From 789d46c340f2fdcf7bf54ca7700b464770aeae57 Mon Sep 17 00:00:00 2001 From: Dandy Cheung Date: Wed, 13 Dec 2017 00:40:01 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E5=AF=BC?= =?UTF-8?q?=E5=87=BA=E5=8D=95=E7=AF=87=E6=96=87=E6=A1=A3=E4=B8=BA=20PDF=20?= =?UTF-8?q?=E7=9A=84=E5=8A=9F=E8=83=BD=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TODO | 11 +++ controllers/document.go | 127 ++++++++++++++++++++++---------- routers/router.go | 3 +- views/document/default_read.tpl | 16 +++- 4 files changed, 115 insertions(+), 42 deletions(-) create mode 100644 TODO diff --git a/TODO b/TODO new file mode 100644 index 00000000..d3bf105e --- /dev/null +++ b/TODO @@ -0,0 +1,11 @@ +1、把 log 提取出 dbgout 之类的方法; +2、把源代码里的 TODO 完成; +3、Export 的两个 URL 应该可以合并,用是否有 :id 来区分;这样 0 号文档输出整个 book 更顺; +4、统一代码风格,空格、命名之类的; +5、美化 PDF 的输出格式; +6、自动登录新开标签页而且并不能跳转至起始请求页的问题; +7、用户分组管理; +8、[自动]展示历史版本;增强历史版本对比显示的能力; +9、[自动]展示作者信息;也许可以和上一需求合并考虑; +10、查看了解评论功能; + diff --git a/controllers/document.go b/controllers/document.go index 48023380..a5a9b98d 100644 --- a/controllers/document.go +++ b/controllers/document.go @@ -16,6 +16,8 @@ import ( "bytes" + "log" + "github.com/PuerkitoBio/goquery" "github.com/astaxie/beego" "github.com/astaxie/beego/orm" @@ -125,6 +127,9 @@ func (c *DocumentController) Index() { c.Data["Result"] = template.HTML(tree) c.Data["Title"] = "概要" c.Data["Content"] = template.HTML( blackfriday.MarkdownBasic([]byte(bookResult.Description))) + + c.Data["DocumentId"] = "0" // added by dandycheung, 2017-12-08, for exporting + log.Println("DocumentController.Index(): c.Data[\"DocumentId\"] = ", 0) } //阅读文档. @@ -134,6 +139,9 @@ func (c *DocumentController) Read() { token := c.GetString("token") id := c.GetString(":id") + c.Data["DocumentId"] = id // added by dandycheung, 2017-12-08, for exporting + log.Println("DocumentController.Read(): c.Data[\"DocumentId\"] = ", id, ", IsAjax = ", c.IsAjax()) + if identify == "" || id == "" { c.Abort("404") } @@ -735,8 +743,32 @@ func (c *DocumentController) Content() { c.JsonResult(0, "ok", doc) } -//导出文件 -func (c *DocumentController) Export() { +func (c *DocumentController) ExportDoc() { + c.Export(true) +} + +func (c *DocumentController) ExportBook() { + c.Export(false) +} + +func (c *DocumentController) GetDocumentById(id string) (doc *models.Document, err error) { + doc = models.NewDocument() + if doc_id, err := strconv.Atoi(id); err == nil { + doc, err = doc.Find(doc_id) + if err != nil { + return nil, err + } + } else { + doc, err = doc.FindByFieldFirst("identify", id) + if err != nil { + return nil, err + } + } + return doc, nil +} + +// 导出 +func (c *DocumentController) Export(single_doc bool) { c.Prepare() c.TplName = "document/export.tpl" @@ -791,10 +823,20 @@ func (c *DocumentController) Export() { pathList := list.New() - RecursiveFun(0, "", dpath, c, bookResult, docs, pathList) + // 增加对单页文档的导出,dandycheung, 2017-12-07 + if single_doc { + id := c.Ctx.Input.Param(":id") + if doc, err := c.GetDocumentById(id); err == nil { + EachFun("", dpath, c, bookResult, doc, pathList) + } + } else { + RecursiveFun(0, "", dpath, c, bookResult, docs, pathList) + } defer os.RemoveAll(dpath) + // TODO: check if the pathList is empty + os.MkdirAll("./cache", 0766) pdfpath := filepath.Join("cache", identify+"_"+c.CruSession.SessionID()+".pdf") @@ -1142,49 +1184,54 @@ func (c *DocumentController) Compare() { func RecursiveFun(parent_id int, prefix, dpath string, c *DocumentController, book *models.BookResult, docs []*models.Document, paths *list.List) { for _, item := range docs { if item.ParentId == parent_id { - name := prefix + strconv.Itoa(item.ParentId) + strconv.Itoa(item.OrderSort) + strconv.Itoa(item.DocumentId) - fpath := dpath + "/" + name + ".html" - paths.PushBack(fpath) - - f, err := os.OpenFile(fpath, os.O_CREATE|os.O_RDWR, 0777) - - if err != nil { - beego.Error(err) - c.Abort("500") - } - - html, err := c.ExecuteViewPathTemplate("document/export.tpl", map[string]interface{}{"Model": book, "Lists": item, "BaseUrl": c.BaseUrl()}) - if err != nil { - f.Close() - beego.Error(err) - c.Abort("500") - } - - buf := bytes.NewReader([]byte(html)) - doc, err := goquery.NewDocumentFromReader(buf) - doc.Find("img").Each(func(i int, contentSelection *goquery.Selection) { - if src, ok := contentSelection.Attr("src"); ok && strings.HasPrefix(src, "/uploads/") { - contentSelection.SetAttr("src", c.BaseUrl()+src) - } - }) - html, err = doc.Html() - - if err != nil { - f.Close() - beego.Error(err) - c.Abort("500") - } - //html = strings.Replace(html,"项目分享 -
  • 项目导出PDF
  • +
  • 文档导出为 PDF
  • +
  • 项目导出为 PDF
  • {{end}}
  • 返回首页
  • @@ -234,6 +235,13 @@ \ No newline at end of file From 292cf049e230e14b3ae7463fb675b87822d05e6e Mon Sep 17 00:00:00 2001 From: Dandy Cheung Date: Wed, 20 Dec 2017 16:16:41 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BA=86=E5=9C=A8?= =?UTF-8?q?=E6=AF=8F=E7=AF=87=E6=96=87=E6=A1=A3=E6=A0=87=E9=A2=98=E4=B8=8B?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E5=8E=9F=E5=A7=8B=E4=BD=9C=E8=80=85=E3=80=81?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=E6=97=B6=E9=97=B4=E5=92=8C=E6=9C=80=E5=90=8E?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=97=B6=E9=97=B4=E7=9A=84=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controllers/document.go | 72 ++++++++++------- routers/router.go | 138 ++++++++++++++++---------------- static/css/kancloud.css | 16 +++- static/js/kancloud.js | 2 + views/document/default_read.tpl | 1 + 5 files changed, 130 insertions(+), 99 deletions(-) diff --git a/controllers/document.go b/controllers/document.go index a5a9b98d..dbbb8c65 100644 --- a/controllers/document.go +++ b/controllers/document.go @@ -16,8 +16,6 @@ import ( "bytes" - "log" - "github.com/PuerkitoBio/goquery" "github.com/astaxie/beego" "github.com/astaxie/beego/orm" @@ -126,10 +124,11 @@ func (c *DocumentController) Index() { c.Data["Model"] = bookResult c.Data["Result"] = template.HTML(tree) c.Data["Title"] = "概要" - c.Data["Content"] = template.HTML( blackfriday.MarkdownBasic([]byte(bookResult.Description))) + c.Data["Content"] = template.HTML(blackfriday.MarkdownBasic([]byte(bookResult.Description))) + c.Data["Info"] = "" - c.Data["DocumentId"] = "0" // added by dandycheung, 2017-12-08, for exporting - log.Println("DocumentController.Index(): c.Data[\"DocumentId\"] = ", 0) + c.Data["DocumentId"] = "0" // added by dandycheung, 2017-12-08, for exporting + beego.Info("DocumentController.Index(): c.Data[\"DocumentId\"] = ", 0) } //阅读文档. @@ -139,8 +138,8 @@ func (c *DocumentController) Read() { token := c.GetString("token") id := c.GetString(":id") - c.Data["DocumentId"] = id // added by dandycheung, 2017-12-08, for exporting - log.Println("DocumentController.Read(): c.Data[\"DocumentId\"] = ", id, ", IsAjax = ", c.IsAjax()) + c.Data["DocumentId"] = id // added by dandycheung, 2017-12-08, for exporting + beego.Info("DocumentController.Read(): c.Data[\"DocumentId\"] = ", id, ", IsAjax = ", c.IsAjax()) if identify == "" || id == "" { c.Abort("404") @@ -200,15 +199,33 @@ func (c *DocumentController) Read() { } } + + // assemble doc info, added by dandycheung, 2017-12-20 + docInfo := "" + docCreator, err := models.NewMember().Find(doc.MemberId) + if err == nil { + docInfo += docCreator.Account + } + + docInfo += " 创建于 " + docInfo += doc.CreateTime.Format("2006-01-02 15:04") + + if doc.ModifyTime != doc.CreateTime { + docInfo += ";更新于 " + docInfo += doc.ModifyTime.Format("2006-01-02 15:04") + } + if c.IsAjax() { var data struct { DocTitle string `json:"doc_title"` Body string `json:"body"` Title string `json:"title"` + DocInfo string `json:"doc_info"` } data.DocTitle = doc.DocumentName data.Body = doc.Release data.Title = doc.DocumentName + " - Powered by MinDoc" + data.DocInfo = docInfo c.JsonResult(0, "ok", data) } @@ -223,6 +240,7 @@ func (c *DocumentController) Read() { c.Data["Model"] = bookResult c.Data["Result"] = template.HTML(tree) c.Data["Title"] = doc.DocumentName + c.Data["Info"] = docInfo c.Data["Content"] = template.HTML(doc.Release) } @@ -753,17 +771,17 @@ func (c *DocumentController) ExportBook() { func (c *DocumentController) GetDocumentById(id string) (doc *models.Document, err error) { doc = models.NewDocument() - if doc_id, err := strconv.Atoi(id); err == nil { - doc, err = doc.Find(doc_id) - if err != nil { - return nil, err - } - } else { - doc, err = doc.FindByFieldFirst("identify", id) - if err != nil { + if doc_id, err := strconv.Atoi(id); err == nil { + doc, err = doc.Find(doc_id) + if err != nil { return nil, err - } - } + } + } else { + doc, err = doc.FindByFieldFirst("identify", id) + if err != nil { + return nil, err + } + } return doc, nil } @@ -1121,10 +1139,10 @@ func (c *DocumentController) RestoreHistory() { c.JsonResult(0, "ok", doc) } -func (c *DocumentController) Compare() { +func (c *DocumentController) Compare() { c.Prepare() c.TplName = "document/compare.tpl" - history_id ,_ := strconv.Atoi(c.Ctx.Input.Param(":id")) + history_id, _ := strconv.Atoi(c.Ctx.Input.Param(":id")) identify := c.Ctx.Input.Param(":key") book_id := 0 @@ -1155,18 +1173,18 @@ func (c *DocumentController) Compare() { } if history_id <= 0 { - c.ShowErrorPage(60002,"参数错误") + c.ShowErrorPage(60002, "参数错误") } - history,err := models.NewDocumentHistory().Find(history_id) + history, err := models.NewDocumentHistory().Find(history_id) if err != nil { - beego.Error("DocumentController.Compare => ",err) - c.ShowErrorPage(60003,err.Error()) + beego.Error("DocumentController.Compare => ", err) + c.ShowErrorPage(60003, err.Error()) } - doc,err := models.NewDocument().Find(history.DocumentId) + doc, err := models.NewDocument().Find(history.DocumentId) if doc.BookId != book_id { - c.ShowErrorPage(60002,"参数错误") + c.ShowErrorPage(60002, "参数错误") } c.Data["HistoryId"] = history_id c.Data["DocumentId"] = doc.DocumentId @@ -1174,7 +1192,7 @@ func (c *DocumentController) Compare() { if editor == "markdown" { c.Data["HistoryContent"] = history.Markdown c.Data["Content"] = doc.Markdown - }else{ + } else { c.Data["HistoryContent"] = template.HTML(history.Content) c.Data["Content"] = template.HTML(doc.Content) } @@ -1188,7 +1206,7 @@ func RecursiveFun(parent_id int, prefix, dpath string, c *DocumentController, bo for _, sub := range docs { if sub.ParentId == item.DocumentId { - prefix += strconv.Itoa(item.ParentId) + strconv.Itoa(item.OrderSort) + strconv.Itoa(item.DocumentId); + prefix += strconv.Itoa(item.ParentId) + strconv.Itoa(item.OrderSort) + strconv.Itoa(item.DocumentId) RecursiveFun(item.DocumentId, prefix, dpath, c, book, docs, paths) break } diff --git a/routers/router.go b/routers/router.go index 94ef8f25..65ea3408 100644 --- a/routers/router.go +++ b/routers/router.go @@ -5,87 +5,85 @@ import ( "github.com/lifei6671/mindoc/controllers" ) -func init() { - beego.Router("/",&controllers.HomeController{},"*:Index") +func init() { + beego.Router("/", &controllers.HomeController{}, "*:Index") - beego.Router("/login", &controllers.AccountController{},"*:Login") - beego.Router("/logout", &controllers.AccountController{},"*:Logout") - beego.Router("/register", &controllers.AccountController{},"*:Register") - beego.Router("/find_password", &controllers.AccountController{},"*:FindPassword") - beego.Router("/valid_email", &controllers.AccountController{},"post:ValidEmail") - beego.Router("/captcha", &controllers.AccountController{},"*:Captcha") + beego.Router("/login", &controllers.AccountController{}, "*:Login") + beego.Router("/logout", &controllers.AccountController{}, "*:Logout") + beego.Router("/register", &controllers.AccountController{}, "*:Register") + beego.Router("/find_password", &controllers.AccountController{}, "*:FindPassword") + beego.Router("/valid_email", &controllers.AccountController{}, "post:ValidEmail") + beego.Router("/captcha", &controllers.AccountController{}, "*:Captcha") - beego.Router("/manager", &controllers.ManagerController{},"*:Index") - beego.Router("/manager/users", &controllers.ManagerController{},"*:Users") - beego.Router("/manager/users/edit/:id", &controllers.ManagerController{},"*:EditMember") - beego.Router("/manager/member/create", &controllers.ManagerController{},"post:CreateMember") - beego.Router("/manager/member/delete", &controllers.ManagerController{},"post:DeleteMember") - beego.Router("/manager/member/update-member-status",&controllers.ManagerController{},"post:UpdateMemberStatus") - beego.Router("/manager/member/change-member-role", &controllers.ManagerController{},"post:ChangeMemberRole") - beego.Router("/manager/books", &controllers.ManagerController{},"*:Books") - beego.Router("/manager/books/edit/:key", &controllers.ManagerController{},"*:EditBook") - beego.Router("/manager/books/delete", &controllers.ManagerController{},"*:DeleteBook") - beego.Router("/manager/comments", &controllers.ManagerController{},"*:Comments") - beego.Router("/manager/books/token", &controllers.ManagerController{},"post:CreateToken") - beego.Router("/manager/setting",&controllers.ManagerController{},"*:Setting") - beego.Router("/manager/books/transfer", &controllers.ManagerController{},"post:Transfer") - beego.Router("/manager/books/open", &controllers.ManagerController{},"post:PrivatelyOwned") - beego.Router("/manager/attach/list", &controllers.ManagerController{},"*:AttachList") - beego.Router("/manager/attach/detailed/:id", &controllers.ManagerController{},"*:AttachDetailed") - beego.Router("/manager/attach/delete", &controllers.ManagerController{},"post:AttachDelete") + beego.Router("/manager", &controllers.ManagerController{}, "*:Index") + beego.Router("/manager/users", &controllers.ManagerController{}, "*:Users") + beego.Router("/manager/users/edit/:id", &controllers.ManagerController{}, "*:EditMember") + beego.Router("/manager/member/create", &controllers.ManagerController{}, "post:CreateMember") + beego.Router("/manager/member/delete", &controllers.ManagerController{}, "post:DeleteMember") + beego.Router("/manager/member/update-member-status", &controllers.ManagerController{}, "post:UpdateMemberStatus") + beego.Router("/manager/member/change-member-role", &controllers.ManagerController{}, "post:ChangeMemberRole") + beego.Router("/manager/books", &controllers.ManagerController{}, "*:Books") + beego.Router("/manager/books/edit/:key", &controllers.ManagerController{}, "*:EditBook") + beego.Router("/manager/books/delete", &controllers.ManagerController{}, "*:DeleteBook") + beego.Router("/manager/comments", &controllers.ManagerController{}, "*:Comments") + beego.Router("/manager/books/token", &controllers.ManagerController{}, "post:CreateToken") + beego.Router("/manager/setting", &controllers.ManagerController{}, "*:Setting") + beego.Router("/manager/books/transfer", &controllers.ManagerController{}, "post:Transfer") + beego.Router("/manager/books/open", &controllers.ManagerController{}, "post:PrivatelyOwned") + beego.Router("/manager/attach/list", &controllers.ManagerController{}, "*:AttachList") + beego.Router("/manager/attach/detailed/:id", &controllers.ManagerController{}, "*:AttachDetailed") + beego.Router("/manager/attach/delete", &controllers.ManagerController{}, "post:AttachDelete") + beego.Router("/setting", &controllers.SettingController{}, "*:Index") + beego.Router("/setting/password", &controllers.SettingController{}, "*:Password") + beego.Router("/setting/upload", &controllers.SettingController{}, "*:Upload") - beego.Router("/setting", &controllers.SettingController{},"*:Index") - beego.Router("/setting/password", &controllers.SettingController{},"*:Password") - beego.Router("/setting/upload", &controllers.SettingController{},"*:Upload") + beego.Router("/book", &controllers.BookController{}, "*:Index") + beego.Router("/book/:key/dashboard", &controllers.BookController{}, "*:Dashboard") + beego.Router("/book/:key/setting", &controllers.BookController{}, "*:Setting") + beego.Router("/book/:key/users", &controllers.BookController{}, "*:Users") + beego.Router("/book/:key/release", &controllers.BookController{}, "post:Release") + beego.Router("/book/:key/sort", &controllers.BookController{}, "post:SaveSort") - beego.Router("/book", &controllers.BookController{},"*:Index") - beego.Router("/book/:key/dashboard", &controllers.BookController{},"*:Dashboard") - beego.Router("/book/:key/setting", &controllers.BookController{},"*:Setting") - beego.Router("/book/:key/users", &controllers.BookController{},"*:Users") - beego.Router("/book/:key/release", &controllers.BookController{},"post:Release") - beego.Router("/book/:key/sort", &controllers.BookController{},"post:SaveSort") + beego.Router("/book/create", &controllers.BookController{}, "*:Create") + beego.Router("/book/users/create", &controllers.BookMemberController{}, "post:AddMember") + beego.Router("/book/users/change", &controllers.BookMemberController{}, "post:ChangeRole") + beego.Router("/book/users/delete", &controllers.BookMemberController{}, "post:RemoveMember") - beego.Router("/book/create", &controllers.BookController{},"*:Create") - beego.Router("/book/users/create", &controllers.BookMemberController{},"post:AddMember") - beego.Router("/book/users/change", &controllers.BookMemberController{},"post:ChangeRole") - beego.Router("/book/users/delete", &controllers.BookMemberController{},"post:RemoveMember") + beego.Router("/book/setting/save", &controllers.BookController{}, "post:SaveBook") + beego.Router("/book/setting/open", &controllers.BookController{}, "post:PrivatelyOwned") + beego.Router("/book/setting/transfer", &controllers.BookController{}, "post:Transfer") + beego.Router("/book/setting/upload", &controllers.BookController{}, "post:UploadCover") + beego.Router("/book/setting/token", &controllers.BookController{}, "post:CreateToken") + beego.Router("/book/setting/delete", &controllers.BookController{}, "post:Delete") - beego.Router("/book/setting/save", &controllers.BookController{},"post:SaveBook") - beego.Router("/book/setting/open", &controllers.BookController{},"post:PrivatelyOwned") - beego.Router("/book/setting/transfer", &controllers.BookController{},"post:Transfer") - beego.Router("/book/setting/upload", &controllers.BookController{},"post:UploadCover") - beego.Router("/book/setting/token", &controllers.BookController{},"post:CreateToken") - beego.Router("/book/setting/delete", &controllers.BookController{},"post:Delete") + beego.Router("/api/attach/remove/", &controllers.DocumentController{}, "post:RemoveAttachment") + beego.Router("/api/:key/edit/?:id", &controllers.DocumentController{}, "*:Edit") + beego.Router("/api/upload", &controllers.DocumentController{}, "post:Upload") + beego.Router("/api/:key/create", &controllers.DocumentController{}, "post:Create") + beego.Router("/api/:key/delete", &controllers.DocumentController{}, "post:Delete") + beego.Router("/api/:key/content/?:id", &controllers.DocumentController{}, "*:Content") + beego.Router("/api/:key/compare/:id", &controllers.DocumentController{}, "*:Compare") - beego.Router("/api/attach/remove/", &controllers.DocumentController{},"post:RemoveAttachment") - beego.Router("/api/:key/edit/?:id", &controllers.DocumentController{},"*:Edit") - beego.Router("/api/upload",&controllers.DocumentController{},"post:Upload") - beego.Router("/api/:key/create",&controllers.DocumentController{},"post:Create") - beego.Router("/api/:key/delete", &controllers.DocumentController{},"post:Delete") - beego.Router("/api/:key/content/?:id",&controllers.DocumentController{},"*:Content") - beego.Router("/api/:key/compare/:id", &controllers.DocumentController{},"*:Compare") + beego.Router("/history/get", &controllers.DocumentController{}, "get:History") + beego.Router("/history/delete", &controllers.DocumentController{}, "*:DeleteHistory") + beego.Router("/history/restore", &controllers.DocumentController{}, "*:RestoreHistory") - beego.Router("/history/get", &controllers.DocumentController{},"get:History") - beego.Router("/history/delete", &controllers.DocumentController{},"*:DeleteHistory") - beego.Router("/history/restore", &controllers.DocumentController{},"*:RestoreHistory") + beego.Router("/docs/:key", &controllers.DocumentController{}, "*:Index") + beego.Router("/docs/:key/:id", &controllers.DocumentController{}, "*:Read") + beego.Router("/docs/:key/search", &controllers.DocumentController{}, "post:Search") + beego.Router("/export/:key", &controllers.DocumentController{}, "*:ExportBook") + beego.Router("/export/:key/:id", &controllers.DocumentController{}, "*:ExportDoc") + beego.Router("/qrcode/:key.png", &controllers.DocumentController{}, "get:QrCode") - beego.Router("/docs/:key", &controllers.DocumentController{},"*:Index") - beego.Router("/docs/:key/:id", &controllers.DocumentController{},"*:Read") - beego.Router("/docs/:key/search", &controllers.DocumentController{},"post:Search") - beego.Router("/export/:key", &controllers.DocumentController{},"*:ExportBook") - beego.Router("/export/:key/:id", &controllers.DocumentController{},"*:ExportDoc") - beego.Router("/qrcode/:key.png",&controllers.DocumentController{},"get:QrCode") + beego.Router("/attach_files/:key/:attach_id", &controllers.DocumentController{}, "get:DownloadAttachment") - beego.Router("/attach_files/:key/:attach_id",&controllers.DocumentController{},"get:DownloadAttachment") + beego.Router("/comment/create", &controllers.CommentController{}, "post:Create") + beego.Router("/comment/lists", &controllers.CommentController{}, "get:Lists") + beego.Router("/comment/index", &controllers.CommentController{}, "*:Index") - beego.Router("/comment/create", &controllers.CommentController{},"post:Create") - beego.Router("/comment/lists", &controllers.CommentController{},"get:Lists") - beego.Router("/comment/index", &controllers.CommentController{},"*:Index") + beego.Router("/search", &controllers.SearchController{}, "get:Index") - beego.Router("/search",&controllers.SearchController{},"get:Index") - - beego.Router("/tag/:key", &controllers.LabelController{},"get:Index") - beego.Router("/tags", &controllers.LabelController{},"get:List") + beego.Router("/tag/:key", &controllers.LabelController{}, "get:Index") + beego.Router("/tags", &controllers.LabelController{}, "get:List") } - diff --git a/static/css/kancloud.css b/static/css/kancloud.css index 426b67d1..36dcd5b0 100644 --- a/static/css/kancloud.css +++ b/static/css/kancloud.css @@ -417,7 +417,8 @@ table>tbody>tr:hover{ } .manual-article .article-head { position: relative; - zoom:1;padding: 10px 20px + zoom: 1; + padding: 10px 20px } .manual-reader .book-title{ color: #333333; @@ -430,7 +431,7 @@ table>tbody>tr:hover{ .manual-article .article-head h1 { margin: 0; font-size: 20px; - font-weight: 200; + font-weight: 300; text-align: center; line-height: 30px; overflow: hidden; @@ -438,6 +439,17 @@ table>tbody>tr:hover{ white-space: nowrap; color: #444 } +.manual-article .article-head h3 { + margin: 0; + font-size: 12px; + font-weight: 200; + text-align: center; + line-height: 18px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + color: #444 +} .manual-article .article-content{ min-width: 980px; max-width: 98%; diff --git a/static/js/kancloud.js b/static/js/kancloud.js index a333e5ff..2d5e9a2e 100644 --- a/static/js/kancloud.js +++ b/static/js/kancloud.js @@ -33,6 +33,7 @@ function loadDocument($url,$id,$callback) { var body = res.data.body; var doc_title = res.data.doc_title; var title = res.data.title; + var doc_info = res.data.doc_info; $body = body; if (typeof $callback === "function" ){ @@ -41,6 +42,7 @@ function loadDocument($url,$id,$callback) { $("#page-content").html($body); $("title").text(title); $("#article-title").text(doc_title); + $("#article-info").text(doc_info); events.data('body_' + $id,body); events.data('title_' + $id,title); diff --git a/views/document/default_read.tpl b/views/document/default_read.tpl index d10a0ae7..c886ea72 100644 --- a/views/document/default_read.tpl +++ b/views/document/default_read.tpl @@ -128,6 +128,7 @@

    {{.Title}}

    +

    {{.Info}}

    From 9e2fbccc92ced93e489454f3f16b62bd803568af Mon Sep 17 00:00:00 2001 From: Dandy Cheung Date: Wed, 20 Dec 2017 18:55:17 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E4=BF=AE=E8=AE=A2=E5=9C=A8=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E4=BB=B6=E5=88=87=E6=8D=A2=E6=97=B6=E6=9C=89=E6=97=B6?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E4=BF=A1=E6=81=AF=E4=B8=8D=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/js/kancloud.js | 64 ++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/static/js/kancloud.js b/static/js/kancloud.js index 2d5e9a2e..03d74ec8 100644 --- a/static/js/kancloud.js +++ b/static/js/kancloud.js @@ -12,45 +12,49 @@ function loadDocument($url,$id,$callback) { var body = events.data('body_' + $id); var title = events.data('title_' + $id); var doc_title = events.data('doc_title_' + $id); + var doc_info = events.data('doc_info_' + $id); - if(body && title && doc_title){ - + if(body && title && doc_title) { if (typeof $callback === "function") { body = $callback(body); } + $("#page-content").html(body); $("title").text(title); $("#article-title").text(doc_title); + $("#article-info").text(doc_info); - events.trigger('article.open',{ $url : $url, $init : false , $id : $id }); + events.trigger('article.open', { $url : $url, $init : false , $id : $id }); return false; } NProgress.start(); }, success : function (res) { - if(res.errcode === 0){ + if (res.errcode === 0) { var body = res.data.body; var doc_title = res.data.doc_title; var title = res.data.title; var doc_info = res.data.doc_info; $body = body; - if (typeof $callback === "function" ){ + if (typeof $callback === "function" ) { $body = $callback(body); } + $("#page-content").html($body); $("title").text(title); $("#article-title").text(doc_title); $("#article-info").text(doc_info); - events.data('body_' + $id,body); - events.data('title_' + $id,title); - events.data('doc_title_' + $id,doc_title); + events.data('body_' + $id, body); + events.data('title_' + $id, title); + events.data('doc_title_' + $id, doc_title); + events.data('doc_info_' + $id, doc_info); - events.trigger('article.open',{ $url : $url, $init : true, $id : $id }); + events.trigger('article.open', { $url : $url, $init : true, $id : $id }); - }else{ + } else { layer.msg("加载失败"); } }, @@ -76,9 +80,9 @@ $(function () { }); $(".manual-right").scroll(function () { var top = $(".manual-right").scrollTop(); - if(top > 100){ + if (top > 100) { $(".view-backtop").addClass("active"); - }else{ + } else { $(".view-backtop").removeClass("active"); } }); @@ -87,7 +91,7 @@ $(function () { initHighlighting(); window.jsTree = $("#sidebar").jstree({ - 'plugins':["wholerow","types"], + 'plugins':["wholerow", "types"], "types": { "default" : { "icon" : false // 删除默认图标 @@ -95,24 +99,24 @@ $(function () { }, 'core' : { 'check_callback' : true, - "multiple" : false , + "multiple" : false, 'animation' : 0 } }).on('select_node.jstree',function (node,selected,event) { $(".m-manual").removeClass('manual-mobile-show-left'); var url = selected.node.a_attr.href; - if(url === window.location.href){ + if (url === window.location.href) { return false; } - loadDocument(url,selected.node.id); + loadDocument(url, selected.node.id); }); - $("#slidebar").on("click",function () { + $("#slidebar").on("click", function () { $(".m-manual").addClass('manual-mobile-show-left'); }); - $(".manual-mask").on("click",function () { + $(".manual-mask").on("click", function () { $(".m-manual").removeClass('manual-mobile-show-left'); }); @@ -128,19 +132,18 @@ $(function () { } }); - //处理打开事件 + // 处理打开事件 events.on('article.open', function (event, $param) { - if ('pushState' in history) { if ($param.$init === false) { - window.history.replaceState($param , $param.$id , $param.$url); + window.history.replaceState($param, $param.$id, $param.$url); } else { - window.history.pushState($param, $param.$id , $param.$url); + window.history.pushState($param, $param.$id, $param.$url); } - } else { window.location.hash = $param.$url; } + initHighlighting(); $(".manual-right").scrollTop(0); }); @@ -165,17 +168,17 @@ $(function () { $("#btnSearch").attr("disabled","disabled").find("i").removeClass("fa-search").addClass("loading"); window.keyword = keyword; }, - success :function (res) { + success : function (res) { var html = ""; if(res.errcode === 0){ for(var i in res.data){ var item = res.data[i]; - html += '
  • '+ item.doc_name +'
  • '; + html += '
  • ' + item.doc_name + '
  • '; } } - if(html !== ""){ + if(html !== "") { $(".search-empty").hide(); - }else{ + } else { $(".search-empty").show(); } $("#searchList").html(html); @@ -186,7 +189,6 @@ $(function () { }); window.onpopstate = function (e) { - var $param = e.state; console.log($param); if($param.hasOwnProperty("$url")) { @@ -194,8 +196,8 @@ $(function () { window.jsTree.jstree().select_node({ id : $param.$id }); $param.$init = false; - //events.trigger('article.open', $param ); - }else{ + // events.trigger('article.open', $param); + } else { console.log($param); } }; @@ -205,7 +207,7 @@ $(function () { $node = window.jsTree.jstree().get_node({id: $node[0]}); events.trigger('article.open', {$url: $node.a_attr.href, $init: true, $id: $node.a_attr.id}); } - }catch (e){ + } catch (e) { console.log(e); } }); \ No newline at end of file From 15ad23a0303673c46111d7c7b048121362705225 Mon Sep 17 00:00:00 2001 From: Dandy Cheung Date: Thu, 21 Dec 2017 15:27:57 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86=E9=80=80?= =?UTF-8?q?=E5=87=BA=E7=99=BB=E5=BD=95=E5=90=8E=E5=9C=A8=E5=B7=B2=E7=BB=8F?= =?UTF-8?q?=E6=89=93=E5=BC=80=E7=9A=84=E9=A1=B5=E9=9D=A2=E4=B8=8A=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E6=96=87=E6=A1=A3=E6=97=B6=E5=91=88=E7=8E=B0=E7=9A=84?= =?UTF-8?q?=E4=B8=80=E7=9B=B4=E5=A4=84=E4=BA=8E=E5=8A=A0=E8=BD=BD=E4=B8=AD?= =?UTF-8?q?=E7=9A=84=E5=81=87=E8=B1=A1=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TODO | 5 +- controllers/document.go | 291 +++++++++++++++++++++++++--------------- static/js/kancloud.js | 33 ++--- 3 files changed, 204 insertions(+), 125 deletions(-) diff --git a/TODO b/TODO index d3bf105e..99e7e542 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,6 @@ -1、把 log 提取出 dbgout 之类的方法; +1、把 log 提取出 dbgout 之类的方法;已改作 beego.Info() 调用; 2、把源代码里的 TODO 完成; -3、Export 的两个 URL 应该可以合并,用是否有 :id 来区分;这样 0 号文档输出整个 book 更顺; +3、Export 的两个 URL 应该可以合并,用是否有 :id 来区分;这样 0 号文档输出整个 book 更顺;已完成; 4、统一代码风格,空格、命名之类的; 5、美化 PDF 的输出格式; 6、自动登录新开标签页而且并不能跳转至起始请求页的问题; @@ -8,4 +8,3 @@ 8、[自动]展示历史版本;增强历史版本对比显示的能力; 9、[自动]展示作者信息;也许可以和上一需求合并考虑; 10、查看了解评论功能; - diff --git a/controllers/document.go b/controllers/document.go index dbbb8c65..172e3c12 100644 --- a/controllers/document.go +++ b/controllers/document.go @@ -29,12 +29,12 @@ import ( "github.com/russross/blackfriday" ) -//DocumentController struct. +// DocumentController struct type DocumentController struct { BaseController } -//判断用户是否可以阅读文档. +// 判断用户是否可以阅读文档 func isReadable(identify, token string, c *DocumentController) *models.BookResult { book, err := models.NewBook().FindByFieldFirst("identify", identify) @@ -43,9 +43,8 @@ func isReadable(identify, token string, c *DocumentController) *models.BookResul c.Abort("500") } - //如果文档是私有的 + // 如果文档是私有的 if book.PrivatelyOwned == 1 && !c.Member.IsAdministrator() { - is_ok := false if c.Member != nil { @@ -54,25 +53,24 @@ func isReadable(identify, token string, c *DocumentController) *models.BookResul is_ok = true } } + if book.PrivateToken != "" && !is_ok { - //如果有访问的Token,并且该项目设置了访问Token,并且和用户提供的相匹配,则记录到Session中. - //如果用户未提供Token且用户登录了,则判断用户是否参与了该项目. - //如果用户未登录,则从Session中读取Token. + // 如果有访问的 Token,并且该项目设置了访问 Token,并且和用户提供的相匹配,则记录到 Session 中。 + // 如果用户未提供 Token 且用户登录了,则判断用户是否参与了该项目。 + // 如果用户未登录,则从 Session 中读取 Token。 if token != "" && strings.EqualFold(token, book.PrivateToken) { c.SetSession(identify, token) - } else if token, ok := c.GetSession(identify).(string); !ok || !strings.EqualFold(token, book.PrivateToken) { c.Abort("403") } } else if !is_ok { c.Abort("403") } - } + bookResult := book.ToBookResult() if c.Member != nil { - rel, err := models.NewRelationship().FindByBookIdAndMemberId(bookResult.BookId, c.Member.MemberId) if err == nil { @@ -80,9 +78,9 @@ func isReadable(identify, token string, c *DocumentController) *models.BookResul bookResult.RoleId = rel.RoleId bookResult.RelationshipId = rel.RelationshipId } - } - //判断是否需要显示评论框 + + // 判断是否需要显示评论框 if bookResult.CommentStatus == "closed" { bookResult.IsDisplayComment = false } else if bookResult.CommentStatus == "open" { @@ -96,20 +94,35 @@ func isReadable(identify, token string, c *DocumentController) *models.BookResul return bookResult } -//文档首页. +func isUserLoggedIn(c *DocumentController) bool { + return c.Member != nil && c.Member.MemberId > 0 +} + +func promptUserToLogIn(c *DocumentController) { + if c.IsAjax() { + c.JsonResult(6000, "需要[重]登录。") + } else { + c.Redirect(beego.URLFor("AccountController.Login"), 302) + } +} + +// 文档首页 func (c *DocumentController) Index() { c.Prepare() + identify := c.Ctx.Input.Param(":key") token := c.GetString("token") if identify == "" { c.Abort("404") } - //如果没有开启你们访问则跳转到登录 - if !c.EnableAnonymous && c.Member == nil { - c.Redirect(beego.URLFor("AccountController.Login"), 302) + + // 如果没有开启匿名访问则跳转到登录 + if !c.EnableAnonymous && !isUserLoggedIn(c) { + promptUserToLogIn(c) return } + bookResult := isReadable(identify, token, c) c.TplName = "document/" + bookResult.Theme + "_read.tpl" @@ -131,9 +144,10 @@ func (c *DocumentController) Index() { beego.Info("DocumentController.Index(): c.Data[\"DocumentId\"] = ", 0) } -//阅读文档. +// 阅读文档 func (c *DocumentController) Read() { c.Prepare() + identify := c.Ctx.Input.Param(":key") token := c.GetString("token") id := c.GetString(":id") @@ -145,9 +159,9 @@ func (c *DocumentController) Read() { c.Abort("404") } - //如果没有开启你们访问则跳转到登录 - if !c.EnableAnonymous && c.Member == nil { - c.Redirect(beego.URLFor("AccountController.Login"), 302) + // 如果没有开启匿名访问则跳转到登录 + if !c.EnableAnonymous && !isUserLoggedIn(c) { + promptUserToLogIn(c) return } @@ -174,6 +188,7 @@ func (c *DocumentController) Read() { if doc.BookId != bookResult.BookId { c.Abort("403") } + attach, err := models.NewAttachment().FindListByDocumentId(doc.DocumentId) if err == nil { doc.AttachList = attach @@ -190,6 +205,7 @@ func (c *DocumentController) Read() { contentSelection.SetAttr("src", utils.JoinURI(cdnimg, src)) } }) + html, err := query.Html() if err != nil { beego.Error(err) @@ -197,7 +213,6 @@ func (c *DocumentController) Read() { doc.Release = html } } - } // assemble doc info, added by dandycheung, 2017-12-20 @@ -244,7 +259,7 @@ func (c *DocumentController) Read() { c.Data["Content"] = template.HTML(doc.Release) } -//编辑文档. +// 编辑文档 func (c *DocumentController) Edit() { c.Prepare() @@ -254,30 +269,30 @@ func (c *DocumentController) Edit() { } bookResult := models.NewBookResult() + var err error - //如果是超级管理者,则不判断权限 + // 如果是超级管理者,则不判断权限 if c.Member.IsAdministrator() { book, err := models.NewBook().FindByFieldFirst("identify", identify) if err != nil { c.JsonResult(6002, "项目不存在或权限不足") } - bookResult = book.ToBookResult() + bookResult = book.ToBookResult() } else { bookResult, err = models.NewBookResult().FindByIdentify(identify, c.Member.MemberId) if err != nil { beego.Error("DocumentController.Edit => ", err) - c.Abort("403") } - if bookResult.RoleId == conf.BookObserver { + if bookResult.RoleId == conf.BookObserver { c.JsonResult(6002, "项目不存在或权限不足") } } - //根据不同编辑器类型加载编辑器 + // 根据不同编辑器类型加载编辑器 if bookResult.Editor == "markdown" { c.TplName = "document/markdown_edit_template.tpl" } else if bookResult.Editor == "html" { @@ -307,11 +322,11 @@ func (c *DocumentController) Edit() { c.Data["Result"] = template.JS("[]") } } - c.Data["BaiDuMapKey"] = beego.AppConfig.DefaultString("baidumapkey", "") + c.Data["BaiDuMapKey"] = beego.AppConfig.DefaultString("baidumapkey", "") } -//创建一个文档. +// 创建一个文档 func (c *DocumentController) Create() { identify := c.GetString("identify") doc_identify := c.GetString("doc_identify") @@ -322,27 +337,32 @@ func (c *DocumentController) Create() { if identify == "" { c.JsonResult(6001, "参数错误") } + if doc_name == "" { c.JsonResult(6004, "文档名称不能为空") } + if doc_identify != "" { if ok, err := regexp.MatchString(`^[a-z]+[a-zA-Z0-9_\-]*$`, doc_identify); !ok || err != nil { - c.JsonResult(6003, "文档标识只能包含小写字母、数字,以及“-”和“_”符号,并且只能小写字母开头") } + d, _ := models.NewDocument().FindByFieldFirst("identify", doc_identify) if d.DocumentId > 0 && d.DocumentId != doc_id { c.JsonResult(6006, "文档标识已被使用") } } + book_id := 0 - //如果是超级管理员则不判断权限 + + // 如果是超级管理员则不判断权限 if c.Member.IsAdministrator() { book, err := models.NewBook().FindByFieldFirst("identify", identify) if err != nil { beego.Error(err) c.JsonResult(6002, "项目不存在或权限不足") } + book_id = book.BookId } else { bookResult, err := models.NewBookResult().FindByIdentify(identify, c.Member.MemberId) @@ -351,8 +371,10 @@ func (c *DocumentController) Create() { beego.Error("FindByIdentify => ", err) c.JsonResult(6002, "项目不存在或权限不足") } + book_id = bookResult.BookId } + if parent_id > 0 { doc, err := models.NewDocument().Find(parent_id) if err != nil || doc.BookId != book_id { @@ -364,9 +386,11 @@ func (c *DocumentController) Create() { document.MemberId = c.Member.MemberId document.BookId = book_id + if doc_identify != "" { document.Identify = doc_identify } + document.Version = time.Now().Unix() document.DocumentName = doc_name document.ParentId = parent_id @@ -375,14 +399,12 @@ func (c *DocumentController) Create() { beego.Error("InsertOrUpdate => ", err) c.JsonResult(6005, "保存失败") } else { - c.JsonResult(0, "ok", document) } } -//上传附件或图片. +// 上传附件或图片 func (c *DocumentController) Upload() { - identify := c.GetString("identify") doc_id, _ := c.GetInt("doc_id") is_attach := true @@ -401,6 +423,7 @@ func (c *DocumentController) Upload() { c.JsonResult(6003, "没有发现需要上传的文件") } } + if err != nil { c.JsonResult(6002, err.Error()) } @@ -416,16 +439,18 @@ func (c *DocumentController) Upload() { if !conf.IsAllowUploadFileExt(ext) { c.JsonResult(6004, "不允许的文件类型") } + book_id := 0 - //如果是超级管理员,则不判断权限 + + // 如果是超级管理员,则不判断权限 if c.Member.IsAdministrator() { book, err := models.NewBook().FindByFieldFirst("identify", identify) if err != nil { c.JsonResult(6006, "文档不存在或权限不足") } - book_id = book.BookId + book_id = book.BookId } else { book, err := models.NewBookResult().FindByIdentify(identify, c.Member.MemberId) @@ -434,12 +459,15 @@ func (c *DocumentController) Upload() { if err == orm.ErrNoRows { c.JsonResult(6006, "权限不足") } + c.JsonResult(6001, err.Error()) } - //如果没有编辑权限 + + // 如果没有编辑权限 if book.RoleId != conf.BookEditor && book.RoleId != conf.BookAdmin && book.RoleId != conf.BookFounder { c.JsonResult(6006, "权限不足") } + book_id = book.BookId } @@ -448,15 +476,14 @@ func (c *DocumentController) Upload() { if err != nil { c.JsonResult(6007, "文档不存在") } + if doc.BookId != book_id { c.JsonResult(6008, "文档不属于指定的项目") } } fileName := "attach_" + strconv.FormatInt(time.Now().UnixNano(), 16) - filePath := filepath.Join(commands.WorkingDirectory, "uploads", time.Now().Format("200601"), fileName+ext) - path := filepath.Dir(filePath) os.MkdirAll(path, os.ModePerm) @@ -467,6 +494,7 @@ func (c *DocumentController) Upload() { beego.Error("SaveToFile => ", err) c.JsonResult(6005, "保存文件失败") } + attachment := models.NewAttachment() attachment.BookId = book_id attachment.FileName = moreFile.Filename @@ -478,16 +506,17 @@ func (c *DocumentController) Upload() { if fileInfo, err := os.Stat(filePath); err == nil { attachment.FileSize = float64(fileInfo.Size()) } + if doc_id > 0 { attachment.DocumentId = doc_id } if strings.EqualFold(ext, ".jpg") || strings.EqualFold(ext, ".jpeg") || strings.EqualFold(ext, ".png") || strings.EqualFold(ext, ".gif") { - attachment.HttpPath = "/" + strings.Replace(strings.TrimPrefix(filePath, commands.WorkingDirectory), "\\", "/", -1) if strings.HasPrefix(attachment.HttpPath, "//") { attachment.HttpPath = string(attachment.HttpPath[1:]) } + is_attach = false } @@ -498,6 +527,7 @@ func (c *DocumentController) Upload() { beego.Error("Attachment Insert => ", err) c.JsonResult(6006, "文件保存失败") } + if attachment.HttpPath == "" { attachment.HttpPath = beego.URLFor("DocumentController.DownloadAttachment", ":key", identify, ":attach_id", attachment.AttachmentId) @@ -516,11 +546,12 @@ func (c *DocumentController) Upload() { "is_attach": is_attach, "attach": attachment, } + c.Ctx.Output.JSON(result, true, false) c.StopRun() } -//DownloadAttachment 下载附件. +// 下载附件 func (c *DocumentController) DownloadAttachment() { c.Prepare() @@ -533,20 +564,22 @@ func (c *DocumentController) DownloadAttachment() { if c.Member != nil { member_id = c.Member.MemberId } + book_id := 0 - //判断用户是否参与了项目 + // 判断用户是否参与了项目 bookResult, err := models.NewBookResult().FindByIdentify(identify, member_id) if err != nil { - //判断项目公开状态 + // 判断项目公开状态 book, err := models.NewBook().FindByFieldFirst("identify", identify) if err != nil { c.Abort("404") } - //如果不是超级管理员则判断权限 + + // 如果不是超级管理员则判断权限 if c.Member == nil || c.Member.Role != conf.MemberSuperRole { - //如果项目是私有的,并且token不正确 + // 如果项目是私有的,并且 token 不正确 if (book.PrivatelyOwned == 1 && token == "") || (book.PrivatelyOwned == 1 && book.PrivateToken != token) { c.Abort("403") } @@ -556,7 +589,8 @@ func (c *DocumentController) DownloadAttachment() { } else { book_id = bookResult.BookId } - //查找附件 + + // 查找附件 attachment, err := models.NewAttachment().Find(attach_id) if err != nil { @@ -567,15 +601,16 @@ func (c *DocumentController) DownloadAttachment() { c.Abort("500") } } + if attachment.BookId != book_id { c.Abort("404") } - c.Ctx.Output.Download(filepath.Join(commands.WorkingDirectory, attachment.FilePath), attachment.FileName) + c.Ctx.Output.Download(filepath.Join(commands.WorkingDirectory, attachment.FilePath), attachment.FileName) c.StopRun() } -//删除附件. +// 删除附件 func (c *DocumentController) RemoveAttachment() { c.Prepare() attach_id, _ := c.GetInt("attach_id") @@ -583,40 +618,45 @@ func (c *DocumentController) RemoveAttachment() { if attach_id <= 0 { c.JsonResult(6001, "参数错误") } + attach, err := models.NewAttachment().Find(attach_id) if err != nil { beego.Error(err) c.JsonResult(6002, "附件不存在") } + document, err := models.NewDocument().Find(attach.DocumentId) if err != nil { beego.Error(err) c.JsonResult(6003, "文档不存在") } + if c.Member.Role != conf.MemberSuperRole { rel, err := models.NewRelationship().FindByBookIdAndMemberId(document.BookId, c.Member.MemberId) if err != nil { beego.Error(err) c.JsonResult(6004, "权限不足") } + if rel.RoleId == conf.BookObserver { c.JsonResult(6004, "权限不足") } } - err = attach.Delete() + err = attach.Delete() if err != nil { beego.Error(err) c.JsonResult(6005, "删除失败") } + os.Remove(filepath.Join(commands.WorkingDirectory, attach.FilePath)) c.JsonResult(0, "ok", attach) } -//删除文档. +// 删除文档 func (c *DocumentController) Delete() { c.Prepare() @@ -624,13 +664,15 @@ func (c *DocumentController) Delete() { doc_id, err := c.GetInt("doc_id", 0) book_id := 0 - //如果是超级管理员则忽略权限判断 + + // 如果是超级管理员则忽略权限判断 if c.Member.IsAdministrator() { book, err := models.NewBook().FindByFieldFirst("identify", identify) if err != nil { beego.Error("FindByIdentify => ", err) c.JsonResult(6002, "项目不存在或权限不足") } + book_id = book.BookId } else { bookResult, err := models.NewBookResult().FindByIdentify(identify, c.Member.MemberId) @@ -639,6 +681,7 @@ func (c *DocumentController) Delete() { beego.Error("FindByIdentify => ", err) c.JsonResult(6002, "项目不存在或权限不足") } + book_id = bookResult.BookId } @@ -652,21 +695,23 @@ func (c *DocumentController) Delete() { beego.Error("Delete => ", err) c.JsonResult(6003, "删除失败") } - //如果文档所属项目错误 + // 如果文档所属项目错误 if doc.BookId != book_id { c.JsonResult(6004, "参数错误") } - //递归删除项目下的文档以及子文档 + + // 递归删除项目下的文档以及子文档 err = doc.RecursiveDocument(doc.DocumentId) if err != nil { c.JsonResult(6005, "删除失败") } - //重置文档数量统计 + + // 重置文档数量统计 models.NewBook().ResetDocumentNumber(doc.BookId) c.JsonResult(0, "ok") } -//获取文档内容. +// 获取文档内容 func (c *DocumentController) Content() { c.Prepare() @@ -676,13 +721,16 @@ func (c *DocumentController) Content() { if err != nil { doc_id, _ = strconv.Atoi(c.Ctx.Input.Param(":id")) } + book_id := 0 - //如果是超级管理员,则忽略权限 + + // 如果是超级管理员,则忽略权限 if c.Member.IsAdministrator() { book, err := models.NewBook().FindByFieldFirst("identify", identify) if err != nil { c.JsonResult(6002, "项目不存在或权限不足") } + book_id = book.BookId } else { bookResult, err := models.NewBookResult().FindByIdentify(identify, c.Member.MemberId) @@ -691,6 +739,7 @@ func (c *DocumentController) Content() { beego.Error("FindByIdentify => ", err) c.JsonResult(6002, "项目不存在或权限不足") } + book_id = bookResult.BookId } @@ -709,13 +758,16 @@ func (c *DocumentController) Content() { if err != nil { c.JsonResult(6003, "读取文档错误") } + if doc.BookId != book_id { c.JsonResult(6004, "保存的文档不属于指定项目") } + if doc.Version != version && !strings.EqualFold(is_cover, "yes") { beego.Info("%d|", version, doc.Version) c.JsonResult(6005, "文档已被修改确定要覆盖吗?") } + history := models.NewDocumentHistory() history.DocumentId = doc_id history.Content = doc.Content @@ -733,13 +785,16 @@ func (c *DocumentController) Content() { } else { doc.Markdown = markdown } + doc.Version = time.Now().Unix() doc.Content = content + if err := doc.InsertOrUpdate(); err != nil { beego.Error("InsertOrUpdate => ", err) c.JsonResult(6006, "保存失败") } - //如果启用了文档历史,则添加历史文档 + + // 如果启用了文档历史,则添加历史文档 if c.EnableDocumentHistory { _, err = history.InsertOrUpdate() if err != nil { @@ -749,15 +804,17 @@ func (c *DocumentController) Content() { c.JsonResult(0, "ok", doc) } - doc, err := models.NewDocument().Find(doc_id) + doc, err := models.NewDocument().Find(doc_id) if err != nil { c.JsonResult(6003, "文档不存在") } + attach, err := models.NewAttachment().FindListByDocumentId(doc.DocumentId) if err == nil { doc.AttachList = attach } + c.JsonResult(0, "ok", doc) } @@ -782,6 +839,7 @@ func (c *DocumentController) GetDocumentById(id string) (doc *models.Document, e return nil, err } } + return doc, nil } @@ -791,19 +849,19 @@ func (c *DocumentController) Export(single_doc bool) { c.TplName = "document/export.tpl" identify := c.Ctx.Input.Param(":key") - - output := c.GetString("output") - - token := c.GetString("token") - if identify == "" { c.Abort("404") } - //如果没有开启你们访问则跳转到登录 - if !c.EnableAnonymous && c.Member == nil { - c.Redirect(beego.URLFor("AccountController.Login"), 302) + + output := c.GetString("output") + token := c.GetString("token") + + // 如果没有开启匿名访问则跳转到登录 + if !c.EnableAnonymous && !isUserLoggedIn(c) { + promptUserToLogIn(c) return } + bookResult := models.NewBookResult() if c.Member != nil && c.Member.IsAdministrator() { book, err := models.NewBook().FindByIdentify(identify) @@ -811,32 +869,32 @@ func (c *DocumentController) Export(single_doc bool) { beego.Error(err) c.Abort("500") } + bookResult = book.ToBookResult() } else { bookResult = isReadable(identify, token, c) } - if bookResult.PrivatelyOwned == 0 { - //TODO 私有项目禁止导出 - } - docs, err := models.NewDocument().FindListByBookId(bookResult.BookId) + if bookResult.PrivatelyOwned == 0 { + // TODO: 私有项目禁止导出 + } + + docs, err := models.NewDocument().FindListByBookId(bookResult.BookId) if err != nil { beego.Error(err) c.Abort("500") } if output == "pdf" { - exe := beego.AppConfig.String("wkhtmltopdf") - if exe == "" { c.TplName = "errors/error.tpl" c.Data["ErrorMessage"] = "没有配置PDF导出程序" c.Data["ErrorCode"] = 50010 return } - dpath := "cache/" + bookResult.Identify + dpath := "cache/" + bookResult.Identify os.MkdirAll(dpath, 0766) pathList := list.New() @@ -859,21 +917,22 @@ func (c *DocumentController) Export(single_doc bool) { pdfpath := filepath.Join("cache", identify+"_"+c.CruSession.SessionID()+".pdf") if _, err := os.Stat(pdfpath); os.IsNotExist(err) { - wkhtmltopdf.SetPath(beego.AppConfig.String("wkhtmltopdf")) - pdfg, err := wkhtmltopdf.NewPDFGenerator() - pdfg.MarginBottom.Set(35) + pdfg, err := wkhtmltopdf.NewPDFGenerator() if err != nil { beego.Error(err) c.Abort("500") } + pdfg.MarginBottom.Set(35) + for e := pathList.Front(); e != nil; e = e.Next() { if page, ok := e.Value.(string); ok { pdfg.AddPage(wkhtmltopdf.NewPage(page)) } } + err = pdfg.Create() if err != nil { beego.Error(err) @@ -896,13 +955,13 @@ func (c *DocumentController) Export(single_doc bool) { c.Abort("404") } -//生成项目访问的二维码. +// 生成项目访问的二维码 func (c *DocumentController) QrCode() { c.Prepare() + identify := c.GetString(":key") book, err := models.NewBook().FindByIdentify(identify) - if err != nil || book.BookId <= 0 { c.Abort("404") } @@ -913,15 +972,16 @@ func (c *DocumentController) QrCode() { beego.Error(err) c.Abort("500") } - code, err = barcode.Scale(code, 150, 150) + code, err = barcode.Scale(code, 150, 150) if err != nil { beego.Error(err) c.Abort("500") } + c.Ctx.ResponseWriter.Header().Set("Content-Type", "image/png") - //imgpath := filepath.Join("cache","qrcode",identify + ".png") + // imgpath := filepath.Join("cache","qrcode",identify + ".png") err = png.Encode(c.Ctx.ResponseWriter, code) if err != nil { @@ -930,7 +990,7 @@ func (c *DocumentController) QrCode() { } } -//项目内搜索. +// 项目内搜索 func (c *DocumentController) Search() { c.Prepare() @@ -941,21 +1001,24 @@ func (c *DocumentController) Search() { if identify == "" { c.JsonResult(6001, "参数错误") } - if !c.EnableAnonymous && c.Member == nil { - c.Redirect(beego.URLFor("AccountController.Login"), 302) + + if !c.EnableAnonymous && !isUserLoggedIn(c) { + promptUserToLogIn(c) return } + bookResult := isReadable(identify, token, c) docs, err := models.NewDocumentSearchResult().SearchDocument(keyword, bookResult.BookId) - if err != nil { beego.Error(err) c.JsonResult(6002, "搜索结果错误") } + if len(docs) < 0 { c.JsonResult(404, "没有数据库") } + for _, doc := range docs { doc.BookId = bookResult.BookId doc.BookName = bookResult.BookName @@ -966,9 +1029,10 @@ func (c *DocumentController) Search() { c.JsonResult(0, "ok", docs) } -//文档历史列表. +// 文档历史列表 func (c *DocumentController) History() { c.Prepare() + c.TplName = "document/history.tpl" identify := c.GetString("identify") @@ -976,7 +1040,8 @@ func (c *DocumentController) History() { pageIndex, _ := c.GetInt("page", 1) book_id := 0 - //如果是超级管理员则忽略权限判断 + + // 如果是超级管理员则忽略权限判断 if c.Member.IsAdministrator() { book, err := models.NewBook().FindByFieldFirst("identify", identify) if err != nil { @@ -984,16 +1049,17 @@ func (c *DocumentController) History() { c.Data["ErrorMessage"] = "项目不存在或权限不足" return } + book_id = book.BookId c.Data["Model"] = book } else { bookResult, err := models.NewBookResult().FindByIdentify(identify, c.Member.MemberId) - if err != nil || bookResult.RoleId == conf.BookObserver { beego.Error("FindByIdentify => ", err) c.Data["ErrorMessage"] = "项目不存在或权限不足" return } + book_id = bookResult.BookId c.Data["Model"] = bookResult } @@ -1004,20 +1070,19 @@ func (c *DocumentController) History() { } doc, err := models.NewDocument().Find(doc_id) - if err != nil { beego.Error("Delete => ", err) c.Data["ErrorMessage"] = "获取历史失败" return } - //如果文档所属项目错误 + + // 如果文档所属项目错误 if doc.BookId != book_id { c.Data["ErrorMessage"] = "参数错误" return } historis, totalCount, err := models.NewDocumentHistory().FindToPager(doc_id, pageIndex, conf.PageSize) - if err != nil { beego.Error("FindToPager => ", err) c.Data["ErrorMessage"] = "获取历史失败" @@ -1030,13 +1095,13 @@ func (c *DocumentController) History() { if totalCount > 0 { html := utils.GetPagerHtml(c.Ctx.Request.RequestURI, pageIndex, conf.PageSize, totalCount) - c.Data["PageHtml"] = html } } func (c *DocumentController) DeleteHistory() { c.Prepare() + c.TplName = "document/history.tpl" identify := c.GetString("identify") @@ -1046,22 +1111,25 @@ func (c *DocumentController) DeleteHistory() { if history_id <= 0 { c.JsonResult(6001, "参数错误") } + book_id := 0 - //如果是超级管理员则忽略权限判断 + + // 如果是超级管理员则忽略权限判断 if c.Member.IsAdministrator() { book, err := models.NewBook().FindByFieldFirst("identify", identify) if err != nil { beego.Error("FindByIdentify => ", err) c.JsonResult(6002, "项目不存在或权限不足") } + book_id = book.BookId } else { bookResult, err := models.NewBookResult().FindByIdentify(identify, c.Member.MemberId) - if err != nil || bookResult.RoleId == conf.BookObserver { beego.Error("FindByIdentify => ", err) c.JsonResult(6002, "项目不存在或权限不足") } + book_id = bookResult.BookId } @@ -1070,25 +1138,28 @@ func (c *DocumentController) DeleteHistory() { } doc, err := models.NewDocument().Find(doc_id) - if err != nil { beego.Error("Delete => ", err) c.JsonResult(6001, "获取历史失败") } - //如果文档所属项目错误 + + // 如果文档所属项目错误 if doc.BookId != book_id { c.JsonResult(6001, "参数错误") } + err = models.NewDocumentHistory().Delete(history_id, doc_id) if err != nil { beego.Error(err) c.JsonResult(6002, "删除失败") } + c.JsonResult(0, "ok") } func (c *DocumentController) RestoreHistory() { c.Prepare() + c.TplName = "document/history.tpl" identify := c.GetString("identify") @@ -1098,22 +1169,24 @@ func (c *DocumentController) RestoreHistory() { if history_id <= 0 { c.JsonResult(6001, "参数错误") } + book_id := 0 - //如果是超级管理员则忽略权限判断 + // 如果是超级管理员则忽略权限判断 if c.Member.IsAdministrator() { book, err := models.NewBook().FindByFieldFirst("identify", identify) if err != nil { beego.Error("FindByIdentify => ", err) c.JsonResult(6002, "项目不存在或权限不足") } + book_id = book.BookId } else { bookResult, err := models.NewBookResult().FindByIdentify(identify, c.Member.MemberId) - if err != nil || bookResult.RoleId == conf.BookObserver { beego.Error("FindByIdentify => ", err) c.JsonResult(6002, "项目不存在或权限不足") } + book_id = bookResult.BookId } @@ -1122,33 +1195,37 @@ func (c *DocumentController) RestoreHistory() { } doc, err := models.NewDocument().Find(doc_id) - if err != nil { beego.Error("Delete => ", err) c.JsonResult(6001, "获取历史失败") } - //如果文档所属项目错误 + + // 如果文档所属项目错误 if doc.BookId != book_id { c.JsonResult(6001, "参数错误") } + err = models.NewDocumentHistory().Restore(history_id, doc_id, c.Member.MemberId) if err != nil { beego.Error(err) c.JsonResult(6002, "删除失败") } + c.JsonResult(0, "ok", doc) } func (c *DocumentController) Compare() { c.Prepare() + c.TplName = "document/compare.tpl" + history_id, _ := strconv.Atoi(c.Ctx.Input.Param(":id")) identify := c.Ctx.Input.Param(":key") book_id := 0 editor := "markdown" - //如果是超级管理员则忽略权限判断 + // 如果是超级管理员则忽略权限判断 if c.Member.IsAdministrator() { book, err := models.NewBook().FindByFieldFirst("identify", identify) if err != nil { @@ -1156,17 +1233,18 @@ func (c *DocumentController) Compare() { c.Abort("403") return } + book_id = book.BookId c.Data["Model"] = book editor = book.Editor } else { bookResult, err := models.NewBookResult().FindByIdentify(identify, c.Member.MemberId) - if err != nil || bookResult.RoleId == conf.BookObserver { beego.Error("FindByIdentify => ", err) c.Abort("403") return } + book_id = bookResult.BookId c.Data["Model"] = bookResult editor = bookResult.Editor @@ -1181,11 +1259,12 @@ func (c *DocumentController) Compare() { beego.Error("DocumentController.Compare => ", err) c.ShowErrorPage(60003, err.Error()) } - doc, err := models.NewDocument().Find(history.DocumentId) + doc, err := models.NewDocument().Find(history.DocumentId) if doc.BookId != book_id { c.ShowErrorPage(60002, "参数错误") } + c.Data["HistoryId"] = history_id c.Data["DocumentId"] = doc.DocumentId @@ -1198,7 +1277,7 @@ func (c *DocumentController) Compare() { } } -//递归生成文档序列数组. +// 递归生成文档序列数组 func RecursiveFun(parent_id int, prefix, dpath string, c *DocumentController, book *models.BookResult, docs []*models.Document, paths *list.List) { for _, item := range docs { if item.ParentId == parent_id { @@ -1221,7 +1300,6 @@ func EachFun(prefix, dpath string, c *DocumentController, book *models.BookResul paths.PushBack(fpath) f, err := os.OpenFile(fpath, os.O_CREATE|os.O_RDWR, 0777) - if err != nil { beego.Error(err) c.Abort("500") @@ -1241,14 +1319,15 @@ func EachFun(prefix, dpath string, c *DocumentController, book *models.BookResul contentSelection.SetAttr("src", c.BaseUrl()+src) } }) - html, err = doc.Html() + html, err = doc.Html() if err != nil { f.Close() beego.Error(err) c.Abort("500") } - //html = strings.Replace(html," ' + item.doc_name + ' '; } } - if(html !== "") { + if (html !== "") { $(".search-empty").hide(); } else { $(".search-empty").show(); @@ -204,8 +205,8 @@ $(function () { try { var $node = window.jsTree.jstree().get_selected(); if (typeof $node === "object") { - $node = window.jsTree.jstree().get_node({id: $node[0]}); - events.trigger('article.open', {$url: $node.a_attr.href, $init: true, $id: $node.a_attr.id}); + $node = window.jsTree.jstree().get_node({ id: $node[0] }); + events.trigger('article.open', { $url: $node.a_attr.href, $init: true, $id: $node.a_attr.id }); } } catch (e) { console.log(e);