book.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656
  1. package controllers
  2. import (
  3. "strings"
  4. "regexp"
  5. "strconv"
  6. "time"
  7. "encoding/json"
  8. "html/template"
  9. "errors"
  10. "fmt"
  11. "path/filepath"
  12. "os"
  13. "github.com/lifei6671/mindoc/models"
  14. "github.com/lifei6671/mindoc/utils"
  15. "github.com/astaxie/beego"
  16. "github.com/astaxie/beego/orm"
  17. "github.com/astaxie/beego/logs"
  18. "github.com/lifei6671/mindoc/conf"
  19. "github.com/lifei6671/mindoc/graphics"
  20. "github.com/lifei6671/mindoc/commands"
  21. )
  22. type BookController struct {
  23. BaseController
  24. }
  25. func (c *BookController) Index() {
  26. c.Prepare()
  27. c.TplName = "book/index.tpl"
  28. pageIndex, _ := c.GetInt("page", 1)
  29. books,totalCount,err := models.NewBook().FindToPager(pageIndex,conf.PageSize,c.Member.MemberId)
  30. if err != nil {
  31. logs.Error("BookController.Index => ",err)
  32. c.Abort("500")
  33. }
  34. if totalCount > 0 {
  35. html := utils.GetPagerHtml(c.Ctx.Request.RequestURI, pageIndex, conf.PageSize, totalCount)
  36. c.Data["PageHtml"] = html
  37. }else {
  38. c.Data["PageHtml"] = ""
  39. }
  40. b,err := json.Marshal(books)
  41. if err != nil || len(books) <= 0{
  42. c.Data["Result"] = template.JS("[]")
  43. }else{
  44. c.Data["Result"] = template.JS(string(b))
  45. }
  46. }
  47. // Dashboard 项目概要 .
  48. func (c *BookController) Dashboard() {
  49. c.Prepare()
  50. c.TplName = "book/dashboard.tpl"
  51. key := c.Ctx.Input.Param(":key")
  52. if key == ""{
  53. c.Abort("404")
  54. }
  55. book,err := models.NewBookResult().FindByIdentify(key,c.Member.MemberId)
  56. if err != nil {
  57. if err == models.ErrPermissionDenied {
  58. c.Abort("403")
  59. }
  60. beego.Error(err)
  61. c.Abort("500")
  62. }
  63. c.Data["Model"] = *book
  64. }
  65. // Setting 项目设置 .
  66. func (c *BookController) Setting() {
  67. c.Prepare()
  68. c.TplName = "book/setting.tpl"
  69. key := c.Ctx.Input.Param(":key")
  70. if key == ""{
  71. c.Abort("404")
  72. }
  73. book,err := models.NewBookResult().FindByIdentify(key,c.Member.MemberId)
  74. if err != nil {
  75. if err == orm.ErrNoRows {
  76. c.Abort("404")
  77. }
  78. if err == models.ErrPermissionDenied {
  79. c.Abort("403")
  80. }
  81. c.Abort("500")
  82. }
  83. //如果不是创始人也不是管理员则不能操作
  84. if book.RoleId != conf.BookFounder && book.RoleId != conf.BookAdmin {
  85. c.Abort("403")
  86. }
  87. if book.PrivateToken != "" {
  88. book.PrivateToken = c.BaseUrl() + beego.URLFor("DocumentController.Index",":key",book.Identify,"token",book.PrivateToken)
  89. }
  90. c.Data["Model"] = book
  91. }
  92. //保存项目信息
  93. func (c *BookController) SaveBook() {
  94. bookResult,err := c.IsPermission()
  95. if err != nil {
  96. c.JsonResult(6001,err.Error())
  97. }
  98. book,err := models.NewBook().Find(bookResult.BookId)
  99. if err != nil {
  100. logs.Error("SaveBook => ",err)
  101. c.JsonResult(6002,err.Error())
  102. }
  103. book_name := strings.TrimSpace(c.GetString("book_name"))
  104. description := strings.TrimSpace(c.GetString("description",""))
  105. comment_status := c.GetString("comment_status")
  106. tag := strings.TrimSpace(c.GetString("label"))
  107. editor := strings.TrimSpace(c.GetString("editor"))
  108. if strings.Count(description,"") > 500 {
  109. c.JsonResult(6004,"项目描述不能大于500字")
  110. }
  111. if comment_status != "open" && comment_status != "closed" && comment_status != "group_only" && comment_status != "registered_only" {
  112. comment_status = "closed"
  113. }
  114. if tag != ""{
  115. tags := strings.Split(tag,",")
  116. if len(tags) > 10 {
  117. c.JsonResult(6005,"最多允许添加10个标签")
  118. }
  119. }
  120. if editor != "markdown" && editor != "html" {
  121. editor = "markdown"
  122. }
  123. book.BookName = book_name
  124. book.Description = description
  125. book.CommentStatus = comment_status
  126. book.Label = tag
  127. book.Editor = editor
  128. if err := book.Update();err != nil {
  129. c.JsonResult(6006,"保存失败")
  130. }
  131. bookResult.BookName = book_name
  132. bookResult.Description = description
  133. bookResult.CommentStatus = comment_status
  134. bookResult.Label = tag
  135. c.JsonResult(0,"ok",bookResult)
  136. }
  137. //设置项目私有状态.
  138. func (c *BookController) PrivatelyOwned() {
  139. status := c.GetString("status")
  140. if status != "open" && status != "close" {
  141. c.JsonResult(6003,"参数错误")
  142. }
  143. state := 0
  144. if status == "open" {
  145. state = 0
  146. }else{
  147. state = 1
  148. }
  149. bookResult,err := c.IsPermission()
  150. if err != nil {
  151. c.JsonResult(6001,err.Error())
  152. }
  153. //只有创始人才能变更私有状态
  154. if bookResult.RoleId != conf.BookFounder {
  155. c.JsonResult(6002,"权限不足")
  156. }
  157. book,err := models.NewBook().Find(bookResult.BookId)
  158. if err != nil {
  159. c.JsonResult(6005,"项目不存在")
  160. }
  161. book.PrivatelyOwned = state
  162. err = book.Update()
  163. if err != nil {
  164. logs.Error("PrivatelyOwned => ",err)
  165. c.JsonResult(6004,"保存失败")
  166. }
  167. c.JsonResult(0,"ok")
  168. }
  169. // Transfer 转让项目.
  170. func (c *BookController) Transfer() {
  171. c.Prepare()
  172. account := c.GetString("account")
  173. if account == "" {
  174. c.JsonResult(6004,"接受者账号不能为空")
  175. }
  176. member,err := models.NewMember().FindByAccount(account)
  177. if err != nil {
  178. logs.Error("FindByAccount => ",err)
  179. c.JsonResult(6005,"接受用户不存在")
  180. }
  181. if member.Status != 0 {
  182. c.JsonResult(6006,"接受用户已被禁用")
  183. }
  184. if member.MemberId == c.Member.MemberId {
  185. c.JsonResult(6007,"不能转让给自己")
  186. }
  187. bookResult,err := c.IsPermission()
  188. if err != nil {
  189. c.JsonResult(6001,err.Error())
  190. }
  191. err = models.NewRelationship().Transfer(bookResult.BookId,c.Member.MemberId,member.MemberId)
  192. if err != nil {
  193. logs.Error("Transfer => ",err)
  194. c.JsonResult(6008,err.Error())
  195. }
  196. c.JsonResult(0,"ok")
  197. }
  198. //上传项目封面.
  199. func (c *BookController) UploadCover() {
  200. bookResult,err := c.IsPermission()
  201. if err != nil {
  202. c.JsonResult(6001,err.Error())
  203. }
  204. book,err := models.NewBook().Find(bookResult.BookId)
  205. if err != nil {
  206. logs.Error("SaveBook => ",err)
  207. c.JsonResult(6002,err.Error())
  208. }
  209. file,moreFile,err := c.GetFile("image-file")
  210. defer file.Close()
  211. if err != nil {
  212. logs.Error("",err.Error())
  213. c.JsonResult(500,"读取文件异常")
  214. }
  215. ext := filepath.Ext(moreFile.Filename)
  216. if !strings.EqualFold(ext,".png") && !strings.EqualFold(ext,".jpg") && !strings.EqualFold(ext,".gif") && !strings.EqualFold(ext,".jpeg") {
  217. c.JsonResult(500,"不支持的图片格式")
  218. }
  219. x1 ,_ := strconv.ParseFloat(c.GetString("x"),10)
  220. y1 ,_ := strconv.ParseFloat(c.GetString("y"),10)
  221. w1 ,_ := strconv.ParseFloat(c.GetString("width"),10)
  222. h1 ,_ := strconv.ParseFloat(c.GetString("height"),10)
  223. x := int(x1)
  224. y := int(y1)
  225. width := int(w1)
  226. height := int(h1)
  227. fileName := "cover_" + strconv.FormatInt(time.Now().UnixNano(), 16)
  228. filePath := filepath.Join("uploads",time.Now().Format("200601"),fileName + ext)
  229. path := filepath.Dir(filePath)
  230. os.MkdirAll(path, os.ModePerm)
  231. err = c.SaveToFile("image-file",filePath)
  232. if err != nil {
  233. logs.Error("",err)
  234. c.JsonResult(500,"图片保存失败")
  235. }
  236. defer func(filePath string) {
  237. os.Remove(filePath)
  238. }(filePath)
  239. //剪切图片
  240. subImg,err := graphics.ImageCopyFromFile(filePath,x,y,width,height)
  241. if err != nil{
  242. logs.Error("graphics.ImageCopyFromFile => ",err)
  243. c.JsonResult(500,"图片剪切")
  244. }
  245. filePath = filepath.Join(commands.WorkingDirectory,"uploads",time.Now().Format("200601"),fileName + "_small" + ext)
  246. //生成缩略图并保存到磁盘
  247. err = graphics.ImageResizeSaveFile(subImg,175,230,filePath)
  248. if err != nil {
  249. logs.Error("ImageResizeSaveFile => ",err.Error())
  250. c.JsonResult(500,"保存图片失败")
  251. }
  252. url := "/" + strings.Replace(strings.TrimPrefix(filePath,commands.WorkingDirectory),"\\","/",-1)
  253. if strings.HasPrefix(url,"//") {
  254. url = string(url[1:])
  255. }
  256. old_cover := book.Cover
  257. book.Cover = url
  258. if err := book.Update() ; err != nil {
  259. c.JsonResult(6001,"保存图片失败")
  260. }
  261. //如果原封面不是默认封面则删除
  262. if old_cover != conf.GetDefaultCover() {
  263. os.Remove("." + old_cover)
  264. }
  265. c.JsonResult(0,"ok",url)
  266. }
  267. // Users 用户列表.
  268. func (c *BookController) Users() {
  269. c.Prepare()
  270. c.TplName = "book/users.tpl"
  271. key := c.Ctx.Input.Param(":key")
  272. pageIndex,_ := c.GetInt("page",1)
  273. if key == ""{
  274. c.Abort("404")
  275. }
  276. book,err := models.NewBookResult().FindByIdentify(key,c.Member.MemberId)
  277. if err != nil {
  278. if err == models.ErrPermissionDenied {
  279. c.Abort("403")
  280. }
  281. c.Abort("500")
  282. }
  283. c.Data["Model"] = *book
  284. members,totalCount,err := models.NewMemberRelationshipResult().FindForUsersByBookId(book.BookId,pageIndex,15)
  285. if totalCount > 0 {
  286. html := utils.GetPagerHtml(c.Ctx.Request.RequestURI, pageIndex, 10, totalCount)
  287. c.Data["PageHtml"] = html
  288. }else{
  289. c.Data["PageHtml"] = ""
  290. }
  291. b,err := json.Marshal(members)
  292. if err != nil {
  293. c.Data["Result"] = template.JS("[]")
  294. }else{
  295. c.Data["Result"] = template.JS(string(b))
  296. }
  297. }
  298. // Create 创建项目.
  299. func (c *BookController) Create() {
  300. if c.Ctx.Input.IsPost() {
  301. book_name := strings.TrimSpace(c.GetString("book_name",""))
  302. identify := strings.TrimSpace(c.GetString("identify",""))
  303. description := strings.TrimSpace(c.GetString("description",""))
  304. privately_owned,_ := strconv.Atoi(c.GetString("privately_owned"))
  305. comment_status := c.GetString("comment_status")
  306. if book_name == "" {
  307. c.JsonResult(6001,"项目名称不能为空")
  308. }
  309. if identify == "" {
  310. c.JsonResult(6002,"项目标识不能为空")
  311. }
  312. if ok,err := regexp.MatchString(`^[a-z]+[a-zA-Z0-9_\-]*$`,identify); !ok || err != nil {
  313. c.JsonResult(6003,"项目标识只能包含小写字母、数字,以及“-”和“_”符号,并且只能小写字母开头")
  314. }
  315. if strings.Count(identify,"") > 50 {
  316. c.JsonResult(6004,"文档标识不能超过50字")
  317. }
  318. if strings.Count(description,"") > 500 {
  319. c.JsonResult(6004,"项目描述不能大于500字")
  320. }
  321. if privately_owned !=0 && privately_owned != 1 {
  322. privately_owned = 1
  323. }
  324. if comment_status != "open" && comment_status != "closed" && comment_status != "group_only" && comment_status != "registered_only" {
  325. comment_status = "closed"
  326. }
  327. book := models.NewBook()
  328. if books,_ := book.FindByField("identify",identify); len(books) > 0 {
  329. c.JsonResult(6006,"项目标识已存在")
  330. }
  331. book.BookName = book_name
  332. book.Description = description
  333. book.CommentCount = 0
  334. book.PrivatelyOwned = privately_owned
  335. book.CommentStatus = comment_status
  336. book.Identify = identify
  337. book.DocCount = 0
  338. book.MemberId = c.Member.MemberId
  339. book.CommentCount = 0
  340. book.Version = time.Now().Unix()
  341. book.Cover = conf.GetDefaultCover()
  342. book.Editor = "markdown"
  343. book.Theme = "default"
  344. err := book.Insert()
  345. if err != nil {
  346. logs.Error("Insert => ",err)
  347. c.JsonResult(6005,"保存项目失败")
  348. }
  349. bookResult,err := models.NewBookResult().FindByIdentify(book.Identify,c.Member.MemberId)
  350. if err != nil {
  351. beego.Error(err)
  352. }
  353. c.JsonResult(0,"ok",bookResult)
  354. }
  355. c.JsonResult(6001,"error")
  356. }
  357. // CreateToken 创建访问来令牌.
  358. func (c *BookController) CreateToken() {
  359. action := c.GetString("action")
  360. bookResult ,err := c.IsPermission()
  361. if err != nil {
  362. if err == models.ErrPermissionDenied {
  363. c.JsonResult(403,"权限不足")
  364. }
  365. if err == orm.ErrNoRows {
  366. c.JsonResult(404,"项目不存在")
  367. }
  368. logs.Error("生成阅读令牌失败 =>",err)
  369. c.JsonResult(6002,err.Error())
  370. }
  371. book := models.NewBook()
  372. if _,err := book.Find(bookResult.BookId);err != nil {
  373. c.JsonResult(6001,"项目不存在")
  374. }
  375. if action == "create" {
  376. if bookResult.PrivatelyOwned == 0 {
  377. c.JsonResult(6001, "公开项目不能创建阅读令牌")
  378. }
  379. book.PrivateToken = string(utils.Krand(conf.GetTokenSize(), utils.KC_RAND_KIND_ALL))
  380. if err := book.Update(); err != nil {
  381. logs.Error("生成阅读令牌失败 => ", err)
  382. c.JsonResult(6003, "生成阅读令牌失败")
  383. }
  384. c.JsonResult(0, "ok", c.BaseUrl() + beego.URLFor("DocumentController.Index",":key",book.Identify,"token",book.PrivateToken))
  385. }else{
  386. book.PrivateToken = ""
  387. if err := book.Update();err != nil {
  388. logs.Error("CreateToken => ",err)
  389. c.JsonResult(6004,"删除令牌失败")
  390. }
  391. c.JsonResult(0,"ok","")
  392. }
  393. }
  394. // Delete 删除项目.
  395. func (c *BookController) Delete() {
  396. c.Prepare()
  397. bookResult ,err := c.IsPermission()
  398. if err != nil {
  399. c.JsonResult(6001,err.Error())
  400. }
  401. if bookResult.RoleId != conf.BookFounder {
  402. c.JsonResult(6002,"只有创始人才能删除项目")
  403. }
  404. err = models.NewBook().ThoroughDeleteBook(bookResult.BookId)
  405. if err == orm.ErrNoRows {
  406. c.JsonResult(6002,"项目不存在")
  407. }
  408. if err != nil {
  409. logs.Error("删除项目 => ",err)
  410. c.JsonResult(6003,"删除失败")
  411. }
  412. c.JsonResult(0,"ok")
  413. }
  414. //发布项目.
  415. func (c *BookController) Release() {
  416. c.Prepare()
  417. identify := c.GetString("identify")
  418. book_id := 0
  419. if c.Member.IsAdministrator() {
  420. book,err := models.NewBook().FindByFieldFirst("identify",identify)
  421. if err != nil {
  422. }
  423. book_id = book.BookId
  424. }else {
  425. book, err := models.NewBookResult().FindByIdentify(identify, c.Member.MemberId)
  426. if err != nil {
  427. if err == models.ErrPermissionDenied {
  428. c.JsonResult(6001, "权限不足")
  429. }
  430. if err == orm.ErrNoRows {
  431. c.JsonResult(6002, "项目不存在")
  432. }
  433. beego.Error(err)
  434. c.JsonResult(6003, "未知错误")
  435. }
  436. if book.RoleId != conf.BookAdmin && book.RoleId != conf.BookFounder && book.RoleId != conf.BookEditor {
  437. c.JsonResult(6003, "权限不足")
  438. }
  439. book_id = book.BookId
  440. }
  441. go func(identify string) {
  442. models.NewDocument().ReleaseContent(book_id)
  443. }(identify)
  444. c.JsonResult(0,"发布任务已推送到任务队列,稍后将在后台执行。")
  445. }
  446. //文档排序.
  447. func (c *BookController) SaveSort() {
  448. c.Prepare()
  449. identify := c.Ctx.Input.Param(":key")
  450. if identify == "" {
  451. c.Abort("404")
  452. }
  453. book_id := 0
  454. if c.Member.IsAdministrator() {
  455. book,err := models.NewBook().FindByFieldFirst("identify",identify)
  456. if err != nil {
  457. }
  458. book_id = book.BookId
  459. }else{
  460. bookResult,err := models.NewBookResult().FindByIdentify(identify,c.Member.MemberId)
  461. if err != nil {
  462. beego.Error("DocumentController.Edit => ",err)
  463. c.Abort("403")
  464. }
  465. if bookResult.RoleId == conf.BookObserver {
  466. c.JsonResult(6002,"项目不存在或权限不足")
  467. }
  468. book_id = bookResult.BookId
  469. }
  470. content := c.Ctx.Input.RequestBody
  471. var docs []map[string]interface{}
  472. err := json.Unmarshal(content,&docs)
  473. if err != nil {
  474. beego.Error(err)
  475. c.JsonResult(6003,"数据错误")
  476. }
  477. for _,item := range docs {
  478. if doc_id,ok := item["id"].(float64);ok {
  479. doc,err := models.NewDocument().Find(int(doc_id));
  480. if err != nil {
  481. beego.Error(err)
  482. continue;
  483. }
  484. if doc.BookId != book_id {
  485. logs.Info("%s","权限错误")
  486. continue;
  487. }
  488. sort,ok := item["sort"].(float64);
  489. if !ok {
  490. beego.Info("排序数字转换失败 => ",item)
  491. continue
  492. }
  493. parent_id,ok := item["parent"].(float64)
  494. if !ok {
  495. beego.Info("父分类转换失败 => ",item)
  496. continue
  497. }
  498. if parent_id > 0 {
  499. if parent,err := models.NewDocument().Find(int(parent_id)); err != nil || parent.BookId != book_id {
  500. continue
  501. }
  502. }
  503. doc.OrderSort = int(sort)
  504. doc.ParentId = int(parent_id)
  505. if err := doc.InsertOrUpdate(); err != nil {
  506. fmt.Printf("%s",err.Error())
  507. beego.Error(err)
  508. }
  509. }else{
  510. fmt.Printf("文档ID转换失败 => %+v",item)
  511. }
  512. }
  513. c.JsonResult(0,"ok")
  514. }
  515. func (c *BookController) IsPermission() (*models.BookResult,error) {
  516. identify := c.GetString("identify")
  517. book ,err := models.NewBookResult().FindByIdentify(identify,c.Member.MemberId)
  518. if err != nil {
  519. if err == models.ErrPermissionDenied {
  520. return book,errors.New("权限不足")
  521. }
  522. if err == orm.ErrNoRows {
  523. return book,errors.New("项目不存在")
  524. }
  525. return book,err
  526. }
  527. if book.RoleId != conf.BookAdmin && book.RoleId != conf.BookFounder {
  528. return book,errors.New("权限不足")
  529. }
  530. return book,nil
  531. }