diff --git a/.gitignore b/.gitignore
index f7308ef..348dea1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,4 +17,4 @@ app/tmp/main.go
.settings
.project
public/config.codekit
-
+files
diff --git a/app/controllers/AttachController.go b/app/controllers/AttachController.go
new file mode 100644
index 0000000..d238c98
--- /dev/null
+++ b/app/controllers/AttachController.go
@@ -0,0 +1,212 @@
+package controllers
+
+import (
+ "github.com/revel/revel"
+// "encoding/json"
+ "gopkg.in/mgo.v2/bson"
+ . "github.com/leanote/leanote/app/lea"
+ "github.com/leanote/leanote/app/info"
+ "io/ioutil"
+ "os"
+ "strings"
+ "time"
+ "io"
+ "archive/tar"
+ "compress/gzip"
+)
+
+// 附件
+type Attach struct {
+ BaseController
+}
+
+// 上传附件
+func (c Attach) UploadAttach(noteId string) revel.Result {
+ re := c.uploadAttach(noteId)
+ return c.RenderJson(re)
+}
+func (c Attach) uploadAttach(noteId string) (re info.Re) {
+ var fileId = ""
+ var resultMsg = "error" // 错误信息
+ var Ok = false
+ var fileInfo info.Attach
+
+ re = info.NewRe()
+
+ defer func() {
+ re.Id = fileId // 只是id, 没有其它信息
+ re.Msg = resultMsg
+ re.Ok = Ok
+ re.Item = fileInfo
+ }()
+
+ // 判断是否有权限为笔记添加附件
+ if !shareService.HasUpdateNotePerm(noteId, c.GetUserId()) {
+ return re
+ }
+
+ file, handel, err := c.Request.FormFile("file")
+ if err != nil {
+ return re
+ }
+ defer file.Close()
+
+ data, err := ioutil.ReadAll(file)
+ if err != nil {
+ return re
+ }
+ // > 5M?
+ if(len(data) > 5 * 1024 * 1024) {
+ resultMsg = "File is bigger than 5M"
+ return re
+ }
+
+ // 生成上传路径
+ filePath := "files/" + c.GetUserId() + "/attachs"
+ dir := revel.BasePath + "/" + filePath
+ err = os.MkdirAll(dir, 0755)
+ if err != nil {
+ return re
+ }
+ // 生成新的文件名
+ filename := handel.Filename
+ _, ext := SplitFilename(filename) // .doc
+ filename = NewGuid() + ext
+ toPath := dir + "/" + filename;
+ err = ioutil.WriteFile(toPath, data, 0777)
+ if err != nil {
+ return re
+ }
+
+ // add File to db
+ fileType := ""
+ if ext != "" {
+ fileType = strings.ToLower(ext[1:])
+ }
+ filesize := GetFilesize(toPath)
+ fileInfo = info.Attach{Name: filename,
+ Title: handel.Filename,
+ NoteId: bson.ObjectIdHex(noteId),
+ UploadUserId: c.GetObjectUserId(),
+ Path: filePath + "/" + filename,
+ Type: fileType,
+ Size: filesize}
+
+ id := bson.NewObjectId();
+ fileInfo.AttachId = id
+ fileId = id.Hex()
+ Ok = attachService.AddAttach(fileInfo)
+
+ fileInfo.Path = ""; // 不要返回
+ resultMsg = "success"
+
+ return re
+}
+
+// 删除附件
+func (c Attach) DeleteAttach(attachId string) revel.Result {
+ re := info.NewRe()
+ re.Ok, re.Msg = attachService.DeleteAttach(attachId, c.GetUserId())
+ return c.RenderJson(re)
+}
+
+// get all attachs by noteId
+func (c Attach) GetAttachs(noteId string) revel.Result {
+ re := info.NewRe()
+ re.Ok = true
+ re.List = attachService.ListAttachs(noteId, c.GetUserId())
+ return c.RenderJson(re)
+}
+
+// 下载附件
+// 权限判断
+func (c Attach) Download(attachId string) revel.Result {
+ attach := attachService.GetAttach(attachId, c.GetUserId()); // 得到路径
+ path := attach.Path
+ if path == "" {
+ return c.RenderText("")
+ }
+ fn := revel.BasePath + "/" + strings.TrimLeft(path, "/")
+ file, _ := os.Open(fn)
+ return c.RenderBinary(file, attach.Title, revel.Attachment, time.Now()) // revel.Attachment
+ // return c.RenderFile(file, revel.Attachment) // revel.Attachment
+}
+
+func (c Attach) DownloadAll(noteId string) revel.Result {
+ note := noteService.GetNoteById(noteId)
+ if note.NoteId == "" {
+ return c.RenderText("")
+ }
+ // 得到文件列表
+ attachs := attachService.ListAttachs(noteId, c.GetUserId())
+ if attachs == nil || len(attachs) == 0 {
+ return c.RenderText("")
+ }
+
+ /*
+ dir := revel.BasePath + "/files/tmp"
+ err := os.MkdirAll(dir, 0755)
+ if err != nil {
+ return c.RenderText("")
+ }
+ */
+
+ filename := note.Title + ".tar.gz"
+ if note.Title == "" {
+ filename = "all.tar.gz"
+ }
+
+ // file write
+ fw, err := os.Create(revel.BasePath + "/files/" + filename)
+ if err != nil {
+ return c.RenderText("")
+ }
+ // defer fw.Close() // 不需要关闭, 还要读取给用户下载
+
+ // gzip write
+ gw := gzip.NewWriter(fw)
+ defer gw.Close()
+
+ // tar write
+ tw := tar.NewWriter(gw)
+ defer tw.Close()
+
+ // 遍历文件列表
+ for _, attach := range attachs {
+ fn := revel.BasePath + "/" + strings.TrimLeft(attach.Path, "/")
+ fr, err := os.Open(fn)
+ fileInfo, _ := fr.Stat()
+ if err != nil {
+ return c.RenderText("")
+ }
+ defer fr.Close()
+
+ // 信息头
+ h := new(tar.Header)
+ h.Name = attach.Title
+ h.Size = fileInfo.Size()
+ h.Mode = int64(fileInfo.Mode())
+ h.ModTime = fileInfo.ModTime()
+
+ // 写信息头
+ err = tw.WriteHeader(h)
+ if err != nil {
+ panic(err)
+ }
+
+ // 写文件
+ _, err = io.Copy(tw, fr)
+ if err != nil {
+ panic(err)
+ }
+ } // for
+
+// tw.Close()
+// gw.Close()
+// fw.Close()
+// file, _ := os.Open(dir + "/" + filename)
+ // fw.Seek(0, 0)
+ return c.RenderBinary(fw, filename, revel.Attachment, time.Now()) // revel.Attachment
+}
+
+
diff --git a/app/controllers/FileController.go b/app/controllers/FileController.go
index 62a8a35..91cdb6b 100644
--- a/app/controllers/FileController.go
+++ b/app/controllers/FileController.go
@@ -3,11 +3,13 @@ package controllers
import (
"github.com/revel/revel"
// "encoding/json"
+ "gopkg.in/mgo.v2/bson"
. "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
"io/ioutil"
"os"
"strconv"
+ "strings"
)
// 首页
@@ -15,7 +17,7 @@ type File struct {
BaseController
}
-// 上传图片 editor
+// 过时 已弃用!
func (c File) UploadImage(renderHtml string) revel.Result {
if renderHtml == "" {
renderHtml = "file/image.html"
@@ -30,36 +32,60 @@ func (c File) UploadImage(renderHtml string) revel.Result {
return c.RenderTemplate(renderHtml)
}
+// 已弃用
+func (c File) UploadImageJson(from, noteId string) revel.Result {
+ re := c.uploadImage(from, "");
+ return c.RenderJson(re)
+}
+
+
// 上传的是博客logo
+// TODO logo不要设置权限, 另外的目录
func (c File) UploadBlogLogo() revel.Result {
return c.UploadImage("file/blog_logo.html");
}
// 拖拉上传, pasteImage
-func (c File) UploadImageJson(renderHtml, from string) revel.Result {
- re := c.uploadImage(from, "");
- re.Id = siteUrl + re.Id
-// re.Id = re.Id
+// noteId 是为了判断是否是协作的note, 如果是则需要复制一份到note owner中
+func (c File) PasteImage(noteId string) revel.Result {
+ re := c.uploadImage("pasteImage", "");
+
+ userId := c.GetUserId()
+ note := noteService.GetNoteById(noteId)
+ if note.UserId != "" {
+ noteUserId := note.UserId.Hex()
+ if noteUserId != userId {
+ // 是否是有权限协作的
+ if shareService.HasUpdatePerm(noteUserId, userId, noteId) {
+ // 复制图片之, 图片复制给noteUserId
+ _, re.Id = fileService.CopyImage(userId, re.Id, noteUserId)
+ } else {
+ // 怎么可能在这个笔记下paste图片呢?
+ // 正常情况下不会
+ }
+ }
+ }
+
return c.RenderJson(re)
}
-// leaui image plugin
+// leaui image plugin upload image
func (c File) UploadImageLeaui(albumId string) revel.Result {
re := c.uploadImage("", albumId);
- re.Id = siteUrl + re.Id
-// re.Id = re.Id
return c.RenderJson(re)
}
// 上传图片, 公用方法
+// upload image common func
func (c File) uploadImage(from, albumId string) (re info.Re) {
var fileUrlPath = ""
+ var fileId = ""
var resultCode = 0 // 1表示正常
var resultMsg = "内部错误" // 错误信息
var Ok = false
defer func() {
- re.Id = fileUrlPath
+ re.Id = fileId // 只是id, 没有其它信息
re.Code = resultCode
re.Msg = resultMsg
re.Ok = Ok
@@ -71,11 +97,10 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
}
defer file.Close()
// 生成上传路径
- fileUrlPath = "/upload/" + c.GetUserId() + "/images"
- dir := revel.BasePath + "/public/" + fileUrlPath
+ fileUrlPath = "files/" + c.GetUserId() + "/images"
+ dir := revel.BasePath + "/" + fileUrlPath
err = os.MkdirAll(dir, 0755)
if err != nil {
- Log(err)
return re
}
// 生成新的文件名
@@ -126,8 +151,12 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
Path: fileUrlPath,
Size: filesize}
+ id := bson.NewObjectId();
+ fileInfo.FileId = id
+ fileId = id.Hex()
Ok = fileService.AddImage(fileInfo, albumId, c.GetUserId())
+ fileInfo.Path = ""; // 不要返回
re.Item = fileInfo
return re
@@ -197,4 +226,27 @@ func (c File) UpgradeLeauiImage() revel.Result {
re.Msg = msg
return c.RenderJson(re)
-}
\ No newline at end of file
+}
+
+//-----------
+
+// 输出image
+// 权限判断
+func (c File) OutputImage(noteId, fileId string) revel.Result {
+ path := fileService.GetFile(c.GetUserId(), fileId); // 得到路径
+ if path == "" {
+ return c.RenderText("")
+ }
+ fn := revel.BasePath + "/" + strings.TrimLeft(path, "/")
+ file, _ := os.Open(fn)
+ return c.RenderFile(file, revel.Inline) // revel.Attachment
+}
+
+// 协作时复制图片到owner
+func (c File) CopyImage(userId, fileId, toUserId string) revel.Result {
+ re := info.NewRe()
+
+ re.Ok, re.Id = fileService.CopyImage(userId, fileId, toUserId)
+
+ return c.RenderJson(re)
+}
diff --git a/app/controllers/NoteController.go b/app/controllers/NoteController.go
index ac8558c..17b48c5 100644
--- a/app/controllers/NoteController.go
+++ b/app/controllers/NoteController.go
@@ -117,7 +117,6 @@ type NoteOrContent struct {
// 这里不能用json, 要用post
func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result {
// 新添加note
- LogJ(noteOrContent)
if noteOrContent.IsNew {
userId := c.GetObjectUserId();
myUserId := userId
diff --git a/app/controllers/init.go b/app/controllers/init.go
index 5736b19..56fb798 100644
--- a/app/controllers/init.go
+++ b/app/controllers/init.go
@@ -25,6 +25,7 @@ var suggestionService *service.SuggestionService
var albumService *service.AlbumService
var fileService *service.FileService
+var attachService *service.AttachService
var pageSize = 1000
var defaultSortField = "UpdatedTime"
@@ -56,12 +57,13 @@ var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": tru
"User": map[string]bool{"UpdateEmail": true,
"ActiveEmail":true,
},
- "oauth": map[string]bool{"githubCallback": true},
+ "Oauth": map[string]bool{"GithubCallback": true},
+ "File": map[string]bool{"OutputImage": true, "OutputFile": true},
}
func needValidate(controller, method string) bool {
// 在里面
if v, ok := commonUrl[controller]; ok {
- // 不在commonUrl里
+ // 在commonUrl里
if _, ok2 := v[method]; ok2 {
return false
}
diff --git a/app/db/Mgo.go b/app/db/Mgo.go
index 7a330df..6f91f8b 100644
--- a/app/db/Mgo.go
+++ b/app/db/Mgo.go
@@ -36,6 +36,9 @@ var Suggestions *mgo.Collection
// Album & file(image)
var Albums *mgo.Collection
var Files *mgo.Collection
+var Attachs *mgo.Collection
+
+var NoteImages *mgo.Collection
// 初始化时连接数据库
func Init() {
@@ -104,6 +107,9 @@ func Init() {
// Album & file
Albums = Session.DB(dbname).C("albums")
Files = Session.DB(dbname).C("files")
+ Attachs = Session.DB(dbname).C("attachs")
+
+ NoteImages = Session.DB(dbname).C("note_images")
}
func init() {
diff --git a/app/info/AttachInfo.go b/app/info/AttachInfo.go
new file mode 100644
index 0000000..4dc39ef
--- /dev/null
+++ b/app/info/AttachInfo.go
@@ -0,0 +1,21 @@
+package info
+
+import (
+ "gopkg.in/mgo.v2/bson"
+ "time"
+)
+
+// Attach belongs to note
+type Attach struct {
+ AttachId bson.ObjectId `bson:"_id,omitempty"` //
+ NoteId bson.ObjectId `bson:"NoteId"` //
+ UploadUserId bson.ObjectId `bson:"UploadUserId"` // 可以不是note owner, 协作者userId
+ Name string `Name` // file name, md5, such as 13232312.doc
+ Title string `Title` // raw file name
+ Size int64 `Size` // file size (byte)
+ Type string `Type` // file type, "doc" = word
+ Path string `Path` // the file path such as: files/userId/attachs/adfadf.doc
+ CreatedTime time.Time `CreatedTime`
+
+ // FromFileId bson.ObjectId `bson:"FromFileId,omitempty"` // copy from fileId, for collaboration
+}
diff --git a/app/info/FileInfo.go b/app/info/FileInfo.go
index 199d53c..66a7995 100644
--- a/app/info/FileInfo.go
+++ b/app/info/FileInfo.go
@@ -11,9 +11,11 @@ type File struct {
AlbumId bson.ObjectId `bson:"AlbumId"`
Name string `Name` // file name
Title string `Title` // file name or user defined for search
- Size int64 `Size` // file size (byte)
- Type string `Type` // file type, such as image/jpg
- Path string `Path` // the file path, based on /upload
+ Size int64 `Size` // file size (byte)
+ Type string `Type` // file type, "" = image, "doc" = word
+ Path string `Path` // the file path
IsDefaultAlbum bool `IsDefaultAlbum`
CreatedTime time.Time `CreatedTime`
+
+ FromFileId bson.ObjectId `bson:"FromFileId,omitempty"` // copy from fileId, for collaboration
}
diff --git a/app/info/NoteImage.go b/app/info/NoteImage.go
new file mode 100644
index 0000000..38643cf
--- /dev/null
+++ b/app/info/NoteImage.go
@@ -0,0 +1,12 @@
+package info
+
+import (
+ "gopkg.in/mgo.v2/bson"
+)
+
+// 笔记内部图片
+type NoteImage struct {
+ NoteImageId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
+ NoteId bson.ObjectId `bson:"NoteId"` // 笔记
+ ImageId bson.ObjectId `bson:"ImageId"` // 图片fileId
+}
\ No newline at end of file
diff --git a/app/info/NoteInfo.go b/app/info/NoteInfo.go
index 0b3b513..9ba45fd 100644
--- a/app/info/NoteInfo.go
+++ b/app/info/NoteInfo.go
@@ -24,6 +24,8 @@ type Note struct {
IsMarkdown bool `IsMarkdown` // 是否是markdown笔记, 默认是false
+ AttachNum int `AttachNum` // 2014/9/21, attachments num
+
CreatedTime time.Time `CreatedTime`
UpdatedTime time.Time `UpdatedTime`
UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
@@ -54,11 +56,11 @@ type NoteAndContent struct {
// 每一个历史记录对象
type EachHistory struct {
UpdatedUserId bson.ObjectId `UpdatedUserId`
- UpdatedTime time.Time `UpdatedTime`
- Content string `Content`
+ UpdatedTime time.Time `UpdatedTime`
+ Content string `Content`
}
type NoteContentHistory struct {
- NoteId bson.ObjectId `bson:"_id,omitempty"`
- UserId bson.ObjectId `bson:"UserId"` // 所属者
- Histories []EachHistory `Histories`
-}
\ No newline at end of file
+ NoteId bson.ObjectId `bson:"_id,omitempty"`
+ UserId bson.ObjectId `bson:"UserId"` // 所属者
+ Histories []EachHistory `Histories`
+}
diff --git a/app/lea/File.go b/app/lea/File.go
index a1f4dff..503f165 100644
--- a/app/lea/File.go
+++ b/app/lea/File.go
@@ -4,6 +4,7 @@ import (
"strings"
"path/filepath"
"os"
+ "io"
)
// 分离文件名与扩展名(包含.)
@@ -62,4 +63,18 @@ func ListDir(dir string) []string {
}
names, _ := f.Readdirnames(0)
return names
+}
+
+func CopyFile(srcName, dstName string) (written int64, err error) {
+ src, err := os.Open(srcName)
+ if err != nil {
+ return
+ }
+ defer src.Close()
+ dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644)
+ if err != nil {
+ return
+ }
+ defer dst.Close()
+ return io.Copy(dst, src)
}
\ No newline at end of file
diff --git a/app/lea/Util.go b/app/lea/Util.go
index 1685802..3d28047 100644
--- a/app/lea/Util.go
+++ b/app/lea/Util.go
@@ -266,4 +266,16 @@ func RandomPwd(num int) string {
}
return str
+}
+
+func InArray(arr []string, str string) bool {
+ if arr == nil {
+ return false
+ }
+ for _, v := range arr {
+ if v == str {
+ return true
+ }
+ }
+ return false
}
\ No newline at end of file
diff --git a/app/service/AttachService.go b/app/service/AttachService.go
new file mode 100644
index 0000000..521558d
--- /dev/null
+++ b/app/service/AttachService.go
@@ -0,0 +1,175 @@
+package service
+
+import (
+ . "github.com/leanote/leanote/app/lea"
+ "github.com/revel/revel"
+ "github.com/leanote/leanote/app/info"
+ "github.com/leanote/leanote/app/db"
+ "gopkg.in/mgo.v2/bson"
+ "time"
+ "os"
+ "strings"
+)
+
+type AttachService struct {
+}
+
+// add attach
+func (this *AttachService) AddAttach(attach info.Attach) bool {
+ attach.CreatedTime = time.Now()
+ ok := db.Insert(db.Attachs, attach)
+
+ if ok {
+ // 更新笔记的attachs num
+ this.updateNoteAttachNum(attach.NoteId, 1)
+ }
+
+ return ok
+}
+
+// 更新笔记的附件个数
+// addNum 1或-1
+func (this *AttachService) updateNoteAttachNum(noteId bson.ObjectId, addNum int) bool {
+ num := db.Count(db.Attachs, bson.M{"NoteId": noteId})
+ /*
+ note := info.Note{}
+ note = noteService.GetNoteById(noteId.Hex())
+ note.AttachNum += addNum
+ if note.AttachNum < 0 {
+ note.AttachNum = 0
+ }
+ Log(note.AttachNum)
+ */
+ return db.UpdateByQField(db.Notes, bson.M{"_id": noteId}, "AttachNum", num)
+}
+
+// list attachs
+func (this *AttachService) ListAttachs(noteId, userId string) []info.Attach {
+ attachs := []info.Attach{}
+ // 判断是否有权限为笔记添加附件
+ if !shareService.HasUpdateNotePerm(noteId, userId) {
+ return attachs
+ }
+
+ db.ListByQ(db.Attachs, bson.M{"NoteId": bson.ObjectIdHex(noteId)}, &attachs)
+
+ return attachs
+}
+
+func (this *AttachService) UpdateImageTitle(userId, fileId, title string) bool {
+ return db.UpdateByIdAndUserIdField(db.Files, fileId, userId, "Title", title)
+}
+
+
+// Delete note to delete attas firstly
+func (this *AttachService) DeleteAllAttachs(noteId, userId string) bool {
+ note := noteService.GetNoteById(noteId)
+ if note.UserId.Hex() == userId {
+ attachs := []info.Attach{}
+ db.ListByQ(db.Attachs, bson.M{"NoteId": bson.ObjectIdHex(noteId)}, &attachs)
+ for _, attach := range attachs {
+ attach.Path = strings.TrimLeft(attach.Path, "/")
+ os.Remove(revel.BasePath + "/" + attach.Path)
+ }
+ return true
+ }
+
+ return false
+}
+
+// delete attach
+func (this *AttachService) DeleteAttach(attachId, userId string) (bool, string) {
+ attach := info.Attach{}
+ db.Get(db.Attachs, attachId, &attach)
+
+ if(attach.AttachId != "") {
+ // 判断是否有权限为笔记添加附件
+ if !shareService.HasUpdateNotePerm(attach.NoteId.Hex(), userId) {
+ return false, "No Perm"
+ }
+
+ if db.Delete(db.Attachs, bson.M{"_id": bson.ObjectIdHex(attachId)}) {
+ this.updateNoteAttachNum(attach.NoteId, -1)
+ attach.Path = strings.TrimLeft(attach.Path, "/")
+ err := os.Remove(revel.BasePath + "/" + attach.Path)
+ if err == nil {
+ return true, "delete file error"
+ }
+ return false, "delete file error"
+ }
+ return false, "db error"
+ }
+ return false, "no such item"
+}
+
+// 获取文件路径
+// 要判断是否具有权限
+// userId是否具有attach的访问权限
+func (this *AttachService) GetAttach(attachId, userId string) (attach info.Attach) {
+ if attachId == "" {
+ return
+ }
+
+ attach = info.Attach{}
+ db.Get(db.Attachs, attachId, &attach)
+ path := attach.Path
+ if path == "" {
+ return
+ }
+
+ note := noteService.GetNoteById(attach.NoteId.Hex())
+
+ // 判断权限
+
+ // 笔记是否是公开的
+ if note.IsBlog {
+ return
+ }
+
+ // 笔记是否是我的
+ if note.UserId.Hex() == userId {
+ return
+ }
+
+ // 我是否有权限查看或协作
+ if shareService.HasReadNotePerm(attach.NoteId.Hex(), userId) {
+ return
+ }
+
+ attach = info.Attach{}
+ return
+}
+
+// 复制笔记时需要复制附件
+// noteService调用, 权限已判断
+func (this *AttachService) CopyAttachs(noteId, toNoteId, toUserId string) bool {
+ attachs := []info.Attach{}
+ db.ListByQ(db.Attachs, bson.M{"NoteId": bson.ObjectIdHex(noteId)}, &attachs)
+
+ // 复制之
+ toNoteIdO := bson.ObjectIdHex(toNoteId)
+ for _, attach := range attachs {
+ attach.AttachId = ""
+ attach.NoteId = toNoteIdO
+
+ // 文件复制一份
+ _, ext := SplitFilename(attach.Name)
+ newFilename := NewGuid() + ext
+ dir := "files/" + toUserId + "/attachs"
+ filePath := dir + "/" + newFilename
+ err := os.MkdirAll(revel.BasePath + "/" + dir, 0755)
+ if err != nil {
+ return false
+ }
+ _, err = CopyFile(revel.BasePath + "/" + attach.Path, revel.BasePath + "/" + filePath)
+ if err != nil {
+ return false
+ }
+ attach.Name = newFilename
+ attach.Path = filePath
+
+ this.AddAttach(attach)
+ }
+
+ return true
+}
\ No newline at end of file
diff --git a/app/service/FileService.go b/app/service/FileService.go
index 7d8a7bd..8a8cfc3 100644
--- a/app/service/FileService.go
+++ b/app/service/FileService.go
@@ -1,7 +1,7 @@
package service
import (
-// . "github.com/leanote/leanote/app/lea"
+ . "github.com/leanote/leanote/app/lea"
"github.com/revel/revel"
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
@@ -35,7 +35,7 @@ func (this *FileService) ListImagesWithPage(userId, albumId, key string, pageNum
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, "CreatedTime", false)
files := []info.File{}
- q := bson.M{"UserId": bson.ObjectIdHex(userId)}
+ q := bson.M{"UserId": bson.ObjectIdHex(userId), "Type": ""} // life
if albumId != "" {
q["AlbumId"] = bson.ObjectIdHex(albumId);
} else {
@@ -89,6 +89,7 @@ func (this *FileService) DeleteImage(userId, fileId string) (bool, string) {
if(file.FileId != "") {
if db.DeleteByIdAndUserId(db.Files, fileId, userId) {
// delete image
+ // TODO
err := os.Remove(revel.BasePath + "/public/" + file.Path)
if err == nil {
return true, ""
@@ -103,4 +104,125 @@ func (this *FileService) DeleteImage(userId, fileId string) (bool, string) {
// update image title
func (this *FileService) UpdateImage(userId, fileId, title string) bool {
return db.UpdateByIdAndUserIdField(db.Files, fileId, userId, "Title", title)
-}
\ No newline at end of file
+}
+
+// 获取文件路径
+// 要判断是否具有权限
+// userId是否具有fileId的访问权限
+func (this *FileService) GetFile(userId, fileId string) string {
+ if fileId == "" {
+ return ""
+ }
+
+ file := info.File{}
+ db.Get(db.Files, fileId, &file)
+ path := file.Path
+ if path == "" {
+ return ""
+ }
+
+ // 1. 判断权限
+
+ // 是否是我的文件
+ if userId != "" && file.UserId.Hex() == userId {
+ return path
+ }
+
+ // 得到使用过该fileId的所有笔记NoteId
+ // 这些笔记是否有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 db.Has(db.ShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(userId), "NoteId": bson.M{"$in": noteIds}}) {
+ return path
+ }
+
+ // 笔记本是否共享给我?
+ // 通过笔记得到笔记本
+ notes := []info.Note{}
+ db.ListByQWithFields(db.Notes, bson.M{"_id": bson.M{"$in": noteIds}}, []string{"NotebookId"}, ¬es)
+ if notes != nil && len(notes) > 0 {
+ notebookIds := make([]bson.ObjectId, len(notes))
+ for i := 0; i < len(notes); i++ {
+ notebookIds[i] = notes[i].NotebookId
+ }
+
+ if db.Has(db.ShareNotebooks, bson.M{"ToUserId": bson.ObjectIdHex(userId), "NotebookId": bson.M{"$in": notebookIds}}) {
+ return path
+ }
+ }
+ }
+
+ // 可能是刚复制到owner上, 但内容又没有保存, 所以没有note->imageId的映射, 此时看是否有fromFileId
+ if file.FromFileId != "" {
+ fromFile := info.File{}
+ db.Get2(db.Files, file.FromFileId, &fromFile)
+ if fromFile.UserId.Hex() == userId {
+ return fromFile.Path
+ }
+ }
+
+ return ""
+}
+
+// 复制图片
+func (this *FileService) CopyImage(userId, fileId, toUserId string) (bool, string) {
+ // 是否已经复制过了
+ file2 := info.File{}
+ db.GetByQ(db.Files, bson.M{"UserId": bson.ObjectIdHex(toUserId), "FromFileId": bson.ObjectIdHex(fileId)}, &file2)
+ if file2.FileId != "" {
+ return true, file2.FileId.Hex();
+ }
+
+ // 复制之
+
+ file := info.File{}
+ db.GetByIdAndUserId(db.Files, fileId, userId, &file)
+
+ if file.FileId == "" || file.UserId.Hex() != userId {
+ return false, ""
+ }
+
+ _, ext := SplitFilename(file.Name)
+ newFilename := NewGuid() + ext
+
+ dir := "files/" + toUserId + "/images"
+ filePath := dir + "/" + newFilename
+ err := os.MkdirAll(dir, 0755)
+ if err != nil {
+ return false, ""
+ }
+
+ _, err = CopyFile(revel.BasePath + "/" + file.Path, revel.BasePath + "/" + filePath)
+ if err != nil {
+ Log(err)
+ return false, ""
+ }
+
+ fileInfo := info.File{Name: newFilename,
+ Title: file.Title,
+ Path: filePath,
+ Size: file.Size,
+ FromFileId: file.FileId}
+ id := bson.NewObjectId();
+ fileInfo.FileId = id
+ fileId = id.Hex()
+ Ok := this.AddImage(fileInfo, "", toUserId)
+
+ if Ok {
+ return Ok, id.Hex()
+ }
+ return false, ""
+}
+
+// 是否是我的文件
+func (this *FileService) IsMyFile(userId, fileId string) bool {
+ return db.Has(db.Files, bson.M{"UserId": bson.ObjectIdHex(userId), "_id": bson.ObjectIdHex(fileId)})
+}
diff --git a/app/service/NoteImageService.go b/app/service/NoteImageService.go
new file mode 100644
index 0000000..11dcf6d
--- /dev/null
+++ b/app/service/NoteImageService.go
@@ -0,0 +1,102 @@
+package service
+
+import (
+ "github.com/leanote/leanote/app/info"
+ "github.com/leanote/leanote/app/db"
+ . "github.com/leanote/leanote/app/lea"
+ "gopkg.in/mgo.v2/bson"
+ "regexp"
+// "time"
+)
+
+type NoteImageService struct {
+}
+
+// 通过id, userId得到noteIds
+func (this *NoteImageService) GetNoteIds(imageId string) ([]bson.ObjectId) {
+ noteImages := []info.NoteImage{}
+ db.ListByQWithFields(db.NoteImages, bson.M{"ImageId": bson.ObjectIdHex(imageId)}, []string{"NoteId"}, ¬eImages)
+
+ if noteImages != nil && len(noteImages) > 0 {
+ noteIds := make([]bson.ObjectId, len(noteImages))
+ cnt := len(noteImages)
+ for i := 0; i < cnt; i++ {
+ noteIds[i] = noteImages[i].NoteId
+ }
+ return noteIds
+ }
+
+ return nil
+}
+
+// 解析内容中的图片, 建立图片与note的关系
+//
+// 图片必须是我的, 不然不添加
+func (this *NoteImageService) UpdateNoteImages(userId, noteId, content string) bool {
+ reg, _ := regexp.Compile("outputImage\\?fileId=([a-z0-9A-Z]{24})")
+ find := reg.FindAllStringSubmatch(content, -1) // 查找所有的
+
+ // 删除旧的
+ db.DeleteAll(db.NoteImages, bson.M{"NoteId": bson.ObjectIdHex(noteId)})
+
+ // 添加新的
+ var fileId string
+ noteImage := info.NoteImage{NoteId: bson.ObjectIdHex(noteId)}
+ hasAdded := make(map[string]bool)
+ if find != nil && len(find) > 0 {
+ for _, each := range find {
+ if each != nil && len(each) == 2 {
+ fileId = each[1]
+ // 之前没能添加过的
+ if _, ok := hasAdded[fileId]; !ok {
+ Log(fileId)
+ // 判断是否是我的文件
+ if fileService.IsMyFile(userId, fileId) {
+ noteImage.ImageId = bson.ObjectIdHex(fileId)
+ db.Insert(db.NoteImages, noteImage)
+ }
+ hasAdded[fileId] = true
+ }
+ }
+ }
+ }
+
+ return true
+}
+
+// 复制图片, 把note的图片都copy给我, 且修改noteContent图片路径
+func (this *NoteImageService) CopyNoteImages(fromNoteId, fromUserId, newNoteId, content, toUserId string) string {
+ // 得到fromNoteId的noteImages, 如果为空, 则直接返回content
+ noteImages := []info.NoteImage{}
+ db.ListByQWithFields(db.NoteImages, bson.M{"NoteId": bson.ObjectIdHex(fromNoteId)}, []string{"ImageId"}, ¬eImages)
+
+ if len(noteImages) == 0 {
+ return content;
+ }
+
+ //
+ // 把fileId=1232替换成新的
+ replaceMap := map[string]string{}
+ for _, noteImage := range noteImages {
+ imageId := noteImage.ImageId.Hex()
+ ok, newImageId := fileService.CopyImage(fromUserId, imageId, toUserId)
+ if ok {
+ replaceMap[imageId] = newImageId
+ }
+ }
+
+ if len(replaceMap) > 0 {
+ // 替换之
+ reg, _ := regexp.Compile("outputImage\\?fileId=([a-z0-9A-Z]{24})")
+ content = reg.ReplaceAllStringFunc(content, func(each string) string {
+ // each=outputImage?fileId=541bd2f599c37b4f3r000003
+ fileId := each[len(each)-24:] // 得到后24位, 也即id
+ if replaceFileId, ok := replaceMap[fileId]; ok {
+ return "outputImage?fileId=" + replaceFileId
+ }
+ return each
+ });
+ }
+
+ return content;
+}
diff --git a/app/service/NoteService.go b/app/service/NoteService.go
index f1341fd..7fc2504 100644
--- a/app/service/NoteService.go
+++ b/app/service/NoteService.go
@@ -17,6 +17,12 @@ func (this *NoteService) GetNote(noteId, userId string) (note info.Note) {
db.GetByIdAndUserId(db.Notes, noteId, userId, ¬e)
return
}
+// fileService调用
+func (this *NoteService) GetNoteById(noteId string) (note info.Note) {
+ note = info.Note{}
+ db.Get(db.Notes, noteId, ¬e)
+ return
+}
// 得到blog, blogService用
// 不要传userId, 因为是公开的
func (this *NoteService) GetBlogNote(noteId string) (note info.Note) {
@@ -148,6 +154,10 @@ func (this *NoteService) AddNoteContent(noteContent info.NoteContent) info.NoteC
noteContent.UpdatedTime = noteContent.CreatedTime
noteContent.UpdatedUserId = noteContent.UserId
db.Insert(db.NoteContents, noteContent)
+
+ // 更新笔记图片
+ noteImageService.UpdateNoteImages(noteContent.UserId.Hex(), noteContent.NoteId.Hex(), noteContent.Content)
+
return noteContent;
}
@@ -237,11 +247,23 @@ func (this *NoteService) UpdateNoteContent(userId, updatedUserId, noteId, conten
Content: content,
UpdatedTime: time.Now(),
})
+
+ // 更新笔记图片
+ noteImageService.UpdateNoteImages(userId, noteId, content)
+
return true
}
return false
}
+// ?????
+// 这种方式太恶心, 改动很大
+// 通过content修改笔记的imageIds列表
+// src="http://localhost:9000/file/outputImage?fileId=541ae75499c37b6b79000005¬eId=541ae63c19807a4bb9000000"
+func (this *NoteService) updateNoteImages(noteId string, content string) bool {
+ return true
+}
+
// 更新tags
// [ok] [del]
func (this *NoteService) UpdateTags(noteId string, userId string, tags []string) bool {
@@ -316,9 +338,12 @@ func (this *NoteService) CopyNote(noteId, notebookId, userId string) info.Note {
}
// 复制别人的共享笔记给我
-// TODO 判断是否共享了给我
+// 将别人可用的图片转为我的图片, 复制图片
func (this *NoteService) CopySharedNote(noteId, notebookId, fromUserId, myUserId string) info.Note {
- if notebookService.IsMyNotebook(notebookId, myUserId) {
+ Log(shareService.HasSharedNote(noteId, myUserId) || shareService.HasSharedNotebook(noteId, myUserId, fromUserId))
+ // 判断是否共享了给我
+ if notebookService.IsMyNotebook(notebookId, myUserId) &&
+ (shareService.HasSharedNote(noteId, myUserId) || shareService.HasSharedNotebook(noteId, myUserId, fromUserId)) {
note := this.GetNote(noteId, fromUserId)
if note.NoteId == "" {
return info.Note{}
@@ -332,10 +357,18 @@ func (this *NoteService) CopySharedNote(noteId, notebookId, fromUserId, myUserId
note.IsTop = false
note.IsBlog = false // 别人的可能是blog
+ note.ImgSrc = "" // 为什么清空, 因为图片需要复制, 先清空
+
// content
noteContent.NoteId = note.NoteId
noteContent.UserId = note.UserId
+ // 复制图片, 把note的图片都copy给我, 且修改noteContent图片路径
+ noteContent.Content = noteImageService.CopyNoteImages(noteId, fromUserId, note.NoteId.Hex(), noteContent.Content, myUserId)
+
+ // 复制附件
+ attachService.CopyAttachs(noteId, note.NoteId.Hex(), myUserId)
+
// 添加之
note = this.AddNoteAndContent(note, noteContent, note.UserId);
@@ -353,8 +386,10 @@ func (this *NoteService) CopySharedNote(noteId, notebookId, fromUserId, myUserId
// shareService call
// [ok]
func (this *NoteService) GetNotebookId(noteId string) bson.ObjectId {
- note := &info.Note{}
- db.Get(db.Notes, noteId, note)
+ note := info.Note{}
+ // db.Get(db.Notes, noteId, ¬e)
+ // LogJ(note)
+ db.GetByQWithFields(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId)}, []string{"NotebookId"}, ¬e)
return note.NotebookId
}
@@ -396,7 +431,6 @@ func (this *NoteService) searchNoteFromContent(notes []info.Note, userId, key st
for i, note := range notes {
noteIds[i] = note.NoteId
}
- LogJ(noteIds)
noteContents := []info.NoteContent{}
query := bson.M{"_id": bson.M{"$nin": noteIds}, "UserId": bson.ObjectIdHex(userId), "Content": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}}}
if isBlog {
@@ -419,9 +453,6 @@ func (this *NoteService) searchNoteFromContent(notes []info.Note, userId, key st
noteIds2[i] = content.NoteId
}
-// Log(" content search ")
-// Log(lenContent)
-
// 得到notes
notes2 := this.ListNotesByNoteIds(noteIds2)
@@ -446,8 +477,6 @@ func (this *NoteService) SearchNoteByTags(tags []string, userId string, pageNumb
// 总记录数
count, _ = q.Count()
- Log(count)
-
q.Sort(sortFieldR).
Skip(skipNum).
Limit(pageSize).
diff --git a/app/service/ShareService.go b/app/service/ShareService.go
index 8e80e55..ebad5b0 100644
--- a/app/service/ShareService.go
+++ b/app/service/ShareService.go
@@ -3,7 +3,7 @@ package service
import (
"github.com/leanote/leanote/app/info"
"github.com/leanote/leanote/app/db"
-// . "github.com/leanote/leanote/app/lea"
+ . "github.com/leanote/leanote/app/lea"
"gopkg.in/mgo.v2/bson"
"time"
"sort"
@@ -286,6 +286,28 @@ func (this *ShareService) AddShareNote(noteId string, perm int, userId, email st
return db.Insert(db.ShareNotes, shareNote), "", toUserId
}
+// updatedUserId是否有查看userId noteId的权限?
+func (this *ShareService) HasReadPerm(userId, updatedUserId, noteId string) bool {
+ if !db.Has(db.ShareNotes,
+ bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NoteId": bson.ObjectIdHex(noteId)}) {
+ // noteId的notebookId是否被共享了?
+ notebookId := noteService.GetNotebookId(noteId)
+ if notebookId.Hex() == "" {
+ return false
+ }
+
+ // 判断notebook是否被共享
+ if !db.Has(db.ShareNotebooks,
+ bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NotebookId": notebookId}) {
+ return false
+ } else {
+ return true
+ }
+ } else {
+ return true
+ }
+}
+
// updatedUserId是否有修改userId noteId的权限?
func (this *ShareService) HasUpdatePerm(userId, updatedUserId, noteId string) bool {
// 1. noteId是否被共享了?
@@ -334,14 +356,14 @@ func (this *ShareService) AddHasShareNote(userId, toUserId string) bool {
}
// userId是否被共享了noteId
-func (this *ShareService) hasSharedNote(noteId, myUserId string) bool {
+func (this *ShareService) HasSharedNote(noteId, myUserId string) bool {
return db.Has(db.ShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(myUserId), "NoteId": bson.ObjectIdHex(noteId)})
}
// noteId的notebook是否共享了给我
-func (this *ShareService) hasSharedNotebook(noteId, myUserId, sharedUserId string) bool {
- note := noteService.GetNote(noteId, sharedUserId)
- if note.NoteId != "" {
- return db.Has(db.ShareNotebooks, bson.M{"NotebookId": note.NotebookId,
+func (this *ShareService) HasSharedNotebook(noteId, myUserId, sharedUserId string) bool {
+ notebookId := noteService.GetNotebookId(noteId)
+ if notebookId != "" {
+ return db.Has(db.ShareNotebooks, bson.M{"NotebookId": notebookId,
"UserId": bson.ObjectIdHex(sharedUserId),
"ToUserId": bson.ObjectIdHex(myUserId),
})
@@ -355,7 +377,7 @@ func (this *ShareService) GetShareNoteContent(noteId, myUserId, sharedUserId str
noteContent = info.NoteContent{}
// 是否单独共享了该notebook
// 或者, 其notebook共享了我
- if this.hasSharedNote(noteId, myUserId) || this.hasSharedNotebook(noteId, myUserId, sharedUserId) {
+ if this.HasSharedNote(noteId, myUserId) || this.HasSharedNotebook(noteId, myUserId, sharedUserId) {
db.Get(db.NoteContents, noteId, ¬eContent)
} else {
}
@@ -507,4 +529,51 @@ func (this *ShareService) DeleteUserShareNoteAndNotebook(userId, toUserId string
db.DeleteAll(db.HasShareNotes, query);
return true
+}
+
+// 用户userId是否有修改noteId的权限
+func (this *ShareService) HasUpdateNotePerm(noteId, userId string) bool {
+ if noteId == "" || userId == "" {
+ return false;
+ }
+ note := noteService.GetNoteById(noteId)
+ LogJ(note);
+ if note.UserId != "" {
+ noteUserId := note.UserId.Hex()
+ if noteUserId != userId {
+ // 是否是有权限协作的
+ if this.HasUpdatePerm(noteUserId, userId, noteId) {
+ return true
+ } else {
+ return false;
+ }
+ } else {
+ return true
+ }
+ } else {
+ return false;
+ }
+}
+
+// 用户userId是否有修改noteId的权限
+func (this *ShareService) HasReadNotePerm(noteId, userId string) bool {
+ if noteId == "" || userId == "" {
+ return false;
+ }
+ note := noteService.GetNoteById(noteId)
+ if note.UserId != "" {
+ noteUserId := note.UserId.Hex()
+ if noteUserId != userId {
+ // 是否是有权限协作的
+ if this.HasReadPerm(noteUserId, userId, noteId) {
+ return true
+ } else {
+ return false;
+ }
+ } else {
+ return true
+ }
+ } else {
+ return false;
+ }
}
\ No newline at end of file
diff --git a/app/service/TrashService.go b/app/service/TrashService.go
index 23b972a..014e6ac 100644
--- a/app/service/TrashService.go
+++ b/app/service/TrashService.go
@@ -53,7 +53,15 @@ func (this *TrashService) recoverNote(noteId, notebookId, userId string) bool {
// 删除trash
func (this *TrashService) DeleteTrash(noteId, userId string) bool {
- return db.DeleteByIdAndUserId(db.Notes, noteId, userId)
+ // delete note's attachs
+ ok := attachService.DeleteAllAttachs(noteId, userId)
+
+ // delete note
+ ok = db.DeleteByIdAndUserId(db.Notes, noteId, userId)
+ // delete content
+ ok = db.DeleteByIdAndUserId(db.NoteContents, noteId, userId)
+
+ return ok
}
// 列出note, 排序规则, 还有分页
diff --git a/app/service/init.go b/app/service/init.go
index cd020c4..d8bf943 100644
--- a/app/service/init.go
+++ b/app/service/init.go
@@ -17,6 +17,9 @@ var userService *UserService
var tagService *TagService
var blogService *BlogService
var tokenService *TokenService
+var noteImageService *NoteImageService
+var fileService *FileService
+var attachService *AttachService
func init() {
notebookService = &NotebookService{}
@@ -28,4 +31,7 @@ func init() {
tagService = &TagService{}
blogService = &BlogService{}
tokenService = &TokenService{}
+ fileService = &FileService{}
+ attachService = &AttachService{}
+ noteImageService = &NoteImageService{}
}
\ No newline at end of file
diff --git a/app/views/Note/note-dev.html b/app/views/Note/note-dev.html
index d65a11c..088c817 100644
--- a/app/views/Note/note-dev.html
+++ b/app/views/Note/note-dev.html
@@ -353,6 +353,7 @@ function log(o) {
Sort
-->
+
@@ -466,6 +468,38 @@ function log(o) {