2017-04-21 18:20:35 +08:00
package models
2017-04-22 17:24:17 +08:00
import (
2021-03-26 11:34:02 +08:00
"context"
2018-03-25 14:59:42 +08:00
"crypto/md5"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
2019-05-20 17:38:37 +08:00
"sync"
2017-04-22 17:24:17 +08:00
"time"
2019-05-20 17:38:37 +08:00
"encoding/json"
2021-03-23 15:09:17 +08:00
2021-03-26 11:34:02 +08:00
"github.com/beego/beego/v2/client/orm"
2021-03-26 14:26:19 +08:00
"github.com/beego/beego/v2/core/logs"
2021-04-12 21:12:26 +08:00
"github.com/beego/i18n"
2021-03-23 15:09:17 +08:00
"github.com/mindoc-org/mindoc/conf"
"github.com/mindoc-org/mindoc/utils"
"github.com/mindoc-org/mindoc/utils/cryptil"
"github.com/mindoc-org/mindoc/utils/filetil"
"github.com/mindoc-org/mindoc/utils/requests"
"github.com/mindoc-org/mindoc/utils/ziptil"
2021-03-24 00:28:13 +08:00
"github.com/russross/blackfriday/v2"
2017-04-22 17:24:17 +08:00
)
2017-04-21 18:20:35 +08:00
2019-05-20 17:38:37 +08:00
var releaseQueue = make ( chan int , 500 )
var once = sync . Once { }
2017-04-21 18:20:35 +08:00
// Book struct .
type Book struct {
2017-07-07 16:20:55 +08:00
BookId int ` orm:"pk;auto;unique;column(book_id)" json:"book_id" `
2017-04-21 18:20:35 +08:00
// BookName 项目名称.
2017-07-07 16:20:55 +08:00
BookName string ` orm:"column(book_name);size(500)" json:"book_name" `
2018-11-21 11:03:16 +08:00
//所属项目空间
2019-05-20 17:38:37 +08:00
ItemId int ` orm:"column(item_id);type(int);default(1)" json:"item_id" `
2017-04-21 18:20:35 +08:00
// Identify 项目唯一标识.
2018-01-26 17:17:38 +08:00
Identify string ` orm:"column(identify);size(100);unique" json:"identify" `
2018-01-19 20:10:54 +08:00
//是否是自动发布 0 否/1 是
AutoRelease int ` orm:"column(auto_release);type(int);default(0)" json:"auto_release" `
2018-02-28 15:47:00 +08:00
//是否开启下载功能 0 是/1 否
IsDownload int ` orm:"column(is_download);type(int);default(0)" json:"is_download" `
2018-03-25 14:59:42 +08:00
OrderIndex int ` orm:"column(order_index);type(int);default(0)" json:"order_index" `
2017-04-21 18:20:35 +08:00
// Description 项目描述.
2017-07-07 16:20:55 +08:00
Description string ` orm:"column(description);size(2000)" json:"description" `
2018-01-25 19:18:59 +08:00
//发行公司
2018-01-26 17:17:38 +08:00
Publisher string ` orm:"column(publisher);size(500)" json:"publisher" `
2018-03-25 14:59:42 +08:00
Label string ` orm:"column(label);size(500)" json:"label" `
2017-04-21 18:20:35 +08:00
// PrivatelyOwned 项目私有: 0 公开/ 1 私有
2017-07-07 16:20:55 +08:00
PrivatelyOwned int ` orm:"column(privately_owned);type(int);default(0)" json:"privately_owned" `
2017-04-21 18:20:35 +08:00
// 当项目是私有时的访问Token.
2017-07-07 16:20:55 +08:00
PrivateToken string ` orm:"column(private_token);size(500);null" json:"private_token" `
2018-11-14 15:57:55 +08:00
//访问密码.
BookPassword string ` orm:"column(book_password);size(500);null" json:"book_password" `
2017-05-01 12:15:55 +08:00
//状态: 0 正常/1 已删除
2017-07-07 16:20:55 +08:00
Status int ` orm:"column(status);type(int);default(0)" json:"status" `
2017-04-26 18:17:38 +08:00
//默认的编辑器.
2017-07-07 16:20:55 +08:00
Editor string ` orm:"column(editor);size(50)" json:"editor" `
2017-04-21 18:20:35 +08:00
// DocCount 包含文档数量.
2017-07-07 16:20:55 +08:00
DocCount int ` orm:"column(doc_count);type(int)" json:"doc_count" `
2017-04-22 17:24:17 +08:00
// CommentStatus 评论设置的状态:open 为允许所有人评论, closed 为不允许评论, group_only 仅允许参与者评论 ,registered_only 仅允许注册者评论.
2017-07-07 16:20:55 +08:00
CommentStatus string ` orm:"column(comment_status);size(20);default(open)" json:"comment_status" `
CommentCount int ` orm:"column(comment_count);type(int)" json:"comment_count" `
2017-04-30 22:13:12 +08:00
//封面地址
2017-07-07 16:20:55 +08:00
Cover string ` orm:"column(cover);size(1000)" json:"cover" `
2017-04-30 22:13:12 +08:00
//主题风格
2017-07-07 16:20:55 +08:00
Theme string ` orm:"column(theme);size(255);default(default)" json:"theme" `
2017-04-21 18:20:35 +08:00
// CreateTime 创建时间 .
2017-07-07 16:20:55 +08:00
CreateTime time . Time ` orm:"type(datetime);column(create_time);auto_now_add" json:"create_time" `
2018-02-02 23:12:29 +08:00
//每个文档保存的历史记录数量, 0 为不限制
2018-03-25 14:59:42 +08:00
HistoryCount int ` orm:"column(history_count);type(int);default(0)" json:"history_count" `
2018-03-13 19:20:50 +08:00
//是否启用分享, 0启用/1不启用
2018-03-25 14:59:42 +08:00
IsEnableShare int ` orm:"column(is_enable_share);type(int);default(0)" json:"is_enable_share" `
MemberId int ` orm:"column(member_id);size(100)" json:"member_id" `
ModifyTime time . Time ` orm:"type(datetime);column(modify_time);null;auto_now" json:"modify_time" `
Version int64 ` orm:"type(bigint);column(version)" json:"version" `
2018-03-23 10:00:36 +08:00
//是否使用第一篇文章项目为默认首页,0 否/1 是
IsUseFirstDocument int ` orm:"column(is_use_first_document);type(int);default(0)" json:"is_use_first_document" `
2018-08-17 17:33:45 +08:00
//是否开启自动保存: 0 否/1 是
2018-11-13 17:33:13 +08:00
AutoSave int ` orm:"column(auto_save);type(tinyint);default(0)" json:"auto_save" `
2017-04-21 18:20:35 +08:00
}
2018-11-13 17:33:13 +08:00
func ( book * Book ) String ( ) string {
2018-08-14 15:57:52 +08:00
ret , err := json . Marshal ( * book )
2018-08-13 19:05:49 +08:00
if err != nil {
return ""
}
return string ( ret )
}
2017-04-21 18:20:35 +08:00
// TableName 获取对应数据库表名.
2018-03-24 22:36:35 +08:00
func ( book * Book ) TableName ( ) string {
2017-04-21 18:20:35 +08:00
return "books"
}
2017-07-07 16:20:55 +08:00
2017-04-21 18:20:35 +08:00
// TableEngine 获取数据使用的引擎.
2018-03-24 22:36:35 +08:00
func ( book * Book ) TableEngine ( ) string {
2017-04-21 18:20:35 +08:00
return "INNODB"
}
2018-03-24 22:36:35 +08:00
func ( book * Book ) TableNameWithPrefix ( ) string {
return conf . GetDatabasePrefix ( ) + book . TableName ( )
2017-04-22 17:24:17 +08:00
}
2018-11-13 17:33:13 +08:00
func ( book * Book ) QueryTable ( ) orm . QuerySeter {
2018-11-12 21:01:59 +08:00
return orm . NewOrm ( ) . QueryTable ( book . TableNameWithPrefix ( ) )
}
2017-04-22 17:24:17 +08:00
func NewBook ( ) * Book {
return & Book { }
}
2018-03-24 17:24:02 +08:00
//添加一个项目
2021-04-21 22:00:03 +08:00
func ( book * Book ) Insert ( lang string ) error {
2017-04-22 17:24:17 +08:00
o := orm . NewOrm ( )
2017-07-07 16:20:55 +08:00
// o.Begin()
2018-11-08 20:08:30 +08:00
book . BookName = utils . StripTags ( book . BookName )
2018-11-20 20:36:14 +08:00
if book . ItemId <= 0 {
book . ItemId = 1
}
2018-03-24 22:36:35 +08:00
_ , err := o . Insert ( book )
2017-04-22 17:24:17 +08:00
2017-04-24 18:25:17 +08:00
if err == nil {
2018-03-24 22:36:35 +08:00
if book . Label != "" {
NewLabel ( ) . InsertOrUpdateMulti ( book . Label )
2017-07-07 16:20:55 +08:00
}
2017-04-24 18:25:17 +08:00
relationship := NewRelationship ( )
2018-03-24 22:36:35 +08:00
relationship . BookId = book . BookId
2017-04-24 18:25:17 +08:00
relationship . RoleId = 0
2018-03-24 22:36:35 +08:00
relationship . MemberId = book . MemberId
2017-04-24 18:25:17 +08:00
err = relationship . Insert ( )
2017-04-29 21:28:09 +08:00
if err != nil {
2018-11-20 20:36:14 +08:00
logs . Error ( "插入项目与用户关联 -> " , err )
2017-05-05 11:09:17 +08:00
//o.Rollback()
2017-04-29 21:28:09 +08:00
return err
}
document := NewDocument ( )
2018-03-24 22:36:35 +08:00
document . BookId = book . BookId
2021-04-21 22:00:03 +08:00
document . DocumentName = i18n . Tr ( lang , "init.blank_doc" ) //"空白文档"
2018-03-24 22:36:35 +08:00
document . MemberId = book . MemberId
2017-04-29 21:28:09 +08:00
err = document . InsertOrUpdate ( )
2017-07-07 16:20:55 +08:00
if err != nil {
2017-05-05 11:09:17 +08:00
//o.Rollback()
2017-04-29 21:28:09 +08:00
return err
}
2017-05-05 11:09:17 +08:00
//o.Commit()
2017-05-04 10:35:56 +08:00
return nil
2017-04-24 18:25:17 +08:00
}
2017-05-05 11:09:17 +08:00
//o.Rollback()
2017-04-22 17:24:17 +08:00
return err
}
2018-11-13 17:33:13 +08:00
func ( book * Book ) Find ( id int , cols ... string ) ( * Book , error ) {
2017-04-23 20:33:21 +08:00
if id <= 0 {
2018-03-24 22:36:35 +08:00
return book , ErrInvalidParameter
2017-04-23 20:33:21 +08:00
}
o := orm . NewOrm ( )
2018-11-13 17:33:13 +08:00
err := o . QueryTable ( book . TableNameWithPrefix ( ) ) . Filter ( "book_id" , id ) . One ( book , cols ... )
2017-04-25 20:05:59 +08:00
2018-03-24 22:36:35 +08:00
return book , err
2017-04-23 20:33:21 +08:00
}
2018-03-25 14:59:42 +08:00
2018-03-24 17:24:02 +08:00
//更新一个项目
2018-03-24 22:36:35 +08:00
func ( book * Book ) Update ( cols ... string ) error {
2017-04-22 17:24:17 +08:00
o := orm . NewOrm ( )
2018-11-08 20:08:30 +08:00
book . BookName = utils . StripTags ( book . BookName )
2017-07-07 16:20:55 +08:00
temp := NewBook ( )
2018-03-24 22:36:35 +08:00
temp . BookId = book . BookId
2017-07-07 16:20:55 +08:00
2018-01-26 17:17:38 +08:00
if err := o . Read ( temp ) ; err != nil {
2017-07-07 16:20:55 +08:00
return err
}
2018-03-25 14:59:42 +08:00
if book . Label != "" || temp . Label != "" {
2017-07-07 16:20:55 +08:00
2018-03-24 22:36:35 +08:00
go NewLabel ( ) . InsertOrUpdateMulti ( book . Label + "," + temp . Label )
2017-07-07 16:20:55 +08:00
}
2018-03-24 22:36:35 +08:00
_ , err := o . Update ( book , cols ... )
2017-04-22 17:24:17 +08:00
return err
}
2018-07-10 18:53:41 +08:00
//复制项目
func ( book * Book ) Copy ( identify string ) error {
o := orm . NewOrm ( )
2018-11-13 17:33:13 +08:00
err := o . QueryTable ( book . TableNameWithPrefix ( ) ) . Filter ( "identify" , identify ) . One ( book )
2018-07-10 18:53:41 +08:00
if err != nil {
2021-03-30 14:24:14 +08:00
logs . Error ( "查询项目时出错 -> " , err )
2018-07-10 18:53:41 +08:00
return err
}
2021-03-26 11:34:02 +08:00
if _ , err := o . Begin ( ) ; err != nil {
2021-03-30 14:24:14 +08:00
logs . Error ( "开启事物时出错 -> " , err )
2018-07-10 18:53:41 +08:00
return err
}
bookId := book . BookId
book . BookId = 0
2018-11-13 17:33:13 +08:00
book . Identify = book . Identify + fmt . Sprintf ( "%s-%s" , identify , strconv . FormatInt ( time . Now ( ) . UnixNano ( ) , 32 ) )
2018-07-10 18:53:41 +08:00
book . BookName = book . BookName + "[副本]"
book . CreateTime = time . Now ( )
book . CommentCount = 0
book . HistoryCount = 0
2021-03-26 11:34:02 +08:00
/ * v2 version of beego remove the o . Rollback api for transaction operation .
* typically , in v1 , you can write code like this :
*
* o := orm . NewOrm ( )
* if err := o . Operateion ( ) ; err != nil {
* o . Rollback ( )
* ...
* }
*
* however , in v2 , this is not available . beego will handles the transaction in new way using
* cluster . the new code is like below :
*
* o := orm . NewOrm ( )
* if err := o . DoTx ( func ( ctx context . Context , txOrm orm . TxOrmer ) error {
* err := o . Operations ( )
* if err != nil {
* return err
* }
* ...
* } ) ; err != nil {
* ...
* }
*
* when operation failed , it will automatically calls o . Rollback ( ) for TxOrmer .
* more details see https : //beego.me/docs/mvc/model/transaction.md
* /
if err := o . DoTx ( func ( ctx context . Context , txo orm . TxOrmer ) error {
_ , err := txo . Insert ( book )
return err
} ) ; err != nil {
logs . Error ( "复制项目时出错: %s" , err )
2018-07-10 18:53:41 +08:00
return err
}
2021-03-26 11:34:02 +08:00
2018-07-10 18:53:41 +08:00
var rels [ ] * Relationship
2021-03-26 11:34:02 +08:00
if err := o . DoTx ( func ( ctx context . Context , txo orm . TxOrmer ) error {
_ , err := txo . QueryTable ( NewRelationship ( ) . TableNameWithPrefix ( ) ) . Filter ( "book_id" , bookId ) . All ( & rels )
return err
} ) ; err != nil {
2021-03-30 14:24:14 +08:00
logs . Error ( "复制项目关系时出错 -> " , err )
2018-07-10 18:53:41 +08:00
return err
}
2018-11-13 17:33:13 +08:00
for _ , rel := range rels {
2018-07-10 18:53:41 +08:00
rel . BookId = book . BookId
rel . RelationshipId = 0
2021-03-26 11:34:02 +08:00
if err := o . DoTx ( func ( ctx context . Context , txo orm . TxOrmer ) error {
_ , err := txo . Insert ( rel )
return err
} ) ; err != nil {
2021-03-30 14:24:14 +08:00
logs . Error ( "复制项目关系时出错 -> " , err )
2018-07-10 18:53:41 +08:00
return err
}
}
var docs [ ] * Document
2021-03-26 11:34:02 +08:00
if err := o . DoTx ( func ( ctx context . Context , txOrm orm . TxOrmer ) error {
_ , err := txOrm . QueryTable ( NewDocument ( ) . TableNameWithPrefix ( ) ) . Filter ( "book_id" , bookId ) . Filter ( "parent_id" , 0 ) . All ( & docs )
return err
} ) ; err != nil && err != orm . ErrNoRows {
2021-03-30 14:24:14 +08:00
logs . Error ( "读取项目文档时出错 -> " , err )
2018-07-10 18:53:41 +08:00
return err
}
2021-03-26 11:34:02 +08:00
2018-07-10 18:53:41 +08:00
if len ( docs ) > 0 {
2021-03-26 11:34:02 +08:00
if err := o . DoTx ( func ( ctx context . Context , txOrm orm . TxOrmer ) error {
return recursiveInsertDocument ( docs , txOrm , book . BookId , 0 )
} ) ; err != nil {
2021-03-30 14:24:14 +08:00
logs . Error ( "复制项目时出错 -> " , err )
2018-07-10 18:53:41 +08:00
return err
}
}
2021-03-26 11:34:02 +08:00
return nil
2018-07-10 18:53:41 +08:00
}
2018-11-13 17:33:13 +08:00
2018-07-10 18:53:41 +08:00
//递归的复制文档
2021-03-26 11:34:02 +08:00
func recursiveInsertDocument ( docs [ ] * Document , o orm . TxOrmer , bookId int , parentId int ) error {
2018-11-13 17:33:13 +08:00
for _ , doc := range docs {
2018-07-10 18:53:41 +08:00
docId := doc . DocumentId
doc . DocumentId = 0
doc . ParentId = parentId
doc . BookId = bookId
doc . Version = time . Now ( ) . Unix ( )
2018-11-13 17:33:13 +08:00
if _ , err := o . Insert ( doc ) ; err != nil {
2021-03-30 14:24:14 +08:00
logs . Error ( "插入项目时出错 -> " , err )
2018-07-10 18:53:41 +08:00
return err
}
var attachList [ ] * Attachment
//读取所有附件列表
2018-11-13 17:33:13 +08:00
if _ , err := o . QueryTable ( NewAttachment ( ) . TableNameWithPrefix ( ) ) . Filter ( "document_id" , docId ) . All ( & attachList ) ; err == nil {
for _ , attach := range attachList {
2018-07-10 18:53:41 +08:00
attach . BookId = bookId
attach . DocumentId = doc . DocumentId
attach . AttachmentId = 0
2018-11-13 17:33:13 +08:00
if _ , err := o . Insert ( attach ) ; err != nil {
2018-07-10 18:53:41 +08:00
return err
}
}
}
var subDocs [ ] * Document
2018-11-13 17:33:13 +08:00
if _ , err := o . QueryTable ( NewDocument ( ) . TableNameWithPrefix ( ) ) . Filter ( "parent_id" , docId ) . All ( & subDocs ) ; err != nil && err != orm . ErrNoRows {
2021-03-30 14:24:14 +08:00
logs . Error ( "读取文档时出错 -> " , err )
2018-07-10 18:53:41 +08:00
return err
}
2018-11-13 17:33:13 +08:00
if len ( subDocs ) > 0 {
2018-07-10 18:53:41 +08:00
2018-11-13 17:33:13 +08:00
if err := recursiveInsertDocument ( subDocs , o , bookId , doc . DocumentId ) ; err != nil {
2018-07-10 18:53:41 +08:00
return err
}
}
}
return nil
}
2017-04-30 22:13:12 +08:00
//根据指定字段查询结果集.
2018-11-13 17:33:13 +08:00
func ( book * Book ) FindByField ( field string , value interface { } , cols ... string ) ( [ ] * Book , error ) {
2017-04-22 17:24:17 +08:00
o := orm . NewOrm ( )
2017-04-30 22:13:12 +08:00
var books [ ] * Book
2018-11-13 17:33:13 +08:00
_ , err := o . QueryTable ( book . TableNameWithPrefix ( ) ) . Filter ( field , value ) . All ( & books , cols ... )
2017-04-22 17:24:17 +08:00
2017-07-07 16:20:55 +08:00
return books , err
2017-04-22 17:24:17 +08:00
}
2017-04-30 22:13:12 +08:00
//根据指定字段查询一个结果.
2018-03-24 22:36:35 +08:00
func ( book * Book ) FindByFieldFirst ( field string , value interface { } ) ( * Book , error ) {
2017-04-24 18:25:17 +08:00
o := orm . NewOrm ( )
2018-03-24 22:36:35 +08:00
err := o . QueryTable ( book . TableNameWithPrefix ( ) ) . Filter ( field , value ) . One ( book )
2017-04-24 18:25:17 +08:00
2018-03-24 22:36:35 +08:00
return book , err
2017-04-24 18:25:17 +08:00
}
2017-04-30 22:13:12 +08:00
2018-03-24 17:24:02 +08:00
//根据项目标识查询项目
2018-11-13 17:33:13 +08:00
func ( book * Book ) FindByIdentify ( identify string , cols ... string ) ( * Book , error ) {
2017-05-12 10:45:40 +08:00
o := orm . NewOrm ( )
2018-11-13 17:33:13 +08:00
err := o . QueryTable ( book . TableNameWithPrefix ( ) ) . Filter ( "identify" , identify ) . One ( book , cols ... )
2017-05-12 10:45:40 +08:00
2018-03-24 22:36:35 +08:00
return book , err
2017-05-12 10:45:40 +08:00
}
2017-04-30 22:13:12 +08:00
//分页查询指定用户的项目
2021-04-12 21:12:26 +08:00
func ( book * Book ) FindToPager ( pageIndex , pageSize , memberId int , lang string ) ( books [ ] * BookResult , totalCount int , err error ) {
2017-04-22 17:24:17 +08:00
o := orm . NewOrm ( )
2018-11-13 17:33:13 +08:00
//sql1 := "SELECT COUNT(book.book_id) AS total_count FROM " + book.TableNameWithPrefix() + " AS book LEFT JOIN " +
// relationship.TableNameWithPrefix() + " AS rel ON book.book_id=rel.book_id AND rel.member_id = ? WHERE rel.relationship_id > 0 "
sql1 := ` SELECT
count ( * ) AS total_count
FROM md_books AS book
LEFT JOIN md_relationship AS rel ON book . book_id = rel . book_id AND rel . member_id = ?
2018-11-26 18:54:50 +08:00
left join ( select book_id , min ( role_id ) as role_id
2018-11-13 17:33:13 +08:00
from ( select book_id , team_member_id , role_id
from md_team_relationship as mtr
2018-11-26 18:54:50 +08:00
left join md_team_member as mtm on mtm . team_id = mtr . team_id and mtm . member_id = ? order by role_id desc )
as t group by t . book_id )
as team on team . book_id = book . book_id WHERE rel . role_id >= 0 or team . role_id >= 0 `
2017-04-22 17:24:17 +08:00
2018-11-13 17:33:13 +08:00
err = o . Raw ( sql1 , memberId , memberId ) . QueryRow ( & totalCount )
2017-04-22 17:24:17 +08:00
if err != nil {
return
}
offset := ( pageIndex - 1 ) * pageSize
2017-07-07 16:20:55 +08:00
2018-11-13 17:33:13 +08:00
//sql2 := "SELECT book.*,rel.member_id,rel.role_id,m.account as create_name FROM " + book.TableNameWithPrefix() + " AS book" +
// " LEFT JOIN " + relationship.TableNameWithPrefix() + " AS rel ON book.book_id=rel.book_id AND rel.member_id = ?" +
// " LEFT JOIN " + relationship.TableNameWithPrefix() + " AS rel1 ON book.book_id=rel1.book_id AND rel1.role_id=0" +
// " LEFT JOIN " + NewMember().TableNameWithPrefix() + " AS m ON rel1.member_id=m.member_id " +
// " WHERE rel.relationship_id > 0 ORDER BY book.order_index DESC,book.book_id DESC LIMIT " + fmt.Sprintf("%d,%d", offset, pageSize)
sql2 := ` SELECT
book . * ,
case when rel . relationship_id is null then team . role_id else rel . role_id end as role_id ,
m . account as create_name
FROM md_books AS book
LEFT JOIN md_relationship AS rel ON book . book_id = rel . book_id AND rel . member_id = ?
2018-11-26 18:54:50 +08:00
left join ( select book_id , min ( role_id ) as role_id
2018-11-13 17:33:13 +08:00
from ( select book_id , team_member_id , role_id
from md_team_relationship as mtr
2018-11-26 18:54:50 +08:00
left join md_team_member as mtm on mtm . team_id = mtr . team_id and mtm . member_id = ? order by role_id desc )
as t group by book_id ) as team
2018-11-13 17:33:13 +08:00
on team . book_id = book . book_id
LEFT JOIN md_relationship AS rel1 ON book . book_id = rel1 . book_id AND rel1 . role_id = 0
LEFT JOIN md_members AS m ON rel1 . member_id = m . member_id
2018-11-26 18:54:50 +08:00
WHERE rel . role_id >= 0 or team . role_id >= 0
2018-11-13 17:33:13 +08:00
ORDER BY book . order_index , book . book_id DESC limit ? , ? `
_ , err = o . Raw ( sql2 , memberId , memberId , offset , pageSize ) . QueryRows ( & books )
2017-04-24 18:25:17 +08:00
if err != nil {
2017-07-07 16:20:55 +08:00
logs . Error ( "分页查询项目列表 => " , err )
2017-04-24 18:25:17 +08:00
return
}
2017-04-22 17:24:17 +08:00
sql := "SELECT m.account,doc.modify_time FROM md_documents AS doc LEFT JOIN md_members AS m ON doc.modify_at=m.member_id WHERE book_id = ? LIMIT 1 ORDER BY doc.modify_time DESC"
2019-05-20 17:38:37 +08:00
if len ( books ) > 0 {
2017-07-07 16:20:55 +08:00
for index , book := range books {
var text struct {
Account string
2017-04-22 17:24:17 +08:00
ModifyTime time . Time
}
2017-07-07 16:20:55 +08:00
err1 := o . Raw ( sql , book . BookId ) . QueryRow ( & text )
2017-04-22 17:24:17 +08:00
if err1 == nil {
books [ index ] . LastModifyText = text . Account + " 于 " + text . ModifyTime . Format ( "2006-01-02 15:04:05" )
}
2017-07-07 16:20:55 +08:00
if book . RoleId == 0 {
2021-04-12 21:12:26 +08:00
book . RoleName = i18n . Tr ( lang , "common.creator" )
2017-07-07 16:20:55 +08:00
} else if book . RoleId == 1 {
2021-04-12 21:12:26 +08:00
book . RoleName = i18n . Tr ( lang , "common.administrator" )
2017-07-07 16:20:55 +08:00
} else if book . RoleId == 2 {
2021-04-12 21:12:26 +08:00
book . RoleName = i18n . Tr ( lang , "common.editor" )
2017-07-07 16:20:55 +08:00
} else if book . RoleId == 3 {
2021-04-12 21:12:26 +08:00
book . RoleName = i18n . Tr ( lang , "common.observer" )
2017-04-22 17:24:17 +08:00
}
}
}
return
2017-04-23 12:48:46 +08:00
}
2017-04-23 20:33:21 +08:00
// 彻底删除项目.
2018-03-24 22:36:35 +08:00
func ( book * Book ) ThoroughDeleteBook ( id int ) error {
2017-07-07 16:20:55 +08:00
if id <= 0 {
2017-04-23 20:33:21 +08:00
return ErrInvalidParameter
}
o := orm . NewOrm ( )
2018-03-25 14:59:42 +08:00
book , err := book . Find ( id )
2018-03-08 16:36:13 +08:00
if err != nil {
2017-04-23 20:33:21 +08:00
return err
}
o . Begin ( )
2017-07-07 16:20:55 +08:00
2018-08-14 15:57:52 +08:00
//删除附件,这里没有删除实际物理文件
2021-03-26 11:34:02 +08:00
if err := o . DoTx ( func ( ctx context . Context , txOrm orm . TxOrmer ) error {
_ , err = txOrm . Raw ( "DELETE FROM " + NewAttachment ( ) . TableNameWithPrefix ( ) + " WHERE book_id=?" , book . BookId ) . Exec ( )
return err
} ) ; err != nil {
2017-04-23 20:33:21 +08:00
return err
}
2018-08-14 15:57:52 +08:00
//删除文档
2021-03-26 11:34:02 +08:00
if err := o . DoTx ( func ( ctx context . Context , txOrm orm . TxOrmer ) error {
_ , err = txOrm . Raw ( "DELETE FROM " + NewDocument ( ) . TableNameWithPrefix ( ) + " WHERE book_id = ?" , book . BookId ) . Exec ( )
return err
} ) ; err != nil {
2017-04-23 20:33:21 +08:00
return err
}
2018-08-14 15:57:52 +08:00
//删除项目
2021-03-26 11:34:02 +08:00
if err := o . DoTx ( func ( ctx context . Context , txOrm orm . TxOrmer ) error {
_ , err = txOrm . Raw ( "DELETE FROM " + book . TableNameWithPrefix ( ) + " WHERE book_id = ?" , book . BookId ) . Exec ( )
return err
} ) ; err != nil {
2018-08-14 15:57:52 +08:00
return err
}
2018-04-02 15:52:36 +08:00
2018-08-14 15:57:52 +08:00
//删除关系
2021-03-26 11:34:02 +08:00
if err := o . DoTx ( func ( ctx context . Context , txOrm orm . TxOrmer ) error {
_ , err = txOrm . Raw ( "DELETE FROM " + NewRelationship ( ) . TableNameWithPrefix ( ) + " WHERE book_id = ?" , book . BookId ) . Exec ( )
return err
} ) ; err != nil {
2018-11-16 10:46:37 +08:00
return err
}
2021-03-26 11:34:02 +08:00
if err := o . DoTx ( func ( ctx context . Context , txOrm orm . TxOrmer ) error {
_ , err = txOrm . Raw ( fmt . Sprintf ( "DELETE FROM %s WHERE book_id=?" , NewTeamRelationship ( ) . TableNameWithPrefix ( ) ) , book . BookId ) . Exec ( )
return err
} ) ; err != nil {
2018-08-14 15:57:52 +08:00
return err
}
//删除模板
2021-03-26 11:34:02 +08:00
if err := o . DoTx ( func ( ctx context . Context , txOrm orm . TxOrmer ) error {
_ , err = txOrm . Raw ( "DELETE FROM " + NewTemplate ( ) . TableNameWithPrefix ( ) + " WHERE book_id = ?" , book . BookId ) . Exec ( )
return err
} ) ; err != nil {
2017-04-23 20:33:21 +08:00
return err
}
2018-03-24 22:36:35 +08:00
if book . Label != "" {
NewLabel ( ) . InsertOrUpdateMulti ( book . Label )
2017-07-07 16:20:55 +08:00
}
2018-08-20 15:11:32 +08:00
//删除导出缓存
2018-08-15 16:00:04 +08:00
if err := os . RemoveAll ( filepath . Join ( conf . GetExportOutputPath ( ) , strconv . Itoa ( id ) ) ) ; err != nil {
2021-03-30 14:24:14 +08:00
logs . Error ( "删除项目缓存失败 ->" , err )
2018-08-15 16:00:04 +08:00
}
2018-08-20 15:11:32 +08:00
//删除附件和图片
2018-11-13 17:33:13 +08:00
if err := os . RemoveAll ( filepath . Join ( conf . WorkingDirectory , "uploads" , book . Identify ) ) ; err != nil {
2021-03-30 14:24:14 +08:00
logs . Error ( "删除项目附件和图片失败 ->" , err )
2018-08-20 15:11:32 +08:00
}
2018-01-26 17:17:38 +08:00
2021-03-26 11:34:02 +08:00
return nil
2017-04-23 20:33:21 +08:00
}
2017-05-13 12:12:37 +08:00
//分页查找系统首页数据.
2018-11-13 17:33:13 +08:00
func ( book * Book ) FindForHomeToPager ( pageIndex , pageSize , memberId int ) ( books [ ] * BookResult , totalCount int , err error ) {
2017-04-30 22:13:12 +08:00
o := orm . NewOrm ( )
offset := ( pageIndex - 1 ) * pageSize
//如果是登录用户
2018-11-13 17:33:13 +08:00
if memberId > 0 {
sql1 := ` SELECT COUNT ( * )
FROM md_books AS book
LEFT JOIN md_relationship AS rel ON rel . book_id = book . book_id AND rel . member_id = ?
2018-11-26 18:54:50 +08:00
left join ( select book_id , min ( role_id ) AS role_id
from ( select book_id , role_id
2018-11-13 17:33:13 +08:00
from md_team_relationship as mtr
2018-11-26 18:54:50 +08:00
left join md_team_member as mtm on mtm . team_id = mtr . team_id and mtm . member_id = ? order by role_id desc )
as t group by book_id ) as team on team . book_id = book . book_id
WHERE book . privately_owned = 0 or rel . role_id >= 0 or team . role_id >= 0 `
2018-11-13 17:33:13 +08:00
err = o . Raw ( sql1 , memberId , memberId ) . QueryRow ( & totalCount )
2017-04-30 22:13:12 +08:00
if err != nil {
return
}
2022-03-03 11:38:11 +08:00
sql2 := ` SELECT book . * , rel1 . * , mdmb . account AS create_name , mdmb . real_name FROM md_books AS book
2018-11-13 17:33:13 +08:00
LEFT JOIN md_relationship AS rel ON rel . book_id = book . book_id AND rel . member_id = ?
2018-11-26 18:54:50 +08:00
left join ( select book_id , min ( role_id ) AS role_id
from ( select book_id , role_id
2018-11-13 17:33:13 +08:00
from md_team_relationship as mtr
2018-11-26 18:54:50 +08:00
left join md_team_member as mtm on mtm . team_id = mtr . team_id and mtm . member_id = ? order by role_id desc )
as t group by book_id ) as team on team . book_id = book . book_id
2018-11-13 17:33:13 +08:00
LEFT JOIN md_relationship AS rel1 ON rel1 . book_id = book . book_id AND rel1 . role_id = 0
2022-03-03 11:38:11 +08:00
LEFT JOIN md_members AS mdmb ON rel1 . member_id = mdmb . member_id
2018-11-28 09:56:20 +08:00
WHERE book . privately_owned = 0 or rel . role_id >= 0 or team . role_id >= 0 ORDER BY order_index desc , book . book_id DESC LIMIT ? , ? `
2017-04-23 20:33:21 +08:00
2018-11-13 17:33:13 +08:00
_ , err = o . Raw ( sql2 , memberId , memberId , offset , pageSize ) . QueryRows ( & books )
2017-04-23 20:33:21 +08:00
2017-07-07 16:20:55 +08:00
} else {
2018-03-24 22:36:35 +08:00
count , err1 := o . QueryTable ( book . TableNameWithPrefix ( ) ) . Filter ( "privately_owned" , 0 ) . Count ( )
2017-04-23 20:33:21 +08:00
2017-04-30 22:13:12 +08:00
if err1 != nil {
err = err1
return
}
totalCount = int ( count )
2017-04-23 20:33:21 +08:00
2022-03-03 11:38:11 +08:00
sql := ` SELECT book . * , rel . * , mdmb . account AS create_name , mdmb . real_name FROM md_books AS book
2017-04-30 22:13:12 +08:00
LEFT JOIN md_relationship AS rel ON rel . book_id = book . book_id AND rel . role_id = 0
2022-03-03 11:38:11 +08:00
LEFT JOIN md_members AS mdmb ON rel . member_id = mdmb . member_id
2017-04-30 22:13:12 +08:00
WHERE book . privately_owned = 0 ORDER BY order_index DESC , book . book_id DESC LIMIT ? , ? `
2017-07-07 16:20:55 +08:00
_ , err = o . Raw ( sql , offset , pageSize ) . QueryRows ( & books )
2017-04-30 22:13:12 +08:00
}
2018-02-02 23:12:29 +08:00
return
2017-04-30 22:13:12 +08:00
}
2017-07-07 16:20:55 +08:00
//分页全局搜索.
2018-03-24 22:36:35 +08:00
func ( book * Book ) FindForLabelToPager ( keyword string , pageIndex , pageSize , memberId int ) ( books [ ] * BookResult , totalCount int , err error ) {
2017-07-07 16:20:55 +08:00
o := orm . NewOrm ( )
keyword = "%" + keyword + "%"
offset := ( pageIndex - 1 ) * pageSize
//如果是登录用户
2018-02-28 15:47:00 +08:00
if memberId > 0 {
2018-11-13 17:33:13 +08:00
sql1 := ` SELECT COUNT ( * )
FROM md_books AS book
LEFT JOIN md_relationship AS rel ON rel . book_id = book . book_id AND rel . member_id = ?
left join ( select *
from ( select book_id , team_member_id , role_id
from md_team_relationship as mtr
2018-11-26 18:54:50 +08:00
left join md_team_member as mtm on mtm . team_id = mtr . team_id and mtm . member_id = ? order by role_id desc ) as t group by t . role_id , t . team_member_id , t . book_id ) as team on team . book_id = book . book_id
2018-11-13 17:33:13 +08:00
WHERE ( relationship_id > 0 OR book . privately_owned = 0 or team . team_member_id > 0 ) AND book . label LIKE ? `
err = o . Raw ( sql1 , memberId , memberId , keyword ) . QueryRow ( & totalCount )
2017-07-07 16:20:55 +08:00
if err != nil {
return
}
2022-03-03 11:38:11 +08:00
sql2 := ` SELECT book . * , rel1 . * , mdmb . account AS create_name FROM md_books AS book
2017-07-07 16:20:55 +08:00
LEFT JOIN md_relationship AS rel ON rel . book_id = book . book_id AND rel . member_id = ?
2018-11-13 17:33:13 +08:00
left join ( select * from ( select book_id , team_member_id , role_id
from md_team_relationship as mtr
2018-11-26 18:54:50 +08:00
left join md_team_member as mtm on mtm . team_id = mtr . team_id and mtm . member_id = ? order by role_id desc ) as t group by t . role_id , t . team_member_id , t . book_id ) as team
2018-11-13 17:33:13 +08:00
on team . book_id = book . book_id
2017-07-07 16:20:55 +08:00
LEFT JOIN md_relationship AS rel1 ON rel1 . book_id = book . book_id AND rel1 . role_id = 0
2022-03-03 11:38:11 +08:00
LEFT JOIN md_members AS mdmb ON rel1 . member_id = mdmb . member_id
2018-11-13 17:33:13 +08:00
WHERE ( rel . relationship_id > 0 OR book . privately_owned = 0 or team . team_member_id > 0 )
AND book . label LIKE ? ORDER BY order_index DESC , book . book_id DESC LIMIT ? , ? `
2017-07-07 16:20:55 +08:00
2018-11-13 17:33:13 +08:00
_ , err = o . Raw ( sql2 , memberId , memberId , keyword , offset , pageSize ) . QueryRows ( & books )
2017-07-07 16:20:55 +08:00
return
} else {
2018-01-26 17:17:38 +08:00
count , err1 := o . QueryTable ( NewBook ( ) . TableNameWithPrefix ( ) ) . Filter ( "privately_owned" , 0 ) . Filter ( "label__icontains" , keyword ) . Count ( )
2017-07-07 16:20:55 +08:00
if err1 != nil {
err = err1
return
}
totalCount = int ( count )
2022-03-03 11:38:11 +08:00
sql := ` SELECT book . * , rel . * , mdmb . account AS create_name FROM md_books AS book
2017-07-07 16:20:55 +08:00
LEFT JOIN md_relationship AS rel ON rel . book_id = book . book_id AND rel . role_id = 0
2022-03-03 11:38:11 +08:00
LEFT JOIN md_members AS mdmb ON rel . member_id = mdmb . member_id
2017-07-07 16:20:55 +08:00
WHERE book . privately_owned = 0 AND book . label LIKE ? ORDER BY order_index DESC , book . book_id DESC LIMIT ? , ? `
2018-01-26 17:17:38 +08:00
_ , err = o . Raw ( sql , keyword , offset , pageSize ) . QueryRows ( & books )
2017-07-07 16:20:55 +08:00
return
}
}
2019-05-20 17:38:37 +08:00
// ReleaseContent 批量发布文档
2021-04-12 21:12:26 +08:00
func ( book * Book ) ReleaseContent ( bookId int , lang string ) {
2019-05-20 17:38:37 +08:00
releaseQueue <- bookId
once . Do ( func ( ) {
go func ( ) {
defer func ( ) {
if err := recover ( ) ; err != nil {
2021-03-30 14:24:14 +08:00
logs . Error ( "协程崩溃 ->" , err )
2019-05-20 17:38:37 +08:00
}
} ( )
for bookId := range releaseQueue {
o := orm . NewOrm ( )
2018-03-25 14:59:42 +08:00
2019-05-20 17:38:37 +08:00
var docs [ ] * Document
_ , err := o . QueryTable ( NewDocument ( ) . TableNameWithPrefix ( ) ) . Filter ( "book_id" , bookId ) . All ( & docs )
2018-03-25 14:59:42 +08:00
2019-05-20 17:38:37 +08:00
if err != nil {
2021-03-30 14:24:14 +08:00
logs . Error ( "发布失败 =>" , bookId , err )
2019-05-20 17:38:37 +08:00
continue
}
for _ , item := range docs {
item . BookId = bookId
2021-04-12 21:12:26 +08:00
item . Lang = lang
2019-05-20 17:38:37 +08:00
_ = item . ReleaseContent ( )
}
2018-03-25 14:59:42 +08:00
2019-05-20 17:38:37 +08:00
//当文档发布后,需要删除已缓存的转换项目
outputPath := filepath . Join ( conf . GetExportOutputPath ( ) , strconv . Itoa ( bookId ) )
_ = os . RemoveAll ( outputPath )
}
} ( )
} )
2018-03-25 14:59:42 +08:00
}
2017-05-02 10:00:21 +08:00
//重置文档数量
2018-03-24 22:36:35 +08:00
func ( book * Book ) ResetDocumentNumber ( bookId int ) {
2017-05-02 10:00:21 +08:00
o := orm . NewOrm ( )
2017-04-23 20:33:21 +08:00
2018-02-28 15:47:00 +08:00
totalCount , err := o . QueryTable ( NewDocument ( ) . TableNameWithPrefix ( ) ) . Filter ( "book_id" , bookId ) . Count ( )
2017-05-02 10:00:21 +08:00
if err == nil {
2018-11-13 17:33:13 +08:00
_ , err = o . Raw ( "UPDATE md_books SET doc_count = ? WHERE book_id = ?" , int ( totalCount ) , bookId ) . Exec ( )
2018-04-02 15:52:36 +08:00
if err != nil {
2021-03-30 14:24:14 +08:00
logs . Error ( "重置文档数量失败 =>" , bookId , err )
2018-04-02 15:52:36 +08:00
}
2017-07-07 16:20:55 +08:00
} else {
2021-03-30 14:24:14 +08:00
logs . Error ( "获取文档数量失败 =>" , bookId , err )
2017-05-02 10:00:21 +08:00
}
}
2018-03-24 17:24:02 +08:00
2022-02-11 11:10:58 +08:00
// 导入zip项目
2021-04-12 21:12:26 +08:00
func ( book * Book ) ImportBook ( zipPath string , lang string ) error {
2018-03-24 17:24:02 +08:00
if ! filetil . FileExists ( zipPath ) {
2018-03-25 14:59:42 +08:00
return errors . New ( "文件不存在 => " + zipPath )
2018-03-24 17:24:02 +08:00
}
w := md5 . New ( )
2018-03-25 14:59:42 +08:00
io . WriteString ( w , zipPath ) //将str写入到w中
2018-03-24 17:24:02 +08:00
io . WriteString ( w , time . Now ( ) . String ( ) )
2018-03-24 22:36:35 +08:00
io . WriteString ( w , book . BookName )
2018-03-24 17:24:02 +08:00
md5str := fmt . Sprintf ( "%x" , w . Sum ( nil ) ) //w.Sum(nil)将w的hash转成[]byte格式
2018-03-25 14:59:42 +08:00
tempPath := filepath . Join ( os . TempDir ( ) , md5str )
2018-03-24 17:24:02 +08:00
2018-04-02 15:52:36 +08:00
if err := os . MkdirAll ( tempPath , 0766 ) ; err != nil {
2021-03-30 14:24:14 +08:00
logs . Error ( "创建导入目录出错 => " , err )
2018-04-02 15:52:36 +08:00
}
2018-03-24 17:24:02 +08:00
//如果加压缩失败
2018-03-25 14:59:42 +08:00
if err := ziptil . Unzip ( zipPath , tempPath ) ; err != nil {
2022-06-20 13:54:53 +08:00
logs . Error ( "CAll ziptil.Unzip error, zipPath: %s, tempPath: %s, err: %v" ,
zipPath , tempPath , err )
2018-03-24 17:24:02 +08:00
return err
}
2018-03-25 14:59:42 +08:00
//当导入结束后,删除临时文件
2018-07-23 09:54:00 +08:00
//defer os.RemoveAll(tempPath)
2018-03-25 14:59:42 +08:00
for {
//如果当前目录下只有一个目录,则重置根目录
if entries , err := ioutil . ReadDir ( tempPath ) ; err == nil && len ( entries ) == 1 {
dir := entries [ 0 ]
if dir . IsDir ( ) && dir . Name ( ) != "." && dir . Name ( ) != ".." {
tempPath = filepath . Join ( tempPath , dir . Name ( ) )
break
}
} else {
break
}
}
2018-03-24 17:24:02 +08:00
2018-03-25 14:59:42 +08:00
tempPath = strings . Replace ( tempPath , "\\" , "/" , - 1 )
2018-03-24 22:36:35 +08:00
2018-03-25 14:59:42 +08:00
docMap := make ( map [ string ] int , 0 )
o := orm . NewOrm ( )
o . Insert ( book )
relationship := NewRelationship ( )
relationship . BookId = book . BookId
relationship . RoleId = 0
relationship . MemberId = book . MemberId
relationship . Insert ( )
2018-03-24 17:24:02 +08:00
err := filepath . Walk ( tempPath , func ( path string , info os . FileInfo , err error ) error {
2018-03-25 14:59:42 +08:00
path = strings . Replace ( path , "\\" , "/" , - 1 )
2018-03-24 17:24:02 +08:00
if path == tempPath {
return nil
}
if ! info . IsDir ( ) {
ext := filepath . Ext ( info . Name ( ) )
2018-03-24 22:36:35 +08:00
//如果是Markdown文件
2018-03-25 14:59:42 +08:00
if strings . EqualFold ( ext , ".md" ) || strings . EqualFold ( ext , ".markdown" ) {
2021-03-30 14:24:14 +08:00
logs . Info ( "正在处理 =>" , path , info . Name ( ) )
2018-03-24 17:24:02 +08:00
doc := NewDocument ( )
doc . BookId = book . BookId
2018-03-24 22:36:35 +08:00
doc . MemberId = book . MemberId
2018-03-24 17:24:02 +08:00
docIdentify := strings . Replace ( strings . TrimPrefix ( path , tempPath + "/" ) , "/" , "-" , - 1 )
if ok , err := regexp . MatchString ( ` [a-z]+[a-zA-Z0-9_.\-]*$ ` , docIdentify ) ; ! ok || err != nil {
docIdentify = "import-" + docIdentify
}
doc . Identify = docIdentify
2018-03-24 22:36:35 +08:00
//匹配图片,如果图片语法是在代码块中,这里同样会处理
2018-03-24 17:24:02 +08:00
re := regexp . MustCompile ( ` !\[(.*?)\]\((.*?)\) ` )
2018-03-26 19:26:01 +08:00
markdown , err := filetil . ReadFileAndIgnoreUTF8BOM ( path )
2018-03-24 17:24:02 +08:00
if err != nil {
return err
}
2018-03-26 19:26:01 +08:00
2018-03-25 10:56:52 +08:00
//处理图片
2018-03-24 17:24:02 +08:00
doc . Markdown = re . ReplaceAllStringFunc ( string ( markdown ) , func ( image string ) string {
2018-03-25 14:59:42 +08:00
images := re . FindAllSubmatch ( [ ] byte ( image ) , - 1 )
2018-03-24 17:24:02 +08:00
if len ( images ) <= 0 || len ( images [ 0 ] ) < 3 {
return image
}
2018-03-24 22:36:35 +08:00
originalImageUrl := string ( images [ 0 ] [ 2 ] )
imageUrl := strings . Replace ( string ( originalImageUrl ) , "\\" , "/" , - 1 )
2018-03-24 17:24:02 +08:00
//如果是本地路径,则需要将图片复制到项目目录
2018-07-23 09:54:00 +08:00
if ! strings . HasPrefix ( imageUrl , "http://" ) &&
! strings . HasPrefix ( imageUrl , "https://" ) &&
2018-11-13 17:33:13 +08:00
! strings . HasPrefix ( imageUrl , "ftp://" ) {
2018-03-26 22:39:16 +08:00
//如果路径中存在参数
2018-11-13 17:33:13 +08:00
if l := strings . Index ( imageUrl , "?" ) ; l > 0 {
2018-03-26 22:39:16 +08:00
imageUrl = imageUrl [ : l ]
}
2018-03-24 17:24:02 +08:00
if strings . HasPrefix ( imageUrl , "/" ) {
imageUrl = filepath . Join ( tempPath , imageUrl )
} else if strings . HasPrefix ( imageUrl , "./" ) {
imageUrl = filepath . Join ( filepath . Dir ( path ) , strings . TrimPrefix ( imageUrl , "./" ) )
} else if strings . HasPrefix ( imageUrl , "../" ) {
imageUrl = filepath . Join ( filepath . Dir ( path ) , imageUrl )
} else {
imageUrl = filepath . Join ( filepath . Dir ( path ) , imageUrl )
}
2018-03-24 22:36:35 +08:00
imageUrl = strings . Replace ( imageUrl , "\\" , "/" , - 1 )
dstFile := filepath . Join ( conf . WorkingDirectory , "uploads" , time . Now ( ) . Format ( "200601" ) , strings . TrimPrefix ( imageUrl , tempPath ) )
2018-03-24 17:24:02 +08:00
if filetil . FileExists ( imageUrl ) {
2018-03-24 22:36:35 +08:00
filetil . CopyFile ( imageUrl , dstFile )
2018-03-24 17:24:02 +08:00
2018-11-13 17:33:13 +08:00
imageUrl = strings . TrimPrefix ( strings . Replace ( dstFile , "\\" , "/" , - 1 ) , strings . Replace ( conf . WorkingDirectory , "\\" , "/" , - 1 ) )
2018-03-24 17:24:02 +08:00
2018-03-24 22:36:35 +08:00
if ! strings . HasPrefix ( imageUrl , "/" ) && ! strings . HasPrefix ( imageUrl , "\\" ) {
2018-03-24 17:24:02 +08:00
imageUrl = "/" + imageUrl
}
}
2018-03-24 22:36:35 +08:00
} else {
2018-03-24 17:24:02 +08:00
imageExt := cryptil . Md5Crypt ( imageUrl ) + filepath . Ext ( imageUrl )
2018-03-24 22:36:35 +08:00
dstFile := filepath . Join ( conf . WorkingDirectory , "uploads" , time . Now ( ) . Format ( "200601" ) , imageExt )
2018-03-24 17:24:02 +08:00
2018-03-24 22:36:35 +08:00
if err := requests . DownloadAndSaveFile ( imageUrl , dstFile ) ; err == nil {
imageUrl = strings . TrimPrefix ( strings . Replace ( dstFile , "\\" , "/" , - 1 ) , strings . Replace ( conf . WorkingDirectory , "\\" , "/" , - 1 ) )
if ! strings . HasPrefix ( imageUrl , "/" ) && ! strings . HasPrefix ( imageUrl , "\\" ) {
2018-03-24 17:24:02 +08:00
imageUrl = "/" + imageUrl
}
}
}
2018-11-13 17:33:13 +08:00
imageUrl = strings . Replace ( strings . TrimSuffix ( image , originalImageUrl + ")" ) + conf . URLForWithCdnImage ( imageUrl ) + ")" , "\\" , "/" , - 1 )
2018-03-24 17:24:02 +08:00
return imageUrl
} )
2018-03-25 10:56:52 +08:00
linkRegexp := regexp . MustCompile ( ` \[(.*?)\]\((.*?)\) ` )
2018-07-23 09:54:00 +08:00
//处理链接
2018-03-25 10:56:52 +08:00
doc . Markdown = linkRegexp . ReplaceAllStringFunc ( doc . Markdown , func ( link string ) string {
2018-03-25 14:59:42 +08:00
links := linkRegexp . FindAllStringSubmatch ( link , - 1 )
originalLink := links [ 0 ] [ 2 ]
2018-07-23 09:54:00 +08:00
var linkPath string
var err error
2018-11-13 17:33:13 +08:00
if strings . HasPrefix ( originalLink , "<" ) {
originalLink = strings . TrimPrefix ( originalLink , "<" )
2018-07-23 14:38:33 +08:00
}
2018-11-13 17:33:13 +08:00
if strings . HasSuffix ( originalLink , ">" ) {
originalLink = strings . TrimSuffix ( originalLink , ">" )
2018-07-23 14:38:33 +08:00
}
2018-07-23 09:54:00 +08:00
//如果是从根目录开始,
2018-07-23 14:38:33 +08:00
if strings . HasPrefix ( originalLink , "/" ) {
linkPath , err = filepath . Abs ( filepath . Join ( tempPath , originalLink ) )
} else if strings . HasPrefix ( originalLink , "./" ) {
2018-07-23 09:54:00 +08:00
linkPath , err = filepath . Abs ( filepath . Join ( filepath . Dir ( path ) , originalLink [ 1 : ] ) )
2018-11-13 17:33:13 +08:00
} else {
2018-07-23 09:54:00 +08:00
linkPath , err = filepath . Abs ( filepath . Join ( filepath . Dir ( path ) , originalLink ) )
}
2018-03-25 10:56:52 +08:00
if err == nil {
//如果本地存在该链接
if filetil . FileExists ( linkPath ) {
ext := filepath . Ext ( linkPath )
2021-03-30 14:24:14 +08:00
//logs.Info("当前后缀 -> ",ext)
2018-03-25 10:56:52 +08:00
//如果链接是Markdown文件, 则生成文档标识,否则,将目标文件复制到项目目录
2018-03-25 14:59:42 +08:00
if strings . EqualFold ( ext , ".md" ) || strings . EqualFold ( ext , ".markdown" ) {
docIdentify := strings . Replace ( strings . TrimPrefix ( strings . Replace ( linkPath , "\\" , "/" , - 1 ) , tempPath + "/" ) , "/" , "-" , - 1 )
2021-03-30 14:24:14 +08:00
//logs.Info(originalLink, "|", linkPath, "|", docIdentify)
2018-03-25 10:56:52 +08:00
if ok , err := regexp . MatchString ( ` [a-z]+[a-zA-Z0-9_.\-]*$ ` , docIdentify ) ; ! ok || err != nil {
docIdentify = "import-" + docIdentify
}
2018-03-25 14:59:42 +08:00
docIdentify = strings . TrimSuffix ( docIdentify , "-README.md" )
link = strings . TrimSuffix ( link , originalLink + ")" ) + conf . URLFor ( "DocumentController.Read" , ":key" , book . Identify , ":id" , docIdentify ) + ")"
2018-07-23 09:54:00 +08:00
2018-03-25 14:59:42 +08:00
} else {
dstPath := filepath . Join ( conf . WorkingDirectory , "uploads" , time . Now ( ) . Format ( "200601" ) , originalLink )
filetil . CopyFile ( linkPath , dstPath )
2018-03-27 00:55:11 +08:00
tempLink := conf . BaseUrl + strings . TrimPrefix ( strings . Replace ( dstPath , "\\" , "/" , - 1 ) , strings . Replace ( conf . WorkingDirectory , "\\" , "/" , - 1 ) )
2018-03-25 14:59:42 +08:00
2018-03-27 00:55:11 +08:00
link = strings . TrimSuffix ( link , originalLink + ")" ) + tempLink + ")"
2018-03-25 14:59:42 +08:00
2018-03-25 10:56:52 +08:00
}
2018-11-13 17:33:13 +08:00
} else {
2021-03-30 14:24:14 +08:00
logs . Info ( "文件不存在 ->" , linkPath )
2018-03-25 10:56:52 +08:00
}
}
return link
} )
2018-03-26 13:32:02 +08:00
//codeRe := regexp.MustCompile("```\\w+")
//doc.Markdown = codeRe.ReplaceAllStringFunc(doc.Markdown, func(s string) string {
2021-03-30 14:24:14 +08:00
// //logs.Info(s)
2018-03-26 13:32:02 +08:00
// return strings.Replace(s,"```","``` ",-1)
//})
doc . Content = string ( blackfriday . Run ( [ ] byte ( doc . Markdown ) ) )
2018-03-25 14:59:42 +08:00
2018-03-24 22:36:35 +08:00
doc . Version = time . Now ( ) . Unix ( )
//解析文档名称, 默认使用第一个h标签为标题
docName := strings . TrimSuffix ( info . Name ( ) , ext )
for _ , line := range strings . Split ( doc . Markdown , "\n" ) {
if strings . HasPrefix ( line , "#" ) {
docName = strings . TrimLeft ( line , "#" )
break
}
}
2018-03-26 22:39:16 +08:00
doc . DocumentName = strings . TrimSpace ( docName )
2018-03-24 22:36:35 +08:00
parentId := 0
2018-03-25 14:59:42 +08:00
parentIdentify := strings . Replace ( strings . Trim ( strings . TrimSuffix ( strings . TrimPrefix ( path , tempPath ) , info . Name ( ) ) , "/" ) , "/" , "-" , - 1 )
2018-03-24 22:36:35 +08:00
if parentIdentify != "" {
2018-03-24 23:17:50 +08:00
2018-03-24 22:36:35 +08:00
if ok , err := regexp . MatchString ( ` [a-z]+[a-zA-Z0-9_.\-]*$ ` , parentIdentify ) ; ! ok || err != nil {
parentIdentify = "import-" + parentIdentify
}
if id , ok := docMap [ parentIdentify ] ; ok {
parentId = id
}
}
2018-03-24 23:17:50 +08:00
if strings . EqualFold ( info . Name ( ) , "README.md" ) {
2021-03-30 14:24:14 +08:00
logs . Info ( path , "|" , info . Name ( ) , "|" , parentIdentify , "|" , parentId )
2018-03-24 23:17:50 +08:00
}
2018-03-24 22:36:35 +08:00
isInsert := false
//如果当前文件是README.md, 则将内容更新到父级
2018-03-24 23:17:50 +08:00
if strings . EqualFold ( info . Name ( ) , "README.md" ) && parentId != 0 {
2018-03-24 22:36:35 +08:00
doc . DocumentId = parentId
2021-03-30 14:24:14 +08:00
//logs.Info(path,"|",parentId)
2018-03-24 22:36:35 +08:00
} else {
2021-03-30 14:24:14 +08:00
//logs.Info(path,"|",parentIdentify)
2018-03-24 22:36:35 +08:00
doc . ParentId = parentId
isInsert = true
}
2018-03-25 14:59:42 +08:00
if err := doc . InsertOrUpdate ( "document_name" , "markdown" , "content" ) ; err != nil {
2021-03-30 14:24:14 +08:00
logs . Error ( doc . DocumentId , err )
2018-03-24 22:36:35 +08:00
}
if isInsert {
docMap [ docIdentify ] = doc . DocumentId
}
}
2018-03-25 14:59:42 +08:00
} else {
2018-03-24 22:36:35 +08:00
//如果当前目录下存在Markdown文件, 则需要创建此节点
2018-03-25 14:59:42 +08:00
if filetil . HasFileOfExt ( path , [ ] string { ".md" , ".markdown" } ) {
2021-03-30 14:24:14 +08:00
logs . Info ( "正在处理 =>" , path , info . Name ( ) )
2018-03-25 14:59:42 +08:00
identify := strings . Replace ( strings . Trim ( strings . TrimPrefix ( path , tempPath ) , "/" ) , "/" , "-" , - 1 )
2018-03-24 22:36:35 +08:00
if ok , err := regexp . MatchString ( ` [a-z]+[a-zA-Z0-9_.\-]*$ ` , identify ) ; ! ok || err != nil {
identify = "import-" + identify
}
2018-03-24 23:17:50 +08:00
2018-03-24 22:36:35 +08:00
parentDoc := NewDocument ( )
parentDoc . MemberId = book . MemberId
parentDoc . BookId = book . BookId
parentDoc . Identify = identify
parentDoc . Version = time . Now ( ) . Unix ( )
parentDoc . DocumentName = "空白文档"
parentId := 0
2018-03-24 23:17:50 +08:00
2018-03-25 14:59:42 +08:00
parentIdentify := strings . TrimSuffix ( identify , "-" + info . Name ( ) )
2018-03-24 22:36:35 +08:00
2018-03-25 14:59:42 +08:00
if id , ok := docMap [ parentIdentify ] ; ok {
2018-03-24 22:36:35 +08:00
parentId = id
}
parentDoc . ParentId = parentId
2018-03-25 14:59:42 +08:00
if err := parentDoc . InsertOrUpdate ( ) ; err != nil {
2021-03-30 14:24:14 +08:00
logs . Error ( err )
2018-03-24 22:36:35 +08:00
}
2018-03-24 17:24:02 +08:00
2018-03-24 22:36:35 +08:00
docMap [ identify ] = parentDoc . DocumentId
2021-03-30 14:24:14 +08:00
//logs.Info(path,"|",parentDoc.DocumentId,"|",identify,"|",info.Name(),"|",parentIdentify)
2018-03-24 17:24:02 +08:00
}
}
return nil
} )
2018-03-25 14:59:42 +08:00
if err != nil {
2021-03-30 14:24:14 +08:00
logs . Error ( "导入项目异常 => " , err )
2018-03-25 14:59:42 +08:00
book . Description = "【项目导入存在错误:" + err . Error ( ) + "】"
}
2021-03-30 14:24:14 +08:00
logs . Info ( "项目导入完毕 => " , book . BookName )
2021-04-12 21:12:26 +08:00
book . ReleaseContent ( book . BookId , lang )
2018-03-24 17:24:02 +08:00
return err
2018-03-25 14:59:42 +08:00
}
2018-11-13 17:33:13 +08:00
2022-02-11 11:10:58 +08:00
// 导入docx项目
2022-02-11 13:31:03 +08:00
func ( book * Book ) ImportWordBook ( docxPath string , lang string ) ( err error ) {
2022-02-11 11:10:58 +08:00
if ! filetil . FileExists ( docxPath ) {
return errors . New ( "文件不存在" )
}
2022-02-11 13:31:03 +08:00
docxPath = strings . Replace ( docxPath , "\\" , "/" , - 1 )
2022-02-11 11:10:58 +08:00
o := orm . NewOrm ( )
o . Insert ( book )
relationship := NewRelationship ( )
relationship . BookId = book . BookId
2022-02-11 16:37:42 +08:00
relationship . RoleId = 0
2022-02-11 11:10:58 +08:00
relationship . MemberId = book . MemberId
2022-02-11 16:37:42 +08:00
err = relationship . Insert ( )
if err != nil {
logs . Error ( "插入项目与用户关联 -> " , err )
return err
}
2022-02-11 11:10:58 +08:00
2022-02-11 13:31:03 +08:00
doc := NewDocument ( )
doc . BookId = book . BookId
doc . MemberId = book . MemberId
docIdentify := strings . Replace ( strings . TrimPrefix ( docxPath , os . TempDir ( ) + "/" ) , "/" , "-" , - 1 )
2022-02-11 11:10:58 +08:00
2022-02-11 13:31:03 +08:00
if ok , err := regexp . MatchString ( ` [a-z]+[a-zA-Z0-9_.\-]*$ ` , docIdentify ) ; ! ok || err != nil {
docIdentify = "import-" + docIdentify
}
2022-02-11 11:10:58 +08:00
2022-02-11 13:31:03 +08:00
doc . Identify = docIdentify
2022-02-11 11:10:58 +08:00
2022-02-11 13:31:03 +08:00
if doc . Markdown , err = utils . Docx2md ( docxPath , false ) ; err != nil {
logs . Error ( "导入doc项目转换异常 => " , err )
return err
}
2022-02-11 11:10:58 +08:00
2022-02-11 16:37:42 +08:00
// fmt.Println("===doc.Markdown===")
// fmt.Println(doc.Markdown)
// fmt.Println("==================")
2022-02-11 13:31:03 +08:00
doc . Content = string ( blackfriday . Run ( [ ] byte ( doc . Markdown ) ) )
2022-02-11 11:10:58 +08:00
2022-02-11 16:37:42 +08:00
// fmt.Println("===doc.Content===")
// fmt.Println(doc.Content)
// fmt.Println("==================")
2022-02-11 13:31:03 +08:00
doc . Version = time . Now ( ) . Unix ( )
2022-02-11 11:10:58 +08:00
2022-02-11 13:31:03 +08:00
var docName string
for _ , line := range strings . Split ( doc . Markdown , "\n" ) {
if strings . HasPrefix ( line , "#" ) {
docName = strings . TrimLeft ( line , "#" )
break
}
}
2022-02-11 11:10:58 +08:00
2022-02-11 13:31:03 +08:00
doc . DocumentName = strings . TrimSpace ( docName )
2022-02-11 16:37:42 +08:00
doc . DocumentId = book . MemberId
if err := doc . InsertOrUpdate ( "document_name" , "book_id" , "markdown" , "content" ) ; err != nil {
logs . Error ( doc . DocumentId , err )
}
if err != nil {
logs . Error ( "导入项目异常 => " , err )
book . Description = "【项目导入存在错误:" + err . Error ( ) + "】"
}
logs . Info ( "项目导入完毕 => " , book . BookName )
book . ReleaseContent ( book . BookId , lang )
2022-02-11 13:31:03 +08:00
return err
2022-02-11 11:10:58 +08:00
}
2018-11-13 17:33:13 +08:00
func ( book * Book ) FindForRoleId ( bookId , memberId int ) ( conf . BookRole , error ) {
o := orm . NewOrm ( )
var relationship Relationship
err := NewRelationship ( ) . QueryTable ( ) . Filter ( "book_id" , bookId ) . Filter ( "member_id" , memberId ) . One ( & relationship )
if err != nil && err != orm . ErrNoRows {
return 0 , err
}
if err == nil {
return relationship . RoleId , nil
}
sql := ` select role_id
from md_team_relationship as mtr
left join md_team_member as mtm using ( team_id )
where mtr . book_id = ? and mtm . member_id = ? order by mtm . role_id asc limit 1 ; `
var roleId int
err = o . Raw ( sql , bookId , memberId ) . QueryRow ( & roleId )
if err != nil {
2021-03-30 14:24:14 +08:00
logs . Error ( "查询用户项目角色出错 -> book_id=" , bookId , " member_id=" , memberId , err )
2018-11-14 15:57:55 +08:00
return 0 , err
2018-11-13 17:33:13 +08:00
}
return conf . BookRole ( roleId ) , nil
}