add share note

This commit is contained in:
binnchx
2015-01-22 23:13:58 +08:00
parent c35aa1eaa4
commit f78eb4db49
16 changed files with 185 additions and 109 deletions

View File

@@ -129,9 +129,18 @@ func (c Attach) GetAttachs(noteId string) revel.Result {
// 下载附件
// 权限判断
func (c Attach) Download(attachId string) revel.Result {
attach := attachService.GetAttach(attachId, c.GetUserId()); // 得到路径
func (c Attach) Download(attachId, token string) revel.Result {
if c.GetUserId() == "" && token == "" {
return c.RenderText("你需要从分享页面下载附件!")
}
sessionId := c.Session.Id()
attach := attachService.GetAttach(attachId, c.GetUserId(), token, sessionId); // 得到路径
path := attach.Path
if token != "" && attach.Path == "" {
return c.RenderText("该下载链接已经失效,请重新刷新原分享笔记页面下载")
}
if path == "" {
return c.RenderText("")
}

View File

@@ -5,6 +5,7 @@ import (
"github.com/leanote/leanote/app/info"
. "github.com/leanote/leanote/app/lea"
// "strconv"
"fmt"
)
// 用户登录/注销/找回密码
@@ -40,7 +41,7 @@ func (c Auth) Login(email, from string) revel.Result {
func (c Auth) doLogin(email, pwd string) revel.Result {
sessionId := c.Session.Id()
var msg = ""
fmt.Println(sessionId)
userInfo := authService.Login(email, pwd)
if userInfo.Email != "" {
c.SetSession(userInfo)
@@ -55,8 +56,8 @@ func (c Auth) doLogin(email, pwd string) revel.Result {
}
func (c Auth) DoLogin(email, pwd string, captcha string) revel.Result {
sessionId := c.Session.Id()
var msg = ""
var msg = ""
// > 5次需要验证码, 直到登录成功
if sessionService.LoginTimesIsOver(sessionId) && sessionService.GetCaptcha(sessionId) != captcha {
msg = "captchaError"

View File

@@ -540,21 +540,27 @@ func (c Blog) Index(userIdOrEmail string) (re revel.Result) {
}
userId, userInfo := c.userIdOrEmail(hasDomain, userBlog, userIdOrEmail)
var ok = false
fmt.Println("before test...");
if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok {
fmt.Println("404 occur");
return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404
}
fmt.Println("after test0...");
// 分页的话, 需要分页信息, totalPage, curPage
page := c.GetPage()
pageInfo, blogs := blogService.ListBlogs(userId, "", page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc)
blogs2 := blogService.FixBlogs(blogs)
c.RenderArgs["posts"] = blogs2
c.setPaging(pageInfo)
c.RenderArgs["pagingBaseUrl"] = c.RenderArgs["indexUrl"]
c.RenderArgs["curIsIndex"] = true
return c.render("index.html", userBlog.ThemePath)
}

View File

@@ -9,9 +9,9 @@ import (
"github.com/leanote/leanote/app/info"
"io/ioutil"
"os"
"fmt"
// "strconv"
"strings"
"fmt"
)
// 首页
@@ -208,8 +208,9 @@ func (c File) DeleteImage(fileId string) revel.Result {
// 输出image
// 权限判断
func (c File) OutputImage(noteId, fileId string) revel.Result {
path := fileService.GetFile(c.GetUserId(), fileId); // 得到路径
func (c File) OutputImage(noteId, fileId , token string) revel.Result {
sessionId := c.Session.Id()
path := fileService.GetFile(c.GetUserId(), fileId, sessionId, token); // 得到路径
if path == "" {
return c.RenderText("")
}

View File

@@ -16,6 +16,8 @@ type Share struct {
BaseController
}
const AttachToken = 2
// 添加共享note
func (c Share) AddShareNote(noteId string, emails []string, perm int) revel.Result {
status := make(map[string]info.Re, len(emails))
@@ -205,7 +207,7 @@ func (c Share) QuerySharePass(noteId string) revel.Result {
//展示分享笔记
func (c Share) ShowShareNote(noteId string) revel.Result {
note := noteService.GetNote(noteId, c.GetUserId())
note := noteService.GetNoteById(noteId)
//
c.RenderArgs["noteId"] = noteId
username := userService.GetUsernameById(note.UserId)
@@ -219,11 +221,33 @@ func (c Share) ShowShareNote(noteId string) revel.Result {
//验证分享密码
func (c Share) Verify4ShareNote(noteId string, sharePass int) revel.Result {
ok, note := shareService.Verify4ShareNote(noteId, sharePass);
ok, note, noteContent := shareService.Verify4ShareNote(noteId, sharePass)
attaches := []info.Attach{}
if (ok == true && note.AttachNum > 0) {
attaches = attachService.ListAttachs(noteId, c.GetUserId())
if ok && note.AttachNum > 0 {
attaches = attachService.ListAttachs(noteId, "")
}
re := info.Re{Ok : ok, Item: note, List: attaches}
token := tokenService.NewToken(noteId, noteId, AttachToken)
//插入笔记作为链接中的附件
noteAttachIds := map[string]bool{}
noteContent.Content, noteAttachIds = shareService.AppendToken4URL(token, noteContent.Content)
//过滤掉插入笔记的附件
filteredAttaches := []info.Attach{}
if len(noteAttachIds) > 0 && len(attaches) > 0 {
for _, attach := range attaches {
if !noteAttachIds[attach.AttachId.Hex()] {
filteredAttaches = append(filteredAttaches, attach)
}
}
} else {
filteredAttaches = attaches
}
sessionId := c.Session.Id()
sessionService.SetToken(sessionId, token)
re := info.Re{Ok : ok, Item: note, List: filteredAttaches, Id: token, Msg: noteContent.Content}
return c.RenderJson(re)
}

View File

@@ -49,6 +49,7 @@ var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": tru
"Suggestion": true,
},
"Note": map[string]bool{"ToImage": true},
"Share": map[string]bool{"ShowShareNote": true, "Verify4ShareNote": true},
"Blog": map[string]bool{"Index": true,
"View": true,
"AboutMe": true,

View File

@@ -10,10 +10,11 @@ type Session struct {
Id bson.ObjectId `bson:"_id,omitempty"` // 没有意义
SessionId string `bson:"SessionId"` // SessionId
LoginTimes int `LoginTimes` // 登录错误时间
Captcha string `Captcha` // 验证码
Token string `Token` //attach token
TokenTime time.Time `TokenTime` //token生成时间
CreatedTime time.Time `CreatedTime`
UpdatedTime time.Time `UpdatedTime` // 更新时间, expire这个时间会自动清空
}

View File

@@ -51,6 +51,7 @@ func init() {
// Id retrieves from the cookie or creates a time-based UUID identifying this
// session.
func (s Session) Id() string {
if sessionIdStr, ok := s[SESSION_ID_KEY]; ok {
return sessionIdStr
}
@@ -131,7 +132,7 @@ func getSessionFromCookie(cookie *http.Cookie) Session {
return session
}
sig, data := cookie.Value[:hyphen], cookie.Value[hyphen+1:]
// Verify the signature.
if !revel.Verify(data, sig) {
revel.INFO.Println("Session cookie signature failed")
@@ -145,7 +146,7 @@ func getSessionFromCookie(cookie *http.Cookie) Session {
if sessionTimeoutExpiredOrMissing(session) {
session = make(Session)
}
return session
}
@@ -157,6 +158,7 @@ func SessionFilter(c *revel.Controller, fc []revel.Filter) {
// c.Session, 重新生成一个revel.Session给controller!!!
// Log("sessoin--------")
// LogJ(session)
revelSession := revel.Session(session) // 强制转换 还是同一个对象, 但有个问题, 这样Session.Id()方法是用revel的了
c.Session = revelSession
// 生成sessionId

View File

@@ -46,8 +46,8 @@ func (this *AttachService) updateNoteAttachNum(noteId bson.ObjectId, addNum int)
// list attachs
func (this *AttachService) ListAttachs(noteId, userId string) []info.Attach {
attachs := []info.Attach{}
// 判断是否有权限为笔记添加附件
if !shareService.HasUpdateNotePerm(noteId, userId) {
// 判断是否有权限为笔记添加附件, userId为空时表示是分享笔记的附件
if userId != "" && !shareService.HasUpdateNotePerm(noteId, userId) {
return attachs
}
@@ -56,6 +56,7 @@ func (this *AttachService) ListAttachs(noteId, userId string) []info.Attach {
return attachs
}
func (this *AttachService) UpdateImageTitle(userId, fileId, title string) bool {
return db.UpdateByIdAndUserIdField(db.Files, fileId, userId, "Title", title)
}
@@ -105,7 +106,7 @@ func (this *AttachService) DeleteAttach(attachId, userId string) (bool, string)
// 获取文件路径
// 要判断是否具有权限
// userId是否具有attach的访问权限
func (this *AttachService) GetAttach(attachId, userId string) (attach info.Attach) {
func (this *AttachService) GetAttach(attachId, userId, token, sessionId string) (attach info.Attach) {
if attachId == "" {
return
}
@@ -136,6 +137,17 @@ func (this *AttachService) GetAttach(attachId, userId string) (attach info.Attac
return
}
//userId为空则是分享笔记的附件
if userId == "" && sessionId != "" {
if token != "" {
realToken := sessionService.GetToken(sessionId)
if token == realToken {
Log("attach token is equal!")
return
}
}
}
attach = info.Attach{}
return
}

View File

@@ -9,6 +9,7 @@ import (
"time"
"os"
"strings"
// "fmt"
)
const DEFAULT_ALBUM_ID = "52d3e8ac99c37b7f0d000001"
@@ -118,7 +119,8 @@ func (this *FileService) UpdateImage(userId, fileId, title string) bool {
// 获取文件路径
// 要判断是否具有权限
// userId是否具有fileId的访问权限
func (this *FileService) GetFile(userId, fileId string) string {
func (this *FileService) GetFile(userId, fileId , sessionId , token string) string {
if fileId == "" {
return ""
}
@@ -131,7 +133,8 @@ func (this *FileService) GetFile(userId, fileId string) string {
}
// 1. 判断权限
//未登录用户判断token
noteIds := noteImageService.GetNoteIds(fileId)
// 是否是我的文件
if userId != "" && file.UserId.Hex() == userId {
return path
@@ -141,13 +144,30 @@ func (this *FileService) GetFile(userId, fileId string) string {
// 这些笔记是否有public的, 若有则ok
// 这些笔记(笔记本)是否有共享给我的, 若有则ok
noteIds := noteImageService.GetNoteIds(fileId)
if noteIds != nil && len(noteIds) > 0 {
// 这些笔记是否有public的
if db.Has(db.Notes, bson.M{"_id": bson.M{"$in": noteIds}, "IsBlog": true}) {
return path
}
//分享给未注册用户
if userId == "" && sessionId != "" {
if token != "" {
realToken := sessionService.GetToken(sessionId)
if token == realToken {
Log("image token is equal!")
return path
} else {
Log("image token is different!")
return ""
}
} else {
return ""
}
}
// 2014/12/28 修复, 如果是分享给用户组, 那就不行, 这里可以实现
for _, noteId := range noteIds {
note := noteService.GetNoteById(noteId.Hex())
@@ -155,6 +175,7 @@ func (this *FileService) GetFile(userId, fileId string) string {
return path;
}
}
/*
// 若有共享给我的笔记?
// 对该笔记可读?
@@ -191,6 +212,7 @@ func (this *FileService) GetFile(userId, fileId string) string {
return ""
}
// 复制图片
func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, string) {
// 是否已经复制过了

View File

@@ -17,6 +17,17 @@ func (this *NoteService) GetNote(noteId, userId string) (note info.Note) {
db.GetByIdAndUserId(db.Notes, noteId, userId, &note)
return
}
//通过附件id得到note
func (this *NoteService) GetNoteByAttachId(attachId string) (note info.Note) {
attach := info.Attach{}
db.Get(db.Attachs, attachId, &attach)
note = info.Note{}
noteId := attach.NoteId
db.Get(db.Notes, noteId.Hex(), &note)
return
}
// fileService调用
func (this *NoteService) GetNoteById(noteId string) (note info.Note) {
note = info.Note{}

View File

@@ -17,6 +17,13 @@ func (this *SessionService) Update(sessionId, key string, value interface{}) boo
return db.UpdateByQMap(db.Sessions, bson.M{"SessionId": sessionId},
bson.M{key: value, "UpdatedTime": time.Now()})
}
func (this *SessionService) UpdateToken(sessionId, key string, value interface{}) bool {
return db.UpdateByQMap(db.Sessions, bson.M{"SessionId": sessionId},
bson.M{key: value, "UpdatedTime": time.Now(), "TokenTime": time.Now()})
}
// 注销时清空session
func (this *SessionService) Clear(sessionId string) bool {
return db.Delete(db.Sessions, bson.M{"SessionId": sessionId})
@@ -69,3 +76,19 @@ func (this *SessionService) SetCaptcha(sessionId, captcha string) bool {
Log(ok)
return ok
}
// 附件token
func (this *SessionService) GetToken(sessionId string) string {
session := this.Get(sessionId)
return session.Token
}
func (this *SessionService) SetToken(sessionId, token string) bool {
this.Get(sessionId)
Log(sessionId)
Log(token)
ok := this.UpdateToken(sessionId, "Token", token)
Log(ok)
return ok
}

View File

@@ -8,6 +8,8 @@ import (
"time"
"sort"
"math/rand"
"regexp"
"strings"
)
// 共享Notebook, Note服务
@@ -797,13 +799,42 @@ func (this *ShareService) QuerySharePass(noteId string) int {
return note.SharePass
}
func (this *ShareService) Verify4ShareNote(noteId string, sharePass int) (bool, *info.Note) {
note := &info.Note{}
db.Get(db.Notes, noteId, note)
func (this *ShareService) Verify4ShareNote(noteId string, sharePass int) (flag bool, note info.Note, noteContent info.NoteContent) {
note = info.Note{}
db.Get(db.Notes, noteId, &note)
if note.SharePass == sharePass {
return true, note
note = noteService.GetNoteById(noteId)
noteContent = noteService.GetNoteContent(noteId, note.UserId.Hex())
flag = true
} else {
note := &info.Note{}
return false, note
note = info.Note{}
noteContent = info.NoteContent{}
flag = false
}
return
}
//把笔记中含有attachID的url后加上token返回笔记中含有的attachids
func (this *ShareService) AppendToken4URL(token, content string) (c string, attachIds map[string]bool) {
re := regexp.MustCompile(`href=\"(.*?attachId.*?)\".*?data-mce-href=\"(.*?attachId.*?)\"`)
re2 := regexp.MustCompile(`\"(.*?attachId.*?)\"`)
attachIds = map[string]bool{}
s := re.ReplaceAllStringFunc(content, func(m string) string {
idx := strings.Index(m, "attachId=") + len("attachId=")
var ss []byte = []byte(m)
attachId := string(ss[idx: idx + 24])
attachIds[attachId] = true
return re2.ReplaceAllString(m, `"${1}&token=` + token + `"`)
})
re3 := regexp.MustCompile(`<img\s+src=\"(.*?fileId.*?)\".*?data-mce-src=\"(.*?fileId.*?)\"`)
re4 := regexp.MustCompile(`\"(.*?fileId.*?)\"`)
c = re3.ReplaceAllStringFunc(s, func(m string) string {
return re4.ReplaceAllString(m, `"${1}&token=` + token + `"`)
})
return
}

View File

@@ -13,7 +13,9 @@
<span id="showMsg"></span>
</div>
<div id="noteContainer"></div>
<div id="noteContainer" style="display:none">
</div>
{{template "home/footer.html"}}
@@ -47,7 +49,7 @@ var getHost = function(url) {
if(typeof match != "undefined"
&& null != match)
host = match[1];
return host;
return "http://" + host;
}
$(function() {
@@ -62,23 +64,21 @@ $(function() {
if(reIsOk(re)) {
$("#queryNote").css("display", "none");
var title = re.Item.Title;
var desc = re.Item.Desc;
var content = re.Msg;
var imgSrc = re.Item.ImgSrc;
var htmlContent = "<div><h1 height='50px'>{0}</h1></div><hr/><div style='vertical-align:center'><p height='auto'>{1}<br>{2}</p>";
if (re.Item.ImgSrc != "") {
htmlContent += "<img src=" + imgSrc + "></img>";
}
var attaches = re.List;
var attachesHtml = "";
if (attaches.length > 0) {
var token = re.Id;
for (var i=0; i<attaches.length; i++) {
var linkUrl = getHost() + "/attach/download?attachId=" + attaches[i].AttachId;
attachesHtml += "<a href='{0}' target='_blank' data-mce-href='{1}' >附件{2}</a><br/>".format(linkUrl, linkUrl, i+1);
var linkUrl = "{0}/attach/download?attachId={1}&token={2}".format(getHost(), attaches[i].AttachId, token);
attachesHtml += "<p><a href='{0}' target='_blank' data-mce-href='{1}' >附件{2}</a></p><br/>".format(linkUrl, linkUrl, i+1);
}
}
htmlContent = htmlContent.format(title, desc, attachesHtml) + "</div>";
htmlContent = htmlContent.format(title, content, attachesHtml) + "</div>";
/* if (isMarkDown) {

View File

@@ -1,69 +0,0 @@
#------------------------
# leanote config
#------------------------
http.port=9000
site.url=http://localhost:9000
# mongdb
db.host=localhost
#db.host=leanote
db.port=27017
db.dbname=leanote_beta2 # required
db.username= # if not exists, please leave it blank
db.password= # if not exists, please leave it blank
# or you can set the mongdb url
# mongodb://myuser:mypass@localhost:40001,otherhost:40001/mydb
# db.url=mongodb://root:root123@localhost:27017/leanote
#--------------------------------
# revel config
# for dev
#--------------------------------
app.name=leanote
app.secret=V85ZzBeTnzpsHyjQX4zukbQ8qqtju9y2aDM55VWxAH9Qop19poekx3xkcDVvrD0y
http.addr=
http.ssl=false
cookie.httponly=false
cookie.prefix=LEANOTE
cookie.domain= # for share cookie with subdomain, 默认为空, 即不设置 不能设置为localhost, 要么就为空
cookie.secure=false
format.date=01/02/2006
format.datetime=01/02/2006 15:04
results.chunked=false
log.trace.prefix = "TRACE "
log.info.prefix = "INFO "
log.warn.prefix = "WARN "
log.error.prefix = "ERROR "
# The default language of this application.
i18n.default_language=en
module.static=github.com/revel/revel/modules/static
[dev]
mode.dev=true
results.pretty=true
watch=true
module.testrunner = github.com/revel/revel/modules/testrunner
log.trace.output = stderr
log.info.output = stderr
log.warn.output = stderr
log.error.output = stderr
[prod]
mode.dev=false
results.pretty=false
watch=false
module.testrunner =
log.trace.output = off
log.info.output = off
log.warn.output = %(app.name)s.log
log.error.output = %(app.name)s.log

View File

@@ -128,6 +128,7 @@ GET /upload/*filepath Static.Serve("public/upload")
* /member MemberIndex.Index
* /member/index MemberIndex.Index
GET /share/note/:noteId Share.ShowShareNote
# common
* /:controller/:action :controller.:action
* /api/:controller/:action :controller.:action