diff --git a/app/controllers/AttachController.go b/app/controllers/AttachController.go
index cb91632..90246d7 100644
--- a/app/controllers/AttachController.go
+++ b/app/controllers/AttachController.go
@@ -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
}
diff --git a/app/controllers/BaseController.go b/app/controllers/BaseController.go
index d86a99e..fcef661 100644
--- a/app/controllers/BaseController.go
+++ b/app/controllers/BaseController.go
@@ -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
@@ -239,4 +242,4 @@ func (c BaseController) RenderRe(re info.Re) revel.Result {
}
}
return c.RenderJson(re)
-}
\ No newline at end of file
+}
diff --git a/app/controllers/BlogController.go b/app/controllers/BlogController.go
index 30a79bc..172b9d8 100644
--- a/app/controllers/BlogController.go
+++ b/app/controllers/BlogController.go
@@ -1,18 +1,19 @@
package controllers
import (
- "strings"
- "time"
"github.com/revel/revel"
-// "encoding/json"
- "gopkg.in/mgo.v2/bson"
-// . "github.com/leanote/leanote/app/lea"
+ "strings"
+ // "encoding/json"
+ "fmt"
"github.com/leanote/leanote/app/info"
-// "github.com/leanote/leanote/app/types"
-// "io/ioutil"
-// "math"
-// "os"
-// "path"
+ . "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 Blog struct {
@@ -21,183 +22,396 @@ type Blog struct {
//-----------------------------
// 前台
+/*
+公共
+// 分类 [ok]
+$.cates = [{title, cateId}]
+// 单页 [ok]
+$.singles = [{pageId, title}]
+// 博客信息 [ok]
+$.blog = {userId, desc, title, logo, openComment, disqusId}
-// 域名, 没用
+// 公用url ok
+$.indexUrl
+$.cateUrl
+$.searchUrl
+$.postUrl
+$.archiveUrl
+$.singleUrl
+$.themeBaseUrl
+
+// 静态文件 [ok]
+$.jQueryUrl
+$.fontAsomeUrl
+$.bootstrapCssUrl
+$.bootstrapJsUrl
+*/
+
+func (c Blog) render(templateName string, themePath string) revel.Result {
+ isPreview := false
+ if c.RenderArgs["isPreview"] != nil {
+ themePath2 := c.RenderArgs["themePath"]
+ if themePath2 == nil {
+ return c.E404()
+ }
+ isPreview = true
+ themePath = themePath2.(string)
+ c.setPreviewUrl()
+ }
+ return blog.RenderTemplate(templateName, c.RenderArgs, revel.BasePath+"/"+themePath, isPreview)
+}
+
+// 404
+func (c Blog) e404(themePath string) revel.Result {
+ // 不知道是谁的404, 则用系统的404
+ if themePath == "" {
+ return c.E404()
+ }
+ return c.render("404.html", themePath)
+}
+
+// 二级域名或自定义域名
+// life.leanote.com
+// lealife.com
func (c Blog) domain() (ok bool, userBlog info.UserBlog) {
- return
+ host := c.Request.Request.Host // a.cc.com:9000
+ hostArr := strings.Split(host, ".")
+ if strings.Contains(host, configService.GetDefaultDomain()) {
+ // 有二级域名 a.leanoe.com 3个
+ if len(hostArr) > 2 {
+ if userBlog = blogService.GetUserBlogBySubDomain(hostArr[0]); userBlog.UserId != "" {
+ ok = true
+ return
+ }
+ }
+ } else {
+ // 自定义域名
+ // 把:9000去掉
+ hostArr2 := strings.Split(host, ":")
+ if userBlog = blogService.GetUserBlogByDomain(hostArr2[0]); userBlog.UserId != "" {
+ ok = true
+ return
+ }
+ }
+ ok = false
+ return
+}
+
+// 渲染模板之
+func (c Blog) setPreviewUrl() {
+ var indexUrl, postUrl, searchUrl, cateUrl, singleUrl, tagsUrl, archiveUrl string
+
+ userId := c.GetUserId()
+ themeId := c.Session["themeId"]
+ theme := themeService.GetTheme(userId, themeId)
+
+ siteUrl := configService.GetSiteUrl()
+ blogUrl := siteUrl + "/preview" // blog.leanote.com
+ userIdOrEmail := userId
+
+ indexUrl = blogUrl + "/" + userIdOrEmail
+ cateUrl = blogUrl + "/cate" // /notebookId
+
+ postUrl = blogUrl + "/post" // /xxxxx
+ searchUrl = blogUrl + "/search/" + userIdOrEmail // blog.leanote.com/search/userId
+ singleUrl = blogUrl + "/single" // blog.leanote.com/single/singleId
+ archiveUrl = blogUrl + "/archives/" + userIdOrEmail // blog.leanote.com/archive/userId
+ tagsUrl = blogUrl + "/tags/" + userIdOrEmail // blog.leanote.com/archive/userId
+
+ c.RenderArgs["indexUrl"] = indexUrl
+ c.RenderArgs["cateUrl"] = cateUrl
+ c.RenderArgs["postUrl"] = postUrl
+ c.RenderArgs["searchUrl"] = searchUrl
+ c.RenderArgs["singleUrl"] = singleUrl // 单页
+ c.RenderArgs["archiveUrl"] = archiveUrl
+ c.RenderArgs["archivesUrl"] = archiveUrl // 别名
+ c.RenderArgs["tagsUrl"] = tagsUrl
+ c.RenderArgs["tagPostsUrl"] = blogUrl + "/tag/" + userIdOrEmail
+ c.RenderArgs["tagUrl"] = c.RenderArgs["tagPostsUrl"]
+
+ // themeBaseUrl 本theme的路径url, 可以加载js, css, images之类的
+ c.RenderArgs["themeBaseUrl"] = "/" + theme.Path
}
// 各种地址设置
func (c Blog) setUrl(userBlog info.UserBlog, userInfo info.User) {
// 主页 http://leanote.com/blog/life or http://blog.leanote.com/life or http:// xxxx.leanote.com or aa.com
- var indexUrl, viewUrl, searchUrl, cateUrl, aboutMeUrl, staticUrl string
host := c.Request.Request.Host
- staticUrl = configService.GetUserUrl(strings.Split(host, ":")[0])
+ var staticUrl = configService.GetUserUrl(strings.Split(host, ":")[0])
// staticUrl == host, 为保证同源!!! 只有host, http://leanote.com, http://blog/leanote.com
// life.leanote.com, lealife.com
- if userBlog.Domain != "" && configService.AllowCustomDomain() {
- // ok
- indexUrl = configService.GetUserUrl(userBlog.Domain)
- cateUrl = indexUrl + "/cate" // /xxxxx
- viewUrl = indexUrl + "/view" // /xxxxx
- searchUrl = indexUrl + "/search" // /xxxxx
- aboutMeUrl = indexUrl + "/aboutMe"
- } else if userBlog.SubDomain != "" {
- indexUrl = configService.GetUserSubUrl(userBlog.SubDomain)
- cateUrl = indexUrl + "/cate" // /xxxxx
- viewUrl = indexUrl + "/view" // /xxxxx
- searchUrl = indexUrl + "/search" // /xxxxx
- aboutMeUrl = indexUrl + "/aboutMe"
- } else {
- // ok
- blogUrl := configService.GetBlogUrl()
- 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" // /notebookId
- viewUrl = blogUrl + "/view" // /xxxxx
- searchUrl = blogUrl + "/search/" + userIdOrEmail // /xxxxx
- aboutMeUrl = blogUrl + "/aboutMe/" + userIdOrEmail
- }
-
+ siteUrl := configService.GetSiteUrl()
+ blogUrls := blogService.GetBlogUrls(&userBlog, &userInfo)
// 分类
// 搜索
// 查看
- c.RenderArgs["indexUrl"] = indexUrl
- c.RenderArgs["cateUrl"] = cateUrl
- c.RenderArgs["viewUrl"] = viewUrl
- c.RenderArgs["searchUrl"] = searchUrl
- c.RenderArgs["aboutMeUrl"] = aboutMeUrl
- c.RenderArgs["staticUrl"] = staticUrl
+ c.RenderArgs["siteUrl"] = siteUrl
+ c.RenderArgs["indexUrl"] = blogUrls.IndexUrl
+ c.RenderArgs["cateUrl"] = blogUrls.CateUrl
+ c.RenderArgs["postUrl"] = blogUrls.PostUrl
+ c.RenderArgs["searchUrl"] = blogUrls.SearchUrl
+ c.RenderArgs["singleUrl"] = blogUrls.SingleUrl // 单页
+ c.RenderArgs["archiveUrl"] = blogUrls.ArchiveUrl
+ c.RenderArgs["archivesUrl"] = blogUrls.ArchiveUrl // 别名
+ c.RenderArgs["tagsUrl"] = blogUrls.TagsUrl
+ c.RenderArgs["tagPostsUrl"] = blogUrls.TagPostsUrl
+ c.RenderArgs["tagUrl"] = blogUrls.TagPostsUrl // 别名
+
+ // themeBaseUrl 本theme的路径url, 可以加载js, css, images之类的
+ c.RenderArgs["themeBaseUrl"] = "/" + userBlog.ThemePath
+
+ // 其它static js
+ c.RenderArgs["jQueryUrl"] = siteUrl + "/js/jquery-1.9.0.min.js"
+
+ c.RenderArgs["prettifyJsUrl"] = siteUrl + "/js/google-code-prettify/prettify.js"
+ c.RenderArgs["prettifyCssUrl"] = siteUrl + "/js/google-code-prettify/prettify.css"
+
+ c.RenderArgs["blogCommonJsUrl"] = siteUrl + "/public/blog/js/common.js"
+
+ c.RenderArgs["shareCommentCssUrl"] = siteUrl + "/public/blog/css/share_comment.css"
+ c.RenderArgs["shareCommentJsUrl"] = siteUrl + "/public/blog/js/share_comment.js"
+
+ c.RenderArgs["fontAwesomeUrl"] = staticUrl + "/css/font-awesome-4.2.0/css/font-awesome.css"
+
+ c.RenderArgs["bootstrapCssUrl"] = siteUrl + "/css/bootstrap.css"
+ c.RenderArgs["bootstrapJsUrl"] = siteUrl + "/js/bootstrap-min.js"
+}
+
+// 笔记本分类
+// cates = [{title:"xxx", cateId: "xxxx"}, {}]
+func (c Blog) getCateUrlTitle(n *info.Notebook) string {
+ if n.UrlTitle != "" {
+ return n.UrlTitle
+ }
+ return n.NotebookId.Hex()
+}
+func (c Blog) getCates(userBlog info.UserBlog) {
+ notebooks := blogService.ListBlogNotebooks(userBlog.UserId.Hex())
+ notebooksMap := map[string]info.Notebook{}
+ for _, each := range notebooks {
+ notebooksMap[each.NotebookId.Hex()] = each
+ }
+
+ var i = 0
+ cates := make([]map[string]string, 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 {
+ cates[i] = map[string]string{"Title": n.Title, "UrlTitle": c.getCateUrlTitle(&n), "CateId": n.NotebookId.Hex()}
+ i++
+ has[cateId] = true
+ }
+ }
+ }
+ // 之后
+ for _, n := range notebooks {
+ id := n.NotebookId.Hex()
+ if !has[id] {
+ cates[i] = map[string]string{"Title": n.Title, "UrlTitle": c.getCateUrlTitle(&n), "CateId": id}
+ i++
+ }
+ }
+ c.RenderArgs["cates"] = cates
+}
+
+// 单页
+func (c Blog) getSingles(userId string) {
+ singles := blogService.GetSingles(userId)
+ /*
+ if singles == nil {
+ return
+ }
+ singles2 := make([]map[string]string, len(singles))
+ for i, page := range singles {
+ singles2[i] = map[string]string{"title": page["Title"], "singleId": page["SingleId"]}
+ }
+ */
+ c.RenderArgs["singles"] = singles
+}
+
+// $.blog = {userId, title, subTitle, desc, openComment, }
+func (c Blog) setBlog(userBlog info.UserBlog, userInfo info.User) {
+ blogInfo := map[string]interface{}{
+ "UserId": userBlog.UserId.Hex(),
+ "Username": userInfo.Username,
+ "UserLogo": userInfo.Logo,
+ "Title": userBlog.Title,
+ "SubTitle": userBlog.SubTitle,
+ "Logo": userBlog.Logo,
+ "OpenComment": userBlog.CanComment,
+ "CommentType": userBlog.CommentType, // leanote, or disqus
+ "DisqusId": userBlog.DisqusId,
+ "ThemeId": userBlog.ThemeId,
+ "SubDomain": userBlog.SubDomain,
+ "Domain": userBlog.Domain,
+ }
+ c.RenderArgs["blogInfo"] = blogInfo
+}
+
+func (c Blog) setPaging(pageInfo info.Page) {
+ c.RenderArgs["paging"] = pageInfo
}
// 公共
-func (c Blog) blogCommon(userId string, userBlog info.UserBlog, userInfo info.User) (ok bool) {
+func (c Blog) blogCommon(userId string, userBlog info.UserBlog, userInfo info.User) (ok bool, ub info.UserBlog) {
if userInfo.UserId == "" {
userInfo = userService.GetUserInfoByAny(userId)
if userInfo.UserId == "" {
- return
+ return false, userBlog
}
}
- c.RenderArgs["userInfo"] = userInfo
-
- // 分类导航
- c.RenderArgs["notebooks"] = blogService.ListBlogNotebooks(userId)
+ // c.RenderArgs["userInfo"] = userInfo
+
// 最新笔记
- c.getRecentBlogs(userId)
+ _, recentBlogs := blogService.ListBlogs(userId, "", 1, 5, userBlog.SortField, userBlog.IsAsc)
+ c.RenderArgs["recentPosts"] = blogService.FixBlogs(recentBlogs)
+ c.RenderArgs["latestPosts"] = c.RenderArgs["recentPosts"]
+ c.RenderArgs["tags"] = blogService.GetBlogTags(userId)
+
// 语言, url地址
- c.SetLocale();
- c.RenderArgs["isMe"] = userId == c.GetUserId()
-
+ c.SetLocale()
+
// 得到博客设置信息
if userBlog.UserId == "" {
userBlog = blogService.GetUserBlog(userId)
}
- c.RenderArgs["userBlog"] = userBlog
-
+ c.setBlog(userBlog, userInfo)
+ // c.RenderArgs["userBlog"] = userBlog
+
+ // 分类导航
+ c.getCates(userBlog)
+
+ // 单页导航
+ c.getSingles(userId)
+
c.setUrl(userBlog, userInfo)
-
- return true
+
+ // 当前分类Id, 全设为""
+ c.RenderArgs["curCateId"] = ""
+ c.RenderArgs["curSingleId"] = ""
+
+ // 得到主题信息
+ themeInfo := themeService.GetThemeInfo(userBlog.ThemeId.Hex(), userBlog.Style)
+ c.RenderArgs["themeInfo"] = themeInfo
+
+ return true, userBlog
}
-// 跨域判断是否是我的博客
-func (c Blog) IsMe(userId string) revel.Result {
- var js = ""
- if c.GetUserId() == userId {
- js = "$('.is-me').removeClass('hide');"
+// 404
+func (c Blog) E(userIdOrEmail, tag string) revel.Result {
+ ok, userBlog := c.domain()
+ var userId string
+ if ok {
+ userId = userBlog.UserId.Hex()
}
- return c.RenderText(js);
+ var userInfo info.User
+ if userId != "" {
+ userInfo = userService.GetUserInfoByAny(userId)
+ } else {
+ // blog.leanote.com/userid/tag
+ userInfo = userService.GetUserInfoByAny(userIdOrEmail)
+ }
+ userId = userInfo.UserId.Hex()
+ _, userBlog = c.blogCommon(userId, userBlog, userInfo)
+
+ return c.e404(userBlog.ThemePath)
}
-// 进入某个用户的博客
-var blogPageSize = 5
-var searchBlogPageSize = 30
-
-// 分类 /cate/xxxxxxxx?notebookId=1212
-func (c Blog) Cate(notebookId string) revel.Result {
- if notebookId == "" {
- return c.E404()
- }
+func (c Blog) Tags(userIdOrEmail string) (re revel.Result) {
// 自定义域名
hasDomain, userBlog := c.domain()
+ defer func() {
+ if err := recover(); err != nil {
+ re = c.e404(userBlog.ThemePath)
+ }
+ }()
+
userId := ""
if hasDomain {
userId = userBlog.UserId.Hex()
}
-
- var notebook info.Notebook
- notebook = notebookService.GetNotebookById(notebookId)
- if !notebook.IsBlog {
- return c.E404()
+
+ var userInfo info.User
+ if userId != "" {
+ userInfo = userService.GetUserInfoByAny(userId)
+ } else {
+ // blog.leanote.com/userid/tag
+ userInfo = userService.GetUserInfoByAny(userIdOrEmail)
}
- if userId != "" && userId != notebook.UserId.Hex() {
- return c.E404()
+ userId = userInfo.UserId.Hex()
+
+ var ok = false
+ if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok {
+ return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404
}
- userId = notebook.UserId.Hex()
-
- if !c.blogCommon(userId, userBlog, info.User{}) {
- return c.E404()
+
+ c.RenderArgs["curIsTags"] = true
+ tags := blogService.GetBlogTags(userId)
+ c.RenderArgs["tags"] = tags
+ return c.render("tags.html", userBlog.ThemePath)
+}
+
+// 标签的文章页
+func (c Blog) Tag(userIdOrEmail, tag string) (re revel.Result) {
+ // 自定义域名
+ hasDomain, userBlog := c.domain()
+ defer func() {
+ if err := recover(); err != nil {
+ re = c.e404(userBlog.ThemePath)
+ }
+ }()
+
+ userId := ""
+ if hasDomain {
+ userId = userBlog.UserId.Hex()
}
-
- // 分页的话, 需要分页信息, totalPage, curPage
+
+ var userInfo info.User
+ if userId != "" {
+ userInfo = userService.GetUserInfoByAny(userId)
+ } else {
+ // blog.leanote.com/userid/tag
+ userInfo = userService.GetUserInfoByAny(userIdOrEmail)
+ }
+ userId = userInfo.UserId.Hex()
+
+ var ok = false
+ if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok {
+ return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404
+ }
+
+ if hasDomain && tag == "" {
+ tag = userIdOrEmail
+ }
+
+ c.RenderArgs["curIsTagPosts"] = true
+ c.RenderArgs["curTag"] = tag
page := c.GetPage()
- count, blogs := blogService.ListBlogs(userId, notebookId, page, blogPageSize, "PublicTime", false)
-
- c.RenderArgs["notebookId"] = notebookId
- c.RenderArgs["notebook"] = notebook
- c.RenderArgs["title"] = c.Message("blogClass") + " - " + notebook.Title
- c.RenderArgs["blogs"] = blogs
- c.RenderArgs["page"] = page
- c.RenderArgs["pageSize"] = blogPageSize
- c.RenderArgs["count"] = count
-
- return c.RenderTemplate("blog/index.html")
+ pageInfo, blogs := blogService.SearchBlogByTags([]string{tag}, userId, page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc)
+ c.setPaging(pageInfo)
+
+ c.RenderArgs["posts"] = blogService.FixBlogs(blogs)
+ tagPostsUrl := c.RenderArgs["tagPostsUrl"].(string)
+ c.RenderArgs["pagingBaseUrl"] = tagPostsUrl + "/" + tag
+
+ return c.render("tag_posts.html", userBlog.ThemePath)
}
-// 显示分类的最近博客, json
-func (c Blog) ListCateLatest(notebookId, callback string) revel.Result {
- if notebookId == "" {
- return c.E404()
- }
- // 自定义域名
- hasDomain, userBlog := c.domain()
- userId := ""
- if hasDomain {
- userId = userBlog.UserId.Hex()
- }
-
- var notebook info.Notebook
- notebook = notebookService.GetNotebookById(notebookId)
- if !notebook.IsBlog {
- return c.E404()
- }
- if userId != "" && userId != notebook.UserId.Hex() {
- return c.E404()
- }
- userId = notebook.UserId.Hex()
-
- if !c.blogCommon(userId, userBlog, info.User{}) {
- return c.E404()
- }
-
- // 分页的话, 需要分页信息, totalPage, curPage
- page := 1
- _, blogs := blogService.ListBlogs(userId, notebookId, page, 5, "PublicTime", false)
- re := info.NewRe()
- re.Ok = true
- re.List = blogs
- return c.RenderJsonP(callback, re)
-}
-
-func (c Blog) Index(userIdOrEmail string) revel.Result {
+// 归档
+func (c Blog) Archives(userIdOrEmail string, cateId string, year, month int) (re revel.Result) {
+ notebookId := cateId
// 自定义域名
hasDomain, userBlog := c.domain()
+ defer func() {
+ if err := recover(); err != nil {
+ fmt.Println(err)
+ re = c.e404(userBlog.ThemePath)
+ }
+ }()
userId := ""
if hasDomain {
userId = userBlog.UserId.Hex()
@@ -205,7 +419,7 @@ func (c Blog) Index(userIdOrEmail string) revel.Result {
// 用户id为空, 转至博客平台
if userIdOrEmail == "" {
- userIdOrEmail = leanoteUserId;
+ userIdOrEmail = configService.GetAdminUsername()
}
var userInfo info.User
if userId != "" {
@@ -215,158 +429,250 @@ func (c Blog) Index(userIdOrEmail string) revel.Result {
}
userId = userInfo.UserId.Hex()
- if !c.blogCommon(userId, userBlog, userInfo) {
- return c.E404()
+ var ok = false
+ if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok {
+ return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404
}
-
- // 分页的话, 需要分页信息, totalPage, curPage
- page := c.GetPage()
- count, blogs := blogService.ListBlogs(userId, "", page, blogPageSize, "PublicTime", false)
-
- c.RenderArgs["blogs"] = blogs
- c.RenderArgs["page"] = page
- c.RenderArgs["pageSize"] = blogPageSize
- c.RenderArgs["count"] = count
- c.RenderArgs["index"] = true
- c.RenderArgs["notebookId"] = ""
- c.RenderArgs["title"] = userBlog.Title
-
- return c.RenderTemplate("blog/index.html")
+
+ arcs := blogService.ListBlogsArchive(userId, notebookId, year, month, "PublicTime", false)
+ c.RenderArgs["archives"] = arcs
+
+ c.RenderArgs["curIsArchive"] = true
+ if notebookId != "" {
+ notebook := notebookService.GetNotebookById(notebookId)
+ c.RenderArgs["curCateTitle"] = notebook.Title
+ c.RenderArgs["curCateId"] = notebookId
+ }
+ c.RenderArgs["curYear"] = year
+ c.RenderArgs["curMonth"] = month
+
+ return c.render("archive.html", userBlog.ThemePath)
}
-// 详情
-func (c Blog) View(noteId string) revel.Result {
+// 进入某个用户的博客
+var blogPageSize = 5
+var searchBlogPageSize = 30
+// 分类 /cate/xxxxxxxx?notebookId=1212
+func (c Blog) Cate(userIdOrEmail string, notebookId string) (re revel.Result) {
// 自定义域名
hasDomain, userBlog := c.domain()
- userId := ""
+ defer func() {
+ if err := recover(); err != nil {
+ fmt.Println(err)
+ re = c.e404(userBlog.ThemePath)
+ }
+ }()
+
+ userId, userInfo := c.userIdOrEmail(hasDomain, userBlog, userIdOrEmail)
+ notebookId2 := notebookId
+ var notebook info.Notebook
+ if userId == "" { // 证明没有userIdOrEmail, 只有singleId, 那么直接查
+ notebook = notebookService.GetNotebookById(notebookId)
+ userId = notebook.UserId.Hex()
+ } else {
+ notebook = notebookService.GetNotebookByUserIdAndUrlTitle(userId, notebookId)
+ notebookId2 = notebook.NotebookId.Hex()
+ }
+ var ok = false
+ if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok {
+ return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404
+ }
+ if !notebook.IsBlog {
+ return c.e404("")
+ }
+
+ // 分页的话, 需要分页信息, totalPage, curPage
+ page := c.GetPage()
+ pageInfo, blogs := blogService.ListBlogs(userId, notebookId2, page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc)
+ blogs2 := blogService.FixBlogs(blogs)
+ c.RenderArgs["posts"] = blogs2
+
+ c.setPaging(pageInfo)
+
+ c.RenderArgs["curCateTitle"] = notebook.Title
+ c.RenderArgs["curCateId"] = notebookId2
+ cateUrl := c.RenderArgs["cateUrl"].(string)
+ c.RenderArgs["pagingBaseUrl"] = cateUrl + "/" + notebookId
+ c.RenderArgs["curIsCate"] = true
+
+ return c.render("cate.html", userBlog.ThemePath)
+}
+
+func (c Blog) userIdOrEmail(hasDomain bool, userBlog info.UserBlog, userIdOrEmail string) (userId string, userInfo info.User) {
+ userId = ""
if hasDomain {
userId = userBlog.UserId.Hex()
}
-
- blog := blogService.GetBlog(noteId)
- userInfo := userService.GetUserInfo(blog.UserId.Hex())
- if userId != "" && userInfo.UserId.Hex() != userId {
- return c.E404()
- }
- c.RenderArgs["blog"] = blog
- c.RenderArgs["userInfo"] = userInfo
- c.RenderArgs["title"] = blog.Title + " - " + userInfo.Username
-
- userId = userInfo.UserId.Hex()
- c.blogCommon(userId, userBlog, info.User{})
-
- // 得到访问者id
- visitUserId := c.GetUserId()
- if(visitUserId != "") {
- visitUserInfo := userService.GetUserInfo(visitUserId)
- c.RenderArgs["visitUserInfoJson"] = c.Json(visitUserInfo)
- c.RenderArgs["visitUserInfo"] = visitUserInfo
+ if userId != "" {
+ userInfo = userService.GetUserInfoByAny(userId)
} else {
- c.RenderArgs["visitUserInfoJson"] = "{}";
+ if userIdOrEmail != "" {
+ userInfo = userService.GetUserInfoByAny(userIdOrEmail)
+ } else {
+ return
+ }
}
-
- return c.RenderTemplate("blog/view.html")
+ userId = userInfo.UserId.Hex()
+ return
+}
+
+func (c Blog) Index(userIdOrEmail string) (re revel.Result) {
+ // 自定义域名
+ hasDomain, userBlog := c.domain()
+ defer func() {
+ if err := recover(); err != nil {
+ re = c.e404(userBlog.ThemePath)
+ }
+ }()
+ // 用户id为空, 则是admin用户的博客
+ if userIdOrEmail == "" {
+ userIdOrEmail = configService.GetAdminUsername()
+ }
+ userId, userInfo := c.userIdOrEmail(hasDomain, userBlog, userIdOrEmail)
+ var ok = false
+ if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok {
+ return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404
+ }
+
+ // 分页的话, 需要分页信息, totalPage, curPage
+ page := c.GetPage()
+ pageInfo, blogs := blogService.ListBlogs(userId, "", page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc)
+ blogs2 := blogService.FixBlogs(blogs)
+ c.RenderArgs["posts"] = blogs2
+
+ c.setPaging(pageInfo)
+ c.RenderArgs["pagingBaseUrl"] = c.RenderArgs["indexUrl"]
+
+ c.RenderArgs["curIsIndex"] = true
+
+ return c.render("index.html", userBlog.ThemePath)
+}
+
+func (c Blog) Post(userIdOrEmail, noteId string) (re revel.Result) {
+ // 自定义域名
+ hasDomain, userBlog := c.domain()
+ defer func() {
+ if err := recover(); err != nil {
+ Log(err)
+ re = c.e404(userBlog.ThemePath)
+ }
+ }()
+
+ userId, userInfo := c.userIdOrEmail(hasDomain, userBlog, userIdOrEmail)
+ var blogInfo info.BlogItem
+ if userId == "" { // 证明没有userIdOrEmail, 只有singleId, 那么直接查
+ blogInfo = blogService.GetBlog(noteId)
+ userId = blogInfo.UserId.Hex()
+ } else {
+ blogInfo = blogService.GetBlogByIdAndUrlTitle(userId, noteId)
+ }
+ var ok = false
+ if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok {
+ return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404
+ }
+ if blogInfo.NoteId == "" {
+ return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404
+ }
+
+ c.RenderArgs["post"] = blogService.FixBlog(blogInfo)
+ // c.RenderArgs["userInfo"] = userInfo
+ c.RenderArgs["curIsPost"] = true
+
+ // 上一篇, 下一篇
+ var baseTime interface{}
+ if userBlog.SortField == "PublicTime" {
+ baseTime = blogInfo.PublicTime
+ } else if userBlog.SortField == "CreatedTime" {
+ baseTime = blogInfo.CreatedTime
+ } else if userBlog.SortField == "UpdatedTime" {
+ baseTime = blogInfo.UpdatedTime
+ } else {
+ baseTime = blogInfo.Title
+ }
+
+ prePost, nextPost := blogService.PreNextBlog(userId, userBlog.SortField, userBlog.IsAsc, baseTime)
+ c.RenderArgs["prePost"] = prePost
+ c.RenderArgs["nextPost"] = nextPost
+ return c.render("post.html", userBlog.ThemePath)
+}
+
+func (c Blog) Single(userIdOrEmail, singleId string) (re revel.Result) {
+ // 自定义域名
+ hasDomain, userBlog := c.domain()
+ defer func() {
+ if err := recover(); err != nil {
+ re = c.e404(userBlog.ThemePath)
+ }
+ }()
+
+ userId, userInfo := c.userIdOrEmail(hasDomain, userBlog, userIdOrEmail)
+ var single info.BlogSingle
+ if userId == "" { // 证明没有userIdOrEmail, 只有singleId, 那么直接查
+ single = blogService.GetSingle(singleId)
+ userId = single.UserId.Hex()
+ } else {
+ single = blogService.GetSingleByUserIdAndUrlTitle(userId, singleId)
+ }
+ var ok = false
+ if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok {
+ return c.e404(userBlog.ThemePath) // 404 TODO 使用用户的404
+ }
+ if single.SingleId == "" {
+ panic("")
+ }
+
+ c.RenderArgs["single"] = map[string]interface{}{
+ "SingleId": single.SingleId.Hex(),
+ "Title": single.Title,
+ "UrlTitle": single.UrlTitle,
+ "Content": single.Content,
+ "CreatedTime": single.CreatedTime,
+ "UpdatedTime": single.UpdatedTime,
+ }
+ c.RenderArgs["curSingleId"] = single.SingleId.Hex()
+ c.RenderArgs["curIsSingle"] = true
+
+ return c.render("single.html", userBlog.ThemePath)
}
// 搜索
-func (c Blog) Search(userIdOrEmail, key string) revel.Result {
+func (c Blog) Search(userIdOrEmail, keywords string) (re revel.Result) {
// 自定义域名
hasDomain, userBlog := c.domain()
+ defer func() {
+ if err := recover(); err != nil {
+ re = c.e404(userBlog.ThemePath)
+ }
+ }()
userId := ""
if hasDomain {
userId = userBlog.UserId.Hex()
}
-
- c.RenderArgs["title"] = c.Message("search") + " - " + key
- c.RenderArgs["key"] = key
-
+
var userInfo info.User
if userId != "" {
userInfo = userService.GetUserInfoByAny(userId)
} else {
userInfo = userService.GetUserInfoByAny(userIdOrEmail)
}
- c.RenderArgs["userInfo"] = userInfo
+ // c.RenderArgs["userInfo"] = userInfo
userId = userInfo.UserId.Hex()
- c.blogCommon(userId, userBlog, userInfo)
-
+ var ok = false
+ if ok, userBlog = c.blogCommon(userId, userBlog, userInfo); !ok {
+ return c.e404(userBlog.ThemePath)
+ }
+
page := c.GetPage()
- _, blogs := blogService.SearchBlog(key, userId, page, searchBlogPageSize, "PublicTime", false)
-
- c.RenderArgs["blogs"] = blogs
- c.RenderArgs["key"] = key
+ pageInfo, blogs := blogService.SearchBlog(keywords, userId, page, userBlog.PerPageSize, userBlog.SortField, userBlog.IsAsc)
+ c.setPaging(pageInfo)
- return c.RenderTemplate("blog/search.html")
-}
+ c.RenderArgs["posts"] = blogService.FixBlogs(blogs)
+ c.RenderArgs["keywords"] = keywords
+ searchUrl, _ := c.RenderArgs["searchUrl"].(string)
+ c.RenderArgs["pagingBaseUrl"] = searchUrl + "?keywords=" + keywords
+ c.RenderArgs["curIsSearch"] = true
-// 博客设置
-func (c Blog) Set() revel.Result {
- userId := c.GetUserId()
- userInfo := userService.GetUserInfo(userId)
- c.RenderArgs["userInfo"] = userInfo
-
- // 得到博客设置信息
- c.RenderArgs["title"] = c.Message("blogSet")
- c.RenderArgs["isMe"] = true
- c.RenderArgs["set"] = true
-
- c.RenderArgs["allowCustomDomain"] = configService.GetGlobalStringConfig("allowCustomDomain")
-
- userBlog := blogService.GetUserBlog(userId)
- c.blogCommon(userId, userBlog, info.User{})
-
- return c.RenderTemplate("blog/set.html")
-}
-
-func (c Blog) SetUserBlogBase(userBlog info.UserBlogBase) revel.Result {
- re := info.NewRe()
- re.Ok = blogService.UpdateUserBlogBase(c.GetUserId(), userBlog)
- return c.RenderJson(re)
-}
-func (c Blog) SetUserBlogComment(userBlog info.UserBlogComment) revel.Result {
- re := info.NewRe()
- re.Ok = blogService.UpdateUserBlogComment(c.GetUserId(), userBlog)
- return c.RenderJson(re)
-}
-func (c Blog) SetUserBlogStyle(userBlog info.UserBlogStyle) revel.Result {
- re := info.NewRe()
- re.Ok = blogService.UpdateUserBlogStyle(c.GetUserId(), userBlog)
- return c.RenderJson(re)
-}
-
-// userId可能是其它的
-func (c Blog) AboutMe(userIdOrEmail string) revel.Result {
- // 自定义域名
- hasDomain, userBlog := c.domain()
- userId := ""
- if hasDomain {
- userId = userBlog.UserId.Hex()
- }
-
- var userInfo info.User
- if userId != "" {
- userInfo = userService.GetUserInfoByAny(userId)
- } else {
- userInfo = userService.GetUserInfoByAny(userIdOrEmail)
- }
-
- if userInfo.UserId == "" {
- return c.E404()
- }
- userId = userInfo.UserId.Hex()
-
- c.RenderArgs["userInfo"] = userInfo
- c.RenderArgs["aboutMe"] = true
-
- c.RenderArgs["title"] = c.Message("aboutMe")
- c.blogCommon(userId, userBlog, info.User{})
-
- return c.RenderTemplate("blog/about_me.html")
-}
-
-// 优化, 这里不要得到count
-func (c Blog) getRecentBlogs(userId string) {
- _, c.RenderArgs["recentBlogs"] = blogService.ListBlogs(userId, "", 1, 5, "PublicTime", false)
+ return c.render("search.html", userBlog.ThemePath)
}
// 可以不要, 因为注册的时候已经把username设为email了
@@ -377,128 +683,155 @@ func (c Blog) setRenderUserInfo(userInfo info.User) {
c.RenderArgs["userInfo"] = userInfo
}
-//---------------------------
-// 后台 note<->blog
-
-// 设置/取消Blog; 置顶
-func (c Blog) SetNote2Blog(noteId string, isBlog, isTop bool) revel.Result {
- noteUpdate := bson.M{}
- if isTop {
- isBlog = true
- }
- if !isBlog {
- isTop = false
- }
- noteUpdate["IsBlog"] = isBlog
- noteUpdate["IsTop"] = isTop
- if isBlog {
- noteUpdate["PublicTime"] = time.Now()
- }
- re := noteService.UpdateNote(c.GetUserId(), c.GetUserId(),
- noteId, noteUpdate)
- return c.RenderJson(re)
-}
-
-// 设置notebook <-> blog
-func (c Blog) SetNotebook2Blog(notebookId string, isBlog bool) revel.Result {
- noteUpdate := bson.M{"IsBlog": isBlog}
- re := notebookService.UpdateNotebook(c.GetUserId(),
- notebookId, noteUpdate)
- return c.RenderJson(re)
-}
-
//----------------
// 社交, 点赞, 评论
-// 我是否点过赞?
+// 得到博客统计信息
+func (c Blog) GetPostStat(noteId string) revel.Result {
+ re := info.NewRe()
+ re.Ok = true
+ statInfo := blogService.GetBlogStat(noteId)
+ re.Item = statInfo
+ return c.RenderJson(re)
+}
+
+// jsonP
+// 我是否点过赞? 得到我的信息
// 所有点赞的用户列表
// 各个评论中是否我也点过赞?
-func (c Blog) GetLike(noteId string) revel.Result {
+func (c Blog) GetLikes(noteId string, callback string) revel.Result {
userId := c.GetUserId()
-
- // 我也点过?
- isILikeIt := blogService.IsILikeIt(noteId, userId)
+ result := map[string]interface{}{}
+ isILikeIt := false
+ if userId != "" {
+ isILikeIt = blogService.IsILikeIt(noteId, userId)
+ result["visitUserInfo"] = userService.GetUserAndBlog(userId)
+ }
// 点赞用户列表
likedUsers, hasMoreLikedUser := blogService.ListLikedUsers(noteId, false)
- result := map[string]interface{}{}
+ re := info.NewRe()
+ re.Ok = true
result["isILikeIt"] = isILikeIt
result["likedUsers"] = likedUsers
result["hasMoreLikedUser"] = hasMoreLikedUser
-
- return c.RenderJson(result)
+
+ re.Item = result
+ return c.RenderJsonP(callback, re)
}
-func (c Blog) GetLikeAndComments(noteId string) revel.Result {
+func (c Blog) GetLikesAndComments(noteId, callback string) revel.Result {
userId := c.GetUserId()
-
+ result := map[string]interface{}{}
+
// 我也点过?
- isILikeIt := blogService.IsILikeIt(noteId, userId)
+ isILikeIt := false
+ if userId != "" {
+ isILikeIt = blogService.IsILikeIt(noteId, userId)
+ result["visitUserInfo"] = userService.GetUserAndBlog(userId)
+ }
+
// 点赞用户列表
likedUsers, hasMoreLikedUser := blogService.ListLikedUsers(noteId, false)
// 评论
page := c.GetPage()
pageInfo, comments, commentUserInfo := blogService.ListComments(userId, noteId, page, 15)
-
- result := map[string]interface{}{}
+
+ re := info.NewRe()
+ re.Ok = true
result["isILikeIt"] = isILikeIt
result["likedUsers"] = likedUsers
result["hasMoreLikedUser"] = hasMoreLikedUser
result["pageInfo"] = pageInfo
result["comments"] = comments
result["commentUserInfo"] = commentUserInfo
-
- return c.RenderJson(result)
+ re.Item = result
+ return c.RenderJsonP(callback, re)
}
func (c Blog) IncReadNum(noteId string) revel.Result {
- blogService.IncReadNum(noteId)
- return nil
-}
-// 点赞
-func (c Blog) LikeBlog(noteId string) revel.Result {
- userId := c.GetUserId()
re := info.NewRe()
- re.Ok, re.Item = blogService.LikeBlog(noteId, userId)
-
+ re.Ok = blogService.IncReadNum(noteId)
return c.RenderJson(re)
}
-func (c Blog) ListLikes(noteId string) revel.Result {
- return nil
-}
-func (c Blog) ListComments(noteId string) revel.Result {
+// 点赞, 要用jsonp
+func (c Blog) LikePost(noteId string, callback string) revel.Result {
+ re := info.NewRe()
+ userId := c.GetUserId()
+ re.Ok, re.Item = blogService.LikeBlog(noteId, userId)
+ return c.RenderJsonP(callback, re)
+}
+func (c Blog) GetComments(noteId string) revel.Result {
// 评论
userId := c.GetUserId()
page := c.GetPage()
pageInfo, comments, commentUserInfo := blogService.ListComments(userId, noteId, page, 15)
-
+ re := info.NewRe()
+ re.Ok = true
result := map[string]interface{}{}
result["pageInfo"] = pageInfo
result["comments"] = comments
result["commentUserInfo"] = commentUserInfo
-
- return c.RenderJson(result)
+ re.Item = result
+
+ return c.RenderJson(re)
}
-func (c Blog) DeleteComment(noteId, commentId string) revel.Result {
+
+// jsonp
+func (c Blog) DeleteComment(noteId, commentId string, callback string) revel.Result {
re := info.NewRe()
re.Ok = blogService.DeleteComment(noteId, commentId, c.GetUserId())
- return c.RenderJson(re)
+ return c.RenderJsonP(callback, re)
}
-func (c Blog) Comment(noteId, content, toCommentId string) revel.Result {
+
+// jsonp
+func (c Blog) CommentPost(noteId, content, toCommentId string, callback string) revel.Result {
re := info.NewRe()
- re.Ok, re.Item = blogService.Comment(noteId, toCommentId, c.GetUserId(), content);
- return c.RenderJson(re)
+ re.Ok, re.Item = blogService.Comment(noteId, toCommentId, c.GetUserId(), content)
+ return c.RenderJsonP(callback, re)
}
-func (c Blog) LikeComment(commentId string) revel.Result {
+
+// jsonp
+func (c Blog) LikeComment(commentId string, callback string) revel.Result {
re := info.NewRe()
ok, isILikeIt, num := blogService.LikeComment(commentId, c.GetUserId())
re.Ok = ok
re.Item = bson.M{"IsILikeIt": isILikeIt, "Num": num}
- return c.RenderJson(re)
+ return c.RenderJsonP(callback, re)
}
-func (c Blog) Report(noteId, commentId, reason string) revel.Result {
+// 显示分类的最近博客, jsonp
+func (c Blog) ListCateLatest(notebookId, callback string) revel.Result {
+ if notebookId == "" {
+ return c.e404("")
+ }
+ // 自定义域名
+ hasDomain, userBlog := c.domain()
+ userId := ""
+ if hasDomain {
+ userId = userBlog.UserId.Hex()
+ }
+
+ var notebook info.Notebook
+ notebook = notebookService.GetNotebookById(notebookId)
+ if !notebook.IsBlog {
+ return c.e404(userBlog.ThemePath)
+ }
+ if userId != "" && userId != notebook.UserId.Hex() {
+ return c.e404(userBlog.ThemePath)
+ }
+ userId = notebook.UserId.Hex()
+
+ var ok = false
+ if ok, userBlog = c.blogCommon(userId, userBlog, info.User{}); !ok {
+ return c.e404(userBlog.ThemePath)
+ }
+
+ // 分页的话, 需要分页信息, totalPage, curPage
+ page := 1
+ _, blogs := blogService.ListBlogs(userId, notebookId, page, 5, userBlog.SortField, userBlog.IsAsc)
re := info.NewRe()
- re.Ok = blogService.Report(noteId, commentId, reason, c.GetUserId());
- return c.RenderJson(re)
-}
\ No newline at end of file
+ re.Ok = true
+ re.List = blogs
+ return c.RenderJsonP(callback, re)
+}
diff --git a/app/controllers/FileController.go b/app/controllers/FileController.go
index e8609bd..7e4a4b7 100644
--- a/app/controllers/FileController.go
+++ b/app/controllers/FileController.go
@@ -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
@@ -314,4 +327,4 @@ func (c File) UploadImage(renderHtml string) revel.Result {
func (c File) UploadImageJson(from, noteId string) revel.Result {
re := c.uploadImage(from, "");
return c.RenderJson(re)
-}
\ No newline at end of file
+}
diff --git a/app/controllers/IndexController.go b/app/controllers/IndexController.go
index b6a86a6..bc4b86d 100644
--- a/app/controllers/IndexController.go
+++ b/app/controllers/IndexController.go
@@ -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"]
diff --git a/app/controllers/NoteController.go b/app/controllers/NoteController.go
index 6811c3f..d0c7bcb 100644
--- a/app/controllers/NoteController.go
+++ b/app/controllers/NoteController.go
@@ -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 == "" {
@@ -350,4 +354,10 @@ func (c Note) Html2Image(noteId string) revel.Result {
}
*/
-}
\ No newline at end of file
+}
+
+// 设置/取消Blog; 置顶
+func (c Note) SetNote2Blog(noteId string, isBlog, isTop bool) revel.Result {
+ re := noteService.ToBlog(c.GetUserId(), noteId, isBlog, isTop)
+ return c.RenderJson(re)
+}
diff --git a/app/controllers/NotebookController.go b/app/controllers/NotebookController.go
index d09d95a..db1d7d9 100644
--- a/app/controllers/NotebookController.go
+++ b/app/controllers/NotebookController.go
@@ -68,4 +68,10 @@ func (c Notebook) DragNotebooks(data string) revel.Result {
json.Unmarshal([]byte(data), &info)
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)
}
\ No newline at end of file
diff --git a/app/controllers/PreviewController.go b/app/controllers/PreviewController.go
new file mode 100644
index 0000000..03cfca9
--- /dev/null
+++ b/app/controllers/PreviewController.go
@@ -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(""))
+}
\ No newline at end of file
diff --git a/app/controllers/ShareController.go b/app/controllers/ShareController.go
index 15dc17c..9630b0b 100644
--- a/app/controllers/ShareController.go
+++ b/app/controllers/ShareController.go
@@ -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
@@ -139,4 +144,45 @@ func (c Share) DeleteShareNotebookBySharedUser(notebookId string, fromUserId str
// 删除fromUserId分享给我的所有note, notebook
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)
}
\ No newline at end of file
diff --git a/app/controllers/admin/AdminBlogController.go b/app/controllers/admin/AdminBlogController.go
index 9843938..ca8a48d 100644
--- a/app/controllers/admin/AdminBlogController.go
+++ b/app/controllers/admin/AdminBlogController.go
@@ -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
@@ -27,4 +27,4 @@ func (c AdminBlog) SetRecommend(noteId string, recommend bool) revel.Result {
re := info.NewRe()
re.Ok = blogService.SetRecommend(noteId, recommend);
return c.RenderJson(re)
-}
\ No newline at end of file
+}
diff --git a/app/controllers/admin/AdminController.go b/app/controllers/admin/AdminController.go
index 5bdc5e8..c3215a5 100644
--- a/app/controllers/admin/AdminController.go
+++ b/app/controllers/admin/AdminController.go
@@ -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")
}
diff --git a/app/controllers/admin/AdminSettingController.go b/app/controllers/admin/AdminSettingController.go
index e46c58d..8a4ce51 100644
--- a/app/controllers/admin/AdminSettingController.go
+++ b/app/controllers/admin/AdminSettingController.go
@@ -5,6 +5,7 @@ import (
// . "github.com/leanote/leanote/app/lea"
"github.com/leanote/leanote/app/info"
"strings"
+ "fmt"
)
// admin 首页
@@ -110,10 +111,28 @@ 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)
re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "mongorestorePath", mongorestorePath)
+ return c.RenderJson(re)
+}
+
+func (c AdminSetting) UploadSize(uploadImageSize, uploadAvatarSize, uploadBlogLogoSize, uploadAttachSize float64) revel.Result {
+ re := info.NewRe()
+ re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadImageSize", fmt.Sprintf("%v", uploadImageSize))
+ re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadAvatarSize", fmt.Sprintf("%v", uploadAvatarSize))
+ re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadBlogLogoSize", fmt.Sprintf("%v", uploadBlogLogoSize))
+ re.Ok = configService.UpdateGlobalStringConfig(c.GetUserId(), "uploadAttachSize", fmt.Sprintf("%v", uploadAttachSize))
return c.RenderJson(re)
}
\ No newline at end of file
diff --git a/app/controllers/admin/AdminUpgradeController.go b/app/controllers/admin/AdminUpgradeController.go
index c8dc206..3835d68 100644
--- a/app/controllers/admin/AdminUpgradeController.go
+++ b/app/controllers/admin/AdminUpgradeController.go
@@ -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"
)
@@ -15,4 +15,10 @@ type AdminUpgrade struct {
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)
}
\ No newline at end of file
diff --git a/app/controllers/admin/AdminUserController.go b/app/controllers/admin/AdminUserController.go
index 1ab80a0..e44eb4f 100644
--- a/app/controllers/admin/AdminUserController.go
+++ b/app/controllers/admin/AdminUserController.go
@@ -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)
+}
\ No newline at end of file
diff --git a/app/controllers/admin/init.go b/app/controllers/admin/init.go
index c151864..bcd964c 100644
--- a/app/controllers/admin/init.go
+++ b/app/controllers/admin/init.go
@@ -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 // 已登录
}
@@ -129,4 +128,4 @@ func init() {
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &AdminEmail{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &AdminUpgrade{})
revel.InterceptFunc(AuthInterceptor, revel.BEFORE, &AdminData{})
-}
\ No newline at end of file
+}
diff --git a/app/controllers/init.go b/app/controllers/init.go
index 19f00a2..11c1761 100644
--- a/app/controllers/init.go
+++ b/app/controllers/init.go
@@ -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"
@@ -19,53 +20,57 @@ 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 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 sessionService *service.SessionService
+var themeService *service.ThemeService
var pageSize = 1000
var defaultSortField = "UpdatedTime"
-var leanoteUserId = "admin" // 不能更改
-var siteUrl = "http://leanote.com"
// 拦截器
// 不需要拦截的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,
- },
+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,
+},
"Note": map[string]bool{"ToImage": true},
"Blog": map[string]bool{"Index": true,
- "View": true,
- "AboutMe": true,
- "Cate": true,
- "Search": true,
+ "View": true,
+ "AboutMe": true,
+ "Cate": true,
+ "ListCateLatest": true,
+ "Search": true,
"GetLikeAndComments": true,
- "IncReadNum": true,
- "ListComments": true,
- },
+ "IncReadNum": true,
+ "ListComments": true,
+ "Single": true,
+ "Archive": true,
+ "Tags": true,
+ },
// 用户的激活与修改邮箱都不需要登录, 通过链接地址
"User": map[string]bool{"UpdateEmail": true,
- "ActiveEmail":true,
- },
- "Oauth": map[string]bool{"GithubCallback": true},
- "File": map[string]bool{"OutputImage": true, "OutputFile": 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 {
@@ -76,31 +81,31 @@ func needValidate(controller, method string) bool {
return true
} else {
// controller不在这里的, 肯定要验证
- return true;
+ 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 userId, ok := c.Session["UserId"]; ok && userId != "" {
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")
}
@@ -118,7 +123,7 @@ func InitService() {
tokenService = service.TokenS
noteImageService = service.NoteImageS
fileService = service.FileS
- albumService= service.AlbumS
+ albumService = service.AlbumS
attachService = service.AttachS
pwdService = service.PwdS
suggestionService = service.SuggestionS
@@ -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()
})
-}
\ No newline at end of file
+}
diff --git a/app/controllers/member/MemberBaseController.go b/app/controllers/member/MemberBaseController.go
new file mode 100644
index 0000000..2fac5f4
--- /dev/null
+++ b/app/controllers/member/MemberBaseController.go
@@ -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)
+ }
+}
\ No newline at end of file
diff --git a/app/controllers/member/MemberBlogController.go b/app/controllers/member/MemberBlogController.go
new file mode 100644
index 0000000..daa75b5
--- /dev/null
+++ b/app/controllers/member/MemberBlogController.go
@@ -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)
+}
diff --git a/app/controllers/member/MemberGroupController.go b/app/controllers/member/MemberGroupController.go
new file mode 100644
index 0000000..815857d
--- /dev/null
+++ b/app/controllers/member/MemberGroupController.go
@@ -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)
+}
diff --git a/app/controllers/member/MemberIndexController.go b/app/controllers/member/MemberIndexController.go
new file mode 100644
index 0000000..6393450
--- /dev/null
+++ b/app/controllers/member/MemberIndexController.go
@@ -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);
+}
\ No newline at end of file
diff --git a/app/controllers/member/MemberUserController.go b/app/controllers/member/MemberUserController.go
new file mode 100644
index 0000000..4fdb2eb
--- /dev/null
+++ b/app/controllers/member/MemberUserController.go
@@ -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");
+}
\ No newline at end of file
diff --git a/app/controllers/member/init.go b/app/controllers/member/init.go
new file mode 100644
index 0000000..d891db2
--- /dev/null
+++ b/app/controllers/member/init.go
@@ -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() {
+ })
+}
diff --git a/app/controllers/member/个人中心.md b/app/controllers/member/个人中心.md
new file mode 100644
index 0000000..ab0218f
--- /dev/null
+++ b/app/controllers/member/个人中心.md
@@ -0,0 +1,2 @@
+包括基本信息设置
+博客设置
diff --git a/app/db/Mgo.go b/app/db/Mgo.go
index 55c2326..37b0bdb 100644
--- a/app/db/Mgo.go
+++ b/app/db/Mgo.go
@@ -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 {
@@ -66,9 +71,9 @@ func Init() {
if username == "" || password == "" {
usernameAndPassword = ""
}
- url = "mongodb://" + usernameAndPassword + host + ":" + port + "/" + dbname
+ url = "mongodb://" + usernameAndPassword + host + ":" + port + "/" + dbname
}
-
+
// [mongodb://][user:pass@]host1[:port1][,host2[:port2],...][/database][?options]
// mongodb://myuser:mypass@localhost:40001,otherhost:40001/mydb
var err error
@@ -82,55 +87,61 @@ func Init() {
// notebook
Notebooks = Session.DB(dbname).C("notebooks")
-
+
// notes
Notes = Session.DB(dbname).C("notes")
-
+
// noteContents
NoteContents = Session.DB(dbname).C("note_contents")
NoteContentHistories = Session.DB(dbname).C("note_content_histories")
-
+
// share
ShareNotes = Session.DB(dbname).C("share_notes")
ShareNotebooks = Session.DB(dbname).C("share_notebooks")
HasShareNotes = Session.DB(dbname).C("has_share_notes")
-
+
// 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")
-
+
// Suggestion
Suggestions = Session.DB(dbname).C("suggestions")
-
+
// Album & file
Albums = Session.DB(dbname).C("albums")
Files = Session.DB(dbname).C("files")
Attachs = Session.DB(dbname).C("attachs")
-
+
NoteImages = Session.DB(dbname).C("note_images")
-
+
Configs = Session.DB(dbname).C("configs")
EmailLogs = Session.DB(dbname).C("email_logs")
-
+
// 社交
BlogLikes = Session.DB(dbname).C("blog_likes")
BlogComments = Session.DB(dbname).C("blog_comments")
-
+
// 举报
Reports = Session.DB(dbname).C("reports")
-
+
// session
Sessions = Session.DB(dbname).C("sessions")
}
@@ -174,22 +185,29 @@ func UpdateByIdAndUserId2(collection *mgo.Collection, id, userId bson.ObjectId,
return Err(err)
}
func UpdateByIdAndUserIdField(collection *mgo.Collection, id, userId, field string, value interface{}) bool {
- return UpdateByIdAndUserId(collection, id, userId, bson.M{"$set": bson.M{field:value}})
+ return UpdateByIdAndUserId(collection, id, userId, bson.M{"$set": bson.M{field: value}})
}
func UpdateByIdAndUserIdMap(collection *mgo.Collection, id, userId string, v bson.M) bool {
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}})
+ 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,9 +327,9 @@ func Err(err error) bool {
fmt.Println(err)
// 删除时, 查找
if err.Error() == "not found" {
- return true;
+ return true
}
return false
}
return true
-}
\ No newline at end of file
+}
diff --git a/app/info/BlogCustom.go b/app/info/BlogCustom.go
new file mode 100644
index 0000000..c309c21
--- /dev/null
+++ b/app/info/BlogCustom.go
@@ -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
+}
diff --git a/app/info/BlogInfo.go b/app/info/BlogInfo.go
index 976c24f..24dafae 100644
--- a/app/info/BlogInfo.go
+++ b/app/info/BlogInfo.go
@@ -9,6 +9,7 @@ import (
type BlogItem struct {
Note
+ Abstract string
Content string // 可能是content的一部分, 截取. 点击more后就是整个信息了
HasMore bool // 是否是否还有
User User // 用户信息
@@ -18,13 +19,13 @@ type UserBlogBase struct {
Logo string `Logo`
Title string `Title` // 标题
SubTitle string `SubTitle` // 副标题
- AboutMe string `AboutMe` // 关于我
+// AboutMe string `AboutMe` // 关于我
}
type UserBlogComment struct {
- CanComment bool `CanComment` // 是否可以评论
+ CanComment bool `CanComment` // 是否可以评论
CommentType string `CommentType` // default 或 disqus
- DisqusId string `DisqusId`
+ DisqusId string `DisqusId`
}
type UserBlogStyle struct {
@@ -38,18 +39,48 @@ type UserBlog struct {
Logo string `Logo`
Title string `Title` // 标题
SubTitle string `SubTitle` // 副标题
- AboutMe string `AboutMe` // 关于我
+ AboutMe string `AboutMe` // 关于我, 弃用
+
+ CanComment bool `CanComment` // 是否可以评论
- CanComment bool `CanComment` // 是否可以评论
-
CommentType string `CommentType` // default 或 disqus
- DisqusId string `DisqusId`
+ DisqusId string `DisqusId`
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
+}
diff --git a/app/info/GroupInfo.go b/app/info/GroupInfo.go
new file mode 100644
index 0000000..e75b352
--- /dev/null
+++ b/app/info/GroupInfo.go
@@ -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`
+}
diff --git a/app/info/NoteInfo.go b/app/info/NoteInfo.go
index e8560e0..a1bce49 100644
--- a/app/info/NoteInfo.go
+++ b/app/info/NoteInfo.go
@@ -20,9 +20,11 @@ type Note struct {
IsTrash bool `IsTrash` // 是否是trash, 默认是false
- IsBlog bool `IsBlog,omitempty` // 是否设置成了blog 2013/12/29 新加
- IsRecommend bool `IsRecommend,omitempty` // 是否为推荐博客 2014/9/24新加
- IsTop bool `IsTop,omitempty` // blog是否置顶
+ 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
@@ -35,9 +37,9 @@ type Note struct {
CreatedTime time.Time `CreatedTime`
UpdatedTime time.Time `UpdatedTime`
- RecommendTime time.Time `RecommendTime,omitempty` // 推荐时间
- PublicTime time.Time `PublicTime,omitempty` // 发表时间, 公开为博客则设置
- UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
+ RecommendTime time.Time `RecommendTime,omitempty` // 推荐时间
+ PublicTime time.Time `PublicTime,omitempty` // 发表时间, 公开为博客则设置
+ UpdatedUserId bson.ObjectId `bson:"UpdatedUserId"` // 如果共享了, 并可写, 那么可能是其它他修改了
}
// 内容
diff --git a/app/info/NotebookInfo.go b/app/info/NotebookInfo.go
index 8275c9f..8d0db19 100644
--- a/app/info/NotebookInfo.go
+++ b/app/info/NotebookInfo.go
@@ -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 新加
diff --git a/app/info/ShareNotebookNoteInfo.go b/app/info/ShareNotebookNoteInfo.go
index dfea67b..401b720 100644
--- a/app/info/ShareNotebookNoteInfo.go
+++ b/app/info/ShareNotebookNoteInfo.go
@@ -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`
diff --git a/app/info/TagInfo.go b/app/info/TagInfo.go
index b8ab389..722bd5f 100644
--- a/app/info/TagInfo.go
+++ b/app/info/TagInfo.go
@@ -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`
-}
\ No newline at end of file
+}
+
+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]
+}
+*/
\ No newline at end of file
diff --git a/app/info/ThemeInfo.go b/app/info/ThemeInfo.go
new file mode 100644
index 0000000..886cce3
--- /dev/null
+++ b/app/info/ThemeInfo.go
@@ -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`
+}
diff --git a/app/info/UserInfo.go b/app/info/UserInfo.go
index 104069e..7d4e49d 100644
--- a/app/info/UserInfo.go
+++ b/app/info/UserInfo.go
@@ -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 // 各个页面
}
diff --git a/app/info/common.go b/app/info/common.go
index 3ea4521..25ef0e0 100644
--- a/app/info/common.go
+++ b/app/info/common.go
@@ -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}
-}
\ No newline at end of file
+ return Page{page, totalPage, perPageSize, count, list}
+}
diff --git a/app/init.go b/app/init.go
index 10e94f9..a0cb922 100644
--- a/app/init.go
+++ b/app/init.go
@@ -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()
})
-}
\ No newline at end of file
+}
diff --git a/app/lea/File.go b/app/lea/File.go
index d3d54f9..20e245f 100644
--- a/app/lea/File.go
+++ b/app/lea/File.go
@@ -1,10 +1,11 @@
package lea
import (
- "strings"
- "path/filepath"
- "os"
"io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
)
// 分离文件名与扩展名(包含.)
@@ -14,14 +15,14 @@ func SplitFilename(filename string) (baseName, ext string) {
ext = SubstringByte(filename, strings.LastIndex(filename, "."))
baseName = strings.TrimRight(filename, ext)
ext = strings.ToLower(ext)
- return;
+ return
}
// 转换文件的格式
// toExt包含.
func TransferExt(path string, toExt string) string {
- dir := filepath.Dir(path) + "/" // 文件路径
- name := filepath.Base(path) // 文件名 a.jpg
+ dir := filepath.Dir(path) + "/" // 文件路径
+ name := filepath.Base(path) // 文件名 a.jpg
// 获取文件名与路径
baseName, _ := SplitFilename(name)
return dir + baseName + toExt
@@ -38,7 +39,7 @@ func GetFilesize(path string) int64 {
if err == nil {
return fileinfo.Size()
}
- return 0;
+ return 0
}
// 清空dir下所有的文件和文件夹
@@ -79,12 +80,103 @@ 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 {
- return os.IsExist(err)
- }else{
- return fi.IsDir()
- }
- return false
-}
\ No newline at end of file
+ fi, err := os.Stat(path)
+ if err != nil {
+ return os.IsExist(err)
+ } else {
+ return fi.IsDir()
+ }
+ 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
+}
diff --git a/app/lea/Vd.go b/app/lea/Vd.go
index 4adcf12..6dcf409 100644
--- a/app/lea/Vd.go
+++ b/app/lea/Vd.go
@@ -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 == "" {
diff --git a/app/lea/archive/tar.go b/app/lea/archive/tar.go
new file mode 100644
index 0000000..3bb914f
--- /dev/null
+++ b/app/lea/archive/tar.go
@@ -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)
+}
\ No newline at end of file
diff --git a/app/lea/archive/zip.go b/app/lea/archive/zip.go
new file mode 100644
index 0000000..c1a705c
--- /dev/null
+++ b/app/lea/archive/zip.go
@@ -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
+}
\ No newline at end of file
diff --git a/app/lea/blog/Template.go b/app/lea/blog/Template.go
new file mode 100644
index 0000000..7586788
--- /dev/null
+++ b/app/lea/blog/Template.go
@@ -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)
+// }
+}
\ No newline at end of file
diff --git a/app/lea/netutil/NetUtil.go b/app/lea/netutil/NetUtil.go
index 9cf4ff3..c27af89 100644
--- a/app/lea/netutil/NetUtil.go
+++ b/app/lea/netutil/NetUtil.go
@@ -3,6 +3,7 @@ import (
"strings"
"os"
// "path/filepath"
+ "net"
"net/http"
"io/ioutil"
. "github.com/leanote/leanote/app/lea"
@@ -89,4 +90,13 @@ func trimQueryParams(url string) string {
url = Substr(url, 0, pos);
}
return url;
+}
+
+// 通过domain得到ip
+func GetIpFromDomain(domain string) string {
+ ip, _ := net.LookupIP(domain)
+ if ip != nil && len(ip) > 0 {
+ return ip[0].String()
+ }
+ return ""
}
\ No newline at end of file
diff --git a/app/lea/route/Route.go b/app/lea/route/Route.go
index 386d74b..595a529 100644
--- a/app/lea/route/Route.go
+++ b/app/lea/route/Route.go
@@ -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
}
diff --git a/app/service/AuthService.go b/app/service/AuthService.go
index 1d4e66a..6e4fd24 100644
--- a/app/service/AuthService.go
+++ b/app/service/AuthService.go
@@ -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, ""
diff --git a/app/service/BlogService.go b/app/service/BlogService.go
index 4ca78fd..789a519 100644
--- a/app/service/BlogService.go
+++ b/app/service/BlogService.go
@@ -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"
+ // "time"
+ // "sort"
+ "strconv"
"strings"
"time"
)
@@ -30,20 +31,40 @@ 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
}
-
+
// 内容
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,19 +77,19 @@ 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);
-
- if(notes == nil || len(notes) == 0) {
- return 0, nil
+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 info.Page{}, nil
}
-
+
// 得到content, 并且每个都要substring
noteIds := make([]bson.ObjectId, len(notes))
for i, note := range notes {
noteIds[i] = note.NoteId
}
-
+
// 直接得到noteContents表的abstract
// 这里可能是乱序的
noteContents := noteService.ListNoteAbstractsByNoteIds(noteIds) // 返回[info.NoteContent]
@@ -76,97 +97,361 @@ func (this *BlogService) ListBlogs(userId, notebookId string, page, pageSize int
for _, noteContent := range noteContents {
noteContentsMap[noteContent.NoteId] = noteContent
}
-
+
// 组装成blogItem
// 按照notes的顺序
blogs := make([]info.BlogItem, len(noteIds))
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{}}
+ blogs[i] = info.BlogItem{note, abstract, content, hasMore, info.User{}}
}
- return count, blogs
+
+ pageInfo := info.NewPage(page, pageSize, count, nil)
+
+ return pageInfo, blogs
}
-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);
-
- if(notes == nil || len(notes) == 0) {
- return 0, nil
+// 得到博客的标签, 那得先得到所有博客, 比较慢
+/*
+[
+ {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 {
noteIds[i] = note.NoteId
}
-
+
// 直接得到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
}
-
+
// 组装成blogItem
// 按照notes的顺序
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{}
-
+
skipNum, sortFieldR := parsePageAndSort(page, pageSize, sorterField, isAsc)
-
+
// 不是trash的
- query := bson.M{"IsTrash": false, "IsBlog": true, "Title": bson.M{"$ne":"欢迎来到leanote!"}}
+ query := bson.M{"IsTrash": false, "IsBlog": true, "Title": bson.M{"$ne": "欢迎来到leanote!"}}
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)}
}
-
+
if isRecommend {
query["IsRecommend"] = isRecommend
}
if keywords != "" {
query["Title"] = bson.M{"$regex": bson.RegEx{".*?" + keywords + ".*", "i"}}
}
- q := db.Notes.Find(query);
-
+ q := db.Notes.Find(query)
+
// 总记录数
count, _ := q.Count()
-
+
q.Sort(sortFieldR).
Skip(skipNum).
Limit(pageSize).
All(¬es)
-
- if(notes == nil || len(notes) == 0) {
+
+ if notes == nil || len(notes) == 0 {
return pageInfo, nil
}
-
+
// 得到content, 并且每个都要substring
noteIds := make([]bson.ObjectId, len(notes))
userIds := make([]bson.ObjectId, len(notes))
@@ -174,21 +459,21 @@ func (this *BlogService) ListAllBlogs(tag string, keywords string, isRecommend b
noteIds[i] = note.NoteId
userIds[i] = note.UserId
}
-
+
// 可以不要的
// 直接得到noteContents表的abstract
// 这里可能是乱序的
/*
- noteContents := noteService.ListNoteAbstractsByNoteIds(noteIds) // 返回[info.NoteContent]
- noteContentsMap := make(map[bson.ObjectId]info.NoteContent, len(noteContents))
- for _, noteContent := range noteContents {
- noteContentsMap[noteContent.NoteId] = noteContent
- }
+ noteContents := noteService.ListNoteAbstractsByNoteIds(noteIds) // 返回[info.NoteContent]
+ noteContentsMap := make(map[bson.ObjectId]info.NoteContent, len(noteContents))
+ for _, noteContent := range noteContents {
+ noteContentsMap[noteContent.NoteId] = noteContent
+ }
*/
-
+
// 得到用户信息
userMap := userService.MapUserInfoAndBlogInfosByUserIds(userIds)
-
+
// 组装成blogItem
// 按照notes的顺序
blogs := make([]info.BlogItem, len(noteIds))
@@ -196,32 +481,41 @@ func (this *BlogService) ListAllBlogs(tag string, keywords string, isRecommend b
hasMore := true
var content string
/*
- if noteContent, ok := noteContentsMap[note.NoteId]; ok {
- content = noteContent.Abstract
- }
+ if noteContent, ok := noteContentsMap[note.NoteId]; ok {
+ 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)
-
+
return pageInfo, blogs
}
//------------------------
// 博客设置
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,40 +581,40 @@ 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()
if count == 0 {
return nil, false
}
-
+
if isAll {
q.Sort(sortFieldR).Skip(skipNum).Limit(pageSize).All(&likes)
} else {
q.Sort(sortFieldR).All(&likes)
}
-
+
// 得到所有userIds
userIds := make([]bson.ObjectId, len(likes))
for i, like := range likes {
userIds[i] = like.UserId
}
// 得到用户信息
- userMap := userService.MapUserInfoAndBlogInfosByUserIds(userIds)
-
- users := make([]info.User, len(likes));
+ userMap := userService.MapUserAndBlogByUserIds(userIds)
+
+ 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
}
@@ -326,14 +643,14 @@ func (this *BlogService) LikeBlog(noteId, userId string) (ok bool, isLike bool)
ok = false
isLike = false
if noteId == "" || userId == "" {
- return
+ return
}
// 判断是否点过赞, 如果点过那么取消点赞
note := noteService.GetNoteById(noteId)
- if !note.IsBlog /*|| note.UserId.Hex() == userId */{
- return
+ if !note.IsBlog /*|| note.UserId.Hex() == userId */ {
+ return
}
-
+
noteIdO := bson.ObjectIdHex(noteId)
userIdO := bson.ObjectIdHex(userId)
var n int
@@ -349,7 +666,7 @@ func (this *BlogService) LikeBlog(noteId, userId string) (ok bool, isLike bool)
isLike = false
}
ok = db.Update(db.Notes, bson.M{"_id": noteIdO}, bson.M{"$inc": bson.M{"LikeNum": n}})
-
+
return
}
@@ -361,16 +678,16 @@ func (this *BlogService) Comment(noteId, toCommentId, userId, content string) (b
if content == "" {
return false, comment
}
-
+
note := noteService.GetNoteById(noteId)
if !note.IsBlog {
return false, comment
}
- comment = info.BlogComment{CommentId: bson.NewObjectId(),
- NoteId: bson.ObjectIdHex(noteId),
- UserId: bson.ObjectIdHex(userId),
- Content: content,
+ comment = info.BlogComment{CommentId: bson.NewObjectId(),
+ NoteId: bson.ObjectIdHex(noteId),
+ UserId: bson.ObjectIdHex(userId),
+ Content: content,
CreatedTime: time.Now(),
}
var comment2 = info.BlogComment{}
@@ -389,44 +706,44 @@ func (this *BlogService) Comment(noteId, toCommentId, userId, content string) (b
// 评论+1
db.Update(db.Notes, bson.M{"_id": bson.ObjectIdHex(noteId)}, bson.M{"$inc": bson.M{"CommentNum": 1}})
}
-
+
if userId != note.UserId.Hex() || toCommentId != "" {
go func() {
- this.sendEmail(note, comment2, userId, content);
+ this.sendEmail(note, comment2, userId, content)
}()
}
-
+
return ok, comment
}
// 发送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 := "评论提醒"
-
- // 表示回复回复的内容, 那么发送给之前回复的
- if comment.CommentId != "" {
- toUserId = comment.UserId.Hex()
- }
- toUserInfo := userService.GetUserInfo(toUserId)
- sendUserInfo := userService.GetUserInfo(userId)
-
- subject := note.Title + " 收到 " + sendUserInfo.Username + " 的评论";
- if comment.CommentId != "" {
- subject = "您在 " + note.Title + " 发表的评论收到 " + sendUserInfo.Username;
- if userId == note.UserId.Hex() {
- subject += "(作者)";
- }
- subject += " 的评论";
- }
+ toUserId := note.UserId.Hex()
+ // title := "评论提醒"
- body := "{header}评论内容:
" + content + ""; - href := "http://"+ configService.GetBlogDomain() + "/view/" + note.NoteId.Hex() - body += "
" + content + ""; + href := "http://"+ configService.GetBlogDomain() + "/view/" + note.NoteId.Hex() + body += "