for safety image v1.0 #14
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@ -17,4 +17,4 @@ app/tmp/main.go
|
|||||||
.settings
|
.settings
|
||||||
.project
|
.project
|
||||||
public/config.codekit
|
public/config.codekit
|
||||||
|
files
|
||||||
|
@ -3,11 +3,13 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
// "encoding/json"
|
// "encoding/json"
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 首页
|
// 首页
|
||||||
@ -16,6 +18,7 @@ type File struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 上传图片 editor
|
// 上传图片 editor
|
||||||
|
// 过时
|
||||||
func (c File) UploadImage(renderHtml string) revel.Result {
|
func (c File) UploadImage(renderHtml string) revel.Result {
|
||||||
if renderHtml == "" {
|
if renderHtml == "" {
|
||||||
renderHtml = "file/image.html"
|
renderHtml = "file/image.html"
|
||||||
@ -31,6 +34,7 @@ func (c File) UploadImage(renderHtml string) revel.Result {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 上传的是博客logo
|
// 上传的是博客logo
|
||||||
|
// TODO logo不要设置权限, 另外的目录
|
||||||
func (c File) UploadBlogLogo() revel.Result {
|
func (c File) UploadBlogLogo() revel.Result {
|
||||||
return c.UploadImage("file/blog_logo.html");
|
return c.UploadImage("file/blog_logo.html");
|
||||||
}
|
}
|
||||||
@ -38,28 +42,25 @@ func (c File) UploadBlogLogo() revel.Result {
|
|||||||
// 拖拉上传, pasteImage
|
// 拖拉上传, pasteImage
|
||||||
func (c File) UploadImageJson(renderHtml, from string) revel.Result {
|
func (c File) UploadImageJson(renderHtml, from string) revel.Result {
|
||||||
re := c.uploadImage(from, "");
|
re := c.uploadImage(from, "");
|
||||||
re.Id = siteUrl + re.Id
|
|
||||||
// re.Id = re.Id
|
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// leaui image plugin
|
// leaui image plugin
|
||||||
func (c File) UploadImageLeaui(albumId string) revel.Result {
|
func (c File) UploadImageLeaui(albumId string) revel.Result {
|
||||||
re := c.uploadImage("", albumId);
|
re := c.uploadImage("", albumId);
|
||||||
re.Id = siteUrl + re.Id
|
|
||||||
// re.Id = re.Id
|
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 上传图片, 公用方法
|
// 上传图片, 公用方法
|
||||||
func (c File) uploadImage(from, albumId string) (re info.Re) {
|
func (c File) uploadImage(from, albumId string) (re info.Re) {
|
||||||
var fileUrlPath = ""
|
var fileUrlPath = ""
|
||||||
|
var fileId = ""
|
||||||
var resultCode = 0 // 1表示正常
|
var resultCode = 0 // 1表示正常
|
||||||
var resultMsg = "内部错误" // 错误信息
|
var resultMsg = "内部错误" // 错误信息
|
||||||
var Ok = false
|
var Ok = false
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
re.Id = fileUrlPath
|
re.Id = fileId
|
||||||
re.Code = resultCode
|
re.Code = resultCode
|
||||||
re.Msg = resultMsg
|
re.Msg = resultMsg
|
||||||
re.Ok = Ok
|
re.Ok = Ok
|
||||||
@ -71,11 +72,10 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
|
|||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
// 生成上传路径
|
// 生成上传路径
|
||||||
fileUrlPath = "/upload/" + c.GetUserId() + "/images"
|
fileUrlPath = "files/" + c.GetUserId() + "/images"
|
||||||
dir := revel.BasePath + "/public/" + fileUrlPath
|
dir := revel.BasePath + "/" + fileUrlPath
|
||||||
err = os.MkdirAll(dir, 0755)
|
err = os.MkdirAll(dir, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Log(err)
|
|
||||||
return re
|
return re
|
||||||
}
|
}
|
||||||
// 生成新的文件名
|
// 生成新的文件名
|
||||||
@ -126,8 +126,12 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
|
|||||||
Path: fileUrlPath,
|
Path: fileUrlPath,
|
||||||
Size: filesize}
|
Size: filesize}
|
||||||
|
|
||||||
|
id := bson.NewObjectId();
|
||||||
|
fileInfo.FileId = id
|
||||||
|
fileId = id.Hex()
|
||||||
Ok = fileService.AddImage(fileInfo, albumId, c.GetUserId())
|
Ok = fileService.AddImage(fileInfo, albumId, c.GetUserId())
|
||||||
|
|
||||||
|
fileInfo.Path = ""; // 不要返回
|
||||||
re.Item = fileInfo
|
re.Item = fileInfo
|
||||||
|
|
||||||
return re
|
return re
|
||||||
@ -197,4 +201,27 @@ func (c File) UpgradeLeauiImage() revel.Result {
|
|||||||
|
|
||||||
re.Msg = msg
|
re.Msg = msg
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------
|
||||||
|
|
||||||
|
// 输出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)
|
||||||
|
}
|
||||||
|
@ -117,7 +117,6 @@ type NoteOrContent struct {
|
|||||||
// 这里不能用json, 要用post
|
// 这里不能用json, 要用post
|
||||||
func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result {
|
func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result {
|
||||||
// 新添加note
|
// 新添加note
|
||||||
LogJ(noteOrContent)
|
|
||||||
if noteOrContent.IsNew {
|
if noteOrContent.IsNew {
|
||||||
userId := c.GetObjectUserId();
|
userId := c.GetObjectUserId();
|
||||||
myUserId := userId
|
myUserId := userId
|
||||||
|
@ -56,12 +56,13 @@ var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": tru
|
|||||||
"User": map[string]bool{"UpdateEmail": true,
|
"User": map[string]bool{"UpdateEmail": true,
|
||||||
"ActiveEmail":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 {
|
func needValidate(controller, method string) bool {
|
||||||
// 在里面
|
// 在里面
|
||||||
if v, ok := commonUrl[controller]; ok {
|
if v, ok := commonUrl[controller]; ok {
|
||||||
// 不在commonUrl里
|
// 在commonUrl里
|
||||||
if _, ok2 := v[method]; ok2 {
|
if _, ok2 := v[method]; ok2 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,8 @@ var Suggestions *mgo.Collection
|
|||||||
var Albums *mgo.Collection
|
var Albums *mgo.Collection
|
||||||
var Files *mgo.Collection
|
var Files *mgo.Collection
|
||||||
|
|
||||||
|
var NoteImages *mgo.Collection
|
||||||
|
|
||||||
// 初始化时连接数据库
|
// 初始化时连接数据库
|
||||||
func Init() {
|
func Init() {
|
||||||
var url string
|
var url string
|
||||||
@ -104,6 +106,8 @@ func Init() {
|
|||||||
// Album & file
|
// Album & file
|
||||||
Albums = Session.DB(dbname).C("albums")
|
Albums = Session.DB(dbname).C("albums")
|
||||||
Files = Session.DB(dbname).C("files")
|
Files = Session.DB(dbname).C("files")
|
||||||
|
|
||||||
|
NoteImages = Session.DB(dbname).C("note_images")
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -11,9 +11,11 @@ type File struct {
|
|||||||
AlbumId bson.ObjectId `bson:"AlbumId"`
|
AlbumId bson.ObjectId `bson:"AlbumId"`
|
||||||
Name string `Name` // file name
|
Name string `Name` // file name
|
||||||
Title string `Title` // file name or user defined for search
|
Title string `Title` // file name or user defined for search
|
||||||
Size int64 `Size` // file size (byte)
|
Size int64 `Size` // file size (byte)
|
||||||
Type string `Type` // file type, such as image/jpg
|
Type string `Type` // file type, "" = image, "doc" = word
|
||||||
Path string `Path` // the file path, based on /upload
|
Path string `Path` // the file path
|
||||||
IsDefaultAlbum bool `IsDefaultAlbum`
|
IsDefaultAlbum bool `IsDefaultAlbum`
|
||||||
CreatedTime time.Time `CreatedTime`
|
CreatedTime time.Time `CreatedTime`
|
||||||
|
|
||||||
|
FromFileId bson.ObjectId `bson:"FromFileId,omitempty"` // copy from fileId, for collaboration
|
||||||
}
|
}
|
||||||
|
12
app/info/NoteImage.go
Normal file
12
app/info/NoteImage.go
Normal file
@ -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
|
||||||
|
}
|
@ -24,6 +24,8 @@ type Note struct {
|
|||||||
|
|
||||||
IsMarkdown bool `IsMarkdown` // 是否是markdown笔记, 默认是false
|
IsMarkdown bool `IsMarkdown` // 是否是markdown笔记, 默认是false
|
||||||
|
|
||||||
|
AttachIds []string `FileIds,omitempty` // 2014/9/18, attachments
|
||||||
|
|
||||||
CreatedTime time.Time `CreatedTime`
|
CreatedTime time.Time `CreatedTime`
|
||||||
UpdatedTime time.Time `UpdatedTime`
|
UpdatedTime time.Time `UpdatedTime`
|
||||||
UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
|
UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
|
||||||
@ -54,11 +56,11 @@ type NoteAndContent struct {
|
|||||||
// 每一个历史记录对象
|
// 每一个历史记录对象
|
||||||
type EachHistory struct {
|
type EachHistory struct {
|
||||||
UpdatedUserId bson.ObjectId `UpdatedUserId`
|
UpdatedUserId bson.ObjectId `UpdatedUserId`
|
||||||
UpdatedTime time.Time `UpdatedTime`
|
UpdatedTime time.Time `UpdatedTime`
|
||||||
Content string `Content`
|
Content string `Content`
|
||||||
}
|
}
|
||||||
type NoteContentHistory struct {
|
type NoteContentHistory struct {
|
||||||
NoteId bson.ObjectId `bson:"_id,omitempty"`
|
NoteId bson.ObjectId `bson:"_id,omitempty"`
|
||||||
UserId bson.ObjectId `bson:"UserId"` // 所属者
|
UserId bson.ObjectId `bson:"UserId"` // 所属者
|
||||||
Histories []EachHistory `Histories`
|
Histories []EachHistory `Histories`
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"os"
|
"os"
|
||||||
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 分离文件名与扩展名(包含.)
|
// 分离文件名与扩展名(包含.)
|
||||||
@ -62,4 +63,18 @@ func ListDir(dir string) []string {
|
|||||||
}
|
}
|
||||||
names, _ := f.Readdirnames(0)
|
names, _ := f.Readdirnames(0)
|
||||||
return names
|
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)
|
||||||
}
|
}
|
@ -266,4 +266,16 @@ func RandomPwd(num int) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return str
|
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
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
"github.com/leanote/leanote/app/db"
|
"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)
|
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, "CreatedTime", false)
|
||||||
files := []info.File{}
|
files := []info.File{}
|
||||||
|
|
||||||
q := bson.M{"UserId": bson.ObjectIdHex(userId)}
|
q := bson.M{"UserId": bson.ObjectIdHex(userId), "Type": ""} // life
|
||||||
if albumId != "" {
|
if albumId != "" {
|
||||||
q["AlbumId"] = bson.ObjectIdHex(albumId);
|
q["AlbumId"] = bson.ObjectIdHex(albumId);
|
||||||
} else {
|
} else {
|
||||||
@ -89,6 +89,7 @@ func (this *FileService) DeleteImage(userId, fileId string) (bool, string) {
|
|||||||
if(file.FileId != "") {
|
if(file.FileId != "") {
|
||||||
if db.DeleteByIdAndUserId(db.Files, fileId, userId) {
|
if db.DeleteByIdAndUserId(db.Files, fileId, userId) {
|
||||||
// delete image
|
// delete image
|
||||||
|
// TODO
|
||||||
err := os.Remove(revel.BasePath + "/public/" + file.Path)
|
err := os.Remove(revel.BasePath + "/public/" + file.Path)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return true, ""
|
return true, ""
|
||||||
@ -103,4 +104,126 @@ func (this *FileService) DeleteImage(userId, fileId string) (bool, string) {
|
|||||||
// update image title
|
// update image title
|
||||||
func (this *FileService) UpdateImage(userId, fileId, title string) bool {
|
func (this *FileService) UpdateImage(userId, fileId, title string) bool {
|
||||||
return db.UpdateByIdAndUserIdField(db.Files, fileId, userId, "Title", title)
|
return db.UpdateByIdAndUserIdField(db.Files, fileId, userId, "Title", title)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取文件路径
|
||||||
|
// 要判断是否具有权限
|
||||||
|
// userId是否具有fileId的访问权限
|
||||||
|
func (this *FileService) GetFile(userId, fileId string) string {
|
||||||
|
if userId == "" || fileId == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
file := info.File{}
|
||||||
|
db.Get(db.Files, fileId, &file)
|
||||||
|
path := file.Path
|
||||||
|
if path == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. 判断权限
|
||||||
|
|
||||||
|
// 是否是我的文件
|
||||||
|
if 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, ""
|
||||||
|
}
|
||||||
|
Log(file)
|
||||||
|
|
||||||
|
_, 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)})
|
||||||
|
}
|
||||||
|
69
app/service/NoteImageService.go
Normal file
69
app/service/NoteImageService.go
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
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的关系
|
||||||
|
// <img src="/file/outputImage?fileId=12323232" />
|
||||||
|
// 图片必须是我的, 不然不添加
|
||||||
|
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)})
|
||||||
|
|
||||||
|
Log("--------ii--")
|
||||||
|
|
||||||
|
// 添加新的
|
||||||
|
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) {
|
||||||
|
Log("?????")
|
||||||
|
Log("<><><>")
|
||||||
|
noteImage.ImageId = bson.ObjectIdHex(fileId)
|
||||||
|
db.Insert(db.NoteImages, noteImage)
|
||||||
|
}
|
||||||
|
hasAdded[fileId] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
@ -17,6 +17,12 @@ func (this *NoteService) GetNote(noteId, userId string) (note info.Note) {
|
|||||||
db.GetByIdAndUserId(db.Notes, noteId, userId, ¬e)
|
db.GetByIdAndUserId(db.Notes, noteId, userId, ¬e)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// fileService调用
|
||||||
|
func (this *NoteService) GetNoteById(noteId string) (note info.Note) {
|
||||||
|
note = info.Note{}
|
||||||
|
db.Get(db.Notes, noteId, ¬e)
|
||||||
|
return
|
||||||
|
}
|
||||||
// 得到blog, blogService用
|
// 得到blog, blogService用
|
||||||
// 不要传userId, 因为是公开的
|
// 不要传userId, 因为是公开的
|
||||||
func (this *NoteService) GetBlogNote(noteId string) (note info.Note) {
|
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.UpdatedTime = noteContent.CreatedTime
|
||||||
noteContent.UpdatedUserId = noteContent.UserId
|
noteContent.UpdatedUserId = noteContent.UserId
|
||||||
db.Insert(db.NoteContents, noteContent)
|
db.Insert(db.NoteContents, noteContent)
|
||||||
|
|
||||||
|
// 更新笔记图片
|
||||||
|
noteImageService.UpdateNoteImages(noteContent.UserId.Hex(), noteContent.NoteId.Hex(), noteContent.Content)
|
||||||
|
|
||||||
return noteContent;
|
return noteContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,11 +247,23 @@ func (this *NoteService) UpdateNoteContent(userId, updatedUserId, noteId, conten
|
|||||||
Content: content,
|
Content: content,
|
||||||
UpdatedTime: time.Now(),
|
UpdatedTime: time.Now(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 更新笔记图片
|
||||||
|
noteImageService.UpdateNoteImages(userId, noteId, content)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
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
|
// 更新tags
|
||||||
// [ok] [del]
|
// [ok] [del]
|
||||||
func (this *NoteService) UpdateTags(noteId string, userId string, tags []string) bool {
|
func (this *NoteService) UpdateTags(noteId string, userId string, tags []string) bool {
|
||||||
@ -396,7 +418,6 @@ func (this *NoteService) searchNoteFromContent(notes []info.Note, userId, key st
|
|||||||
for i, note := range notes {
|
for i, note := range notes {
|
||||||
noteIds[i] = note.NoteId
|
noteIds[i] = note.NoteId
|
||||||
}
|
}
|
||||||
LogJ(noteIds)
|
|
||||||
noteContents := []info.NoteContent{}
|
noteContents := []info.NoteContent{}
|
||||||
query := bson.M{"_id": bson.M{"$nin": noteIds}, "UserId": bson.ObjectIdHex(userId), "Content": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}}}
|
query := bson.M{"_id": bson.M{"$nin": noteIds}, "UserId": bson.ObjectIdHex(userId), "Content": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}}}
|
||||||
if isBlog {
|
if isBlog {
|
||||||
@ -419,9 +440,6 @@ func (this *NoteService) searchNoteFromContent(notes []info.Note, userId, key st
|
|||||||
noteIds2[i] = content.NoteId
|
noteIds2[i] = content.NoteId
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log(" content search ")
|
|
||||||
// Log(lenContent)
|
|
||||||
|
|
||||||
// 得到notes
|
// 得到notes
|
||||||
notes2 := this.ListNotesByNoteIds(noteIds2)
|
notes2 := this.ListNotesByNoteIds(noteIds2)
|
||||||
|
|
||||||
@ -446,8 +464,6 @@ func (this *NoteService) SearchNoteByTags(tags []string, userId string, pageNumb
|
|||||||
// 总记录数
|
// 总记录数
|
||||||
count, _ = q.Count()
|
count, _ = q.Count()
|
||||||
|
|
||||||
Log(count)
|
|
||||||
|
|
||||||
q.Sort(sortFieldR).
|
q.Sort(sortFieldR).
|
||||||
Skip(skipNum).
|
Skip(skipNum).
|
||||||
Limit(pageSize).
|
Limit(pageSize).
|
||||||
|
@ -334,7 +334,7 @@ func (this *ShareService) AddHasShareNote(userId, toUserId string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// userId是否被共享了noteId
|
// 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)})
|
return db.Has(db.ShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(myUserId), "NoteId": bson.ObjectIdHex(noteId)})
|
||||||
}
|
}
|
||||||
// noteId的notebook是否共享了给我
|
// noteId的notebook是否共享了给我
|
||||||
@ -355,7 +355,7 @@ func (this *ShareService) GetShareNoteContent(noteId, myUserId, sharedUserId str
|
|||||||
noteContent = info.NoteContent{}
|
noteContent = info.NoteContent{}
|
||||||
// 是否单独共享了该notebook
|
// 是否单独共享了该notebook
|
||||||
// 或者, 其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)
|
db.Get(db.NoteContents, noteId, ¬eContent)
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,8 @@ var userService *UserService
|
|||||||
var tagService *TagService
|
var tagService *TagService
|
||||||
var blogService *BlogService
|
var blogService *BlogService
|
||||||
var tokenService *TokenService
|
var tokenService *TokenService
|
||||||
|
var noteImageService *NoteImageService
|
||||||
|
var fileService *FileService
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
notebookService = &NotebookService{}
|
notebookService = &NotebookService{}
|
||||||
@ -28,4 +30,6 @@ func init() {
|
|||||||
tagService = &TagService{}
|
tagService = &TagService{}
|
||||||
blogService = &BlogService{}
|
blogService = &BlogService{}
|
||||||
tokenService = &TokenService{}
|
tokenService = &TokenService{}
|
||||||
|
fileService = &FileService{}
|
||||||
|
noteImageService = &NoteImageService{}
|
||||||
}
|
}
|
@ -988,11 +988,13 @@ initSlimScroll();
|
|||||||
<script src="/public/mdeditor/editor/underscore-min.js"></script>
|
<script src="/public/mdeditor/editor/underscore-min.js"></script>
|
||||||
<script src="/public/mdeditor/editor/scrollLink.js"></script>
|
<script src="/public/mdeditor/editor/scrollLink.js"></script>
|
||||||
<!--mathjax-->
|
<!--mathjax-->
|
||||||
|
<!--
|
||||||
<script type="text/x-mathjax-config">
|
<script type="text/x-mathjax-config">
|
||||||
MathJax.Hub.Config({ tex2jax: { inlineMath: [['$','$'], ["\\(","\\)"]], processEscapes: true }, messageStyle: "none"});
|
MathJax.Hub.Config({ tex2jax: { inlineMath: [['$','$'], ["\\(","\\)"]], processEscapes: true }, messageStyle: "none"});
|
||||||
</script>
|
</script>
|
||||||
<script src="/public/mdeditor/editor/mathJax-min.js"></script>
|
<script src="/public/mdeditor/editor/mathJax-min.js"></script>
|
||||||
<script src="//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
<script src="//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||||||
|
-->
|
||||||
<script src="/public/mdeditor/editor/jquery.waitforimages-min.js"></script>
|
<script src="/public/mdeditor/editor/jquery.waitforimages-min.js"></script>
|
||||||
<script src="/public/mdeditor/editor/google-code-prettify/prettify.js"></script>
|
<script src="/public/mdeditor/editor/google-code-prettify/prettify.js"></script>
|
||||||
<script src="/public/mdeditor/editor/editor.js"></script>
|
<script src="/public/mdeditor/editor/editor.js"></script>
|
||||||
|
@ -71,6 +71,15 @@ Note.setNoteCache = function(content, clear) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 得到当前的笔记
|
||||||
|
Note.getCurNote = function() {
|
||||||
|
var self = this;
|
||||||
|
if(self.curNoteId == "") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return self.cache[self.curNoteId];
|
||||||
|
}
|
||||||
|
|
||||||
// 每当有notebookId相应的note改变时都要重新清空之
|
// 每当有notebookId相应的note改变时都要重新清空之
|
||||||
// 并设置该notebookId有值
|
// 并设置该notebookId有值
|
||||||
Note.clearCacheByNotebookId = function(notebookId) {
|
Note.clearCacheByNotebookId = function(notebookId) {
|
||||||
|
@ -93,8 +93,8 @@ Share.renderShareNotebooks = function(sharedUserInfos, shareNotebooks) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!shareNotebooks || typeof shareNotebooks != "object" || shareNotebooks.length < 0) {
|
if(!shareNotebooks || typeof shareNotebooks != "object" || shareNotebooks.length < 0) {
|
||||||
return;
|
shareNotebooks = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
var $shareNotebooks = $("#shareNotebooks");
|
var $shareNotebooks = $("#shareNotebooks");
|
||||||
|
@ -88,7 +88,7 @@ tinymce.PluginManager.add('leaui_image', function(editor, url) {
|
|||||||
d.height = img.getAttribute("data-height");
|
d.height = img.getAttribute("data-height");
|
||||||
d.title = img.getAttribute("data-title");
|
d.title = img.getAttribute("data-title");
|
||||||
|
|
||||||
datas.push(d);
|
datas.push(d);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -104,49 +104,63 @@ tinymce.PluginManager.add('leaui_image', function(editor, url) {
|
|||||||
}
|
}
|
||||||
data.src = trueSrc;
|
data.src = trueSrc;
|
||||||
|
|
||||||
/*
|
var renderImage = function(data) {
|
||||||
var width = "", height="", title="";
|
// 这里, 如果图片宽度过大, 这里设置成500px
|
||||||
if(data.width) {
|
var back = (function(data2, i) {
|
||||||
width = 'width="' + data.width +'" ';
|
var d = {};
|
||||||
}
|
var imgElm;
|
||||||
if(data.height) {
|
// 先显示loading...
|
||||||
height = 'height="' + data.height +'" ';
|
d.id = '__mcenew' + i;
|
||||||
}
|
d.src = "http://leanote.com/images/loading-24.gif";
|
||||||
if(data.title) {
|
imgElm = dom.createHTML('img', d);
|
||||||
title = 'title="' + data.title +'" ';
|
editor.insertContent(imgElm);
|
||||||
}
|
imgElm = dom.get(d.id);
|
||||||
var attrs = width + height + title;
|
|
||||||
editor.insertContent('<img ' + attrs + ' data-src="' + src + '" src="' + trueSrc + '" />');
|
|
||||||
*/
|
|
||||||
|
|
||||||
// 这里, 如果图片宽度过大, 这里设置成500px
|
|
||||||
var back = (function(data2, i) {
|
|
||||||
var d = {};
|
|
||||||
var imgElm;
|
|
||||||
// 先显示loading...
|
|
||||||
d.id = '__mcenew' + i;
|
|
||||||
d.src = "http://leanote.com/images/loading-24.gif";
|
|
||||||
imgElm = dom.createHTML('img', d);
|
|
||||||
editor.insertContent(imgElm);
|
|
||||||
imgElm = dom.get(d.id);
|
|
||||||
log(imgElm)
|
|
||||||
|
|
||||||
return function(wh) {
|
|
||||||
if(wh && wh.width) {
|
|
||||||
if(wh.width > 600) {
|
|
||||||
wh.width = 600;
|
|
||||||
}
|
|
||||||
data2.width = wh.width;
|
|
||||||
}
|
|
||||||
dom.setAttrib(imgElm, 'src', data2.src);
|
|
||||||
dom.setAttrib(imgElm, 'width', data2.width);
|
|
||||||
dom.setAttrib(imgElm, 'title', data2.title);
|
|
||||||
|
|
||||||
dom.setAttrib(imgElm, 'id', null);
|
return function(wh) {
|
||||||
|
if(wh && wh.width) {
|
||||||
|
if(wh.width > 600) {
|
||||||
|
wh.width = 600;
|
||||||
|
}
|
||||||
|
data2.width = wh.width;
|
||||||
|
}
|
||||||
|
dom.setAttrib(imgElm, 'src', data2.src);
|
||||||
|
dom.setAttrib(imgElm, 'width', data2.width);
|
||||||
|
dom.setAttrib(imgElm, 'title', data2.title);
|
||||||
|
|
||||||
|
dom.setAttrib(imgElm, 'id', null);
|
||||||
|
}
|
||||||
|
})(data, i);
|
||||||
|
getImageSize(data.src, back);
|
||||||
|
}
|
||||||
|
|
||||||
|
// outputImage?fileId=123232323
|
||||||
|
var fileId = "";
|
||||||
|
fileIds = trueSrc.split("fileId=")
|
||||||
|
if(fileIds.length == 2 && fileIds[1].length == "53aecf8a8a039a43c8036282".length) {
|
||||||
|
fileId = fileIds[1];
|
||||||
|
}
|
||||||
|
if(fileId) {
|
||||||
|
// 得到fileId, 如果这个笔记不是我的, 那么肯定是协作的笔记, 那么需要将图片copy给原note owner
|
||||||
|
var curNote = Note.getCurNote();
|
||||||
|
if(curNote && curNote.UserId != UserInfo.UserId) {
|
||||||
|
(function(data) {
|
||||||
|
ajaxPost("/file/copyImage", {userId: UserInfo.UserId, fileId: fileId, toUserId: curNote.UserId}, function(re) {
|
||||||
|
if(reIsOk(re) && re.Id) {
|
||||||
|
var urlPrefix = window.location.protocol + "//" + window.location.host;
|
||||||
|
data.src = urlPrefix + "/file/outputImage?fileId=" + re.Id;
|
||||||
|
}
|
||||||
|
renderImage(data);
|
||||||
|
});
|
||||||
|
})(data);
|
||||||
|
} else {
|
||||||
|
renderImage(data);
|
||||||
}
|
}
|
||||||
})(data, i);
|
} else {
|
||||||
getImageSize(data.src, back);
|
renderImage(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // end for
|
||||||
|
|
||||||
this.parent().parent().close();
|
this.parent().parent().close();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// for editor.
|
// for editor.
|
||||||
// drag image to editor
|
// drag image to editor
|
||||||
// Copyright leaui
|
// Copyright leaui
|
||||||
|
var urlPrefix = window.location.protocol + "//" + window.location.host;
|
||||||
define('leaui_image', ['jquery.ui.widget', 'fileupload'], function(){
|
define('leaui_image', ['jquery.ui.widget', 'fileupload'], function(){
|
||||||
var editor = tinymce.activeEditor;
|
var editor = tinymce.activeEditor;
|
||||||
var dom = editor.dom;
|
var dom = editor.dom;
|
||||||
@ -103,7 +103,8 @@ define('leaui_image', ['jquery.ui.widget', 'fileupload'], function(){
|
|||||||
done: function(e, data) {
|
done: function(e, data) {
|
||||||
if (data.result.Ok == true) {
|
if (data.result.Ok == true) {
|
||||||
data.context.remove();
|
data.context.remove();
|
||||||
var data2 = {src: data.result.Id}
|
// life
|
||||||
|
var data2 = {src: urlPrefix + "/file/outputImage?fileId=" + data.result.Id + "¬eId=" + Note.curNoteId}
|
||||||
insertImage(data2);
|
insertImage(data2);
|
||||||
} else {
|
} else {
|
||||||
data.context.empty();
|
data.context.empty();
|
||||||
|
@ -260,13 +260,19 @@ var o = {
|
|||||||
for(var i in datas){
|
for(var i in datas){
|
||||||
var each = datas[i];
|
var each = datas[i];
|
||||||
var classes = "";
|
var classes = "";
|
||||||
var src = urlPrefix + each.Path;
|
// life edit
|
||||||
|
// 之前的
|
||||||
|
if(each.Path != "" && each.Path.substr(0, 7) == "/upload") {
|
||||||
|
var src = urlPrefix + each.Path;
|
||||||
|
} else {
|
||||||
|
var src = urlPrefix + "/file/outputImage?fileId=" + each.FileId;
|
||||||
|
}
|
||||||
// log(src);
|
// log(src);
|
||||||
if(selectedMap[src]) {
|
if(selectedMap[src]) {
|
||||||
classes = 'class="selected"';
|
classes = 'class="selected"';
|
||||||
}
|
}
|
||||||
html += '<li ' + classes + '>';
|
html += '<li ' + classes + '>';
|
||||||
html += '<a title="" href="javascript:;" class="a-img"><img alt="" data-original="' + src + '" ></a>';
|
html += '<a title="" href="javascript:;" class="a-img"><img alt="" data-original="' + src + '" ></a>';
|
||||||
// html += '<div class="tools"><a href="javascript:;" class="del" data-id="' + each.FileId + '"><span class="glyphicon glyphicon-trash"></span></a></div>';
|
// html += '<div class="tools"><a href="javascript:;" class="del" data-id="' + each.FileId + '"><span class="glyphicon glyphicon-trash"></span></a></div>';
|
||||||
html += '<div class="tools clearfix" data-id="' + each.FileId + '"><div class="file-title pull-left">' + each.Title + '</div><div class="pull-right"><a href="javascript:;" class="del" data-id="' + each.FileId + '"><span class="glyphicon glyphicon-trash"></span></a></div></div>';
|
html += '<div class="tools clearfix" data-id="' + each.FileId + '"><div class="file-title pull-left">' + each.Title + '</div><div class="pull-right"><a href="javascript:;" class="del" data-id="' + each.FileId + '"><span class="glyphicon glyphicon-trash"></span></a></div></div>';
|
||||||
html += "</li>";
|
html += "</li>";
|
||||||
@ -348,10 +354,11 @@ var o = {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// life 为了图片安全
|
||||||
if(typeof $li == "object") {
|
if(typeof $li == "object") {
|
||||||
var src = $li.find("img").attr('src');
|
var src = $li.find("img").attr('src');
|
||||||
} else {
|
} else {
|
||||||
src = $li;
|
src = urlPrefix + "/file/outputImage?fileId=" + $li;
|
||||||
}
|
}
|
||||||
this.selectedImages.push(src);
|
this.selectedImages.push(src);
|
||||||
this.reRenderSelectedImages(false, src);
|
this.reRenderSelectedImages(false, src);
|
||||||
|
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user