Merge branch 'feature-blog-theme'
This commit is contained in:
commit
4d7a9c8089
518 files changed
+25401
-751
No files matched your search
@@ -11,6 +11,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
"io"
|
||||
"fmt"
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
)
|
||||
@@ -56,8 +57,12 @@ func (c Attach) uploadAttach(noteId string) (re info.Re) {
|
||||
return re
|
||||
}
|
||||
// > 5M?
|
||||
if(len(data) > 5 * 1024 * 1024) {
|
||||
resultMsg = "File is bigger than 5M"
|
||||
maxFileSize := configService.GetUploadSize("uploadAttachSize");
|
||||
if maxFileSize <= 0 {
|
||||
maxFileSize = 1000
|
||||
}
|
||||
if(float64(len(data)) > maxFileSize * float64(1024*1024)) {
|
||||
resultMsg = fmt.Sprintf("附件大于%vM", maxFileSize)
|
||||
return re
|
||||
}
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@ func (c BaseController) SetLocale() string {
|
||||
lang = "en";
|
||||
}
|
||||
c.RenderArgs["locale"] = lang;
|
||||
c.RenderArgs["siteUrl"] = siteUrl;
|
||||
c.RenderArgs["siteUrl"] = configService.GetSiteUrl();
|
||||
|
||||
c.RenderArgs["blogUrl"] = configService.GetBlogUrl()
|
||||
c.RenderArgs["leaUrl"] = configService.GetLeaUrl()
|
||||
@@ -196,6 +196,9 @@ func (c BaseController) SetLocale() string {
|
||||
func (c BaseController) SetUserInfo() {
|
||||
userInfo := c.GetUserInfo()
|
||||
c.RenderArgs["userInfo"] = userInfo
|
||||
if(userInfo.Username == configService.GetAdminUsername()) {
|
||||
c.RenderArgs["isAdmin"] = true
|
||||
}
|
||||
}
|
||||
|
||||
// life
|
||||
|
||||
+641
-308
File diff suppressed because it is too large.
Load diff
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
@@ -21,7 +22,7 @@ type File struct {
|
||||
// 上传的是博客logo
|
||||
// TODO logo不要设置权限, 另外的目录
|
||||
func (c File) UploadBlogLogo() revel.Result {
|
||||
re := c.uploadImage("logo", "");
|
||||
re := c.uploadImage("blogLogo", "");
|
||||
|
||||
c.RenderArgs["fileUrlPath"] = re.Id
|
||||
c.RenderArgs["resultCode"] = re.Code
|
||||
@@ -100,7 +101,7 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
|
||||
}
|
||||
defer file.Close()
|
||||
// 生成上传路径
|
||||
if(from == "logo") {
|
||||
if(from == "logo" || from == "blogLogo") {
|
||||
fileUrlPath = "public/upload/" + c.GetUserId() + "/images/logo"
|
||||
} else {
|
||||
fileUrlPath = "files/" + c.GetUserId() + "/images"
|
||||
@@ -131,10 +132,22 @@ func (c File) uploadImage(from, albumId string) (re info.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?
|
||||
if(len(data) > 5 * 1024 * 1024) {
|
||||
if(float64(len(data)) > maxFileSize * float64(1024*1024)) {
|
||||
resultCode = 0
|
||||
resultMsg = "图片大于2M"
|
||||
resultMsg = fmt.Sprintf("图片大于%vM", maxFileSize)
|
||||
return re
|
||||
}
|
||||
|
||||
@@ -161,7 +174,7 @@ func (c File) uploadImage(from, albumId string) (re info.Re) {
|
||||
id := bson.NewObjectId();
|
||||
fileInfo.FileId = id
|
||||
fileId = id.Hex()
|
||||
if(from == "logo") {
|
||||
if(from == "logo" || from == "blogLogo") {
|
||||
fileId = "public/upload/" + c.GetUserId() + "/images/logo/" + filename
|
||||
}
|
||||
|
||||
@@ -303,7 +316,7 @@ func (c File) UploadImage(renderHtml string) revel.Result {
|
||||
|
||||
re := c.uploadImage("", "");
|
||||
|
||||
c.RenderArgs["fileUrlPath"] = siteUrl + re.Id
|
||||
c.RenderArgs["fileUrlPath"] = configService.GetSiteUrl() + re.Id
|
||||
c.RenderArgs["resultCode"] = re.Code
|
||||
c.RenderArgs["resultMsg"] = re.Msg
|
||||
|
||||
|
||||
@@ -14,6 +14,10 @@ type Index struct {
|
||||
|
||||
// leanote展示页, 没有登录的, 或已登录明确要进该页的
|
||||
func (c Index) Index() revel.Result {
|
||||
if configService.HomePageIsAdminsBlog(){
|
||||
blog := Blog{c.BaseController}
|
||||
return blog.Index(configService.GetAdminUsername());
|
||||
}
|
||||
c.SetUserInfo()
|
||||
c.RenderArgs["title"] = "leanote"
|
||||
c.RenderArgs["openRegister"] = configService.GlobalStringConfigs["openRegister"]
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"os/exec"
|
||||
// "time"
|
||||
// "github.com/leanote/leanote/app/types"
|
||||
// "io/ioutil"
|
||||
// "fmt"
|
||||
@@ -52,8 +53,9 @@ func (c Note) Index() revel.Result {
|
||||
}
|
||||
// 当然, 还需要得到第一个notes的content
|
||||
//...
|
||||
Log(configService.GetAdminUsername())
|
||||
c.RenderArgs["isAdmin"] = configService.GetAdminUsername() == userInfo.Username
|
||||
|
||||
c.RenderArgs["isAdmin"] = leanoteUserId == userInfo.Username
|
||||
c.RenderArgs["userInfo"] = userInfo
|
||||
c.RenderArgs["userInfoJson"] = c.Json(userInfo)
|
||||
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["globalConfigs"] = configService.GetGlobalConfigForUser()
|
||||
|
||||
if isDev, _ := revel.Config.Bool("mode.dev"); isDev {
|
||||
return c.RenderTemplate("note/note-dev.html")
|
||||
} else {
|
||||
@@ -121,7 +125,7 @@ func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result {
|
||||
// 新添加note
|
||||
if noteOrContent.IsNew {
|
||||
userId := c.GetObjectUserId();
|
||||
myUserId := userId
|
||||
// myUserId := userId
|
||||
// 为共享新建?
|
||||
if noteOrContent.FromUserId != "" {
|
||||
userId = bson.ObjectIdHex(noteOrContent.FromUserId)
|
||||
@@ -143,7 +147,7 @@ func (c Note) UpdateNoteOrContent(noteOrContent NoteOrContent) revel.Result {
|
||||
Content: noteOrContent.Content,
|
||||
Abstract: noteOrContent.Abstract};
|
||||
|
||||
note = noteService.AddNoteAndContent(note, noteContent, myUserId)
|
||||
note = noteService.AddNoteAndContentForController(note, noteContent, c.GetUserId())
|
||||
return c.RenderJson(note)
|
||||
}
|
||||
|
||||
@@ -296,7 +300,7 @@ func (c Note) Html2Image(noteId string) revel.Result {
|
||||
appKey, _ := revel.Config.String("app.secret")
|
||||
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
|
||||
binPath := configService.GetGlobalStringConfig("toImageBinPath")
|
||||
if binPath == "" {
|
||||
@@ -351,3 +355,9 @@ 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)
|
||||
}
|
||||
@@ -69,3 +69,9 @@ func (c Notebook) DragNotebooks(data string) revel.Result {
|
||||
|
||||
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"
|
||||
// "encoding/json"
|
||||
// "gopkg.in/mgo.v2/bson"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// "github.com/leanote/leanote/app/types"
|
||||
// "io/ioutil"
|
||||
@@ -87,6 +87,8 @@ func (c Share) ListNoteShareUserInfo(noteId string) revel.Result {
|
||||
noteShareUserInfos := shareService.ListNoteShareUserInfo(noteId, c.GetUserId())
|
||||
c.RenderArgs["noteOrNotebookShareUserInfos"] = noteShareUserInfos
|
||||
|
||||
c.RenderArgs["noteOrNotebookShareGroupInfos"] = shareService.GetNoteShareGroups(noteId, c.GetUserId())
|
||||
|
||||
c.RenderArgs["isNote"] = true
|
||||
c.RenderArgs["noteOrNotebookId"] = note.NoteId.Hex();
|
||||
c.RenderArgs["title"] = note.Title
|
||||
@@ -99,6 +101,9 @@ func (c Share) ListNotebookShareUserInfo(notebookId string) revel.Result {
|
||||
notebookShareUserInfos := shareService.ListNotebookShareUserInfo(notebookId, c.GetUserId())
|
||||
c.RenderArgs["noteOrNotebookShareUserInfos"] = notebookShareUserInfos
|
||||
|
||||
c.RenderArgs["noteOrNotebookShareGroupInfos"] = shareService.GetNotebookShareGroups(notebookId, c.GetUserId())
|
||||
LogJ(c.RenderArgs["noteOrNotebookShareGroupInfos"])
|
||||
|
||||
c.RenderArgs["isNote"] = false
|
||||
c.RenderArgs["noteOrNotebookId"] = notebook.NotebookId.Hex();
|
||||
c.RenderArgs["title"] = notebook.Title
|
||||
@@ -140,3 +145,44 @@ func (c Share) DeleteShareNotebookBySharedUser(notebookId string, fromUserId str
|
||||
func (c Share) DeleteUserShareNoteAndNotebook(fromUserId string) revel.Result {
|
||||
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 {
|
||||
pageNumber := c.GetPage()
|
||||
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["blogs"] = blogs
|
||||
c.RenderArgs["keywords"] = keywords
|
||||
|
||||
@@ -18,8 +18,8 @@ func (c Admin) Index() revel.Result {
|
||||
c.SetLocale()
|
||||
|
||||
c.RenderArgs["countUser"] = userService.CountUser()
|
||||
c.RenderArgs["countNote"] = noteService.CountNote()
|
||||
c.RenderArgs["countBlog"] = noteService.CountBlog()
|
||||
c.RenderArgs["countNote"] = noteService.CountNote("")
|
||||
c.RenderArgs["countBlog"] = noteService.CountBlog("")
|
||||
|
||||
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["map"] = configService.GlobalMapConfigs
|
||||
c.RenderArgs["arrMap"] = configService.GlobalArrMapConfigs
|
||||
c.RenderArgs["version"] = configService.GetVersion()
|
||||
return c.RenderTemplate("admin/" + t + ".html")
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"strings"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// admin 首页
|
||||
@@ -110,6 +111,15 @@ func (c AdminSetting) OpenRegister(openRegister string) revel.Result {
|
||||
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 {
|
||||
re := info.NewRe()
|
||||
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "mongodumpPath", mongodumpPath)
|
||||
@@ -117,3 +127,12 @@ func (c AdminSetting) Mongodb(mongodumpPath, mongorestorePath string) revel.Resu
|
||||
|
||||
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)
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package admin
|
||||
import (
|
||||
"github.com/revel/revel"
|
||||
// "encoding/json"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
// "io/ioutil"
|
||||
)
|
||||
|
||||
@@ -16,3 +16,9 @@ func (c AdminUpgrade) UpgradeBlog() revel.Result {
|
||||
upgradeService.UpgradeBlog()
|
||||
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 (
|
||||
"github.com/revel/revel"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
// "time"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
)
|
||||
|
||||
// admin 首页
|
||||
@@ -13,10 +15,13 @@ type AdminUser struct {
|
||||
|
||||
// admin 主页
|
||||
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()
|
||||
sorterField, isAsc := c.getSorter("CreatedTime", false, []string{"email", "username", "verified", "createdTime"});
|
||||
pageInfo, users := userService.ListUsers(pageNumber, userPageSize, sorterField, isAsc, keywords);
|
||||
if userPageSize == 0 {
|
||||
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["users"] = users
|
||||
c.RenderArgs["keywords"] = keywords
|
||||
@@ -26,3 +31,36 @@ func (c AdminUser) Index(sorter, keywords string) revel.Result {
|
||||
func (c AdminUser) Add() revel.Result {
|
||||
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 upgradeService *service.UpgradeService
|
||||
|
||||
var adminUsername = "admin"
|
||||
// 拦截器
|
||||
// 不需要拦截的url
|
||||
// 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 // 已登录
|
||||
}
|
||||
|
||||
|
||||
+17
-5
@@ -3,6 +3,7 @@ package controllers
|
||||
import (
|
||||
"github.com/leanote/leanote/app/service"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/lea/blog"
|
||||
// . "github.com/leanote/leanote/app/lea"
|
||||
"github.com/revel/revel"
|
||||
"strings"
|
||||
@@ -27,11 +28,10 @@ var attachService *service.AttachService
|
||||
var configService *service.ConfigService
|
||||
var emailService *service.EmailService
|
||||
var sessionService *service.SessionService
|
||||
var themeService *service.ThemeService
|
||||
|
||||
var pageSize = 1000
|
||||
var defaultSortField = "UpdatedTime"
|
||||
var leanoteUserId = "admin" // 不能更改
|
||||
var siteUrl = "http://leanote.com"
|
||||
|
||||
// 拦截器
|
||||
// 不需要拦截的url
|
||||
@@ -53,10 +53,14 @@ var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": tru
|
||||
"View": true,
|
||||
"AboutMe": true,
|
||||
"Cate": true,
|
||||
"ListCateLatest": true,
|
||||
"Search": true,
|
||||
"GetLikeAndComments": true,
|
||||
"IncReadNum": true,
|
||||
"ListComments": true,
|
||||
"Single": true,
|
||||
"Archive": true,
|
||||
"Tags": true,
|
||||
},
|
||||
// 用户的激活与修改邮箱都不需要登录, 通过链接地址
|
||||
"User": map[string]bool{"UpdateEmail": true,
|
||||
@@ -66,6 +70,7 @@ var commonUrl = map[string]map[string]bool{"Index": map[string]bool{"Index": tru
|
||||
"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 {
|
||||
@@ -76,7 +81,7 @@ func needValidate(controller, method string) bool {
|
||||
return true
|
||||
} else {
|
||||
// controller不在这里的, 肯定要验证
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
}
|
||||
func AuthInterceptor(c *revel.Controller) revel.Result {
|
||||
@@ -126,6 +131,12 @@ func InitService() {
|
||||
configService = service.ConfigS
|
||||
emailService = service.EmailS
|
||||
sessionService = service.SessionS
|
||||
themeService = service.ThemeS
|
||||
}
|
||||
|
||||
// 初始化博客模板
|
||||
// 博客模板不由revel的
|
||||
func initBlogTemplate() {
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -137,10 +148,11 @@ func init() {
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &User{})
|
||||
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &File{})
|
||||
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.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 @@
|
||||
包括基本信息设置
|
||||
博客设置
|
||||
+29
-5
@@ -2,9 +2,9 @@ package db
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/revel/revel"
|
||||
"gopkg.in/mgo.v2"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
"github.com/revel/revel"
|
||||
)
|
||||
|
||||
// Init mgo and the common DAO
|
||||
@@ -23,9 +23,12 @@ var ShareNotebooks *mgo.Collection
|
||||
var HasShareNotes *mgo.Collection
|
||||
var Blogs *mgo.Collection
|
||||
var Users *mgo.Collection
|
||||
var Groups *mgo.Collection
|
||||
var GroupUsers *mgo.Collection
|
||||
|
||||
var Tags *mgo.Collection
|
||||
var TagNotes *mgo.Collection
|
||||
//var TagNotes *mgo.Collection
|
||||
var TagCounts *mgo.Collection
|
||||
|
||||
var UserBlogs *mgo.Collection
|
||||
|
||||
@@ -46,6 +49,8 @@ var EmailLogs *mgo.Collection
|
||||
var BlogLikes *mgo.Collection
|
||||
var BlogComments *mgo.Collection
|
||||
var Reports *mgo.Collection
|
||||
var BlogSingles *mgo.Collection
|
||||
var Themes *mgo.Collection
|
||||
|
||||
// session
|
||||
var Sessions *mgo.Collection
|
||||
@@ -54,7 +59,7 @@ var Sessions *mgo.Collection
|
||||
func Init() {
|
||||
var url string
|
||||
var ok bool
|
||||
config := revel.Config;
|
||||
config := revel.Config
|
||||
url, ok = config.String("db.url")
|
||||
dbname, _ := config.String("db.dbname")
|
||||
if !ok {
|
||||
@@ -97,16 +102,22 @@ func Init() {
|
||||
|
||||
// user
|
||||
Users = Session.DB(dbname).C("users")
|
||||
// group
|
||||
Groups = Session.DB(dbname).C("groups")
|
||||
GroupUsers = Session.DB(dbname).C("group_users")
|
||||
|
||||
// blog
|
||||
Blogs = Session.DB(dbname).C("blogs")
|
||||
|
||||
// tag
|
||||
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
|
||||
UserBlogs = Session.DB(dbname).C("user_blogs")
|
||||
BlogSingles = Session.DB(dbname).C("blog_singles")
|
||||
Themes = Session.DB(dbname).C("themes")
|
||||
|
||||
// find password
|
||||
Tokens = Session.DB(dbname).C("tokens")
|
||||
@@ -179,17 +190,24 @@ func UpdateByIdAndUserIdField(collection *mgo.Collection, id, userId, field stri
|
||||
func UpdateByIdAndUserIdMap(collection *mgo.Collection, id, userId string, v bson.M) bool {
|
||||
return UpdateByIdAndUserId(collection, id, userId, bson.M{"$set": v})
|
||||
}
|
||||
|
||||
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}})
|
||||
}
|
||||
func UpdateByIdAndUserIdMap2(collection *mgo.Collection, id, userId bson.ObjectId, v bson.M) bool {
|
||||
return UpdateByIdAndUserId2(collection, id, userId, bson.M{"$set": v})
|
||||
}
|
||||
|
||||
//
|
||||
func UpdateByQField(collection *mgo.Collection, q interface{}, field string, value interface{}) bool {
|
||||
_, err := collection.UpdateAll(q, bson.M{"$set": bson.M{field: value}})
|
||||
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 {
|
||||
_, 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)
|
||||
}
|
||||
|
||||
// 查询某些字段, q是查询条件, fields是字段名列表
|
||||
func ListByQWithFields(collection *mgo.Collection, q bson.M, fields []string, i interface{}) {
|
||||
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)
|
||||
}
|
||||
|
||||
// 按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 {
|
||||
@@ -303,7 +327,7 @@ func Err(err error) bool {
|
||||
fmt.Println(err)
|
||||
// 删除时, 查找
|
||||
if err.Error() == "not found" {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
+46
-4
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
type BlogItem struct {
|
||||
Note
|
||||
Abstract string
|
||||
Content string // 可能是content的一部分, 截取. 点击more后就是整个信息了
|
||||
HasMore bool // 是否是否还有
|
||||
User User // 用户信息
|
||||
@@ -18,7 +19,7 @@ type UserBlogBase struct {
|
||||
Logo string `Logo`
|
||||
Title string `Title` // 标题
|
||||
SubTitle string `SubTitle` // 副标题
|
||||
AboutMe string `AboutMe` // 关于我
|
||||
// AboutMe string `AboutMe` // 关于我
|
||||
}
|
||||
|
||||
type UserBlogComment struct {
|
||||
@@ -38,7 +39,7 @@ type UserBlog struct {
|
||||
Logo string `Logo`
|
||||
Title string `Title` // 标题
|
||||
SubTitle string `SubTitle` // 副标题
|
||||
AboutMe string `AboutMe` // 关于我
|
||||
AboutMe string `AboutMe` // 关于我, 弃用
|
||||
|
||||
CanComment bool `CanComment` // 是否可以评论
|
||||
|
||||
@@ -48,8 +49,38 @@ type UserBlog struct {
|
||||
Style string `Style` // 风格
|
||||
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` // 二级域名
|
||||
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 {
|
||||
LikeId bson.ObjectId `bson:"_id"`
|
||||
LikeId bson.ObjectId `bson:"_id,omitempty"`
|
||||
NoteId bson.ObjectId `NoteId`
|
||||
UserId bson.ObjectId `UserId`
|
||||
CreatedTime time.Time `CreatedTime`
|
||||
@@ -65,7 +96,7 @@ type BlogLike struct {
|
||||
|
||||
// 评论
|
||||
type BlogComment struct {
|
||||
CommentId bson.ObjectId `bson:"_id"`
|
||||
CommentId bson.ObjectId `bson:"_id,omitempty"`
|
||||
NoteId bson.ObjectId `NoteId`
|
||||
|
||||
UserId bson.ObjectId `UserId` // UserId回复ToUserId
|
||||
@@ -84,3 +115,14 @@ type BlogCommentPublic struct {
|
||||
BlogComment
|
||||
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`
|
||||
}
|
||||
@@ -21,8 +21,10 @@ type Note struct {
|
||||
IsTrash bool `IsTrash` // 是否是trash, 默认是false
|
||||
|
||||
IsBlog bool `IsBlog,omitempty` // 是否设置成了blog 2013/12/29 新加
|
||||
UrlTitle string `UrlTitle,omitempty` // 博客的url标题, 为了更友好的url, 在UserId, UrlName下唯一
|
||||
IsRecommend bool `IsRecommend,omitempty` // 是否为推荐博客 2014/9/24新加
|
||||
IsTop bool `IsTop,omitempty` // blog是否置顶
|
||||
HasSelfDefined bool `HasSelfDefined` // 是否已经自定义博客图片, desc, abstract
|
||||
|
||||
// 2014/9/28 添加评论社交功能
|
||||
ReadNum int `ReadNum,omitempty` // 阅读次数 2014/9/28
|
||||
|
||||
@@ -13,6 +13,7 @@ type Notebook struct {
|
||||
ParentNotebookId bson.ObjectId `bson:"ParentNotebookId,omitempty"` // 上级
|
||||
Seq int `Seq` // 排序
|
||||
Title string `Title` // 标题
|
||||
UrlTitle string `UrlTitle` // Url标题 2014/11.11加
|
||||
NumberNotes int `NumberNotes` // 笔记数
|
||||
IsTrash bool `IsTrash,omitempty` // 是否是trash, 默认是false
|
||||
IsBlog bool `IsBlog,omitempty` // 是否是Blog 2013/12/29 新加
|
||||
|
||||
@@ -76,7 +76,9 @@ type SharingNotebookAndNotes struct {
|
||||
type ShareNotebook struct {
|
||||
ShareNotebookId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||
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"`
|
||||
Seq int `bson:"Seq"` // 排序
|
||||
Perm int `bson:"Perm"` // 权限, 其下所有notes 0只读, 1可修改
|
||||
@@ -134,7 +136,9 @@ type ShareNotebooksByUser struct {
|
||||
type ShareNote struct {
|
||||
ShareNoteId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||
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"`
|
||||
Perm int `bson:"Perm"` // 权限, 0只读, 1可修改
|
||||
CreatedTime time.Time `CreatedTime`
|
||||
|
||||
@@ -5,15 +5,38 @@ import (
|
||||
)
|
||||
|
||||
// 这里主要是为了统计每个tag的note数目
|
||||
// 暂时没用
|
||||
/*
|
||||
type TagNote struct {
|
||||
TagId bson.ObjectId `bson:"_id,omitempty"` // 必须要设置bson:"_id" 不然mgo不会认为是主键
|
||||
UserId bson.ObjectId `bson:"UserId"`
|
||||
Tag string `Title` // 标题
|
||||
NoteNum int `NoteNum` // note数目
|
||||
}
|
||||
*/
|
||||
|
||||
// 每个用户一条记录, 存储用户的所有tags
|
||||
type Tag struct {
|
||||
UserId bson.ObjectId `bson:"_id"`
|
||||
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, 在第三方中唯一可识别
|
||||
ThirdUsername string `ThirdUsername` // 第三方中username, 为了显示
|
||||
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 // 各个页面
|
||||
}
|
||||
+2
-1
@@ -9,6 +9,7 @@ import (
|
||||
type Page struct {
|
||||
CurPage int // 当前页码
|
||||
TotalPage int // 总页
|
||||
PerPageSize int
|
||||
Count int // 总记录数
|
||||
List interface{}
|
||||
}
|
||||
@@ -18,5 +19,5 @@ func NewPage(page, perPageSize, count int, list interface{}) Page {
|
||||
if count > 0 {
|
||||
totalPage = int(math.Ceil(float64(count) / float64(perPageSize)))
|
||||
}
|
||||
return Page{page, totalPage, count, list}
|
||||
return Page{page, totalPage, perPageSize, count, list}
|
||||
}
|
||||
+21
-2
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/leanote/leanote/app/db"
|
||||
"github.com/leanote/leanote/app/controllers"
|
||||
"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/session"
|
||||
"github.com/leanote/leanote/app/lea/memcache"
|
||||
@@ -19,6 +20,7 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -56,6 +58,11 @@ func init() {
|
||||
i = i - 1;
|
||||
return i
|
||||
}
|
||||
// 增加或减少
|
||||
revel.TemplateFuncs["incr"] = func(n, i int) int {
|
||||
n = n + i;
|
||||
return n
|
||||
}
|
||||
revel.TemplateFuncs["join"] = func(arr []string) template.HTML {
|
||||
if arr == nil {
|
||||
return template.HTML("")
|
||||
@@ -72,13 +79,24 @@ func init() {
|
||||
}
|
||||
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 {
|
||||
b, _ := json.Marshal(i)
|
||||
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 {
|
||||
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 {
|
||||
sec, _ := strconv.Atoi(unixSec)
|
||||
t := time.Unix(int64(sec), 0)
|
||||
@@ -135,8 +153,6 @@ func init() {
|
||||
}
|
||||
*/
|
||||
revel.TemplateFuncs["li"] = func(a string) string {
|
||||
Log(a)
|
||||
Log("life==")
|
||||
return ""
|
||||
}
|
||||
// str连接
|
||||
@@ -248,6 +264,7 @@ func init() {
|
||||
// https://groups.google.com/forum/#!topic/golang-nuts/OEdSDgEC7js
|
||||
// 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
|
||||
/*
|
||||
revel.TemplateFuncs["gt"] = func(a1, a2 interface{}) bool {
|
||||
switch a1.(type) {
|
||||
case string:
|
||||
@@ -273,6 +290,7 @@ func init() {
|
||||
}
|
||||
return false
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
{{range $i := N 1 10}}
|
||||
@@ -302,6 +320,7 @@ func init() {
|
||||
service.InitService()
|
||||
controllers.InitService()
|
||||
admin.InitService()
|
||||
member.InitService()
|
||||
service.ConfigS.InitGlobalConfigs()
|
||||
})
|
||||
}
|
||||
+97
-5
@@ -1,10 +1,11 @@
|
||||
package lea
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"path/filepath"
|
||||
"os"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 分离文件名与扩展名(包含.)
|
||||
@@ -14,7 +15,7 @@ func SplitFilename(filename string) (baseName, ext string) {
|
||||
ext = SubstringByte(filename, strings.LastIndex(filename, "."))
|
||||
baseName = strings.TrimRight(filename, ext)
|
||||
ext = strings.ToLower(ext)
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
// 转换文件的格式
|
||||
@@ -38,7 +39,7 @@ func GetFilesize(path string) int64 {
|
||||
if err == nil {
|
||||
return fileinfo.Size()
|
||||
}
|
||||
return 0;
|
||||
return 0
|
||||
}
|
||||
|
||||
// 清空dir下所有的文件和文件夹
|
||||
@@ -79,6 +80,55 @@ func CopyFile(srcName, dstName string) (written int64, err error) {
|
||||
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 {
|
||||
fi, err := os.Stat(path)
|
||||
if err != nil {
|
||||
@@ -88,3 +138,45 @@ func IsDirExists(path string) bool {
|
||||
}
|
||||
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": [
|
||||
{"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
|
||||
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) {
|
||||
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"
|
||||
"os"
|
||||
// "path/filepath"
|
||||
"net"
|
||||
"net/http"
|
||||
"io/ioutil"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
@@ -90,3 +91,12 @@ func trimQueryParams(url string) string {
|
||||
}
|
||||
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" {
|
||||
// api设置
|
||||
// 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
|
||||
} else if strings.HasPrefix(path, "/member") && !strings.HasPrefix(route.ControllerName, "Member") {
|
||||
// member设置
|
||||
route.ControllerName = "Member" + route.ControllerName
|
||||
}
|
||||
// end
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ func (this *AuthService) Login(emailOrUsername, pwd string) info.User {
|
||||
func (this *AuthService) Register(email, pwd string) (bool, string) {
|
||||
// 用户是否已存在
|
||||
if userService.IsExistsUser(email) {
|
||||
return false, email + " 已被注册"
|
||||
return false, "userHasBeenRegistered-" + email
|
||||
}
|
||||
user := info.User{UserId: bson.NewObjectId(), Email: email, Username: email, Pwd: Md5(pwd)}
|
||||
return this.register(user)
|
||||
@@ -90,7 +90,10 @@ func (this *AuthService) register(user info.User) (bool, string) {
|
||||
Title: user.Username + " 's Blog",
|
||||
SubTitle: "love leanote!",
|
||||
AboutMe: "Hello, I am (^_^)",
|
||||
CanComment: true,
|
||||
})
|
||||
// 添加一个单页面
|
||||
blogService.AddOrUpdateSingle(user.UserId.Hex(), "", "About Me", "Hello, I am (^_^)")
|
||||
}
|
||||
|
||||
return true, ""
|
||||
|
||||
+696
-54
@@ -1,12 +1,13 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/leanote/leanote/app/info"
|
||||
"github.com/leanote/leanote/app/db"
|
||||
"github.com/leanote/leanote/app/info"
|
||||
. "github.com/leanote/leanote/app/lea"
|
||||
"gopkg.in/mgo.v2/bson"
|
||||
// "time"
|
||||
// "sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@@ -30,10 +31,30 @@ note, notebook都可设为blog
|
||||
type BlogService struct {
|
||||
}
|
||||
|
||||
// 得到博客统计信息
|
||||
// ReadNum, LikeNum, CommentNum
|
||||
func (this *BlogService) GetBlogStat(noteId string) (stat info.BlogStat) {
|
||||
note := noteService.GetBlogNote(noteId)
|
||||
stat = info.BlogStat{note.NoteId, note.ReadNum, note.LikeNum, note.CommentNum}
|
||||
return
|
||||
}
|
||||
|
||||
// 通过id或urlTitle得到博客
|
||||
func (this *BlogService) GetBlogByIdAndUrlTitle(userId string, noteIdOrUrlTitle string) (blog info.BlogItem) {
|
||||
if IsObjectId(noteIdOrUrlTitle) {
|
||||
return this.GetBlog(noteIdOrUrlTitle)
|
||||
}
|
||||
note := info.Note{}
|
||||
db.GetByQ(db.Notes, bson.M{"UserId": bson.ObjectIdHex(userId), "UrlTitle": encodeValue(noteIdOrUrlTitle), "IsBlog": true, "IsTrash": false}, ¬e)
|
||||
return this.GetBlogItem(note)
|
||||
}
|
||||
|
||||
// 得到某博客具体信息
|
||||
func (this *BlogService) GetBlog(noteId string) (blog info.BlogItem) {
|
||||
note := noteService.GetBlogNote(noteId)
|
||||
|
||||
return this.GetBlogItem(note)
|
||||
}
|
||||
func (this *BlogService) GetBlogItem(note info.Note) (blog info.BlogItem) {
|
||||
if note.NoteId == "" || !note.IsBlog {
|
||||
return
|
||||
}
|
||||
@@ -42,7 +63,7 @@ func (this *BlogService) GetBlog(noteId string) (blog info.BlogItem) {
|
||||
noteContent := noteService.GetNoteContent(note.NoteId.Hex(), note.UserId.Hex())
|
||||
|
||||
// 组装成blogItem
|
||||
blog = info.BlogItem{note, noteContent.Content, false, info.User{}}
|
||||
blog = info.BlogItem{note, noteContent.Abstract, noteContent.Content, false, info.User{}}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -56,11 +77,11 @@ func (this *BlogService) ListBlogNotebooks(userId string) []info.Notebook {
|
||||
|
||||
// 博客列表
|
||||
// userId 表示谁的blog
|
||||
func (this *BlogService) ListBlogs(userId, notebookId string, page, pageSize int, sortField string, isAsc bool) (int, []info.BlogItem) {
|
||||
count, notes := noteService.ListNotes(userId, notebookId, false, page, pageSize, sortField, isAsc, true);
|
||||
func (this *BlogService) ListBlogs(userId, notebookId string, page, pageSize int, sortField string, isAsc bool) (info.Page, []info.BlogItem) {
|
||||
count, notes := noteService.ListNotes(userId, notebookId, false, page, pageSize, sortField, isAsc, true)
|
||||
|
||||
if(notes == nil || len(notes) == 0) {
|
||||
return 0, nil
|
||||
if notes == nil || len(notes) == 0 {
|
||||
return info.Page{}, nil
|
||||
}
|
||||
|
||||
// 得到content, 并且每个都要substring
|
||||
@@ -83,21 +104,212 @@ func (this *BlogService) ListBlogs(userId, notebookId string, page, pageSize int
|
||||
for i, note := range notes {
|
||||
hasMore := true
|
||||
var content string
|
||||
var abstract string
|
||||
if noteContent, ok := noteContentsMap[note.NoteId]; ok {
|
||||
content = noteContent.Abstract
|
||||
abstract = noteContent.Abstract
|
||||
content = noteContent.Content
|
||||
}
|
||||
blogs[i] = info.BlogItem{note, content, hasMore, info.User{}}
|
||||
}
|
||||
return count, blogs
|
||||
blogs[i] = info.BlogItem{note, abstract, content, hasMore, info.User{}}
|
||||
}
|
||||
|
||||
func (this *BlogService) SearchBlog(key, userId string, page, pageSize int, sortField string, isAsc bool) (int, []info.BlogItem) {
|
||||
count, notes := noteService.SearchNote(key, userId, page, pageSize, sortField, isAsc, true);
|
||||
pageInfo := info.NewPage(page, pageSize, count, nil)
|
||||
|
||||
if(notes == nil || len(notes) == 0) {
|
||||
return 0, nil
|
||||
return pageInfo, blogs
|
||||
}
|
||||
|
||||
// 得到博客的标签, 那得先得到所有博客, 比较慢
|
||||
/*
|
||||
[
|
||||
{Tag:xxx, Count: 32}
|
||||
]
|
||||
*/
|
||||
func (this *BlogService) GetBlogTags(userId string) []info.TagCount {
|
||||
// 得到所有博客
|
||||
tagCounts := []info.TagCount{}
|
||||
query := bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true}
|
||||
db.TagCounts.Find(query).Sort("-Count").All(&tagCounts)
|
||||
return tagCounts
|
||||
}
|
||||
|
||||
// 重新计算博客的标签
|
||||
// 在设置设置/取消为博客时调用
|
||||
func (this *BlogService) ReCountBlogTags(userId string) bool {
|
||||
// 得到所有博客
|
||||
notes := []info.Note{}
|
||||
userIdO := bson.ObjectIdHex(userId)
|
||||
query := bson.M{"UserId": userIdO, "IsTrash": false, "IsBlog": true}
|
||||
db.ListByQWithFields(db.Notes, query, []string{"Tags"}, ¬es)
|
||||
|
||||
db.DeleteAll(db.TagCounts, bson.M{"UserId": userIdO, "IsBlog": true})
|
||||
if notes == nil || len(notes) == 0 {
|
||||
return true
|
||||
}
|
||||
// 统计所有的Tags和数目
|
||||
tagsCount := map[string]int{}
|
||||
for _, note := range notes {
|
||||
tags := note.Tags
|
||||
if tags != nil && len(tags) > 0 {
|
||||
for _, tag := range tags {
|
||||
count := tagsCount[tag]
|
||||
count++
|
||||
tagsCount[tag] = count
|
||||
}
|
||||
}
|
||||
}
|
||||
// 一个个插入
|
||||
for tag, count := range tagsCount {
|
||||
db.Insert(db.TagCounts,
|
||||
info.TagCount{UserId: userIdO, IsBlog: true, Tag: tag, Count: count})
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 归档博客
|
||||
/*
|
||||
数据: 按年汇总
|
||||
[
|
||||
archive1,
|
||||
archive2,
|
||||
]
|
||||
archive的数据类型是
|
||||
{
|
||||
Year: 2014
|
||||
Posts: []
|
||||
}
|
||||
*/
|
||||
func (this *BlogService) ListBlogsArchive(userId, notebookId string, year, month int, sortField string, isAsc bool) []info.Archive {
|
||||
// _, notes := noteService.ListNotes(userId, notebookId, false, 1, 99999, sortField, isAsc, true);
|
||||
q := bson.M{"UserId": bson.ObjectIdHex(userId), "IsBlog": true, "IsTrash": false}
|
||||
if notebookId != "" {
|
||||
q["NotebookId"] = bson.ObjectIdHex(notebookId)
|
||||
}
|
||||
if year > 0 {
|
||||
now := time.Now()
|
||||
nextYear := year
|
||||
nextMonth := month
|
||||
if month == 0 {
|
||||
month = 1
|
||||
nextYear = year + 1
|
||||
nextMonth = month
|
||||
} else if month >= 12 {
|
||||
month = 12
|
||||
nextYear = year + 1
|
||||
nextMonth = 1
|
||||
} else { // month 在1-12之间
|
||||
nextMonth = month + 1
|
||||
}
|
||||
leftT := time.Date(year, time.Month(month), 1, 0, 0, 0, 0, now.Location())
|
||||
rightT := time.Date(nextYear, time.Month(nextMonth), 1, 0, 0, 0, 0, now.Location())
|
||||
if sortField == "CreatedTime" || sortField == "UpdatedTime" {
|
||||
q[sortField] = bson.M{"$gte": leftT, "$lt": rightT}
|
||||
} else {
|
||||
q["PublicTime"] = bson.M{"$gte": leftT, "$lt": rightT}
|
||||
}
|
||||
}
|
||||
|
||||
sorter := sortField
|
||||
if !isAsc {
|
||||
sorter = "-" + sortField
|
||||
}
|
||||
notes := []info.Note{}
|
||||
db.Notes.Find(q).Sort(sorter).All(¬es)
|
||||
|
||||
if notes == nil || len(notes) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
arcs := []info.Archive{}
|
||||
// 按年汇总
|
||||
arcsMap := map[int]info.Archive{}
|
||||
// 按月汇总
|
||||
arcsMonth := []info.ArchiveMonth{}
|
||||
var t time.Time
|
||||
var arc info.Archive
|
||||
everYear := 0
|
||||
for _, note := range notes {
|
||||
if sortField == "PublicTime" {
|
||||
t = note.PublicTime
|
||||
} else if sortField == "CreatedTime" {
|
||||
t = note.CreatedTime
|
||||
} else {
|
||||
t = note.UpdatedTime
|
||||
}
|
||||
year := t.Year()
|
||||
month := int(t.Month())
|
||||
if everYear == 0 {
|
||||
everYear = year
|
||||
}
|
||||
|
||||
if everYear != year {
|
||||
yearArc := arcsMap[everYear]
|
||||
yearArc.MonthAchives = arcsMonth
|
||||
arcs = append(arcs, yearArc)
|
||||
everYear = year
|
||||
|
||||
// 新的一年
|
||||
arcsMonth = []info.ArchiveMonth{}
|
||||
}
|
||||
|
||||
if arcT, ok := arcsMap[year]; ok {
|
||||
arc = arcT
|
||||
} else {
|
||||
arc = info.Archive{Year: year, Posts: []*info.Post{}}
|
||||
}
|
||||
|
||||
pt := this.FixNote(note)
|
||||
p := &pt
|
||||
arc.Posts = append(arc.Posts, p)
|
||||
arcsMap[year] = arc
|
||||
|
||||
// month
|
||||
lm := len(arcsMonth)
|
||||
if lm == 0 || arcsMonth[lm-1].Month != month {
|
||||
arcsMonth = append(arcsMonth, info.ArchiveMonth{month, []*info.Post{p}})
|
||||
} else {
|
||||
arcsMonth[lm-1].Posts = append(arcsMonth[lm-1].Posts, p)
|
||||
}
|
||||
}
|
||||
// 最后一个
|
||||
if everYear > 0 {
|
||||
yearArc := arcsMap[everYear]
|
||||
yearArc.MonthAchives = arcsMonth
|
||||
arcs = append(arcs, yearArc)
|
||||
}
|
||||
|
||||
return arcs
|
||||
}
|
||||
|
||||
// 根据tag搜索博客
|
||||
func (this *BlogService) SearchBlogByTags(tags []string, userId string, pageNumber, pageSize int, sortField string, isAsc bool) (pageInfo info.Page, blogs []info.BlogItem) {
|
||||
notes := []info.Note{}
|
||||
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
||||
|
||||
// 不是trash的
|
||||
query := bson.M{"UserId": bson.ObjectIdHex(userId),
|
||||
"IsTrash": false,
|
||||
"IsBlog": true,
|
||||
"Tags": bson.M{"$all": tags}}
|
||||
|
||||
q := db.Notes.Find(query)
|
||||
|
||||
// 总记录数
|
||||
count, _ := q.Count()
|
||||
if count == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
q.Sort(sortFieldR).
|
||||
Skip(skipNum).
|
||||
Limit(pageSize).
|
||||
All(¬es)
|
||||
|
||||
blogs = this.notes2BlogItems(notes)
|
||||
pageInfo = info.NewPage(pageNumber, pageSize, count, nil)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (this *BlogService) notes2BlogItems(notes []info.Note) []info.BlogItem {
|
||||
// 得到content, 并且每个都要substring
|
||||
noteIds := make([]bson.ObjectId, len(notes))
|
||||
for i, note := range notes {
|
||||
@@ -106,7 +318,7 @@ func (this *BlogService) SearchBlog(key, userId string, page, pageSize int, sort
|
||||
|
||||
// 直接得到noteContents表的abstract
|
||||
// 这里可能是乱序的
|
||||
noteContents := noteService.ListNoteAbstractsByNoteIds(noteIds) // 返回[info.NoteContent]
|
||||
noteContents := noteService.ListNoteContentByNoteIds(noteIds) // 返回[info.NoteContent]
|
||||
noteContentsMap := make(map[bson.ObjectId]info.NoteContent, len(noteContents))
|
||||
for _, noteContent := range noteContents {
|
||||
noteContentsMap[noteContent.NoteId] = noteContent
|
||||
@@ -117,20 +329,90 @@ func (this *BlogService) SearchBlog(key, userId string, page, pageSize int, sort
|
||||
blogs := make([]info.BlogItem, len(noteIds))
|
||||
for i, note := range notes {
|
||||
hasMore := true
|
||||
var content string
|
||||
var content, abstract string
|
||||
if noteContent, ok := noteContentsMap[note.NoteId]; ok {
|
||||
content = noteContent.Abstract
|
||||
abstract = noteContent.Abstract
|
||||
content = noteContent.Content
|
||||
}
|
||||
blogs[i] = info.BlogItem{note, content, hasMore, info.User{}}
|
||||
blogs[i] = info.BlogItem{note, abstract, content, hasMore, info.User{}}
|
||||
}
|
||||
return count, blogs
|
||||
return blogs
|
||||
}
|
||||
func (this *BlogService) SearchBlog(key, userId string, page, pageSize int, sortField string, isAsc bool) (info.Page, []info.BlogItem) {
|
||||
count, notes := noteService.SearchNote(key, userId, page, pageSize, sortField, isAsc, true)
|
||||
|
||||
if notes == nil || len(notes) == 0 {
|
||||
return info.Page{}, nil
|
||||
}
|
||||
|
||||
blogs := this.notes2BlogItems(notes)
|
||||
pageInfo := info.NewPage(page, pageSize, count, nil)
|
||||
return pageInfo, blogs
|
||||
}
|
||||
|
||||
// 上一篇文章, 下一篇文章
|
||||
// sorterField, baseTime是基准, sorterField=PublicTime, title
|
||||
// isAsc是用户自定义的排序方式
|
||||
func (this *BlogService) PreNextBlog(userId string, sorterField string, isAsc bool, baseTime interface{}) (info.Post, info.Post) {
|
||||
userIdO := bson.ObjectIdHex(userId)
|
||||
|
||||
var sortFieldT1, sortFieldT2 bson.M
|
||||
var sortFieldR1, sortFieldR2 string
|
||||
if !isAsc {
|
||||
// 降序
|
||||
/*
|
||||
------- pre
|
||||
----- now
|
||||
--- next
|
||||
--
|
||||
*/
|
||||
// 上一篇时间要比它大, 找最小的
|
||||
sortFieldT1 = bson.M{"$gt": baseTime}
|
||||
sortFieldR1 = sorterField
|
||||
// 下一篇时间要比它小
|
||||
sortFieldT2 = bson.M{"$lt": baseTime}
|
||||
sortFieldR2 = "-" + sorterField
|
||||
} else {
|
||||
// 升序
|
||||
/*
|
||||
--- pre
|
||||
----- now
|
||||
------- next
|
||||
---------
|
||||
*/
|
||||
// 上一篇要比它小, 找最大的
|
||||
sortFieldT1 = bson.M{"$lt": baseTime}
|
||||
sortFieldR1 = "-" + sorterField
|
||||
// 下一篇, 找最小的
|
||||
sortFieldT2 = bson.M{"$gt": baseTime}
|
||||
sortFieldR2 = sorterField
|
||||
}
|
||||
|
||||
// 上一篇, 比基时间要小, 但是是最后一篇, 所以是降序
|
||||
note := info.Note{}
|
||||
query := bson.M{"UserId": userIdO, "IsTrash": false, "IsBlog": true,
|
||||
sorterField: sortFieldT1,
|
||||
}
|
||||
q := db.Notes.Find(query)
|
||||
q.Sort(sortFieldR1).Limit(1).One(¬e)
|
||||
|
||||
// 下一篇, 比基时间要大, 但是是第一篇, 所以是升序
|
||||
note2 := info.Note{}
|
||||
query[sorterField] = sortFieldT2
|
||||
// Log(isAsc)
|
||||
// LogJ(query)
|
||||
// Log(sortFieldR2)
|
||||
q = db.Notes.Find(query)
|
||||
q.Sort(sortFieldR2).Limit(1).One(¬e2)
|
||||
|
||||
return this.FixNote(note), this.FixNote(note2)
|
||||
}
|
||||
|
||||
//-------
|
||||
// p
|
||||
// 平台 lea+
|
||||
// 博客列表
|
||||
func (this *BlogService) ListAllBlogs(tag string, keywords string, isRecommend bool, page, pageSize int, sorterField string, isAsc bool) (info.Page, []info.BlogItem) {
|
||||
func (this *BlogService) ListAllBlogs(userId, tag string, keywords string, isRecommend bool, page, pageSize int, sorterField string, isAsc bool) (info.Page, []info.BlogItem) {
|
||||
pageInfo := info.Page{CurPage: page}
|
||||
notes := []info.Note{}
|
||||
|
||||
@@ -141,9 +423,12 @@ func (this *BlogService) ListAllBlogs(tag string, keywords string, isRecommend b
|
||||
if tag != "" {
|
||||
query["Tags"] = bson.M{"$in": []string{tag}}
|
||||
}
|
||||
if userId != "" {
|
||||
query["UserId"] = bson.ObjectIdHex(userId)
|
||||
}
|
||||
// 不是demo的博客
|
||||
demoUserId := configService.GetGlobalStringConfig("demoUserId")
|
||||
if demoUserId != "" {
|
||||
if userId == "" && demoUserId != "" {
|
||||
query["UserId"] = bson.M{"$ne": bson.ObjectIdHex(demoUserId)}
|
||||
}
|
||||
|
||||
@@ -153,7 +438,7 @@ func (this *BlogService) ListAllBlogs(tag string, keywords string, isRecommend b
|
||||
if keywords != "" {
|
||||
query["Title"] = bson.M{"$regex": bson.RegEx{".*?" + keywords + ".*", "i"}}
|
||||
}
|
||||
q := db.Notes.Find(query);
|
||||
q := db.Notes.Find(query)
|
||||
|
||||
// 总记录数
|
||||
count, _ := q.Count()
|
||||
@@ -163,7 +448,7 @@ func (this *BlogService) ListAllBlogs(tag string, keywords string, isRecommend b
|
||||
Limit(pageSize).
|
||||
All(¬es)
|
||||
|
||||
if(notes == nil || len(notes) == 0) {
|
||||
if notes == nil || len(notes) == 0 {
|
||||
return pageInfo, nil
|
||||
}
|
||||
|
||||
@@ -200,7 +485,7 @@ func (this *BlogService) ListAllBlogs(tag string, keywords string, isRecommend b
|
||||
content = noteContent.Abstract
|
||||
}
|
||||
*/
|
||||
blogs[i] = info.BlogItem{note, content, hasMore, userMap[note.UserId]}
|
||||
blogs[i] = info.BlogItem{note, "", content, hasMore, userMap[note.UserId]}
|
||||
}
|
||||
pageInfo = info.NewPage(page, pageSize, count, nil)
|
||||
|
||||
@@ -210,18 +495,27 @@ func (this *BlogService) ListAllBlogs(tag string, keywords string, isRecommend b
|
||||
//------------------------
|
||||
// 博客设置
|
||||
func (this *BlogService) fixUserBlog(userBlog *info.UserBlog) {
|
||||
/*
|
||||
if userBlog.Title == "" {
|
||||
userInfo := userService.GetUserInfo(userBlog)
|
||||
userBlog.Title = userInfo.Username + " 's Blog"
|
||||
}
|
||||
*/
|
||||
|
||||
// Logo路径问题, 有些有http: 有些没有
|
||||
Log(userBlog.Logo)
|
||||
if userBlog.Logo != "" && !strings.HasPrefix(userBlog.Logo, "http") {
|
||||
userBlog.Logo = strings.Trim(userBlog.Logo, "/")
|
||||
userBlog.Logo = siteUrl + "/" + userBlog.Logo
|
||||
userBlog.Logo = configService.GetSiteUrl() + "/" + userBlog.Logo
|
||||
}
|
||||
|
||||
if userBlog.SortField == "" {
|
||||
userBlog.SortField = "PublicTime"
|
||||
}
|
||||
if userBlog.PerPageSize <= 0 {
|
||||
userBlog.PerPageSize = 10
|
||||
}
|
||||
|
||||
// themePath
|
||||
if userBlog.Style == "" {
|
||||
userBlog.Style = defaultStyle
|
||||
}
|
||||
if userBlog.ThemeId == "" {
|
||||
userBlog.ThemePath = themeService.GetDefaultThemePath(userBlog.Style)
|
||||
} else {
|
||||
userBlog.ThemePath = themeService.GetThemePath(userBlog.UserId.Hex(), userBlog.ThemeId.Hex())
|
||||
}
|
||||
}
|
||||
func (this *BlogService) GetUserBlog(userId string) info.UserBlog {
|
||||
@@ -235,6 +529,7 @@ func (this *BlogService) GetUserBlog(userId string) info.UserBlog {
|
||||
func (this *BlogService) UpdateUserBlog(userBlog info.UserBlog) bool {
|
||||
return db.Upsert(db.UserBlogs, bson.M{"_id": userBlog.UserId}, userBlog)
|
||||
}
|
||||
|
||||
// 修改之UserBlogBase
|
||||
func (this *BlogService) UpdateUserBlogBase(userId string, userBlog info.UserBlogBase) bool {
|
||||
ok := db.UpdateByQMap(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, userBlog)
|
||||
@@ -247,6 +542,28 @@ func (this *BlogService) UpdateUserBlogStyle(userId string, userBlog info.UserBl
|
||||
return db.UpdateByQMap(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, userBlog)
|
||||
}
|
||||
|
||||
// 分页与排序
|
||||
func (this *BlogService) UpdateUserBlogPaging(userId string, perPageSize int, sortField string, isAsc bool) (ok bool, msg string) {
|
||||
if ok, msg = Vds(map[string]string{"perPageSize": strconv.Itoa(perPageSize), "sortField": sortField}); !ok {
|
||||
return
|
||||
}
|
||||
ok = db.UpdateByQMap(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)},
|
||||
bson.M{"PerPageSize": perPageSize, "SortField": sortField, "IsAsc": isAsc})
|
||||
return
|
||||
}
|
||||
|
||||
func (this *BlogService) GetUserBlogBySubDomain(subDomain string) info.UserBlog {
|
||||
blogUser := info.UserBlog{}
|
||||
db.GetByQ(db.UserBlogs, bson.M{"SubDomain": subDomain}, &blogUser)
|
||||
this.fixUserBlog(&blogUser)
|
||||
return blogUser
|
||||
}
|
||||
func (this *BlogService) GetUserBlogByDomain(domain string) info.UserBlog {
|
||||
blogUser := info.UserBlog{}
|
||||
db.GetByQ(db.UserBlogs, bson.M{"Domain": domain}, &blogUser)
|
||||
this.fixUserBlog(&blogUser)
|
||||
return blogUser
|
||||
}
|
||||
|
||||
//---------------------
|
||||
// 后台管理
|
||||
@@ -264,14 +581,14 @@ func (this *BlogService) SetRecommend(noteId string, isRecommend bool) bool {
|
||||
// 博客社交, 评论
|
||||
|
||||
// 返回所有liked用户, bool是否还有
|
||||
func (this *BlogService) ListLikedUsers(noteId string, isAll bool) ([]info.User, bool) {
|
||||
func (this *BlogService) ListLikedUsers(noteId string, isAll bool) ([]info.UserAndBlog, bool) {
|
||||
// 默认前5
|
||||
pageSize := 5
|
||||
skipNum, sortFieldR := parsePageAndSort(1, pageSize, "CreatedTime", false)
|
||||
|
||||
likes := []info.BlogLike{}
|
||||
query := bson.M{"NoteId": bson.ObjectIdHex(noteId)}
|
||||
q := db.BlogLikes.Find(query);
|
||||
q := db.BlogLikes.Find(query)
|
||||
|
||||
// 总记录数
|
||||
count, _ := q.Count()
|
||||
@@ -291,11 +608,11 @@ func (this *BlogService) ListLikedUsers(noteId string, isAll bool) ([]info.User,
|
||||
userIds[i] = like.UserId
|
||||
}
|
||||
// 得到用户信息
|
||||
userMap := userService.MapUserInfoAndBlogInfosByUserIds(userIds)
|
||||
userMap := userService.MapUserAndBlogByUserIds(userIds)
|
||||
|
||||
users := make([]info.User, len(likes));
|
||||
users := make([]info.UserAndBlog, len(likes))
|
||||
for i, like := range likes {
|
||||
users[i] = userMap[like.UserId]
|
||||
users[i] = userMap[like.UserId.Hex()]
|
||||
}
|
||||
|
||||
return users, count > pageSize
|
||||
@@ -392,7 +709,7 @@ func (this *BlogService) Comment(noteId, toCommentId, userId, content string) (b
|
||||
|
||||
if userId != note.UserId.Hex() || toCommentId != "" {
|
||||
go func() {
|
||||
this.sendEmail(note, comment2, userId, content);
|
||||
this.sendEmail(note, comment2, userId, content)
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -401,7 +718,7 @@ func (this *BlogService) Comment(noteId, toCommentId, userId, content string) (b
|
||||
|
||||
// 发送email
|
||||
func (this *BlogService) sendEmail(note info.Note, comment info.BlogComment, userId, content string) {
|
||||
emailService.SendCommentEmail(note, comment, userId, content);
|
||||
emailService.SendCommentEmail(note, comment, userId, content)
|
||||
/*
|
||||
toUserId := note.UserId.Hex()
|
||||
// title := "评论提醒"
|
||||
@@ -445,7 +762,7 @@ func (this *BlogService) DeleteComment(noteId, commentId, userId string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if userId == adminUserId || note.UserId.Hex() == userId || comment.UserId.Hex() == userId {
|
||||
if userId == configService.GetAdminUserId() || note.UserId.Hex() == userId || comment.UserId.Hex() == userId {
|
||||
if db.Delete(db.BlogComments, bson.M{"_id": bson.ObjectIdHex(commentId)}) {
|
||||
// 评论-1
|
||||
db.Update(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId)}, bson.M{"$inc": bson.M{"CommentNum": -1}})
|
||||
@@ -495,7 +812,7 @@ func (this *BlogService) LikeComment(commentId, userId string) (ok bool, isILike
|
||||
// 评论列表
|
||||
// userId主要是显示userId是否点过某评论的赞
|
||||
// 还要获取用户信息
|
||||
func (this *BlogService) ListComments(userId, noteId string, page, pageSize int) (info.Page, []info.BlogCommentPublic, map[string]info.User) {
|
||||
func (this *BlogService) ListComments(userId, noteId string, page, pageSize int) (info.Page, []info.BlogCommentPublic, map[string]info.UserAndBlog) {
|
||||
pageInfo := info.Page{CurPage: page}
|
||||
|
||||
comments2 := []info.BlogComment{}
|
||||
@@ -503,13 +820,13 @@ func (this *BlogService) ListComments(userId, noteId string, page, pageSize int)
|
||||
skipNum, sortFieldR := parsePageAndSort(page, pageSize, "CreatedTime", false)
|
||||
|
||||
query := bson.M{"NoteId": bson.ObjectIdHex(noteId)}
|
||||
q := db.BlogComments.Find(query);
|
||||
q := db.BlogComments.Find(query)
|
||||
|
||||
// 总记录数
|
||||
count, _ := q.Count()
|
||||
q.Sort(sortFieldR).Skip(skipNum).Limit(pageSize).All(&comments2)
|
||||
|
||||
if(len(comments2) == 0) {
|
||||
if len(comments2) == 0 {
|
||||
return pageInfo, nil, nil
|
||||
}
|
||||
|
||||
@@ -522,7 +839,7 @@ func (this *BlogService) ListComments(userId, noteId string, page, pageSize int)
|
||||
}
|
||||
}
|
||||
|
||||
note := noteService.GetNoteById(noteId);
|
||||
note := noteService.GetNoteById(noteId)
|
||||
|
||||
// 得到用户信息
|
||||
userIdsMap := map[bson.ObjectId]bool{note.UserId: true}
|
||||
@@ -540,19 +857,14 @@ func (this *BlogService) ListComments(userId, noteId string, page, pageSize int)
|
||||
}
|
||||
|
||||
// 得到用户信息
|
||||
userMap := userService.MapUserInfoByUserIds(userIds)
|
||||
userMap2 := make(map[string]info.User, len(userMap))
|
||||
for userId, v := range userMap {
|
||||
userMap2[userId.Hex()] = v
|
||||
}
|
||||
|
||||
userMap := userService.MapUserAndBlogByUserIds(userIds)
|
||||
pageInfo = info.NewPage(page, pageSize, count, nil)
|
||||
|
||||
return pageInfo, comments, userMap2
|
||||
return pageInfo, comments, userMap
|
||||
}
|
||||
|
||||
// 举报
|
||||
func (this *BlogService) Report(noteId, commentId, reason, userId string) (bool) {
|
||||
func (this *BlogService) Report(noteId, commentId, reason, userId string) bool {
|
||||
note := noteService.GetNoteById(noteId)
|
||||
if !note.IsBlog {
|
||||
return false
|
||||
@@ -569,3 +881,333 @@ func (this *BlogService) Report(noteId, commentId, reason, userId string) (bool)
|
||||
}
|
||||
return db.Insert(db.Reports, report)
|
||||
}
|
||||
|
||||
//---------------
|
||||
// 分类排序
|
||||
|
||||
// CateIds
|
||||
func (this *BlogService) UpateCateIds(userId string, cateIds []string) bool {
|
||||
return db.UpdateByQField(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, "CateIds", cateIds)
|
||||
}
|
||||
|
||||
// 修改笔记本urlTitle
|
||||
func (this *BlogService) UpateCateUrlTitle(userId string, cateId, urlTitle string) (ok bool, url string) {
|
||||
url = urlTitle
|
||||
/*
|
||||
// 先清空
|
||||
ok = db.UpdateByIdAndUserIdMap(db.Notebooks, cateId, userId, bson.M{
|
||||
"UrlTitle": "",
|
||||
})
|
||||
*/
|
||||
url = GetUrTitle(userId, urlTitle, "notebook")
|
||||
ok = db.UpdateByIdAndUserIdMap(db.Notebooks, cateId, userId, bson.M{
|
||||
"UrlTitle": url,
|
||||
})
|
||||
// 返回给前端的是decode
|
||||
url = decodeValue(url)
|
||||
return
|
||||
}
|
||||
|
||||
// 修改笔记urlTitle
|
||||
func (this *BlogService) UpateBlogUrlTitle(userId string, noteId, urlTitle string) (ok bool, url string) {
|
||||
url = urlTitle
|
||||
// 先清空
|
||||
ok = db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, bson.M{
|
||||
"UrlTitle": "",
|
||||
})
|
||||
url = GetUrTitle(userId, urlTitle, "note")
|
||||
ok = db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, bson.M{
|
||||
"UrlTitle": url,
|
||||
})
|
||||
// 返回给前端的是decode
|
||||
url = decodeValue(url)
|
||||
return
|
||||
}
|
||||
|
||||
// 修改博客的图片, 描述, 摘要
|
||||
func (this *BlogService) UpateBlogAbstract(userId string, noteId, imgSrc, desc, abstract string) (ok bool) {
|
||||
ok = db.UpdateByIdAndUserIdMap(db.Notes, noteId, userId, bson.M{
|
||||
"ImgSrc": imgSrc,
|
||||
"Desc": desc,
|
||||
"HasSelfDefined": true,
|
||||
})
|
||||
ok = db.UpdateByIdAndUserIdMap(db.NoteContents, noteId, userId, bson.M{
|
||||
"Abstract": abstract,
|
||||
})
|
||||
return ok
|
||||
}
|
||||
|
||||
// 单页
|
||||
func (this *BlogService) GetSingles(userId string) []map[string]string {
|
||||
userBlog := this.GetUserBlog(userId)
|
||||
singles := userBlog.Singles
|
||||
LogJ(singles)
|
||||
return singles
|
||||
}
|
||||
func (this *BlogService) GetSingle(singleId string) info.BlogSingle {
|
||||
page := info.BlogSingle{}
|
||||
db.Get(db.BlogSingles, singleId, &page)
|
||||
return page
|
||||
}
|
||||
func (this *BlogService) GetSingleByUserIdAndUrlTitle(userId, singleIdOrUrlTitle string) info.BlogSingle {
|
||||
page := info.BlogSingle{}
|
||||
if IsObjectId(singleIdOrUrlTitle) {
|
||||
db.Get(db.BlogSingles, singleIdOrUrlTitle, &page)
|
||||
} else {
|
||||
db.GetByQ(db.BlogSingles, bson.M{"UserId": bson.ObjectIdHex(userId), "UrlTitle": encodeValue(singleIdOrUrlTitle)}, &page)
|
||||
}
|
||||
return page
|
||||
}
|
||||
|
||||
func (this *BlogService) updateBlogSingles(userId string, isDelete bool, isAdd bool, singleId, title, urlTitle string) (ok bool) {
|
||||
userBlog := this.GetUserBlog(userId)
|
||||
singles := userBlog.Singles
|
||||
if singles == nil {
|
||||
singles = []map[string]string{}
|
||||
}
|
||||
if isDelete || !isAdd { // 删除或更新, 需要找到相应的
|
||||
i := 0
|
||||
for _, p := range singles {
|
||||
if p["SingleId"] == singleId {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
// 得到i
|
||||
// 找不到
|
||||
if i == len(singles) {
|
||||
} else {
|
||||
// 找到了, 如果是删除, 则删除
|
||||
if isDelete {
|
||||
singles = append(singles[:i], singles[i+1:]...)
|
||||
} else {
|
||||
// 是更新
|
||||
if title != "" {
|
||||
singles[i]["Title"] = title
|
||||
}
|
||||
if urlTitle != "" {
|
||||
singles[i]["UrlTitle"] = urlTitle
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 是添加, 直接添加到最后
|
||||
singles = append(singles, map[string]string{"SingleId": singleId, "Title": title, "UrlTitle": urlTitle})
|
||||
}
|
||||
return db.UpdateByQField(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, "Singles", singles)
|
||||
}
|
||||
|
||||
// 删除页面
|
||||
func (this *BlogService) DeleteSingle(userId, singleId string) (ok bool) {
|
||||
ok = db.DeleteByIdAndUserId(db.BlogSingles, singleId, userId)
|
||||
if ok {
|
||||
// 还要修改UserBlog中的Singles
|
||||
this.updateBlogSingles(userId, true, false, singleId, "", "")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 修改urlTitle
|
||||
func (this *BlogService) UpdateSingleUrlTitle(userId, singleId, urlTitle string) (ok bool, url string) {
|
||||
url = urlTitle
|
||||
/*
|
||||
// 先清空
|
||||
ok = db.UpdateByIdAndUserIdMap(db.BlogSingles, singleId, userId, bson.M{
|
||||
"UrlTitle": "",
|
||||
})
|
||||
*/
|
||||
url = GetUrTitle(userId, urlTitle, "single")
|
||||
ok = db.UpdateByIdAndUserIdMap(db.BlogSingles, singleId, userId, bson.M{
|
||||
"UrlTitle": url,
|
||||
})
|
||||
if ok {
|
||||
// 还要修改UserBlog中的Singles
|
||||
this.updateBlogSingles(userId, false, false, singleId, "", url)
|
||||
}
|
||||
// 返回给前端的是decode
|
||||
url = decodeValue(url)
|
||||
return
|
||||
}
|
||||
|
||||
// 更新或添加
|
||||
func (this *BlogService) AddOrUpdateSingle(userId, singleId, title, content string) (ok bool) {
|
||||
ok = false
|
||||
if singleId != "" {
|
||||
ok = db.UpdateByIdAndUserIdMap(db.BlogSingles, singleId, userId, bson.M{
|
||||
"Title": title,
|
||||
"Content": content,
|
||||
"UpdatedTime": time.Now(),
|
||||
})
|
||||
if ok {
|
||||
// 还要修改UserBlog中的Singles
|
||||
this.updateBlogSingles(userId, false, false, singleId, title, "")
|
||||
}
|
||||
return
|
||||
}
|
||||
// 添加
|
||||
page := info.BlogSingle{
|
||||
SingleId: bson.NewObjectId(),
|
||||
UserId: bson.ObjectIdHex(userId),
|
||||
Title: title,
|
||||
Content: content,
|
||||
UrlTitle: GetUrTitle(userId, title, "single"),
|
||||
CreatedTime: time.Now(),
|
||||
}
|
||||
page.UpdatedTime = page.CreatedTime
|
||||
ok = db.Insert(db.BlogSingles, page)
|
||||
|
||||
// 还要修改UserBlog中的Singles
|
||||
this.updateBlogSingles(userId, false, true, page.SingleId.Hex(), title, page.UrlTitle)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 重新排序
|
||||
func (this *BlogService) SortSingles(userId string, singleIds []string) (ok bool) {
|
||||
if singleIds == nil || len(singleIds) == 0 {
|
||||
return
|
||||
}
|
||||
userBlog := this.GetUserBlog(userId)
|
||||
singles := userBlog.Singles
|
||||
if singles == nil || len(singles) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
singlesMap := map[string]map[string]string{}
|
||||
for _, page := range singles {
|
||||
singlesMap[page["SingleId"]] = page
|
||||
}
|
||||
|
||||
singles2 := make([]map[string]string, len(singles))
|
||||
for i, singleId := range singleIds {
|
||||
singles2[i] = singlesMap[singleId]
|
||||
}
|
||||
|
||||
return db.UpdateByQField(db.UserBlogs, bson.M{"_id": bson.ObjectIdHex(userId)}, "Singles", singles2)
|
||||
}
|
||||
|
||||
// 得到用户的博客url
|
||||
func (this *BlogService) GetUserBlogUrl(userBlog *info.UserBlog, username string) string {
|
||||
if userBlog.Domain != "" && configService.AllowCustomDomain() {
|
||||
return configService.GetUserUrl(userBlog.Domain)
|
||||
} else if userBlog.SubDomain != "" {
|
||||
return configService.GetUserSubUrl(userBlog.SubDomain)
|
||||
}
|
||||
if username == "" {
|
||||
username = userBlog.UserId.Hex()
|
||||
}
|
||||
return configService.GetBlogUrl() + "/" + username
|
||||
}
|
||||
|
||||
// 得到所有url
|
||||
func (this *BlogService) GetBlogUrls(userBlog *info.UserBlog, userInfo *info.User) info.BlogUrls {
|
||||
var indexUrl, postUrl, searchUrl, cateUrl, singleUrl, tagsUrl, archiveUrl, tagPostsUrl string
|
||||
if userBlog.Domain != "" && configService.AllowCustomDomain() { // http://demo.com
|
||||
// ok
|
||||
indexUrl = configService.GetUserUrl(userBlog.Domain)
|
||||
cateUrl = indexUrl + "/cate" // /xxxxx
|
||||
postUrl = indexUrl + "/post" // /xxxxx
|
||||
searchUrl = indexUrl + "/search" // /xxxxx
|
||||
singleUrl = indexUrl + "/single"
|
||||
archiveUrl = indexUrl + "/archives"
|
||||
tagsUrl = indexUrl + "/tags"
|
||||
tagPostsUrl = indexUrl + "/tag"
|
||||
} else if userBlog.SubDomain != "" { // demo.leanote.com
|
||||
indexUrl = configService.GetUserSubUrl(userBlog.SubDomain)
|
||||
cateUrl = indexUrl + "/cate" // /xxxxx
|
||||
postUrl = indexUrl + "/post" // /xxxxx
|
||||
searchUrl = indexUrl + "/search" // /xxxxx
|
||||
singleUrl = indexUrl + "/single"
|
||||
archiveUrl = indexUrl + "/archives"
|
||||
tagsUrl = indexUrl + "/tags"
|
||||
tagPostsUrl = indexUrl + "/tag"
|
||||
} else {
|
||||
// ok
|
||||
blogUrl := configService.GetBlogUrl() // blog.leanote.com
|
||||
userIdOrEmail := ""
|
||||
if userInfo.Username != "" {
|
||||
userIdOrEmail = userInfo.Username
|
||||
} else if userInfo.Email != "" {
|
||||
userIdOrEmail = userInfo.Email
|
||||
} else {
|
||||
userIdOrEmail = userInfo.UserId.Hex()
|
||||
}
|
||||
indexUrl = blogUrl + "/" + userIdOrEmail
|
||||
cateUrl = blogUrl + "/cate/" + userIdOrEmail // /username/notebookId
|
||||
postUrl = blogUrl + "/post/" + userIdOrEmail // /username/xxxxx
|
||||
searchUrl = blogUrl + "/search/" + userIdOrEmail // blog.leanote.com/search/username
|
||||
singleUrl = blogUrl + "/single/" + userIdOrEmail // blog.leanote.com/single/username/singleId
|
||||
archiveUrl = blogUrl + "/archives/" + userIdOrEmail // blog.leanote.com/archive/username
|
||||
tagsUrl = blogUrl + "/tags/" + userIdOrEmail
|
||||
tagPostsUrl = blogUrl + "/tag/" + userIdOrEmail // blog.leanote.com/archive/username
|
||||
}
|
||||
|
||||
return info.BlogUrls{
|
||||
IndexUrl: indexUrl,
|
||||
CateUrl: cateUrl,
|
||||
SearchUrl: searchUrl,
|
||||
SingleUrl: singleUrl,
|
||||
PostUrl: postUrl,
|
||||
ArchiveUrl: archiveUrl,
|
||||
TagsUrl: tagsUrl,
|
||||
TagPostsUrl: tagPostsUrl,
|
||||
}
|
||||
}
|
||||
|
||||
// 转成post
|
||||
func (this *BlogService) FixBlogs(blogs []info.BlogItem) []info.Post {
|
||||
blogs2 := make([]info.Post, len(blogs))
|
||||
for i, blog := range blogs {
|
||||
blogs2[i] = this.FixBlog(blog)
|
||||
}
|
||||
return blogs2
|
||||
}
|
||||
func (this *BlogService) FixBlog(blog info.BlogItem) info.Post {
|
||||
urlTitle := blog.UrlTitle
|
||||
if urlTitle == "" {
|
||||
urlTitle = blog.NoteId.Hex()
|
||||
}
|
||||
blog2 := info.Post{
|
||||
NoteId: blog.NoteId.Hex(),
|
||||
Title: blog.Title,
|
||||
UrlTitle: urlTitle,
|
||||
ImgSrc: blog.ImgSrc,
|
||||
CreatedTime: blog.CreatedTime,
|
||||
UpdatedTime: blog.UpdatedTime,
|
||||
PublicTime: blog.PublicTime,
|
||||
Desc: blog.Desc,
|
||||
Abstract: blog.Abstract,
|
||||
Content: blog.Content,
|
||||
Tags: blog.Tags,
|
||||
CommentNum: blog.CommentNum,
|
||||
ReadNum: blog.ReadNum,
|
||||
LikeNum: blog.LikeNum,
|
||||
IsMarkdown: blog.IsMarkdown,
|
||||
}
|
||||
return blog2
|
||||
}
|
||||
|
||||
func (this *BlogService) FixNote(note info.Note) info.Post {
|
||||
if note.NoteId == "" {
|
||||
return info.Post{}
|
||||
}
|
||||
urlTitle := note.UrlTitle
|
||||
if urlTitle == "" {
|
||||
urlTitle = note.NoteId.Hex()
|
||||
}
|
||||
return info.Post{
|
||||
NoteId: note.NoteId.Hex(),
|
||||
Title: note.Title,
|
||||
ImgSrc: note.ImgSrc,
|
||||
UrlTitle: urlTitle,
|
||||
CreatedTime: note.CreatedTime,
|
||||
UpdatedTime: note.UpdatedTime,
|
||||
PublicTime: note.PublicTime,
|
||||
Desc: note.Desc,
|
||||
Tags: note.Tags,
|
||||
CommentNum: note.CommentNum,
|
||||
ReadNum: note.ReadNum,
|
||||
LikeNum: note.LikeNum,
|
||||
IsMarkdown: note.IsMarkdown,
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,9 @@ import (
|
||||
// 配置服务
|
||||
// 只是全局的, 用户的配置没有
|
||||
type ConfigService struct {
|
||||
adminUserId string
|
||||
siteUrl string
|
||||
adminUsername string
|
||||
// 全局的
|
||||
GlobalAllConfigs map[string]interface{}
|
||||
GlobalStringConfigs map[string]string
|
||||
@@ -24,9 +27,6 @@ type ConfigService struct {
|
||||
GlobalMapConfigs map[string]map[string]string
|
||||
GlobalArrMapConfigs map[string][]map[string]string
|
||||
}
|
||||
|
||||
var adminUserId = ""
|
||||
|
||||
// appStart时 将全局的配置从数据库中得到作为全局
|
||||
func (this *ConfigService) InitGlobalConfigs() bool {
|
||||
this.GlobalAllConfigs = map[string]interface{}{}
|
||||
@@ -35,16 +35,17 @@ func (this *ConfigService) InitGlobalConfigs() bool {
|
||||
this.GlobalMapConfigs = map[string]map[string]string{}
|
||||
this.GlobalArrMapConfigs = map[string][]map[string]string{}
|
||||
|
||||
adminUsername, _ := revel.Config.String("adminUsername")
|
||||
if adminUsername == "" {
|
||||
adminUsername = "admin"
|
||||
this.adminUsername, _ = revel.Config.String("adminUsername")
|
||||
if this.adminUsername == "" {
|
||||
this.adminUsername = "admin"
|
||||
}
|
||||
this.siteUrl, _ = revel.Config.String("site.url")
|
||||
|
||||
userInfo := userService.GetUserInfoByAny(adminUsername)
|
||||
userInfo := userService.GetUserInfoByAny(this.adminUsername)
|
||||
if userInfo.UserId == "" {
|
||||
return false
|
||||
}
|
||||
adminUserId = userInfo.UserId.Hex()
|
||||
this.adminUserId = userInfo.UserId.Hex()
|
||||
|
||||
configs := []info.Config{}
|
||||
db.ListByQ(db.Configs, bson.M{"UserId": userInfo.UserId}, &configs)
|
||||
@@ -68,6 +69,16 @@ func (this *ConfigService) InitGlobalConfigs() bool {
|
||||
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 {
|
||||
// 判断是否存在
|
||||
@@ -183,7 +194,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
|
||||
if registerSharedUserId == "" {
|
||||
ok = true
|
||||
msg = "share userId is blank, So it share nothing to register"
|
||||
this.UpdateGlobalStringConfig(adminUserId, "registerSharedUserId", "")
|
||||
this.UpdateGlobalStringConfig(this.adminUserId, "registerSharedUserId", "")
|
||||
return
|
||||
} else {
|
||||
user := userService.GetUserInfo(registerSharedUserId)
|
||||
@@ -192,7 +203,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
|
||||
msg = "no such user: " + registerSharedUserId
|
||||
return
|
||||
} 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{}
|
||||
// 共享笔记
|
||||
@@ -244,7 +255,7 @@ func (this *ConfigService) UpdateShareNoteConfig(registerSharedUserId string,
|
||||
}
|
||||
}
|
||||
}
|
||||
this.UpdateGlobalArrMapConfig(adminUserId, "registerSharedNotes", notes)
|
||||
this.UpdateGlobalArrMapConfig(this.adminUserId, "registerSharedNotes", notes)
|
||||
|
||||
// 复制
|
||||
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
|
||||
return
|
||||
@@ -277,7 +288,7 @@ func (this *ConfigService) AddBackup(path, remark string) bool {
|
||||
n := time.Now().Unix()
|
||||
nstr := fmt.Sprintf("%v", n)
|
||||
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 {
|
||||
@@ -349,7 +360,7 @@ func (this *ConfigService) Restore(createdTime string) (ok bool, msg string) {
|
||||
port, _ := revel.Config.String("db.port")
|
||||
username, _ := revel.Config.String("db.username")
|
||||
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
|
||||
if username != "" {
|
||||
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:]...)
|
||||
|
||||
ok := this.UpdateGlobalArrMapConfig(adminUserId, "backups", backups)
|
||||
ok := this.UpdateGlobalArrMapConfig(this.adminUserId, "backups", backups)
|
||||
return ok, ""
|
||||
}
|
||||
|
||||
@@ -416,7 +427,7 @@ func (this *ConfigService) UpdateBackupRemark(createdTime, remark string) (bool,
|
||||
}
|
||||
backup["remark"] = remark;
|
||||
|
||||
ok := this.UpdateGlobalArrMapConfig(adminUserId, "backups", backups)
|
||||
ok := this.UpdateGlobalArrMapConfig(this.adminUserId, "backups", backups)
|
||||
return ok, ""
|
||||
}
|
||||
|
||||
@@ -451,7 +462,7 @@ func init() {
|
||||
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://") {
|
||||
defaultDomain = siteUrl[len("http://"):]
|
||||
} else if strings.HasPrefix(siteUrl, "https://") {
|
||||
@@ -461,7 +472,6 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
func (this *ConfigService) GetSchema() string {
|
||||
return schema;
|
||||
}
|
||||
@@ -539,3 +549,36 @@ func (this *ConfigService) IsGoodSubDomain(domain string) bool {
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
tokenUrl := siteUrl + "/user/activeEmail?token=" + token
|
||||
tokenUrl := configService.GetSiteUrl() + "/user/activeEmail?token=" + token
|
||||
// {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{}{
|
||||
"userId": userInfo.UserId.Hex(),
|
||||
"email": userInfo.Email,
|
||||
@@ -122,9 +122,9 @@ func (this *EmailService) UpdateEmailSendActiveEmail(userInfo info.User, email s
|
||||
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}
|
||||
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,
|
||||
"user": map[string]interface{}{
|
||||
"userId": userInfo.UserId.Hex(),
|
||||
@@ -148,9 +148,9 @@ func (this *EmailService) FindPwdSendEmail(token, email string) (ok bool, msg st
|
||||
tpl := configService.GetGlobalStringConfig("emailTemplateFindPassword");
|
||||
|
||||
// 发送邮件
|
||||
tokenUrl := siteUrl + "/findPassword/" + token
|
||||
tokenUrl := configService.GetSiteUrl() + "/findPassword/" + token
|
||||
// {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)))}
|
||||
|
||||
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");
|
||||
tpl := configService.GetGlobalStringConfig("emailTemplateInvite");
|
||||
|
||||
token2Value := map[string]interface{}{"siteUrl": siteUrl,
|
||||
"registerUrl": siteUrl + "/register?from=" + userInfo.Username,
|
||||
token2Value := map[string]interface{}{"siteUrl": configService.GetSiteUrl(),
|
||||
"registerUrl": configService.GetSiteUrl() + "/register?from=" + userInfo.Username,
|
||||
"content": content,
|
||||
"user": map[string]interface{}{
|
||||
"username": userInfo.Username,
|
||||
@@ -225,7 +225,7 @@ func (this *EmailService) SendCommentEmail(note info.Note, comment info.BlogComm
|
||||
// {blog.id} {blog.title} {blog.url}
|
||||
// {commentUser.userId} {commentUser.username} {commentUser.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{
|
||||
"id": note.NoteId.Hex(),
|
||||
"title": note.Title,
|
||||
@@ -316,7 +316,7 @@ func (this *EmailService) renderEmail(subject, body string, values map[string]in
|
||||
|
||||
var tpl *template.Template
|
||||
|
||||
values["siteUrl"] = siteUrl;
|
||||
values["siteUrl"] = configService.GetSiteUrl();
|
||||
|
||||
// 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的关系
|
||||
// <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})")
|
||||
find := reg.FindAllStringSubmatch(content, -1) // 查找所有的
|
||||
|
||||
|
||||
+80
-13
@@ -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)
|
||||
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
|
||||
// [ok]
|
||||
|
||||
func (this *NoteService) AddNote(note info.Note) info.Note {
|
||||
if(note.NoteId.Hex() == "") {
|
||||
noteId := bson.NewObjectId();
|
||||
@@ -124,6 +130,7 @@ func (this *NoteService) AddNote(note info.Note) info.Note {
|
||||
note.UpdatedTime = note.CreatedTime
|
||||
note.IsTrash = false
|
||||
note.UpdatedUserId = note.UserId
|
||||
note.UrlTitle = GetUrTitle(note.UserId.Hex(), note.Title, "note")
|
||||
|
||||
// 设为blog
|
||||
notebookId := note.NotebookId.Hex()
|
||||
@@ -164,13 +171,24 @@ func (this *NoteService) AddNoteContent(noteContent info.NoteContent) info.NoteC
|
||||
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;
|
||||
}
|
||||
|
||||
// 添加笔记和内容
|
||||
// 这里使用 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 {
|
||||
if(note.NoteId.Hex() == "") {
|
||||
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 {
|
||||
// updatedUserId 要修改userId的note, 此时需要判断是否有修改权限
|
||||
if userId != updatedUserId {
|
||||
if !shareService.HasUpdatePerm(userId, updatedUserId, noteId) {
|
||||
Log("NO AUTH")
|
||||
Log("NO AUTH2")
|
||||
return false
|
||||
} else {
|
||||
Log("HAS AUTH -----------")
|
||||
}
|
||||
}
|
||||
|
||||
// 是否已自定义
|
||||
note := this.GetNoteById(noteId)
|
||||
if note.IsBlog && note.HasSelfDefined {
|
||||
delete(needUpdate, "ImgSrc")
|
||||
delete(needUpdate, "Desc")
|
||||
}
|
||||
|
||||
needUpdate["UpdatedUserId"] = bson.ObjectIdHex(updatedUserId);
|
||||
needUpdate["UpdatedTime"] = time.Now();
|
||||
|
||||
@@ -244,12 +268,18 @@ func (this *NoteService) UpdateNoteContent(userId, updatedUserId, noteId, conten
|
||||
}
|
||||
}
|
||||
|
||||
if db.UpdateByIdAndUserIdMap(db.NoteContents, noteId, userId,
|
||||
bson.M{"UpdatedUserId": bson.ObjectIdHex(updatedUserId),
|
||||
data := bson.M{"UpdatedUserId": bson.ObjectIdHex(updatedUserId),
|
||||
"Content": content,
|
||||
"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),
|
||||
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
|
||||
}
|
||||
@@ -278,6 +308,29 @@ func (this *NoteService) UpdateTags(noteId string, userId string, tags []string)
|
||||
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
|
||||
// trash, 正常的都可以用
|
||||
// 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) {
|
||||
notes = []info.Note{}
|
||||
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的
|
||||
query := bson.M{"UserId": bson.ObjectIdHex(userId),
|
||||
"IsTrash": false,
|
||||
"Title": bson.M{"$regex": bson.RegEx{".*?" + key + ".*", "i"}},
|
||||
"$or": orQ,
|
||||
}
|
||||
if isBlog {
|
||||
query["IsBlog"] = true
|
||||
@@ -509,11 +567,20 @@ func (this *NoteService) SearchNoteByTags(tags []string, userId string, pageNumb
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
//------------
|
||||
// 统计
|
||||
func (this *NoteService) CountNote() int {
|
||||
return db.Count(db.Notes, bson.M{"IsTrash": false})
|
||||
func (this *NoteService) CountNote(userId string) int {
|
||||
q := bson.M{"IsTrash": false}
|
||||
if userId != "" {
|
||||
q["UserId"] = bson.ObjectIdHex(userId)
|
||||
}
|
||||
func (this *NoteService) CountBlog() int {
|
||||
return db.Count(db.Notes, bson.M{"IsBlog": true, "IsTrash": false})
|
||||
return db.Count(db.Notes, q)
|
||||
}
|
||||
func (this *NoteService) CountBlog(userId string) int {
|
||||
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)
|
||||
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
|
||||
// 排序好之后返回
|
||||
@@ -133,6 +142,7 @@ func (this *NotebookService) GetNotebooksByNotebookIds(notebookIds []bson.Object
|
||||
// 添加
|
||||
// [ok]
|
||||
func (this *NotebookService) AddNotebook(notebook info.Notebook) bool {
|
||||
notebook.UrlTitle = GetUrTitle(notebook.UserId.Hex(), notebook.Title, "notebook")
|
||||
err := db.Notebooks.Insert(notebook)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -170,16 +180,18 @@ func (this *NotebookService) UpdateNotebookTitle(notebookId, userId, title strin
|
||||
// 更新notebook
|
||||
func (this *NotebookService) UpdateNotebook(userId, notebookId string, needUpdate bson.M) bool {
|
||||
needUpdate["UpdatedTime"] = time.Now();
|
||||
return db.UpdateByIdAndUserIdMap(db.Notebooks, notebookId, userId, needUpdate)
|
||||
}
|
||||
|
||||
// 如果有IsBlog之类的, 需要特殊处理
|
||||
if isBlog, ok := needUpdate["IsBlog"]; ok {
|
||||
// 设为blog/取消, 把它下面所有的note都设为isBlog
|
||||
if is, ok2 := isBlog.(bool); ok2 {
|
||||
// ToBlog or Not
|
||||
func (this *NotebookService) ToBlog(userId, notebookId string, isBlog bool) (bool) {
|
||||
q := bson.M{"UserId": bson.ObjectIdHex(userId),
|
||||
"NotebookId": bson.ObjectIdHex(notebookId)}
|
||||
data := bson.M{"IsBlog": is}
|
||||
if is {
|
||||
data := bson.M{"IsBlog": isBlog}
|
||||
if isBlog {
|
||||
data["PublicTime"] = time.Now()
|
||||
} else {
|
||||
data["HasSelfDefined"] = false
|
||||
}
|
||||
db.UpdateByQMap(db.Notes, q, data)
|
||||
|
||||
@@ -194,10 +206,13 @@ func (this *NotebookService) UpdateNotebook(userId, notebookId string, needUpdat
|
||||
}
|
||||
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
|
||||
|
||||
+267
-68
@@ -13,7 +13,10 @@ import (
|
||||
type ShareService struct {
|
||||
}
|
||||
|
||||
//-----------------
|
||||
//-----------------------------------
|
||||
// 返回shareNotebooks, sharedUserInfos
|
||||
// info.ShareNotebooksByUser, []info.User
|
||||
|
||||
// 总体来说, 这个方法比较麻烦, 速度未知. 以后按以下方案来缓存用户基础数据
|
||||
|
||||
// 以后建个用户的基本数据表, 放所有notebook, sharedNotebook的缓存!!
|
||||
@@ -27,23 +30,48 @@ type ShareService struct {
|
||||
// 3 每个层按seq进行排序
|
||||
// 4 按用户分组
|
||||
// [ok]
|
||||
func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksByUser, []info.User) {
|
||||
//-------------
|
||||
// 查询HasShareNote表得到所有其它用户信息
|
||||
hasShareNotes := []info.HasShareNote{}
|
||||
db.ListByQ(db.HasShareNotes, bson.M{"ToUserId": bson.ObjectIdHex(userId)}, &hasShareNotes);
|
||||
|
||||
userIds := make([]bson.ObjectId, len(hasShareNotes))
|
||||
for i, each := range hasShareNotes {
|
||||
userIds[i] = each.UserId
|
||||
// 谁共享给了我的Query
|
||||
func (this *ShareService) getOrQ(userId string) bson.M {
|
||||
// 得到我参与的组织
|
||||
groupIds := groupService.GetBelongToGroupIds(userId)
|
||||
q := bson.M{}
|
||||
if len(groupIds) > 0 {
|
||||
orQ := []bson.M{
|
||||
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);
|
||||
|
||||
//--------------------
|
||||
// 得到他们共享给我的notebooks
|
||||
|
||||
// 这里可能会得到重复的记录
|
||||
// 权限: 笔记本分享给个人 > 笔记本分享给组织
|
||||
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 {
|
||||
return nil, userInfos
|
||||
@@ -52,13 +80,16 @@ func (this *ShareService) GetShareNotebooks(userId string) (info.ShareNotebooksB
|
||||
shareNotebooksLen := len(shareNotebooks)
|
||||
|
||||
// 找到了所有的notbookId, 那么找notebook表得到其详细信息
|
||||
notebookIds := make([]bson.ObjectId, shareNotebooksLen)
|
||||
notebookIds := []bson.ObjectId{}
|
||||
shareNotebooksMap := make(map[bson.ObjectId]info.ShareNotebook, shareNotebooksLen)
|
||||
for i, each := range shareNotebooks {
|
||||
for _, each := range shareNotebooks {
|
||||
// 之后的就不要了, 只留权限高的
|
||||
if _, ok := shareNotebooksMap[each.NotebookId]; !ok {
|
||||
// 默认的是没有notebookId的
|
||||
notebookIds[i] = each.NotebookId
|
||||
notebookIds = append(notebookIds, each.NotebookId)
|
||||
shareNotebooksMap[each.NotebookId] = each
|
||||
}
|
||||
}
|
||||
|
||||
// 1, 2
|
||||
subNotebooks := notebookService.GetNotebooksByNotebookIds(notebookIds)
|
||||
@@ -127,9 +158,13 @@ func (this *ShareService) parseToSubShareNotebooks(subNotebooks *info.SubNoteboo
|
||||
func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, sharedUserId string,
|
||||
page, pageSize int, sortField string, isAsc bool) ([]info.ShareNoteWithPerm) {
|
||||
// 1 首先判断是否真的sharedUserId 共享了 notebookId 给 myUserId
|
||||
q := this.getOrQ(myUserId)
|
||||
q["NotebookId"] = bson.ObjectIdHex(notebookId);
|
||||
q["UserId"] = bson.ObjectIdHex(sharedUserId);
|
||||
shareNotebook := info.ShareNotebook{}
|
||||
db.GetByQ(db.ShareNotebooks, bson.M{"NotebookId": bson.ObjectIdHex(notebookId),
|
||||
"UserId": bson.ObjectIdHex(sharedUserId), "ToUserId": bson.ObjectIdHex(myUserId)}, &shareNotebook)
|
||||
db.GetByQ(db.ShareNotebooks,
|
||||
q,
|
||||
&shareNotebook)
|
||||
|
||||
if shareNotebook.NotebookId == "" {
|
||||
return nil
|
||||
@@ -146,7 +181,19 @@ func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, share
|
||||
for i, note := range notes {
|
||||
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 组合
|
||||
notesWithPerm := make([]info.ShareNoteWithPerm, len(notes))
|
||||
@@ -162,17 +209,21 @@ func (this *ShareService) ListShareNotesByNotebookId(notebookId, myUserId, share
|
||||
}
|
||||
|
||||
// 得到note的perm信息
|
||||
func (this *ShareService) getNotesPerm(noteIds []bson.ObjectId, myUserId, sharedUserId string) map[bson.ObjectId]int {
|
||||
shareNotes := []info.ShareNote{}
|
||||
db.ListByQ(db.ShareNotes, bson.M{"NoteId": bson.M{"$in": noteIds}, "UserId": bson.ObjectIdHex(sharedUserId), "ToUserId": bson.ObjectIdHex(myUserId)}, &shareNotes)
|
||||
|
||||
notesPerm := make(map[bson.ObjectId]int, len(shareNotes))
|
||||
for _, each := range shareNotes {
|
||||
notesPerm[each.NoteId] = each.Perm
|
||||
}
|
||||
|
||||
return notesPerm
|
||||
}
|
||||
//func (this *ShareService) getNotesPerm(noteIds []bson.ObjectId, myUserId, sharedUserId string) map[bson.ObjectId]int {
|
||||
// shareNotes := []info.ShareNote{}
|
||||
// db.ListByQ(db.ShareNotes,
|
||||
// bson.M{
|
||||
// "NoteId": bson.M{"$in": noteIds},
|
||||
// "UserId": bson.ObjectIdHex(sharedUserId),
|
||||
// "ToUserId": bson.ObjectIdHex(myUserId)}, &shareNotes)
|
||||
//
|
||||
// notesPerm := make(map[bson.ObjectId]int, len(shareNotes))
|
||||
// for _, each := range shareNotes {
|
||||
// notesPerm[each.NoteId] = each.Perm
|
||||
// }
|
||||
//
|
||||
// return notesPerm
|
||||
//}
|
||||
|
||||
// 得到默认的单个的notes 共享集
|
||||
// 如果真要支持排序, 这里得到所有共享的notes, 到noteService方再sort和limit
|
||||
@@ -184,9 +235,12 @@ func (this *ShareService) ListShareNotes(myUserId, sharedUserId string,
|
||||
skipNum, _ := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
||||
shareNotes := []info.ShareNote{}
|
||||
|
||||
q := this.getOrQ(myUserId)
|
||||
q["UserId"] = bson.ObjectIdHex(sharedUserId);
|
||||
|
||||
db.ShareNotes.
|
||||
Find(bson.M{"UserId": bson.ObjectIdHex(sharedUserId), "ToUserId": bson.ObjectIdHex(myUserId)}).
|
||||
// Sort(sortFieldR).
|
||||
Find(q).
|
||||
Sort("-ToUserId"). // 给个人的权限 > 给组织的权限
|
||||
Skip(skipNum).
|
||||
Limit(pageSize).
|
||||
All(&shareNotes)
|
||||
@@ -200,15 +254,20 @@ func (this *ShareService) ListShareNotes(myUserId, sharedUserId string,
|
||||
noteIds[i] = each.NoteId
|
||||
}
|
||||
notes := noteService.ListNotesByNoteIds(noteIds)
|
||||
notesMap := make(map[bson.ObjectId]info.Note, len(notes))
|
||||
notesMap := map[bson.ObjectId]info.Note{}
|
||||
for _, each := range notes {
|
||||
notesMap[each.NoteId] = each
|
||||
}
|
||||
|
||||
// 将shareNotes与notes结合起来
|
||||
notesWithPerm := make([]info.ShareNoteWithPerm, len(shareNotes))
|
||||
for i, each := range shareNotes {
|
||||
notesWithPerm[i] = info.ShareNoteWithPerm{notesMap[each.NoteId], each.Perm}
|
||||
notesWithPerm := []info.ShareNoteWithPerm{}
|
||||
hasAdded := map[bson.ObjectId]bool{} // 防止重复, 只要前面权限高的
|
||||
for _, each := range shareNotes {
|
||||
if !hasAdded[each.NoteId] {
|
||||
// 待优化
|
||||
notesWithPerm = append(notesWithPerm, info.ShareNoteWithPerm{notesMap[each.NoteId], each.Perm})
|
||||
hasAdded[each.NoteId] = true
|
||||
}
|
||||
}
|
||||
return notesWithPerm
|
||||
}
|
||||
@@ -286,19 +345,25 @@ func (this *ShareService) AddShareNote(noteId string, perm int, userId, email st
|
||||
return db.Insert(db.ShareNotes, shareNote), "", toUserId
|
||||
}
|
||||
|
||||
|
||||
// updatedUserId是否有查看userId noteId的权限?
|
||||
// userId是所有者
|
||||
func (this *ShareService) HasReadPerm(userId, updatedUserId, noteId string) bool {
|
||||
if !db.Has(db.ShareNotes,
|
||||
bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NoteId": bson.ObjectIdHex(noteId)}) {
|
||||
q := this.getOrQ(updatedUserId) // (toUserId == "xxx" || ToGroupId in (1, 2,3))
|
||||
q["UserId"] = bson.ObjectIdHex(userId)
|
||||
q["NoteId"] = bson.ObjectIdHex(noteId)
|
||||
if !db.Has(db.ShareNotes, q) {
|
||||
// noteId的notebookId是否被共享了?
|
||||
notebookId := noteService.GetNotebookId(noteId)
|
||||
if notebookId.Hex() == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
delete(q, "NoteId")
|
||||
q["NotebookId"] = notebookId
|
||||
|
||||
// 判断notebook是否被共享
|
||||
if !db.Has(db.ShareNotebooks,
|
||||
bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NotebookId": notebookId}) {
|
||||
if !db.Has(db.ShareNotebooks, q) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
@@ -310,43 +375,44 @@ func (this *ShareService) HasReadPerm(userId, updatedUserId, noteId string) bool
|
||||
|
||||
// updatedUserId是否有修改userId noteId的权限?
|
||||
func (this *ShareService) HasUpdatePerm(userId, updatedUserId, noteId string) bool {
|
||||
// 1. noteId是否被共享了?
|
||||
// 得到该note share的信息
|
||||
/*
|
||||
UserId bson.ObjectId `bson:"UserId"`
|
||||
ToUserId bson.ObjectId `bson:"ToUserId"`
|
||||
NoteId bson.ObjectId `bson:"NoteId"`
|
||||
Perm int `bson:"Perm"` // 权限, 0只读, 1可修改
|
||||
*/
|
||||
if !db.Has(db.ShareNotes,
|
||||
bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NoteId": bson.ObjectIdHex(noteId), "Perm": 1}) {
|
||||
// noteId的notebookId是否被共享了?
|
||||
q := this.getOrQ(updatedUserId) // (toUserId == "xxx" || ToGroupId in (1, 2,3))
|
||||
q["UserId"] = bson.ObjectIdHex(userId)
|
||||
q["NoteId"] = bson.ObjectIdHex(noteId)
|
||||
|
||||
// note的权限
|
||||
shares := []info.ShareNote{}
|
||||
db.ShareNotes.Find(q).Sort("-ToUserId").All(&shares) // 个人 > 组织
|
||||
for _, share := range shares {
|
||||
return share.Perm == 1 // 第1个权限最大
|
||||
}
|
||||
|
||||
// notebook的权限
|
||||
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}) {
|
||||
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
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// updatedUserId是否有修改userId notebookId的权限?
|
||||
func (this *ShareService) HasUpdateNotebookPerm(userId, updatedUserId, notebookId string) bool {
|
||||
// 判断notebook是否被共享
|
||||
if !db.Has(db.ShareNotebooks,
|
||||
bson.M{"UserId": bson.ObjectIdHex(userId), "ToUserId": bson.ObjectIdHex(updatedUserId), "NotebookId": bson.ObjectIdHex(notebookId), "Perm": 1}) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
q := this.getOrQ(updatedUserId) // (toUserId == "xxx" || ToGroupId in (1, 2,3))
|
||||
q["UserId"] = bson.ObjectIdHex(userId)
|
||||
q["NotebookId"] = bson.ObjectIdHex(notebookId)
|
||||
shares2 := []info.ShareNotebook{}
|
||||
db.ShareNotebooks.Find(q).Sort("-ToUserId").All(&shares2) // 个人 > 组织
|
||||
for _, share := range shares2 {
|
||||
return share.Perm == 1 // 第1个权限最大
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 共享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) {
|
||||
noteContent = info.NoteContent{}
|
||||
// 是否单独共享了该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)
|
||||
} else {
|
||||
}
|
||||
@@ -391,7 +461,15 @@ func (this *ShareService) GetShareNoteContent(noteId, myUserId, sharedUserId str
|
||||
func (this *ShareService) ListNoteShareUserInfo(noteId, userId string) []info.ShareUserInfo {
|
||||
// 得到shareNote信息, 得到所有的ToUserId
|
||||
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 {
|
||||
return nil
|
||||
@@ -450,7 +528,11 @@ func (this *ShareService) ListNotebookShareUserInfo(notebookId, userId string) [
|
||||
shareNotebooks := []info.ShareNotebook{}
|
||||
|
||||
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)
|
||||
|
||||
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 {
|
||||
if noteId == "" || userId == "" {
|
||||
return false;
|
||||
@@ -577,3 +659,120 @@ func (this *ShareService) HasReadNotePerm(noteId, userId string) bool {
|
||||
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
|
||||
for _, note := range notes {
|
||||
if note.IsBlog && note.PublicTime.Year() < 100 {
|
||||
db.UpdateByIdAndUserIdMap2(db.Notes, note.NoteId, note.UserId, bson.M{"PublicTime": note.UpdatedTime, "RecommendTime": note.UpdatedTime})
|
||||
Log(note.NoteId.Hex())
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
emailService.RegisterSendActiveEmail(user, user.Email)
|
||||
// 发送给我 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()
|
||||
}
|
||||
|
||||
// 得到用户名
|
||||
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
|
||||
func (this *UserService) IsExistsUser(email string) bool {
|
||||
if this.GetUserId(email) == "" {
|
||||
@@ -75,7 +82,7 @@ func (this *UserService) setUserLogo(user *info.User) {
|
||||
}
|
||||
if user.Logo != "" && !strings.HasPrefix(user.Logo, "http") {
|
||||
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)
|
||||
}
|
||||
|
||||
// 返回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
|
||||
func (this *UserService) GetUserInfosOrderBySeq(userIds []bson.ObjectId) []info.User {
|
||||
users := []info.User{}
|
||||
@@ -143,9 +202,11 @@ func (this *UserService) GetUserInfosOrderBySeq(userIds []bson.ObjectId) []info.
|
||||
usersMap[user.UserId] = user
|
||||
}
|
||||
|
||||
hasAppend := map[bson.ObjectId]bool{} // 为了防止userIds有重复的
|
||||
users2 := []info.User{};
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -169,7 +230,7 @@ func (this *UserService) LoginGetUserInfo(emailOrUsername, md5Pwd string) info.U
|
||||
// 更新username
|
||||
func (this *UserService) UpdateUsername(userId, username string) (bool, string) {
|
||||
if userId == "" || username == "" || username == "admin" { // admin用户是内置的, 不能设置
|
||||
return false, "用户已存在"
|
||||
return false, "usernameIsExisted"
|
||||
}
|
||||
usernameRaw := username // 原先的, 可能是同一个, 但有大小写
|
||||
username = strings.ToLower(username)
|
||||
@@ -177,7 +238,7 @@ func (this *UserService) UpdateUsername(userId, username string) (bool, string)
|
||||
// 先判断是否存在
|
||||
userIdO := bson.ObjectIdHex(userId)
|
||||
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})
|
||||
@@ -195,18 +256,42 @@ func (this *UserService) UpdateAvatar(userId, avatarPath string) (bool) {
|
||||
func (this *UserService) UpdatePwd(userId, oldPwd, pwd string) (bool, string) {
|
||||
userInfo := this.GetUserInfo(userId)
|
||||
if userInfo.Pwd != Md5(oldPwd) {
|
||||
return false, "旧密码错误"
|
||||
return false, "oldPasswordError"
|
||||
}
|
||||
ok := db.UpdateByQField(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, "Pwd", Md5(pwd))
|
||||
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) {
|
||||
ok := db.UpdateByQField(db.Users, bson.M{"_id": bson.ObjectIdHex(userId)}, "Theme", theme)
|
||||
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
|
||||
|
||||
@@ -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) {
|
||||
// 判断该用户是否已有了帐户
|
||||
userInfo := this.GetUserInfo(userId)
|
||||
if userInfo.Email != "" {
|
||||
msg = "你已有帐户"
|
||||
return
|
||||
}
|
||||
|
||||
// 判断email是否存在
|
||||
if this.IsExistsUser(email) {
|
||||
msg = "该用户已存在"
|
||||
@@ -291,7 +383,11 @@ func (this *UserService) ListUsers(pageNumber, pageSize int, sortField string, i
|
||||
skipNum, sortFieldR := parsePageAndSort(pageNumber, pageSize, sortField, isAsc)
|
||||
query := bson.M{}
|
||||
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);
|
||||
// 总记录数
|
||||
|
||||
+79
-5
@@ -1,7 +1,13 @@
|
||||
package service
|
||||
|
||||
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
|
||||
@@ -14,6 +20,7 @@ var noteContentHistoryService, NoteContentHistoryS *NoteContentHistoryService
|
||||
var trashService, TrashS *TrashService
|
||||
var shareService, ShareS *ShareService
|
||||
var userService, UserS *UserService
|
||||
var groupService, GroupS *GroupService
|
||||
var tagService, TagS *TagService
|
||||
var blogService, BlogS *BlogService
|
||||
var tokenService, TokenS *TokenService
|
||||
@@ -28,8 +35,7 @@ var emailService, EmailS *EmailService
|
||||
var AuthS *AuthService
|
||||
var UpgradeS *UpgradeService
|
||||
var SessionS, sessionService *SessionService
|
||||
|
||||
var siteUrl string
|
||||
var ThemeS, themeService *ThemeService
|
||||
|
||||
// onAppStart调用
|
||||
func InitService() {
|
||||
@@ -39,6 +45,7 @@ func InitService() {
|
||||
TrashS = &TrashService{}
|
||||
ShareS = &ShareService{}
|
||||
UserS = &UserService{}
|
||||
GroupS = &GroupService{}
|
||||
TagS = &TagService{}
|
||||
BlogS = &BlogService{}
|
||||
TokenS = &TokenService{}
|
||||
@@ -53,6 +60,7 @@ func InitService() {
|
||||
EmailS = NewEmailService()
|
||||
UpgradeS = &UpgradeService{}
|
||||
SessionS = &SessionService{}
|
||||
ThemeS = &ThemeService{}
|
||||
|
||||
notebookService = NotebookS
|
||||
noteService = NoteS
|
||||
@@ -60,6 +68,7 @@ func InitService() {
|
||||
trashService = TrashS
|
||||
shareService = ShareS
|
||||
userService = UserS
|
||||
groupService = GroupS
|
||||
tagService = TagS
|
||||
blogService = BlogS
|
||||
tokenService = TokenS
|
||||
@@ -70,7 +79,72 @@ func InitService() {
|
||||
configService = ConfigS
|
||||
emailService = EmailS
|
||||
sessionService = SessionS
|
||||
themeService = ThemeS
|
||||
}
|
||||
|
||||
//
|
||||
siteUrl, _ = revel.Config.String("site.url")
|
||||
//----------------
|
||||
// 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
|
||||
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>
|
||||
</div>
|
||||
<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 class="col-sm-4 text-right text-center-xs">
|
||||
{{set . "url" (urlConcat "/adminBlog/index" "sorter" .sorter "keywords" .keywords)}}
|
||||
|
||||
@@ -128,10 +128,18 @@
|
||||
</i>
|
||||
</span>
|
||||
<span>
|
||||
Setting
|
||||
Configuration
|
||||
</span>
|
||||
</a>
|
||||
<ul class="nav lt">
|
||||
<li>
|
||||
<a href="/admin/t?t=setting/home_page">
|
||||
<span>
|
||||
Home Page
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/admin/t?t=setting/demo">
|
||||
<span>
|
||||
@@ -141,7 +149,7 @@
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/admin/t?t=setting/openRegister">
|
||||
<a href="/admin/t?t=setting/open_register">
|
||||
<span>
|
||||
Open Register
|
||||
</span>
|
||||
@@ -155,6 +163,14 @@
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/admin/t?t=setting/upload">
|
||||
<span>
|
||||
Upload File Size Limit
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
@@ -192,5 +208,32 @@
|
||||
</li>
|
||||
</ul>
|
||||
</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>
|
||||
</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;
|
||||
if($("#add_user_form").valid()) {
|
||||
$(t).button('loading');
|
||||
ajaxPost("/auth/doRegister", getFormJsonData("add_user_form"), function(ret){
|
||||
ajaxPost("/adminUser/register", getFormJsonData("add_user_form"), function(ret){
|
||||
$(t).button('reset')
|
||||
if(!ret.Ok) {
|
||||
art.alert(ret.Msg);
|
||||
|
||||
@@ -4,16 +4,8 @@
|
||||
<section class="panel panel-default">
|
||||
<div class="row wrapper">
|
||||
<div class="col-sm-5 m-b-xs">
|
||||
<select class="input-sm form-control input-s-sm inline v-middle">
|
||||
<option value="">
|
||||
Bulk action
|
||||
</option>
|
||||
<option value="1">
|
||||
<button class="btn btn-sm btn-default bulk-email">
|
||||
Send Email
|
||||
</option>
|
||||
</select>
|
||||
<button class="btn btn-sm btn-default bulk-btn">
|
||||
Apply
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-sm-4 m-b-xs">
|
||||
@@ -21,7 +13,7 @@
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<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">
|
||||
<button class="btn btn-sm btn-default" type="button" data-url="/adminUser/index">Search</button>
|
||||
</span>
|
||||
@@ -99,7 +91,8 @@
|
||||
{{.CreatedTime|datetime}}
|
||||
</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>
|
||||
</tr>
|
||||
{{end}}
|
||||
@@ -109,16 +102,8 @@
|
||||
<footer class="panel-footer">
|
||||
<div class="row">
|
||||
<div class="col-sm-4 hidden-xs">
|
||||
<select class="input-sm form-control input-s-sm inline v-middle">
|
||||
<option value="">
|
||||
Bulk action
|
||||
</option>
|
||||
<option value="1">
|
||||
<button class="btn btn-sm btn-default bulk-email">
|
||||
Send Email
|
||||
</option>
|
||||
</select>
|
||||
<button class="btn btn-sm btn-default bulk-btn">
|
||||
Apply
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -137,9 +122,7 @@ $(function() {
|
||||
$(".send-email").click(function() {
|
||||
openSendEmailDialog($(this).data("email"));
|
||||
});
|
||||
$(".bulk-btn").click(function() {
|
||||
// email
|
||||
if($(this).prev().val() == "1") {
|
||||
$(".bulk-email").click(function() {
|
||||
var emails = [];
|
||||
$(".ck:checked").each(function() {
|
||||
emails.push($(this).data("email"));
|
||||
@@ -149,7 +132,12 @@ $(function() {
|
||||
return;
|
||||
}
|
||||
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>
|
||||
|
||||
@@ -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>
|
||||
</a>
|
||||
<ul class="dropdown-menu li-a" role="menu">
|
||||
<li role="presentation" id="setInfo">
|
||||
<a>
|
||||
<i class="fa fa-info"></i>
|
||||
{{msg . "accountSetting"}}
|
||||
</a>
|
||||
</li>
|
||||
<li role="presentation" id="setAvatarMenu">
|
||||
<a>
|
||||
<i class="fa fa-smile-o"></i>
|
||||
{{msg . "setAvatar"}}
|
||||
<li role="presentation">
|
||||
<a href="/member" target="_blank">
|
||||
<i class="fa fa-user"></i>
|
||||
{{msg . "memberCenter"}}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li role="presentation" id="setTheme">
|
||||
<a>
|
||||
<i class="fa fa-sun-o"></i>
|
||||
{{msg . "themeSetting"}}
|
||||
</a>
|
||||
</li>
|
||||
<!--
|
||||
<li role="presentation" id="yourSuggestions">
|
||||
<i class="fa fa-comment-o"></i>
|
||||
{{msg . "yourSuggestions"}}
|
||||
|
||||
<li role="presentation" class="divider"></li>
|
||||
<li role="presentation">
|
||||
<a href="/member/blog/index" target="_blank">
|
||||
<i class="fa fa-bold"></i>
|
||||
{{msg . "blogSet"}}
|
||||
</a>
|
||||
</li>
|
||||
-->
|
||||
|
||||
<li role="presentation" class="my-link" >
|
||||
<a target="_blank" href="{{$.blogUrl}}/{{.userInfo.Username}}">
|
||||
<i class="fa fa-bold"></i>
|
||||
@@ -843,6 +841,7 @@ var notes = json({{.notes}});
|
||||
var noteContentJson = json({{.noteContentJson}});
|
||||
var tagsJson = json({{.tagsJson}});
|
||||
LEA.locale = "{{.locale}}";
|
||||
var GlobalConfigs = {{.globalConfigs|jsonJs}}; // 2014/11/9 beta2
|
||||
</script>
|
||||
|
||||
<!-- 渲染view -->
|
||||
|
||||
+13
-15
@@ -136,30 +136,28 @@ function log(o) {
|
||||
<i class="fa fa-angle-down"></i>
|
||||
</a>
|
||||
<ul class="dropdown-menu li-a" role="menu">
|
||||
<li role="presentation" id="setInfo">
|
||||
<a>
|
||||
<i class="fa fa-info"></i>
|
||||
{{msg . "accountSetting"}}
|
||||
</a>
|
||||
</li>
|
||||
<li role="presentation" id="setAvatarMenu">
|
||||
<a>
|
||||
<i class="fa fa-smile-o"></i>
|
||||
{{msg . "setAvatar"}}
|
||||
<li role="presentation">
|
||||
<a href="/member" target="_blank">
|
||||
<i class="fa fa-user"></i>
|
||||
{{msg . "memberCenter"}}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li role="presentation" id="setTheme">
|
||||
<a>
|
||||
<i class="fa fa-sun-o"></i>
|
||||
{{msg . "themeSetting"}}
|
||||
</a>
|
||||
</li>
|
||||
<!--
|
||||
<li role="presentation" id="yourSuggestions">
|
||||
<i class="fa fa-comment-o"></i>
|
||||
{{msg . "yourSuggestions"}}
|
||||
|
||||
<li role="presentation" class="divider"></li>
|
||||
<li role="presentation">
|
||||
<a href="/member/blog/base" target="_blank">
|
||||
<i class="fa fa-bold"></i>
|
||||
{{msg . "blogSet"}}
|
||||
</a>
|
||||
</li>
|
||||
-->
|
||||
|
||||
<li role="presentation" class="my-link" >
|
||||
<a target="_blank" href="{{$.blogUrl}}/{{.userInfo.Username}}">
|
||||
<i class="fa fa-bold"></i>
|
||||
|
||||
@@ -7,6 +7,13 @@
|
||||
{{$noteOrNotebookId := .noteOrNotebookId}}
|
||||
|
||||
<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>
|
||||
<div id="shareMsg" class="alert alert-danger" style="display: none; margin: 5px 0 0 0;"></div>
|
||||
<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>
|
||||
</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>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -40,19 +47,57 @@
|
||||
<td>{{$v.Email}}</td>
|
||||
<td>
|
||||
{{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}}
|
||||
<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}}
|
||||
</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>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</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 class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{msg . "close"}}</button>
|
||||
@@ -67,5 +112,72 @@ $(function() {
|
||||
setTimeout(function() {
|
||||
$("#tr1 #friendsEmail").focus();
|
||||
}, 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>
|
||||
@@ -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 /findPasswordUpdate Auth.FindPasswordUpdate
|
||||
|
||||
|
||||
# blog
|
||||
|
||||
GET /blog/getLikeAndComments Blog.GetLikeAndComments
|
||||
GET /blog/getLike Blog.GetLike
|
||||
GET /blog/listLikes Blog.ListLikes
|
||||
GET /blog/incReadNum Blog.IncReadNum
|
||||
POST /blog/likeBlog Blog.LikeBlog
|
||||
POST /blog/likeComment Blog.LikeComment
|
||||
POST /blog/deleteComment Blog.DeleteComment
|
||||
GET /blog/listComments Blog.ListComments
|
||||
POST /blog/comment Blog.Comment
|
||||
GET /blog/ListComments Blog.ListComments
|
||||
GET /blog/getLikesAndComments Blog.GetLikesAndComments
|
||||
GET /blog/getLikes Blog.GetLikes
|
||||
* /blog/incReadNum Blog.IncReadNum
|
||||
* /blog/likePost Blog.LikePost
|
||||
* /blog/likeComment Blog.LikeComment
|
||||
* /blog/deleteComment Blog.DeleteComment
|
||||
GET /blog/getComments Blog.GetComments
|
||||
* /blog/commentPost Blog.CommentPost
|
||||
GET /blog/getPostStat Blog.GetPostStat
|
||||
|
||||
|
||||
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 Blog.Search
|
||||
GET /blog/set Blog.Set
|
||||
GET /blog/aboutMe/:userIdOrEmail Blog.AboutMe
|
||||
GET /blog/aboutMe Blog.AboutMe
|
||||
GET /blog/view/:noteId Blog.View
|
||||
POST /blog/setUserBlogBase Blog.SetUserBlogBase
|
||||
POST /blog/setUserBlogComment Blog.SetUserBlogComment
|
||||
POST /blog/setUserBlogStyle Blog.SetUserBlogStyle
|
||||
|
||||
GET /blog/archives/:userIdOrEmail Blog.Archives
|
||||
GET /blog/archives Blog.Archives
|
||||
|
||||
GET /blog/post/:noteId Blog.Post
|
||||
GET /blog/post/:userIdOrEmail/:noteId Blog.Post
|
||||
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/:userIdOrEmail/:notebookId Blog.Cate
|
||||
|
||||
GET /blog/listCateLatest/:notebookId Blog.ListCateLatest
|
||||
GET /blog/isMe.js Blog.IsMe
|
||||
GET /blog/:userIdOrEmail 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
|
||||
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 /upload/*filepath Static.Serve("public/upload")
|
||||
|
||||
# API
|
||||
# the prefix of api's controllername is "Api"
|
||||
# member
|
||||
# the prefix of member's controllername is "Member"
|
||||
* /member MemberIndex.Index
|
||||
* /member/index MemberIndex.Index
|
||||
|
||||
# common
|
||||
* /: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...
|
||||
userHasBeenRegistered=%s has been registered
|
||||
|
||||
# 找回密码
|
||||
passwordTips=The length is at least 6
|
||||
@@ -87,6 +88,7 @@ new=New
|
||||
newMarkdown=New markdown note
|
||||
clickAddTag=Click to add Tag
|
||||
notebook=Notebook
|
||||
note=Note
|
||||
myNotebook=My notebook
|
||||
addNotebook=Add notebook
|
||||
search=Search
|
||||
@@ -129,6 +131,7 @@ logout=Logout
|
||||
basicInfo=Basic
|
||||
updateEmail=Update email
|
||||
usernameSetting=Update username
|
||||
username=Username
|
||||
oldPassword=Old password
|
||||
newPassword=New password
|
||||
admin=Admin
|
||||
@@ -222,17 +225,26 @@ inputPassword=Password is required
|
||||
inputNewPassword=The new password is required
|
||||
inputPassword2=Please input the new password again
|
||||
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
|
||||
updatePasswordSuccess=Update password success
|
||||
errorDomain=The custom domain is invalid, eg. www.myblog.com
|
||||
domainExisted=Custom domain is already existed
|
||||
errorSubDomain=Please input the valid sub domain, the length is at least 4 and no special chars
|
||||
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++
|
||||
leaDesc=leanote blog platform
|
||||
recommend=Recommend
|
||||
latest=Latest
|
||||
|
||||
# 用户中心
|
||||
memberCenter=Member Center
|
||||
userNotExists=该成员沿未注册
|
||||
hasUsers=已存在该成员
|
||||
|
||||
# error
|
||||
notFound=This page cann't found.
|
||||
@@ -79,6 +79,7 @@ hasAcount = 还无帐户?
|
||||
|
||||
# 注册
|
||||
registerSuccessAndRdirectToNote=注册成功, 正在跳转...
|
||||
userHasBeenRegistered=%s已被注册
|
||||
|
||||
# 找回密码
|
||||
passwordTips=密码至少6位
|
||||
@@ -108,6 +109,7 @@ new=新建
|
||||
newMarkdown=新建Markdown笔记
|
||||
clickAddTag=点击添加标签
|
||||
notebook=笔记本
|
||||
note=笔记
|
||||
myNotebook=我的笔记本
|
||||
addNotebook=添加笔记本
|
||||
search=搜索
|
||||
@@ -150,6 +152,7 @@ logout=退出
|
||||
basicInfo=基本信息
|
||||
updateEmail=修改Email
|
||||
usernameSetting=用户名设置
|
||||
username=用户名
|
||||
oldPassword=旧密码
|
||||
newPassword=新密码
|
||||
admin=后台管理
|
||||
@@ -248,17 +251,26 @@ inputPassword=请输入密码
|
||||
inputNewPassword=请输入新密码
|
||||
inputPassword2=请输入确认密码
|
||||
errorPassword=请输入长度不少于6位的密码, 尽量复杂
|
||||
oldPasswordError=旧密码错误
|
||||
confirmPassword=两次密码输入不正确
|
||||
updatePasswordSuccess=修改密码成功
|
||||
errorDomain=请输入正确的域名, 如www.myblog.com
|
||||
domainExisted=域名已存在
|
||||
errorSubDomain=请输入正确的博客子域名, 长度至少为4, 不能包含特殊字符
|
||||
subDomainExisted=博客子域名已存在
|
||||
domainNotPointToLeanote=该域名还未指向 d.leanote.com, 请稍后再试
|
||||
errorPerPageSize=每页记录数至少为1
|
||||
errorSortField=排序类型错误
|
||||
|
||||
# lea++
|
||||
leaDesc=leanote博客平台
|
||||
recommend=推荐
|
||||
latest=最新
|
||||
|
||||
# 用户中心
|
||||
memberCenter=用户中心
|
||||
userNotExists=该成员沿未注册
|
||||
hasUsers=已存在该成员
|
||||
|
||||
# 必须要加这个, 奇怪
|
||||
[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