Merge branch 'feature-blog-theme'
This commit is contained in:
commit
4d7a9c8089
518 files changed
+25660
-1010
No files matched your search
@@ -11,6 +11,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"io"
|
"io"
|
||||||
|
"fmt"
|
||||||
"archive/tar"
|
"archive/tar"
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
)
|
)
|
||||||
@@ -56,8 +57,12 @@ func (c Attach) uploadAttach(noteId string) (re info.Re) {
|
|||||||
return re
|
return re
|
||||||
}
|
}
|
||||||
// > 5M?
|
// > 5M?
|
||||||
if(len(data) > 5 * 1024 * 1024) {
|
maxFileSize := configService.GetUploadSize("uploadAttachSize");
|
||||||
resultMsg = "File is bigger than 5M"
|
if maxFileSize <= 0 {
|
||||||
|
maxFileSize = 1000
|
||||||
|
}
|
||||||
|
if(float64(len(data)) > maxFileSize * float64(1024*1024)) {
|
||||||
|
resultMsg = fmt.Sprintf("附件大于%vM", maxFileSize)
|
||||||
return re
|
return re
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ func (c BaseController) SetLocale() string {
|
|||||||
lang = "en";
|
lang = "en";
|
||||||
}
|
}
|
||||||
c.RenderArgs["locale"] = lang;
|
c.RenderArgs["locale"] = lang;
|
||||||
c.RenderArgs["siteUrl"] = siteUrl;
|
c.RenderArgs["siteUrl"] = configService.GetSiteUrl();
|
||||||
|
|
||||||
c.RenderArgs["blogUrl"] = configService.GetBlogUrl()
|
c.RenderArgs["blogUrl"] = configService.GetBlogUrl()
|
||||||
c.RenderArgs["leaUrl"] = configService.GetLeaUrl()
|
c.RenderArgs["leaUrl"] = configService.GetLeaUrl()
|
||||||
@@ -196,6 +196,9 @@ func (c BaseController) SetLocale() string {
|
|||||||
func (c BaseController) SetUserInfo() {
|
func (c BaseController) SetUserInfo() {
|
||||||
userInfo := c.GetUserInfo()
|
userInfo := c.GetUserInfo()
|
||||||
c.RenderArgs["userInfo"] = userInfo
|
c.RenderArgs["userInfo"] = userInfo
|
||||||
|
if(userInfo.Username == configService.GetAdminUsername()) {
|
||||||
|
c.RenderArgs["isAdmin"] = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// life
|
// life
|
||||||
@@ -239,4 +242,4 @@ func (c BaseController) RenderRe(re info.Re) revel.Result {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
+668
-335
File diff suppressed because it is too large.
Load diff
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -21,7 +22,7 @@ type File struct {
|
|||||||
// 上传的是博客logo
|
// 上传的是博客logo
|
||||||
// TODO logo不要设置权限, 另外的目录
|
// TODO logo不要设置权限, 另外的目录
|
||||||
func (c File) UploadBlogLogo() revel.Result {
|
func (c File) UploadBlogLogo() revel.Result {
|
||||||
re := c.uploadImage("logo", "");
|
re := c.uploadImage("blogLogo", "");
|
||||||
|
|
||||||
c.RenderArgs["fileUrlPath"] = re.Id
|
c.RenderArgs["fileUrlPath"] = re.Id
|
||||||
c.RenderArgs["resultCode"] = re.Code
|
c.RenderArgs["resultCode"] = re.Code
|
||||||
@@ -100,7 +101,7 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
|
|||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
// 生成上传路径
|
// 生成上传路径
|
||||||
if(from == "logo") {
|
if(from == "logo" || from == "blogLogo") {
|
||||||
fileUrlPath = "public/upload/" + c.GetUserId() + "/images/logo"
|
fileUrlPath = "public/upload/" + c.GetUserId() + "/images/logo"
|
||||||
} else {
|
} else {
|
||||||
fileUrlPath = "files/" + c.GetUserId() + "/images"
|
fileUrlPath = "files/" + c.GetUserId() + "/images"
|
||||||
@@ -131,10 +132,22 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
|
|||||||
return re
|
return re
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var maxFileSize float64
|
||||||
|
if(from == "logo") {
|
||||||
|
maxFileSize = configService.GetUploadSize("uploadAvatarSize");
|
||||||
|
} else if from == "blogLogo" {
|
||||||
|
maxFileSize = configService.GetUploadSize("uploadBlogLogoSize");
|
||||||
|
} else {
|
||||||
|
maxFileSize = configService.GetUploadSize("uploadImageSize");
|
||||||
|
}
|
||||||
|
if maxFileSize <= 0 {
|
||||||
|
maxFileSize = 1000
|
||||||
|
}
|
||||||
|
|
||||||
// > 2M?
|
// > 2M?
|
||||||
if(len(data) > 5 * 1024 * 1024) {
|
if(float64(len(data)) > maxFileSize * float64(1024*1024)) {
|
||||||
resultCode = 0
|
resultCode = 0
|
||||||
resultMsg = "图片大于2M"
|
resultMsg = fmt.Sprintf("图片大于%vM", maxFileSize)
|
||||||
return re
|
return re
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +174,7 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
|
|||||||
id := bson.NewObjectId();
|
id := bson.NewObjectId();
|
||||||
fileInfo.FileId = id
|
fileInfo.FileId = id
|
||||||
fileId = id.Hex()
|
fileId = id.Hex()
|
||||||
if(from == "logo") {
|
if(from == "logo" || from == "blogLogo") {
|
||||||
fileId = "public/upload/" + c.GetUserId() + "/images/logo/" + filename
|
fileId = "public/upload/" + c.GetUserId() + "/images/logo/" + filename
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,7 +316,7 @@ func (c File) UploadImage(renderHtml string) revel.Result {
|
|||||||
|
|
||||||
re := c.uploadImage("", "");
|
re := c.uploadImage("", "");
|
||||||
|
|
||||||
c.RenderArgs["fileUrlPath"] = siteUrl + re.Id
|
c.RenderArgs["fileUrlPath"] = configService.GetSiteUrl() + re.Id
|
||||||
c.RenderArgs["resultCode"] = re.Code
|
c.RenderArgs["resultCode"] = re.Code
|
||||||
c.RenderArgs["resultMsg"] = re.Msg
|
c.RenderArgs["resultMsg"] = re.Msg
|
||||||
|
|
||||||
@@ -314,4 +327,4 @@ func (c File) UploadImage(renderHtml string) revel.Result {
|
|||||||
func (c File) UploadImageJson(from, noteId string) revel.Result {
|
func (c File) UploadImageJson(from, noteId string) revel.Result {
|
||||||
re := c.uploadImage(from, "");
|
re := c.uploadImage(from, "");
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,10 @@ type Index struct {
|
|||||||
|
|
||||||
// leanote展示页, 没有登录的, 或已登录明确要进该页的
|
// leanote展示页, 没有登录的, 或已登录明确要进该页的
|
||||||
func (c Index) Index() revel.Result {
|
func (c Index) Index() revel.Result {
|
||||||
|
if configService.HomePageIsAdminsBlog(){
|
||||||
|
blog := Blog{c.BaseController}
|
||||||
|
return blog.Index(configService.GetAdminUsername());
|
||||||
|
}
|
||||||
c.SetUserInfo()
|
c.SetUserInfo()
|
||||||
c.RenderArgs["title"] = "leanote"
|
c.RenderArgs["title"] = "leanote"
|
||||||
c.RenderArgs["openRegister"] = configService.GlobalStringConfigs["openRegister"]
|
c.RenderArgs["openRegister"] = configService.GlobalStringConfigs["openRegister"]
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
// "time"
|
||||||
// "github.com/leanote/leanote/app/types"
|
// "github.com/leanote/leanote/app/types"
|
||||||
// "io/ioutil"
|
// "io/ioutil"
|
||||||
// "fmt"
|
// "fmt"
|
||||||
@@ -52,8 +53,9 @@ func (c Note) Index() revel.Result {
|
|||||||
}
|
}
|
||||||
// 当然, 还需要得到第一个notes的content
|
// 当然, 还需要得到第一个notes的content
|
||||||
//...
|
//...
|
||||||
|
Log(configService.GetAdminUsername())
|
||||||
|
c.RenderArgs["isAdmin"] = configService.GetAdminUsername() == userInfo.Username
|
||||||
|
|
||||||
c.RenderArgs["isAdmin"] = leanoteUserId == userInfo.Username
|
|
||||||
c.RenderArgs["userInfo"] = userInfo
|
c.RenderArgs["userInfo"] = userInfo
|
||||||
c.RenderArgs["userInfoJson"] = c.Json(userInfo)
|
c.RenderArgs["userInfoJson"] = c.Json(userInfo)
|
||||||
c.RenderArgs["notebooks"] = c.Json(notebooks)
|
c.RenderArgs["notebooks"] = c.Json(notebooks)
|
||||||
@@ -66,6 +68,8 @@ func (c Note) Index() revel.Result {
|
|||||||
|
|
||||||
c.RenderArgs["tagsJson"] = c.Json(tagService.GetTags(c.GetUserId()))
|
c.RenderArgs["tagsJson"] = c.Json(tagService.GetTags(c.GetUserId()))
|
||||||
|
|
||||||
|
c.RenderArgs["globalConfigs"] = configService.GetGlobalConfigForUser()
|
||||||
|
|
||||||
if isDev, _ := revel.Config.Bool("mode.dev"); isDev {
|
if isDev, _ := revel.Config.Bool("mode.dev"); isDev {
|
||||||
return c.RenderTemplate("note/note-dev.html")
|
return c.RenderTemplate("note/note-dev.html")
|
||||||
} else {
|
} else {
|
||||||
@@ -121,7 +125,7 @@ func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result {
|
|||||||
// 新添加note
|
// 新添加note
|
||||||
if noteOrContent.IsNew {
|
if noteOrContent.IsNew {
|
||||||
userId := c.GetObjectUserId();
|
userId := c.GetObjectUserId();
|
||||||
myUserId := userId
|
// myUserId := userId
|
||||||
// 为共享新建?
|
// 为共享新建?
|
||||||
if noteOrContent.FromUserId != "" {
|
if noteOrContent.FromUserId != "" {
|
||||||
userId = bson.ObjectIdHex(noteOrContent.FromUserId)
|
userId = bson.ObjectIdHex(noteOrContent.FromUserId)
|
||||||
@@ -143,7 +147,7 @@ func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result {
|
|||||||
Content: noteOrContent.Content,
|
Content: noteOrContent.Content,
|
||||||
Abstract: noteOrContent.Abstract};
|
Abstract: noteOrContent.Abstract};
|
||||||
|
|
||||||
note = noteService.AddNoteAndContent(note, noteContent, myUserId)
|
note = noteService.AddNoteAndContentForController(note, noteContent, c.GetUserId())
|
||||||
return c.RenderJson(note)
|
return c.RenderJson(note)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,7 +300,7 @@ func (c Note) Html2Image(noteId string) revel.Result {
|
|||||||
appKey, _ := revel.Config.String("app.secret")
|
appKey, _ := revel.Config.String("app.secret")
|
||||||
cookieDomain, _ := revel.Config.String("cookie.domain")
|
cookieDomain, _ := revel.Config.String("cookie.domain")
|
||||||
// 生成之
|
// 生成之
|
||||||
url := siteUrl + "/note/toImage?noteId=" + noteId + "&appKey=" + appKey;
|
url := configService.GetSiteUrl() + "/note/toImage?noteId=" + noteId + "&appKey=" + appKey;
|
||||||
// /Users/life/Documents/bin/phantomjs/bin/phantomjs /Users/life/Desktop/test/b.js
|
// /Users/life/Documents/bin/phantomjs/bin/phantomjs /Users/life/Desktop/test/b.js
|
||||||
binPath := configService.GetGlobalStringConfig("toImageBinPath")
|
binPath := configService.GetGlobalStringConfig("toImageBinPath")
|
||||||
if binPath == "" {
|
if binPath == "" {
|
||||||
@@ -350,4 +354,10 @@ func (c Note) Html2Image(noteId string) revel.Result {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设置/取消Blog; 置顶
|
||||||
|
func (c Note) SetNote2Blog(noteId string, isBlog, isTop bool) revel.Result {
|
||||||
|
re := noteService.ToBlog(c.GetUserId(), noteId, isBlog, isTop)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
@@ -68,4 +68,10 @@ func (c Notebook) DragNotebooks(data string) revel.Result {
|
|||||||
json.Unmarshal([]byte(data), &info)
|
json.Unmarshal([]byte(data), &info)
|
||||||
|
|
||||||
return c.RenderJson(notebookService.DragNotebooks(c.GetUserId(), info.CurNotebookId, info.ParentNotebookId, info.Siblings))
|
return c.RenderJson(notebookService.DragNotebooks(c.GetUserId(), info.CurNotebookId, info.ParentNotebookId, info.Siblings))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置notebook <-> blog
|
||||||
|
func (c Notebook) SetNotebook2Blog(notebookId string, isBlog bool) revel.Result {
|
||||||
|
re := notebookService.ToBlog(c.GetUserId(), notebookId, isBlog)
|
||||||
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
// "strings"
|
||||||
|
// "time"
|
||||||
|
// "encoding/json"
|
||||||
|
// "github.com/leanote/leanote/app/info"
|
||||||
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
|
// "github.com/leanote/leanote/app/lea/blog"
|
||||||
|
// "gopkg.in/mgo.v2/bson"
|
||||||
|
// "github.com/leanote/leanote/app/types"
|
||||||
|
// "io/ioutil"
|
||||||
|
// "math"
|
||||||
|
// "os"
|
||||||
|
// "path"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Preview struct {
|
||||||
|
Blog
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到要预览的主题绝对路径
|
||||||
|
func (c Preview) getPreviewThemeAbsolutePath(themeId string) bool {
|
||||||
|
if themeId != "" {
|
||||||
|
c.Session["themeId"] = themeId // 存到session中, 下次的url就不能带了
|
||||||
|
} else {
|
||||||
|
themeId = c.Session["themeId"] // 直接从session中获取
|
||||||
|
}
|
||||||
|
if themeId == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
theme := themeService.GetTheme(c.GetUserId(), themeId)
|
||||||
|
|
||||||
|
c.RenderArgs["isPreview"] = true
|
||||||
|
c.RenderArgs["themePath"] = theme.Path
|
||||||
|
if theme.Path == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Preview) Index(userIdOrEmail string, themeId string) revel.Result {
|
||||||
|
if !c.getPreviewThemeAbsolutePath(themeId) {
|
||||||
|
return c.E404()
|
||||||
|
}
|
||||||
|
return c.Blog.Index(c.GetUserId())
|
||||||
|
// return blog.RenderTemplate("index.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(themeId))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Preview) Tag(userIdOrEmail, tag string) revel.Result {
|
||||||
|
if !c.getPreviewThemeAbsolutePath("") {
|
||||||
|
return c.E404()
|
||||||
|
}
|
||||||
|
return c.Blog.Tag(c.GetUserId(), tag)
|
||||||
|
}
|
||||||
|
func (c Preview) Tags(userIdOrEmail string) revel.Result {
|
||||||
|
if !c.getPreviewThemeAbsolutePath("") {
|
||||||
|
return c.E404()
|
||||||
|
}
|
||||||
|
return c.Blog.Tags(c.GetUserId())
|
||||||
|
// if tag == "" {
|
||||||
|
// return blog.RenderTemplate("tags.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||||
|
// }
|
||||||
|
// return blog.RenderTemplate("tag_posts.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||||
|
}
|
||||||
|
func (c Preview) Archives(userIdOrEmail string, notebookId string, year, month int) revel.Result {
|
||||||
|
if !c.getPreviewThemeAbsolutePath("") {
|
||||||
|
return c.E404()
|
||||||
|
}
|
||||||
|
return c.Blog.Archives(c.GetUserId(), notebookId, year, month)
|
||||||
|
// return blog.RenderTemplate("archive.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||||
|
}
|
||||||
|
func (c Preview) Cate(userIdOrEmail, notebookId string) revel.Result {
|
||||||
|
if !c.getPreviewThemeAbsolutePath("") {
|
||||||
|
return c.E404()
|
||||||
|
}
|
||||||
|
return c.Blog.Cate(userIdOrEmail, notebookId)
|
||||||
|
// return blog.RenderTemplate("cate.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||||
|
}
|
||||||
|
func (c Preview) Post(userIdOrEmail, noteId string) revel.Result {
|
||||||
|
if !c.getPreviewThemeAbsolutePath("") {
|
||||||
|
return c.E404()
|
||||||
|
}
|
||||||
|
return c.Blog.Post(userIdOrEmail, noteId)
|
||||||
|
// return blog.RenderTemplate("view.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||||
|
}
|
||||||
|
func (c Preview) Single(userIdOrEmail, singleId string) revel.Result {
|
||||||
|
if !c.getPreviewThemeAbsolutePath("") {
|
||||||
|
return c.E404()
|
||||||
|
}
|
||||||
|
return c.Blog.Single(userIdOrEmail, singleId)
|
||||||
|
// return blog.RenderTemplate("single.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||||
|
}
|
||||||
|
func (c Preview) Search(userIdOrEmail, keywords string) revel.Result {
|
||||||
|
if !c.getPreviewThemeAbsolutePath("") {
|
||||||
|
return c.E404()
|
||||||
|
}
|
||||||
|
return c.Blog.Search(c.GetUserId(), keywords)
|
||||||
|
// return blog.RenderTemplate("search.html", c.RenderArgs, c.getPreviewThemeAbsolutePath(""))
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
// "encoding/json"
|
// "encoding/json"
|
||||||
// "gopkg.in/mgo.v2/bson"
|
// "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"
|
||||||
// "github.com/leanote/leanote/app/types"
|
// "github.com/leanote/leanote/app/types"
|
||||||
// "io/ioutil"
|
// "io/ioutil"
|
||||||
@@ -87,6 +87,8 @@ func (c Share) ListNoteShareUserInfo(noteId string) revel.Result {
|
|||||||
noteShareUserInfos := shareService.ListNoteShareUserInfo(noteId, c.GetUserId())
|
noteShareUserInfos := shareService.ListNoteShareUserInfo(noteId, c.GetUserId())
|
||||||
c.RenderArgs["noteOrNotebookShareUserInfos"] = noteShareUserInfos
|
c.RenderArgs["noteOrNotebookShareUserInfos"] = noteShareUserInfos
|
||||||
|
|
||||||
|
c.RenderArgs["noteOrNotebookShareGroupInfos"] = shareService.GetNoteShareGroups(noteId, c.GetUserId())
|
||||||
|
|
||||||
c.RenderArgs["isNote"] = true
|
c.RenderArgs["isNote"] = true
|
||||||
c.RenderArgs["noteOrNotebookId"] = note.NoteId.Hex();
|
c.RenderArgs["noteOrNotebookId"] = note.NoteId.Hex();
|
||||||
c.RenderArgs["title"] = note.Title
|
c.RenderArgs["title"] = note.Title
|
||||||
@@ -99,6 +101,9 @@ func (c Share) ListNotebookShareUserInfo(notebookId string) revel.Result {
|
|||||||
notebookShareUserInfos := shareService.ListNotebookShareUserInfo(notebookId, c.GetUserId())
|
notebookShareUserInfos := shareService.ListNotebookShareUserInfo(notebookId, c.GetUserId())
|
||||||
c.RenderArgs["noteOrNotebookShareUserInfos"] = notebookShareUserInfos
|
c.RenderArgs["noteOrNotebookShareUserInfos"] = notebookShareUserInfos
|
||||||
|
|
||||||
|
c.RenderArgs["noteOrNotebookShareGroupInfos"] = shareService.GetNotebookShareGroups(notebookId, c.GetUserId())
|
||||||
|
LogJ(c.RenderArgs["noteOrNotebookShareGroupInfos"])
|
||||||
|
|
||||||
c.RenderArgs["isNote"] = false
|
c.RenderArgs["isNote"] = false
|
||||||
c.RenderArgs["noteOrNotebookId"] = notebook.NotebookId.Hex();
|
c.RenderArgs["noteOrNotebookId"] = notebook.NotebookId.Hex();
|
||||||
c.RenderArgs["title"] = notebook.Title
|
c.RenderArgs["title"] = notebook.Title
|
||||||
@@ -139,4 +144,45 @@ func (c Share) DeleteShareNotebookBySharedUser(notebookId string, fromUserId str
|
|||||||
// 删除fromUserId分享给我的所有note, notebook
|
// 删除fromUserId分享给我的所有note, notebook
|
||||||
func (c Share) DeleteUserShareNoteAndNotebook(fromUserId string) revel.Result {
|
func (c Share) DeleteUserShareNoteAndNotebook(fromUserId string) revel.Result {
|
||||||
return c.RenderJson(shareService.DeleteUserShareNoteAndNotebook(fromUserId, c.GetUserId()));
|
return c.RenderJson(shareService.DeleteUserShareNoteAndNotebook(fromUserId, c.GetUserId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------
|
||||||
|
// 用户组
|
||||||
|
|
||||||
|
|
||||||
|
// 将笔记分享给分组
|
||||||
|
func (c Share) AddShareNoteGroup(noteId, groupId string, perm int) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = shareService.AddShareNoteGroup(c.GetUserId(), noteId, groupId, perm);
|
||||||
|
return c.RenderJson(re);
|
||||||
|
}
|
||||||
|
// 删除
|
||||||
|
func (c Share) DeleteShareNoteGroup(noteId, groupId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = shareService.DeleteShareNoteGroup(c.GetUserId(), noteId, groupId);
|
||||||
|
return c.RenderJson(re);
|
||||||
|
}
|
||||||
|
// 更新, 也是一样, 先删后加
|
||||||
|
func (c Share) UpdateShareNoteGroupPerm(noteId, groupId string, perm int) revel.Result {
|
||||||
|
return c.AddShareNoteGroup(noteId, groupId, perm)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//------
|
||||||
|
|
||||||
|
// 将笔记分享给分组
|
||||||
|
func (c Share) AddShareNotebookGroup(notebookId, groupId string, perm int) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = shareService.AddShareNotebookGroup(c.GetUserId(), notebookId, groupId, perm);
|
||||||
|
return c.RenderJson(re);
|
||||||
|
}
|
||||||
|
// 删除
|
||||||
|
func (c Share) DeleteShareNotebookGroup(notebookId, groupId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = shareService.DeleteShareNotebookGroup(c.GetUserId(), notebookId, groupId);
|
||||||
|
return c.RenderJson(re);
|
||||||
|
}
|
||||||
|
// 更新, 也是一样, 先删后加
|
||||||
|
func (c Share) UpdateShareNotebookGroupPerm(notebookId, groupId string, perm int) revel.Result {
|
||||||
|
return c.AddShareNotebookGroup(notebookId, groupId, perm)
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,7 @@ type AdminBlog struct {
|
|||||||
func (c AdminBlog) Index(sorter, keywords string) revel.Result {
|
func (c AdminBlog) Index(sorter, keywords string) revel.Result {
|
||||||
pageNumber := c.GetPage()
|
pageNumber := c.GetPage()
|
||||||
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "userId", "isRecommed", "createdTime"});
|
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "userId", "isRecommed", "createdTime"});
|
||||||
pageInfo, blogs := blogService.ListAllBlogs("", keywords, false, pageNumber, userPageSize, sorterField, isAsc);
|
pageInfo, blogs := blogService.ListAllBlogs("", "", keywords, false, pageNumber, userPageSize, sorterField, isAsc);
|
||||||
c.RenderArgs["pageInfo"] = pageInfo
|
c.RenderArgs["pageInfo"] = pageInfo
|
||||||
c.RenderArgs["blogs"] = blogs
|
c.RenderArgs["blogs"] = blogs
|
||||||
c.RenderArgs["keywords"] = keywords
|
c.RenderArgs["keywords"] = keywords
|
||||||
@@ -27,4 +27,4 @@ func (c AdminBlog) SetRecommend(noteId string, recommend bool) revel.Result {
|
|||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = blogService.SetRecommend(noteId, recommend);
|
re.Ok = blogService.SetRecommend(noteId, recommend);
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
@@ -18,8 +18,8 @@ func (c Admin) Index() revel.Result {
|
|||||||
c.SetLocale()
|
c.SetLocale()
|
||||||
|
|
||||||
c.RenderArgs["countUser"] = userService.CountUser()
|
c.RenderArgs["countUser"] = userService.CountUser()
|
||||||
c.RenderArgs["countNote"] = noteService.CountNote()
|
c.RenderArgs["countNote"] = noteService.CountNote("")
|
||||||
c.RenderArgs["countBlog"] = noteService.CountBlog()
|
c.RenderArgs["countBlog"] = noteService.CountBlog("")
|
||||||
|
|
||||||
return c.RenderTemplate("admin/index.html");
|
return c.RenderTemplate("admin/index.html");
|
||||||
}
|
}
|
||||||
@@ -30,6 +30,7 @@ func (c Admin) T(t string) revel.Result {
|
|||||||
c.RenderArgs["arr"] = configService.GlobalArrayConfigs
|
c.RenderArgs["arr"] = configService.GlobalArrayConfigs
|
||||||
c.RenderArgs["map"] = configService.GlobalMapConfigs
|
c.RenderArgs["map"] = configService.GlobalMapConfigs
|
||||||
c.RenderArgs["arrMap"] = configService.GlobalArrMapConfigs
|
c.RenderArgs["arrMap"] = configService.GlobalArrMapConfigs
|
||||||
|
c.RenderArgs["version"] = configService.GetVersion()
|
||||||
return c.RenderTemplate("admin/" + t + ".html")
|
return c.RenderTemplate("admin/" + t + ".html")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
// . "github.com/leanote/leanote/app/lea"
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
"strings"
|
"strings"
|
||||||
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// admin 首页
|
// admin 首页
|
||||||
@@ -110,10 +111,28 @@ func (c AdminSetting) OpenRegister(openRegister string) revel.Result {
|
|||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c AdminSetting) HomePage(homePage string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
if homePage == "0" {
|
||||||
|
homePage = ""
|
||||||
|
}
|
||||||
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "homePage", homePage)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
func (c AdminSetting) Mongodb(mongodumpPath, mongorestorePath string) revel.Result {
|
func (c AdminSetting) Mongodb(mongodumpPath, mongorestorePath string) revel.Result {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "mongodumpPath", mongodumpPath)
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "mongodumpPath", mongodumpPath)
|
||||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "mongorestorePath", mongorestorePath)
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "mongorestorePath", mongorestorePath)
|
||||||
|
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c AdminSetting) UploadSize(uploadImageSize, uploadAvatarSize, uploadBlogLogoSize, uploadAttachSize float64) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadImageSize", fmt.Sprintf("%v", uploadImageSize))
|
||||||
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadAvatarSize", fmt.Sprintf("%v", uploadAvatarSize))
|
||||||
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadBlogLogoSize", fmt.Sprintf("%v", uploadBlogLogoSize))
|
||||||
|
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadAttachSize", fmt.Sprintf("%v", uploadAttachSize))
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@ package admin
|
|||||||
import (
|
import (
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
// "encoding/json"
|
// "encoding/json"
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
"github.com/leanote/leanote/app/info"
|
||||||
// "io/ioutil"
|
// "io/ioutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,4 +15,10 @@ type AdminUpgrade struct {
|
|||||||
func (c AdminUpgrade) UpgradeBlog() revel.Result {
|
func (c AdminUpgrade) UpgradeBlog() revel.Result {
|
||||||
upgradeService.UpgradeBlog()
|
upgradeService.UpgradeBlog()
|
||||||
return nil;
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c AdminUpgrade) UpgradeBetaToBeta2() revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok, re.Msg = upgradeService.UpgradeBetaToBeta2(c.GetUserId())
|
||||||
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,9 @@ package admin
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
// "time"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
)
|
)
|
||||||
|
|
||||||
// admin 首页
|
// admin 首页
|
||||||
@@ -13,10 +15,13 @@ type AdminUser struct {
|
|||||||
|
|
||||||
// admin 主页
|
// admin 主页
|
||||||
var userPageSize = 10
|
var userPageSize = 10
|
||||||
func (c AdminUser) Index(sorter, keywords string) revel.Result {
|
func (c AdminUser) Index(sorter, keywords string, pageSize int) revel.Result {
|
||||||
pageNumber := c.GetPage()
|
pageNumber := c.GetPage()
|
||||||
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "username", "verified", "createdTime"});
|
if userPageSize == 0 {
|
||||||
pageInfo, users := userService.ListUsers(pageNumber, userPageSize, sorterField, isAsc, keywords);
|
pageSize = userPageSize
|
||||||
|
}
|
||||||
|
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "username", "verified", "createdTime", "accountType"});
|
||||||
|
pageInfo, users := userService.ListUsers(pageNumber, pageSize, sorterField, isAsc, keywords);
|
||||||
c.RenderArgs["pageInfo"] = pageInfo
|
c.RenderArgs["pageInfo"] = pageInfo
|
||||||
c.RenderArgs["users"] = users
|
c.RenderArgs["users"] = users
|
||||||
c.RenderArgs["keywords"] = keywords
|
c.RenderArgs["keywords"] = keywords
|
||||||
@@ -26,3 +31,36 @@ func (c AdminUser) Index(sorter, keywords string) revel.Result {
|
|||||||
func (c AdminUser) Add() revel.Result {
|
func (c AdminUser) Add() revel.Result {
|
||||||
return c.RenderTemplate("admin/user/add.html");
|
return c.RenderTemplate("admin/user/add.html");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加
|
||||||
|
func (c AdminUser) Register(email, pwd string) revel.Result {
|
||||||
|
re := info.NewRe();
|
||||||
|
|
||||||
|
if re.Ok, re.Msg = Vd("email", email); !re.Ok {
|
||||||
|
return c.RenderRe(re);
|
||||||
|
}
|
||||||
|
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
|
||||||
|
return c.RenderRe(re);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册
|
||||||
|
re.Ok, re.Msg = authService.Register(email, pwd)
|
||||||
|
|
||||||
|
return c.RenderRe(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改帐户
|
||||||
|
func (c AdminUser) ResetPwd(userId string) revel.Result {
|
||||||
|
userInfo := userService.GetUserInfo(userId)
|
||||||
|
c.RenderArgs["userInfo"] = userInfo
|
||||||
|
return c.RenderTemplate("admin/user/reset_pwd.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c AdminUser) DoResetPwd(userId, pwd string) revel.Result {
|
||||||
|
re := info.NewRe();
|
||||||
|
if re.Ok, re.Msg = Vd("password", pwd); !re.Ok {
|
||||||
|
return c.RenderRe(re);
|
||||||
|
}
|
||||||
|
re.Ok, re.Msg = userService.ResetPwd(c.GetUserId(), userId, pwd)
|
||||||
|
return c.RenderRe(re)
|
||||||
|
}
|
||||||
@@ -28,7 +28,6 @@ var configService *service.ConfigService
|
|||||||
var emailService *service.EmailService
|
var emailService *service.EmailService
|
||||||
var upgradeService *service.UpgradeService
|
var upgradeService *service.UpgradeService
|
||||||
|
|
||||||
var adminUsername = "admin"
|
|
||||||
// 拦截器
|
// 拦截器
|
||||||
// 不需要拦截的url
|
// 不需要拦截的url
|
||||||
// Index 除了Note之外都不需要
|
// Index 除了Note之外都不需要
|
||||||
@@ -83,7 +82,7 @@ func AuthInterceptor(c *revel.Controller) revel.Result {
|
|||||||
|
|
||||||
// 验证是否已登录
|
// 验证是否已登录
|
||||||
// 必须是管理员
|
// 必须是管理员
|
||||||
if username, ok := c.Session["Username"]; ok && username == adminUsername {
|
if username, ok := c.Session["Username"]; ok && username == configService.GetAdminUsername() {
|
||||||
return nil // 已登录
|
return nil // 已登录
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,4 +128,4 @@ func init() {
|
|||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &AdminEmail{})
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &AdminEmail{})
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &AdminUpgrade{})
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &AdminUpgrade{})
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &AdminData{})
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &AdminData{})
|
||||||
}
|
}
|
||||||
+50
-38
@@ -3,6 +3,7 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"github.com/leanote/leanote/app/service"
|
"github.com/leanote/leanote/app/service"
|
||||||
"github.com/leanote/leanote/app/info"
|
"github.com/leanote/leanote/app/info"
|
||||||
|
"github.com/leanote/leanote/app/lea/blog"
|
||||||
// . "github.com/leanote/leanote/app/lea"
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
"github.com/revel/revel"
|
"github.com/revel/revel"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -19,53 +20,57 @@ var blogService *service.BlogService
|
|||||||
var tagService *service.TagService
|
var tagService *service.TagService
|
||||||
var pwdService *service.PwdService
|
var pwdService *service.PwdService
|
||||||
var tokenService *service.TokenService
|
var tokenService *service.TokenService
|
||||||
var suggestionService *service.SuggestionService
|
var suggestionService *service.SuggestionService
|
||||||
var albumService *service.AlbumService
|
var albumService *service.AlbumService
|
||||||
var noteImageService *service.NoteImageService
|
var noteImageService *service.NoteImageService
|
||||||
var fileService *service.FileService
|
var fileService *service.FileService
|
||||||
var attachService *service.AttachService
|
var attachService *service.AttachService
|
||||||
var configService *service.ConfigService
|
var configService *service.ConfigService
|
||||||
var emailService *service.EmailService
|
var emailService *service.EmailService
|
||||||
var sessionService *service.SessionService
|
var sessionService *service.SessionService
|
||||||
|
var themeService *service.ThemeService
|
||||||
|
|
||||||
var pageSize = 1000
|
var pageSize = 1000
|
||||||
var defaultSortField = "UpdatedTime"
|
var defaultSortField = "UpdatedTime"
|
||||||
var leanoteUserId = "admin" // 不能更改
|
|
||||||
var siteUrl = "http://leanote.com"
|
|
||||||
|
|
||||||
// 拦截器
|
// 拦截器
|
||||||
// 不需要拦截的url
|
// 不需要拦截的url
|
||||||
// Index 除了Note之外都不需要
|
// Index 除了Note之外都不需要
|
||||||
var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": true,
|
var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": true,
|
||||||
"Login": true,
|
"Login": true,
|
||||||
"DoLogin": true,
|
"DoLogin": true,
|
||||||
"Logout": true,
|
"Logout": true,
|
||||||
"Register": true,
|
"Register": true,
|
||||||
"DoRegister": true,
|
"DoRegister": true,
|
||||||
"FindPasswword": true,
|
"FindPasswword": true,
|
||||||
"DoFindPassword": true,
|
"DoFindPassword": true,
|
||||||
"FindPassword2": true,
|
"FindPassword2": true,
|
||||||
"FindPasswordUpdate": true,
|
"FindPasswordUpdate": true,
|
||||||
"Suggestion": true,
|
"Suggestion": true,
|
||||||
},
|
},
|
||||||
"Note": map[string]bool{"ToImage": true},
|
"Note": map[string]bool{"ToImage": true},
|
||||||
"Blog": map[string]bool{"Index": true,
|
"Blog": map[string]bool{"Index": true,
|
||||||
"View": true,
|
"View": true,
|
||||||
"AboutMe": true,
|
"AboutMe": true,
|
||||||
"Cate": true,
|
"Cate": true,
|
||||||
"Search": true,
|
"ListCateLatest": true,
|
||||||
|
"Search": true,
|
||||||
"GetLikeAndComments": true,
|
"GetLikeAndComments": true,
|
||||||
"IncReadNum": true,
|
"IncReadNum": true,
|
||||||
"ListComments": true,
|
"ListComments": true,
|
||||||
},
|
"Single": true,
|
||||||
|
"Archive": true,
|
||||||
|
"Tags": true,
|
||||||
|
},
|
||||||
// 用户的激活与修改邮箱都不需要登录, 通过链接地址
|
// 用户的激活与修改邮箱都不需要登录, 通过链接地址
|
||||||
"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},
|
"File": map[string]bool{"OutputImage": true, "OutputFile": true},
|
||||||
"Attach": map[string]bool{"Download": true, "DownloadAll": true},
|
"Attach": map[string]bool{"Download": true, "DownloadAll": 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 {
|
||||||
@@ -76,31 +81,31 @@ func needValidate(controller, method string) bool {
|
|||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
// controller不在这里的, 肯定要验证
|
// controller不在这里的, 肯定要验证
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func AuthInterceptor(c *revel.Controller) revel.Result {
|
func AuthInterceptor(c *revel.Controller) revel.Result {
|
||||||
// 全部变成首字大写
|
// 全部变成首字大写
|
||||||
var controller = strings.Title(c.Name)
|
var controller = strings.Title(c.Name)
|
||||||
var method = strings.Title(c.MethodName)
|
var method = strings.Title(c.MethodName)
|
||||||
|
|
||||||
// 是否需要验证?
|
// 是否需要验证?
|
||||||
if !needValidate(controller, method) {
|
if !needValidate(controller, method) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证是否已登录
|
// 验证是否已登录
|
||||||
if userId, ok := c.Session["UserId"]; ok && userId != "" {
|
if userId, ok := c.Session["UserId"]; ok && userId != "" {
|
||||||
return nil // 已登录
|
return nil // 已登录
|
||||||
}
|
}
|
||||||
|
|
||||||
// 没有登录, 判断是否是ajax操作
|
// 没有登录, 判断是否是ajax操作
|
||||||
if c.Request.Header.Get("X-Requested-With") == "XMLHttpRequest" {
|
if c.Request.Header.Get("X-Requested-With") == "XMLHttpRequest" {
|
||||||
re := info.NewRe()
|
re := info.NewRe()
|
||||||
re.Msg = "NOTLOGIN"
|
re.Msg = "NOTLOGIN"
|
||||||
return c.RenderJson(re)
|
return c.RenderJson(re)
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.Redirect("/login")
|
return c.Redirect("/login")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +123,7 @@ func InitService() {
|
|||||||
tokenService = service.TokenS
|
tokenService = service.TokenS
|
||||||
noteImageService = service.NoteImageS
|
noteImageService = service.NoteImageS
|
||||||
fileService = service.FileS
|
fileService = service.FileS
|
||||||
albumService= service.AlbumS
|
albumService = service.AlbumS
|
||||||
attachService = service.AttachS
|
attachService = service.AttachS
|
||||||
pwdService = service.PwdS
|
pwdService = service.PwdS
|
||||||
suggestionService = service.SuggestionS
|
suggestionService = service.SuggestionS
|
||||||
@@ -126,6 +131,12 @@ func InitService() {
|
|||||||
configService = service.ConfigS
|
configService = service.ConfigS
|
||||||
emailService = service.EmailS
|
emailService = service.EmailS
|
||||||
sessionService = service.SessionS
|
sessionService = service.SessionS
|
||||||
|
themeService = service.ThemeS
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化博客模板
|
||||||
|
// 博客模板不由revel的
|
||||||
|
func initBlogTemplate() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -137,10 +148,11 @@ func init() {
|
|||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &User{})
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &User{})
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &File{})
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &File{})
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Attach{})
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Attach{})
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Blog{})
|
// revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &Blog{})
|
||||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &NoteContentHistory{})
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &NoteContentHistory{})
|
||||||
|
|
||||||
revel.OnAppStart(func() {
|
revel.OnAppStart(func() {
|
||||||
siteUrl, _ = revel.Config.String("site.url")
|
// 博客初始化模板
|
||||||
|
blog.Init()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package member
|
||||||
|
|
||||||
|
import (
|
||||||
|
// "github.com/revel/revel"
|
||||||
|
// "gopkg.in/mgo.v2/bson"
|
||||||
|
// "encoding/json"
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/leanote/leanote/app/controllers"
|
||||||
|
// "io/ioutil"
|
||||||
|
// "fmt"
|
||||||
|
// "math"
|
||||||
|
// "strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 公用Controller, 其它Controller继承它
|
||||||
|
type MemberBaseController struct {
|
||||||
|
controllers.BaseController // 不能用*BaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到sorterField 和 isAsc
|
||||||
|
// okSorter = ['email', 'username']
|
||||||
|
func (c MemberBaseController) getSorter(sorterField string, isAsc bool, okSorter []string) (string, bool){
|
||||||
|
sorter := ""
|
||||||
|
c.Params.Bind(&sorter, "sorter")
|
||||||
|
if sorter == "" {
|
||||||
|
return sorterField, isAsc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sorter形式 email-up, email-down
|
||||||
|
s2 := strings.Split(sorter, "-")
|
||||||
|
if len(s2) != 2 {
|
||||||
|
return sorterField, isAsc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 必须是可用的sorter
|
||||||
|
if okSorter != nil && len(okSorter) > 0 {
|
||||||
|
if !InArray(okSorter, s2[0]) {
|
||||||
|
return sorterField, isAsc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sorterField = strings.Title(s2[0])
|
||||||
|
if s2[1] == "up" {
|
||||||
|
isAsc = true
|
||||||
|
} else {
|
||||||
|
isAsc = false
|
||||||
|
}
|
||||||
|
c.RenderArgs["sorter"] = sorter
|
||||||
|
return sorterField, isAsc;
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberBaseController) updateConfig(keys []string) {
|
||||||
|
userId := c.GetUserId()
|
||||||
|
for _, key := range keys {
|
||||||
|
v := c.Params.Values.Get(key)
|
||||||
|
configService.UpdateGlobalStringConfig(userId, key, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,519 @@
|
|||||||
|
package member
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
"os"
|
||||||
|
"io/ioutil"
|
||||||
|
"time"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
// "github.com/leanote/leanote/app/lea/blog"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 博客管理
|
||||||
|
|
||||||
|
type MemberBlog struct {
|
||||||
|
MemberBaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberBlog) common() info.UserBlog {
|
||||||
|
userId := c.GetUserId()
|
||||||
|
userInfo := userService.GetUserInfo(userId)
|
||||||
|
c.RenderArgs["userInfo"] = userInfo
|
||||||
|
|
||||||
|
// 得到博客设置信息
|
||||||
|
c.RenderArgs["allowCustomDomain"] = configService.GetGlobalStringConfig("allowCustomDomain")
|
||||||
|
|
||||||
|
userBlog := blogService.GetUserBlog(userId)
|
||||||
|
c.RenderArgs["userBlog"] = userBlog
|
||||||
|
|
||||||
|
c.SetUserInfo()
|
||||||
|
c.SetLocale()
|
||||||
|
return userBlog
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 得到sorterField 和 isAsc
|
||||||
|
// okSorter = ['email', 'username']
|
||||||
|
func (c MemberBlog) getSorter(sorterField string, isAsc bool, okSorter []string) (string, bool){
|
||||||
|
sorter := ""
|
||||||
|
c.Params.Bind(&sorter, "sorter")
|
||||||
|
if sorter == "" {
|
||||||
|
return sorterField, isAsc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sorter形式 email-up, email-down
|
||||||
|
s2 := strings.Split(sorter, "-")
|
||||||
|
if len(s2) != 2 {
|
||||||
|
return sorterField, isAsc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 必须是可用的sorter
|
||||||
|
if okSorter != nil && len(okSorter) > 0 {
|
||||||
|
if !InArray(okSorter, s2[0]) {
|
||||||
|
return sorterField, isAsc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sorterField = strings.Title(s2[0])
|
||||||
|
if s2[1] == "up" {
|
||||||
|
isAsc = true
|
||||||
|
} else {
|
||||||
|
isAsc = false
|
||||||
|
}
|
||||||
|
c.RenderArgs["sorter"] = sorter
|
||||||
|
return sorterField, isAsc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 博客列表
|
||||||
|
var userPageSize = 15
|
||||||
|
func (c MemberBlog) Index(sorter, keywords string) revel.Result {
|
||||||
|
c.RenderArgs["title"] = "Posts"
|
||||||
|
pageNumber := c.GetPage()
|
||||||
|
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"title", "urlTitle", "updatedTime", "publicTime", "createdTime"});
|
||||||
|
pageInfo, blogs := blogService.ListAllBlogs(c.GetUserId(), "", keywords, false, pageNumber, userPageSize, sorterField, isAsc);
|
||||||
|
c.RenderArgs["pageInfo"] = pageInfo
|
||||||
|
c.RenderArgs["blogs"] = blogs
|
||||||
|
c.RenderArgs["keywords"] = keywords
|
||||||
|
|
||||||
|
userAndBlog := userService.GetUserAndBlog(c.GetUserId())
|
||||||
|
c.RenderArgs["userAndBlog"] = userAndBlog
|
||||||
|
|
||||||
|
return c.RenderTemplate("member/blog/list.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改笔记的urlTitle
|
||||||
|
func (c MemberBlog) UpdateBlogUrlTitle(noteId, urlTitle string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok, re.Item = blogService.UpateBlogUrlTitle(c.GetUserId(), noteId, urlTitle)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 修改笔记的urlTitle
|
||||||
|
func (c MemberBlog) UpdateBlogAbstract(noteId string) revel.Result {
|
||||||
|
c.RenderArgs["title"] = "Update Post Abstract"
|
||||||
|
note := noteService.GetNoteAndContent(noteId, c.GetUserId());
|
||||||
|
if !note.Note.IsBlog {
|
||||||
|
return c.E404();
|
||||||
|
}
|
||||||
|
c.RenderArgs["note"] = note
|
||||||
|
c.RenderArgs["noteId"] = noteId
|
||||||
|
return c.RenderTemplate("member/blog/update_abstract.html");
|
||||||
|
}
|
||||||
|
func (c MemberBlog) DoUpdateBlogAbstract(noteId, imgSrc, desc, abstract string) revel.Result {
|
||||||
|
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = blogService.UpateBlogAbstract(c.GetUserId(), noteId, imgSrc, desc, abstract)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 基本信息设置
|
||||||
|
func (c MemberBlog) Base() revel.Result {
|
||||||
|
c.common()
|
||||||
|
c.RenderArgs["title"] = "Blog Base Info"
|
||||||
|
return c.RenderTemplate("member/blog/base.html");
|
||||||
|
}
|
||||||
|
func (c MemberBlog) Comment() revel.Result {
|
||||||
|
c.common()
|
||||||
|
c.RenderArgs["title"] = "Comment"
|
||||||
|
return c.RenderTemplate("member/blog/comment.html");
|
||||||
|
}
|
||||||
|
func (c MemberBlog) Domain() revel.Result {
|
||||||
|
c.common()
|
||||||
|
c.RenderArgs["title"] = "Domain"
|
||||||
|
return c.RenderTemplate("member/blog/domain.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberBlog) Paging() revel.Result {
|
||||||
|
c.common()
|
||||||
|
c.RenderArgs["title"] = "Paging"
|
||||||
|
return c.RenderTemplate("member/blog/paging.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberBlog) Cate() revel.Result {
|
||||||
|
userBlog := c.common()
|
||||||
|
c.RenderArgs["title"] = "Cate"
|
||||||
|
|
||||||
|
notebooks := blogService.ListBlogNotebooks(c.GetUserId())
|
||||||
|
notebooksMap := map[string]info.Notebook{}
|
||||||
|
for _, each := range notebooks {
|
||||||
|
notebooksMap[each.NotebookId.Hex()] = each
|
||||||
|
}
|
||||||
|
|
||||||
|
var i = 0;
|
||||||
|
notebooks2 := make([]info.Notebook, len(notebooks))
|
||||||
|
|
||||||
|
// 先要保证已有的是正确的排序
|
||||||
|
cateIds := userBlog.CateIds
|
||||||
|
has := map[string]bool{} // cateIds中有的
|
||||||
|
if cateIds != nil && len(cateIds) > 0 {
|
||||||
|
for _, cateId := range cateIds {
|
||||||
|
if n, ok := notebooksMap[cateId]; ok {
|
||||||
|
notebooks2[i] = n
|
||||||
|
i++
|
||||||
|
has[cateId] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 之后
|
||||||
|
for _, each := range notebooks {
|
||||||
|
id := each.NotebookId.Hex()
|
||||||
|
if !has[id] {
|
||||||
|
notebooks2[i] = each
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.RenderArgs["notebooks"] = notebooks2
|
||||||
|
|
||||||
|
return c.RenderTemplate("member/blog/cate.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改分类排序
|
||||||
|
func (c MemberBlog) UpateCateIds(cateIds []string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = blogService.UpateCateIds(c.GetUserId(), cateIds)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberBlog) UpdateCateUrlTitle(cateId, urlTitle string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok, re.Item = blogService.UpateCateUrlTitle(c.GetUserId(), cateId, urlTitle)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存之, 包含增加与保存
|
||||||
|
func (c MemberBlog) DoAddOrUpdateSingle(singleId, title, content string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = blogService.AddOrUpdateSingle(c.GetUserId(), singleId, title, content)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
func (c MemberBlog) AddOrUpdateSingle(singleId string) revel.Result {
|
||||||
|
c.common()
|
||||||
|
c.RenderArgs["title"] = "Add Single"
|
||||||
|
c.RenderArgs["singleId"] = singleId
|
||||||
|
if singleId != "" {
|
||||||
|
c.RenderArgs["single"] = blogService.GetSingle(singleId)
|
||||||
|
}
|
||||||
|
return c.RenderTemplate("member/blog/add_single.html");
|
||||||
|
}
|
||||||
|
func (c MemberBlog) SortSingles(singleIds []string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = blogService.SortSingles(c.GetUserId(), singleIds)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberBlog) DeleteSingle(singleId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = blogService.DeleteSingle(c.GetUserId(), singleId)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改页面标题
|
||||||
|
func (c MemberBlog) UpdateSingleUrlTitle(singleId, urlTitle string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok, re.Item = blogService.UpdateSingleUrlTitle(c.GetUserId(), singleId, urlTitle)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberBlog) Single() revel.Result {
|
||||||
|
c.common()
|
||||||
|
c.RenderArgs["title"] = "Cate"
|
||||||
|
c.RenderArgs["singles"] = blogService.GetSingles(c.GetUserId())
|
||||||
|
|
||||||
|
return c.RenderTemplate("member/blog/single.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 主题
|
||||||
|
func (c MemberBlog) Theme() revel.Result {
|
||||||
|
c.common()
|
||||||
|
activeTheme, otherThemes := themeService.GetUserThemes(c.GetUserId())
|
||||||
|
c.RenderArgs["activeTheme"] = activeTheme
|
||||||
|
c.RenderArgs["otherThemes"] = otherThemes
|
||||||
|
|
||||||
|
c.RenderArgs["optionThemes"] = themeService.GetDefaultThemes()
|
||||||
|
|
||||||
|
c.RenderArgs["title"] = "Theme"
|
||||||
|
return c.RenderTemplate("member/blog/theme.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 编辑主题
|
||||||
|
var baseTpls = []string{"header.html", "footer.html", "index.html", "cate.html", "search.html", "post.html", "single.html", "tags.html", "tag_posts.html", "archive.html", "share_comment.html", "404.html", "theme.json", "style.css", "blog.js"}
|
||||||
|
func (c MemberBlog) UpdateTheme(themeId string, isNew int) revel.Result {
|
||||||
|
// 查看用户是否有该theme, 若没有则复制default之
|
||||||
|
// 得到主题的文件列表
|
||||||
|
userBlog := blogService.GetUserBlog(c.GetUserId())
|
||||||
|
if themeId == "" {
|
||||||
|
_, themeId = themeService.NewThemeForFirst(userBlog)
|
||||||
|
return c.Redirect("/member/blog/updateTheme?themeId=" + themeId)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.common()
|
||||||
|
c.RenderArgs["title"] = "Upate Theme"
|
||||||
|
c.RenderArgs["isNew"] = isNew
|
||||||
|
|
||||||
|
// 先复制之
|
||||||
|
c.RenderArgs["themeId"] = themeId
|
||||||
|
|
||||||
|
// 得到脚本目录
|
||||||
|
userId := c.GetUserId()
|
||||||
|
|
||||||
|
theme := themeService.GetTheme(userId, themeId)
|
||||||
|
c.RenderArgs["theme"] = theme
|
||||||
|
|
||||||
|
path := revel.BasePath + "/" + theme.Path
|
||||||
|
|
||||||
|
tpls := ListDir(path)
|
||||||
|
myTpls := make([]string, len(baseTpls))
|
||||||
|
tplMap := map[string]bool{}
|
||||||
|
for i, t := range baseTpls {
|
||||||
|
myTpls[i] = t
|
||||||
|
tplMap[t] = true
|
||||||
|
}
|
||||||
|
// 得到没有的tpls
|
||||||
|
for _, t := range tpls {
|
||||||
|
if t == "images" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if !tplMap[t] {
|
||||||
|
myTpls = append(myTpls, t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.RenderArgs["myTpls"] = myTpls
|
||||||
|
|
||||||
|
return c.RenderTemplate("member/blog/update_theme.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到文件内容
|
||||||
|
func (c MemberBlog) GetTplContent(themeId string, filename string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = true
|
||||||
|
re.Item = themeService.GetTplContent(c.GetUserId(), themeId, filename)
|
||||||
|
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
func (c MemberBlog) UpdateTplContent(themeId, filename, content string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok, re.Msg = themeService.UpdateTplContent(c.GetUserId(), themeId, filename, content)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberBlog) DeleteTpl(themeId, filename string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = themeService.DeleteTpl(c.GetUserId(), themeId, filename)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberBlog) ListThemeImages(themeId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
userId := c.GetUserId()
|
||||||
|
path := themeService.GetThemeAbsolutePath(userId, themeId) + "/images"
|
||||||
|
os.MkdirAll(path, 0755)
|
||||||
|
images := ListDir(path)
|
||||||
|
re.List = images
|
||||||
|
re.Ok = true
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberBlog) DeleteThemeImage(themeId, filename string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
path := themeService.GetThemeAbsolutePath(c.GetUserId(), themeId) + "/images/" + filename
|
||||||
|
re.Ok = DeleteFile(path)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 上传主题图片
|
||||||
|
func (c MemberBlog) UploadThemeImage(themeId string) revel.Result {
|
||||||
|
re := c.uploadImage(themeId);
|
||||||
|
c.RenderArgs["fileUrlPath"] = re.Id
|
||||||
|
c.RenderArgs["resultCode"] = re.Code
|
||||||
|
c.RenderArgs["resultMsg"] = re.Msg
|
||||||
|
return c.RenderTemplate("file/blog_logo.html")
|
||||||
|
}
|
||||||
|
func (c MemberBlog) uploadImage(themeId string) (re info.Re) {
|
||||||
|
var fileId = ""
|
||||||
|
var resultCode = 0 // 1表示正常
|
||||||
|
var resultMsg = "内部错误" // 错误信息
|
||||||
|
var Ok = false
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
re.Id = fileId // 只是id, 没有其它信息
|
||||||
|
re.Code = resultCode
|
||||||
|
re.Msg = resultMsg
|
||||||
|
re.Ok = Ok
|
||||||
|
}()
|
||||||
|
|
||||||
|
file, handel, err := c.Request.FormFile("file")
|
||||||
|
if err != nil {
|
||||||
|
return re
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
// 生成上传路径
|
||||||
|
dir := themeService.GetThemeAbsolutePath(c.GetUserId(), themeId) + "/images"
|
||||||
|
err = os.MkdirAll(dir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return re
|
||||||
|
}
|
||||||
|
// 生成新的文件名
|
||||||
|
filename := handel.Filename
|
||||||
|
|
||||||
|
var ext string;
|
||||||
|
|
||||||
|
_, ext = SplitFilename(filename)
|
||||||
|
if(ext != ".gif" && ext != ".jpg" && ext != ".png" && ext != ".bmp" && ext != ".jpeg") {
|
||||||
|
resultMsg = "不是图片"
|
||||||
|
return re
|
||||||
|
}
|
||||||
|
|
||||||
|
filename = filename
|
||||||
|
data, err := ioutil.ReadAll(file)
|
||||||
|
if err != nil {
|
||||||
|
LogJ(err)
|
||||||
|
return re
|
||||||
|
}
|
||||||
|
|
||||||
|
// > 2M?
|
||||||
|
if(len(data) > 5 * 1024 * 1024) {
|
||||||
|
resultCode = 0
|
||||||
|
resultMsg = "图片大于2M"
|
||||||
|
return re
|
||||||
|
}
|
||||||
|
|
||||||
|
toPath := dir + "/" + filename;
|
||||||
|
err = ioutil.WriteFile(toPath, data, 0777)
|
||||||
|
if err != nil {
|
||||||
|
LogJ(err)
|
||||||
|
return re
|
||||||
|
}
|
||||||
|
TransToGif(toPath, 0, true)
|
||||||
|
resultCode = 1
|
||||||
|
resultMsg = "上传成功!"
|
||||||
|
|
||||||
|
return re
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// 使用主题
|
||||||
|
func (c MemberBlog) ActiveTheme(themeId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = themeService.ActiveTheme(c.GetUserId(), themeId)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
// 删除主题
|
||||||
|
func (c MemberBlog) DeleteTheme(themeId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = themeService.DeleteTheme(c.GetUserId(), themeId)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
// 管理员公开主题
|
||||||
|
func (c MemberBlog) PublicTheme(themeId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = themeService.PublicTheme(c.GetUserId(), themeId)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
// 导出
|
||||||
|
func (c MemberBlog) ExportTheme(themeId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
var path string
|
||||||
|
re.Ok, path = themeService.ExportTheme(c.GetUserId(), themeId)
|
||||||
|
if !re.Ok {
|
||||||
|
return c.RenderText("error...")
|
||||||
|
}
|
||||||
|
fw, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return c.RenderText("error")
|
||||||
|
}
|
||||||
|
return c.RenderBinary(fw, GetFilename(path), revel.Attachment, time.Now()) // revel.Attachment
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导入主题
|
||||||
|
func (c MemberBlog) ImportTheme() revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
|
||||||
|
file, handel, err := c.Request.FormFile("file")
|
||||||
|
if err != nil {
|
||||||
|
re.Msg = fmt.Sprintf("%v", err)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
// 生成上传路径
|
||||||
|
userId := c.GetUserId()
|
||||||
|
dir := revel.BasePath + "/public/upload/" + userId + "/tmp"
|
||||||
|
err = os.MkdirAll(dir, 0755)
|
||||||
|
if err != nil {
|
||||||
|
re.Msg = fmt.Sprintf("%v", err)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
// 生成新的文件名
|
||||||
|
filename := handel.Filename
|
||||||
|
|
||||||
|
var ext string;
|
||||||
|
_, ext = SplitFilename(filename)
|
||||||
|
if(ext != ".zip") {
|
||||||
|
re.Msg = "请上传zip文件"
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
filename = filename
|
||||||
|
data, err := ioutil.ReadAll(file)
|
||||||
|
if err != nil {
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// > 10M?
|
||||||
|
if(len(data) > 10 * 1024 * 1024) {
|
||||||
|
re.Msg = "文件大于10M"
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
toPath := dir + "/" + filename;
|
||||||
|
err = ioutil.WriteFile(toPath, data, 0777)
|
||||||
|
if err != nil {
|
||||||
|
re.Msg = fmt.Sprintf("%v", err)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 上传好后, 增加之
|
||||||
|
themeService.ImportTheme(c.GetUserId(), toPath)
|
||||||
|
|
||||||
|
re.Ok = true
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 安装
|
||||||
|
func (c MemberBlog) InstallTheme(themeId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = themeService.InstallTheme(c.GetUserId(), themeId)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
// 新建主题
|
||||||
|
func (c MemberBlog) NewTheme() revel.Result {
|
||||||
|
_, themeId := themeService.NewTheme(c.GetUserId())
|
||||||
|
return c.Redirect("/member/blog/updateTheme?isNew=1&themeId=" + themeId)
|
||||||
|
}
|
||||||
|
//-----------
|
||||||
|
//
|
||||||
|
func (c MemberBlog) SetUserBlogBase(userBlog info.UserBlogBase) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = blogService.UpdateUserBlogBase(c.GetUserId(), userBlog)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
func (c MemberBlog) SetUserBlogComment(userBlog info.UserBlogComment) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = blogService.UpdateUserBlogComment(c.GetUserId(), userBlog)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
func (c MemberBlog) SetUserBlogStyle(userBlog info.UserBlogStyle) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = blogService.UpdateUserBlogStyle(c.GetUserId(), userBlog)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
func (c MemberBlog) SetUserBlogPaging(perPageSize int, sortField string, isAsc bool) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok, re.Msg = blogService.UpdateUserBlogPaging(c.GetUserId(), perPageSize, sortField, isAsc)
|
||||||
|
return c.RenderRe(re)
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package member
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 分组管理
|
||||||
|
type MemberGroup struct {
|
||||||
|
MemberBaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
// 首页, 显示所有分组和用户
|
||||||
|
func (c MemberGroup) Index() revel.Result {
|
||||||
|
c.SetUserInfo()
|
||||||
|
c.SetLocale()
|
||||||
|
c.RenderArgs["title"] = "My Group"
|
||||||
|
c.RenderArgs["groups"] = groupService.GetGroupsAndUsers(c.GetUserId())
|
||||||
|
return c.RenderTemplate("member/group/index.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加分组
|
||||||
|
func (c MemberGroup) AddGroup(title string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok, re.Item = groupService.AddGroup(c.GetUserId(), title)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberGroup) UpdateGroupTitle(groupId, title string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok = groupService.UpdateGroupTitle(c.GetUserId(), groupId, title)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberGroup) DeleteGroup(groupId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok, re.Msg = groupService.DeleteGroup(c.GetUserId(), groupId)
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加用户
|
||||||
|
func (c MemberGroup) AddUser(groupId, email string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
userInfo := userService.GetUserInfoByAny(email)
|
||||||
|
if userInfo.UserId == "" {
|
||||||
|
re.Msg = "userNotExists"
|
||||||
|
} else {
|
||||||
|
re.Ok, re.Msg = groupService.AddUser(c.GetUserId(), groupId, userInfo.UserId.Hex())
|
||||||
|
re.Item = userInfo
|
||||||
|
}
|
||||||
|
return c.RenderRe(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberGroup) DeleteUser(groupId, userId string) revel.Result {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Ok, re.Msg = groupService.DeleteUser(c.GetUserId(), groupId, userId)
|
||||||
|
return c.RenderRe(re)
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package member
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
)
|
||||||
|
|
||||||
|
// admin 首页
|
||||||
|
|
||||||
|
type MemberIndex struct {
|
||||||
|
MemberBaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
// admin 主页
|
||||||
|
func (c MemberIndex) Index() revel.Result {
|
||||||
|
c.SetUserInfo()
|
||||||
|
c.RenderArgs["title"] = "Leanote Member Center"
|
||||||
|
|
||||||
|
c.RenderArgs["countNote"] = noteService.CountNote(c.GetUserId())
|
||||||
|
c.RenderArgs["countBlog"] = noteService.CountBlog(c.GetUserId())
|
||||||
|
|
||||||
|
c.SetLocale()
|
||||||
|
|
||||||
|
return c.RenderTemplate("member/index.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模板
|
||||||
|
func (c MemberIndex) T(t string) revel.Result {
|
||||||
|
c.RenderArgs["str"] = configService.GlobalStringConfigs
|
||||||
|
c.RenderArgs["arr"] = configService.GlobalArrayConfigs
|
||||||
|
c.RenderArgs["map"] = configService.GlobalMapConfigs
|
||||||
|
c.RenderArgs["arrMap"] = configService.GlobalArrMapConfigs
|
||||||
|
return c.RenderTemplate("admin/" + t + ".html")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberIndex) GetView(view string) revel.Result {
|
||||||
|
return c.RenderTemplate("admin/" + view);
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package member
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 帐户信息
|
||||||
|
|
||||||
|
type MemberUser struct {
|
||||||
|
MemberBaseController
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberUser) Username() revel.Result {
|
||||||
|
c.SetUserInfo()
|
||||||
|
c.SetLocale()
|
||||||
|
c.RenderArgs["title"] = "Username"
|
||||||
|
return c.RenderTemplate("member/user/username.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberUser) Email() revel.Result {
|
||||||
|
c.SetUserInfo()
|
||||||
|
c.SetLocale()
|
||||||
|
c.RenderArgs["title"] = "Email"
|
||||||
|
return c.RenderTemplate("member/user/email.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberUser) Password() revel.Result {
|
||||||
|
c.SetUserInfo()
|
||||||
|
c.SetLocale()
|
||||||
|
c.RenderArgs["title"] = "Password"
|
||||||
|
return c.RenderTemplate("member/user/password.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c MemberUser) Avatar() revel.Result {
|
||||||
|
c.SetUserInfo()
|
||||||
|
c.SetLocale()
|
||||||
|
c.RenderArgs["title"] = "Avatar"
|
||||||
|
c.RenderArgs["globalConfigs"] = configService.GetGlobalConfigForUser()
|
||||||
|
return c.RenderTemplate("member/user/avatar.html");
|
||||||
|
}
|
||||||
|
func (c MemberUser) AddAccount() revel.Result {
|
||||||
|
c.SetUserInfo()
|
||||||
|
c.SetLocale()
|
||||||
|
c.RenderArgs["title"] = "Add Account"
|
||||||
|
return c.RenderTemplate("member/user/add_account.html");
|
||||||
|
}
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
package member
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/leanote/leanote/app/service"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
// . "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/revel/revel"
|
||||||
|
// "strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var userService *service.UserService
|
||||||
|
var groupService *service.GroupService
|
||||||
|
var noteService *service.NoteService
|
||||||
|
var trashService *service.TrashService
|
||||||
|
var notebookService *service.NotebookService
|
||||||
|
var noteContentHistoryService *service.NoteContentHistoryService
|
||||||
|
var authService *service.AuthService
|
||||||
|
var shareService *service.ShareService
|
||||||
|
var blogService *service.BlogService
|
||||||
|
var tagService *service.TagService
|
||||||
|
var pwdService *service.PwdService
|
||||||
|
var tokenService *service.TokenService
|
||||||
|
var suggestionService *service.SuggestionService
|
||||||
|
var albumService *service.AlbumService
|
||||||
|
var noteImageService *service.NoteImageService
|
||||||
|
var fileService *service.FileService
|
||||||
|
var attachService *service.AttachService
|
||||||
|
var configService *service.ConfigService
|
||||||
|
var emailService *service.EmailService
|
||||||
|
var upgradeService *service.UpgradeService
|
||||||
|
var themeService *service.ThemeService
|
||||||
|
|
||||||
|
// 拦截器
|
||||||
|
// 不需要拦截的url
|
||||||
|
// Index 除了Note之外都不需要
|
||||||
|
var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": true,
|
||||||
|
"Login": true,
|
||||||
|
"DoLogin": true,
|
||||||
|
"Logout": true,
|
||||||
|
"Register": true,
|
||||||
|
"DoRegister": true,
|
||||||
|
"FindPasswword": true,
|
||||||
|
"DoFindPassword": true,
|
||||||
|
"FindPassword2": true,
|
||||||
|
"FindPasswordUpdate": true,
|
||||||
|
"Suggestion": true,
|
||||||
|
},
|
||||||
|
"Blog": map[string]bool{"Index": true,
|
||||||
|
"View": true,
|
||||||
|
"AboutMe": true,
|
||||||
|
"SearchBlog": true,
|
||||||
|
},
|
||||||
|
// 用户的激活与修改邮箱都不需要登录, 通过链接地址
|
||||||
|
"User": map[string]bool{"UpdateEmail": true,
|
||||||
|
"ActiveEmail":true,
|
||||||
|
},
|
||||||
|
"Oauth": map[string]bool{"GithubCallback": true},
|
||||||
|
"File": map[string]bool{"OutputImage": true, "OutputFile": true},
|
||||||
|
"Attach": map[string]bool{"Download": true, "DownloadAll": true},
|
||||||
|
}
|
||||||
|
func needValidate(controller, method string) bool {
|
||||||
|
// 在里面
|
||||||
|
if v, ok := commonUrl[controller]; ok {
|
||||||
|
// 在commonUrl里
|
||||||
|
if _, ok2 := v[method]; ok2 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
// controller不在这里的, 肯定要验证
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func AuthInterceptor(c *revel.Controller) revel.Result {
|
||||||
|
// 全部变成首字大写
|
||||||
|
/*
|
||||||
|
var controller = strings.Title(c.Name)
|
||||||
|
var method = strings.Title(c.MethodName)
|
||||||
|
// 是否需要验证?
|
||||||
|
if !needValidate(controller, method) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 验证是否已登录
|
||||||
|
// 必须是管理员
|
||||||
|
if _, ok := c.Session["Username"]; ok {
|
||||||
|
return nil // 已登录
|
||||||
|
}
|
||||||
|
|
||||||
|
// 没有登录, 判断是否是ajax操作
|
||||||
|
if c.Request.Header.Get("X-Requested-With") == "XMLHttpRequest" {
|
||||||
|
re := info.NewRe()
|
||||||
|
re.Msg = "NOTLOGIN"
|
||||||
|
return c.RenderJson(re)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Redirect("/login")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 最外层init.go调用
|
||||||
|
// 获取service, 单例
|
||||||
|
func InitService() {
|
||||||
|
notebookService = service.NotebookS
|
||||||
|
noteService = service.NoteS
|
||||||
|
noteContentHistoryService = service.NoteContentHistoryS
|
||||||
|
trashService = service.TrashS
|
||||||
|
shareService = service.ShareS
|
||||||
|
userService = service.UserS
|
||||||
|
groupService = service.GroupS
|
||||||
|
tagService = service.TagS
|
||||||
|
blogService = service.BlogS
|
||||||
|
tokenService = service.TokenS
|
||||||
|
noteImageService = service.NoteImageS
|
||||||
|
fileService = service.FileS
|
||||||
|
albumService= service.AlbumS
|
||||||
|
attachService = service.AttachS
|
||||||
|
pwdService = service.PwdS
|
||||||
|
suggestionService = service.SuggestionS
|
||||||
|
authService = service.AuthS
|
||||||
|
configService = service.ConfigS
|
||||||
|
emailService = service.EmailS
|
||||||
|
upgradeService = service.UpgradeS
|
||||||
|
themeService = service.ThemeS
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberIndex{})
|
||||||
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberUser{})
|
||||||
|
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &MemberBlog{})
|
||||||
|
revel.OnAppStart(func() {
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
包括基本信息设置
|
||||||
|
博客设置
|
||||||
+50
-26
@@ -2,9 +2,9 @@ package db
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/revel/revel"
|
||||||
"gopkg.in/mgo.v2"
|
"gopkg.in/mgo.v2"
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
"github.com/revel/revel"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Init mgo and the common DAO
|
// Init mgo and the common DAO
|
||||||
@@ -23,9 +23,12 @@ var ShareNotebooks *mgo.Collection
|
|||||||
var HasShareNotes *mgo.Collection
|
var HasShareNotes *mgo.Collection
|
||||||
var Blogs *mgo.Collection
|
var Blogs *mgo.Collection
|
||||||
var Users *mgo.Collection
|
var Users *mgo.Collection
|
||||||
|
var Groups *mgo.Collection
|
||||||
|
var GroupUsers *mgo.Collection
|
||||||
|
|
||||||
var Tags *mgo.Collection
|
var Tags *mgo.Collection
|
||||||
var TagNotes *mgo.Collection
|
//var TagNotes *mgo.Collection
|
||||||
|
var TagCounts *mgo.Collection
|
||||||
|
|
||||||
var UserBlogs *mgo.Collection
|
var UserBlogs *mgo.Collection
|
||||||
|
|
||||||
@@ -46,6 +49,8 @@ var EmailLogs *mgo.Collection
|
|||||||
var BlogLikes *mgo.Collection
|
var BlogLikes *mgo.Collection
|
||||||
var BlogComments *mgo.Collection
|
var BlogComments *mgo.Collection
|
||||||
var Reports *mgo.Collection
|
var Reports *mgo.Collection
|
||||||
|
var BlogSingles *mgo.Collection
|
||||||
|
var Themes *mgo.Collection
|
||||||
|
|
||||||
// session
|
// session
|
||||||
var Sessions *mgo.Collection
|
var Sessions *mgo.Collection
|
||||||
@@ -54,7 +59,7 @@ var Sessions *mgo.Collection
|
|||||||
func Init() {
|
func Init() {
|
||||||
var url string
|
var url string
|
||||||
var ok bool
|
var ok bool
|
||||||
config := revel.Config;
|
config := revel.Config
|
||||||
url, ok = config.String("db.url")
|
url, ok = config.String("db.url")
|
||||||
dbname, _ := config.String("db.dbname")
|
dbname, _ := config.String("db.dbname")
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -66,9 +71,9 @@ func Init() {
|
|||||||
if username == "" || password == "" {
|
if username == "" || password == "" {
|
||||||
usernameAndPassword = ""
|
usernameAndPassword = ""
|
||||||
}
|
}
|
||||||
url = "mongodb://" + usernameAndPassword + host + ":" + port + "/" + dbname
|
url = "mongodb://" + usernameAndPassword + host + ":" + port + "/" + dbname
|
||||||
}
|
}
|
||||||
|
|
||||||
// [mongodb://][user:pass@]host1[:port1][,host2[:port2],...][/database][?options]
|
// [mongodb://][user:pass@]host1[:port1][,host2[:port2],...][/database][?options]
|
||||||
// mongodb://myuser:mypass@localhost:40001,otherhost:40001/mydb
|
// mongodb://myuser:mypass@localhost:40001,otherhost:40001/mydb
|
||||||
var err error
|
var err error
|
||||||
@@ -82,55 +87,61 @@ func Init() {
|
|||||||
|
|
||||||
// notebook
|
// notebook
|
||||||
Notebooks = Session.DB(dbname).C("notebooks")
|
Notebooks = Session.DB(dbname).C("notebooks")
|
||||||
|
|
||||||
// notes
|
// notes
|
||||||
Notes = Session.DB(dbname).C("notes")
|
Notes = Session.DB(dbname).C("notes")
|
||||||
|
|
||||||
// noteContents
|
// noteContents
|
||||||
NoteContents = Session.DB(dbname).C("note_contents")
|
NoteContents = Session.DB(dbname).C("note_contents")
|
||||||
NoteContentHistories = Session.DB(dbname).C("note_content_histories")
|
NoteContentHistories = Session.DB(dbname).C("note_content_histories")
|
||||||
|
|
||||||
// share
|
// share
|
||||||
ShareNotes = Session.DB(dbname).C("share_notes")
|
ShareNotes = Session.DB(dbname).C("share_notes")
|
||||||
ShareNotebooks = Session.DB(dbname).C("share_notebooks")
|
ShareNotebooks = Session.DB(dbname).C("share_notebooks")
|
||||||
HasShareNotes = Session.DB(dbname).C("has_share_notes")
|
HasShareNotes = Session.DB(dbname).C("has_share_notes")
|
||||||
|
|
||||||
// user
|
// user
|
||||||
Users = Session.DB(dbname).C("users")
|
Users = Session.DB(dbname).C("users")
|
||||||
|
// group
|
||||||
|
Groups = Session.DB(dbname).C("groups")
|
||||||
|
GroupUsers = Session.DB(dbname).C("group_users")
|
||||||
|
|
||||||
// blog
|
// blog
|
||||||
Blogs = Session.DB(dbname).C("blogs")
|
Blogs = Session.DB(dbname).C("blogs")
|
||||||
|
|
||||||
// tag
|
// tag
|
||||||
Tags = Session.DB(dbname).C("tags")
|
Tags = Session.DB(dbname).C("tags")
|
||||||
TagNotes = Session.DB(dbname).C("tag_notes")
|
// TagNotes = Session.DB(dbname).C("tag_notes")
|
||||||
|
TagCounts = Session.DB(dbname).C("tag_count")
|
||||||
|
|
||||||
// blog
|
// blog
|
||||||
UserBlogs = Session.DB(dbname).C("user_blogs")
|
UserBlogs = Session.DB(dbname).C("user_blogs")
|
||||||
|
BlogSingles = Session.DB(dbname).C("blog_singles")
|
||||||
|
Themes = Session.DB(dbname).C("themes")
|
||||||
|
|
||||||
// find password
|
// find password
|
||||||
Tokens = Session.DB(dbname).C("tokens")
|
Tokens = Session.DB(dbname).C("tokens")
|
||||||
|
|
||||||
// Suggestion
|
// Suggestion
|
||||||
Suggestions = Session.DB(dbname).C("suggestions")
|
Suggestions = Session.DB(dbname).C("suggestions")
|
||||||
|
|
||||||
// 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")
|
||||||
Attachs = Session.DB(dbname).C("attachs")
|
Attachs = Session.DB(dbname).C("attachs")
|
||||||
|
|
||||||
NoteImages = Session.DB(dbname).C("note_images")
|
NoteImages = Session.DB(dbname).C("note_images")
|
||||||
|
|
||||||
Configs = Session.DB(dbname).C("configs")
|
Configs = Session.DB(dbname).C("configs")
|
||||||
EmailLogs = Session.DB(dbname).C("email_logs")
|
EmailLogs = Session.DB(dbname).C("email_logs")
|
||||||
|
|
||||||
// 社交
|
// 社交
|
||||||
BlogLikes = Session.DB(dbname).C("blog_likes")
|
BlogLikes = Session.DB(dbname).C("blog_likes")
|
||||||
BlogComments = Session.DB(dbname).C("blog_comments")
|
BlogComments = Session.DB(dbname).C("blog_comments")
|
||||||
|
|
||||||
// 举报
|
// 举报
|
||||||
Reports = Session.DB(dbname).C("reports")
|
Reports = Session.DB(dbname).C("reports")
|
||||||
|
|
||||||
// session
|
// session
|
||||||
Sessions = Session.DB(dbname).C("sessions")
|
Sessions = Session.DB(dbname).C("sessions")
|
||||||
}
|
}
|
||||||
@@ -174,22 +185,29 @@ func UpdateByIdAndUserId2(collection *mgo.Collection, id, userId bson.ObjectId,
|
|||||||
return Err(err)
|
return Err(err)
|
||||||
}
|
}
|
||||||
func UpdateByIdAndUserIdField(collection *mgo.Collection, id, userId, field string, value interface{}) bool {
|
func UpdateByIdAndUserIdField(collection *mgo.Collection, id, userId, field string, value interface{}) bool {
|
||||||
return UpdateByIdAndUserId(collection, id, userId, bson.M{"$set": bson.M{field:value}})
|
return UpdateByIdAndUserId(collection, id, userId, bson.M{"$set": bson.M{field: value}})
|
||||||
}
|
}
|
||||||
func UpdateByIdAndUserIdMap(collection *mgo.Collection, id, userId string, v bson.M) bool {
|
func UpdateByIdAndUserIdMap(collection *mgo.Collection, id, userId string, v bson.M) bool {
|
||||||
return UpdateByIdAndUserId(collection, id, userId, bson.M{"$set": v})
|
return UpdateByIdAndUserId(collection, id, userId, bson.M{"$set": v})
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateByIdAndUserIdField2(collection *mgo.Collection, id, userId bson.ObjectId, field string, value interface{}) bool {
|
func UpdateByIdAndUserIdField2(collection *mgo.Collection, id, userId bson.ObjectId, field string, value interface{}) bool {
|
||||||
return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": bson.M{field:value}})
|
return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": bson.M{field: value}})
|
||||||
}
|
}
|
||||||
func UpdateByIdAndUserIdMap2(collection *mgo.Collection, id, userId bson.ObjectId, v bson.M) bool {
|
func UpdateByIdAndUserIdMap2(collection *mgo.Collection, id, userId bson.ObjectId, v bson.M) bool {
|
||||||
return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": v})
|
return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": v})
|
||||||
}
|
}
|
||||||
//
|
|
||||||
|
//
|
||||||
func UpdateByQField(collection *mgo.Collection, q interface{}, field string, value interface{}) bool {
|
func UpdateByQField(collection *mgo.Collection, q interface{}, field string, value interface{}) bool {
|
||||||
_, err := collection.UpdateAll(q, bson.M{"$set": bson.M{field: value}})
|
_, err := collection.UpdateAll(q, bson.M{"$set": bson.M{field: value}})
|
||||||
return Err(err)
|
return Err(err)
|
||||||
}
|
}
|
||||||
|
func UpdateByQI(collection *mgo.Collection, q interface{}, v interface{}) bool {
|
||||||
|
_, err := collection.UpdateAll(q, bson.M{"$set": v})
|
||||||
|
return Err(err)
|
||||||
|
}
|
||||||
|
|
||||||
// 查询条件和值
|
// 查询条件和值
|
||||||
func UpdateByQMap(collection *mgo.Collection, q interface{}, v interface{}) bool {
|
func UpdateByQMap(collection *mgo.Collection, q interface{}, v interface{}) bool {
|
||||||
_, err := collection.UpdateAll(q, bson.M{"$set": v})
|
_, err := collection.UpdateAll(q, bson.M{"$set": v})
|
||||||
@@ -255,6 +273,7 @@ func GetByQWithFields(collection *mgo.Collection, q bson.M, fields []string, i i
|
|||||||
}
|
}
|
||||||
collection.Find(q).Select(selector).One(i)
|
collection.Find(q).Select(selector).One(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询某些字段, q是查询条件, fields是字段名列表
|
// 查询某些字段, q是查询条件, fields是字段名列表
|
||||||
func ListByQWithFields(collection *mgo.Collection, q bson.M, fields []string, i interface{}) {
|
func ListByQWithFields(collection *mgo.Collection, q bson.M, fields []string, i interface{}) {
|
||||||
selector := make(bson.M, len(fields))
|
selector := make(bson.M, len(fields))
|
||||||
@@ -270,6 +289,11 @@ func GetByIdAndUserId2(collection *mgo.Collection, id, userId bson.ObjectId, i i
|
|||||||
collection.Find(GetIdAndUserIdBsonQ(id, userId)).One(i)
|
collection.Find(GetIdAndUserIdBsonQ(id, userId)).One(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 按field去重
|
||||||
|
func Distinct(collection *mgo.Collection, q bson.M, field string, i interface{}) {
|
||||||
|
collection.Find(q).Distinct(field, i)
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------
|
//----------------------
|
||||||
|
|
||||||
func Count(collection *mgo.Collection, q interface{}) int {
|
func Count(collection *mgo.Collection, q interface{}) int {
|
||||||
@@ -303,9 +327,9 @@ func Err(err error) bool {
|
|||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
// 删除时, 查找
|
// 删除时, 查找
|
||||||
if err.Error() == "not found" {
|
if err.Error() == "not found" {
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package info
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 仅仅为了博客的主题
|
||||||
|
|
||||||
|
type BlogInfoCustom struct {
|
||||||
|
UserId string
|
||||||
|
Username string
|
||||||
|
UserLogo string
|
||||||
|
Title string
|
||||||
|
SubTitle string
|
||||||
|
Logo string
|
||||||
|
OpenComment bool
|
||||||
|
CommentType string
|
||||||
|
ThemeId string
|
||||||
|
SubDomain string
|
||||||
|
Domain string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Post struct {
|
||||||
|
NoteId string
|
||||||
|
Title string
|
||||||
|
UrlTitle string
|
||||||
|
ImgSrc string
|
||||||
|
CreatedTime time.Time
|
||||||
|
UpdatedTime time.Time
|
||||||
|
PublicTime time.Time
|
||||||
|
Desc string
|
||||||
|
Abstract string
|
||||||
|
Content string
|
||||||
|
Tags []string
|
||||||
|
CommentNum int
|
||||||
|
ReadNum int
|
||||||
|
LikeNum int
|
||||||
|
IsMarkdown bool
|
||||||
|
}
|
||||||
|
// 归档
|
||||||
|
type ArchiveMonth struct {
|
||||||
|
Month int
|
||||||
|
Posts []*Post
|
||||||
|
}
|
||||||
|
type Archive struct {
|
||||||
|
Year int
|
||||||
|
MonthAchives []ArchiveMonth
|
||||||
|
Posts []*Post
|
||||||
|
}
|
||||||
+51
-9
@@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
type BlogItem struct {
|
type BlogItem struct {
|
||||||
Note
|
Note
|
||||||
|
Abstract string
|
||||||
Content string // 可能是content的一部分, 截取. 点击more后就是整个信息了
|
Content string // 可能是content的一部分, 截取. 点击more后就是整个信息了
|
||||||
HasMore bool // 是否是否还有
|
HasMore bool // 是否是否还有
|
||||||
User User // 用户信息
|
User User // 用户信息
|
||||||
@@ -18,13 +19,13 @@ type UserBlogBase struct {
|
|||||||
Logo string `Logo`
|
Logo string `Logo`
|
||||||
Title string `Title` // 标题
|
Title string `Title` // 标题
|
||||||
SubTitle string `SubTitle` // 副标题
|
SubTitle string `SubTitle` // 副标题
|
||||||
AboutMe string `AboutMe` // 关于我
|
// AboutMe string `AboutMe` // 关于我
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserBlogComment struct {
|
type UserBlogComment struct {
|
||||||
CanComment bool `CanComment` // 是否可以评论
|
CanComment bool `CanComment` // 是否可以评论
|
||||||
CommentType string `CommentType` // default 或 disqus
|
CommentType string `CommentType` // default 或 disqus
|
||||||
DisqusId string `DisqusId`
|
DisqusId string `DisqusId`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserBlogStyle struct {
|
type UserBlogStyle struct {
|
||||||
@@ -38,18 +39,48 @@ type UserBlog struct {
|
|||||||
Logo string `Logo`
|
Logo string `Logo`
|
||||||
Title string `Title` // 标题
|
Title string `Title` // 标题
|
||||||
SubTitle string `SubTitle` // 副标题
|
SubTitle string `SubTitle` // 副标题
|
||||||
AboutMe string `AboutMe` // 关于我
|
AboutMe string `AboutMe` // 关于我, 弃用
|
||||||
|
|
||||||
|
CanComment bool `CanComment` // 是否可以评论
|
||||||
|
|
||||||
CanComment bool `CanComment` // 是否可以评论
|
|
||||||
|
|
||||||
CommentType string `CommentType` // default 或 disqus
|
CommentType string `CommentType` // default 或 disqus
|
||||||
DisqusId string `DisqusId`
|
DisqusId string `DisqusId`
|
||||||
|
|
||||||
Style string `Style` // 风格
|
Style string `Style` // 风格
|
||||||
Css string `Css` // 自定义css
|
Css string `Css` // 自定义css
|
||||||
|
|
||||||
|
ThemeId bson.ObjectId `ThemeId,omitempty` // 主题Id
|
||||||
|
ThemePath string `bson:"ThemePath" json:"-"` // 不存值, 从Theme中获取, 相对路径 public/
|
||||||
|
|
||||||
|
CateIds []string `CateIds,omitempty` // 分类Id, 排序好的
|
||||||
|
Singles []map[string]string `Singles,omitempty` // 单页, 排序好的, map包含: ["Title"], ["SingleId"]
|
||||||
|
|
||||||
|
PerPageSize int `PerPageSize,omitempty`
|
||||||
|
SortField string `SortField` // 排序字段
|
||||||
|
IsAsc bool `IsAsc,omitempty` // 排序类型, 降序, 升序, 默认是false, 表示降序
|
||||||
|
|
||||||
SubDomain string `SubDomain` // 二级域名
|
SubDomain string `SubDomain` // 二级域名
|
||||||
Domain string `Domain` // 自定义域名
|
Domain string `Domain` // 自定义域名
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 博客统计信息
|
||||||
|
type BlogStat struct {
|
||||||
|
NoteId bson.ObjectId `bson:"_id,omitempty"`
|
||||||
|
ReadNum int `ReadNum,omitempty` // 阅读次数 2014/9/28
|
||||||
|
LikeNum int `LikeNum,omitempty` // 点赞次数 2014/9/28
|
||||||
|
CommentNum int `CommentNum,omitempty` // 评论次数 2014/9/28
|
||||||
|
}
|
||||||
|
|
||||||
|
// 单页
|
||||||
|
type BlogSingle struct {
|
||||||
|
SingleId bson.ObjectId `bson:"_id,omitempty"`
|
||||||
|
UserId bson.ObjectId `UserId`
|
||||||
|
Title string `Title`
|
||||||
|
UrlTitle string `UrlTitle` // 2014/11/11
|
||||||
|
Content string `Content`
|
||||||
|
UpdatedTime time.Time `UpdatedTime`
|
||||||
|
CreatedTime time.Time `CreatedTime`
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------
|
//------------------------
|
||||||
@@ -57,7 +88,7 @@ type UserBlog struct {
|
|||||||
|
|
||||||
// 点赞记录
|
// 点赞记录
|
||||||
type BlogLike struct {
|
type BlogLike struct {
|
||||||
LikeId bson.ObjectId `bson:"_id"`
|
LikeId bson.ObjectId `bson:"_id,omitempty"`
|
||||||
NoteId bson.ObjectId `NoteId`
|
NoteId bson.ObjectId `NoteId`
|
||||||
UserId bson.ObjectId `UserId`
|
UserId bson.ObjectId `UserId`
|
||||||
CreatedTime time.Time `CreatedTime`
|
CreatedTime time.Time `CreatedTime`
|
||||||
@@ -65,7 +96,7 @@ type BlogLike struct {
|
|||||||
|
|
||||||
// 评论
|
// 评论
|
||||||
type BlogComment struct {
|
type BlogComment struct {
|
||||||
CommentId bson.ObjectId `bson:"_id"`
|
CommentId bson.ObjectId `bson:"_id,omitempty"`
|
||||||
NoteId bson.ObjectId `NoteId`
|
NoteId bson.ObjectId `NoteId`
|
||||||
|
|
||||||
UserId bson.ObjectId `UserId` // UserId回复ToUserId
|
UserId bson.ObjectId `UserId` // UserId回复ToUserId
|
||||||
@@ -84,3 +115,14 @@ type BlogCommentPublic struct {
|
|||||||
BlogComment
|
BlogComment
|
||||||
IsILikeIt bool
|
IsILikeIt bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BlogUrls struct {
|
||||||
|
IndexUrl string
|
||||||
|
CateUrl string
|
||||||
|
SearchUrl string
|
||||||
|
SingleUrl string
|
||||||
|
PostUrl string
|
||||||
|
ArchiveUrl string
|
||||||
|
TagsUrl string
|
||||||
|
TagPostsUrl string
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package info
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 分组
|
||||||
|
type Group struct {
|
||||||
|
GroupId bson.ObjectId `bson:"_id"` // 谁的
|
||||||
|
UserId bson.ObjectId `UserId` // 所有者Id
|
||||||
|
Title string `Title` // 标题
|
||||||
|
UserCount int `UserCount` // 用户数
|
||||||
|
CreatedTime time.Time `CreatedTime`
|
||||||
|
|
||||||
|
Users []User `Users,omitempty` // 分组下的用户, 不保存, 仅查看
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分组好友
|
||||||
|
type GroupUser struct {
|
||||||
|
GroupUserId bson.ObjectId `bson:"_id"` // 谁的
|
||||||
|
GroupId bson.ObjectId `GroupId` // 分组
|
||||||
|
UserId bson.ObjectId `UserId` // 用户
|
||||||
|
CreatedTime time.Time `CreatedTime`
|
||||||
|
}
|
||||||
@@ -20,9 +20,11 @@ type Note struct {
|
|||||||
|
|
||||||
IsTrash bool `IsTrash` // 是否是trash, 默认是false
|
IsTrash bool `IsTrash` // 是否是trash, 默认是false
|
||||||
|
|
||||||
IsBlog bool `IsBlog,omitempty` // 是否设置成了blog 2013/12/29 新加
|
IsBlog bool `IsBlog,omitempty` // 是否设置成了blog 2013/12/29 新加
|
||||||
IsRecommend bool `IsRecommend,omitempty` // 是否为推荐博客 2014/9/24新加
|
UrlTitle string `UrlTitle,omitempty` // 博客的url标题, 为了更友好的url, 在UserId, UrlName下唯一
|
||||||
IsTop bool `IsTop,omitempty` // blog是否置顶
|
IsRecommend bool `IsRecommend,omitempty` // 是否为推荐博客 2014/9/24新加
|
||||||
|
IsTop bool `IsTop,omitempty` // blog是否置顶
|
||||||
|
HasSelfDefined bool `HasSelfDefined` // 是否已经自定义博客图片, desc, abstract
|
||||||
|
|
||||||
// 2014/9/28 添加评论社交功能
|
// 2014/9/28 添加评论社交功能
|
||||||
ReadNum int `ReadNum,omitempty` // 阅读次数 2014/9/28
|
ReadNum int `ReadNum,omitempty` // 阅读次数 2014/9/28
|
||||||
@@ -35,9 +37,9 @@ type Note struct {
|
|||||||
|
|
||||||
CreatedTime time.Time `CreatedTime`
|
CreatedTime time.Time `CreatedTime`
|
||||||
UpdatedTime time.Time `UpdatedTime`
|
UpdatedTime time.Time `UpdatedTime`
|
||||||
RecommendTime time.Time `RecommendTime,omitempty` // 推荐时间
|
RecommendTime time.Time `RecommendTime,omitempty` // 推荐时间
|
||||||
PublicTime time.Time `PublicTime,omitempty` // 发表时间, 公开为博客则设置
|
PublicTime time.Time `PublicTime,omitempty` // 发表时间, 公开为博客则设置
|
||||||
UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
|
UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
|
||||||
}
|
}
|
||||||
|
|
||||||
// 内容
|
// 内容
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ type Notebook struct {
|
|||||||
ParentNotebookId bson.ObjectId `bson:"ParentNotebookId,omitempty"` // 上级
|
ParentNotebookId bson.ObjectId `bson:"ParentNotebookId,omitempty"` // 上级
|
||||||
Seq int `Seq` // 排序
|
Seq int `Seq` // 排序
|
||||||
Title string `Title` // 标题
|
Title string `Title` // 标题
|
||||||
|
UrlTitle string `UrlTitle` // Url标题 2014/11.11加
|
||||||
NumberNotes int `NumberNotes` // 笔记数
|
NumberNotes int `NumberNotes` // 笔记数
|
||||||
IsTrash bool `IsTrash,omitempty` // 是否是trash, 默认是false
|
IsTrash bool `IsTrash,omitempty` // 是否是trash, 默认是false
|
||||||
IsBlog bool `IsBlog,omitempty` // 是否是Blog 2013/12/29 新加
|
IsBlog bool `IsBlog,omitempty` // 是否是Blog 2013/12/29 新加
|
||||||
|
|||||||
@@ -76,7 +76,9 @@ type SharingNotebookAndNotes struct {
|
|||||||
type ShareNotebook struct {
|
type ShareNotebook struct {
|
||||||
ShareNotebookId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
ShareNotebookId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||||
UserId bson.ObjectId `bson:"UserId"`
|
UserId bson.ObjectId `bson:"UserId"`
|
||||||
ToUserId bson.ObjectId `bson:"ToUserId"`
|
ToUserId bson.ObjectId `bson:"ToUserId,omitempty"`
|
||||||
|
ToGroupId bson.ObjectId `bson:"ToGroupId,omitempty"` // 分享给的用户组
|
||||||
|
ToGroup Group `ToGroup,omitempty` // 仅仅为了显示, 不存储, 分组信息
|
||||||
NotebookId bson.ObjectId `bson:"NotebookId"`
|
NotebookId bson.ObjectId `bson:"NotebookId"`
|
||||||
Seq int `bson:"Seq"` // 排序
|
Seq int `bson:"Seq"` // 排序
|
||||||
Perm int `bson:"Perm"` // 权限, 其下所有notes 0只读, 1可修改
|
Perm int `bson:"Perm"` // 权限, 其下所有notes 0只读, 1可修改
|
||||||
@@ -134,7 +136,9 @@ type ShareNotebooksByUser struct {
|
|||||||
type ShareNote struct {
|
type ShareNote struct {
|
||||||
ShareNoteId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
ShareNoteId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||||
UserId bson.ObjectId `bson:"UserId"`
|
UserId bson.ObjectId `bson:"UserId"`
|
||||||
ToUserId bson.ObjectId `bson:"ToUserId"`
|
ToUserId bson.ObjectId `bson:"ToUserId,omitempty"`
|
||||||
|
ToGroupId bson.ObjectId `bson:"ToGroupId,omitempty"` // 分享给的用户组
|
||||||
|
ToGroup Group `ToGroup,omitempty` // 仅仅为了显示, 不存储, 分组信息
|
||||||
NoteId bson.ObjectId `bson:"NoteId"`
|
NoteId bson.ObjectId `bson:"NoteId"`
|
||||||
Perm int `bson:"Perm"` // 权限, 0只读, 1可修改
|
Perm int `bson:"Perm"` // 权限, 0只读, 1可修改
|
||||||
CreatedTime time.Time `CreatedTime`
|
CreatedTime time.Time `CreatedTime`
|
||||||
|
|||||||
+24
-1
@@ -5,15 +5,38 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// 这里主要是为了统计每个tag的note数目
|
// 这里主要是为了统计每个tag的note数目
|
||||||
|
// 暂时没用
|
||||||
|
/*
|
||||||
type TagNote struct {
|
type TagNote struct {
|
||||||
TagId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
TagId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||||
UserId bson.ObjectId `bson:"UserId"`
|
UserId bson.ObjectId `bson:"UserId"`
|
||||||
Tag string `Title` // 标题
|
Tag string `Title` // 标题
|
||||||
NoteNum int `NoteNum` // note数目
|
NoteNum int `NoteNum` // note数目
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// 每个用户一条记录, 存储用户的所有tags
|
// 每个用户一条记录, 存储用户的所有tags
|
||||||
type Tag struct {
|
type Tag struct {
|
||||||
UserId bson.ObjectId `bson:"_id"`
|
UserId bson.ObjectId `bson:"_id"`
|
||||||
Tags []string `Tags`
|
Tags []string `Tags`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TagCount struct {
|
||||||
|
TagCountId bson.ObjectId `bson:"_id,omitempty"`
|
||||||
|
UserId bson.ObjectId `UserId` // 谁的
|
||||||
|
Tag string `Tag`
|
||||||
|
IsBlog bool `IsBlog` // 是否是博客的tag统计
|
||||||
|
Count int `Count` // 统计数量
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
type TagsCounts []TagCount
|
||||||
|
func (this TagsCounts) Len() int {
|
||||||
|
return len(this)
|
||||||
|
}
|
||||||
|
func (this TagsCounts) Less(i, j int) bool {
|
||||||
|
return this[i].Count > this[j].Count
|
||||||
|
}
|
||||||
|
func (this TagsCounts) Swap(i, j int) {
|
||||||
|
this[i], this[j] = this[j], this[i]
|
||||||
|
}
|
||||||
|
*/
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package info
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 主题, 每个用户有多个主题, 这里面有主题的配置信息
|
||||||
|
// 模板, css, js, images, 都在路径Path下
|
||||||
|
type Theme struct {
|
||||||
|
ThemeId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||||
|
UserId bson.ObjectId `UserId`
|
||||||
|
Name string `Name`
|
||||||
|
Version string `Version`
|
||||||
|
Author string `Author`
|
||||||
|
AuthorUrl string `AuthorUrl`
|
||||||
|
Path string `Path` // 文件夹路径
|
||||||
|
Info map[string]interface{} `Info` // 所有信息
|
||||||
|
IsActive bool `IsActive` // 是否在用
|
||||||
|
|
||||||
|
IsDefault bool `IsDefault` // leanote默认主题, 如果用户修改了默认主题, 则先copy之. 也是admin用户的主题
|
||||||
|
Style string `Style,omitempty` // 之前的, 只有default的用户才有blog_default, blog_daqi, blog_left_fixed
|
||||||
|
|
||||||
|
CreatedTime time.Time `CreatedTime`
|
||||||
|
UpdatedTime time.Time `UpdatedTime`
|
||||||
|
}
|
||||||
@@ -34,4 +34,47 @@ type User struct {
|
|||||||
ThirdUserId string `ThirdUserId` // 用户Id, 在第三方中唯一可识别
|
ThirdUserId string `ThirdUserId` // 用户Id, 在第三方中唯一可识别
|
||||||
ThirdUsername string `ThirdUsername` // 第三方中username, 为了显示
|
ThirdUsername string `ThirdUsername` // 第三方中username, 为了显示
|
||||||
ThirdType int `ThirdType` // 第三方类型
|
ThirdType int `ThirdType` // 第三方类型
|
||||||
|
|
||||||
|
// 用户的帐户类型
|
||||||
|
|
||||||
|
ImageNum int `bson:"ImageNum" json:"-"` // 图片数量
|
||||||
|
ImageSize int `bson:"ImageSize" json:"-"` // 图片大小
|
||||||
|
AttachNum int `bson:"AttachNum" json:"-"` // 附件数量
|
||||||
|
AttachSize int `bson:"AttachSize" json:"-"` // 附件大小
|
||||||
|
PerAttachSize int `bson:"PerAttachSize" json:"-"` // 单个附件大小
|
||||||
|
|
||||||
|
AccountType string `bson:"AccountType" json:"-"` // normal(为空), premium
|
||||||
|
AccountStartTime time.Time `bson:"AccountStartTime" json:"-"` // 开始日期
|
||||||
|
AccountEndTime time.Time `bson:"AccountEndTime" json:"-"` // 结束日期
|
||||||
|
// 阈值
|
||||||
|
MaxImageNum int `bson:"MaxImageNums" json:"-"` // 图片数量
|
||||||
|
MaxImageSize int `bson:"MaxImageSize" json:"-"` // 图片大小
|
||||||
|
MaxAttachNum int `bson:"MaxAttachNum" json:"-"` // 图片数量
|
||||||
|
MaxAttachSize int `bson:"MaxAttachSize" json:"-"` // 图片大小
|
||||||
|
MaxPerAttachSize int `bson:"MaxPerAttachSize" json:"-"` // 单个附件大小
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserAccount struct {
|
||||||
|
AccountType string `bson:"AccountType" json:"-"` // normal(为空), premium
|
||||||
|
AccountStartTime time.Time `bson:"AccountStartTime" json:"-"` // 开始日期
|
||||||
|
AccountEndTime time.Time `bson:"AccountEndTime" json:"-"` // 结束日期
|
||||||
|
// 阈值
|
||||||
|
MaxImageNum int `bson:"MaxImageNums" json:"-"` // 图片数量
|
||||||
|
MaxImageSize int `bson:"MaxImageSize" json:"-"` // 图片大小
|
||||||
|
MaxAttachNum int `bson:"MaxAttachNum" json:"-"` // 图片数量
|
||||||
|
MaxAttachSize int `bson:"MaxAttachSize" json:"-"` // 图片大小
|
||||||
|
MaxPerAttachSize int `bson:"MaxPerAttachSize" json:"-"` // 单个附件大小
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户与博客信息结合, 公开
|
||||||
|
type UserAndBlog struct {
|
||||||
|
UserId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||||
|
Email string `Email` // 全是小写
|
||||||
|
Username string `Username` // 不区分大小写, 全是小写
|
||||||
|
Logo string `Logo`
|
||||||
|
BlogTitle string `BlogTitle` // 博客标题
|
||||||
|
BlogLogo string `BlogLogo` // 博客Logo
|
||||||
|
BlogUrl string `BlogUrl` // 博客链接, 主页
|
||||||
|
|
||||||
|
BlogUrls // 各个页面
|
||||||
}
|
}
|
||||||
+3
-2
@@ -9,6 +9,7 @@ import (
|
|||||||
type Page struct {
|
type Page struct {
|
||||||
CurPage int // 当前页码
|
CurPage int // 当前页码
|
||||||
TotalPage int // 总页
|
TotalPage int // 总页
|
||||||
|
PerPageSize int
|
||||||
Count int // 总记录数
|
Count int // 总记录数
|
||||||
List interface{}
|
List interface{}
|
||||||
}
|
}
|
||||||
@@ -18,5 +19,5 @@ func NewPage(page, perPageSize, count int, list interface{}) Page {
|
|||||||
if count > 0 {
|
if count > 0 {
|
||||||
totalPage = int(math.Ceil(float64(count) / float64(perPageSize)))
|
totalPage = int(math.Ceil(float64(count) / float64(perPageSize)))
|
||||||
}
|
}
|
||||||
return Page{page, totalPage, count, list}
|
return Page{page, totalPage, perPageSize, count, list}
|
||||||
}
|
}
|
||||||
+22
-3
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/leanote/leanote/app/db"
|
"github.com/leanote/leanote/app/db"
|
||||||
"github.com/leanote/leanote/app/controllers"
|
"github.com/leanote/leanote/app/controllers"
|
||||||
"github.com/leanote/leanote/app/controllers/admin"
|
"github.com/leanote/leanote/app/controllers/admin"
|
||||||
|
"github.com/leanote/leanote/app/controllers/member"
|
||||||
_ "github.com/leanote/leanote/app/lea/binder"
|
_ "github.com/leanote/leanote/app/lea/binder"
|
||||||
"github.com/leanote/leanote/app/lea/session"
|
"github.com/leanote/leanote/app/lea/session"
|
||||||
"github.com/leanote/leanote/app/lea/memcache"
|
"github.com/leanote/leanote/app/lea/memcache"
|
||||||
@@ -19,6 +20,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -56,6 +58,11 @@ func init() {
|
|||||||
i = i - 1;
|
i = i - 1;
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
|
// 增加或减少
|
||||||
|
revel.TemplateFuncs["incr"] = func(n, i int) int {
|
||||||
|
n = n + i;
|
||||||
|
return n
|
||||||
|
}
|
||||||
revel.TemplateFuncs["join"] = func(arr []string) template.HTML {
|
revel.TemplateFuncs["join"] = func(arr []string) template.HTML {
|
||||||
if arr == nil {
|
if arr == nil {
|
||||||
return template.HTML("")
|
return template.HTML("")
|
||||||
@@ -72,13 +79,24 @@ func init() {
|
|||||||
}
|
}
|
||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
revel.TemplateFuncs["decodeUrlValue"] = func(i string) string {
|
||||||
|
v, _ := url.ParseQuery("a=" + i)
|
||||||
|
return v.Get("a")
|
||||||
|
}
|
||||||
revel.TemplateFuncs["json"] = func(i interface{}) string {
|
revel.TemplateFuncs["json"] = func(i interface{}) string {
|
||||||
b, _ := json.Marshal(i)
|
b, _ := json.Marshal(i)
|
||||||
return string(b)
|
return string(b)
|
||||||
}
|
}
|
||||||
|
revel.TemplateFuncs["jsonJs"] = func(i interface{}) template.JS {
|
||||||
|
b, _ := json.Marshal(i)
|
||||||
|
return template.JS(string(b))
|
||||||
|
}
|
||||||
revel.TemplateFuncs["datetime"] = func(t time.Time) template.HTML {
|
revel.TemplateFuncs["datetime"] = func(t time.Time) template.HTML {
|
||||||
return template.HTML(t.Format("2006-01-02 15:04:05"))
|
return template.HTML(t.Format("2006-01-02 15:04:05"))
|
||||||
}
|
}
|
||||||
|
revel.TemplateFuncs["dateFormat"] = func(t time.Time, format string) template.HTML {
|
||||||
|
return template.HTML(t.Format(format))
|
||||||
|
}
|
||||||
revel.TemplateFuncs["unixDatetime"] = func(unixSec string) template.HTML {
|
revel.TemplateFuncs["unixDatetime"] = func(unixSec string) template.HTML {
|
||||||
sec, _ := strconv.Atoi(unixSec)
|
sec, _ := strconv.Atoi(unixSec)
|
||||||
t := time.Unix(int64(sec), 0)
|
t := time.Unix(int64(sec), 0)
|
||||||
@@ -135,8 +153,6 @@ func init() {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
revel.TemplateFuncs["li"] = func(a string) string {
|
revel.TemplateFuncs["li"] = func(a string) string {
|
||||||
Log(a)
|
|
||||||
Log("life==")
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
// str连接
|
// str连接
|
||||||
@@ -248,6 +264,7 @@ func init() {
|
|||||||
// https://groups.google.com/forum/#!topic/golang-nuts/OEdSDgEC7js
|
// https://groups.google.com/forum/#!topic/golang-nuts/OEdSDgEC7js
|
||||||
// http://play.golang.org/p/snygrVpQva
|
// http://play.golang.org/p/snygrVpQva
|
||||||
// http://grokbase.com/t/gg/golang-nuts/142a6dhfh3/go-nuts-text-template-using-comparison-operators-eq-gt-etc-on-non-existent-variable-causes-the-template-to-stop-outputting-but-with-no-error-correct-behaviour
|
// http://grokbase.com/t/gg/golang-nuts/142a6dhfh3/go-nuts-text-template-using-comparison-operators-eq-gt-etc-on-non-existent-variable-causes-the-template-to-stop-outputting-but-with-no-error-correct-behaviour
|
||||||
|
/*
|
||||||
revel.TemplateFuncs["gt"] = func(a1, a2 interface{}) bool {
|
revel.TemplateFuncs["gt"] = func(a1, a2 interface{}) bool {
|
||||||
switch a1.(type) {
|
switch a1.(type) {
|
||||||
case string:
|
case string:
|
||||||
@@ -273,6 +290,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
{{range $i := N 1 10}}
|
{{range $i := N 1 10}}
|
||||||
@@ -302,6 +320,7 @@ func init() {
|
|||||||
service.InitService()
|
service.InitService()
|
||||||
controllers.InitService()
|
controllers.InitService()
|
||||||
admin.InitService()
|
admin.InitService()
|
||||||
|
member.InitService()
|
||||||
service.ConfigS.InitGlobalConfigs()
|
service.ConfigS.InitGlobalConfigs()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
+107
-15
@@ -1,10 +1,11 @@
|
|||||||
package lea
|
package lea
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
|
||||||
"path/filepath"
|
|
||||||
"os"
|
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 分离文件名与扩展名(包含.)
|
// 分离文件名与扩展名(包含.)
|
||||||
@@ -14,14 +15,14 @@ func SplitFilename(filename string) (baseName, ext string) {
|
|||||||
ext = SubstringByte(filename, strings.LastIndex(filename, "."))
|
ext = SubstringByte(filename, strings.LastIndex(filename, "."))
|
||||||
baseName = strings.TrimRight(filename, ext)
|
baseName = strings.TrimRight(filename, ext)
|
||||||
ext = strings.ToLower(ext)
|
ext = strings.ToLower(ext)
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 转换文件的格式
|
// 转换文件的格式
|
||||||
// toExt包含.
|
// toExt包含.
|
||||||
func TransferExt(path string, toExt string) string {
|
func TransferExt(path string, toExt string) string {
|
||||||
dir := filepath.Dir(path) + "/" // 文件路径
|
dir := filepath.Dir(path) + "/" // 文件路径
|
||||||
name := filepath.Base(path) // 文件名 a.jpg
|
name := filepath.Base(path) // 文件名 a.jpg
|
||||||
// 获取文件名与路径
|
// 获取文件名与路径
|
||||||
baseName, _ := SplitFilename(name)
|
baseName, _ := SplitFilename(name)
|
||||||
return dir + baseName + toExt
|
return dir + baseName + toExt
|
||||||
@@ -38,7 +39,7 @@ func GetFilesize(path string) int64 {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
return fileinfo.Size()
|
return fileinfo.Size()
|
||||||
}
|
}
|
||||||
return 0;
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清空dir下所有的文件和文件夹
|
// 清空dir下所有的文件和文件夹
|
||||||
@@ -79,12 +80,103 @@ func CopyFile(srcName, dstName string) (written int64, err error) {
|
|||||||
return io.Copy(dst, src)
|
return io.Copy(dst, src)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CopyDir(source string, dest string) (err error) {
|
||||||
|
// get properties of source dir
|
||||||
|
sourceinfo, err := os.Stat(source)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// create dest dir
|
||||||
|
|
||||||
|
err = os.MkdirAll(dest, sourceinfo.Mode())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
directory, _ := os.Open(source)
|
||||||
|
|
||||||
|
objects, err := directory.Readdir(-1)
|
||||||
|
|
||||||
|
for _, obj := range objects {
|
||||||
|
|
||||||
|
sourcefilepointer := source + "/" + obj.Name()
|
||||||
|
|
||||||
|
destinationfilepointer := dest + "/" + obj.Name()
|
||||||
|
|
||||||
|
if obj.IsDir() {
|
||||||
|
// create sub-directories - recursively
|
||||||
|
err = CopyDir(sourcefilepointer, destinationfilepointer)
|
||||||
|
if err != nil {
|
||||||
|
// fmt.Println(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// perform copy
|
||||||
|
_, err = CopyFile(sourcefilepointer, destinationfilepointer)
|
||||||
|
if err != nil {
|
||||||
|
// fmt.Println(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteFile(path string) bool {
|
||||||
|
err := os.Remove(path)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func IsDirExists(path string) bool {
|
func IsDirExists(path string) bool {
|
||||||
fi, err := os.Stat(path)
|
fi, err := os.Stat(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return os.IsExist(err)
|
return os.IsExist(err)
|
||||||
}else{
|
} else {
|
||||||
return fi.IsDir()
|
return fi.IsDir()
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获得文件str内容
|
||||||
|
func GetFileStrContent(path string) string {
|
||||||
|
fileBytes, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return string(fileBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsFileExist(filename string) bool {
|
||||||
|
var exist = true
|
||||||
|
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||||
|
exist = false
|
||||||
|
}
|
||||||
|
return exist
|
||||||
|
}
|
||||||
|
|
||||||
|
// 写入string内容
|
||||||
|
func PutFileStrContent(path, content string) bool {
|
||||||
|
var f *os.File
|
||||||
|
var err1 error
|
||||||
|
defer (func() {
|
||||||
|
if f != nil {
|
||||||
|
f.Close()
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
f, err1 = os.OpenFile(path, os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0666) //打开文件
|
||||||
|
// Log(err1)
|
||||||
|
// var n int
|
||||||
|
_, err1 = io.WriteString(f, content) //写入文件(字符串)
|
||||||
|
// Log(content)
|
||||||
|
// Log(err1)
|
||||||
|
// Log(n)
|
||||||
|
// Log(path)
|
||||||
|
|
||||||
|
if err1 != nil {
|
||||||
|
Log(err1)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
@@ -27,6 +27,12 @@ var rulesStr = `{
|
|||||||
],
|
],
|
||||||
"domain": [
|
"domain": [
|
||||||
{"rule": "domain", "msg": "errorDomain"}
|
{"rule": "domain", "msg": "errorDomain"}
|
||||||
|
],
|
||||||
|
"perPageSize": [
|
||||||
|
{"rule": "min", "data": "1", "msg": "errorPerPageSize"}
|
||||||
|
],
|
||||||
|
"sortField": [
|
||||||
|
{"rule": "sortField", "msg": "errorSortField"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
@@ -49,6 +55,25 @@ var rules = map[string]func(string, map[string]string)(bool, string) {
|
|||||||
ok = len(value) >= dataI
|
ok = len(value) >= dataI
|
||||||
return
|
return
|
||||||
},
|
},
|
||||||
|
"min": func(value string, rule map[string]string)(ok bool, msg string) {
|
||||||
|
if value == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data := rule["data"]
|
||||||
|
dataI, _ := strconv.Atoi(data)
|
||||||
|
vI, _ := strconv.Atoi(value)
|
||||||
|
ok = vI >= dataI
|
||||||
|
return
|
||||||
|
},
|
||||||
|
|
||||||
|
"sortField": func(value string, rule map[string]string)(ok bool, msg string) {
|
||||||
|
if value == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sortFields := []string{"PublicTime", "CreatedTime", "UpdatedTime", "Title"}
|
||||||
|
ok = InArray(sortFields, value)
|
||||||
|
return
|
||||||
|
},
|
||||||
|
|
||||||
"password": func(value string, rule map[string]string)(ok bool, msg string) {
|
"password": func(value string, rule map[string]string)(ok bool, msg string) {
|
||||||
if value == "" {
|
if value == "" {
|
||||||
|
|||||||
@@ -0,0 +1,230 @@
|
|||||||
|
package archive
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/tar"
|
||||||
|
"compress/gzip"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
)
|
||||||
|
|
||||||
|
// main functions shows how to TarGz a directory/file and
|
||||||
|
// UnTarGz a file
|
||||||
|
// Gzip and tar from source directory or file to destination file
|
||||||
|
// you need check file exist before you call this function
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
/*
|
||||||
|
os.Mkdir("/home/ty4z2008/tar", 0777)
|
||||||
|
w, err := CopyFile("/home/ty4z2008/tar/1.pdf", "/home/ty4z2008/src/1.pdf")
|
||||||
|
//targetfile,sourcefile
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
}
|
||||||
|
fmt.Println(w)
|
||||||
|
|
||||||
|
TarGz("/home/ty4z2008/tar/1.pdf", "/home/ty4z2008/test.tar.gz") //压缩
|
||||||
|
//UnTarGz("/home/ty4z2008/1.tar.gz", "/home/ty4z2008") //解压
|
||||||
|
os.RemoveAll("/home/ty4z2008/tar")
|
||||||
|
*/
|
||||||
|
// TaZip("/Users/life/Desktop/j", "/Users/life/Desktop/aaa.tar.gz")
|
||||||
|
Zip("/Users/life/Desktop/j", "/Users/life/Desktop/aaa.zip")
|
||||||
|
fmt.Println("ok")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TarGz(srcDirPath string, destFilePath string) (ok bool) {
|
||||||
|
defer func() { //必须要先声明defer,否则不能捕获到panic异常
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
|
||||||
|
}()
|
||||||
|
|
||||||
|
fw, err := os.Create(destFilePath)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer fw.Close()
|
||||||
|
|
||||||
|
// Gzip writer
|
||||||
|
gw := gzip.NewWriter(fw)
|
||||||
|
defer gw.Close()
|
||||||
|
|
||||||
|
// Tar writer
|
||||||
|
tw := tar.NewWriter(gw)
|
||||||
|
defer tw.Close()
|
||||||
|
|
||||||
|
// Check if it's a file or a directory
|
||||||
|
f, err := os.Open(srcDirPath)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fi, err := f.Stat()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if fi.IsDir() {
|
||||||
|
// handle source directory
|
||||||
|
// fmt.Println("Cerating tar.gz from directory...")
|
||||||
|
tarGzDir(srcDirPath, path.Base(srcDirPath), tw)
|
||||||
|
} else {
|
||||||
|
// handle file directly
|
||||||
|
// fmt.Println("Cerating tar.gz from " + fi.Name() + "...")
|
||||||
|
tarGzFile(srcDirPath, fi.Name(), tw, fi)
|
||||||
|
}
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deal with directories
|
||||||
|
// if find files, handle them with tarGzFile
|
||||||
|
// Every recurrence append the base path to the recPath
|
||||||
|
// recPath is the path inside of tar.gz
|
||||||
|
func tarGzDir(srcDirPath string, recPath string, tw *tar.Writer) {
|
||||||
|
// Open source diretory
|
||||||
|
dir, err := os.Open(srcDirPath)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer dir.Close()
|
||||||
|
|
||||||
|
// Get file info slice
|
||||||
|
fis, err := dir.Readdir(0)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
for _, fi := range fis {
|
||||||
|
// Append path
|
||||||
|
curPath := srcDirPath + "/" + fi.Name()
|
||||||
|
// Check it is directory or file
|
||||||
|
if fi.IsDir() {
|
||||||
|
// Directory
|
||||||
|
// (Directory won't add unitl all subfiles are added)
|
||||||
|
// fmt.Printf("Adding path...%s\n", curPath)
|
||||||
|
tarGzDir(curPath, recPath+"/"+fi.Name(), tw)
|
||||||
|
} else {
|
||||||
|
// File
|
||||||
|
// fmt.Printf("Adding file...%s\n", curPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
tarGzFile(curPath, recPath+"/"+fi.Name(), tw, fi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deal with files
|
||||||
|
func tarGzFile(srcFile string, recPath string, tw *tar.Writer, fi os.FileInfo) {
|
||||||
|
if fi.IsDir() {
|
||||||
|
// fmt.Println("??")
|
||||||
|
// Create tar header
|
||||||
|
hdr := new(tar.Header)
|
||||||
|
// if last character of header name is '/' it also can be directory
|
||||||
|
// but if you don't set Typeflag, error will occur when you untargz
|
||||||
|
hdr.Name = recPath // + "/"
|
||||||
|
// fmt.Println(hdr.Name)
|
||||||
|
hdr.Typeflag = tar.TypeDir
|
||||||
|
// hdr.Size = 0
|
||||||
|
//hdr.Mode = 0755 | c_ISDIR
|
||||||
|
// hdr.Mode = int64(fi.Mode()) // 加这个会有错误!!!
|
||||||
|
// hdr.ModTime = fi.ModTime() // 加这个会有错误!!
|
||||||
|
|
||||||
|
// Write hander
|
||||||
|
err := tw.WriteHeader(hdr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// File reader
|
||||||
|
fr, err := os.Open(srcFile)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer fr.Close()
|
||||||
|
|
||||||
|
// Create tar header
|
||||||
|
hdr := new(tar.Header)
|
||||||
|
hdr.Name = recPath
|
||||||
|
// fmt.Println(hdr.Name)
|
||||||
|
hdr.Size = fi.Size()
|
||||||
|
hdr.Mode = int64(fi.Mode())
|
||||||
|
hdr.ModTime = fi.ModTime()
|
||||||
|
|
||||||
|
// Write hander
|
||||||
|
err = tw.WriteHeader(hdr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write file data
|
||||||
|
_, err = io.Copy(tw, fr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ungzip and untar from source file to destination directory
|
||||||
|
// you need check file exist before you call this function
|
||||||
|
func UnTarGz(srcFilePath string, destDirPath string) {
|
||||||
|
// fmt.Println("UnTarGzing " + srcFilePath + "...")
|
||||||
|
// Create destination directory
|
||||||
|
os.Mkdir(destDirPath, os.ModePerm)
|
||||||
|
|
||||||
|
fr, err := os.Open(srcFilePath)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer fr.Close()
|
||||||
|
|
||||||
|
// Gzip reader
|
||||||
|
gr, err := gzip.NewReader(fr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer gr.Close()
|
||||||
|
|
||||||
|
// Tar reader
|
||||||
|
tr := tar.NewReader(gr)
|
||||||
|
|
||||||
|
for {
|
||||||
|
hdr, err := tr.Next()
|
||||||
|
if err == io.EOF {
|
||||||
|
// End of tar archive
|
||||||
|
break
|
||||||
|
}
|
||||||
|
//handleError(err)
|
||||||
|
// fmt.Println("UnTarGzing file..." + hdr.Name)
|
||||||
|
// Check if it is diretory or file
|
||||||
|
if hdr.Typeflag != tar.TypeDir {
|
||||||
|
// Get files from archive
|
||||||
|
// Create diretory before create file
|
||||||
|
os.MkdirAll(destDirPath+"/"+path.Dir(hdr.Name), os.ModePerm)
|
||||||
|
// Write data to file
|
||||||
|
fw, _ := os.Create(destDirPath + "/" + hdr.Name)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
_, err = io.Copy(fw, tr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// fmt.Println("Well done!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copyfile
|
||||||
|
func CopyFile(dstName, srcName 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)
|
||||||
|
}
|
||||||
@@ -0,0 +1,192 @@
|
|||||||
|
package archive
|
||||||
|
|
||||||
|
import (
|
||||||
|
"archive/zip"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
)
|
||||||
|
|
||||||
|
// main functions shows how to TarGz a directory/file and
|
||||||
|
// UnTarGz a file
|
||||||
|
// Gzip and tar from source directory or file to destination file
|
||||||
|
// you need check file exist before you call this function
|
||||||
|
|
||||||
|
func Zip(srcDirPath string, destFilePath string) (ok bool) {
|
||||||
|
defer func() { //必须要先声明defer,否则不能捕获到panic异常
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
fw, err := os.Create(destFilePath)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer fw.Close()
|
||||||
|
|
||||||
|
// Tar writer
|
||||||
|
tw := zip.NewWriter(fw)
|
||||||
|
defer tw.Close()
|
||||||
|
|
||||||
|
// Check if it's a file or a directory
|
||||||
|
f, err := os.Open(srcDirPath)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fi, err := f.Stat()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if fi.IsDir() {
|
||||||
|
// handle source directory
|
||||||
|
// fmt.Println("Cerating tar.gz from directory...")
|
||||||
|
zipDir(srcDirPath, path.Base(srcDirPath), tw)
|
||||||
|
} else {
|
||||||
|
// handle file directly
|
||||||
|
// fmt.Println("Cerating tar.gz from " + fi.Name() + "...")
|
||||||
|
zipFile(srcDirPath, fi.Name(), tw, fi)
|
||||||
|
}
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deal with directories
|
||||||
|
// if find files, handle them with zipFile
|
||||||
|
// Every recurrence append the base path to the recPath
|
||||||
|
// recPath is the path inside of tar.gz
|
||||||
|
func zipDir(srcDirPath string, recPath string, tw *zip.Writer) {
|
||||||
|
// Open source diretory
|
||||||
|
dir, err := os.Open(srcDirPath)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer dir.Close()
|
||||||
|
|
||||||
|
// Get file info slice
|
||||||
|
fis, err := dir.Readdir(0)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
for _, fi := range fis {
|
||||||
|
// Append path
|
||||||
|
curPath := srcDirPath + "/" + fi.Name()
|
||||||
|
// Check it is directory or file
|
||||||
|
if fi.IsDir() {
|
||||||
|
// Directory
|
||||||
|
// (Directory won't add unitl all subfiles are added)
|
||||||
|
// fmt.Printf("Adding path...%s\n", curPath)
|
||||||
|
zipDir(curPath, recPath+"/"+fi.Name(), tw)
|
||||||
|
} else {
|
||||||
|
// File
|
||||||
|
// fmt.Printf("Adding file...%s\n", curPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
zipFile(curPath, recPath+"/"+fi.Name(), tw, fi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deal with files
|
||||||
|
func zipFile(srcFile string, recPath string, tw *zip.Writer, fi os.FileInfo) {
|
||||||
|
if fi.IsDir() {
|
||||||
|
// fmt.Println("??")
|
||||||
|
// Create tar header
|
||||||
|
/*
|
||||||
|
fh, err := zip.FileInfoHeader(fi)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fh.Name = recPath // + "/"
|
||||||
|
err = tw.WriteHeader(hdr)
|
||||||
|
tw.Create(recPath)
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
// File reader
|
||||||
|
fr, err := os.Open(srcFile)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer fr.Close()
|
||||||
|
|
||||||
|
// Write hander
|
||||||
|
w, err2 := tw.Create(recPath)
|
||||||
|
if err2 != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
// Write file data
|
||||||
|
_, err = io.Copy(w, fr)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ungzip and untar from source file to destination directory
|
||||||
|
// you need check file exist before you call this function
|
||||||
|
func Unzip(srcFilePath string, destDirPath string) (ok bool, msg string) {
|
||||||
|
ok = false
|
||||||
|
msg = ""
|
||||||
|
|
||||||
|
defer func() { //必须要先声明defer,否则不能捕获到panic异常
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
msg = fmt.Sprintf("%v", err)
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
os.Mkdir(destDirPath, os.ModePerm)
|
||||||
|
r, err := zip.OpenReader(srcFilePath);
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer r.Close();
|
||||||
|
for _, f := range r.File {
|
||||||
|
// fmt.Println("FileName : ", f.Name); // j/aaa.zip
|
||||||
|
rc, err := f.Open();
|
||||||
|
if err!=nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 把首文件夹去掉, 即j去掉, 分离出文件夹和文件名
|
||||||
|
paths := strings.Split(f.Name, "/")
|
||||||
|
prePath := ""
|
||||||
|
filename := ""
|
||||||
|
l := len(paths)
|
||||||
|
// fmt.Println(l)
|
||||||
|
if l > 1 {
|
||||||
|
// 去掉第1个文件夹
|
||||||
|
if l == 2 {
|
||||||
|
filename = paths[1]
|
||||||
|
} else {
|
||||||
|
filename = paths[l-1]
|
||||||
|
prePath = strings.Join(paths[1:l-1], "/")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
filename = f.Name
|
||||||
|
}
|
||||||
|
// fmt.Println(prePath)
|
||||||
|
|
||||||
|
// 相对于目标文件件下的路径
|
||||||
|
destPath := destDirPath + "/" + filename
|
||||||
|
if prePath != "" {
|
||||||
|
os.MkdirAll(destDirPath + "/" + prePath, os.ModePerm)
|
||||||
|
destPath = destDirPath + "/" + prePath + "/" + filename
|
||||||
|
}
|
||||||
|
// Write data to file
|
||||||
|
// fmt.Println(destPath)
|
||||||
|
fw, _ := os.Create(destPath)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
_, err = io.Copy(fw, rc)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = true
|
||||||
|
return
|
||||||
|
}
|
||||||
@@ -0,0 +1,302 @@
|
|||||||
|
package blog
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/revel/revel"
|
||||||
|
"html/template"
|
||||||
|
"io/ioutil"
|
||||||
|
// "os"
|
||||||
|
"fmt"
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
//--------------------
|
||||||
|
// leanote 自定义主题
|
||||||
|
// 不使用revel的模板机制
|
||||||
|
// By life
|
||||||
|
//--------------------
|
||||||
|
|
||||||
|
var ts = []string{"header.html", "footer.html", "highlight.html", "comment.html", "view.html", "404.html"}
|
||||||
|
var selfTs = []string{"header.html", "footer.html", "index.html", "about_me.html"} // 用户自定义的文件列表
|
||||||
|
|
||||||
|
type BlogTpl struct {
|
||||||
|
Template *template.Template
|
||||||
|
PathContent map[string]string // path => content
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *BlogTpl) Content(name string) string {
|
||||||
|
return this.PathContent[name]
|
||||||
|
}
|
||||||
|
|
||||||
|
var BlogTplObject *BlogTpl
|
||||||
|
var CloneTemplate *template.Template
|
||||||
|
|
||||||
|
type RenderTemplateResult struct {
|
||||||
|
Template *template.Template
|
||||||
|
PathContent map[string]string
|
||||||
|
RenderArgs map[string]interface{}
|
||||||
|
|
||||||
|
IsPreview bool // 是否是预览
|
||||||
|
CurBlogTpl *BlogTpl
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseTemplateError(err error) (templateName string, line int, description string) {
|
||||||
|
description = err.Error()
|
||||||
|
i := regexp.MustCompile(`:\d+:`).FindStringIndex(description)
|
||||||
|
if i != nil {
|
||||||
|
line, err = strconv.Atoi(description[i[0]+1 : i[1]-1])
|
||||||
|
if err != nil {
|
||||||
|
}
|
||||||
|
templateName = description[:i[0]]
|
||||||
|
if colon := strings.Index(templateName, ":"); colon != -1 {
|
||||||
|
templateName = templateName[colon+1:]
|
||||||
|
}
|
||||||
|
templateName = strings.TrimSpace(templateName)
|
||||||
|
description = description[i[1]+1:]
|
||||||
|
}
|
||||||
|
return templateName, line, description
|
||||||
|
}
|
||||||
|
func (r *RenderTemplateResult) render(req *revel.Request, resp *revel.Response, wr io.Writer) {
|
||||||
|
err := r.Template.Execute(wr, r.RenderArgs)
|
||||||
|
if err == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var templateContent []string
|
||||||
|
templateName, line, description := parseTemplateError(err)
|
||||||
|
var content = ""
|
||||||
|
if templateName == "" {
|
||||||
|
templateName = r.Template.Name()
|
||||||
|
content = r.PathContent[templateName]
|
||||||
|
} else {
|
||||||
|
content = r.PathContent[templateName]
|
||||||
|
}
|
||||||
|
if content != "" {
|
||||||
|
templateContent = strings.Split(content, "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
compileError := &revel.Error{
|
||||||
|
Title: "Template Execution Error",
|
||||||
|
Path: templateName,
|
||||||
|
Description: description,
|
||||||
|
Line: line,
|
||||||
|
SourceLines: templateContent,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 这里, 错误!!
|
||||||
|
// 这里应该导向到本主题的错误页面
|
||||||
|
resp.Status = 500
|
||||||
|
ErrorResult{r.RenderArgs, compileError, r.IsPreview, r.CurBlogTpl}.Apply(req, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RenderTemplateResult) Apply(req *revel.Request, resp *revel.Response) {
|
||||||
|
// Handle panics when rendering templates.
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
chunked := revel.Config.BoolDefault("results.chunked", false)
|
||||||
|
|
||||||
|
// If it's a HEAD request, throw away the bytes.
|
||||||
|
out := io.Writer(resp.Out)
|
||||||
|
if req.Method == "HEAD" {
|
||||||
|
out = ioutil.Discard
|
||||||
|
}
|
||||||
|
|
||||||
|
// In a prod mode, write the status, render, and hope for the best.
|
||||||
|
// (In a dev mode, always render to a temporary buffer first to avoid having
|
||||||
|
// error pages distorted by HTML already written)
|
||||||
|
if chunked && !revel.DevMode {
|
||||||
|
resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8")
|
||||||
|
r.render(req, resp, out) // 这里!!!
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render the template into a temporary buffer, to see if there was an error
|
||||||
|
// rendering the template. If not, then copy it into the response buffer.
|
||||||
|
// Otherwise, template render errors may result in unpredictable HTML (and
|
||||||
|
// would carry a 200 status code)
|
||||||
|
var b bytes.Buffer
|
||||||
|
r.render(req, resp, &b)
|
||||||
|
if !chunked {
|
||||||
|
resp.Out.Header().Set("Content-Length", strconv.Itoa(b.Len()))
|
||||||
|
}
|
||||||
|
resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8")
|
||||||
|
b.WriteTo(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 博客模板
|
||||||
|
func Init() {
|
||||||
|
BlogTplObject = &BlogTpl{PathContent: map[string]string{}}
|
||||||
|
BlogTplObject.Template = template.New("blog").Funcs(revel.TemplateFuncs)
|
||||||
|
for _, path := range ts {
|
||||||
|
fileBytes, _ := ioutil.ReadFile(revel.ViewsPath + "/Blog/" + path)
|
||||||
|
fileStr := string(fileBytes)
|
||||||
|
path := "blog/" + path
|
||||||
|
// path := path
|
||||||
|
BlogTplObject.PathContent[path] = fileStr
|
||||||
|
BlogTplObject.Template.New(path).Parse(fileStr) // 以blog为根
|
||||||
|
}
|
||||||
|
// 复制一份
|
||||||
|
CloneTemplate, _ = BlogTplObject.Template.Clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
// name = index.html, search.html, cate.html, page.html
|
||||||
|
// basePath 表未用户主题的基路径, 如/xxx/public/upload/32323232/themes/theme1, 如果没有, 则表示用自带的
|
||||||
|
// isPreview 如果是, 错误提示则显示系统的 500 错误详情信息, 供debug
|
||||||
|
//
|
||||||
|
func RenderTemplate(name string, args map[string]interface{}, basePath string, isPreview bool) revel.Result {
|
||||||
|
var r *RenderTemplateResult
|
||||||
|
// 传来的主题路径为空, 则用系统的
|
||||||
|
// 都不会为空的
|
||||||
|
if basePath == "" {
|
||||||
|
path := "blog/" + name
|
||||||
|
// path := name
|
||||||
|
t := BlogTplObject.Template.Lookup(path)
|
||||||
|
r = &RenderTemplateResult{
|
||||||
|
Template: t,
|
||||||
|
PathContent: BlogTplObject.PathContent, // 为了显示错误
|
||||||
|
RenderArgs: args, // 把args给它
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 复制一份
|
||||||
|
newBlogTplObject := &BlogTpl{}
|
||||||
|
var err error
|
||||||
|
newBlogTplObject.Template, err = CloneTemplate.Clone() // 复制一份, 为防止多用户出现问题, 因为newBlogTplObject是全局的
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
newBlogTplObject.PathContent = map[string]string{}
|
||||||
|
for k, v := range BlogTplObject.PathContent {
|
||||||
|
newBlogTplObject.PathContent[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将该basePath下的所有文件提出
|
||||||
|
files := ListDir(basePath)
|
||||||
|
Log(basePath)
|
||||||
|
LogJ(files);
|
||||||
|
for _, t := range files {
|
||||||
|
if !strings.Contains(t, ".html") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fileBytes, err := ioutil.ReadFile(basePath + "/" + t)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fileStr := string(fileBytes)
|
||||||
|
newBlogTplObject.PathContent[t] = fileStr
|
||||||
|
newBlogTplObject.Template.New(t).Parse(fileStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果本主题下没有, 则用系统的
|
||||||
|
t := newBlogTplObject.Template.Lookup(name)
|
||||||
|
|
||||||
|
if t == nil {
|
||||||
|
path := "blog/" + name
|
||||||
|
t = BlogTplObject.Template.Lookup(path)
|
||||||
|
}
|
||||||
|
r = &RenderTemplateResult{
|
||||||
|
Template: t,
|
||||||
|
PathContent: newBlogTplObject.PathContent, // 为了显示错误
|
||||||
|
RenderArgs: args,
|
||||||
|
CurBlogTpl: newBlogTplObject,
|
||||||
|
IsPreview: isPreview,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////
|
||||||
|
// 错误显示
|
||||||
|
|
||||||
|
type ErrorResult struct {
|
||||||
|
RenderArgs map[string]interface{}
|
||||||
|
Error error
|
||||||
|
IsPreview bool
|
||||||
|
CurBlogTpl *BlogTpl
|
||||||
|
}
|
||||||
|
|
||||||
|
// 错误显示出
|
||||||
|
func (r ErrorResult) Apply(req *revel.Request, resp *revel.Response) {
|
||||||
|
format := req.Format
|
||||||
|
status := resp.Status
|
||||||
|
if status == 0 {
|
||||||
|
status = http.StatusInternalServerError
|
||||||
|
}
|
||||||
|
|
||||||
|
contentType := revel.ContentTypeByFilename("xxx." + format)
|
||||||
|
if contentType == revel.DefaultFileContentType {
|
||||||
|
contentType = "text/plain"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the error template.
|
||||||
|
var err error
|
||||||
|
templatePath := fmt.Sprintf("errors/%d.%s", status, format)
|
||||||
|
err = nil
|
||||||
|
// tmpl, err := revel.MainTemplateLoader.Template("index.html") // 这里找到错误页面主题
|
||||||
|
|
||||||
|
// This func shows a plaintext error message, in case the template rendering
|
||||||
|
// doesn't work.
|
||||||
|
showPlaintext := func(err error) {
|
||||||
|
revel.PlaintextErrorResult{fmt.Errorf("Server Error:\n%s\n\n"+
|
||||||
|
"Additionally, an error occurred when rendering the error page:\n%s",
|
||||||
|
r.Error, err)}.Apply(req, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据是否是preview来得到404模板
|
||||||
|
// 是, 则显示系统的错误信息, blog-500.html
|
||||||
|
var tmpl *template.Template
|
||||||
|
if r.IsPreview {
|
||||||
|
tmpl = r.CurBlogTpl.Template.Lookup("blog/404.html")
|
||||||
|
} else {
|
||||||
|
tmpl = r.CurBlogTpl.Template.Lookup("404.html")
|
||||||
|
}
|
||||||
|
if tmpl == nil {
|
||||||
|
if err == nil {
|
||||||
|
err = fmt.Errorf("Couldn't find template %s", templatePath)
|
||||||
|
}
|
||||||
|
showPlaintext(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it's not a revel error, wrap it in one.
|
||||||
|
var revelError *revel.Error
|
||||||
|
switch e := r.Error.(type) {
|
||||||
|
case *revel.Error:
|
||||||
|
revelError = e
|
||||||
|
case error:
|
||||||
|
revelError = &revel.Error{
|
||||||
|
Title: "Server Error",
|
||||||
|
Description: e.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if revelError == nil {
|
||||||
|
panic("no error provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.RenderArgs == nil {
|
||||||
|
r.RenderArgs = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
r.RenderArgs["Error"] = revelError
|
||||||
|
r.RenderArgs["Router"] = revel.MainRouter
|
||||||
|
|
||||||
|
// 不是preview就不要显示错误了
|
||||||
|
LogJ(revelError)
|
||||||
|
// if r.IsPreview {
|
||||||
|
var b bytes.Buffer
|
||||||
|
out := io.Writer(resp.Out)
|
||||||
|
// out = ioutil.Discard
|
||||||
|
err = tmpl.Execute(&b, r.RenderArgs)
|
||||||
|
resp.WriteHeader(http.StatusOK, "text/html; charset=utf-8")
|
||||||
|
b.WriteTo(out)
|
||||||
|
// }
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"os"
|
"os"
|
||||||
// "path/filepath"
|
// "path/filepath"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
. "github.com/leanote/leanote/app/lea"
|
. "github.com/leanote/leanote/app/lea"
|
||||||
@@ -89,4 +90,13 @@ func trimQueryParams(url string) string {
|
|||||||
url = Substr(url, 0, pos);
|
url = Substr(url, 0, pos);
|
||||||
}
|
}
|
||||||
return url;
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通过domain得到ip
|
||||||
|
func GetIpFromDomain(domain string) string {
|
||||||
|
ip, _ := net.LookupIP(domain)
|
||||||
|
if ip != nil && len(ip) > 0 {
|
||||||
|
return ip[0].String()
|
||||||
|
}
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
@@ -44,8 +44,12 @@ func RouterFilter(c *revel.Controller, fc []revel.Filter) {
|
|||||||
if route.ControllerName != "Static" {
|
if route.ControllerName != "Static" {
|
||||||
// api设置
|
// api设置
|
||||||
// leanote.com/api/user/get => ApiUser::Get
|
// leanote.com/api/user/get => ApiUser::Get
|
||||||
if strings.HasPrefix(path, "/api/") || strings.HasPrefix(path, "api/") {
|
//* /api/login ApiAuth.Login, 这里的设置, 其实已经转成了ApiAuth了
|
||||||
|
if strings.HasPrefix(path, "/api") && !strings.HasPrefix(route.ControllerName, "Api"){
|
||||||
route.ControllerName = "Api" + route.ControllerName
|
route.ControllerName = "Api" + route.ControllerName
|
||||||
|
} else if strings.HasPrefix(path, "/member") && !strings.HasPrefix(route.ControllerName, "Member") {
|
||||||
|
// member设置
|
||||||
|
route.ControllerName = "Member" + route.ControllerName
|
||||||
}
|
}
|
||||||
// end
|
// end
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ func (this *AuthService) Login(emailOrUsername, pwd string) info.User {
|
|||||||
func (this *AuthService) Register(email, pwd string) (bool, string) {
|
func (this *AuthService) Register(email, pwd string) (bool, string) {
|
||||||
// 用户是否已存在
|
// 用户是否已存在
|
||||||
if userService.IsExistsUser(email) {
|
if userService.IsExistsUser(email) {
|
||||||
return false, email + " 已被注册"
|
return false, "userHasBeenRegistered-" + email
|
||||||
}
|
}
|
||||||
user := info.User{UserId: bson.NewObjectId(), Email: email, Username: email, Pwd: Md5(pwd)}
|
user := info.User{UserId: bson.NewObjectId(), Email: email, Username: email, Pwd: Md5(pwd)}
|
||||||
return this.register(user)
|
return this.register(user)
|
||||||
@@ -90,7 +90,10 @@ func (this *AuthService) register(user info.User) (bool, string) {
|
|||||||
Title: user.Username + " 's Blog",
|
Title: user.Username + " 's Blog",
|
||||||
SubTitle: "love leanote!",
|
SubTitle: "love leanote!",
|
||||||
AboutMe: "Hello, I am (^_^)",
|
AboutMe: "Hello, I am (^_^)",
|
||||||
|
CanComment: true,
|
||||||
})
|
})
|
||||||
|
// 添加一个单页面
|
||||||
|
blogService.AddOrUpdateSingle(user.UserId.Hex(), "", "About Me", "Hello, I am (^_^)")
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, ""
|
return true, ""
|
||||||
|
|||||||
+800
-158
File diff suppressed because it is too large.
Load diff
@@ -17,6 +17,9 @@ import (
|
|||||||
// 配置服务
|
// 配置服务
|
||||||
// 只是全局的, 用户的配置没有
|
// 只是全局的, 用户的配置没有
|
||||||
type ConfigService struct {
|
type ConfigService struct {
|
||||||
|
adminUserId string
|
||||||
|
siteUrl string
|
||||||
|
adminUsername string
|
||||||
// 全局的
|
// 全局的
|
||||||
GlobalAllConfigs map[string]interface{}
|
GlobalAllConfigs map[string]interface{}
|
||||||
GlobalStringConfigs map[string]string
|
GlobalStringConfigs map[string]string
|
||||||
@@ -24,9 +27,6 @@ type ConfigService struct {
|
|||||||
GlobalMapConfigs map[string]map[string]string
|
GlobalMapConfigs map[string]map[string]string
|
||||||
GlobalArrMapConfigs map[string][]map[string]string
|
GlobalArrMapConfigs map[string][]map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
var adminUserId = ""
|
|
||||||
|
|
||||||
// appStart时 将全局的配置从数据库中得到作为全局
|
// appStart时 将全局的配置从数据库中得到作为全局
|
||||||
func (this *ConfigService) InitGlobalConfigs() bool {
|
func (this *ConfigService) InitGlobalConfigs() bool {
|
||||||
this.GlobalAllConfigs = map[string]interface{}{}
|
this.GlobalAllConfigs = map[string]interface{}{}
|
||||||
@@ -35,16 +35,17 @@ func (this *ConfigService) InitGlobalConfigs() bool {
|
|||||||
this.GlobalMapConfigs = map[string]map[string]string{}
|
this.GlobalMapConfigs = map[string]map[string]string{}
|
||||||
this.GlobalArrMapConfigs = map[string][]map[string]string{}
|
this.GlobalArrMapConfigs = map[string][]map[string]string{}
|
||||||
|
|
||||||
adminUsername, _ := revel.Config.String("adminUsername")
|
this.adminUsername, _ = revel.Config.String("adminUsername")
|
||||||
if adminUsername == "" {
|
if this.adminUsername == "" {
|
||||||
adminUsername = "admin"
|
this.adminUsername = "admin"
|
||||||
}
|
}
|
||||||
|
this.siteUrl, _ = revel.Config.String("site.url")
|
||||||
|
|
||||||
userInfo := userService.GetUserInfoByAny(adminUsername)
|
userInfo := userService.GetUserInfoByAny(this.adminUsername)
|
||||||
if userInfo.UserId == "" {
|
if userInfo.UserId == "" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
adminUserId = userInfo.UserId.Hex()
|
this.adminUserId = userInfo.UserId.Hex()
|
||||||
|
|
||||||
configs := []info.Config{}
|
configs := []info.Config{}
|
||||||
db.ListByQ(db.Configs, bson.M{"UserId": userInfo.UserId}, &configs)
|
db.ListByQ(db.Configs, bson.M{"UserId": userInfo.UserId}, &configs)
|
||||||
@@ -68,6 +69,16 @@ func (this *ConfigService) InitGlobalConfigs() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *ConfigService) GetSiteUrl() string {
|
||||||
|
return this.siteUrl;
|
||||||
|
}
|
||||||
|
func (this *ConfigService) GetAdminUsername() string {
|
||||||
|
return this.adminUsername
|
||||||
|
}
|
||||||
|
func (this *ConfigService) GetAdminUserId() string {
|
||||||
|
return this.adminUserId
|
||||||
|
}
|
||||||
|
|
||||||
// 通用方法
|
// 通用方法
|
||||||
func (this *ConfigService) updateGlobalConfig(userId, key string, value interface{}, isArr, isMap, isArrMap bool) bool {
|
func (this *ConfigService) updateGlobalConfig(userId, key string, value interface{}, isArr, isMap, isArrMap bool) bool {
|
||||||
// 判断是否存在
|
// 判断是否存在
|
||||||
@@ -183,7 +194,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
|
|||||||
if registerSharedUserId == "" {
|
if registerSharedUserId == "" {
|
||||||
ok = true
|
ok = true
|
||||||
msg = "share userId is blank, So it share nothing to register"
|
msg = "share userId is blank, So it share nothing to register"
|
||||||
this.UpdateGlobalStringConfig(adminUserId, "registerSharedUserId", "")
|
this.UpdateGlobalStringConfig(this.adminUserId, "registerSharedUserId", "")
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
user := userService.GetUserInfo(registerSharedUserId)
|
user := userService.GetUserInfo(registerSharedUserId)
|
||||||
@@ -192,7 +203,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
|
|||||||
msg = "no such user: " + registerSharedUserId
|
msg = "no such user: " + registerSharedUserId
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
this.UpdateGlobalStringConfig(adminUserId, "registerSharedUserId", registerSharedUserId)
|
this.UpdateGlobalStringConfig(this.adminUserId, "registerSharedUserId", registerSharedUserId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,7 +230,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.UpdateGlobalArrMapConfig(adminUserId, "registerSharedNotebooks", notebooks)
|
this.UpdateGlobalArrMapConfig(this.adminUserId, "registerSharedNotebooks", notebooks)
|
||||||
|
|
||||||
notes := []map[string]string{}
|
notes := []map[string]string{}
|
||||||
// 共享笔记
|
// 共享笔记
|
||||||
@@ -244,7 +255,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.UpdateGlobalArrMapConfig(adminUserId, "registerSharedNotes", notes)
|
this.UpdateGlobalArrMapConfig(this.adminUserId, "registerSharedNotes", notes)
|
||||||
|
|
||||||
// 复制
|
// 复制
|
||||||
noteIds := []string{}
|
noteIds := []string{}
|
||||||
@@ -265,7 +276,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.UpdateGlobalArrayConfig(adminUserId, "registerCopyNoteIds", noteIds)
|
this.UpdateGlobalArrayConfig(this.adminUserId, "registerCopyNoteIds", noteIds)
|
||||||
|
|
||||||
ok = true
|
ok = true
|
||||||
return
|
return
|
||||||
@@ -277,7 +288,7 @@ func (this *ConfigService) AddBackup(path, remark string) bool {
|
|||||||
n := time.Now().Unix()
|
n := time.Now().Unix()
|
||||||
nstr := fmt.Sprintf("%v", n)
|
nstr := fmt.Sprintf("%v", n)
|
||||||
backups = append(backups, map[string]string{"createdTime": nstr, "path": path, "remark": remark})
|
backups = append(backups, map[string]string{"createdTime": nstr, "path": path, "remark": remark})
|
||||||
return this.UpdateGlobalArrMapConfig(adminUserId, "backups", backups)
|
return this.UpdateGlobalArrMapConfig(this.adminUserId, "backups", backups)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *ConfigService) getBackupDirname() string {
|
func (this *ConfigService) getBackupDirname() string {
|
||||||
@@ -349,7 +360,7 @@ func (this *ConfigService) Restore(createdTime string) (ok bool, msg string) {
|
|||||||
port, _ := revel.Config.String("db.port")
|
port, _ := revel.Config.String("db.port")
|
||||||
username, _ := revel.Config.String("db.username")
|
username, _ := revel.Config.String("db.username")
|
||||||
password, _ := revel.Config.String("db.password")
|
password, _ := revel.Config.String("db.password")
|
||||||
// mongorestore -h localhost -d leanote -o /root/mongodb_backup/leanote-9-22/ -u leanote -p kk
|
// mongorestore -h localhost -d leanote -o /root/mongodb_backup/leanote-9-22/ -u leanote -p nKFAkxKnWkEQy8Vv2LlM
|
||||||
binPath = binPath + " --drop -h " + host + " -d " + dbname + " -port " + port
|
binPath = binPath + " --drop -h " + host + " -d " + dbname + " -port " + port
|
||||||
if username != "" {
|
if username != "" {
|
||||||
binPath += " -u " + username + " -p " + password
|
binPath += " -u " + username + " -p " + password
|
||||||
@@ -398,7 +409,7 @@ func (this *ConfigService) DeleteBackup(createdTime string) (bool, string) {
|
|||||||
// 删除之
|
// 删除之
|
||||||
backups = append(backups[0:i], backups[i+1:]...)
|
backups = append(backups[0:i], backups[i+1:]...)
|
||||||
|
|
||||||
ok := this.UpdateGlobalArrMapConfig(adminUserId, "backups", backups)
|
ok := this.UpdateGlobalArrMapConfig(this.adminUserId, "backups", backups)
|
||||||
return ok, ""
|
return ok, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -416,7 +427,7 @@ func (this *ConfigService) UpdateBackupRemark(createdTime, remark string) (bool,
|
|||||||
}
|
}
|
||||||
backup["remark"] = remark;
|
backup["remark"] = remark;
|
||||||
|
|
||||||
ok := this.UpdateGlobalArrMapConfig(adminUserId, "backups", backups)
|
ok := this.UpdateGlobalArrMapConfig(this.adminUserId, "backups", backups)
|
||||||
return ok, ""
|
return ok, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -451,7 +462,7 @@ func init() {
|
|||||||
port = "";
|
port = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
siteUrl, _ = revel.Config.String("site.url") // 已包含:9000, http, 去掉成 leanote.com
|
siteUrl, _ := revel.Config.String("site.url") // 已包含:9000, http, 去掉成 leanote.com
|
||||||
if strings.HasPrefix(siteUrl, "http://") {
|
if strings.HasPrefix(siteUrl, "http://") {
|
||||||
defaultDomain = siteUrl[len("http://"):]
|
defaultDomain = siteUrl[len("http://"):]
|
||||||
} else if strings.HasPrefix(siteUrl, "https://") {
|
} else if strings.HasPrefix(siteUrl, "https://") {
|
||||||
@@ -461,7 +472,6 @@ func init() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (this *ConfigService) GetSchema() string {
|
func (this *ConfigService) GetSchema() string {
|
||||||
return schema;
|
return schema;
|
||||||
}
|
}
|
||||||
@@ -539,3 +549,36 @@ func (this *ConfigService) IsGoodSubDomain(domain string) bool {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 上传大小
|
||||||
|
func (this *ConfigService) GetUploadSize(key string) float64 {
|
||||||
|
f, _ := strconv.ParseFloat(this.GetGlobalStringConfig(key), 64)
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
func (this *ConfigService) GetUploadSizeLimit() map[string]float64 {
|
||||||
|
return map[string]float64{
|
||||||
|
"uploadImageSize": this.GetUploadSize("uploadImageSize"),
|
||||||
|
"uploadBlogLogoSize":this.GetUploadSize("uploadBlogLogoSize"),
|
||||||
|
"uploadAttachSize":this.GetUploadSize("uploadAttachSize"),
|
||||||
|
"uploadAvatarSize":this.GetUploadSize("uploadAvatarSize"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 为用户得到全局的配置
|
||||||
|
// NoteController调用
|
||||||
|
func (this *ConfigService) GetGlobalConfigForUser() map[string]interface{} {
|
||||||
|
uploadSizeConfigs := this.GetUploadSizeLimit();
|
||||||
|
config := map[string]interface{}{}
|
||||||
|
for k, v := range uploadSizeConfigs {
|
||||||
|
config[k] = v
|
||||||
|
}
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
// 主页是否是管理员的博客页
|
||||||
|
func (this *ConfigService) HomePageIsAdminsBlog() bool {
|
||||||
|
return this.GetGlobalStringConfig("homePage") == ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ConfigService) GetVersion() string {
|
||||||
|
return "1.0-beta2"
|
||||||
|
}
|
||||||
+10
-10
@@ -82,9 +82,9 @@ func (this *EmailService) RegisterSendActiveEmail(userInfo info.User, email stri
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
tokenUrl := siteUrl + "/user/activeEmail?token=" + token
|
tokenUrl := configService.GetSiteUrl() + "/user/activeEmail?token=" + token
|
||||||
// {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.id} {user.email} {user.username}
|
// {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.id} {user.email} {user.username}
|
||||||
token2Value := map[string]interface{}{"siteUrl": siteUrl, "tokenUrl": tokenUrl, "token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail))),
|
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "tokenUrl": tokenUrl, "token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail))),
|
||||||
"user": map[string]interface{}{
|
"user": map[string]interface{}{
|
||||||
"userId": userInfo.UserId.Hex(),
|
"userId": userInfo.UserId.Hex(),
|
||||||
"email": userInfo.Email,
|
"email": userInfo.Email,
|
||||||
@@ -122,9 +122,9 @@ func (this *EmailService) UpdateEmailSendActiveEmail(userInfo info.User, email s
|
|||||||
tpl := configService.GetGlobalStringConfig("emailTemplateUpdateEmail");
|
tpl := configService.GetGlobalStringConfig("emailTemplateUpdateEmail");
|
||||||
|
|
||||||
// 发送邮件
|
// 发送邮件
|
||||||
tokenUrl := siteUrl + "/user/updateEmail?token=" + token
|
tokenUrl := configService.GetSiteUrl() + "/user/updateEmail?token=" + token
|
||||||
// {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.userId} {user.email} {user.username}
|
// {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.userId} {user.email} {user.username}
|
||||||
token2Value := map[string]interface{}{"siteUrl": siteUrl, "tokenUrl": tokenUrl, "token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail))),
|
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "tokenUrl": tokenUrl, "token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail))),
|
||||||
"newEmail": email,
|
"newEmail": email,
|
||||||
"user": map[string]interface{}{
|
"user": map[string]interface{}{
|
||||||
"userId": userInfo.UserId.Hex(),
|
"userId": userInfo.UserId.Hex(),
|
||||||
@@ -148,9 +148,9 @@ func (this *EmailService) FindPwdSendEmail(token, email string) (ok bool, msg st
|
|||||||
tpl := configService.GetGlobalStringConfig("emailTemplateFindPassword");
|
tpl := configService.GetGlobalStringConfig("emailTemplateFindPassword");
|
||||||
|
|
||||||
// 发送邮件
|
// 发送邮件
|
||||||
tokenUrl := siteUrl + "/findPassword/" + token
|
tokenUrl := configService.GetSiteUrl() + "/findPassword/" + token
|
||||||
// {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.id} {user.email} {user.username}
|
// {siteUrl} {tokenUrl} {token} {tokenTimeout} {user.id} {user.email} {user.username}
|
||||||
token2Value := map[string]interface{}{"siteUrl": siteUrl, "tokenUrl": tokenUrl,
|
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "tokenUrl": tokenUrl,
|
||||||
"token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail)))}
|
"token": token, "tokenTimeout": strconv.Itoa(int(tokenService.GetOverHours(info.TokenActiveEmail)))}
|
||||||
|
|
||||||
ok, msg, subject, tpl = this.renderEmail(subject, tpl, token2Value)
|
ok, msg, subject, tpl = this.renderEmail(subject, tpl, token2Value)
|
||||||
@@ -167,8 +167,8 @@ func (this *EmailService) SendInviteEmail(userInfo info.User, email, content str
|
|||||||
subject := configService.GetGlobalStringConfig("emailTemplateInviteSubject");
|
subject := configService.GetGlobalStringConfig("emailTemplateInviteSubject");
|
||||||
tpl := configService.GetGlobalStringConfig("emailTemplateInvite");
|
tpl := configService.GetGlobalStringConfig("emailTemplateInvite");
|
||||||
|
|
||||||
token2Value := map[string]interface{}{"siteUrl": siteUrl,
|
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(),
|
||||||
"registerUrl": siteUrl + "/register?from=" + userInfo.Username,
|
"registerUrl": configService.GetSiteUrl() + "/register?from=" + userInfo.Username,
|
||||||
"content": content,
|
"content": content,
|
||||||
"user": map[string]interface{}{
|
"user": map[string]interface{}{
|
||||||
"username": userInfo.Username,
|
"username": userInfo.Username,
|
||||||
@@ -225,7 +225,7 @@ func (this *EmailService) SendCommentEmail(note info.Note, comment info.BlogComm
|
|||||||
// {blog.id} {blog.title} {blog.url}
|
// {blog.id} {blog.title} {blog.url}
|
||||||
// {commentUser.userId} {commentUser.username} {commentUser.email}
|
// {commentUser.userId} {commentUser.username} {commentUser.email}
|
||||||
// {commentedUser.userId} {commentedUser.username} {commentedUser.email}
|
// {commentedUser.userId} {commentedUser.username} {commentedUser.email}
|
||||||
token2Value := map[string]interface{}{"siteUrl": siteUrl, "blogUrl": configService.GetBlogUrl(),
|
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(), "blogUrl": configService.GetBlogUrl(),
|
||||||
"blog": map[string]string{
|
"blog": map[string]string{
|
||||||
"id": note.NoteId.Hex(),
|
"id": note.NoteId.Hex(),
|
||||||
"title": note.Title,
|
"title": note.Title,
|
||||||
@@ -316,7 +316,7 @@ func (this *EmailService) renderEmail(subject, body string, values map[string]in
|
|||||||
|
|
||||||
var tpl *template.Template
|
var tpl *template.Template
|
||||||
|
|
||||||
values["siteUrl"] = siteUrl;
|
values["siteUrl"] = configService.GetSiteUrl();
|
||||||
|
|
||||||
// subject
|
// subject
|
||||||
if subject != "" {
|
if subject != "" {
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
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"
|
||||||
|
"time"
|
||||||
|
// "strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 用户组, 用户组用户管理
|
||||||
|
|
||||||
|
type GroupService struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加分组
|
||||||
|
func (this *GroupService) AddGroup(userId, title string) (bool, info.Group) {
|
||||||
|
group := info.Group {
|
||||||
|
GroupId: bson.NewObjectId(),
|
||||||
|
UserId: bson.ObjectIdHex(userId),
|
||||||
|
Title: title,
|
||||||
|
CreatedTime: time.Now(),
|
||||||
|
}
|
||||||
|
return db.Insert(db.Groups, group), group
|
||||||
|
}
|
||||||
|
// 删除分组
|
||||||
|
// 判断是否有好友
|
||||||
|
func (this *GroupService) DeleteGroup(userId, groupId string) (ok bool, msg string) {
|
||||||
|
if db.Has(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId)}) {
|
||||||
|
return false, "hasUsers"
|
||||||
|
}
|
||||||
|
return db.DeleteByIdAndUserId(db.Groups, groupId, userId), ""
|
||||||
|
|
||||||
|
// TODO 删除分组后, 在shareNote, shareNotebook中也要删除
|
||||||
|
}
|
||||||
|
// 修改group标题
|
||||||
|
func (this *GroupService) UpdateGroupTitle(userId, groupId, title string) (ok bool) {
|
||||||
|
return db.UpdateByIdAndUserIdField(db.Groups, groupId, userId, "Title", title)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到用户的所有分组(包括下的所有用户)
|
||||||
|
func (this *GroupService) GetGroupsAndUsers(userId string) ([]info.Group) {
|
||||||
|
// 得到分组s
|
||||||
|
groups := []info.Group{}
|
||||||
|
db.ListByQ(db.Groups, bson.M{"UserId": bson.ObjectIdHex(userId)}, &groups)
|
||||||
|
// 得到其下的用户
|
||||||
|
for i, group := range groups {
|
||||||
|
group.Users = this.GetUsers(group.GroupId.Hex())
|
||||||
|
groups[i] = group
|
||||||
|
}
|
||||||
|
return groups
|
||||||
|
}
|
||||||
|
// 仅仅得到所有分组
|
||||||
|
func (this *GroupService) GetGroups(userId string) ([]info.Group) {
|
||||||
|
// 得到分组s
|
||||||
|
groups := []info.Group{}
|
||||||
|
db.ListByQ(db.Groups, bson.M{"UserId": bson.ObjectIdHex(userId)}, &groups)
|
||||||
|
return groups
|
||||||
|
}
|
||||||
|
// 得到分组, shareService用
|
||||||
|
func (this *GroupService) GetGroup(userId, groupId string) (info.Group) {
|
||||||
|
// 得到分组s
|
||||||
|
group := info.Group{}
|
||||||
|
db.GetByIdAndUserId(db.Groups, groupId, userId, &group)
|
||||||
|
return group
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到某分组下的用户
|
||||||
|
func (this *GroupService) GetUsers(groupId string) ([]info.User) {
|
||||||
|
// 得到UserIds
|
||||||
|
groupUsers := []info.GroupUser{}
|
||||||
|
db.ListByQWithFields(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId)}, []string{"UserId"}, &groupUsers)
|
||||||
|
if len(groupUsers) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
userIds := make([]bson.ObjectId, len(groupUsers))
|
||||||
|
for i, each := range groupUsers {
|
||||||
|
userIds[i] = each.UserId
|
||||||
|
}
|
||||||
|
// 得到userInfos
|
||||||
|
return userService.ListUserInfosByUserIds(userIds)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到我所属的所有分组ids
|
||||||
|
func (this *GroupService) GetBelongToGroupIds(userId string) ([]bson.ObjectId) {
|
||||||
|
// 得到UserIds
|
||||||
|
groupUsers := []info.GroupUser{}
|
||||||
|
db.ListByQWithFields(db.GroupUsers, bson.M{"UserId": bson.ObjectIdHex(userId)}, []string{"GroupId"}, &groupUsers)
|
||||||
|
if len(groupUsers) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
groupIds := make([]bson.ObjectId, len(groupUsers))
|
||||||
|
for i, each := range groupUsers {
|
||||||
|
groupIds[i] = each.GroupId
|
||||||
|
}
|
||||||
|
return groupIds
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *GroupService) isMyGroup(ownUserId, groupId string) (ok bool) {
|
||||||
|
return db.Has(db.Groups, bson.M{"_id": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(ownUserId)})
|
||||||
|
}
|
||||||
|
// 为group添加用户
|
||||||
|
// 用户是否已存在?
|
||||||
|
func (this *GroupService) AddUser(ownUserId, groupId, userId string) (ok bool, msg string) {
|
||||||
|
// groupId是否是ownUserId的?
|
||||||
|
if !this.isMyGroup(ownUserId, groupId) {
|
||||||
|
return false, "forbidden"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 是否已存在
|
||||||
|
if db.Has(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(userId)}) {
|
||||||
|
return false, "hasUsers"
|
||||||
|
}
|
||||||
|
|
||||||
|
return db.Insert(db.GroupUsers, info.GroupUser{
|
||||||
|
GroupUserId: bson.NewObjectId(),
|
||||||
|
GroupId: bson.ObjectIdHex(groupId),
|
||||||
|
UserId: bson.ObjectIdHex(userId),
|
||||||
|
CreatedTime: time.Now(),
|
||||||
|
}), ""
|
||||||
|
}
|
||||||
|
// 删除用户
|
||||||
|
func (this *GroupService) DeleteUser(ownUserId, groupId, userId string) (ok bool, msg string) {
|
||||||
|
// groupId是否是ownUserId的?
|
||||||
|
if !this.isMyGroup(ownUserId, groupId) {
|
||||||
|
return false, "forbidden"
|
||||||
|
}
|
||||||
|
return db.Delete(db.GroupUsers, bson.M{"GroupId": bson.ObjectIdHex(groupId), "UserId": bson.ObjectIdHex(userId)}), ""
|
||||||
|
}
|
||||||
@@ -32,7 +32,12 @@ func (this *NoteImageService) GetNoteIds(imageId string) ([]bson.ObjectId) {
|
|||||||
// 解析内容中的图片, 建立图片与note的关系
|
// 解析内容中的图片, 建立图片与note的关系
|
||||||
// <img src="/file/outputImage?fileId=12323232" />
|
// <img src="/file/outputImage?fileId=12323232" />
|
||||||
// 图片必须是我的, 不然不添加
|
// 图片必须是我的, 不然不添加
|
||||||
func (this *NoteImageService) UpdateNoteImages(userId, noteId, content string) bool {
|
// imgSrc 防止博客修改了, 但内容删除了
|
||||||
|
func (this *NoteImageService) UpdateNoteImages(userId, noteId, imgSrc, content string) bool {
|
||||||
|
// 让主图成为内容的一员
|
||||||
|
if imgSrc != "" {
|
||||||
|
content = "<img src=\"" + imgSrc + "\" >" + content
|
||||||
|
}
|
||||||
reg, _ := regexp.Compile("outputImage\\?fileId=([a-z0-9A-Z]{24})")
|
reg, _ := regexp.Compile("outputImage\\?fileId=([a-z0-9A-Z]{24})")
|
||||||
find := reg.FindAllStringSubmatch(content, -1) // 查找所有的
|
find := reg.FindAllStringSubmatch(content, -1) // 查找所有的
|
||||||
|
|
||||||
|
|||||||
+81
-14
@@ -111,10 +111,16 @@ func (this *NoteService) ListNoteAbstractsByNoteIds(noteIds []bson.ObjectId) (no
|
|||||||
db.ListByQWithFields(db.NoteContents, bson.M{"_id": bson.M{"$in": noteIds}}, []string{"_id", "Abstract"}, ¬es)
|
db.ListByQWithFields(db.NoteContents, bson.M{"_id": bson.M{"$in": noteIds}}, []string{"_id", "Abstract"}, ¬es)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
func (this *NoteService) ListNoteContentByNoteIds(noteIds []bson.ObjectId) (notes []info.NoteContent) {
|
||||||
|
notes = []info.NoteContent{}
|
||||||
|
db.ListByQWithFields(db.NoteContents, bson.M{"_id": bson.M{"$in": noteIds}}, []string{"_id", "Abstract", "Content"}, ¬es)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 添加笔记
|
// 添加笔记
|
||||||
// 首先要判断Notebook是否是Blog, 是的话设为blog
|
// 首先要判断Notebook是否是Blog, 是的话设为blog
|
||||||
// [ok]
|
// [ok]
|
||||||
|
|
||||||
func (this *NoteService) AddNote(note info.Note) info.Note {
|
func (this *NoteService) AddNote(note info.Note) info.Note {
|
||||||
if(note.NoteId.Hex() == "") {
|
if(note.NoteId.Hex() == "") {
|
||||||
noteId := bson.NewObjectId();
|
noteId := bson.NewObjectId();
|
||||||
@@ -124,6 +130,7 @@ func (this *NoteService) AddNote(note info.Note) info.Note {
|
|||||||
note.UpdatedTime = note.CreatedTime
|
note.UpdatedTime = note.CreatedTime
|
||||||
note.IsTrash = false
|
note.IsTrash = false
|
||||||
note.UpdatedUserId = note.UserId
|
note.UpdatedUserId = note.UserId
|
||||||
|
note.UrlTitle = GetUrTitle(note.UserId.Hex(), note.Title, "note")
|
||||||
|
|
||||||
// 设为blog
|
// 设为blog
|
||||||
notebookId := note.NotebookId.Hex()
|
notebookId := note.NotebookId.Hex()
|
||||||
@@ -164,13 +171,24 @@ func (this *NoteService) AddNoteContent(noteContent info.NoteContent) info.NoteC
|
|||||||
db.Insert(db.NoteContents, noteContent)
|
db.Insert(db.NoteContents, noteContent)
|
||||||
|
|
||||||
// 更新笔记图片
|
// 更新笔记图片
|
||||||
noteImageService.UpdateNoteImages(noteContent.UserId.Hex(), noteContent.NoteId.Hex(), noteContent.Content)
|
noteImageService.UpdateNoteImages(noteContent.UserId.Hex(), noteContent.NoteId.Hex(), "", noteContent.Content)
|
||||||
|
|
||||||
return noteContent;
|
return noteContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加笔记和内容
|
// 添加笔记和内容
|
||||||
// 这里使用 info.NoteAndContent 接收?
|
// 这里使用 info.NoteAndContent 接收?
|
||||||
|
func (this *NoteService) AddNoteAndContentForController(note info.Note, noteContent info.NoteContent, updatedUserId string) info.Note {
|
||||||
|
if note.UserId.Hex() != updatedUserId {
|
||||||
|
if !shareService.HasUpdateNotebookPerm(note.UserId.Hex(), updatedUserId, note.NotebookId.Hex()) {
|
||||||
|
Log("NO AUTH11")
|
||||||
|
return info.Note{}
|
||||||
|
} else {
|
||||||
|
Log("HAS AUTH -----------")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.AddNoteAndContent(note, noteContent, bson.ObjectIdHex(updatedUserId));
|
||||||
|
}
|
||||||
func (this *NoteService) AddNoteAndContent(note info.Note, noteContent info.NoteContent, myUserId bson.ObjectId) info.Note {
|
func (this *NoteService) AddNoteAndContent(note info.Note, noteContent info.NoteContent, myUserId bson.ObjectId) info.Note {
|
||||||
if(note.NoteId.Hex() == "") {
|
if(note.NoteId.Hex() == "") {
|
||||||
noteId := bson.NewObjectId()
|
noteId := bson.NewObjectId()
|
||||||
@@ -189,18 +207,24 @@ func (this *NoteService) AddNoteAndContent(note info.Note, noteContent info.Note
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 修改笔记
|
// 修改笔记
|
||||||
// [ok] TODO perm还没测
|
|
||||||
func (this *NoteService) UpdateNote(userId, updatedUserId, noteId string, needUpdate bson.M) bool {
|
func (this *NoteService) UpdateNote(userId, updatedUserId, noteId string, needUpdate bson.M) bool {
|
||||||
// updatedUserId 要修改userId的note, 此时需要判断是否有修改权限
|
// updatedUserId 要修改userId的note, 此时需要判断是否有修改权限
|
||||||
if userId != updatedUserId {
|
if userId != updatedUserId {
|
||||||
if !shareService.HasUpdatePerm(userId, updatedUserId, noteId) {
|
if !shareService.HasUpdatePerm(userId, updatedUserId, noteId) {
|
||||||
Log("NO AUTH")
|
Log("NO AUTH2")
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
Log("HAS AUTH -----------")
|
Log("HAS AUTH -----------")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 是否已自定义
|
||||||
|
note := this.GetNoteById(noteId)
|
||||||
|
if note.IsBlog && note.HasSelfDefined {
|
||||||
|
delete(needUpdate, "ImgSrc")
|
||||||
|
delete(needUpdate, "Desc")
|
||||||
|
}
|
||||||
|
|
||||||
needUpdate["UpdatedUserId"] = bson.ObjectIdHex(updatedUserId);
|
needUpdate["UpdatedUserId"] = bson.ObjectIdHex(updatedUserId);
|
||||||
needUpdate["UpdatedTime"] = time.Now();
|
needUpdate["UpdatedTime"] = time.Now();
|
||||||
|
|
||||||
@@ -244,12 +268,18 @@ func (this *NoteService) UpdateNoteContent(userId, updatedUserId, noteId, conten
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if db.UpdateByIdAndUserIdMap(db.NoteContents, noteId, userId,
|
data := bson.M{"UpdatedUserId": bson.ObjectIdHex(updatedUserId),
|
||||||
bson.M{"UpdatedUserId": bson.ObjectIdHex(updatedUserId),
|
|
||||||
"Content": content,
|
"Content": content,
|
||||||
"Abstract": abstract,
|
"Abstract": abstract,
|
||||||
"UpdatedTime": time.Now()}) {
|
"UpdatedTime": time.Now()}
|
||||||
|
|
||||||
|
// 是否已自定义
|
||||||
|
note := this.GetNoteById(noteId)
|
||||||
|
if note.IsBlog && note.HasSelfDefined {
|
||||||
|
delete(data, "Abstract")
|
||||||
|
}
|
||||||
|
|
||||||
|
if db.UpdateByIdAndUserIdMap(db.NoteContents, noteId, userId, data) {
|
||||||
// 这里, 添加历史记录
|
// 这里, 添加历史记录
|
||||||
noteContentHistoryService.AddHistory(noteId, userId, info.EachHistory{UpdatedUserId: bson.ObjectIdHex(updatedUserId),
|
noteContentHistoryService.AddHistory(noteId, userId, info.EachHistory{UpdatedUserId: bson.ObjectIdHex(updatedUserId),
|
||||||
Content: content,
|
Content: content,
|
||||||
@@ -257,7 +287,7 @@ func (this *NoteService) UpdateNoteContent(userId, updatedUserId, noteId, conten
|
|||||||
})
|
})
|
||||||
|
|
||||||
// 更新笔记图片
|
// 更新笔记图片
|
||||||
noteImageService.UpdateNoteImages(userId, noteId, content)
|
noteImageService.UpdateNoteImages(userId, noteId, note.ImgSrc, content)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -278,6 +308,29 @@ func (this *NoteService) UpdateTags(noteId string, userId string, tags []string)
|
|||||||
return db.UpdateByIdAndUserIdField(db.Notes, noteId, userId, "Tags", tags)
|
return db.UpdateByIdAndUserIdField(db.Notes, noteId, userId, "Tags", tags)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (this *NoteService) ToBlog(userId, noteId string, isBlog, isTop bool) bool {
|
||||||
|
noteUpdate := bson.M{}
|
||||||
|
if isTop {
|
||||||
|
isBlog = true
|
||||||
|
}
|
||||||
|
if !isBlog {
|
||||||
|
isTop = false
|
||||||
|
}
|
||||||
|
noteUpdate["IsBlog"] = isBlog
|
||||||
|
noteUpdate["IsTop"] = isTop
|
||||||
|
if isBlog {
|
||||||
|
noteUpdate["PublicTime"] = time.Now()
|
||||||
|
} else {
|
||||||
|
noteUpdate["HasSelfDefined"] = false
|
||||||
|
}
|
||||||
|
ok := db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, noteUpdate)
|
||||||
|
// 重新计算tags
|
||||||
|
go (func() {
|
||||||
|
blogService.ReCountBlogTags(userId)
|
||||||
|
})()
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
// 移动note
|
// 移动note
|
||||||
// trash, 正常的都可以用
|
// trash, 正常的都可以用
|
||||||
// 1. 要检查下notebookId是否是自己的
|
// 1. 要检查下notebookId是否是自己的
|
||||||
@@ -419,15 +472,20 @@ func (this *NoteService) GetNotebookId(noteId string) bson.ObjectId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------
|
//------------------
|
||||||
// 搜索Note
|
// 搜索Note, 博客使用了
|
||||||
func (this *NoteService) SearchNote(key, userId string, pageNumber, pageSize int, sortField string, isAsc, isBlog bool) (count int, notes []info.Note) {
|
func (this *NoteService) SearchNote(key, userId string, pageNumber, pageSize int, sortField string, isAsc, isBlog bool) (count int, notes []info.Note) {
|
||||||
notes = []info.Note{}
|
notes = []info.Note{}
|
||||||
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
||||||
|
|
||||||
|
// 利用标题和desc, 不用content
|
||||||
|
orQ := []bson.M{
|
||||||
|
bson.M{"Title": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}}},
|
||||||
|
bson.M{"Desc": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}}},
|
||||||
|
}
|
||||||
// 不是trash的
|
// 不是trash的
|
||||||
query := bson.M{"UserId": bson.ObjectIdHex(userId),
|
query := bson.M{"UserId": bson.ObjectIdHex(userId),
|
||||||
"IsTrash": false,
|
"IsTrash": false,
|
||||||
"Title": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}},
|
"$or": orQ,
|
||||||
}
|
}
|
||||||
if isBlog {
|
if isBlog {
|
||||||
query["IsBlog"] = true
|
query["IsBlog"] = true
|
||||||
@@ -509,11 +567,20 @@ func (this *NoteService) SearchNoteByTags(tags []string, userId string, pageNumb
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//------------
|
//------------
|
||||||
// 统计
|
// 统计
|
||||||
func (this *NoteService) CountNote() int {
|
func (this *NoteService) CountNote(userId string) int {
|
||||||
return db.Count(db.Notes, bson.M{"IsTrash": false})
|
q := bson.M{"IsTrash": false}
|
||||||
|
if userId != "" {
|
||||||
|
q["UserId"] = bson.ObjectIdHex(userId)
|
||||||
|
}
|
||||||
|
return db.Count(db.Notes, q)
|
||||||
}
|
}
|
||||||
func (this *NoteService) CountBlog() int {
|
func (this *NoteService) CountBlog(userId string) int {
|
||||||
return db.Count(db.Notes, bson.M{"IsBlog": true, "IsTrash": false})
|
q := bson.M{"IsBlog": true, "IsTrash": false}
|
||||||
|
if userId != "" {
|
||||||
|
q["UserId"] = bson.ObjectIdHex(userId)
|
||||||
|
}
|
||||||
|
return db.Count(db.Notes, q)
|
||||||
}
|
}
|
||||||
@@ -101,6 +101,15 @@ func (this *NotebookService) GetNotebookById(notebookId string) info.Notebook {
|
|||||||
db.Get(db.Notebooks, notebookId, ¬ebook)
|
db.Get(db.Notebooks, notebookId, ¬ebook)
|
||||||
return notebook
|
return notebook
|
||||||
}
|
}
|
||||||
|
func (this *NotebookService) GetNotebookByUserIdAndUrlTitle(userId, notebookIdOrUrlTitle string) info.Notebook {
|
||||||
|
notebook := info.Notebook{}
|
||||||
|
if IsObjectId(notebookIdOrUrlTitle) {
|
||||||
|
db.Get(db.Notebooks, notebookIdOrUrlTitle, ¬ebook)
|
||||||
|
} else {
|
||||||
|
db.GetByQ(db.Notebooks, bson.M{"UserId": bson.ObjectIdHex(userId), "UrlTitle": encodeValue(notebookIdOrUrlTitle)}, ¬ebook)
|
||||||
|
}
|
||||||
|
return notebook
|
||||||
|
}
|
||||||
|
|
||||||
// 得到用户下所有的notebook
|
// 得到用户下所有的notebook
|
||||||
// 排序好之后返回
|
// 排序好之后返回
|
||||||
@@ -133,6 +142,7 @@ func (this *NotebookService) GetNotebooksByNotebookIds(notebookIds []bson.Object
|
|||||||
// 添加
|
// 添加
|
||||||
// [ok]
|
// [ok]
|
||||||
func (this *NotebookService) AddNotebook(notebook info.Notebook) bool {
|
func (this *NotebookService) AddNotebook(notebook info.Notebook) bool {
|
||||||
|
notebook.UrlTitle = GetUrTitle(notebook.UserId.Hex(), notebook.Title, "notebook")
|
||||||
err := db.Notebooks.Insert(notebook)
|
err := db.Notebooks.Insert(notebook)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -170,34 +180,39 @@ func (this *NotebookService) UpdateNotebookTitle(notebookId, userId, title strin
|
|||||||
// 更新notebook
|
// 更新notebook
|
||||||
func (this *NotebookService) UpdateNotebook(userId, notebookId string, needUpdate bson.M) bool {
|
func (this *NotebookService) UpdateNotebook(userId, notebookId string, needUpdate bson.M) bool {
|
||||||
needUpdate["UpdatedTime"] = time.Now();
|
needUpdate["UpdatedTime"] = time.Now();
|
||||||
|
return db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, needUpdate)
|
||||||
// 如果有IsBlog之类的, 需要特殊处理
|
}
|
||||||
if isBlog, ok := needUpdate["IsBlog"]; ok {
|
|
||||||
// 设为blog/取消, 把它下面所有的note都设为isBlog
|
// ToBlog or Not
|
||||||
if is, ok2 := isBlog.(bool); ok2 {
|
func (this *NotebookService) ToBlog(userId, notebookId string, isBlog bool) (bool) {
|
||||||
q := bson.M{"UserId": bson.ObjectIdHex(userId),
|
q := bson.M{"UserId": bson.ObjectIdHex(userId),
|
||||||
"NotebookId": bson.ObjectIdHex(notebookId)}
|
"NotebookId": bson.ObjectIdHex(notebookId)}
|
||||||
data := bson.M{"IsBlog": is}
|
data := bson.M{"IsBlog": isBlog}
|
||||||
if is {
|
if isBlog {
|
||||||
data["PublicTime"] = time.Now()
|
data["PublicTime"] = time.Now()
|
||||||
}
|
} else {
|
||||||
db.UpdateByQMap(db.Notes, q, data)
|
data["HasSelfDefined"] = false
|
||||||
|
}
|
||||||
// noteContents也更新, 这个就麻烦了, noteContents表没有NotebookId
|
db.UpdateByQMap(db.Notes, q, data)
|
||||||
// 先查该notebook下所有notes, 得到id
|
|
||||||
notes := []info.Note{}
|
// noteContents也更新, 这个就麻烦了, noteContents表没有NotebookId
|
||||||
db.ListByQWithFields(db.Notes, q, []string{"_id"}, ¬es)
|
// 先查该notebook下所有notes, 得到id
|
||||||
if len(notes) > 0 {
|
notes := []info.Note{}
|
||||||
noteIds := make([]bson.ObjectId, len(notes))
|
db.ListByQWithFields(db.Notes, q, []string{"_id"}, ¬es)
|
||||||
for i, each := range notes {
|
if len(notes) > 0 {
|
||||||
noteIds[i] = each.NoteId
|
noteIds := make([]bson.ObjectId, len(notes))
|
||||||
}
|
for i, each := range notes {
|
||||||
db.UpdateByQMap(db.NoteContents, bson.M{"_id": bson.M{"$in": noteIds}}, bson.M{"IsBlog": isBlog})
|
noteIds[i] = each.NoteId
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
db.UpdateByQMap(db.NoteContents, bson.M{"_id": bson.M{"$in": noteIds}}, bson.M{"IsBlog": isBlog})
|
||||||
}
|
}
|
||||||
|
|
||||||
return db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, needUpdate)
|
// 重新计算tags
|
||||||
|
go (func() {
|
||||||
|
blogService.ReCountBlogTags(userId)
|
||||||
|
})()
|
||||||
|
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查看是否有子notebook
|
// 查看是否有子notebook
|
||||||
|
|||||||
+277
-78
@@ -13,7 +13,10 @@ import (
|
|||||||
type ShareService struct {
|
type ShareService struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------
|
//-----------------------------------
|
||||||
|
// 返回shareNotebooks, sharedUserInfos
|
||||||
|
// info.ShareNotebooksByUser, []info.User
|
||||||
|
|
||||||
// 总体来说, 这个方法比较麻烦, 速度未知. 以后按以下方案来缓存用户基础数据
|
// 总体来说, 这个方法比较麻烦, 速度未知. 以后按以下方案来缓存用户基础数据
|
||||||
|
|
||||||
// 以后建个用户的基本数据表, 放所有notebook, sharedNotebook的缓存!!
|
// 以后建个用户的基本数据表, 放所有notebook, sharedNotebook的缓存!!
|
||||||
@@ -27,23 +30,48 @@ type ShareService struct {
|
|||||||
// 3 每个层按seq进行排序
|
// 3 每个层按seq进行排序
|
||||||
// 4 按用户分组
|
// 4 按用户分组
|
||||||
// [ok]
|
// [ok]
|
||||||
func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksByUser, []info.User) {
|
|
||||||
//-------------
|
// 谁共享给了我的Query
|
||||||
// 查询HasShareNote表得到所有其它用户信息
|
func (this *ShareService) getOrQ(userId string) bson.M {
|
||||||
hasShareNotes := []info.HasShareNote{}
|
// 得到我参与的组织
|
||||||
db.ListByQ(db.HasShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(userId)}, &hasShareNotes);
|
groupIds := groupService.GetBelongToGroupIds(userId)
|
||||||
|
q := bson.M{}
|
||||||
userIds := make([]bson.ObjectId, len(hasShareNotes))
|
if len(groupIds) > 0 {
|
||||||
for i, each := range hasShareNotes {
|
orQ := []bson.M{
|
||||||
userIds[i] = each.UserId
|
bson.M{"ToUserId": bson.ObjectIdHex(userId)},
|
||||||
|
bson.M{"ToGroupId": bson.M{"$in": groupIds}},
|
||||||
|
}
|
||||||
|
// 不是trash的
|
||||||
|
q["$or"] = orQ
|
||||||
|
} else {
|
||||||
|
q["ToUserId"] = bson.ObjectIdHex(userId);
|
||||||
}
|
}
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksByUser, []info.User) {
|
||||||
|
// 得到共享给我的用户s信息
|
||||||
|
// 得到我参与的组织
|
||||||
|
q := this.getOrQ(userId)
|
||||||
|
|
||||||
|
// 不查hasShareNotes
|
||||||
|
// 直接查shareNotes, shareNotebooks表得到userId
|
||||||
|
userIds1 := []bson.ObjectId{}
|
||||||
|
db.Distinct(db.ShareNotes, q, "UserId", &userIds1)
|
||||||
|
|
||||||
|
userIds2 := []bson.ObjectId{}
|
||||||
|
db.Distinct(db.ShareNotebooks, q, "UserId", &userIds1)
|
||||||
|
|
||||||
|
userIds := append(userIds1, userIds2...)
|
||||||
userInfos := userService.GetUserInfosOrderBySeq(userIds);
|
userInfos := userService.GetUserInfosOrderBySeq(userIds);
|
||||||
|
|
||||||
//--------------------
|
//--------------------
|
||||||
// 得到他们共享给我的notebooks
|
// 得到他们共享给我的notebooks
|
||||||
|
|
||||||
|
// 这里可能会得到重复的记录
|
||||||
|
// 权限: 笔记本分享给个人 > 笔记本分享给组织
|
||||||
shareNotebooks := []info.ShareNotebook{}
|
shareNotebooks := []info.ShareNotebook{}
|
||||||
db.ShareNotebooks.Find(bson.M{"ToUserId": bson.ObjectIdHex(userId)}).All(&shareNotebooks)
|
db.ShareNotebooks.Find(q).Sort("-ToUserId").All(&shareNotebooks) // 按ToUserId降序排序, 那么有ToUserId的在前面
|
||||||
|
|
||||||
if len(shareNotebooks) == 0 {
|
if len(shareNotebooks) == 0 {
|
||||||
return nil, userInfos
|
return nil, userInfos
|
||||||
@@ -52,12 +80,15 @@ func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksB
|
|||||||
shareNotebooksLen := len(shareNotebooks)
|
shareNotebooksLen := len(shareNotebooks)
|
||||||
|
|
||||||
// 找到了所有的notbookId, 那么找notebook表得到其详细信息
|
// 找到了所有的notbookId, 那么找notebook表得到其详细信息
|
||||||
notebookIds := make([]bson.ObjectId, shareNotebooksLen)
|
notebookIds := []bson.ObjectId{}
|
||||||
shareNotebooksMap := make(map[bson.ObjectId]info.ShareNotebook, shareNotebooksLen)
|
shareNotebooksMap := make(map[bson.ObjectId]info.ShareNotebook, shareNotebooksLen)
|
||||||
for i, each := range shareNotebooks {
|
for _, each := range shareNotebooks {
|
||||||
// 默认的是没有notebookId的
|
// 之后的就不要了, 只留权限高的
|
||||||
notebookIds[i] = each.NotebookId
|
if _, ok := shareNotebooksMap[each.NotebookId]; !ok {
|
||||||
shareNotebooksMap[each.NotebookId] = each
|
// 默认的是没有notebookId的
|
||||||
|
notebookIds = append(notebookIds, each.NotebookId)
|
||||||
|
shareNotebooksMap[each.NotebookId] = each
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1, 2
|
// 1, 2
|
||||||
@@ -127,9 +158,13 @@ func (this *ShareService) parseToSubShareNotebooks(subNotebooks *info.SubNoteboo
|
|||||||
func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, sharedUserId string,
|
func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, sharedUserId string,
|
||||||
page, pageSize int, sortField string, isAsc bool) ([]info.ShareNoteWithPerm) {
|
page, pageSize int, sortField string, isAsc bool) ([]info.ShareNoteWithPerm) {
|
||||||
// 1 首先判断是否真的sharedUserId 共享了 notebookId 给 myUserId
|
// 1 首先判断是否真的sharedUserId 共享了 notebookId 给 myUserId
|
||||||
|
q := this.getOrQ(myUserId)
|
||||||
|
q["NotebookId"] = bson.ObjectIdHex(notebookId);
|
||||||
|
q["UserId"] = bson.ObjectIdHex(sharedUserId);
|
||||||
shareNotebook := info.ShareNotebook{}
|
shareNotebook := info.ShareNotebook{}
|
||||||
db.GetByQ(db.ShareNotebooks, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
|
db.GetByQ(db.ShareNotebooks,
|
||||||
"UserId": bson.ObjectIdHex(sharedUserId), "ToUserId": bson.ObjectIdHex(myUserId)}, &shareNotebook)
|
q,
|
||||||
|
&shareNotebook)
|
||||||
|
|
||||||
if shareNotebook.NotebookId == "" {
|
if shareNotebook.NotebookId == "" {
|
||||||
return nil
|
return nil
|
||||||
@@ -146,7 +181,19 @@ func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, share
|
|||||||
for i, note := range notes {
|
for i, note := range notes {
|
||||||
noteIds[i] = note.NoteId
|
noteIds[i] = note.NoteId
|
||||||
}
|
}
|
||||||
notePerms := this.getNotesPerm(noteIds, myUserId, sharedUserId);
|
// 笔记的权限
|
||||||
|
shareNotes := []info.ShareNote{}
|
||||||
|
delete(q, "NotebookId")
|
||||||
|
q["NoteId"] = bson.M{"$in": noteIds}
|
||||||
|
db.ShareNotes.Find(q).Sort("-ToUserId").All(&shareNotes) // 给个的权限>给组织的权限
|
||||||
|
notePerms := map[bson.ObjectId]int{}
|
||||||
|
for _, each := range shareNotes {
|
||||||
|
if _, ok := notePerms[each.NoteId]; !ok {
|
||||||
|
notePerms[each.NoteId] = each.Perm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log("笔记权限")
|
||||||
|
LogJ(notePerms);
|
||||||
|
|
||||||
// 3.2 组合
|
// 3.2 组合
|
||||||
notesWithPerm := make([]info.ShareNoteWithPerm, len(notes))
|
notesWithPerm := make([]info.ShareNoteWithPerm, len(notes))
|
||||||
@@ -162,17 +209,21 @@ func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, share
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 得到note的perm信息
|
// 得到note的perm信息
|
||||||
func (this *ShareService) getNotesPerm(noteIds []bson.ObjectId, myUserId, sharedUserId string) map[bson.ObjectId]int {
|
//func (this *ShareService) getNotesPerm(noteIds []bson.ObjectId, myUserId, sharedUserId string) map[bson.ObjectId]int {
|
||||||
shareNotes := []info.ShareNote{}
|
// shareNotes := []info.ShareNote{}
|
||||||
db.ListByQ(db.ShareNotes, bson.M{"NoteId": bson.M{"$in": noteIds}, "UserId": bson.ObjectIdHex(sharedUserId), "ToUserId": bson.ObjectIdHex(myUserId)}, &shareNotes)
|
// db.ListByQ(db.ShareNotes,
|
||||||
|
// bson.M{
|
||||||
notesPerm := make(map[bson.ObjectId]int, len(shareNotes))
|
// "NoteId": bson.M{"$in": noteIds},
|
||||||
for _, each := range shareNotes {
|
// "UserId": bson.ObjectIdHex(sharedUserId),
|
||||||
notesPerm[each.NoteId] = each.Perm
|
// "ToUserId": bson.ObjectIdHex(myUserId)}, &shareNotes)
|
||||||
}
|
//
|
||||||
|
// notesPerm := make(map[bson.ObjectId]int, len(shareNotes))
|
||||||
return notesPerm
|
// for _, each := range shareNotes {
|
||||||
}
|
// notesPerm[each.NoteId] = each.Perm
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return notesPerm
|
||||||
|
//}
|
||||||
|
|
||||||
// 得到默认的单个的notes 共享集
|
// 得到默认的单个的notes 共享集
|
||||||
// 如果真要支持排序, 这里得到所有共享的notes, 到noteService方再sort和limit
|
// 如果真要支持排序, 这里得到所有共享的notes, 到noteService方再sort和limit
|
||||||
@@ -184,9 +235,12 @@ func (this *ShareService) ListShareNotes(myUserId, sharedUserId string,
|
|||||||
skipNum, _ := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
skipNum, _ := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
||||||
shareNotes := []info.ShareNote{}
|
shareNotes := []info.ShareNote{}
|
||||||
|
|
||||||
|
q := this.getOrQ(myUserId)
|
||||||
|
q["UserId"] = bson.ObjectIdHex(sharedUserId);
|
||||||
|
|
||||||
db.ShareNotes.
|
db.ShareNotes.
|
||||||
Find(bson.M{"UserId": bson.ObjectIdHex(sharedUserId), "ToUserId": bson.ObjectIdHex(myUserId)}).
|
Find(q).
|
||||||
// Sort(sortFieldR).
|
Sort("-ToUserId"). // 给个人的权限 > 给组织的权限
|
||||||
Skip(skipNum).
|
Skip(skipNum).
|
||||||
Limit(pageSize).
|
Limit(pageSize).
|
||||||
All(&shareNotes)
|
All(&shareNotes)
|
||||||
@@ -200,15 +254,20 @@ func (this *ShareService) ListShareNotes(myUserId, sharedUserId string,
|
|||||||
noteIds[i] = each.NoteId
|
noteIds[i] = each.NoteId
|
||||||
}
|
}
|
||||||
notes := noteService.ListNotesByNoteIds(noteIds)
|
notes := noteService.ListNotesByNoteIds(noteIds)
|
||||||
notesMap := make(map[bson.ObjectId]info.Note, len(notes))
|
notesMap := map[bson.ObjectId]info.Note{}
|
||||||
for _, each := range notes {
|
for _, each := range notes {
|
||||||
notesMap[each.NoteId] = each
|
notesMap[each.NoteId] = each
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将shareNotes与notes结合起来
|
// 将shareNotes与notes结合起来
|
||||||
notesWithPerm := make([]info.ShareNoteWithPerm, len(shareNotes))
|
notesWithPerm := []info.ShareNoteWithPerm{}
|
||||||
for i, each := range shareNotes {
|
hasAdded := map[bson.ObjectId]bool{} // 防止重复, 只要前面权限高的
|
||||||
notesWithPerm[i] = info.ShareNoteWithPerm{notesMap[each.NoteId], each.Perm}
|
for _, each := range shareNotes {
|
||||||
|
if !hasAdded[each.NoteId] {
|
||||||
|
// 待优化
|
||||||
|
notesWithPerm = append(notesWithPerm, info.ShareNoteWithPerm{notesMap[each.NoteId], each.Perm})
|
||||||
|
hasAdded[each.NoteId] = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return notesWithPerm
|
return notesWithPerm
|
||||||
}
|
}
|
||||||
@@ -286,19 +345,25 @@ func (this *ShareService) AddShareNote(noteId string, perm int, userId, email st
|
|||||||
return db.Insert(db.ShareNotes, shareNote), "", toUserId
|
return db.Insert(db.ShareNotes, shareNote), "", toUserId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// updatedUserId是否有查看userId noteId的权限?
|
// updatedUserId是否有查看userId noteId的权限?
|
||||||
|
// userId是所有者
|
||||||
func (this *ShareService) HasReadPerm(userId, updatedUserId, noteId string) bool {
|
func (this *ShareService) HasReadPerm(userId, updatedUserId, noteId string) bool {
|
||||||
if !db.Has(db.ShareNotes,
|
q := this.getOrQ(updatedUserId) // (toUserId == "xxx" || ToGroupId in (1, 2,3))
|
||||||
bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NoteId": bson.ObjectIdHex(noteId)}) {
|
q["UserId"] = bson.ObjectIdHex(userId)
|
||||||
|
q["NoteId"] = bson.ObjectIdHex(noteId)
|
||||||
|
if !db.Has(db.ShareNotes, q) {
|
||||||
// noteId的notebookId是否被共享了?
|
// noteId的notebookId是否被共享了?
|
||||||
notebookId := noteService.GetNotebookId(noteId)
|
notebookId := noteService.GetNotebookId(noteId)
|
||||||
if notebookId.Hex() == "" {
|
if notebookId.Hex() == "" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete(q, "NoteId")
|
||||||
|
q["NotebookId"] = notebookId
|
||||||
|
|
||||||
// 判断notebook是否被共享
|
// 判断notebook是否被共享
|
||||||
if !db.Has(db.ShareNotebooks,
|
if !db.Has(db.ShareNotebooks, q) {
|
||||||
bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NotebookId": notebookId}) {
|
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
return true
|
return true
|
||||||
@@ -310,43 +375,44 @@ func (this *ShareService) HasReadPerm(userId, updatedUserId, noteId string) bool
|
|||||||
|
|
||||||
// updatedUserId是否有修改userId noteId的权限?
|
// updatedUserId是否有修改userId noteId的权限?
|
||||||
func (this *ShareService) HasUpdatePerm(userId, updatedUserId, noteId string) bool {
|
func (this *ShareService) HasUpdatePerm(userId, updatedUserId, noteId string) bool {
|
||||||
// 1. noteId是否被共享了?
|
q := this.getOrQ(updatedUserId) // (toUserId == "xxx" || ToGroupId in (1, 2,3))
|
||||||
// 得到该note share的信息
|
q["UserId"] = bson.ObjectIdHex(userId)
|
||||||
/*
|
q["NoteId"] = bson.ObjectIdHex(noteId)
|
||||||
UserId bson.ObjectId `bson:"UserId"`
|
|
||||||
ToUserId bson.ObjectId `bson:"ToUserId"`
|
// note的权限
|
||||||
NoteId bson.ObjectId `bson:"NoteId"`
|
shares := []info.ShareNote{}
|
||||||
Perm int `bson:"Perm"` // 权限, 0只读, 1可修改
|
db.ShareNotes.Find(q).Sort("-ToUserId").All(&shares) // 个人 > 组织
|
||||||
*/
|
for _, share := range shares {
|
||||||
if !db.Has(db.ShareNotes,
|
return share.Perm == 1 // 第1个权限最大
|
||||||
bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NoteId": bson.ObjectIdHex(noteId), "Perm": 1}) {
|
|
||||||
// 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, "Perm": 1}) {
|
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// notebook的权限
|
||||||
|
notebookId := noteService.GetNotebookId(noteId)
|
||||||
|
if notebookId.Hex() == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(q, "NoteId")
|
||||||
|
q["NotebookId"] = notebookId
|
||||||
|
shares2 := []info.ShareNotebook{}
|
||||||
|
db.ShareNotebooks.Find(q).Sort("-ToUserId").All(&shares2) // 个人 > 组织
|
||||||
|
for _, share := range shares2 {
|
||||||
|
return share.Perm == 1 // 第1个权限最大
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// updatedUserId是否有修改userId notebookId的权限?
|
// updatedUserId是否有修改userId notebookId的权限?
|
||||||
func (this *ShareService) HasUpdateNotebookPerm(userId, updatedUserId, notebookId string) bool {
|
func (this *ShareService) HasUpdateNotebookPerm(userId, updatedUserId, notebookId string) bool {
|
||||||
// 判断notebook是否被共享
|
q := this.getOrQ(updatedUserId) // (toUserId == "xxx" || ToGroupId in (1, 2,3))
|
||||||
if !db.Has(db.ShareNotebooks,
|
q["UserId"] = bson.ObjectIdHex(userId)
|
||||||
bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NotebookId": bson.ObjectIdHex(notebookId), "Perm": 1}) {
|
q["NotebookId"] = bson.ObjectIdHex(notebookId)
|
||||||
return false
|
shares2 := []info.ShareNotebook{}
|
||||||
} else {
|
db.ShareNotebooks.Find(q).Sort("-ToUserId").All(&shares2) // 个人 > 组织
|
||||||
return true
|
for _, share := range shares2 {
|
||||||
}
|
return share.Perm == 1 // 第1个权限最大
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 共享note, notebook时使用
|
// 共享note, notebook时使用
|
||||||
@@ -372,12 +438,16 @@ func (this *ShareService) HasSharedNotebook(noteId, myUserId, sharedUserId strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 得到共享的笔记内容
|
// 得到共享的笔记内容
|
||||||
// 首先要判断这个note是否我被共享了
|
// 并返回笔记的权限!!!
|
||||||
func (this *ShareService) GetShareNoteContent(noteId, myUserId, sharedUserId string) (noteContent info.NoteContent) {
|
func (this *ShareService) GetShareNoteContent(noteId, myUserId, sharedUserId string) (noteContent info.NoteContent) {
|
||||||
noteContent = info.NoteContent{}
|
noteContent = info.NoteContent{}
|
||||||
// 是否单独共享了该notebook
|
// 是否单独共享了该notebook
|
||||||
// 或者, 其notebook共享了我
|
// 或者, 其notebook共享了我
|
||||||
if this.HasSharedNote(noteId, myUserId) || this.HasSharedNotebook(noteId, myUserId, sharedUserId) {
|
// Log(this.HasSharedNote(noteId, myUserId))
|
||||||
|
// Log(this.HasSharedNotebook(noteId, myUserId, sharedUserId))
|
||||||
|
Log(this.HasReadPerm(sharedUserId, myUserId, noteId))
|
||||||
|
if this.HasReadPerm(sharedUserId, myUserId, noteId) {
|
||||||
|
// if this.HasSharedNote(noteId, myUserId) || this.HasSharedNotebook(noteId, myUserId, sharedUserId) {
|
||||||
db.Get(db.NoteContents, noteId, ¬eContent)
|
db.Get(db.NoteContents, noteId, ¬eContent)
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
@@ -391,7 +461,15 @@ func (this *ShareService) GetShareNoteContent(noteId, myUserId, sharedUserId str
|
|||||||
func (this *ShareService) ListNoteShareUserInfo(noteId, userId string) []info.ShareUserInfo {
|
func (this *ShareService) ListNoteShareUserInfo(noteId, userId string) []info.ShareUserInfo {
|
||||||
// 得到shareNote信息, 得到所有的ToUserId
|
// 得到shareNote信息, 得到所有的ToUserId
|
||||||
shareNotes := []info.ShareNote{}
|
shareNotes := []info.ShareNote{}
|
||||||
db.ListByQLimit(db.ShareNotes, bson.M{"NoteId": bson.ObjectIdHex(noteId), "UserId": bson.ObjectIdHex(userId)}, &shareNotes, 100)
|
db.ListByQLimit(db.ShareNotes,
|
||||||
|
bson.M{
|
||||||
|
"NoteId": bson.ObjectIdHex(noteId),
|
||||||
|
"UserId": bson.ObjectIdHex(userId),
|
||||||
|
"ToGroupId": bson.M{"$exists": false},
|
||||||
|
}, &shareNotes, 100)
|
||||||
|
|
||||||
|
// Log("<<>>>>")
|
||||||
|
// Log(len(shareNotes))
|
||||||
|
|
||||||
if len(shareNotes) == 0 {
|
if len(shareNotes) == 0 {
|
||||||
return nil
|
return nil
|
||||||
@@ -450,7 +528,11 @@ func (this *ShareService) ListNotebookShareUserInfo(notebookId, userId string) [
|
|||||||
shareNotebooks := []info.ShareNotebook{}
|
shareNotebooks := []info.ShareNotebook{}
|
||||||
|
|
||||||
db.ListByQLimit(db.ShareNotebooks,
|
db.ListByQLimit(db.ShareNotebooks,
|
||||||
bson.M{"NotebookId": bson.ObjectIdHex(notebookId), "UserId": bson.ObjectIdHex(userId)},
|
bson.M{
|
||||||
|
"NotebookId": bson.ObjectIdHex(notebookId),
|
||||||
|
"UserId": bson.ObjectIdHex(userId),
|
||||||
|
"ToGroupId": bson.M{"$exists": false},
|
||||||
|
},
|
||||||
&shareNotebooks, 100)
|
&shareNotebooks, 100)
|
||||||
|
|
||||||
if len(shareNotebooks) == 0 {
|
if len(shareNotebooks) == 0 {
|
||||||
@@ -555,7 +637,7 @@ func (this *ShareService) HasUpdateNotePerm(noteId, userId string) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 用户userId是否有修改noteId的权限
|
// 用户userId是否有查看noteId的权限
|
||||||
func (this *ShareService) HasReadNotePerm(noteId, userId string) bool {
|
func (this *ShareService) HasReadNotePerm(noteId, userId string) bool {
|
||||||
if noteId == "" || userId == "" {
|
if noteId == "" || userId == "" {
|
||||||
return false;
|
return false;
|
||||||
@@ -576,4 +658,121 @@ func (this *ShareService) HasReadNotePerm(noteId, userId string) bool {
|
|||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
// 用户分组
|
||||||
|
|
||||||
|
// 得到笔记分享给的groups
|
||||||
|
func (this *ShareService) GetNoteShareGroups(noteId, userId string) []info.ShareNote {
|
||||||
|
// 得到分组s
|
||||||
|
groups := groupService.GetGroups(userId)
|
||||||
|
|
||||||
|
// 得到有分享的分组
|
||||||
|
shares := []info.ShareNote{}
|
||||||
|
db.ListByQ(db.ShareNotes,
|
||||||
|
bson.M{"NoteId": bson.ObjectIdHex(noteId), "UserId": bson.ObjectIdHex(userId), "ToGroupId": bson.M{"$exists":true}}, &shares)
|
||||||
|
mapShares := map[bson.ObjectId]info.ShareNote{}
|
||||||
|
for _, share := range shares {
|
||||||
|
mapShares[share.ToGroupId] = share
|
||||||
|
}
|
||||||
|
|
||||||
|
// 所有的groups都有share, 但没有share的group没有shareId
|
||||||
|
shares2 := make([]info.ShareNote, len(groups))
|
||||||
|
for i, group := range groups {
|
||||||
|
share, ok := mapShares[group.GroupId]
|
||||||
|
if !ok {
|
||||||
|
share = info.ShareNote{}
|
||||||
|
}
|
||||||
|
share.ToGroup = group;
|
||||||
|
shares2[i] = share
|
||||||
|
}
|
||||||
|
|
||||||
|
return shares2
|
||||||
|
}
|
||||||
|
|
||||||
|
// 共享笔记给分组
|
||||||
|
func (this *ShareService) AddShareNoteGroup(userId, noteId, groupId string, perm int) (bool) {
|
||||||
|
// 得到group, 是否是我的group
|
||||||
|
group := groupService.GetGroup(userId, groupId)
|
||||||
|
if group.GroupId == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 先删除之
|
||||||
|
this.DeleteShareNoteGroup(userId, noteId, groupId)
|
||||||
|
|
||||||
|
shareNote := info.ShareNote{NoteId: bson.ObjectIdHex(noteId),
|
||||||
|
UserId: bson.ObjectIdHex(userId), // 冗余字段
|
||||||
|
ToGroupId: bson.ObjectIdHex(groupId),
|
||||||
|
Perm: perm,
|
||||||
|
CreatedTime: time.Now(),
|
||||||
|
}
|
||||||
|
return db.Insert(db.ShareNotes, shareNote)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
func (this *ShareService) DeleteShareNoteGroup(userId, noteId, groupId string) bool {
|
||||||
|
return db.Delete(db.ShareNotes, bson.M{"NoteId": bson.ObjectIdHex(noteId),
|
||||||
|
"UserId": bson.ObjectIdHex(userId),
|
||||||
|
"ToGroupId": bson.ObjectIdHex(groupId),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------
|
||||||
|
|
||||||
|
// 得到笔记本分享给的groups
|
||||||
|
func (this *ShareService) GetNotebookShareGroups(notebookId, userId string) []info.ShareNotebook {
|
||||||
|
// 得到分组s
|
||||||
|
groups := groupService.GetGroups(userId)
|
||||||
|
|
||||||
|
// 得到有分享的分组
|
||||||
|
shares := []info.ShareNotebook{}
|
||||||
|
db.ListByQ(db.ShareNotebooks,
|
||||||
|
bson.M{"NotebookId": bson.ObjectIdHex(notebookId), "UserId": bson.ObjectIdHex(userId), "ToGroupId": bson.M{"$exists":true}}, &shares)
|
||||||
|
mapShares := map[bson.ObjectId]info.ShareNotebook{}
|
||||||
|
for _, share := range shares {
|
||||||
|
mapShares[share.ToGroupId] = share
|
||||||
|
}
|
||||||
|
LogJ(shares)
|
||||||
|
|
||||||
|
// 所有的groups都有share, 但没有share的group没有shareId
|
||||||
|
shares2 := make([]info.ShareNotebook, len(groups))
|
||||||
|
for i, group := range groups {
|
||||||
|
share, ok := mapShares[group.GroupId]
|
||||||
|
if !ok {
|
||||||
|
share = info.ShareNotebook{}
|
||||||
|
}
|
||||||
|
share.ToGroup = group;
|
||||||
|
shares2[i] = share
|
||||||
|
}
|
||||||
|
|
||||||
|
return shares2
|
||||||
|
}
|
||||||
|
// 共享笔记给分组
|
||||||
|
func (this *ShareService) AddShareNotebookGroup(userId, notebookId, groupId string, perm int) (bool) {
|
||||||
|
// 得到group, 是否是我的group
|
||||||
|
group := groupService.GetGroup(userId, groupId)
|
||||||
|
if group.GroupId == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 先删除之
|
||||||
|
this.DeleteShareNotebookGroup(userId, notebookId, groupId)
|
||||||
|
|
||||||
|
shareNotebook := info.ShareNotebook{NotebookId: bson.ObjectIdHex(notebookId),
|
||||||
|
UserId: bson.ObjectIdHex(userId), // 冗余字段
|
||||||
|
ToGroupId: bson.ObjectIdHex(groupId),
|
||||||
|
Perm: perm,
|
||||||
|
CreatedTime: time.Now(),
|
||||||
|
}
|
||||||
|
return db.Insert(db.ShareNotebooks, shareNotebook)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除
|
||||||
|
func (this *ShareService) DeleteShareNotebookGroup(userId, notebookId, groupId string) bool {
|
||||||
|
return db.Delete(db.ShareNotebooks, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
|
||||||
|
"UserId": bson.ObjectIdHex(userId),
|
||||||
|
"ToGroupId": bson.ObjectIdHex(groupId),
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,507 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/revel/revel"
|
||||||
|
"github.com/leanote/leanote/app/info"
|
||||||
|
"github.com/leanote/leanote/app/db"
|
||||||
|
. "github.com/leanote/leanote/app/lea"
|
||||||
|
"github.com/leanote/leanote/app/lea/archive"
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
|
"time"
|
||||||
|
"strings"
|
||||||
|
"os"
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"regexp"
|
||||||
|
"encoding/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 主题
|
||||||
|
type ThemeService struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultStyle = "blog_default"
|
||||||
|
var elegantStyle = "blog_daqi"
|
||||||
|
var fixedStyle = "blog_left_fixed"
|
||||||
|
|
||||||
|
// admin用户的主题基路径
|
||||||
|
func (this *ThemeService) getDefaultThemeBasePath() string {
|
||||||
|
return revel.BasePath + "/public/blog/themes"
|
||||||
|
}
|
||||||
|
// 默认主题路径
|
||||||
|
func (this *ThemeService) getDefaultThemePath(style string) string {
|
||||||
|
if style == elegantStyle {
|
||||||
|
return this.getDefaultThemeBasePath() + "/elegant"
|
||||||
|
} else if style == fixedStyle {
|
||||||
|
return this.getDefaultThemeBasePath() + "/nav_fixed"
|
||||||
|
} else {
|
||||||
|
return this.getDefaultThemeBasePath() + "/default"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// blogService用
|
||||||
|
func (this *ThemeService) GetDefaultThemePath(style string) string {
|
||||||
|
if style == elegantStyle {
|
||||||
|
return "public/blog/themes/elegant"
|
||||||
|
} else if style == fixedStyle {
|
||||||
|
return "public/blog/themes/nav_fixed"
|
||||||
|
} else {
|
||||||
|
return "public/blog/themes/default"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到默认主题
|
||||||
|
// style是之前的值, 有3个值 blog_default, blog_daqi, blog_left_fixed
|
||||||
|
func (this *ThemeService) getDefaultTheme(style string) info.Theme {
|
||||||
|
if style == elegantStyle {
|
||||||
|
return info.Theme{
|
||||||
|
IsDefault: true,
|
||||||
|
Path: "public/blog/themes/elegant",
|
||||||
|
Name: "leanote elegant",
|
||||||
|
Author: "leanote",
|
||||||
|
AuthorUrl: "http://leanote.com",
|
||||||
|
Version: "1.0",
|
||||||
|
}
|
||||||
|
} else if style == fixedStyle {
|
||||||
|
return info.Theme{
|
||||||
|
IsDefault: true,
|
||||||
|
Path: "public/blog/themes/nav_fixed",
|
||||||
|
Name: "leanote nav fixed",
|
||||||
|
Author: "leanote",
|
||||||
|
AuthorUrl: "http://leanote.com",
|
||||||
|
Version: "1.0",
|
||||||
|
}
|
||||||
|
} else { // blog default
|
||||||
|
return info.Theme{
|
||||||
|
IsDefault: true,
|
||||||
|
Path: "public/blog/themes/default",
|
||||||
|
Name: "leanote default",
|
||||||
|
Author: "leanote",
|
||||||
|
AuthorUrl: "http://leanote.com",
|
||||||
|
Version: "1.0",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户的主题路径设置
|
||||||
|
func (this *ThemeService) getUserThemeBasePath(userId string) string {
|
||||||
|
return revel.BasePath + "/public/upload/" + userId + "/themes"
|
||||||
|
}
|
||||||
|
func (this *ThemeService) getUserThemePath(userId, themeId string) string {
|
||||||
|
return this.getUserThemeBasePath(userId) + "/" + themeId
|
||||||
|
}
|
||||||
|
func (this *ThemeService) getUserThemePath2(userId, themeId string) string {
|
||||||
|
return "public/upload/" + userId + "/themes/" + themeId
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新建主题
|
||||||
|
// 复制默认主题到文件夹下
|
||||||
|
func (this *ThemeService) CopyDefaultTheme(userBlog info.UserBlog) (ok bool, themeId string) {
|
||||||
|
newThemeId := bson.NewObjectId()
|
||||||
|
themeId = newThemeId.Hex()
|
||||||
|
userId := userBlog.UserId.Hex()
|
||||||
|
themePath := this.getUserThemePath(userId, themeId)
|
||||||
|
err := os.MkdirAll(themePath, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 复制默认主题
|
||||||
|
defaultThemePath := this.getDefaultThemePath(userBlog.Style)
|
||||||
|
err = CopyDir(defaultThemePath, themePath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存到数据库中
|
||||||
|
theme, _ := this.getThemeConfig(themePath)
|
||||||
|
theme.ThemeId = newThemeId
|
||||||
|
theme.Path = this.getUserThemePath2(userId, themeId)
|
||||||
|
theme.CreatedTime = time.Now()
|
||||||
|
theme.UpdatedTime = theme.CreatedTime
|
||||||
|
theme.UserId = bson.ObjectIdHex(userId)
|
||||||
|
|
||||||
|
ok = db.Insert(db.Themes, theme)
|
||||||
|
return ok, themeId
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第一次新建主题
|
||||||
|
// 设为active true
|
||||||
|
func (this *ThemeService) NewThemeForFirst(userBlog info.UserBlog) (ok bool, themeId string) {
|
||||||
|
ok, themeId = this.CopyDefaultTheme(userBlog)
|
||||||
|
db.UpdateByQField(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId)}, "IsActive", true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新建主题, 判断是否有主题了
|
||||||
|
func (this *ThemeService) NewTheme(userId string) (ok bool, themeId string) {
|
||||||
|
userBlog := blogService.GetUserBlog(userId)
|
||||||
|
// 如果还没有主题, 那先复制旧的主题
|
||||||
|
if userBlog.ThemeId == "" {
|
||||||
|
themeService.NewThemeForFirst(userBlog)
|
||||||
|
}
|
||||||
|
// 再copy一个默认主题
|
||||||
|
userBlog.Style = "defaultStyle";
|
||||||
|
ok, themeId = this.CopyDefaultTheme(userBlog)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将字符串转成Theme配置
|
||||||
|
func (this *ThemeService) parseConfig(configStr string) (theme info.Theme, err error) {
|
||||||
|
theme = info.Theme{}
|
||||||
|
// 除去/**/注释
|
||||||
|
reg, _ := regexp.Compile("/\\*[\\s\\S]*?\\*/")
|
||||||
|
configStr = reg.ReplaceAllString(configStr, "")
|
||||||
|
// 转成map
|
||||||
|
config := map[string]interface{}{}
|
||||||
|
err = json.Unmarshal([]byte(configStr), &config)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 没有错, 则将Name, Version, Author, AuthorUrl
|
||||||
|
Name := config["Name"]
|
||||||
|
if Name != nil {
|
||||||
|
theme.Name = Name.(string)
|
||||||
|
}
|
||||||
|
Version := config["Version"]
|
||||||
|
if Version != nil {
|
||||||
|
theme.Version = Version.(string)
|
||||||
|
}
|
||||||
|
Author := config["Author"]
|
||||||
|
if Author != nil {
|
||||||
|
theme.Author = Author.(string)
|
||||||
|
}
|
||||||
|
AuthorUrl := config["AuthorUrl"]
|
||||||
|
if AuthorUrl != nil {
|
||||||
|
theme.AuthorUrl = AuthorUrl.(string)
|
||||||
|
}
|
||||||
|
theme.Info = config
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 读取theme.json得到值
|
||||||
|
func (this *ThemeService) getThemeConfig(themePath string) (theme info.Theme, err error) {
|
||||||
|
theme = info.Theme{}
|
||||||
|
configStr := GetFileStrContent(themePath + "/theme.json")
|
||||||
|
theme, err = this.parseConfig(configStr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ThemeService) GetTheme(userId, themeId string) info.Theme {
|
||||||
|
theme := info.Theme{}
|
||||||
|
db.GetByQ(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId), "UserId": bson.ObjectIdHex(userId)}, &theme)
|
||||||
|
return theme
|
||||||
|
}
|
||||||
|
func (this *ThemeService) GetThemeById(themeId string) info.Theme {
|
||||||
|
theme := info.Theme{}
|
||||||
|
db.GetByQ(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId)}, &theme)
|
||||||
|
return theme
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到主题信息, 为了给博客用
|
||||||
|
func (this *ThemeService) GetThemeInfo(themeId, style string) map[string]interface{} {
|
||||||
|
q := bson.M{}
|
||||||
|
if themeId == "" {
|
||||||
|
if style == "" {
|
||||||
|
style = defaultStyle
|
||||||
|
}
|
||||||
|
q["Style"] = style
|
||||||
|
q["IsDefault"] = true
|
||||||
|
} else {
|
||||||
|
q["_id"] = bson.ObjectIdHex(themeId)
|
||||||
|
}
|
||||||
|
theme := info.Theme{}
|
||||||
|
db.GetByQ(db.Themes, q, &theme)
|
||||||
|
return theme.Info
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到用户的主题
|
||||||
|
// 若用户没有主题, 则至少有一个默认主题
|
||||||
|
// 第一个返回值是当前active
|
||||||
|
func (this *ThemeService) GetUserThemes(userId string) (theme info.Theme, themes []info.Theme) {
|
||||||
|
theme = info.Theme{}
|
||||||
|
themes = []info.Theme{}
|
||||||
|
|
||||||
|
// db.ListByQ(db.Themes, bson.M{"UserId": bson.ObjectIdHex(userId)}, &themes)
|
||||||
|
|
||||||
|
// 创建时间逆序
|
||||||
|
query := bson.M{"UserId": bson.ObjectIdHex(userId)}
|
||||||
|
q := db.Themes.Find(query);
|
||||||
|
q.Sort("-CreatedTime").All(&themes)
|
||||||
|
if len(themes) == 0 {
|
||||||
|
userBlog := blogService.GetUserBlog(userId)
|
||||||
|
theme = this.getDefaultTheme(userBlog.Style)
|
||||||
|
} else {
|
||||||
|
var has = false
|
||||||
|
// 第一个是active的主题
|
||||||
|
themes2 := make([]info.Theme, len(themes))
|
||||||
|
i := 0
|
||||||
|
for _, t := range themes {
|
||||||
|
if t.IsActive {
|
||||||
|
theme = t
|
||||||
|
} else {
|
||||||
|
has = true
|
||||||
|
themes2[i] = t
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if has {
|
||||||
|
themes = themes2
|
||||||
|
} else {
|
||||||
|
themes = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到默认主题供选择
|
||||||
|
func (this *ThemeService) GetDefaultThemes() (themes []info.Theme) {
|
||||||
|
themes = []info.Theme{}
|
||||||
|
db.ListByQ(db.Themes, bson.M{"IsDefault": true}, &themes)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到模板内容
|
||||||
|
func (this *ThemeService) GetTplContent(userId, themeId, filename string) string {
|
||||||
|
path := this.GetThemeAbsolutePath(userId, themeId) + "/" + filename
|
||||||
|
return GetFileStrContent(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到主题的绝对路径
|
||||||
|
func (this *ThemeService) GetThemeAbsolutePath(userId, themeId string) string {
|
||||||
|
theme := info.Theme{}
|
||||||
|
db.GetByQWithFields(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId), "UserId": bson.ObjectIdHex(userId)}, []string{"Path"}, &theme)
|
||||||
|
if theme.Path != "" {
|
||||||
|
return revel.BasePath + "/" + theme.Path
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
func (this *ThemeService) GetThemePath(userId, themeId string) string {
|
||||||
|
theme := info.Theme{}
|
||||||
|
db.GetByQWithFields(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId), "UserId": bson.ObjectIdHex(userId)}, []string{"Path"}, &theme)
|
||||||
|
if theme.Path != "" {
|
||||||
|
return theme.Path
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
// 更新模板内容
|
||||||
|
func (this *ThemeService) UpdateTplContent(userId, themeId, filename, content string) (ok bool, msg string) {
|
||||||
|
path := this.GetThemeAbsolutePath(userId, themeId) + "/" + filename
|
||||||
|
if strings.Contains(filename, ".html") {
|
||||||
|
// 模板
|
||||||
|
if ok, msg = this.mustTpl(filename, content); ok {
|
||||||
|
ok = PutFileStrContent(path, content)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
} else if filename == "theme.json" {
|
||||||
|
// 主题配置, 判断是否是正确的json
|
||||||
|
theme, err := this.parseConfig(content)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Sprintf("%v", err)
|
||||||
|
}
|
||||||
|
// 正确, 更新theme信息
|
||||||
|
ok = db.UpdateByQMap(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId), "UserId": bson.ObjectIdHex(userId)},
|
||||||
|
bson.M{
|
||||||
|
"Name": theme.Name,
|
||||||
|
"Version": theme.Version,
|
||||||
|
"Author": theme.Author,
|
||||||
|
"AuthorUrl": theme.AuthorUrl,
|
||||||
|
"Info": theme.Info,
|
||||||
|
})
|
||||||
|
if ok {
|
||||||
|
ok = PutFileStrContent(path, content)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ok = PutFileStrContent(path, content)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *ThemeService) DeleteTpl(userId, themeId, filename string) (ok bool) {
|
||||||
|
path := this.GetThemeAbsolutePath(userId, themeId) + "/" + filename
|
||||||
|
ok = DeleteFile(path)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否有语法错误
|
||||||
|
func (this *ThemeService) mustTpl(filename, content string) (ok bool, msg string) {
|
||||||
|
ok = true
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil {
|
||||||
|
ok = false
|
||||||
|
Log(err)
|
||||||
|
msg = fmt.Sprintf("%v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
template.Must(template.New(filename).Funcs(revel.TemplateFuncs).Parse(content))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////
|
||||||
|
|
||||||
|
// 使用主题
|
||||||
|
func (this *ThemeService) ActiveTheme(userId, themeId string) (ok bool) {
|
||||||
|
if db.Has(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId), "UserId": bson.ObjectIdHex(userId)}) {
|
||||||
|
// 之前的设为false
|
||||||
|
db.UpdateByQField(db.Themes, bson.M{"UserId": bson.ObjectIdHex(userId), "IsActive": true}, "IsActive", false)
|
||||||
|
// 现在的设为true
|
||||||
|
db.UpdateByQField(db.Themes, bson.M{"_id": bson.ObjectIdHex(themeId)}, "IsActive", true)
|
||||||
|
|
||||||
|
// UserBlog ThemeId
|
||||||
|
db.UpdateByQField(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, "ThemeId", bson.ObjectIdHex(themeId))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除主题
|
||||||
|
func (this *ThemeService) DeleteTheme(userId, themeId string) (ok bool) {
|
||||||
|
return db.Delete(db.Themes,bson.M{"_id": bson.ObjectIdHex(themeId), "UserId": bson.ObjectIdHex(userId), "IsActive": false})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 公开主题, 只有管理员才有权限, 之前没公开的变成公开
|
||||||
|
func (this *ThemeService) PublicTheme(userId, themeId string) (ok bool) {
|
||||||
|
// 是否是管理员?
|
||||||
|
userInfo := userService.GetUserInfo(userId)
|
||||||
|
if userInfo.Username == configService.GetAdminUsername() {
|
||||||
|
theme := this.GetThemeById(themeId)
|
||||||
|
return db.UpdateByQField(db.Themes, bson.M{"UserId": bson.ObjectIdHex(userId), "_id": bson.ObjectIdHex(themeId)}, "IsDefault", !theme.IsDefault)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 导出主题
|
||||||
|
func (this *ThemeService) ExportTheme(userId, themeId string) (ok bool, path string) {
|
||||||
|
theme := this.GetThemeById(themeId)
|
||||||
|
// 打包
|
||||||
|
// 验证路径, 别把整个项目打包了
|
||||||
|
Log(theme.Path)
|
||||||
|
if theme.Path == "" ||
|
||||||
|
(!strings.HasPrefix(theme.Path, "public/upload") &&
|
||||||
|
!strings.HasPrefix(theme.Path, "public/blog/themes")) ||
|
||||||
|
strings.Contains(theme.Path, "..") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sourcePath := revel.BasePath + "/" + theme.Path
|
||||||
|
targetPath := revel.BasePath + "/public/upload/" + userId + "/tmp"
|
||||||
|
err := os.MkdirAll(targetPath, 0755)
|
||||||
|
if err != nil {
|
||||||
|
Log(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
targetName := targetPath + "/" + theme.Name + ".zip"
|
||||||
|
Log(sourcePath)
|
||||||
|
Log(targetName)
|
||||||
|
ok = archive.Zip(sourcePath, targetName)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, targetName
|
||||||
|
}
|
||||||
|
// 导入主题
|
||||||
|
// path == /llllllll/..../public/upload/.../aa.zip, 绝对路径
|
||||||
|
func (this *ThemeService) ImportTheme(userId, path string) (ok bool, msg string) {
|
||||||
|
themeIdO := bson.NewObjectId()
|
||||||
|
themeId := themeIdO.Hex()
|
||||||
|
targetPath := this.getUserThemePath(userId, themeId) // revel.BasePath + "/public/upload/" + userId + "/themes/" + themeId
|
||||||
|
if ok, msg = archive.Unzip(path, targetPath); !ok {
|
||||||
|
DeleteFile(targetPath)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 解压成功, 那么新建之
|
||||||
|
// 保存到数据库中
|
||||||
|
theme, _ := this.getThemeConfig(targetPath)
|
||||||
|
if theme.Name == "" {
|
||||||
|
ok = false
|
||||||
|
DeleteFile(targetPath)
|
||||||
|
msg = "解析错误"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
theme.ThemeId = themeIdO
|
||||||
|
theme.Path = this.getUserThemePath2(userId, themeId)
|
||||||
|
theme.CreatedTime = time.Now()
|
||||||
|
theme.UpdatedTime = theme.CreatedTime
|
||||||
|
theme.UserId = bson.ObjectIdHex(userId)
|
||||||
|
|
||||||
|
ok = db.Insert(db.Themes, theme)
|
||||||
|
if !ok {
|
||||||
|
DeleteFile(targetPath)
|
||||||
|
}
|
||||||
|
DeleteFile(path)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 升级用
|
||||||
|
// public/
|
||||||
|
|
||||||
|
func (this *ThemeService) UpgradeThemeBeta2() (ok bool) {
|
||||||
|
adminUserId := configService.GetAdminUserId()
|
||||||
|
this.upgradeThemeBeta2(adminUserId, this.GetDefaultThemePath(defaultStyle), true)
|
||||||
|
this.upgradeThemeBeta2(adminUserId, this.GetDefaultThemePath(elegantStyle), false)
|
||||||
|
this.upgradeThemeBeta2(adminUserId, this.GetDefaultThemePath(fixedStyle), false)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
func (this *ThemeService) upgradeThemeBeta2(userId, targetPath string, isActive bool) (ok bool) {
|
||||||
|
// 解压成功, 那么新建之
|
||||||
|
// 保存到数据库中
|
||||||
|
theme, _ := this.getThemeConfig(revel.BasePath + "/" + targetPath)
|
||||||
|
if theme.Name == "" {
|
||||||
|
ok = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
themeIdO := bson.NewObjectId()
|
||||||
|
theme.ThemeId = themeIdO
|
||||||
|
theme.Path = targetPath // public
|
||||||
|
theme.CreatedTime = time.Now()
|
||||||
|
theme.UpdatedTime = theme.CreatedTime
|
||||||
|
theme.UserId = bson.ObjectIdHex(userId)
|
||||||
|
theme.IsActive = isActive
|
||||||
|
theme.IsDefault = true
|
||||||
|
ok = db.Insert(db.Themes, theme)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// 安装主题
|
||||||
|
// 得到该主题路径
|
||||||
|
func (this *ThemeService) InstallTheme(userId, themeId string) (ok bool) {
|
||||||
|
theme := this.GetThemeById(themeId)
|
||||||
|
// 不是默认主题, 即不是admin用户的主题, 不能乱安装
|
||||||
|
if !theme.IsDefault {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户之前是否有主题?
|
||||||
|
userBlog := blogService.GetUserBlog(userId)
|
||||||
|
if userBlog.ThemeId == "" {
|
||||||
|
this.NewThemeForFirst(userBlog)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成新主题
|
||||||
|
newThemeId := bson.NewObjectId()
|
||||||
|
themeId = newThemeId.Hex()
|
||||||
|
themePath := this.getUserThemePath(userId, themeId)
|
||||||
|
err := os.MkdirAll(themePath, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 复制默认主题
|
||||||
|
sourceThemePath := revel.BasePath + "/" + theme.Path
|
||||||
|
err = CopyDir(sourceThemePath, themePath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存到数据库中
|
||||||
|
theme, _ = this.getThemeConfig(themePath)
|
||||||
|
theme.ThemeId = newThemeId
|
||||||
|
theme.Path = this.getUserThemePath2(userId, themeId)
|
||||||
|
theme.CreatedTime = time.Now()
|
||||||
|
theme.UpdatedTime = theme.CreatedTime
|
||||||
|
theme.UserId = bson.ObjectIdHex(userId)
|
||||||
|
|
||||||
|
ok = db.Insert(db.Themes, theme)
|
||||||
|
|
||||||
|
return ok
|
||||||
|
}
|
||||||
@@ -19,9 +19,88 @@ func (this *UpgradeService) UpgradeBlog() bool {
|
|||||||
|
|
||||||
// PublicTime, RecommendTime = UpdatedTime
|
// PublicTime, RecommendTime = UpdatedTime
|
||||||
for _, note := range notes {
|
for _, note := range notes {
|
||||||
db.UpdateByIdAndUserIdMap2(db.Notes, note.NoteId, note.UserId, bson.M{"PublicTime": note.UpdatedTime, "RecommendTime": note.UpdatedTime})
|
if note.IsBlog && note.PublicTime.Year() < 100 {
|
||||||
Log(note.NoteId.Hex())
|
db.UpdateByIdAndUserIdMap2(db.Notes, note.NoteId, note.UserId, bson.M{"PublicTime": note.UpdatedTime, "RecommendTime": note.UpdatedTime})
|
||||||
|
Log(note.NoteId.Hex())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 11-5自定义博客升级, 将aboutMe移至pages
|
||||||
|
/*
|
||||||
|
<li>Migrate "About me" to single(a single post)</li>
|
||||||
|
<li>Add some default themes to administrator</li>
|
||||||
|
<li>Generate "UrlTitle" for all notes. "UrlTitle" is a friendly url for post</li>
|
||||||
|
<li>Generate "UrlTitle" for all notebooks</li>
|
||||||
|
<li>Generate "UrlTitle" for all singles</li>
|
||||||
|
*/
|
||||||
|
func (this *UpgradeService) UpgradeBetaToBeta2(userId string) (ok bool, msg string) {
|
||||||
|
if configService.GetGlobalStringConfig("UpgradeBetaToBeta2") != "" {
|
||||||
|
return false, "已升级"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. aboutMe -> page
|
||||||
|
userBlogs := []info.UserBlog{}
|
||||||
|
db.ListByQ(db.UserBlogs, bson.M{}, &userBlogs)
|
||||||
|
|
||||||
|
for _, userBlog := range userBlogs {
|
||||||
|
blogService.AddOrUpdateSingle(userBlog.UserId.Hex(), "", "About Me", userBlog.AboutMe)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 2. 默认主题, 给admin用户
|
||||||
|
themeService.UpgradeThemeBeta2()
|
||||||
|
|
||||||
|
// 3. UrlTitles
|
||||||
|
|
||||||
|
// 3.1 note
|
||||||
|
notes := []info.Note{}
|
||||||
|
db.ListByQ(db.Notes, bson.M{}, ¬es)
|
||||||
|
for _, note := range notes {
|
||||||
|
data := bson.M{}
|
||||||
|
noteId := note.NoteId.Hex()
|
||||||
|
// PublicTime, RecommendTime = UpdatedTime
|
||||||
|
if note.IsBlog && note.PublicTime.Year() < 100 {
|
||||||
|
data["PublicTime"] = note.UpdatedTime
|
||||||
|
data["RecommendTime"] = note.UpdatedTime
|
||||||
|
Log("Time " + noteId)
|
||||||
|
}
|
||||||
|
data["UrlTitle"] = GetUrTitle(note.UserId.Hex(), note.Title, "note")
|
||||||
|
db.UpdateByIdAndUserIdMap2(db.Notes, note.NoteId, note.UserId, data)
|
||||||
|
Log(noteId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3.2
|
||||||
|
Log("notebook")
|
||||||
|
notebooks := []info.Notebook{}
|
||||||
|
db.ListByQ(db.Notebooks, bson.M{}, ¬ebooks)
|
||||||
|
for _, notebook := range notebooks {
|
||||||
|
notebookId := notebook.NotebookId.Hex()
|
||||||
|
data := bson.M{}
|
||||||
|
data["UrlTitle"] = GetUrTitle(notebook.UserId.Hex(), notebook.Title, "notebook")
|
||||||
|
db.UpdateByIdAndUserIdMap2(db.Notebooks, notebook.NotebookId, notebook.UserId, data)
|
||||||
|
Log(notebookId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3.3 single
|
||||||
|
/*
|
||||||
|
singles := []info.BlogSingle{}
|
||||||
|
db.ListByQ(db.BlogSingles, bson.M{}, &singles)
|
||||||
|
for _, single := range singles {
|
||||||
|
singleId := single.SingleId.Hex()
|
||||||
|
blogService.UpdateSingleUrlTitle(single.UserId.Hex(), singleId, single.Title)
|
||||||
|
Log(singleId)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 删除索引
|
||||||
|
db.ShareNotes.DropIndex("UserId", "ToUserId", "NoteId")
|
||||||
|
|
||||||
|
ok = true
|
||||||
|
msg = "success"
|
||||||
|
configService.UpdateGlobalStringConfig(userId, "UpgradeBetaToBeta2", "1")
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
+103
-7
@@ -26,7 +26,7 @@ func (this *UserService) AddUser(user info.User) bool {
|
|||||||
go func() {
|
go func() {
|
||||||
emailService.RegisterSendActiveEmail(user, user.Email)
|
emailService.RegisterSendActiveEmail(user, user.Email)
|
||||||
// 发送给我 life@leanote.com
|
// 发送给我 life@leanote.com
|
||||||
// emailService.SendEmail("life@leanote.com", "新增用户", "{header}用户名" + user.Email + "{footer}");
|
emailService.SendEmail("life@leanote.com", "新增用户", "{header}用户名" + user.Email + "{footer}");
|
||||||
}();
|
}();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,6 +41,13 @@ func (this *UserService) GetUserId(email string) string {
|
|||||||
return user.UserId.Hex()
|
return user.UserId.Hex()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 得到用户名
|
||||||
|
func (this *UserService) GetUsername(userId string) string {
|
||||||
|
user := info.User{}
|
||||||
|
db.GetByQWithFields(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, []string{"Username"}, &user)
|
||||||
|
return user.Username
|
||||||
|
}
|
||||||
|
|
||||||
// 是否存在该用户 email
|
// 是否存在该用户 email
|
||||||
func (this *UserService) IsExistsUser(email string) bool {
|
func (this *UserService) IsExistsUser(email string) bool {
|
||||||
if this.GetUserId(email) == "" {
|
if this.GetUserId(email) == "" {
|
||||||
@@ -75,7 +82,7 @@ func (this *UserService) setUserLogo(user *info.User) {
|
|||||||
}
|
}
|
||||||
if user.Logo != "" && !strings.HasPrefix(user.Logo, "http") {
|
if user.Logo != "" && !strings.HasPrefix(user.Logo, "http") {
|
||||||
user.Logo = strings.Trim(user.Logo, "/")
|
user.Logo = strings.Trim(user.Logo, "/")
|
||||||
user.Logo = siteUrl + "/" + user.Logo
|
user.Logo = configService.GetSiteUrl() + "/" + user.Logo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,6 +140,58 @@ func (this *UserService) MapUserInfoAndBlogInfosByUserIds(userIds []bson.ObjectI
|
|||||||
return this.MapUserInfoByUserIds(userIds)
|
return this.MapUserInfoByUserIds(userIds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 返回info.UserAndBlog
|
||||||
|
func (this *UserService) MapUserAndBlogByUserIds(userIds []bson.ObjectId) map[string]info.UserAndBlog {
|
||||||
|
users := []info.User{}
|
||||||
|
db.ListByQ(db.Users, bson.M{"_id": bson.M{"$in": userIds}}, &users)
|
||||||
|
|
||||||
|
userBlogs := []info.UserBlog{}
|
||||||
|
db.ListByQ(db.UserBlogs, bson.M{"_id": bson.M{"$in": userIds}}, &userBlogs)
|
||||||
|
|
||||||
|
userBlogMap := make(map[bson.ObjectId]info.UserBlog, len(userBlogs))
|
||||||
|
for _, user := range userBlogs {
|
||||||
|
userBlogMap[user.UserId] = user
|
||||||
|
}
|
||||||
|
|
||||||
|
userAndBlogMap := make(map[string]info.UserAndBlog, len(users))
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
this.setUserLogo(&user)
|
||||||
|
|
||||||
|
userBlog, ok := userBlogMap[user.UserId]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
userAndBlogMap[user.UserId.Hex()] = info.UserAndBlog{
|
||||||
|
UserId: user.UserId,
|
||||||
|
Username: user.Username,
|
||||||
|
Email: user.Email,
|
||||||
|
Logo: user.Logo,
|
||||||
|
BlogTitle: userBlog.Title,
|
||||||
|
BlogLogo: userBlog.Logo,
|
||||||
|
BlogUrl: blogService.GetUserBlogUrl(&userBlog, user.Username),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return userAndBlogMap
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到userAndBlog公开信息
|
||||||
|
func (this *UserService) GetUserAndBlog(userId string) info.UserAndBlog {
|
||||||
|
user := this.GetUserInfo(userId)
|
||||||
|
userBlog := blogService.GetUserBlog(userId)
|
||||||
|
return info.UserAndBlog{
|
||||||
|
UserId: user.UserId,
|
||||||
|
Username: user.Username,
|
||||||
|
Email: user.Email,
|
||||||
|
Logo: user.Logo,
|
||||||
|
BlogTitle: userBlog.Title,
|
||||||
|
BlogLogo: userBlog.Logo,
|
||||||
|
BlogUrl: blogService.GetUserBlogUrl(&userBlog, user.Username),
|
||||||
|
BlogUrls: blogService.GetBlogUrls(&userBlog, &user),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 通过ids得到users, 按id的顺序组织users
|
// 通过ids得到users, 按id的顺序组织users
|
||||||
func (this *UserService) GetUserInfosOrderBySeq(userIds []bson.ObjectId) []info.User {
|
func (this *UserService) GetUserInfosOrderBySeq(userIds []bson.ObjectId) []info.User {
|
||||||
users := []info.User{}
|
users := []info.User{}
|
||||||
@@ -143,9 +202,11 @@ func (this *UserService) GetUserInfosOrderBySeq(userIds []bson.ObjectId) []info.
|
|||||||
usersMap[user.UserId] = user
|
usersMap[user.UserId] = user
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasAppend := map[bson.ObjectId]bool{} // 为了防止userIds有重复的
|
||||||
users2 := []info.User{};
|
users2 := []info.User{};
|
||||||
for _, userId := range userIds {
|
for _, userId := range userIds {
|
||||||
if user, ok := usersMap[userId]; ok {
|
if user, ok := usersMap[userId]; ok && !hasAppend[userId] {
|
||||||
|
hasAppend[userId] = true
|
||||||
users2 = append(users2, user)
|
users2 = append(users2, user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -169,7 +230,7 @@ func (this *UserService) LoginGetUserInfo(emailOrUsername, md5Pwd string) info.U
|
|||||||
// 更新username
|
// 更新username
|
||||||
func (this *UserService) UpdateUsername(userId, username string) (bool, string) {
|
func (this *UserService) UpdateUsername(userId, username string) (bool, string) {
|
||||||
if userId == "" || username == "" || username == "admin" { // admin用户是内置的, 不能设置
|
if userId == "" || username == "" || username == "admin" { // admin用户是内置的, 不能设置
|
||||||
return false, "用户已存在"
|
return false, "usernameIsExisted"
|
||||||
}
|
}
|
||||||
usernameRaw := username // 原先的, 可能是同一个, 但有大小写
|
usernameRaw := username // 原先的, 可能是同一个, 但有大小写
|
||||||
username = strings.ToLower(username)
|
username = strings.ToLower(username)
|
||||||
@@ -177,7 +238,7 @@ func (this *UserService) UpdateUsername(userId, username string) (bool, string)
|
|||||||
// 先判断是否存在
|
// 先判断是否存在
|
||||||
userIdO := bson.ObjectIdHex(userId)
|
userIdO := bson.ObjectIdHex(userId)
|
||||||
if db.Has(db.Users, bson.M{"Username": username, "_id": bson.M{"$ne": userIdO}}) {
|
if db.Has(db.Users, bson.M{"Username": username, "_id": bson.M{"$ne": userIdO}}) {
|
||||||
return false, "用户已存在"
|
return false, "usernameIsExisted"
|
||||||
}
|
}
|
||||||
|
|
||||||
ok := db.UpdateByQMap(db.Users, bson.M{"_id": userIdO}, bson.M{"Username": username, "UsernameRaw": usernameRaw})
|
ok := db.UpdateByQMap(db.Users, bson.M{"_id": userIdO}, bson.M{"Username": username, "UsernameRaw": usernameRaw})
|
||||||
@@ -195,18 +256,42 @@ func (this *UserService) UpdateAvatar(userId, avatarPath string) (bool) {
|
|||||||
func (this *UserService) UpdatePwd(userId, oldPwd, pwd string) (bool, string) {
|
func (this *UserService) UpdatePwd(userId, oldPwd, pwd string) (bool, string) {
|
||||||
userInfo := this.GetUserInfo(userId)
|
userInfo := this.GetUserInfo(userId)
|
||||||
if userInfo.Pwd != Md5(oldPwd) {
|
if userInfo.Pwd != Md5(oldPwd) {
|
||||||
return false, "旧密码错误"
|
return false, "oldPasswordError"
|
||||||
}
|
}
|
||||||
ok := db.UpdateByQField(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, "Pwd", Md5(pwd))
|
ok := db.UpdateByQField(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, "Pwd", Md5(pwd))
|
||||||
return ok, ""
|
return ok, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 管理员重置密码
|
||||||
|
func (this *UserService) ResetPwd(adminUserId, userId, pwd string) (ok bool, msg string) {
|
||||||
|
if configService.GetAdminUserId() != adminUserId {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ok = db.UpdateByQField(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, "Pwd", Md5(pwd))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 修改主题
|
// 修改主题
|
||||||
func (this *UserService) UpdateTheme(userId, theme string) (bool) {
|
func (this *UserService) UpdateTheme(userId, theme string) (bool) {
|
||||||
ok := db.UpdateByQField(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, "Theme", theme)
|
ok := db.UpdateByQField(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, "Theme", theme)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 帐户类型设置
|
||||||
|
func (this *UserService) UpdateAccount(userId, accountType string, accountStartTime, accountEndTime time.Time,
|
||||||
|
maxImageNum, maxImageSize, maxAttachNum, maxAttachSize, maxPerAttachSize int) bool {
|
||||||
|
return db.UpdateByQI(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, info.UserAccount{
|
||||||
|
AccountType: accountType,
|
||||||
|
AccountStartTime: accountStartTime,
|
||||||
|
AccountEndTime: accountEndTime,
|
||||||
|
MaxImageNum: maxImageNum,
|
||||||
|
MaxImageSize: maxImageSize,
|
||||||
|
MaxAttachNum: maxAttachNum,
|
||||||
|
MaxAttachSize: maxAttachSize,
|
||||||
|
MaxPerAttachSize: maxPerAttachSize,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
//---------------
|
//---------------
|
||||||
// 修改email
|
// 修改email
|
||||||
|
|
||||||
@@ -261,6 +346,13 @@ func (this *UserService) UpdateEmail(token string) (ok bool, msg, email string)
|
|||||||
//---------
|
//---------
|
||||||
// 第三方添加账号
|
// 第三方添加账号
|
||||||
func (this *UserService) ThirdAddUser(userId, email, pwd string) (ok bool, msg string) {
|
func (this *UserService) ThirdAddUser(userId, email, pwd string) (ok bool, msg string) {
|
||||||
|
// 判断该用户是否已有了帐户
|
||||||
|
userInfo := this.GetUserInfo(userId)
|
||||||
|
if userInfo.Email != "" {
|
||||||
|
msg = "你已有帐户"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 判断email是否存在
|
// 判断email是否存在
|
||||||
if this.IsExistsUser(email) {
|
if this.IsExistsUser(email) {
|
||||||
msg = "该用户已存在"
|
msg = "该用户已存在"
|
||||||
@@ -291,7 +383,11 @@ func (this *UserService) ListUsers(pageNumber, pageSize int, sortField string, i
|
|||||||
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
||||||
query := bson.M{}
|
query := bson.M{}
|
||||||
if email != "" {
|
if email != "" {
|
||||||
query["Email"] = bson.M{"$regex": bson.RegEx{".*?" + email + ".*", "i"}}
|
orQ := []bson.M{
|
||||||
|
bson.M{"Email": bson.M{"$regex": bson.RegEx{".*?" + email + ".*", "i"}}},
|
||||||
|
bson.M{"Username": bson.M{"$regex": bson.RegEx{".*?" + email + ".*", "i"}}},
|
||||||
|
}
|
||||||
|
query["$or"] = orQ
|
||||||
}
|
}
|
||||||
q := db.Users.Find(query);
|
q := db.Users.Find(query);
|
||||||
// 总记录数
|
// 总记录数
|
||||||
|
|||||||
+80
-6
@@ -1,7 +1,13 @@
|
|||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/revel/revel"
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"gopkg.in/mgo.v2"
|
||||||
|
"github.com/leanote/leanote/app/db"
|
||||||
|
"gopkg.in/mgo.v2/bson"
|
||||||
)
|
)
|
||||||
|
|
||||||
// init service, for share service bettween services
|
// init service, for share service bettween services
|
||||||
@@ -14,6 +20,7 @@ var noteContentHistoryService, NoteContentHistoryS *NoteContentHistoryService
|
|||||||
var trashService, TrashS *TrashService
|
var trashService, TrashS *TrashService
|
||||||
var shareService, ShareS *ShareService
|
var shareService, ShareS *ShareService
|
||||||
var userService, UserS *UserService
|
var userService, UserS *UserService
|
||||||
|
var groupService, GroupS *GroupService
|
||||||
var tagService, TagS *TagService
|
var tagService, TagS *TagService
|
||||||
var blogService, BlogS *BlogService
|
var blogService, BlogS *BlogService
|
||||||
var tokenService, TokenS *TokenService
|
var tokenService, TokenS *TokenService
|
||||||
@@ -28,8 +35,7 @@ var emailService, EmailS *EmailService
|
|||||||
var AuthS *AuthService
|
var AuthS *AuthService
|
||||||
var UpgradeS *UpgradeService
|
var UpgradeS *UpgradeService
|
||||||
var SessionS, sessionService *SessionService
|
var SessionS, sessionService *SessionService
|
||||||
|
var ThemeS, themeService *ThemeService
|
||||||
var siteUrl string
|
|
||||||
|
|
||||||
// onAppStart调用
|
// onAppStart调用
|
||||||
func InitService() {
|
func InitService() {
|
||||||
@@ -39,6 +45,7 @@ func InitService() {
|
|||||||
TrashS = &TrashService{}
|
TrashS = &TrashService{}
|
||||||
ShareS = &ShareService{}
|
ShareS = &ShareService{}
|
||||||
UserS = &UserService{}
|
UserS = &UserService{}
|
||||||
|
GroupS = &GroupService{}
|
||||||
TagS = &TagService{}
|
TagS = &TagService{}
|
||||||
BlogS = &BlogService{}
|
BlogS = &BlogService{}
|
||||||
TokenS = &TokenService{}
|
TokenS = &TokenService{}
|
||||||
@@ -53,6 +60,7 @@ func InitService() {
|
|||||||
EmailS = NewEmailService()
|
EmailS = NewEmailService()
|
||||||
UpgradeS = &UpgradeService{}
|
UpgradeS = &UpgradeService{}
|
||||||
SessionS = &SessionService{}
|
SessionS = &SessionService{}
|
||||||
|
ThemeS = &ThemeService{}
|
||||||
|
|
||||||
notebookService = NotebookS
|
notebookService = NotebookS
|
||||||
noteService = NoteS
|
noteService = NoteS
|
||||||
@@ -60,6 +68,7 @@ func InitService() {
|
|||||||
trashService = TrashS
|
trashService = TrashS
|
||||||
shareService = ShareS
|
shareService = ShareS
|
||||||
userService = UserS
|
userService = UserS
|
||||||
|
groupService = GroupS
|
||||||
tagService = TagS
|
tagService = TagS
|
||||||
blogService = BlogS
|
blogService = BlogS
|
||||||
tokenService = TokenS
|
tokenService = TokenS
|
||||||
@@ -70,7 +79,72 @@ func InitService() {
|
|||||||
configService = ConfigS
|
configService = ConfigS
|
||||||
emailService = EmailS
|
emailService = EmailS
|
||||||
sessionService = SessionS
|
sessionService = SessionS
|
||||||
|
themeService = ThemeS
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
// service 公用方法
|
||||||
|
|
||||||
|
// 将name=val的val进行encoding
|
||||||
|
func decodeValue(val string) string {
|
||||||
|
v, _ := url.ParseQuery("a=" + val)
|
||||||
|
return v.Get("a")
|
||||||
|
}
|
||||||
|
|
||||||
|
func encodeValue(val string) string {
|
||||||
|
if val == "" {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
v := url.Values{}
|
||||||
|
v.Set("", val)
|
||||||
|
return v.Encode()[1:]
|
||||||
|
}
|
||||||
|
// 添加笔记时通过title得到urlTitle
|
||||||
|
func fixUrlTitle(urlTitle string) string {
|
||||||
|
if urlTitle != "" {
|
||||||
|
// 把特殊字段给替换掉
|
||||||
|
// str := `life "%&()+,/:;<>=?@\|`
|
||||||
|
reg, _ := regexp.Compile("/|#|\\$|!|\\^|\\*|'| |\"|%|&|\\(|\\)|\\+|\\,|/|:|;|<|>|=|\\?|@|\\||\\\\")
|
||||||
|
urlTitle = reg.ReplaceAllString(urlTitle, "-")
|
||||||
|
urlTitle = strings.Trim(urlTitle, "-") // 左右单独的-去掉
|
||||||
|
// 把空格替换成-
|
||||||
|
// urlTitle = strings.Replace(urlTitle, " ", "-", -1)
|
||||||
|
for strings.Index(urlTitle, "--") >= 0 { // 防止出现连续的--
|
||||||
|
urlTitle = strings.Replace(urlTitle, "--", "-", -1)
|
||||||
|
}
|
||||||
|
return encodeValue(urlTitle)
|
||||||
|
}
|
||||||
|
return urlTitle
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUniqueUrlTitle(userId string, urlTitle string, types string, padding int) string {
|
||||||
|
urlTitle2 := urlTitle
|
||||||
|
if padding > 1 {
|
||||||
|
urlTitle2 = urlTitle + "-" + strconv.Itoa(padding)
|
||||||
|
}
|
||||||
|
userIdO := bson.ObjectIdHex(userId)
|
||||||
|
|
||||||
//
|
var collection *mgo.Collection
|
||||||
siteUrl, _ = revel.Config.String("site.url")
|
if types == "note" {
|
||||||
}
|
collection = db.Notes
|
||||||
|
} else if types == "notebook" {
|
||||||
|
collection = db.Notebooks
|
||||||
|
} else if types == "single" {
|
||||||
|
collection = db.BlogSingles
|
||||||
|
}
|
||||||
|
for db.Has(collection, bson.M{"UserId": userIdO, "UrlTitle": urlTitle2}) { // 用户下唯一
|
||||||
|
padding++
|
||||||
|
urlTitle2 = urlTitle + "-" + strconv.Itoa(padding)
|
||||||
|
}
|
||||||
|
|
||||||
|
return urlTitle2
|
||||||
|
}
|
||||||
|
// types == note,notebook,single
|
||||||
|
func GetUrTitle(userId string, title string, types string) string {
|
||||||
|
urlTitle := strings.Trim(title, " ")
|
||||||
|
if urlTitle == "" {
|
||||||
|
urlTitle = "Untitled-" + userId
|
||||||
|
}
|
||||||
|
urlTitle = fixUrlTitle(urlTitle)
|
||||||
|
return getUniqueUrlTitle(userId, urlTitle, types, 1)
|
||||||
|
}
|
||||||
@@ -97,9 +97,6 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4 text-center">
|
<div class="col-sm-4 text-center">
|
||||||
<small class="text-muted inline m-t-sm m-b-sm">
|
|
||||||
showing 20-30 of 50 items
|
|
||||||
</small>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4 text-right text-center-xs">
|
<div class="col-sm-4 text-right text-center-xs">
|
||||||
{{set . "url" (urlConcat "/adminBlog/index" "sorter" .sorter "keywords" .keywords)}}
|
{{set . "url" (urlConcat "/adminBlog/index" "sorter" .sorter "keywords" .keywords)}}
|
||||||
|
|||||||
@@ -128,10 +128,18 @@
|
|||||||
</i>
|
</i>
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
Setting
|
Configuration
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<ul class="nav lt">
|
<ul class="nav lt">
|
||||||
|
<li>
|
||||||
|
<a href="/admin/t?t=setting/home_page">
|
||||||
|
<span>
|
||||||
|
Home Page
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<a href="/admin/t?t=setting/demo">
|
<a href="/admin/t?t=setting/demo">
|
||||||
<span>
|
<span>
|
||||||
@@ -141,7 +149,7 @@
|
|||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<a href="/admin/t?t=setting/openRegister">
|
<a href="/admin/t?t=setting/open_register">
|
||||||
<span>
|
<span>
|
||||||
Open Register
|
Open Register
|
||||||
</span>
|
</span>
|
||||||
@@ -155,6 +163,14 @@
|
|||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<a href="/admin/t?t=setting/upload">
|
||||||
|
<span>
|
||||||
|
Upload File Size Limit
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
@@ -192,5 +208,32 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#">
|
||||||
|
<i class="fa fa-space-shuttle icon">
|
||||||
|
<b class="bg-danger">
|
||||||
|
</b>
|
||||||
|
</i>
|
||||||
|
<span class="pull-right">
|
||||||
|
<i class="fa fa-angle-down text">
|
||||||
|
</i>
|
||||||
|
<i class="fa fa-angle-up text-active">
|
||||||
|
</i>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
Upgrade
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<ul class="nav lt">
|
||||||
|
<li>
|
||||||
|
<a href="/admin/t?t=upgrade/beta2">
|
||||||
|
<span>
|
||||||
|
v1.0-beta to v1.0-beta2
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
{{template "admin/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">Home Page</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<form id="form_data">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label><a href="/blog" target="_blank">Admin's Blog Page</a></label>
|
||||||
|
<input type="radio" class="form-control" name="homePage" {{if not .str.homePage}}checked="checked"{{end}} value="0">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label><a href="/index" target="_blank">Index Page</a></label>
|
||||||
|
<input type="radio" class="form-control" name="homePage" {{if .str.homePage}}checked="checked"{{end}} value="1">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="submit" class="btn btn-success btn-s-xs">Submit</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "admin/footer.html" .}}
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
$("#submit").click(function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
var t = this;
|
||||||
|
$(t).button('loading');
|
||||||
|
ajaxPost("/adminSetting/homePage", getFormJsonData("form_data"), function(ret){
|
||||||
|
$(t).button('reset');
|
||||||
|
if(!ret.Ok) {
|
||||||
|
art.alert(ret.Msg);
|
||||||
|
} else {
|
||||||
|
art.tips("Success");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "admin/end.html" .}}
|
||||||
File renamed without changes.
@@ -0,0 +1,65 @@
|
|||||||
|
{{template "admin/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">Upload File Size Limit</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<form id="add_user_form">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Image</label>
|
||||||
|
<input type="text" class="form-control" name="uploadImageSize" value="{{.str.uploadImageSize}}">
|
||||||
|
MB. Default is unlimit;
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Avatar</label>
|
||||||
|
<input type="text" class="form-control" name="uploadAvatarSize" value="{{.str.uploadAvatarSize}}">
|
||||||
|
MB. Default is unlimit;
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Blog Logo</label>
|
||||||
|
<input type="text" class="form-control" name="uploadBlogLogoSize" value="{{.str.uploadBlogLogoSize}}">
|
||||||
|
MB. Default is unlimit;
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Attachment</label>
|
||||||
|
<input type="text" class="form-control" name="uploadAttachSize" value="{{.str.uploadAttachSize}}">
|
||||||
|
MB. Default is unlimit;
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="submit" class="btn btn-success btn-s-xs">Submit</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "admin/footer.html" .}}
|
||||||
|
<script src="/public/admin/js/jquery-validation-1.13.0/jquery.validate.js"></script>
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
init_validator("#add_user_form");
|
||||||
|
|
||||||
|
$("#submit").click(function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
var t = this;
|
||||||
|
if($("#add_user_form").valid()) {
|
||||||
|
$(t).button('loading');
|
||||||
|
ajaxPost("/adminSetting/uploadSize", getFormJsonData("add_user_form"), function(ret){
|
||||||
|
$(t).button('reset')
|
||||||
|
if(!ret.Ok) {
|
||||||
|
art.alert(ret.Msg)
|
||||||
|
} else {
|
||||||
|
art.tips("Success");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "admin/end.html" .}}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
{{template "admin/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">Upgrade v1.0-beta to v1.0-beta2</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<form id="add_user_form">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
Current Version: <span class="label label-success">leanote v{{.version}}</span>
|
||||||
|
<ul>
|
||||||
|
<li>Migrate "About me" to single(a single post)</li>
|
||||||
|
<li>Add some default themes to administrator</li>
|
||||||
|
<li>Generate "UrlTitle" for all notes. "UrlTitle" is a friendly url for post</li>
|
||||||
|
<li>Generate "UrlTitle" for all notebooks</li>
|
||||||
|
<li>Generate "UrlTitle" for all singles</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="submit" class="btn btn-success btn-s-xs">Upgrade</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "admin/footer.html" .}}
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
$("#submit").click(function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
var t = this;
|
||||||
|
$(t).button('loading');
|
||||||
|
ajaxPost("/adminUpgrade/UpgradeBetaToBeta2", {}, function(ret){
|
||||||
|
$(t).button('reset')
|
||||||
|
if(!ret.Ok) {
|
||||||
|
art.alert(ret.Msg)
|
||||||
|
} else {
|
||||||
|
art.tips("Success");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "admin/end.html" .}}
|
||||||
@@ -42,7 +42,7 @@ $(function() {
|
|||||||
var t = this;
|
var t = this;
|
||||||
if($("#add_user_form").valid()) {
|
if($("#add_user_form").valid()) {
|
||||||
$(t).button('loading');
|
$(t).button('loading');
|
||||||
ajaxPost("/auth/doRegister", getFormJsonData("add_user_form"), function(ret){
|
ajaxPost("/adminUser/register", getFormJsonData("add_user_form"), function(ret){
|
||||||
$(t).button('reset')
|
$(t).button('reset')
|
||||||
if(!ret.Ok) {
|
if(!ret.Ok) {
|
||||||
art.alert(ret.Msg);
|
art.alert(ret.Msg);
|
||||||
|
|||||||
@@ -4,16 +4,8 @@
|
|||||||
<section class="panel panel-default">
|
<section class="panel panel-default">
|
||||||
<div class="row wrapper">
|
<div class="row wrapper">
|
||||||
<div class="col-sm-5 m-b-xs">
|
<div class="col-sm-5 m-b-xs">
|
||||||
<select class="input-sm form-control input-s-sm inline v-middle">
|
<button class="btn btn-sm btn-default bulk-email">
|
||||||
<option value="">
|
Send Email
|
||||||
Bulk action
|
|
||||||
</option>
|
|
||||||
<option value="1">
|
|
||||||
Send Email
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
<button class="btn btn-sm btn-default bulk-btn">
|
|
||||||
Apply
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4 m-b-xs">
|
<div class="col-sm-4 m-b-xs">
|
||||||
@@ -21,7 +13,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-sm-3">
|
<div class="col-sm-3">
|
||||||
<div class="input-group search-group">
|
<div class="input-group search-group">
|
||||||
<input type="text" class="input-sm form-control" placeholder="Email" id="keywords" value="{{.keywords}}" />
|
<input type="text" class="input-sm form-control" placeholder="Username or Email" id="keywords" value="{{.keywords}}" />
|
||||||
<span class="input-group-btn">
|
<span class="input-group-btn">
|
||||||
<button class="btn btn-sm btn-default" type="button" data-url="/adminUser/index">Search</button>
|
<button class="btn btn-sm btn-default" type="button" data-url="/adminUser/index">Search</button>
|
||||||
</span>
|
</span>
|
||||||
@@ -99,7 +91,8 @@
|
|||||||
{{.CreatedTime|datetime}}
|
{{.CreatedTime|datetime}}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="#" class="btn btn-default send-email" data-email="{{.Email}}">Send Email</a>
|
<a href="#" class="btn btn-sm btn-default reset-pwd" data-id="{{.UserId.Hex}}">Reset Password</a>
|
||||||
|
<a href="#" class="btn btn-sm btn-default send-email" data-email="{{.Email}}">Send Email</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{end}}
|
{{end}}
|
||||||
@@ -109,16 +102,8 @@
|
|||||||
<footer class="panel-footer">
|
<footer class="panel-footer">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-sm-4 hidden-xs">
|
<div class="col-sm-4 hidden-xs">
|
||||||
<select class="input-sm form-control input-s-sm inline v-middle">
|
<button class="btn btn-sm btn-default bulk-email">
|
||||||
<option value="">
|
Send Email
|
||||||
Bulk action
|
|
||||||
</option>
|
|
||||||
<option value="1">
|
|
||||||
Send Email
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
<button class="btn btn-sm btn-default bulk-btn">
|
|
||||||
Apply
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -137,19 +122,22 @@ $(function() {
|
|||||||
$(".send-email").click(function() {
|
$(".send-email").click(function() {
|
||||||
openSendEmailDialog($(this).data("email"));
|
openSendEmailDialog($(this).data("email"));
|
||||||
});
|
});
|
||||||
$(".bulk-btn").click(function() {
|
$(".bulk-email").click(function() {
|
||||||
// email
|
var emails = [];
|
||||||
if($(this).prev().val() == "1") {
|
$(".ck:checked").each(function() {
|
||||||
var emails = [];
|
emails.push($(this).data("email"));
|
||||||
$(".ck:checked").each(function() {
|
});
|
||||||
emails.push($(this).data("email"));
|
if(emails.length == 0) {
|
||||||
});
|
art.alert("No user");
|
||||||
if(emails.length == 0) {
|
return;
|
||||||
art.alert("No user");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
openSendEmailDialog(emails.join(","));
|
|
||||||
}
|
}
|
||||||
|
openSendEmailDialog(emails.join(","));
|
||||||
|
});
|
||||||
|
|
||||||
|
// reset password
|
||||||
|
$(".reset-pwd").click(function() {
|
||||||
|
var id = $(this).data("id");
|
||||||
|
openDialog({width: 500, url: "/adminUser/resetPwd?userId=" + id, title: "Reset Password"});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
<div class="row" style="width: 500px;">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<form id="dataForm">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<header class="panel-heading font-bold">Email</header>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="form-group pull-in clearfix">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<label>New password</label>
|
||||||
|
<input id="pwd" type="password" class="form-control" data-rule-required="true" id="pwd" name="pwd" data-rule-minlength="6">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group pull-in clearfix">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<label>Confirm password</label>
|
||||||
|
<input type="password" class="form-control parsley-validated" data-rule-equalto="#pwd" data-rule-required="true" name="password2">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="resetPwdBtn" class="btn btn-success btn-s-xs">Submit</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="/public/admin/js/jquery-validation-1.13.0/jquery.validate.js"></script>
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
var userId = "{{.userInfo.UserId.Hex}}";
|
||||||
|
init_validator("#dataForm");
|
||||||
|
$("#resetPwdBtn").click(function(e){
|
||||||
|
e.preventDefault();
|
||||||
|
var t = this;
|
||||||
|
if($("#dataForm").valid()) {
|
||||||
|
$(t).button('loading');
|
||||||
|
ajaxPost("/adminUser/doResetPwd", {userId: userId, pwd: $("#pwd").val()}, function(ret){
|
||||||
|
$(t).button('reset')
|
||||||
|
if(!ret.Ok) {
|
||||||
|
art.alert(ret.Msg);
|
||||||
|
} else {
|
||||||
|
art.tips("Success");
|
||||||
|
closeDialog();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">
|
||||||
|
{{if .page}}
|
||||||
|
修改页面
|
||||||
|
{{else}}
|
||||||
|
添加页面
|
||||||
|
{{end}}
|
||||||
|
</h3></div>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/tinymce/skins/custom/skin.min.css" type="text/css">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<form id="formData">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="alert alert-danger" id="baseMsg" style="display: none"></div>
|
||||||
|
<input type="hidden" id="singleId" value="{{.single.SingleId.Hex}}" />
|
||||||
|
<div class="form-group">
|
||||||
|
<label>标题</label>
|
||||||
|
<input type="text" class="form-control" id="title" name="title"
|
||||||
|
value="{{.single.Title}}"
|
||||||
|
data-rules='[
|
||||||
|
{rule: "required", msg: "请输入页面标题"},
|
||||||
|
]'
|
||||||
|
data-msg_target="#baseMsg"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="content1">内容</label>
|
||||||
|
<div id="popularToolbar"></div>
|
||||||
|
<textarea id="content1" name="content">{{.single.Content}}</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="baseBtn" class="btn btn-success">{{msg . "submit"}}</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script type="text/javascript" src="/tinymce/tinymce.min.js"></script>
|
||||||
|
<script>
|
||||||
|
var urlPrefix = "{{.siteUrl}}";
|
||||||
|
$(function() {
|
||||||
|
tinymce.init({
|
||||||
|
selector : "#content1",
|
||||||
|
content_css : [ "/css/bootstrap.css", "/css/editor/editor.css" ],
|
||||||
|
skin : "custom",
|
||||||
|
language : "{{.locale}}",
|
||||||
|
height : 300,
|
||||||
|
width : "100%",
|
||||||
|
skin : "custom",
|
||||||
|
plugins : [
|
||||||
|
"advlist autolink link leanote_image lists charmap hr ",
|
||||||
|
"searchreplace visualblocks visualchars leanote_code tabfocus",
|
||||||
|
"table contextmenu directionality textcolor paste fullpage textcolor"],
|
||||||
|
toolbar1 : "formatselect |fontselect fontsizeselect| forecolor backcolor | bold italic underline strikethrough | bullist numlist |",
|
||||||
|
menubar : false,
|
||||||
|
statusbar : false,
|
||||||
|
font_formats : "Arial=arial,helvetica,sans-serif;"
|
||||||
|
+ "Arial Black=arial black,avant garde;"
|
||||||
|
+ "Times New Roman=times new roman,times;"
|
||||||
|
+ "Courier New=courier new,courier;"
|
||||||
|
+ "Tahoma=tahoma,arial,helvetica,sans-serif;"
|
||||||
|
+ "Verdana=verdana,geneva;" + "宋体=SimSun;"
|
||||||
|
+ "新宋体=NSimSun;" + "黑体=SimHei;"
|
||||||
|
+ "微软雅黑=Microsoft YaHei",
|
||||||
|
block_formats : "Header 1=h1;Header 2=h2;Header 3=h3; Header 4=h4;Pre=pre;Paragraph=p"
|
||||||
|
});
|
||||||
|
|
||||||
|
// 基本设置
|
||||||
|
var vdPage = new vd.init("#formData");
|
||||||
|
$("#baseBtn").click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if(!vdPage.valid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var data = {
|
||||||
|
singleId: $("#singleId").val(),
|
||||||
|
title : $("#title").val(),
|
||||||
|
content : getEditorContent()
|
||||||
|
}
|
||||||
|
ajaxPost("/member/blog/doAddOrUpdateSingle/", data, function(re) {
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
// 添加成功后, 跳转之
|
||||||
|
art.tips("Success")
|
||||||
|
if(!data.pageId) {
|
||||||
|
location.href = "/member/blog/single";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
art.alert(re.Msg || "error")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">{{msg . "baseInfoSet"}}</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<div id="formData">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="alert alert-danger" id="baseMsg" style="display: none"></div>
|
||||||
|
<div class="form-horizontal" role="form" id="userBlogForm">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="title" class="col-sm-2 control-label">{{msg . "blogName"}}</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" class="form-control" id="Title" name="Title"
|
||||||
|
placeholder="eg: leanote's blog"
|
||||||
|
value="{{if .userBlog.Title}}{{.userBlog.Title}}{{else}}{{.userInfo.Email}} 's blog{{end}}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="logo" class="col-sm-2 control-label">{{msg . "blogLogo"}}</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="hidden" name="Logo" id="Logo"
|
||||||
|
value="{{.userBlog.Logo}}" />
|
||||||
|
<form id="formLogo" action="{{$.siteUrl}}/file/uploadBlogLogo" method="post"
|
||||||
|
enctype="multipart/form-data" target="logoTarget">
|
||||||
|
<input type="file" class="form-control" id="logo2" name="file"
|
||||||
|
onChange='$("#formLogo").submit();' />
|
||||||
|
<div id="logoImg"
|
||||||
|
{{if .userBlog.Logo }}
|
||||||
|
{{else}}
|
||||||
|
style="display: none"{{end}}
|
||||||
|
>
|
||||||
|
<img src="{{.userBlog.Logo}}" style="height: 40px" /> <a
|
||||||
|
href="#" id="deleteLogo">{{msg . "delete"}}</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<iframe id="logoTarget" name="logoTarget" src="#" style="display: none"></iframe>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="subTitle" class="col-sm-2 control-label">{{msg . "blogDesc"}}</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" class="form-control" id="SubTitle"
|
||||||
|
name="SubTitle" value="{{.userBlog.SubTitle}}"
|
||||||
|
placeholder="eg: leanote, Not Just A Notebook">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="aboutMe" class="col-sm-2 control-label"></label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<div id="popularToolbar"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="aboutMe" class="col-sm-2 control-label">{{msg . "aboutMe"}}</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<textarea id="AboutMe" name="AboutMe">{{.userBlog.AboutMe}}</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
-->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="baseBtn" class="btn btn-success">{{msg . "submit"}}</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script type="text/javascript" src="/tinymce/tinymce.min.js"></script>
|
||||||
|
<script>
|
||||||
|
var urlPrefix = "{{.siteUrl}}";
|
||||||
|
$(function() {
|
||||||
|
$("#deleteLogo").click(function() {
|
||||||
|
$("#Logo").val("");
|
||||||
|
$("#logoImg").hide();
|
||||||
|
});
|
||||||
|
// 基本设置
|
||||||
|
$("#baseBtn").click(function() {
|
||||||
|
var data = {
|
||||||
|
Title : $("#Title").val(),
|
||||||
|
SubTitle : $("#SubTitle").val(),
|
||||||
|
Logo : $("#Logo").val()
|
||||||
|
}
|
||||||
|
post("/member/blog/setUserBlogBase", data, function(ret) {
|
||||||
|
showAlert("#baseMsg", "{{msg . "saveSuccess"}}", "success");
|
||||||
|
}, this);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// filename, result, resultCode
|
||||||
|
function uploadFinish(ret) {
|
||||||
|
if (ret) {
|
||||||
|
if (ret.resultCode == '1') {
|
||||||
|
$("#logoImg img").attr("src", urlPrefix + "/" + ret.filename).parent().show();
|
||||||
|
$("#Logo").val(ret.filename);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
alert(ret.result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 上传出错
|
||||||
|
alert("error");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">(笔记本)分类</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
分类是公开为博客的笔记本
|
||||||
|
<br />
|
||||||
|
拖动可排序
|
||||||
|
<ul class="list-group gutter list-group-lg list-group-sp sortable">
|
||||||
|
{{range .notebooks}}
|
||||||
|
<li class="list-group-item" draggable="true" data-id="{{.NotebookId.Hex}}">
|
||||||
|
<span class="pull-left media-xs"><i class="fa fa-sort text-muted fa m-r-sm"></i></span>
|
||||||
|
<div class="pull-right" style="margin-right: 10px">
|
||||||
|
固定链接: /cate/<input data-id="{{.NotebookId.Hex}}" class="url-title" type="text" value="{{if .UrlTitle}}{{.UrlTitle|decodeUrlValue}}{{else}}{{.NotebookId.Hex}}{{end}}"/>
|
||||||
|
</div>
|
||||||
|
{{.Title}}
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="baseBtn" class="btn btn-success">{{msg . "submit"}}</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script type="text/javascript" src="/public/member/js/jquery.sortable.js"></script>
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
$("#baseBtn").click(function(){
|
||||||
|
var ids = [];
|
||||||
|
$(".list-group-item").each(function() {
|
||||||
|
ids.push($(this).data("id"));
|
||||||
|
});
|
||||||
|
ajaxPost("/member/blog/", {cateIds: ids}, function(re){
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
art.tips("Success");
|
||||||
|
} else {
|
||||||
|
art.alert(re.Msg || "error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".url-title").change(function(){
|
||||||
|
var $t = $(this);
|
||||||
|
var url = $t.val();
|
||||||
|
var cateId = $t.data('id');
|
||||||
|
ajaxPost("/member/blog/updateCateUrlTitle", {cateId: cateId, urlTitle: url}, function(re){
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
$t.val(re.Item);
|
||||||
|
} else {
|
||||||
|
art.alert(re.Msg || "error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">{{msg . "commentSet"}}</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<div id="formData">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="alert alert-danger" id="baseMsg" style="display: none"></div>
|
||||||
|
<form class="form-horizontal" role="form">
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" id="CanComment" name="CanComment"
|
||||||
|
{{if .userBlog.CanComment}}checked="checked"{{end}} > {{msg . "openComment"}}
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<div id="commentSet" {{if not .userBlog.CanComment}}style="display: none"{{end}}>
|
||||||
|
<label>
|
||||||
|
<input type="radio"
|
||||||
|
name="commentType"
|
||||||
|
value="default"
|
||||||
|
{{if or (not .userBlog.CommentType) (eq .userBlog.CommentType "default")}}checked="checked"{{end}} > Default
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input type="radio" name="commentType" id="disqus"
|
||||||
|
value="disqus"
|
||||||
|
{{if eq .userBlog.CommentType "disqus"}}checked="checked"{{end}} > Disqus
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div id="disqusSet" {{if not (eq .userBlog.CommentType "disqus")}}style="display: none"{{end}}>
|
||||||
|
<label for="DisqusId">Disqus Id</label> <input type="text"
|
||||||
|
class="form-control" style="display: inline; width: 50%"
|
||||||
|
id="DisqusId" name="DisqusId"
|
||||||
|
value="{{if .userBlog.DisqusId}}{{.userBlog.DisqusId}}{{else}}leanote{{end}}">
|
||||||
|
<br />
|
||||||
|
{{msg . "disqusHelp"}}
|
||||||
|
<a target="_blank" href="http://leanote.com/blog/view/52db8463e01c530ef8000001">{{msg . "needHelp"}}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="baseBtn" class="btn btn-success">{{msg . "submit"}}</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script>
|
||||||
|
var urlPrefix = "{{.siteUrl}}";
|
||||||
|
$(function() {
|
||||||
|
// 评论
|
||||||
|
$("#baseBtn").click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var data = {
|
||||||
|
CanComment : $("#CanComment").is(":checked"),
|
||||||
|
CommentType: $("input[name='commentType']:checked").val(),
|
||||||
|
DisqusId : $("#DisqusId").val(),
|
||||||
|
}
|
||||||
|
post("/member/blog/setUserBlogComment", data, function(ret) {
|
||||||
|
showAlert("#baseMsg", "{{msg . "saveSuccess"}}", "success");
|
||||||
|
}, this);
|
||||||
|
});
|
||||||
|
$("#CanComment").click(function() {
|
||||||
|
if ($(this).is(":checked")) {
|
||||||
|
$("#commentSet").show();
|
||||||
|
} else {
|
||||||
|
$("#commentSet").hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("input[name='commentType']").click(function() {
|
||||||
|
if ($("input[name='commentType']:checked").val() == "disqus") {
|
||||||
|
$("#disqusSet").show();
|
||||||
|
} else {
|
||||||
|
$("#disqusSet").hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md"><h3 class="m-b-none">文章列表</h3></div>
|
||||||
|
<style>
|
||||||
|
.url-title {
|
||||||
|
width: 260px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="row wrapper">
|
||||||
|
<div class="col-sm-5 m-b-xs">
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4 m-b-xs">
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<div class="input-group search-group">
|
||||||
|
<input type="text" class="input-sm form-control" placeholder="Title" id="keywords" value="{{.keywords}}" />
|
||||||
|
<span class="input-group-btn">
|
||||||
|
<button class="btn btn-sm btn-default" type="button" data-url="/member/blog/index">Search</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped b-t b-light">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
{{$url := urlConcat "/member/blog/index" "keywords" .keywords}}
|
||||||
|
<th style="width: 300px"
|
||||||
|
{{sorterTh $url "title" .sorter}}
|
||||||
|
>
|
||||||
|
Title
|
||||||
|
<span class="th-sort">
|
||||||
|
<i class="fa fa-sort-down"></i>
|
||||||
|
<i class="fa fa-sort-up"></i>
|
||||||
|
<i class="fa fa-sort"></i>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th
|
||||||
|
style="width: 300px"
|
||||||
|
{{sorterTh $url "urlTitle" .sorter}}
|
||||||
|
>
|
||||||
|
固定链接
|
||||||
|
<span class="th-sort">
|
||||||
|
<i class="fa fa-sort-down"></i>
|
||||||
|
<i class="fa fa-sort-up"></i>
|
||||||
|
<i class="fa fa-sort"></i>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
{{sorterTh $url "publicTime" .sorter}}
|
||||||
|
>
|
||||||
|
发布日期
|
||||||
|
<span class="th-sort">
|
||||||
|
<i class="fa fa-sort-down"></i>
|
||||||
|
<i class="fa fa-sort-up"></i>
|
||||||
|
<i class="fa fa-sort"></i>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
|
||||||
|
<th
|
||||||
|
{{sorterTh $url "updatedTime" .sorter}}
|
||||||
|
>
|
||||||
|
更新日期
|
||||||
|
<span class="th-sort">
|
||||||
|
<i class="fa fa-sort-down"></i>
|
||||||
|
<i class="fa fa-sort-up"></i>
|
||||||
|
<i class="fa fa-sort"></i>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th
|
||||||
|
{{sorterTh $url "createdTime" .sorter}}
|
||||||
|
>
|
||||||
|
创建日期
|
||||||
|
<span class="th-sort">
|
||||||
|
<i class="fa fa-sort-down"></i>
|
||||||
|
<i class="fa fa-sort-up"></i>
|
||||||
|
<i class="fa fa-sort"></i>
|
||||||
|
</span>
|
||||||
|
</th>
|
||||||
|
<th width="30">
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{range .blogs}}
|
||||||
|
|
||||||
|
{{if .UrlTitle}}
|
||||||
|
{{set $ "urlTitle" (decodeUrlValue .UrlTitle)}}
|
||||||
|
{{else}}
|
||||||
|
{{set $ "urlTitle" .NoteId.Hex}}
|
||||||
|
{{end}}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="{{$.userAndBlog.PostUrl}}/{{$.urlTitle}}" class="post" target="_blank">{{.Title|raw}}</a>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
/post/
|
||||||
|
<input type="text" data-id="{{.NoteId.Hex}}" class="url-title" value="{{$.urlTitle}}"/>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
{{.PublicTime|datetime}}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td>
|
||||||
|
{{.UpdatedTime|datetime}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{.CreatedTime|datetime}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
<a
|
||||||
|
{{if .HasSelfDefined}}
|
||||||
|
title="已设置"
|
||||||
|
class="btn btn-sm btn-success"
|
||||||
|
{{else}}
|
||||||
|
title="未设置"
|
||||||
|
class="btn btn-sm btn-default"
|
||||||
|
{{end}}
|
||||||
|
href="/member/blog/updateBlogAbstract?noteId={{.NoteId.Hex}}">摘要设置</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-4 hidden-xs">
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4 text-center">
|
||||||
|
<small class="text-muted inline m-t-sm m-b-sm">
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-4 text-right text-center-xs">
|
||||||
|
{{set . "url" (urlConcat "/member/blog/index" "sorter" .sorter "keywords" .keywords)}}
|
||||||
|
{{template "member/blog/page.html" .}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
var postUrl="{{$.userAndBlog.PostUrl}}";
|
||||||
|
$(".url-title").change(function(){
|
||||||
|
var $t = $(this);
|
||||||
|
var url = $t.val();
|
||||||
|
var noteId = $t.data('id');
|
||||||
|
ajaxPost("/member/blog/updateBlogUrlTitle", {noteId: noteId, urlTitle: url}, function(re){
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
$t.val(re.Item);
|
||||||
|
var $a = $t.closest("tr").find(".post");
|
||||||
|
|
||||||
|
$a.attr("href", postUrl + "/" + encodeURI(re.Item));
|
||||||
|
} else {
|
||||||
|
art.alert(re.Msg || "error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
{{if gt .pageInfo.TotalPage 1}}
|
||||||
|
<ul class="pagination pagination-sm m-t-none m-b-none">
|
||||||
|
<li class="{{if eq $.pageInfo.CurPage 1}}disabled{{end}}" >
|
||||||
|
<a href="{{if eq $.pageInfo.CurPage 1}}javascript:;{{else}}{{sub $.pageInfo.CurPage | urlConcat $.url "page" }}{{end}}">
|
||||||
|
<i class="fa fa-chevron-left">
|
||||||
|
</i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
{{range $i := N 1 .pageInfo.TotalPage}}
|
||||||
|
{{if eq $i $.pageInfo.CurPage}}
|
||||||
|
<li class="active">
|
||||||
|
<a href="javascript:;">
|
||||||
|
{{$i}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{else}}
|
||||||
|
<li class="">
|
||||||
|
<a href="{{urlConcat $.url "page" $i}}">
|
||||||
|
{{$i}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<li class="{{if eq .pageInfo.CurPage .pageInfo.TotalPage}}disabled{{end}}" >
|
||||||
|
<a href="{{if eq .pageInfo.CurPage .pageInfo.TotalPage}}javascript:;{{else}}{{add $.pageInfo.CurPage | urlConcat $.url "page" }}{{end}}">
|
||||||
|
<i class="fa fa-chevron-right">
|
||||||
|
</i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{{end}}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">分页与排序设置</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<div id="formData">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="alert alert-danger" id="domainMsg" style="display: none"></div>
|
||||||
|
|
||||||
|
<form class="form-horizontal" role="form" id="dataFrom">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="perPageSize" class="col-sm-2 control-label">每页记录数</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" class="form-control"
|
||||||
|
placeholder="10"
|
||||||
|
id="perPageSize"
|
||||||
|
name="perPageSize"
|
||||||
|
value="{{.userBlog.PerPageSize}}" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="perPageSize" class="col-sm-2 control-label">排序字段</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<select class="form-control"
|
||||||
|
id="sortField"
|
||||||
|
name="sortField"
|
||||||
|
value="">
|
||||||
|
<option value="PublicTime" {{if eq $.userBlog.SortField "PublicTime"}}selected{{end}}>公开为博客时间</option>
|
||||||
|
<option value="CreatedTime" {{if eq $.userBlog.SortField "CreatedTimeTime"}}selected{{end}}>创建时间</option>
|
||||||
|
<option value="UpdatedTime" {{if eq $.userBlog.SortField "UpdatedTime"}}selected{{end}}>更新时间</option>
|
||||||
|
<option value="Title" {{if eq $.userBlog.SortField "Title"}}selected{{end}}>标题</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-2 control-label">排序类型</label>
|
||||||
|
<div class="col-sm-10" style="margin-top: 5px;">
|
||||||
|
<label><input type="radio" name="isAsc" value="0" {{if not .userBlog.IsAsc}}checked{{end}}> 降序</label>
|
||||||
|
<label><input type="radio" name="isAsc" value="1" {{if .userBlog.IsAsc}}checked{{end}}> 升序</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="baseBtn" class="btn btn-success">{{msg . "submit"}}</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script>
|
||||||
|
var urlPrefix = "{{.siteUrl}}";
|
||||||
|
$(function() {
|
||||||
|
// domain
|
||||||
|
$("#baseBtn").click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var data = $("#dataFrom").serialize();
|
||||||
|
post("/member/blog/setUserBlogPaging", data, function(re) {
|
||||||
|
if(re.Ok) {
|
||||||
|
showAlert("#domainMsg", "{{msg . "saveSuccess"}}", "success");
|
||||||
|
} else {
|
||||||
|
showAlert("#domainMsg", re.Msg, "danger");
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">页面</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<p>
|
||||||
|
您可以添加多个单页面
|
||||||
|
<a href="/member/blog/addOrUpdateSingle" id="addBtn" class="btn btn-success">添加页面</a>
|
||||||
|
</p>
|
||||||
|
<ul class="list-group gutter list-group-lg list-group-sp sortable">
|
||||||
|
{{range .singles}}
|
||||||
|
<li class="list-group-item" draggable="true" data-id="{{.SingleId}}">
|
||||||
|
<span class="pull-left media-xs"><i class="fa fa-sort text-muted fa m-r-sm"></i></span>
|
||||||
|
<span class="pull-right">
|
||||||
|
<a href="/member/blog/addOrUpdateSingle?singleId={{.SingleId}}"><i class="fa fa-pencil icon-muted fa-fw m-r-xs page-edit" data-id="{{.SingleId}}"></i></a>
|
||||||
|
<a href="#"><i class="fa fa-times icon-muted fa-fw page-delete" data-id="{{.SingleId}}"></i></a>
|
||||||
|
</span>
|
||||||
|
<div class="pull-right" style="margin-right: 10px">
|
||||||
|
固定链接: /single/<input data-id="{{.SingleId}}" class="url-title" type="text" value="{{if .UrlTitle}}{{.UrlTitle|decodeUrlValue}}{{else}}{{.SingleId}}{{end}}"/>
|
||||||
|
</div>
|
||||||
|
<div class="clear">
|
||||||
|
{{.Title}}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{{if .singles}}
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="baseBtn" class="btn btn-success">保存排序</button>
|
||||||
|
</footer>
|
||||||
|
{{end}}
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script type="text/javascript" src="{{.siteUrl}}/public/member/js/jquery.sortable.js"></script>
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
$("#baseBtn").click(function(){
|
||||||
|
var ids = [];
|
||||||
|
$(".list-group-item").each(function() {
|
||||||
|
ids.push($(this).data("id"));
|
||||||
|
});
|
||||||
|
ajaxPost("/member/blog/sortSingles", {singleIds: ids}, function(re){
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
art.tips("Success");
|
||||||
|
} else {
|
||||||
|
art.alert(re.Msg || "error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".page-delete").click(function() {
|
||||||
|
var singleId = $(this).data('id');
|
||||||
|
art.confirm("Are you sure ?", function() {
|
||||||
|
ajaxPost("/member/blog/deleteSingle", {singleId: singleId}, function(re){
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
art.tips("Success");
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
art.alert(re.Msg || "error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".url-title").change(function(){
|
||||||
|
var $t = $(this);
|
||||||
|
var url = $t.val();
|
||||||
|
var singleId = $t.data('id');
|
||||||
|
ajaxPost("/member/blog/updateSingleUrlTitle", {singleId: singleId, urlTitle: url}, function(re){
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
$t.val(re.Item);
|
||||||
|
} else {
|
||||||
|
art.alert(re.Msg || "error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,221 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md clearfix">
|
||||||
|
<h3 class="m-b-none">
|
||||||
|
{{msg . "themeSet"}}
|
||||||
|
<small>(<a href="http://blog.leanote.com/post/545f1a5c380782565e000000" target="_blank">{{msg . "needHelp"}}</a>)</small>
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12 theme-container">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div>
|
||||||
|
<form id="uploadAvatar" method="post" action="/member/blog/importTheme" enctype="multipart/form-data">
|
||||||
|
<div id="dropAvatar" class="dropzone">
|
||||||
|
<a class="btn btn-default btn-new" href="/member/blog/newTheme"><span class="fa fa-plus"></span> 新建主题</a>
|
||||||
|
<a class="btn btn-success btn-choose-file">
|
||||||
|
<span class="fa fa-upload"></span> 导入主题(.zip)
|
||||||
|
</a>
|
||||||
|
<input type="file" name="file" multiple/>
|
||||||
|
<div id="avatarUploadMsg"></div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
当前主题:
|
||||||
|
</p>
|
||||||
|
<ul class="themes">
|
||||||
|
<li class="theme">
|
||||||
|
<a class="choose-theme" data-method="put" href="#" rel="nofollow">
|
||||||
|
<div class="theme-thumb thumb active-theme">
|
||||||
|
<img src="/{{.activeTheme.Path}}/images/screenshot.png" alt="preview">
|
||||||
|
</div>
|
||||||
|
<span class="theme-title">{{.activeTheme.Name}}</span>
|
||||||
|
</a>
|
||||||
|
<span class="theme-author">
|
||||||
|
By: <a href="{{.activeTheme.AuthorUrl}}" target="_blank">{{.activeTheme.Author}}</a>
|
||||||
|
</span>
|
||||||
|
<div class="theme-btns">
|
||||||
|
<div class="btn-group" data-id="{{.activeTheme.ThemeId.Hex}}">
|
||||||
|
<a class="btn btn-default btn-sm btn-export"><span class="fa fa-download"></span> 导出</a>
|
||||||
|
<a class="btn btn-default btn-sm" href="{{$.siteUrl}}/preview?themeId={{.activeTheme.ThemeId.Hex}}" target="_blank"><span class="fa fa-eye"></span> 预览</a>
|
||||||
|
<a class="btn btn-primary btn-sm" target="_blank" href="/member/blog/updateTheme?themeId={{if .activeTheme.ThemeId}}{{.activeTheme.ThemeId.Hex}}{{end}}"><span class="fa fa-pencil"></span> 编辑</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
<p>
|
||||||
|
我的其它主题:
|
||||||
|
</p>
|
||||||
|
<ul class="themes">
|
||||||
|
{{range $.otherThemes}}
|
||||||
|
{{if .ThemeId}}
|
||||||
|
<li class="theme">
|
||||||
|
<a class="choose-theme" data-method="put" href="#" rel="nofollow">
|
||||||
|
<div class="theme-thumb thumb">
|
||||||
|
<img src="/{{.Path}}/images/screenshot.png" alt="preview">
|
||||||
|
</div>
|
||||||
|
<span class="theme-title">{{.Name}}</span>
|
||||||
|
</a>
|
||||||
|
<span class="theme-author">
|
||||||
|
By: <a href="{{.AuthorUrl}}" target="_blank">{{.Author}}</a>
|
||||||
|
</span>
|
||||||
|
<div class="theme-btns">
|
||||||
|
<div class="btn-group" data-id="{{.ThemeId.Hex}}">
|
||||||
|
<a class="btn btn-default btn-sm btn-delete" data-loading-text="..."><span class="fa fa-remove"></span> 删除</a>
|
||||||
|
<a class="btn btn-default btn-sm btn-export"><span class="fa fa-download"></span> 导出</a>
|
||||||
|
<a class="btn btn-default btn-sm" href="{{$.siteUrl}}/preview?themeId={{.ThemeId.Hex}}" target="_blank"><span class="fa fa-eye"></span> 预览</a>
|
||||||
|
<a class="btn btn-default btn-sm" target="_blank" href="/member/blog/updateTheme?themeId={{.ThemeId.Hex}}"><span class="fa fa-pencil"></span> 编辑</a>
|
||||||
|
<a class="btn btn-primary btn-sm btn-active" data-loading-text="..."><span class="fa fa-check"></span> 使用</a>
|
||||||
|
{{if $.isAdmin}}
|
||||||
|
<a class="btn btn-default btn-sm btn-public" data-loading-text="...">
|
||||||
|
{{if .IsDefault}}
|
||||||
|
公开
|
||||||
|
{{else}}
|
||||||
|
私有
|
||||||
|
{{end}}
|
||||||
|
</a>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
{{else}}
|
||||||
|
无
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
<p>
|
||||||
|
leanote主题市场:
|
||||||
|
</p>
|
||||||
|
<ul class="themes">
|
||||||
|
{{range $.optionThemes}}
|
||||||
|
<li class="theme">
|
||||||
|
<a class="choose-theme" data-method="put" href="#" rel="nofollow">
|
||||||
|
<div class="theme-thumb thumb">
|
||||||
|
<img src="/{{.Path}}/images/screenshot.png" alt="preview">
|
||||||
|
</div>
|
||||||
|
<span class="theme-title">{{.Name}}</span>
|
||||||
|
</a>
|
||||||
|
<span class="theme-author">
|
||||||
|
By: <a href="{{.AuthorUrl}}" target="_blank">{{.Author}}</a>
|
||||||
|
</span>
|
||||||
|
<p class="theme-btns" data-id="{{.ThemeId.Hex}}">
|
||||||
|
<a class="btn btn-primary btn-sm btn-install"><span class="fa fa-gear"></span> 安装</a>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script src="/js/require.js"></script>
|
||||||
|
<script>
|
||||||
|
var urlPrefix = "{{.siteUrl}}";
|
||||||
|
$(function() {
|
||||||
|
// 使用主题
|
||||||
|
$(".btn-active").click(function() {
|
||||||
|
var id = $(this).parent().data('id');
|
||||||
|
var t = $(this);
|
||||||
|
t.button("loading");
|
||||||
|
ajaxPost("/member/blog/activeTheme", {themeId: id}, function(re) {
|
||||||
|
t.button("reset");
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
art.tips("Success");
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
art.alert("Error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 导出主题
|
||||||
|
$(".btn-export").click(function() {
|
||||||
|
var id = $(this).parent().data('id');
|
||||||
|
var t = $(this);
|
||||||
|
window.open("/member/blog/exportTheme?themeId=" + id);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 删除主题
|
||||||
|
$(".btn-delete").click(function() {
|
||||||
|
var id = $(this).parent().data('id');
|
||||||
|
var t = $(this);
|
||||||
|
art.confirm("Are you sure ?", function() {
|
||||||
|
t.button("loading");
|
||||||
|
ajaxPost("/member/blog/deleteTheme", {themeId: id}, function(re) {
|
||||||
|
t.button("reset");
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
art.tips("Success");
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
art.alert("Error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 安装主题
|
||||||
|
$(".btn-install").click(function() {
|
||||||
|
var id = $(this).parent().data('id');
|
||||||
|
var t = $(this);
|
||||||
|
art.confirm("Are you sure ?", function() {
|
||||||
|
t.button("loading");
|
||||||
|
ajaxPost("/member/blog/installTheme", {themeId: id}, function(re) {
|
||||||
|
t.button("reset");
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
art.tips("Success");
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
art.alert("Error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
{{if .isAdmin}}
|
||||||
|
// 只有管理员才有公开主题
|
||||||
|
$(".btn-public").click(function() {
|
||||||
|
var id = $(this).parent().data('id');
|
||||||
|
var t = $(this);
|
||||||
|
art.confirm("Are you sure ?", function() {
|
||||||
|
t.button("loading");
|
||||||
|
ajaxPost("/member/blog/publicTheme", {themeId: id}, function(re) {
|
||||||
|
t.button("reset");
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
art.tips("Success");
|
||||||
|
location.reload();
|
||||||
|
} else {
|
||||||
|
art.alert("Error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// 导入主题
|
||||||
|
require.config({
|
||||||
|
baseUrl: '/public',
|
||||||
|
paths: {
|
||||||
|
'import_theme': 'js/app/import_theme',
|
||||||
|
'jquery.ui.widget': 'tinymce/plugins/leaui_image/public/js/jquery.ui.widget',
|
||||||
|
'fileupload': '/tinymce/plugins/leaui_image/public/js/jquery.fileupload',
|
||||||
|
'iframe-transport': '/tinymce/plugins/leaui_image/public/js/jquery.iframe-transport'
|
||||||
|
},
|
||||||
|
shim: {
|
||||||
|
'fileupload': {deps: ['jquery.ui.widget', 'iframe-transport']}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$(function() {
|
||||||
|
require(['import_theme'], function(import_theme) {});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.img-src {
|
||||||
|
max-height: 200px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">
|
||||||
|
{{.note.Title}} - 摘要设置
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/tinymce/skins/custom/skin.min.css" type="text/css">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<form id="formData">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
以下内容设置后, 以后修改笔记时将不自动获取. 若将该文章取消为博客后, 以下内容会自动获取.
|
||||||
|
<hr />
|
||||||
|
<div class="alert alert-danger" id="baseMsg" style="display: none"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>
|
||||||
|
主图片
|
||||||
|
<a class="btn btn-default btn-select-img">从笔记中自动获取下一张</a>
|
||||||
|
</label>
|
||||||
|
<div>
|
||||||
|
<img src="{{.note.ImgSrc}}" class="img-src" id="imgSrc"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>描述</label>
|
||||||
|
<textarea type="text" rows="6" class="form-control" id="desc" name="desc">{{.note.Desc}}</textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="content1">摘要</label>
|
||||||
|
<div id="popularToolbar"></div>
|
||||||
|
<textarea id="content1" name="content">{{.note.Abstract}}</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="submitBtn" class="btn btn-success">{{msg . "submit"}}</button>
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<div class="panel-body">
|
||||||
|
<p>
|
||||||
|
原文:
|
||||||
|
</p>
|
||||||
|
<div id="rawContent">
|
||||||
|
{{.note.Content|raw}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script type="text/javascript" src="/tinymce/tinymce.js"></script>
|
||||||
|
<script>
|
||||||
|
var UrlPrefix = "{{.siteUrl}}";
|
||||||
|
$(function() {
|
||||||
|
tinymce.init({
|
||||||
|
selector : "#content1",
|
||||||
|
content_css : [ "/css/bootstrap.css", "/css/editor/editor.css" ],
|
||||||
|
skin : "custom",
|
||||||
|
language : "{{.locale}}",
|
||||||
|
height : 300,
|
||||||
|
width : "100%",
|
||||||
|
skin : "custom",
|
||||||
|
plugins : [
|
||||||
|
"advlist autolink link leanote_image lists charmap hr ",
|
||||||
|
"searchreplace visualblocks visualchars leanote_code tabfocus",
|
||||||
|
"table contextmenu directionality textcolor paste fullpage textcolor"],
|
||||||
|
toolbar1 : "formatselect |fontselect fontsizeselect| forecolor backcolor | bold italic underline strikethrough | bullist numlist | leanote_code",
|
||||||
|
menubar : false,
|
||||||
|
statusbar : false,
|
||||||
|
font_formats : "Arial=arial,helvetica,sans-serif;"
|
||||||
|
+ "Arial Black=arial black,avant garde;"
|
||||||
|
+ "Times New Roman=times new roman,times;"
|
||||||
|
+ "Courier New=courier new,courier;"
|
||||||
|
+ "Tahoma=tahoma,arial,helvetica,sans-serif;"
|
||||||
|
+ "Verdana=verdana,geneva;" + "宋体=SimSun;"
|
||||||
|
+ "新宋体=NSimSun;" + "黑体=SimHei;"
|
||||||
|
+ "微软雅黑=Microsoft YaHei",
|
||||||
|
block_formats : "Header 1=h1;Header 2=h2;Header 3=h3; Header 4=h4;Pre=pre;Paragraph=p"
|
||||||
|
});
|
||||||
|
|
||||||
|
// 提交
|
||||||
|
$("#submitBtn").click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
var data = {
|
||||||
|
noteId: "{{.noteId}}",
|
||||||
|
imgSrc: $("#imgSrc").attr("src"),
|
||||||
|
desc : $("#desc").val(),
|
||||||
|
abstract : getEditorContent()
|
||||||
|
}
|
||||||
|
ajaxPost("/member/blog/doUpdateBlogAbstract/", data, function(re) {
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
art.tips("Success");
|
||||||
|
location.href = "/member/blog/index";
|
||||||
|
} else {
|
||||||
|
art.alert(re.Msg || "error")
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 选择主图
|
||||||
|
var $imgs = $("#rawContent").find("img");
|
||||||
|
var imgLen = $imgs.length;
|
||||||
|
var imgSeq = 0;
|
||||||
|
var $imgSrc = $("#imgSrc");
|
||||||
|
$(".btn-select-img").click(function() {
|
||||||
|
if(imgLen == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
imgSeq++;
|
||||||
|
imgSeq = imgSeq%imgLen;
|
||||||
|
$imgSrc.attr("src", $imgs.eq(imgSeq).attr("src"));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,334 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md">
|
||||||
|
<h3 class="m-b-none">
|
||||||
|
{{if .isNew}}
|
||||||
|
新建主题
|
||||||
|
{{else}}
|
||||||
|
编辑主题
|
||||||
|
-
|
||||||
|
{{.theme.Name}}
|
||||||
|
{{end}}
|
||||||
|
<a class="btn btn-default" href="{{$.siteUrl}}/preview?themeId={{.themeId}}" target="_blank"><span class="fa fa-eye"></span> 预览</a>
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#tplContent * {
|
||||||
|
font-family: Monaco, Menlo, 'Ubuntu Mono', Consolas, source-code-pro, monospace;
|
||||||
|
}
|
||||||
|
.image-list {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.image-list li {
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 5px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.image-list li .thumb {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
line-height: 100px;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
padding: 3px;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
.op {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<header class="panel-heading">
|
||||||
|
模板, 样式, 脚本:
|
||||||
|
</header>
|
||||||
|
<div class="panel-body" style="height:430px;overflow: auto;">
|
||||||
|
|
||||||
|
<div class="list-group bg-white file-list">
|
||||||
|
{{range .myTpls}}
|
||||||
|
<a href="#" class="list-group-item " data-file="{{.}}">
|
||||||
|
<i class="fa fa-remove icon-muted remove-file" title="delete file" ></i>
|
||||||
|
{{.}}
|
||||||
|
<span class="badge"></span>
|
||||||
|
</a>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<a class="btn btn-default" id="newFile">新建文件</a>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<header class="panel-heading">
|
||||||
|
当前文件: <span id="curTpl">header.html</span>
|
||||||
|
<span id="msg"></span>
|
||||||
|
</header>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div id="tplContent" class="form-control" style="width: 100%; height: 400px;"></div>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="saveBtn" class="btn btn-success">{{msg . "save"}}</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<header class="panel-heading">
|
||||||
|
图片: images/
|
||||||
|
</header>
|
||||||
|
<div class="panel-body">
|
||||||
|
<ul class="image-list" id="imageList">
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<form id="formLogo" action="/member/blog/uploadThemeImage" method="post"
|
||||||
|
enctype="multipart/form-data" target="logoTarget">
|
||||||
|
<input type="hidden" name="themeId" value="{{.themeId}}" />
|
||||||
|
<input type="file" class="form-control" id="logo2" name="file"
|
||||||
|
onChange='$("#formLogo").submit();' />
|
||||||
|
</form>
|
||||||
|
<iframe id="logoTarget" name="logoTarget" src="#" style="display: none"></iframe>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script src="/public/member/js/ace/ace.js" type="text/javascript"></script>
|
||||||
|
<script>
|
||||||
|
var editor = ace.edit("tplContent");
|
||||||
|
editor.setTheme("ace/theme/tomorrow");
|
||||||
|
|
||||||
|
var urlPrefix = "{{.siteUrl}}";
|
||||||
|
var userId = "{{.userInfo.UserId.Hex}}";
|
||||||
|
var themeId = "{{.themeId}}";
|
||||||
|
var themeBasePath = "/{{$.theme.Path}}";
|
||||||
|
var theme = {
|
||||||
|
cache: {}, // filename => content
|
||||||
|
curTplO: $("#curTpl"),
|
||||||
|
tplContentO: $("#tplContent"),
|
||||||
|
saveBtnO: $("#saveBtn"),
|
||||||
|
newFileO: $("#newFile"),
|
||||||
|
curTpl: "",
|
||||||
|
tplInfos: {"header.html": "头部", "footer.html": "底部", "index.html": "首页", "cate.html": "分类页", "search.html": "搜索页", "single.html": "单页", "archive.html": "归档页", "view.html": "详情页", "tags.html": "标签页", "tag_posts.html": "标签博客", "comment.html": "分享评论", "404.html":"404", "theme.json": "主题配置"},
|
||||||
|
init: function() {
|
||||||
|
var self = this;
|
||||||
|
self.showTplInfo();
|
||||||
|
$(".file-list").on("click", "a", function() {
|
||||||
|
$(".file-list a").removeClass("active");
|
||||||
|
var filename = $(this).data('file');
|
||||||
|
self.saveCurContent(); // 保存当前的
|
||||||
|
self.renderTpl(filename); // 再渲染
|
||||||
|
$(this).addClass("active");
|
||||||
|
});
|
||||||
|
|
||||||
|
self.renderTpl("header.html");
|
||||||
|
$(".file-list a").eq(0).addClass("active");
|
||||||
|
|
||||||
|
self.saveBtnO.click(function(){
|
||||||
|
self.saveCurContent($(this));
|
||||||
|
});
|
||||||
|
|
||||||
|
self.removeFile();
|
||||||
|
self.newFile();
|
||||||
|
|
||||||
|
self.initImage();
|
||||||
|
},
|
||||||
|
removeFile: function() {
|
||||||
|
var self = this;
|
||||||
|
$(".file-list").on("click", ".remove-file", function(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
var $a = $(this).closest("a");
|
||||||
|
var file = $a.data('file');
|
||||||
|
art.confirm("Are you sure to delete " + file + " ?", function() {
|
||||||
|
ajaxPost("/member/blog/deleteTpl", {themeId: themeId, filename: file}, function(re) {
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
art.tips("Success");
|
||||||
|
$a.remove();
|
||||||
|
if(self.curTpl == file) {
|
||||||
|
$(".file-list a").eq(0).trigger("click");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
art.alert(re.Msg);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
newFile: function() {
|
||||||
|
var self = this;
|
||||||
|
self.newFileO.click(function() {
|
||||||
|
art.prompt("文件名", function(file){
|
||||||
|
if(!file) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var t = '<a href="#" class="list-group-item " data-file="' + file + '"> <i class="fa fa-remove icon-muted remove-file" title="delete file" ></i> ' + file + '<span class="badge"></span></a>';
|
||||||
|
$(".file-list").append(t);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
showTplInfo: function() {
|
||||||
|
var self = this;
|
||||||
|
$(".file-list a").each(function() {
|
||||||
|
var file = $(this).data("file");
|
||||||
|
var info = "";
|
||||||
|
info = self.tplInfos[file];
|
||||||
|
if(!info) {
|
||||||
|
if(file.indexOf(".css") > 0) {
|
||||||
|
info = "样式";
|
||||||
|
} else if(file.indexOf(".js") > 0) {
|
||||||
|
info = "脚本";
|
||||||
|
} else if(file.indexOf(".html") > 0) {
|
||||||
|
info = "模板";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$(this).find(".remove-file").remove();
|
||||||
|
}
|
||||||
|
$(this).find(".badge").text(info);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
msgO: $("#msg"),
|
||||||
|
saveCurContent: function(t) {
|
||||||
|
var self = this;
|
||||||
|
var content = editor.getValue()
|
||||||
|
|
||||||
|
var filename = self.curTpl;
|
||||||
|
// 之前的内容是否有改动
|
||||||
|
if(self.cache[filename] == content) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(t) {
|
||||||
|
t.button("loading");
|
||||||
|
}
|
||||||
|
self.msgO.html("正在保存...");
|
||||||
|
ajaxPost("/member/blog/updateTplContent", {themeId: themeId, filename: self.curTpl, content: content}, function(re) {
|
||||||
|
if(t) {
|
||||||
|
t.button("reset");
|
||||||
|
}
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
self.cache[filename] = content;
|
||||||
|
// art.tips("Success");
|
||||||
|
self.msgO.html("保存成功")
|
||||||
|
setTimeout(function() {
|
||||||
|
self.msgO.html("");
|
||||||
|
}, 3000);
|
||||||
|
} else {
|
||||||
|
art.alert(re.Msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
renderContent: function(name, content) {
|
||||||
|
var self = this;
|
||||||
|
self.curTplO.html(name);
|
||||||
|
self.curTpl = name; // 这里设计
|
||||||
|
var lang = "html";
|
||||||
|
if(name.indexOf(".js") > 0 || name.indexOf(".json") > 0) {
|
||||||
|
lang = "javascript";
|
||||||
|
} else if(name.indexOf(".css") > 0) {
|
||||||
|
lang = "css";
|
||||||
|
}
|
||||||
|
editor.setValue(content);
|
||||||
|
editor.session.setMode("ace/mode/" + lang);
|
||||||
|
editor.gotoLine(1);
|
||||||
|
setTimeout(function() {
|
||||||
|
editor.gotoLine(1);
|
||||||
|
}, 200);
|
||||||
|
},
|
||||||
|
renderTpl: function(name) {
|
||||||
|
var self = this;
|
||||||
|
var content = "";
|
||||||
|
self.curTpl = name; // 这里设置
|
||||||
|
if(self.cache[name]) {
|
||||||
|
content = self.cache[name];
|
||||||
|
self.renderContent(name, content);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ajaxGet("/member/blog/getTplContent", {themeId: themeId, filename: name}, function(re){
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
self.cache[name] = re.Item;
|
||||||
|
self.renderContent(name, re.Item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//-----------------
|
||||||
|
// theme images
|
||||||
|
imageListO: $("#imageList"),
|
||||||
|
initImage: function() {
|
||||||
|
var self = this;
|
||||||
|
self.reRenderImages();
|
||||||
|
self.imageListO.on("click", ".delete-image", function(re) {
|
||||||
|
var file = $(this).data('image');
|
||||||
|
var t = this;
|
||||||
|
art.confirm("Are you sure to delete it " + file + " ?", function() {
|
||||||
|
ajaxPost("/member/blog/deleteThemeImage", {themeId: themeId, filename: file}, function(re) {
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
art.tips("Success");
|
||||||
|
$(t).closest("li").remove();
|
||||||
|
} else {
|
||||||
|
art.alert(re.Msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
renderImages: function(images) {
|
||||||
|
var self = this;
|
||||||
|
if(!images || images.length == 0) {
|
||||||
|
self.imageListO.html("无图片");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var html = "";
|
||||||
|
for(var i = 0; i < images.length; ++i) {
|
||||||
|
var image = images[i];
|
||||||
|
var path = themeBasePath + "/images/" + image;
|
||||||
|
|
||||||
|
html += '<li><div class="thumb"><img src="' + path + '"></div><div class="op"><span>' + image + '</span><br /><a class="btn btn-xs btn-warning delete-image" data-image="' + image + '"><span class="fa fa-remove"></span></a></div></li>';
|
||||||
|
}
|
||||||
|
self.imageListO.html(html);
|
||||||
|
},
|
||||||
|
reRenderImages: function() {
|
||||||
|
var self = this;
|
||||||
|
ajaxGet("/member/blog/listThemeImages", {themeId: themeId}, function(re) {
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
var images = re.List;
|
||||||
|
self.renderImages(images);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
$(function() {
|
||||||
|
theme.init();
|
||||||
|
$(window).keydown(function(e) {
|
||||||
|
if (e.keyCode == 83 && (e.ctrlKey || e.metaKey)) {
|
||||||
|
e.preventDefault();
|
||||||
|
theme.saveBtnO.trigger("click");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// filename, result, resultCode
|
||||||
|
function uploadFinish(ret) {
|
||||||
|
if (ret) {
|
||||||
|
if (ret.resultCode == '1') {
|
||||||
|
theme.reRenderImages();
|
||||||
|
art.tips(ret.result)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
art.alert(ret.result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 上传出错
|
||||||
|
art.alert("error");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<script src="/js/jquery-1.9.0.min.js"></script>
|
||||||
|
<script src="/js/bootstrap.js"></script>
|
||||||
|
<script src="/js/i18n/msg.{{.locale}}.js"></script>
|
||||||
|
<script src="/public/admin/js/artDialog/jquery.artDialog.js?skin=default"></script>
|
||||||
|
<script src="/public/js/common.js"></script>
|
||||||
|
<script src="/public/member/js/member.js"></script>
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
var pathname = location.pathname; // admin/t
|
||||||
|
var search = location.search; // ?t=xxx, 如果有?page呢
|
||||||
|
var fullPath = pathname;
|
||||||
|
if(search.indexOf("?t=") >= 0) {
|
||||||
|
var fullPath = pathname + search; // /admin/t?t=xxx
|
||||||
|
}
|
||||||
|
|
||||||
|
if(fullPath == "/member/index") {
|
||||||
|
fullPath = "/member";
|
||||||
|
}
|
||||||
|
$("#nav > li").removeClass("active");
|
||||||
|
// alert(fullPath);
|
||||||
|
// 自己
|
||||||
|
var $thisLi = $('#nav a[href="' + fullPath + '"]').parent();
|
||||||
|
$thisLi.addClass("active");
|
||||||
|
// 父也active
|
||||||
|
$thisLi.parent().parent().addClass('active');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,220 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<style>
|
||||||
|
.group-title {
|
||||||
|
color: #fff;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">项目/成员</h3></div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<a class="btn btn-default btn-add-group"><span class="fa fa-plus"></span> 新建分组</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<script type="text/x-jsrender" id="tUser">
|
||||||
|
<li class="list-group-item" data-id="[[:UserId]]">
|
||||||
|
[[:Username]] [[if Email != Username]]([[:Email]])[[/if]]
|
||||||
|
<span class="fa fa-remove pull-right text-xs m-t-sm"></span>
|
||||||
|
</li>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/x-jsrender" id="tGroup">
|
||||||
|
<div class="col-sm-4 each-group" data-id="[[:GroupId]]">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<header class="panel-heading bg-success lt no-border">
|
||||||
|
<div class="clearfix">
|
||||||
|
<div class="clear">
|
||||||
|
<div class="h3 m-t-xs m-b-xs text-white">
|
||||||
|
<input type="text" data-ever="[[:Title]]" value="[[:Title]]" class="group-title" />
|
||||||
|
<a title="删除分组" class="delete-group">
|
||||||
|
<i class="fa fa-remove text-white pull-right text-xs m-t-sm"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<ul class="list-group no-radius">
|
||||||
|
<li class="list-group-item">
|
||||||
|
<input type="text" class="add-user-input form-control" placeholder="输入用户名或邮箱添加成员" />
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="row" id="groups">
|
||||||
|
{{range .groups}}
|
||||||
|
<div class="col-sm-4 each-group" data-id="{{.GroupId.Hex}}">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<header class="panel-heading bg-success lt no-border">
|
||||||
|
<div class="clearfix">
|
||||||
|
<div class="clear">
|
||||||
|
<div class="h3 m-t-xs m-b-xs text-white">
|
||||||
|
<input type="text" data-ever="{{.Title}}" value="{{.Title}}" class="group-title" />
|
||||||
|
<a title="删除分组" class="delete-group">
|
||||||
|
<i class="fa fa-remove text-white pull-right text-xs m-t-sm"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<ul class="list-group no-radius group-users">
|
||||||
|
{{range .Users}}
|
||||||
|
<li class="list-group-item" data-id="{{.UserId.Hex}}">
|
||||||
|
{{.Username}} {{if not (eq .Email .Username)}}({{.Email}}){{end}}
|
||||||
|
<a title="删除成员" class="delete-user">
|
||||||
|
<span class="fa fa-remove pull-right text-xs m-t-sm"></span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
<li class="list-group-item">
|
||||||
|
<input type="text" class="add-user-input form-control" placeholder="输入用户名或邮箱添加成员" />
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script src="http://leanote.com/public/blog/js/jsrender.js"></script>
|
||||||
|
<script>
|
||||||
|
var group = {
|
||||||
|
tGroupO: $("#tGroup"),
|
||||||
|
groupsO: $("#groups"),
|
||||||
|
tUserO: $("#tUser"),
|
||||||
|
init: function() {
|
||||||
|
var self = this;
|
||||||
|
self.addGroupEvent();
|
||||||
|
self.updateGroupEvent();
|
||||||
|
self.deleteGroupEvent();
|
||||||
|
self.addUserEvent();
|
||||||
|
self.deleteUserEvent();
|
||||||
|
|
||||||
|
var classes = ["bg-warning", "bg-danger", "bg-success", "bg-dark", "bg-primary"];
|
||||||
|
var i = 0;
|
||||||
|
var len = classes.length;
|
||||||
|
$(".panel-heading").each(function() {
|
||||||
|
$(this).removeClass("bg-success").addClass(classes[i%len]);
|
||||||
|
i++;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 添加用户分组
|
||||||
|
addGroupEvent: function() {
|
||||||
|
var self = this;
|
||||||
|
$('.btn-add-group').click(function() {
|
||||||
|
ajaxPost("/member/group/addGroup", {title: "分组名"}, function(re) {
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
var group = re.Item;
|
||||||
|
self.groupsO.prepend(self.tGroupO.render(group))
|
||||||
|
self.groupsO.find(".group-title").eq(0).focus().select();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 修改
|
||||||
|
updateGroupEvent: function() {
|
||||||
|
var self = this;
|
||||||
|
self.groupsO.on("blur", ".group-title", function() {
|
||||||
|
var t = $(this);
|
||||||
|
var ever = t.data('ever');
|
||||||
|
var val = t.val();
|
||||||
|
if(ever == val) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log($(this).closest(".each-group"));
|
||||||
|
var groupId = $(this).closest(".each-group").data("id");
|
||||||
|
ajaxPost("/member/group/updateGroupTitle", {groupId: groupId, title: val}, function(re) {
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
art.tips("Success")
|
||||||
|
t.data('ever', val)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 删除分组
|
||||||
|
deleteGroupEvent: function() {
|
||||||
|
var self = this;
|
||||||
|
self.groupsO.on("click", ".delete-group", function() {
|
||||||
|
var t = $(this);
|
||||||
|
art.confirm("Are you sure ?", function() {
|
||||||
|
var groupId = t.closest(".each-group").data("id");
|
||||||
|
ajaxPost("/member/group/deleteGroup", {groupId: groupId}, function(re) {
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
art.tips("Success");
|
||||||
|
t.closest(".each-group").remove();
|
||||||
|
} else {
|
||||||
|
art.alert(re.Msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 添加好友分组
|
||||||
|
addUserEvent: function() {
|
||||||
|
var self = this;
|
||||||
|
self.groupsO.on("keydown", ".add-user-input", function(e) {
|
||||||
|
// enter
|
||||||
|
if (e.keyCode == 13) {
|
||||||
|
var t = $(this);
|
||||||
|
var email = t.val();
|
||||||
|
if(!email) {
|
||||||
|
t.focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否是合法的email
|
||||||
|
if(!isEmail(email)) {
|
||||||
|
// art.tips("非法的email");
|
||||||
|
// return;
|
||||||
|
}
|
||||||
|
var groupId = t.closest(".each-group").data("id");
|
||||||
|
var p = t.closest("li");
|
||||||
|
ajaxPost("/member/group/addUser", {groupId: groupId, email: email}, function(re) {
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
art.tips("Success");
|
||||||
|
var html = self.tUserO.render(re.Item)
|
||||||
|
p.before(html);
|
||||||
|
t.val("");
|
||||||
|
} else {
|
||||||
|
art.alert(re.Msg);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 删除用户
|
||||||
|
deleteUserEvent: function() {
|
||||||
|
var self = this;
|
||||||
|
self.groupsO.on("click", ".delete-user", function() {
|
||||||
|
var t = $(this);
|
||||||
|
art.confirm("Are you sure ?", function() {
|
||||||
|
var groupId = t.closest(".each-group").data("id");
|
||||||
|
var userId = t.closest("li").data("id");
|
||||||
|
ajaxPost("/member/group/deleteUser", {groupId: groupId, userId: userId}, function(re) {
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
art.tips("Success");
|
||||||
|
t.closest("li").remove();
|
||||||
|
} else {
|
||||||
|
art.alert(re.Msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
$(function() {
|
||||||
|
group.init();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">{{.userInfo.Username}}, 欢迎来到leanote</h3></div>
|
||||||
|
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="row m-l-none m-r-none bg-light lter">
|
||||||
|
<div class="col-sm-6 col-md-3 padder-v b-r b-light">
|
||||||
|
<span class="fa-stack fa-2x pull-left m-r-sm">
|
||||||
|
<i class="fa fa-circle fa-stack-2x text-warning"></i>
|
||||||
|
<i class="fa fa-file-o fa-stack-1x text-white"></i>
|
||||||
|
</span>
|
||||||
|
<a class="clear" href="javascript:;">
|
||||||
|
<span class="h3 block m-t-xs"><strong>{{.countNote}}</strong></span>
|
||||||
|
<small class="text-muted text-uc">{{msg . "note"}}</small>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-sm-6 col-md-3 padder-v b-r b-light">
|
||||||
|
<span class="fa-stack fa-2x pull-left m-r-sm">
|
||||||
|
<i class="fa fa-circle fa-stack-2x text-info"></i>
|
||||||
|
<i class="fa fa-bold fa-stack-1x text-white"></i>
|
||||||
|
</span>
|
||||||
|
<a class="clear" href="javascript:;">
|
||||||
|
<span class="h3 block m-t-xs"><strong>{{.countBlog}}</strong></span>
|
||||||
|
<small class="text-muted text-uc">{{msg . "blog"}}</small>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- 最新动态 -->
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<h4 class="font-thin padder">
|
||||||
|
Leanote 动态
|
||||||
|
</h4>
|
||||||
|
<ul class="list-group" id="eventsList"></ul>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<form>
|
||||||
|
<textarea class="form-control no-border" rows="3" placeholder="Suggestions to leanote"></textarea>
|
||||||
|
</form>
|
||||||
|
<footer class="panel-footer bg-light lter">
|
||||||
|
<button class="btn btn-info pull-right btn-sm">
|
||||||
|
POST
|
||||||
|
</button>
|
||||||
|
<ul class="nav nav-pills nav-sm">
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
-->
|
||||||
|
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
// leanote动态
|
||||||
|
var url = "https://leanote.com/blog/listCateLatest/5446753cfacfaa4f56000000";
|
||||||
|
function renderItem(item) {
|
||||||
|
return '<li class="list-group-item"><p><a target="_blank" href="http://leanote.com/blog/post/' + item.NoteId + '">' + item.Title + '</a></p><small class="block text-muted"><i class="fa fa-clock-o"></i> ' + goNowToDatetime(item.PublicTime) + '</small></li>';
|
||||||
|
}
|
||||||
|
$.ajax({
|
||||||
|
dataType: "jsonp",//跨域访问 dataType 必须是jsonp 类型。
|
||||||
|
url: url,
|
||||||
|
type: "GET",
|
||||||
|
jsonp: "callback",
|
||||||
|
jsonpCallback: "jsonpCallback",
|
||||||
|
success: function(data) {
|
||||||
|
if(typeof data == "object" && data.Ok) {
|
||||||
|
var list = data.List;
|
||||||
|
var html = "";
|
||||||
|
for(var i = 0; i < list.length; ++i) {
|
||||||
|
var item = list[i];
|
||||||
|
html += renderItem(item);
|
||||||
|
}
|
||||||
|
$("#eventsList").html(html);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
<nav class="nav-primary hidden-xs">
|
||||||
|
<ul class="nav" id="nav">
|
||||||
|
|
||||||
|
<li class="active">
|
||||||
|
<a href="/member">
|
||||||
|
<i class="fa fa-dashboard icon">
|
||||||
|
<b class="bg-success">
|
||||||
|
</b>
|
||||||
|
</i>
|
||||||
|
<span>
|
||||||
|
{{msg . "memberCenter"}}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<a href="#">
|
||||||
|
<i class="fa fa-user icon">
|
||||||
|
<b class="bg-danger">
|
||||||
|
</b>
|
||||||
|
</i>
|
||||||
|
<span class="pull-right">
|
||||||
|
<i class="fa fa-angle-down text">
|
||||||
|
</i>
|
||||||
|
<i class="fa fa-angle-up text-active">
|
||||||
|
</i>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
帐户信息
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<!-- 导航列表 -->
|
||||||
|
<ul class="nav lt">
|
||||||
|
{{if $.userInfo.Email}}
|
||||||
|
<li>
|
||||||
|
<a href="/member/user/username">
|
||||||
|
<span>
|
||||||
|
用户名
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/member/user/avatar">
|
||||||
|
<span>
|
||||||
|
头像
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/member/user/email">
|
||||||
|
<span>
|
||||||
|
邮箱
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/member/user/password">
|
||||||
|
<span>
|
||||||
|
密码
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{else}}
|
||||||
|
<li>
|
||||||
|
<a href="/member/user/add_account">
|
||||||
|
<span>
|
||||||
|
添加leanote帐户
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li id="adminEmailNav">
|
||||||
|
<a href="#layout">
|
||||||
|
<i class="fa fa-bold icon">
|
||||||
|
<b class="bg-warning">
|
||||||
|
</b>
|
||||||
|
</i>
|
||||||
|
<span class="pull-right">
|
||||||
|
<i class="fa fa-angle-down text">
|
||||||
|
</i>
|
||||||
|
<i class="fa fa-angle-up text-active">
|
||||||
|
</i>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
博客
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<ul class="nav lt">
|
||||||
|
<li>
|
||||||
|
<a href="/member/blog/index">
|
||||||
|
<span>
|
||||||
|
文章列表
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<a href="/member/blog/base">
|
||||||
|
<span>
|
||||||
|
基本信息
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/member/blog/comment">
|
||||||
|
<span>
|
||||||
|
评论
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/member/blog/cate">
|
||||||
|
<span>
|
||||||
|
分类
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/member/blog/single">
|
||||||
|
<span>
|
||||||
|
单页面
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/member/blog/paging">
|
||||||
|
<span>
|
||||||
|
分页与排序设置
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/member/blog/theme">
|
||||||
|
<span>
|
||||||
|
主题
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="active">
|
||||||
|
<a href="/member/group/index">
|
||||||
|
<i class="fa fa-users icon">
|
||||||
|
<b class="bg-success">
|
||||||
|
</b>
|
||||||
|
</i>
|
||||||
|
<span>
|
||||||
|
项目组/成员
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" class="app">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title>
|
||||||
|
{{.title}}
|
||||||
|
</title>
|
||||||
|
<meta name="description" content="leanote member center"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
|
||||||
|
<link href="/css/font-awesome-4.2.0/css/font-awesome.css" rel="stylesheet">
|
||||||
|
<link href="/public/admin/css/bootstrap.3.2.0.min.css" rel="stylesheet">
|
||||||
|
<link href="/public/member/css/member.css" rel="stylesheet">
|
||||||
|
<!--[if lt IE 9]>
|
||||||
|
<script src="/public/admin/js/ie/html5shiv.js"></script>
|
||||||
|
<script src="/public/admin/js/ie/respond.min.js"></script>
|
||||||
|
<script src="/public/admin/js/ie/excanvas.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
</head>
|
||||||
|
<body class="">
|
||||||
|
<section class="vbox">
|
||||||
|
<header class="bg-dark dk header navbar navbar-fixed-top-xs">
|
||||||
|
<div class="navbar-header aside-md" id="logo">
|
||||||
|
<a href="/member" class="navbar-brand clearfix" data-toggle="fullscreen">
|
||||||
|
<span class="logo-icon"></span>
|
||||||
|
<span class="logo-title">{{msg . "memberCenter"}}</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="nav navbar-nav navbar-right m-n hidden-xs nav-user">
|
||||||
|
<li class="hidden-xs">
|
||||||
|
<a href="http://lea.leanote.com" class="dk" target="_blank">
|
||||||
|
lea++
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="hidden-xs">
|
||||||
|
<a href="/note" class="dk" target="_blank">
|
||||||
|
{{msg . "myNote"}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="hidden-xs">
|
||||||
|
<a href="/blog/{{$.session.Username}}" class="dk" target="_blank">
|
||||||
|
{{msg . "myBlog"}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="hidden-xs">
|
||||||
|
<a href="/logout" class="dk">
|
||||||
|
{{msg . "logout"}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="hidden-xs">
|
||||||
|
<img alt="{{.userInfo.Username}}" title="{{.userInfo.Username}}" src="{{if .userInfo.Logo}}{{.userInfo.Logo}}{{else}}/images/blog/default_avatar.png{{end}}" id="myAvatar"/>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</header>
|
||||||
|
<section>
|
||||||
|
<section class="hbox stretch">
|
||||||
|
<!-- .aside -->
|
||||||
|
<aside class="bg-light lter b-r aside-md hidden-print hidden-xs" id="nav">
|
||||||
|
<section class="vbox">
|
||||||
|
<!--
|
||||||
|
<header class="header bg-primary lter text-center clearfix">
|
||||||
|
<div class="btn-group">
|
||||||
|
<div class="hidden-nav-xs">
|
||||||
|
<a class="btn btn-sm btn-primary">
|
||||||
|
Welcome, admin!
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<section class="w-f scrollable">
|
||||||
|
<div class="slim-scroll" data-height="auto" data-disable-fade-out="true"
|
||||||
|
data-distance="0" data-size="5px" data-color="#333333">
|
||||||
|
<!-- nav -->
|
||||||
|
{{template "member/nav.html" .}}
|
||||||
|
<!-- / nav -->
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<footer class="footer lt hidden-xs b-t b-light" style="min-height: initial;
|
||||||
|
padding: 10px 15px;text-align:center;">
|
||||||
|
<a href="http://leanote.com" target="_blank">leanote</a> © 2014
|
||||||
|
<!--
|
||||||
|
<a href="#nav" data-toggle="class:nav-xs" class="pull-right btn btn-sm btn-default btn-icon">
|
||||||
|
<i class="fa fa-angle-left text">
|
||||||
|
</i>
|
||||||
|
<i class="fa fa-angle-right text-active">
|
||||||
|
</i>
|
||||||
|
</a>
|
||||||
|
-->
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</aside>
|
||||||
|
<!-- /.aside -->
|
||||||
|
<section id="content">
|
||||||
|
<section class="vbox">
|
||||||
|
<section class="scrollable padder">
|
||||||
|
<!-- 导航
|
||||||
|
<ul class="breadcrumb no-border no-radius b-b b-light pull-in">
|
||||||
|
<li>
|
||||||
|
<a href="index.html">
|
||||||
|
<i class="fa fa-home">
|
||||||
|
</i>
|
||||||
|
Home
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#">
|
||||||
|
Elements
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="active">
|
||||||
|
Components
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
-->
|
||||||
|
<!-- 主要内容区 -->
|
||||||
|
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">用户名设置</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<form id="formData">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="alert alert-danger" id="thirdAccountMsg" style="display: none"></div>
|
||||||
|
{{msg . "thirdCreateAcountTips"}}
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label" for="thirdEmail">{{msg . "email"}}</label>
|
||||||
|
<input type="text" class="form-control" id="thirdEmail" name="email"
|
||||||
|
data-rules='[
|
||||||
|
{rule: "required", msg: "inputEmail"},
|
||||||
|
{rule: "email", msg: "errorEmail"}
|
||||||
|
]'
|
||||||
|
data-msg_target="#thirdAccountMsg"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label" for="thirdPwd">{{msg . "password"}}</label>
|
||||||
|
<input type="password" class="form-control" id="thirdPwd" name="pwd"
|
||||||
|
data-rules='[
|
||||||
|
{rule: "required", msg: "inputPassword"},
|
||||||
|
{rule: "password", msg: "errorPassword"}
|
||||||
|
]'
|
||||||
|
data-msg_target="#thirdAccountMsg"
|
||||||
|
/>
|
||||||
|
{{msg . "passwordTips"}}
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label" for="thirdPwd2">{{msg . "password2"}}</label>
|
||||||
|
<input type="password" class="form-control" id="thirdPwd2" name="pwd2"
|
||||||
|
data-rules='[
|
||||||
|
{rule: "required", msg: "inputPassword2"},
|
||||||
|
{rule: "equalTo", data:"#thirdPwd", msg: "confirmPassword"}
|
||||||
|
]'
|
||||||
|
data-msg_target="#thirdAccountMsg"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="accountBtn" class="btn btn-success">{{msg . "submit"}}</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
// 第三方账号设置
|
||||||
|
var acountVd = new vd.init("#formData");
|
||||||
|
$("#accountBtn").click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if(!acountVd.valid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var email = $("#thirdEmail").val();
|
||||||
|
var pwd = $("#thirdPwd").val();
|
||||||
|
var pwd2 = $("#thirdPwd2").val();
|
||||||
|
post("/user/addAccount", {email: email, pwd: pwd}, function(ret) {
|
||||||
|
if(ret.Ok) {
|
||||||
|
showAlert("#thirdAccountMsg", getMsg("createAccountSuccess"), "success");
|
||||||
|
setTimeout(function() {
|
||||||
|
location.reload();
|
||||||
|
}, 1000);
|
||||||
|
} else {
|
||||||
|
showAlert("#thirdAccountMsg", ret.Msg || getMsg("createAccountFailed"), "danger");
|
||||||
|
}
|
||||||
|
}, this);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">头像设置</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<form id="uploadAvatar" method="post" action="/file/uploadAvatar" enctype="multipart/form-data">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<div id="dropAvatar" class="dropzone">
|
||||||
|
<div>
|
||||||
|
<img src="{{if .userInfo.Logo}}{{.userInfo.Logo}}{{else}}/images/blog/default_avatar.png{{end}}" id="avatar"/>
|
||||||
|
</div>
|
||||||
|
<a class="btn btn-success btn-choose-file">
|
||||||
|
<span class="fa fa-upload"></span> Choose Image
|
||||||
|
</a>
|
||||||
|
<input type="file" name="file" multiple/>
|
||||||
|
</div>
|
||||||
|
<div id="avatarUploadMsg">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script src="/js/require.js"></script>
|
||||||
|
<script>
|
||||||
|
var UrlPrefix = "{{.siteUrl}}"; // 为了发weibo
|
||||||
|
var GlobalConfigs = {{.globalConfigs|jsonJs}}; // 2014/11/9 beta2
|
||||||
|
require.config({
|
||||||
|
baseUrl: '/public',
|
||||||
|
paths: {
|
||||||
|
// ajax upload image/attach
|
||||||
|
'attachment_upload': 'js/app/attachment_upload',
|
||||||
|
'jquery.ui.widget': 'tinymce/plugins/leaui_image/public/js/jquery.ui.widget',
|
||||||
|
'fileupload': '/tinymce/plugins/leaui_image/public/js/jquery.fileupload',
|
||||||
|
'iframe-transport': '/tinymce/plugins/leaui_image/public/js/jquery.iframe-transport'
|
||||||
|
},
|
||||||
|
shim: {
|
||||||
|
'fileupload': {deps: ['jquery.ui.widget', 'iframe-transport']}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$(function() {
|
||||||
|
require(['attachment_upload'], function(attachment_upload) {});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">邮箱设置</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<form id="formData">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
{{msg . "currentEmail" .userInfo.Email}}
|
||||||
|
<br />
|
||||||
|
{{if .userInfo.Verified}}
|
||||||
|
<span class="label label-green">{{msg . "verified"}}</span>
|
||||||
|
{{else}}
|
||||||
|
<span class="label label-red">{{msg . "unVerified"}}</span>
|
||||||
|
<a class="raw nowToActive">{{msg . "verifiedNow"}}</a>
|
||||||
|
{{msg . "or"}}
|
||||||
|
<a class="raw reSendActiveEmail">{{msg . "resendVerifiedEmail"}}</a>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<div class="alert alert-danger" id="emailMsg" style="display: none"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>{{msg . "email"}}</label>
|
||||||
|
<input type="text" class="form-control"
|
||||||
|
id="email"
|
||||||
|
data-rules='[
|
||||||
|
{rule: "required", msg: "inputEmail"},
|
||||||
|
{rule: "email", msg: "errorEmail"}
|
||||||
|
]'
|
||||||
|
data-msg_target="#emailMsg"
|
||||||
|
/>
|
||||||
|
{{msg . "updateEmailTips"}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="emailBtn" class="btn btn-success">{{msg . "submit"}}</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 激活邮件 -->
|
||||||
|
<div class="modal fade bs-modal-sm" id="reSendActiveEmailDialog" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-sm">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
|
<h4 class="modal-title" class="modalTitle">{{msg . "sendVerifiedEmail"}}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div style="max-height: 300px; padding: 5px 0; text-align: center; overflow-y: auto; overflow-x: hidden" class="weibo">
|
||||||
|
<span class="text">
|
||||||
|
<img src="/images/loading-24.gif"/>
|
||||||
|
{{msg . "emailInSending"}} {{.userInfo.Email}}...
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">{{msg . "close"}}</button>
|
||||||
|
<button type="button" class="btn btn-success viewEmailBtn disabled">{{msg . "checkEmail"}}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
// 修改邮箱
|
||||||
|
var emailVd = new vd.init("#formData");
|
||||||
|
$("#emailBtn").click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if(!emailVd.valid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var email = $("#email").val();
|
||||||
|
post("/user/updateEmailSendActiveEmail", {email: email}, function(e) {
|
||||||
|
if(e.Ok) {
|
||||||
|
var url = getEmailLoginAddress(email);
|
||||||
|
showAlert("#emailMsg", getMsg("verifiedEmaiHasSent") +" <a href='" + url + "' target='_blank'>" + getMsg("checkEmail") + "</a>", "success");
|
||||||
|
} else {
|
||||||
|
showAlert("#emailMsg", e.Msg || getMsg("emailSendFailed"), "danger");
|
||||||
|
}
|
||||||
|
}, "#emailBtn");
|
||||||
|
});
|
||||||
|
|
||||||
|
// 重新发送
|
||||||
|
$(".reSendActiveEmail").click(function() {
|
||||||
|
// 弹框出来
|
||||||
|
showDialog2("#reSendActiveEmailDialog", {postShow: function() {
|
||||||
|
ajaxGet("/user/reSendActiveEmail", {}, function(ret) {
|
||||||
|
if (typeof ret == "object" && ret.Ok) {
|
||||||
|
$("#reSendActiveEmailDialog .text").html(getMsg("sendSuccess"))
|
||||||
|
$("#reSendActiveEmailDialog .viewEmailBtn").removeClass("disabled");
|
||||||
|
$("#reSendActiveEmailDialog .viewEmailBtn").click(function() {
|
||||||
|
hideDialog();
|
||||||
|
var url = getEmailLoginAddress("{{.userInfo.Email}}");
|
||||||
|
window.open(url, "_blank");
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
$("#reSendActiveEmailDialog .text").html(getMsg("sendFailed"))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}});
|
||||||
|
});
|
||||||
|
// 现在去验证
|
||||||
|
$(".nowToActive").click(function() {
|
||||||
|
var url = getEmailLoginAddress("{{.userInfo.Email}}");
|
||||||
|
window.open(url, "_blank");
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">用户名设置</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<form id="formData">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="alert alert-danger" id="pwdMsg" style="display: none"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label" for="oldPwd">{{msg . "oldPassword"}}</label>
|
||||||
|
<input type="password" class="form-control" id="oldPwd" name="oldPwd"
|
||||||
|
data-rules='[
|
||||||
|
{rule: "required", msg: "inputPassword"}
|
||||||
|
]'
|
||||||
|
data-msg_target="#pwdMsg"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label" for="pwd">{{msg . "newPassword"}}</label>
|
||||||
|
<input type="password" class="form-control" id="pwd" name="pwd"
|
||||||
|
data-rules='[
|
||||||
|
{rule: "required", msg: "inputNewPassword"},
|
||||||
|
{rule: "password", msg: "errorPassword"}
|
||||||
|
]'
|
||||||
|
data-msg_target="#pwdMsg"
|
||||||
|
>
|
||||||
|
{{msg . "passwordTips"}}
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label" for="pwd2">{{msg . "password2"}}</label>
|
||||||
|
<input type="password" class="form-control" id="pwd2" name="pwd2"
|
||||||
|
data-rules='[
|
||||||
|
{rule: "required", msg: "inputPassword2"},
|
||||||
|
{rule: "equalTo", data:"#pwd", msg: "confirmPassword"}
|
||||||
|
]'
|
||||||
|
data-msg_target="#pwdMsg"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="pwdBtn" class="btn btn-success">{{msg . "submit"}}</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
// 修改密码
|
||||||
|
var updatePwdVd = new vd.init("#formData");
|
||||||
|
$("#pwdBtn").click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if(!updatePwdVd.valid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var oldPwd = $("#oldPwd").val();
|
||||||
|
var pwd = $("#pwd").val();
|
||||||
|
post("/user/updatePwd", {oldPwd: oldPwd, pwd: pwd}, function(e) {
|
||||||
|
if(e.Ok) {
|
||||||
|
showAlert("#pwdMsg", getMsg("updatePasswordSuccess"), "success");
|
||||||
|
} else {
|
||||||
|
showAlert("#pwdMsg", e.Msg, "danger");
|
||||||
|
}
|
||||||
|
}, "#pwdBtn");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
{{template "member/top.html" .}}
|
||||||
|
<div class="m-b-md"> <h3 class="m-b-none">用户名设置</h3></div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<form id="formData">
|
||||||
|
<section class="panel panel-default">
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="alert alert-danger" id="usernameMsg" style="display: none"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>{{msg . "username"}}</label>
|
||||||
|
<input type="text" class="form-control" id="username"
|
||||||
|
value="{{.userInfo.Username}}"
|
||||||
|
data-rules='[
|
||||||
|
{rule: "required", msg: "inputUsername"},
|
||||||
|
{rule: "noSpecialChars", msg: "noSpecialChars"},
|
||||||
|
{rule: "minLength", data: 4, msg: "minLength", msgData: 4}
|
||||||
|
]'
|
||||||
|
data-msg_target="#usernameMsg"
|
||||||
|
/>
|
||||||
|
{{msg . "setUsernameTips" .userInfo.Email}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<footer class="panel-footer text-right bg-light lter">
|
||||||
|
<button type="submit" id="usernameBtn" class="btn btn-success">{{msg . "submit"}}</button>
|
||||||
|
</footer>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{template "member/footer.html" .}}
|
||||||
|
<script>
|
||||||
|
$(function() {
|
||||||
|
//-------------
|
||||||
|
var usernameVd = new vd.init("#formData");
|
||||||
|
$("#usernameBtn").click(function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if(!usernameVd.valid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var username = $("#username").val();
|
||||||
|
post("/user/updateUsername", {username: username}, function(ret) {
|
||||||
|
if(ret.Ok) {
|
||||||
|
showAlert('#usernameMsg', getMsg("updateUsernameSuccess"), "success");
|
||||||
|
} else {
|
||||||
|
showAlert('#usernameMsg', ret.Msg || getMsg("usernameIsExisted"), "danger");
|
||||||
|
}
|
||||||
|
}, "#usernameBtn");
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{template "member/end.html" .}}
|
||||||
Whitespace-only changes.
@@ -136,30 +136,28 @@ function log(o) {
|
|||||||
<i class="fa fa-angle-down"></i>
|
<i class="fa fa-angle-down"></i>
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu li-a" role="menu">
|
<ul class="dropdown-menu li-a" role="menu">
|
||||||
<li role="presentation" id="setInfo">
|
<li role="presentation">
|
||||||
<a>
|
<a href="/member" target="_blank">
|
||||||
<i class="fa fa-info"></i>
|
<i class="fa fa-user"></i>
|
||||||
{{msg . "accountSetting"}}
|
{{msg . "memberCenter"}}
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li role="presentation" id="setAvatarMenu">
|
|
||||||
<a>
|
|
||||||
<i class="fa fa-smile-o"></i>
|
|
||||||
{{msg . "setAvatar"}}
|
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li role="presentation" id="setTheme">
|
<li role="presentation" id="setTheme">
|
||||||
<a>
|
<a>
|
||||||
<i class="fa fa-sun-o"></i>
|
<i class="fa fa-sun-o"></i>
|
||||||
{{msg . "themeSetting"}}
|
{{msg . "themeSetting"}}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<!--
|
|
||||||
<li role="presentation" id="yourSuggestions">
|
<li role="presentation" class="divider"></li>
|
||||||
<i class="fa fa-comment-o"></i>
|
<li role="presentation">
|
||||||
{{msg . "yourSuggestions"}}
|
<a href="/member/blog/index" target="_blank">
|
||||||
|
<i class="fa fa-bold"></i>
|
||||||
|
{{msg . "blogSet"}}
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
-->
|
|
||||||
<li role="presentation" class="my-link" >
|
<li role="presentation" class="my-link" >
|
||||||
<a target="_blank" href="{{$.blogUrl}}/{{.userInfo.Username}}">
|
<a target="_blank" href="{{$.blogUrl}}/{{.userInfo.Username}}">
|
||||||
<i class="fa fa-bold"></i>
|
<i class="fa fa-bold"></i>
|
||||||
@@ -843,6 +841,7 @@ var notes = json({{.notes}});
|
|||||||
var noteContentJson = json({{.noteContentJson}});
|
var noteContentJson = json({{.noteContentJson}});
|
||||||
var tagsJson = json({{.tagsJson}});
|
var tagsJson = json({{.tagsJson}});
|
||||||
LEA.locale = "{{.locale}}";
|
LEA.locale = "{{.locale}}";
|
||||||
|
var GlobalConfigs = {{.globalConfigs|jsonJs}}; // 2014/11/9 beta2
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- 渲染view -->
|
<!-- 渲染view -->
|
||||||
|
|||||||
+13
-15
@@ -136,30 +136,28 @@ function log(o) {
|
|||||||
<i class="fa fa-angle-down"></i>
|
<i class="fa fa-angle-down"></i>
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu li-a" role="menu">
|
<ul class="dropdown-menu li-a" role="menu">
|
||||||
<li role="presentation" id="setInfo">
|
<li role="presentation">
|
||||||
<a>
|
<a href="/member" target="_blank">
|
||||||
<i class="fa fa-info"></i>
|
<i class="fa fa-user"></i>
|
||||||
{{msg . "accountSetting"}}
|
{{msg . "memberCenter"}}
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li role="presentation" id="setAvatarMenu">
|
|
||||||
<a>
|
|
||||||
<i class="fa fa-smile-o"></i>
|
|
||||||
{{msg . "setAvatar"}}
|
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li role="presentation" id="setTheme">
|
<li role="presentation" id="setTheme">
|
||||||
<a>
|
<a>
|
||||||
<i class="fa fa-sun-o"></i>
|
<i class="fa fa-sun-o"></i>
|
||||||
{{msg . "themeSetting"}}
|
{{msg . "themeSetting"}}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<!--
|
|
||||||
<li role="presentation" id="yourSuggestions">
|
<li role="presentation" class="divider"></li>
|
||||||
<i class="fa fa-comment-o"></i>
|
<li role="presentation">
|
||||||
{{msg . "yourSuggestions"}}
|
<a href="/member/blog/base" target="_blank">
|
||||||
|
<i class="fa fa-bold"></i>
|
||||||
|
{{msg . "blogSet"}}
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
-->
|
|
||||||
<li role="presentation" class="my-link" >
|
<li role="presentation" class="my-link" >
|
||||||
<a target="_blank" href="{{$.blogUrl}}/{{.userInfo.Username}}">
|
<a target="_blank" href="{{$.blogUrl}}/{{.userInfo.Username}}">
|
||||||
<i class="fa fa-bold"></i>
|
<i class="fa fa-bold"></i>
|
||||||
|
|||||||
@@ -7,6 +7,13 @@
|
|||||||
{{$noteOrNotebookId := .noteOrNotebookId}}
|
{{$noteOrNotebookId := .noteOrNotebookId}}
|
||||||
|
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
|
<ul id="myTab" class="nav nav-tabs">
|
||||||
|
<li class="active"><a href="#baseInfo" data-toggle="tab">分享给好友</a></li>
|
||||||
|
<li class=""><a href="#groupInfo" data-toggle="tab">分享给项目组</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="tab-content">
|
||||||
|
<div class="tab-pane active" id="baseInfo">
|
||||||
<button class="btn btn-default" id="addShareNotebookBtn">{{msg . "addShare"}}</button>
|
<button class="btn btn-default" id="addShareNotebookBtn">{{msg . "addShare"}}</button>
|
||||||
<div id="shareMsg" class="alert alert-danger" style="display: none; margin: 5px 0 0 0;"></div>
|
<div id="shareMsg" class="alert alert-danger" style="display: none; margin: 5px 0 0 0;"></div>
|
||||||
<table class="table table-hover" id="shareNotebookTable">
|
<table class="table table-hover" id="shareNotebookTable">
|
||||||
@@ -29,7 +36,7 @@
|
|||||||
<label for="writePerm1"><input type="radio" name="perm1" value="1" id="writePerm1"> {{msg . "writable"}}</label>
|
<label for="writePerm1"><input type="radio" name="perm1" value="1" id="writePerm1"> {{msg . "writable"}}</label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<button class="btn btn-success" onclick="addShareNoteOrNotebook(1)">{{msg . "share"}}</button>
|
<button class="btn btn-success" data-loading-text="..." onclick="addShareNoteOrNotebook(1)">{{msg . "share"}}</button>
|
||||||
<button class="btn btn-warning" onclick="deleteShareNoteOrNotebook(1)">{{msg . "delete"}}</button>
|
<button class="btn btn-warning" onclick="deleteShareNoteOrNotebook(1)">{{msg . "delete"}}</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -40,18 +47,56 @@
|
|||||||
<td>{{$v.Email}}</td>
|
<td>{{$v.Email}}</td>
|
||||||
<td>
|
<td>
|
||||||
{{if eq $v.Perm 0}}
|
{{if eq $v.Perm 0}}
|
||||||
<a href="#" noteOrNotebookId="{{$noteOrNotebookId}}" perm="{{$v.Perm}}" toUserId="{{$toUserId}}" title="点击改变权限" class="btn btn-default change-perm">{{msg . "readOnly"}}</a>
|
<a href="#" noteOrNotebookId="{{$noteOrNotebookId}}" perm="{{$v.Perm}}" toUserId="{{$toUserId}}" title="点击改变权限" class="btn btn-default change-perm">{{msg $ "readOnly"}}</a>
|
||||||
{{else}}
|
{{else}}
|
||||||
<a href="#" noteOrNotebookId="{{$noteOrNotebookId}}" perm="{{$v.Perm}}" toUserId="{{$toUserId}}" title="点击改变权限" class="btn btn-default change-perm">{{msg . "writable"}}</a>
|
<a href="#" noteOrNotebookId="{{$noteOrNotebookId}}" perm="{{$v.Perm}}" toUserId="{{$toUserId}}" title="点击改变权限" class="btn btn-default change-perm">{{msg $ "writable"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="#" noteOrNotebookId="{{$noteOrNotebookId}}" toUserId="{{$toUserId}}" class="btn btn-warning delete-share">{{msg . "delete"}}</a>
|
<a href="#" noteOrNotebookId="{{$noteOrNotebookId}}" toUserId="{{$toUserId}}" class="btn btn-warning delete-share">{{msg $ "delete"}}</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{end}}
|
{{end}}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane" id="groupInfo">
|
||||||
|
<p>
|
||||||
|
将笔记/笔记本分享给项目组后, 该组下的用户便拥有了该笔记/笔记本. <a href="/member/group/index" target="_blank">项目组/成员管理</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>分组名</th>
|
||||||
|
<th>{{msg . "permission"}}</th>
|
||||||
|
<th width="150px">操作</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{{range $i, $share := .noteOrNotebookShareGroupInfos}}
|
||||||
|
{{$groupId := $share.ToGroup.GroupId.Hex}}
|
||||||
|
<tr data-id="{{$groupId}}" data-uid="{{$share.UserId.Hex}}">
|
||||||
|
<td>
|
||||||
|
{{$share.ToGroup.Title}}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<label><input type="radio" name="perm_{{$groupId}}" {{if not $share.Perm}}checked="checked"{{end}} value="0" class="group-perm"> {{msg $ "readOnly"}}</label>
|
||||||
|
<label><input type="radio" name="perm_{{$groupId}}" {{if $share.Perm}}checked="checked"{{end}} value="1" class="group-perm"> {{msg $ "writable"}}</label>
|
||||||
|
</td>
|
||||||
|
<td> <!-- 有userId 证明已分享 -->
|
||||||
|
{{if $share.UserId}}
|
||||||
|
<button class="btn btn-success btn-share-or-not">已分享</button>
|
||||||
|
{{else}}
|
||||||
|
<button class="btn btn-default btn-share-or-not">未分享</button>
|
||||||
|
{{end}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
@@ -64,8 +109,75 @@
|
|||||||
Share.dialogIsNote = {{.isNote}};
|
Share.dialogIsNote = {{.isNote}};
|
||||||
Share.dialogNoteOrNotebookId = '{{.noteOrNotebookId}}';
|
Share.dialogNoteOrNotebookId = '{{.noteOrNotebookId}}';
|
||||||
$(function() {
|
$(function() {
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
$("#tr1 #friendsEmail").focus();
|
$("#tr1 #friendsEmail").focus();
|
||||||
}, 500);
|
}, 500);
|
||||||
|
|
||||||
|
// 分享/删除给分组
|
||||||
|
$("#groupInfo").on("click", ".btn-share-or-not", function() {
|
||||||
|
var $t = $(this);
|
||||||
|
var $ptd = $t.closest("td");
|
||||||
|
var $ptr = $t.closest("tr");
|
||||||
|
var hasShared = $ptr.data('uid');
|
||||||
|
var groupId = $ptr.data('id');
|
||||||
|
var data = {groupId: groupId};
|
||||||
|
var url = "";
|
||||||
|
if(!hasShared) {
|
||||||
|
var perm = $ptr.find("input:checked").val();
|
||||||
|
data.perm = perm;
|
||||||
|
if(Share.dialogIsNote) {
|
||||||
|
data.noteId = Share.dialogNoteOrNotebookId;
|
||||||
|
url = "/share/addShareNoteGroup";
|
||||||
|
} else {
|
||||||
|
data.notebookId = Share.dialogNoteOrNotebookId;
|
||||||
|
url = "/share/addShareNotebookGroup";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(Share.dialogIsNote) {
|
||||||
|
data.noteId = Share.dialogNoteOrNotebookId;
|
||||||
|
url = "/share/deleteShareNoteGroup";
|
||||||
|
} else {
|
||||||
|
data.notebookId = Share.dialogNoteOrNotebookId;
|
||||||
|
url = "/share/deleteShareNotebookGroup";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ajaxPost(url, data, function(re) {
|
||||||
|
if(reIsOk(re)) {
|
||||||
|
if(!hasShared) {
|
||||||
|
var text = '<button class="btn btn-success btn-share-or-not">已分享</button>';
|
||||||
|
$ptr.data('uid', 'xxxxxx');
|
||||||
|
} else {
|
||||||
|
var text = '<button class="btn btn-default btn-share-or-not">未分享</button>';
|
||||||
|
$ptr.data('uid', '');
|
||||||
|
}
|
||||||
|
$ptd.html(text);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$(".group-perm").click(function() {
|
||||||
|
var $t = $(this);
|
||||||
|
var $ptr = $t.closest("tr");
|
||||||
|
var hasShared = $ptr.data('uid');
|
||||||
|
if(!hasShared) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var groupId = $ptr.data('id');
|
||||||
|
var data = {groupId: groupId, perm: $t.val()};
|
||||||
|
var url = ""
|
||||||
|
if(Share.dialogIsNote) {
|
||||||
|
data.noteId = Share.dialogNoteOrNotebookId;
|
||||||
|
url = "/share/updateShareNoteGroupPerm";
|
||||||
|
} else {
|
||||||
|
data.notebookId = Share.dialogNoteOrNotebookId;
|
||||||
|
url = "/share/updateShareNotebookGroupPerm";
|
||||||
|
}
|
||||||
|
ajaxPost(url, data, function(re) {
|
||||||
|
if(!reIsOk(re)) {
|
||||||
|
alert(re.Msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
<div class="modal-dialog modal-sm">
|
|
||||||
<div class="modal-content">
|
|
||||||
|
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
|
||||||
<h4 class="modal-title" id="modalTitle">{{.note.Title}} 的分享状态</h4>
|
|
||||||
</div>
|
|
||||||
{{$noteId := .note.NoteId.Hex}}
|
|
||||||
|
|
||||||
<div class="modal-body">
|
|
||||||
{{if .noteShareUserInfos }}
|
|
||||||
<table class="table table-hover">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>#</th>
|
|
||||||
<th>Email</th>
|
|
||||||
<th>权限</th>
|
|
||||||
<th>删除分享</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{{range $i, $v := .noteShareUserInfos}}
|
|
||||||
{{$toUserId := $v.ToUserId.Hex}}
|
|
||||||
<tr>
|
|
||||||
<td>{{add $i}}</td>
|
|
||||||
<td>{{$v.Email}}</td>
|
|
||||||
<td>
|
|
||||||
{{if eq $v.Perm 0}}
|
|
||||||
<a href="#" noteId="{{$noteId}}" perm="{{$v.Perm}}" toUserId="{{$toUserId}}" title="点击改变权限" class="btn btn-default change-perm">只读</a>
|
|
||||||
{{else}}
|
|
||||||
<a href="#" noteId="{{$noteId}}" perm="{{$v.Perm}}" toUserId="{{$toUserId}}" title="点击改变权限" class="btn btn-default change-perm">可编辑</a>
|
|
||||||
{{end}}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<a href="#" noteId="{{$noteId}}" toUserId="{{$toUserId}}" class="btn btn-warning delete-share">删除</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{{end}}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{{else}}
|
|
||||||
无分享信息
|
|
||||||
{{end}}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div><!-- /.modal-content -->
|
|
||||||
</div><!-- /.modal-dialog -->
|
|
||||||
<script>
|
|
||||||
$(function() {
|
|
||||||
$(".change-perm").click(function() {
|
|
||||||
var self = this;
|
|
||||||
var perm = $(this).attr("perm");
|
|
||||||
var noteId = $(this).attr("noteId");
|
|
||||||
var toUserId = $(this).attr("toUserId");
|
|
||||||
var toHtml = "可编辑";
|
|
||||||
var toPerm = "1";
|
|
||||||
if(perm == "1") {
|
|
||||||
toHtml = "只读";
|
|
||||||
toPerm = "0";
|
|
||||||
}
|
|
||||||
ajaxGet("/share/UpdateShareNotePerm", {noteId: noteId, perm: toPerm, toUserId: toUserId}, function(ret) {
|
|
||||||
if(ret) {
|
|
||||||
$(self).html(toHtml);
|
|
||||||
$(self).attr("perm", toPerm);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$(".delete-share").click(function() {
|
|
||||||
var self = this;
|
|
||||||
var noteId = $(this).attr("noteId");
|
|
||||||
var toUserId = $(this).attr("toUserId");
|
|
||||||
ajaxGet("/share/DeleteShareNote", {noteId: noteId, toUserId: toUserId}, function(ret) {
|
|
||||||
if(ret) {
|
|
||||||
$(self).parent().parent().remove();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
+65
-21
@@ -23,34 +23,75 @@ GET /findPassword Auth.FindPassword
|
|||||||
POST /doFindPassword Auth.DoFindPassword
|
POST /doFindPassword Auth.DoFindPassword
|
||||||
POST /findPasswordUpdate Auth.FindPasswordUpdate
|
POST /findPasswordUpdate Auth.FindPasswordUpdate
|
||||||
|
|
||||||
|
|
||||||
# blog
|
# blog
|
||||||
|
|
||||||
GET /blog/getLikeAndComments Blog.GetLikeAndComments
|
GET /blog/getLikesAndComments Blog.GetLikesAndComments
|
||||||
GET /blog/getLike Blog.GetLike
|
GET /blog/getLikes Blog.GetLikes
|
||||||
GET /blog/listLikes Blog.ListLikes
|
* /blog/incReadNum Blog.IncReadNum
|
||||||
GET /blog/incReadNum Blog.IncReadNum
|
* /blog/likePost Blog.LikePost
|
||||||
POST /blog/likeBlog Blog.LikeBlog
|
* /blog/likeComment Blog.LikeComment
|
||||||
POST /blog/likeComment Blog.LikeComment
|
* /blog/deleteComment Blog.DeleteComment
|
||||||
POST /blog/deleteComment Blog.DeleteComment
|
GET /blog/getComments Blog.GetComments
|
||||||
GET /blog/listComments Blog.ListComments
|
* /blog/commentPost Blog.CommentPost
|
||||||
POST /blog/comment Blog.Comment
|
GET /blog/getPostStat Blog.GetPostStat
|
||||||
GET /blog/ListComments Blog.ListComments
|
|
||||||
|
|
||||||
|
|
||||||
|
GET /blog/tags/:userIdOrEmail Blog.Tags
|
||||||
|
GET /blog/tags Blog.Tags
|
||||||
|
|
||||||
|
GET /blog/tag/:userIdOrEmail/:tag Blog.Tag
|
||||||
|
GET /blog/tag/:tag Blog.Tag
|
||||||
|
|
||||||
GET /blog/search/:userIdOrEmail Blog.Search
|
GET /blog/search/:userIdOrEmail Blog.Search
|
||||||
GET /blog/search Blog.Search
|
GET /blog/search Blog.Search
|
||||||
GET /blog/set Blog.Set
|
|
||||||
GET /blog/aboutMe/:userIdOrEmail Blog.AboutMe
|
GET /blog/archives/:userIdOrEmail Blog.Archives
|
||||||
GET /blog/aboutMe Blog.AboutMe
|
GET /blog/archives Blog.Archives
|
||||||
GET /blog/view/:noteId Blog.View
|
|
||||||
POST /blog/setUserBlogBase Blog.SetUserBlogBase
|
GET /blog/post/:noteId Blog.Post
|
||||||
POST /blog/setUserBlogComment Blog.SetUserBlogComment
|
GET /blog/post/:userIdOrEmail/:noteId Blog.Post
|
||||||
POST /blog/setUserBlogStyle Blog.SetUserBlogStyle
|
GET /blog/view/:noteId Blog.Post
|
||||||
|
|
||||||
|
GET /blog/single/:userIdOrEmail/:singleId Blog.Single
|
||||||
|
GET /blog/single/:singleId Blog.Single
|
||||||
|
|
||||||
GET /blog/cate/:notebookId Blog.Cate
|
GET /blog/cate/:notebookId Blog.Cate
|
||||||
|
GET /blog/cate/:userIdOrEmail/:notebookId Blog.Cate
|
||||||
|
|
||||||
GET /blog/listCateLatest/:notebookId Blog.ListCateLatest
|
GET /blog/listCateLatest/:notebookId Blog.ListCateLatest
|
||||||
GET /blog/isMe.js Blog.IsMe
|
|
||||||
GET /blog/:userIdOrEmail Blog.Index
|
GET /blog/:userIdOrEmail Blog.Index
|
||||||
GET /blog Blog.Index
|
GET /blog Blog.Index
|
||||||
|
GET /blog/* Blog.E()
|
||||||
|
|
||||||
|
|
||||||
|
#---------------
|
||||||
|
# preview
|
||||||
|
GET /preview/tags/:userIdOrEmail Preview.Tags
|
||||||
|
GET /preview/tags Preview.Tags
|
||||||
|
|
||||||
|
GET /preview/tag/:userIdOrEmail/:tag Preview.Tag
|
||||||
|
GET /preview/tag/:tag Preview.Tag
|
||||||
|
|
||||||
|
GET /preview/search/:userIdOrEmail Preview.Search
|
||||||
|
GET /preview/search Preview.Search
|
||||||
|
|
||||||
|
GET /preview/archives/:userIdOrEmail Preview.Archives
|
||||||
|
GET /preview/archives Preview.Archives
|
||||||
|
|
||||||
|
GET /preview/view/:noteId Preview.Post
|
||||||
|
|
||||||
|
GET /preview/post/:noteId Preview.Post
|
||||||
|
GET /preview/post/userIdOrEmail/:noteId Preview.Post
|
||||||
|
|
||||||
|
GET /preview/single/userIdOrEmail/:singleId Preview.Single
|
||||||
|
GET /preview/single/:singleId Preview.Single
|
||||||
|
|
||||||
|
GET /preview/cate/:notebookId Preview.Cate
|
||||||
|
GET /preview/cate/userIdOrEmail/:notebookId Preview.Cate
|
||||||
|
|
||||||
|
GET /preview/:userIdOrEmail Preview.Index
|
||||||
|
GET /preview Preview.Index
|
||||||
|
|
||||||
# Map static resources from the /app/public folder to the /public path
|
# Map static resources from the /app/public folder to the /public path
|
||||||
GET /favicon.ico Static.Serve("public/images/favicon.ico")
|
GET /favicon.ico Static.Serve("public/images/favicon.ico")
|
||||||
@@ -64,9 +105,12 @@ GET /tinymce/*filepath Static.Serve("public/tinymce")
|
|||||||
#GET /plugins/*filepath Static.Serve("public/tinymce/plugins")
|
#GET /plugins/*filepath Static.Serve("public/tinymce/plugins")
|
||||||
GET /upload/*filepath Static.Serve("public/upload")
|
GET /upload/*filepath Static.Serve("public/upload")
|
||||||
|
|
||||||
# API
|
# member
|
||||||
# the prefix of api's controllername is "Api"
|
# the prefix of member's controllername is "Member"
|
||||||
|
* /member MemberIndex.Index
|
||||||
|
* /member/index MemberIndex.Index
|
||||||
|
|
||||||
# common
|
# common
|
||||||
* /:controller/:action :controller.:action
|
* /:controller/:action :controller.:action
|
||||||
* /api/:controller/:action :controller.:action # 需要
|
* /api/:controller/:action :controller.:action
|
||||||
|
* /member/:controller/:action :controller.:action
|
||||||
@@ -59,6 +59,7 @@ hasAcount = Do not have an account?
|
|||||||
|
|
||||||
# 注册
|
# 注册
|
||||||
registerSuccessAndRdirectToNote=Register success, redirecting...
|
registerSuccessAndRdirectToNote=Register success, redirecting...
|
||||||
|
userHasBeenRegistered=%s has been registered
|
||||||
|
|
||||||
# 找回密码
|
# 找回密码
|
||||||
passwordTips=The length is at least 6
|
passwordTips=The length is at least 6
|
||||||
@@ -87,6 +88,7 @@ new=New
|
|||||||
newMarkdown=New markdown note
|
newMarkdown=New markdown note
|
||||||
clickAddTag=Click to add Tag
|
clickAddTag=Click to add Tag
|
||||||
notebook=Notebook
|
notebook=Notebook
|
||||||
|
note=Note
|
||||||
myNotebook=My notebook
|
myNotebook=My notebook
|
||||||
addNotebook=Add notebook
|
addNotebook=Add notebook
|
||||||
search=Search
|
search=Search
|
||||||
@@ -129,6 +131,7 @@ logout=Logout
|
|||||||
basicInfo=Basic
|
basicInfo=Basic
|
||||||
updateEmail=Update email
|
updateEmail=Update email
|
||||||
usernameSetting=Update username
|
usernameSetting=Update username
|
||||||
|
username=Username
|
||||||
oldPassword=Old password
|
oldPassword=Old password
|
||||||
newPassword=New password
|
newPassword=New password
|
||||||
admin=Admin
|
admin=Admin
|
||||||
@@ -222,17 +225,26 @@ inputPassword=Password is required
|
|||||||
inputNewPassword=The new password is required
|
inputNewPassword=The new password is required
|
||||||
inputPassword2=Please input the new password again
|
inputPassword2=Please input the new password again
|
||||||
errorPassword=The passowd's length is at least 6 and be sure as complex as possible
|
errorPassword=The passowd's length is at least 6 and be sure as complex as possible
|
||||||
|
oldPasswordError=The old password not match
|
||||||
confirmPassword=Password not matched
|
confirmPassword=Password not matched
|
||||||
updatePasswordSuccess=Update password success
|
updatePasswordSuccess=Update password success
|
||||||
errorDomain=The custom domain is invalid, eg. www.myblog.com
|
errorDomain=The custom domain is invalid, eg. www.myblog.com
|
||||||
domainExisted=Custom domain is already existed
|
domainExisted=Custom domain is already existed
|
||||||
errorSubDomain=Please input the valid sub domain, the length is at least 4 and no special chars
|
errorSubDomain=Please input the valid sub domain, the length is at least 4 and no special chars
|
||||||
subDomainExisted=Sub domain is already existed
|
subDomainExisted=Sub domain is already existed
|
||||||
|
domainNotPointToLeanote=The custom domin hasn't pointed to d.leanote.com
|
||||||
|
errorPerPageSize=Page size is error
|
||||||
|
errorSortField=Sort Field is error
|
||||||
|
|
||||||
# lea++
|
# lea++
|
||||||
leaDesc=leanote blog platform
|
leaDesc=leanote blog platform
|
||||||
recommend=Recommend
|
recommend=Recommend
|
||||||
latest=Latest
|
latest=Latest
|
||||||
|
|
||||||
|
# 用户中心
|
||||||
|
memberCenter=Member Center
|
||||||
|
userNotExists=该成员沿未注册
|
||||||
|
hasUsers=已存在该成员
|
||||||
|
|
||||||
# error
|
# error
|
||||||
notFound=This page cann't found.
|
notFound=This page cann't found.
|
||||||
+13
-1
@@ -79,6 +79,7 @@ hasAcount = 还无帐户?
|
|||||||
|
|
||||||
# 注册
|
# 注册
|
||||||
registerSuccessAndRdirectToNote=注册成功, 正在跳转...
|
registerSuccessAndRdirectToNote=注册成功, 正在跳转...
|
||||||
|
userHasBeenRegistered=%s已被注册
|
||||||
|
|
||||||
# 找回密码
|
# 找回密码
|
||||||
passwordTips=密码至少6位
|
passwordTips=密码至少6位
|
||||||
@@ -108,6 +109,7 @@ new=新建
|
|||||||
newMarkdown=新建Markdown笔记
|
newMarkdown=新建Markdown笔记
|
||||||
clickAddTag=点击添加标签
|
clickAddTag=点击添加标签
|
||||||
notebook=笔记本
|
notebook=笔记本
|
||||||
|
note=笔记
|
||||||
myNotebook=我的笔记本
|
myNotebook=我的笔记本
|
||||||
addNotebook=添加笔记本
|
addNotebook=添加笔记本
|
||||||
search=搜索
|
search=搜索
|
||||||
@@ -150,6 +152,7 @@ logout=退出
|
|||||||
basicInfo=基本信息
|
basicInfo=基本信息
|
||||||
updateEmail=修改Email
|
updateEmail=修改Email
|
||||||
usernameSetting=用户名设置
|
usernameSetting=用户名设置
|
||||||
|
username=用户名
|
||||||
oldPassword=旧密码
|
oldPassword=旧密码
|
||||||
newPassword=新密码
|
newPassword=新密码
|
||||||
admin=后台管理
|
admin=后台管理
|
||||||
@@ -248,17 +251,26 @@ inputPassword=请输入密码
|
|||||||
inputNewPassword=请输入新密码
|
inputNewPassword=请输入新密码
|
||||||
inputPassword2=请输入确认密码
|
inputPassword2=请输入确认密码
|
||||||
errorPassword=请输入长度不少于6位的密码, 尽量复杂
|
errorPassword=请输入长度不少于6位的密码, 尽量复杂
|
||||||
|
oldPasswordError=旧密码错误
|
||||||
confirmPassword=两次密码输入不正确
|
confirmPassword=两次密码输入不正确
|
||||||
updatePasswordSuccess=修改密码成功
|
updatePasswordSuccess=修改密码成功
|
||||||
errorDomain=请输入正确的域名, 如www.myblog.com
|
errorDomain=请输入正确的域名, 如www.myblog.com
|
||||||
domainExisted=域名已存在
|
domainExisted=域名已存在
|
||||||
errorSubDomain=请输入正确的博客子域名, 长度至少为4, 不能包含特殊字符
|
errorSubDomain=请输入正确的博客子域名, 长度至少为4, 不能包含特殊字符
|
||||||
subDomainExisted=博客子域名已存在
|
subDomainExisted=博客子域名已存在
|
||||||
|
domainNotPointToLeanote=该域名还未指向 d.leanote.com, 请稍后再试
|
||||||
|
errorPerPageSize=每页记录数至少为1
|
||||||
|
errorSortField=排序类型错误
|
||||||
|
|
||||||
# lea++
|
# lea++
|
||||||
leaDesc=leanote博客平台
|
leaDesc=leanote博客平台
|
||||||
recommend=推荐
|
recommend=推荐
|
||||||
latest=最新
|
latest=最新
|
||||||
|
|
||||||
|
# 用户中心
|
||||||
|
memberCenter=用户中心
|
||||||
|
userNotExists=该成员沿未注册
|
||||||
|
hasUsers=已存在该成员
|
||||||
|
|
||||||
# 必须要加这个, 奇怪
|
# 必须要加这个, 奇怪
|
||||||
[CN]
|
[CN]
|
||||||
@@ -1 +1 @@
|
|||||||
{ "indexes" : [ { "v" : 1, "key" : { "_id" : 1 }, "ns" : "leanote.albums", "name" : "_id_" } ] }
|
{ "indexes" : [ { "v" : 1, "key" : { "_id" : 1 }, "ns" : "leanote_beta2.albums", "name" : "_id_" } ] }
|
||||||
@@ -1 +1 @@
|
|||||||
{ "indexes" : [ { "v" : 1, "key" : { "_id" : 1 }, "ns" : "leanote.attachs", "name" : "_id_" } ] }
|
{ "indexes" : [ { "v" : 1, "key" : { "_id" : 1 }, "ns" : "leanote_beta2.attachs", "name" : "_id_" } ] }
|
||||||
@@ -1 +1 @@
|
|||||||
{ "indexes" : [ { "v" : 1, "key" : { "_id" : 1 }, "ns" : "leanote.blog_comments", "name" : "_id_" } ] }
|
{ "indexes" : [ { "v" : 1, "key" : { "_id" : 1 }, "ns" : "leanote_beta2.blog_comments", "name" : "_id_" } ] }
|
||||||
@@ -1 +1 @@
|
|||||||
{ "indexes" : [ { "v" : 1, "key" : { "_id" : 1 }, "ns" : "leanote.blog_likes", "name" : "_id_" } ] }
|
{ "indexes" : [ { "v" : 1, "key" : { "_id" : 1 }, "ns" : "leanote_beta2.blog_likes", "name" : "_id_" } ] }
|
||||||
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
{ "indexes" : [ { "v" : 1, "key" : { "_id" : 1 }, "ns" : "leanote_beta2.blog_singles", "name" : "_id_" } ] }
|
||||||
Loaded 100 of 518 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user