From 359c5dfb107a3454a4ab96b0b225aed2bfc5426a Mon Sep 17 00:00:00 2001 From: Minho Date: Thu, 22 Mar 2018 14:27:23 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E4=BC=98=E5=8C=96=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E7=9A=84=E6=95=88=E6=9E=9C=202=E3=80=81?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=9B=B4=E6=96=B0=E7=94=A8=E6=88=B7=E6=97=B6?= =?UTF-8?q?=E9=82=AE=E7=AE=B1=E9=87=8D=E5=A4=8D=E7=9A=84=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E6=96=87=E6=A1=88=203=E3=80=81=E4=BC=98=E5=8C=96=E9=83=A8?= =?UTF-8?q?=E5=88=86=E6=98=BE=E7=A4=BA=E6=95=88=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- controllers/account.go | 1 - controllers/manager.go | 4 +- converter/converter.go | 32 +++-- models/book_result.go | 20 ++- models/member.go | 12 +- static/css/export.css | 11 ++ static/css/kancloud.css | 1 + static/prettify/themes/prettify.css | 70 ++++++++++ utils/filetil/filetil.go | 89 ++++++++++++ utils/ziptil/ziptil.go | 162 ++++++++++++++-------- views/document/default_read.tpl | 4 +- views/document/export.tpl | 46 ++---- views/document/markdown_edit_template.tpl | 4 +- 13 files changed, 336 insertions(+), 120 deletions(-) create mode 100644 static/css/export.css create mode 100644 static/prettify/themes/prettify.css diff --git a/controllers/account.go b/controllers/account.go index 62770434..8cdfc2e8 100644 --- a/controllers/account.go +++ b/controllers/account.go @@ -178,7 +178,6 @@ func (c *AccountController) Register() { member.Email = email member.Status = 0 if err := member.Add(); err != nil { - beego.Error(err) c.JsonResult(6006, "注册失败,请联系系统管理员处理") } diff --git a/controllers/manager.go b/controllers/manager.go index 63d85d2a..da9a6f7c 100644 --- a/controllers/manager.go +++ b/controllers/manager.go @@ -181,7 +181,6 @@ func (c *ManagerController) ChangeMemberRole() { member.Role = role if err := member.Update(); err != nil { - logs.Error("", err) c.JsonResult(6003, "用户权限设置失败") } member.ResolveRoleName() @@ -233,8 +232,7 @@ func (c *ManagerController) EditMember() { member.Password = password } if err := member.Update(); err != nil { - beego.Error(err) - c.JsonResult(6004, "保存失败") + c.JsonResult(6004, err.Error()) } c.JsonResult(0, "ok") } diff --git a/converter/converter.go b/converter/converter.go index 3d708441..93b59668 100644 --- a/converter/converter.go +++ b/converter/converter.go @@ -21,6 +21,7 @@ import ( type Converter struct { BasePath string + OutputPath string Config Config Debug bool GeneratedCover string @@ -123,10 +124,9 @@ func (this *Converter) Convert() (err error) { } //将当前文件夹下的所有文件压缩成zip包,然后直接改名成content.epub - f := filepath.Join(this.BasePath, "content.epub") - fmt.Println("epub目录 " + f) + f := filepath.Join(this.OutputPath, "content.epub") os.Remove(f) //如果原文件存在了,则删除; - if err = ziptil.Zip(f, this.BasePath); err == nil { + if err = ziptil.Zip(this.BasePath,f); err == nil { //创建导出文件夹 os.Mkdir(this.BasePath+"/"+output, os.ModePerm) if len(this.Config.Format) > 0 { @@ -434,8 +434,8 @@ func (this *Converter) generateContentOpf() (err error) { //转成epub func (this *Converter) convertToEpub() (err error) { args := []string{ - filepath.Join(this.BasePath, "content.epub"), - filepath.Join(this.BasePath, output, "book.epub"), + filepath.Join(this.OutputPath, "content.epub"), + filepath.Join(this.OutputPath, output, "book.epub"), } cmd := exec.Command(ebookConvert, args...) @@ -443,13 +443,15 @@ func (this *Converter) convertToEpub() (err error) { fmt.Println(cmd.Args) } return cmd.Run() + + //return filetil.CopyFile(filepath.Join(this.OutputPath, "content.epub"),filepath.Join(this.OutputPath, output, "book.epub")) } //转成mobi func (this *Converter) convertToMobi() (err error) { args := []string{ - filepath.Join(this.BasePath, "content.epub"), - filepath.Join(this.BasePath, output, "book.mobi"), + filepath.Join(this.OutputPath, "content.epub"), + filepath.Join(this.OutputPath, output, "book.mobi"), } cmd := exec.Command(ebookConvert, args...) if this.Debug { @@ -462,8 +464,8 @@ func (this *Converter) convertToMobi() (err error) { //转成pdf func (this *Converter) convertToPdf() (err error) { args := []string{ - filepath.Join(this.BasePath, "content.epub"), - filepath.Join(this.BasePath, output, "book.pdf"), + filepath.Join(this.OutputPath, "content.epub"), + filepath.Join(this.OutputPath, output, "book.pdf"), } //页面大小 if len(this.Config.PaperSize) > 0 { @@ -484,16 +486,16 @@ func (this *Converter) convertToPdf() (err error) { args = append(args, "--pdf-footer-template",this.Config.Footer) } - if len(this.Config.MarginLeft) > 0 { + if strings.Count(this.Config.MarginLeft,"") > 0 { args = append(args, "--pdf-page-margin-left", this.Config.MarginLeft) } - if len(this.Config.MarginTop) > 0 { + if strings.Count(this.Config.MarginTop,"") > 0 { args = append(args, "--pdf-page-margin-top", this.Config.MarginTop) } - if len(this.Config.MarginRight) > 0 { + if strings.Count(this.Config.MarginRight,"") > 0 { args = append(args, "--pdf-page-margin-right", this.Config.MarginRight) } - if len(this.Config.MarginBottom) > 0 { + if strings.Count(this.Config.MarginBottom,"") > 0 { args = append(args, "--pdf-page-margin-bottom", this.Config.MarginBottom) } @@ -513,8 +515,8 @@ func (this *Converter) convertToPdf() (err error) { // 转成word func (this *Converter) convertToDocx() (err error) { args := []string{ - this.BasePath + "/content.epub", - this.BasePath + "/" + output + "/book.docx", + filepath.Join(this.OutputPath , "content.epub"), + filepath.Join(this.OutputPath , output , "book.docx"), } args = append(args, "--docx-no-toc") diff --git a/models/book_result.go b/models/book_result.go index 61e677ff..40d4cd31 100644 --- a/models/book_result.go +++ b/models/book_result.go @@ -19,6 +19,7 @@ import ( "github.com/lifei6671/mindoc/utils" "gopkg.in/russross/blackfriday.v2" "github.com/lifei6671/mindoc/utils/ziptil" + "github.com/lifei6671/mindoc/utils/filetil" ) type BookResult struct { @@ -189,6 +190,7 @@ func (m *BookResult) ToBookResult(book Book) *BookResult { return m } +//导出PDF、word等格式 func (m *BookResult) Converter(sessionId string) (ConvertBookResult, error) { convertBookResult := ConvertBookResult{} @@ -202,7 +204,7 @@ func (m *BookResult) Converter(sessionId string) (ConvertBookResult, error) { docxpath := filepath.Join(outputPath, "book.docx") //先将转换的文件储存到临时目录 - tempOutputPath := filepath.Join(os.TempDir(),sessionId) //filepath.Abs(filepath.Join("cache", sessionId)) + tempOutputPath := filepath.Join(os.TempDir(),sessionId,m.Identify) //filepath.Abs(filepath.Join("cache", sessionId)) os.MkdirAll(outputPath, 0766) os.MkdirAll(tempOutputPath, 0766) @@ -332,18 +334,28 @@ func (m *BookResult) Converter(sessionId string) (ConvertBookResult, error) { f.Close() return convertBookResult, err } - - // html = strings.Replace(html, " " + err.Error()) return convertBookResult, err diff --git a/models/member.go b/models/member.go index 7c7c8475..d31651c8 100644 --- a/models/member.go +++ b/models/member.go @@ -169,7 +169,8 @@ func (m *Member) Add() error { hash, err := utils.PasswordHash(m.Password) if err != nil { - return err + beego.Error("加密用户密码失败 =>",err) + return errors.New("加密用户密码失败") } m.Password = hash @@ -179,7 +180,8 @@ func (m *Member) Add() error { _, err = o.Insert(m) if err != nil { - return err + beego.Error("保存用户数据到数据时失败 =>",err) + return errors.New("保存用户失败") } m.ResolveRoleName() return nil @@ -192,8 +194,12 @@ func (m *Member) Update(cols ...string) error { if m.Email == "" { return errors.New("邮箱不能为空") } + if c, err := o.QueryTable(m.TableNameWithPrefix()).Filter("email", m.Email).Exclude("member_id",m.MemberId).Count(); err == nil && c > 0 { + return errors.New("邮箱已被使用") + } if _, err := o.Update(m, cols...); err != nil { - return err + beego.Error("保存用户信息失败=>",err) + return errors.New("保存用户信息失败") } return nil } diff --git a/static/css/export.css b/static/css/export.css new file mode 100644 index 00000000..b640a5d6 --- /dev/null +++ b/static/css/export.css @@ -0,0 +1,11 @@ +body{ + margin: 5px auto; + padding: 5px 30px; +} +.article-title{ + margin: 15px auto; + line-height: 35px; +} +.editormd-preview-container{ + padding: 0 !important; +} \ No newline at end of file diff --git a/static/css/kancloud.css b/static/css/kancloud.css index 2ef74f44..9c1a7076 100644 --- a/static/css/kancloud.css +++ b/static/css/kancloud.css @@ -16,6 +16,7 @@ body { word-wrap: break-word; line-height: 1em; } + h1,h2,h3,h4,h5,h6,strong,input,select,textarea,button,body,code { font-family: "Helvetica Neue",Helvetica,"Segoe UI",Arial,freesans,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Microsoft Yahei","Helvetica Neue",Helvetica; } diff --git a/static/prettify/themes/prettify.css b/static/prettify/themes/prettify.css new file mode 100644 index 00000000..0e751ee5 --- /dev/null +++ b/static/prettify/themes/prettify.css @@ -0,0 +1,70 @@ +/** + * @license + * Copyright (C) 2015 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Pretty printing styles. Used with prettify.js. */ + + +/* SPAN elements with the classes below are added by prettyprint. */ +.pln { color: #000 } /* plain text */ + +@media screen { + .str { color: #080 } /* string content */ + .kwd { color: #008 } /* a keyword */ + .com { color: #800 } /* a comment */ + .typ { color: #606 } /* a type name */ + .lit { color: #066 } /* a literal value */ + /* punctuation, lisp open bracket, lisp close bracket */ + .pun, .opn, .clo { color: #660 } + .tag { color: #008 } /* a markup tag name */ + .atn { color: #606 } /* a markup attribute name */ + .atv { color: #080 } /* a markup attribute value */ + .dec, .var { color: #606 } /* a declaration; a variable name */ + .fun { color: red } /* a function name */ +} + +/* Use higher contrast and text-weight for printable form. */ +@media print, projection { + .str { color: #060 } + .kwd { color: #006; font-weight: bold } + .com { color: #600; font-style: italic } + .typ { color: #404; font-weight: bold } + .lit { color: #044 } + .pun, .opn, .clo { color: #440 } + .tag { color: #006; font-weight: bold } + .atn { color: #404 } + .atv { color: #060 } +} + +/* Put a border around prettyprinted code snippets. */ +pre.prettyprint { padding: 2px; border: 1px solid #888 } + +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { margin-top: 0; margin-bottom: 0 } /* IE indents via margin-left */ +li.L0, +li.L1, +li.L2, +li.L3, +li.L5, +li.L6, +li.L7, +li.L8 { list-style-type: none } +/* Alternate shading for lines */ +li.L1, +li.L3, +li.L5, +li.L7, +li.L9 { background: #eee } \ No newline at end of file diff --git a/utils/filetil/filetil.go b/utils/filetil/filetil.go index 5a42f0f2..90fbd9b8 100644 --- a/utils/filetil/filetil.go +++ b/utils/filetil/filetil.go @@ -4,6 +4,8 @@ import ( "os" "path/filepath" "strings" + "io" + "fmt" ) //================================== @@ -41,3 +43,90 @@ func ScanFiles(dir string) (fl []FileList, err error) { }) return } + +//拷贝文件 +func CopyFile(source string, dst string) (err error) { + sourceFile, err := os.Open(source) + if err != nil { + return err + } + + defer sourceFile.Close() + + _,err = os.Stat(filepath.Dir(dst)) + + if err != nil { + if os.IsNotExist(err) { + os.MkdirAll(filepath.Dir(dst),0766) + }else{ + return err + } + } + + + destFile, err := os.Create(dst) + if err != nil { + return err + } + + defer destFile.Close() + + _, err = io.Copy(destFile, sourceFile) + if err == nil { + sourceInfo, err := os.Stat(source) + if err != nil { + err = os.Chmod(dst, sourceInfo.Mode()) + } + + } + + return +} + +//拷贝目录 +func CopyDir(source string, dest string) (err error) { + + // get properties of source dir + sourceInfo, err := os.Stat(source) + if err != nil { + return err + } + + // create dest dir + err = os.MkdirAll(dest, sourceInfo.Mode()) + if err != nil { + return err + } + + directory, _ := os.Open(source) + + objects, err := directory.Readdir(-1) + + for _, obj := range objects { + + sourceFilePointer := filepath.Join(source , obj.Name()) + + destinationFilePointer := filepath.Join(dest, obj.Name()) + + if obj.IsDir() { + // create sub-directories - recursively + err = CopyDir(sourceFilePointer, destinationFilePointer) + if err != nil { + fmt.Println(err) + } + } else { + // perform copy + err = CopyFile(sourceFilePointer, destinationFilePointer) + if err != nil { + fmt.Println(err) + } + } + + } + return +} + +func RemoveDir(dir string) error { + return os.RemoveAll(dir) +} + diff --git a/utils/ziptil/ziptil.go b/utils/ziptil/ziptil.go index f4a4a2f8..31d768db 100644 --- a/utils/ziptil/ziptil.go +++ b/utils/ziptil/ziptil.go @@ -2,14 +2,11 @@ package ziptil import ( "archive/zip" - "errors" "io" - "io/ioutil" "os" "path/filepath" "strings" - - "github.com/lifei6671/mindoc/utils/filetil" + "fmt" ) //解压zip文件 @@ -47,66 +44,122 @@ func Unzip(zipFile, dest string) (err error) { return nil } -//压缩指定文件或文件夹 -//@param dest 压缩后的zip文件目标,如/usr/local/hello.zip -//@param filepath 需要压缩的文件或者文件夹 -//@return err 错误。如果返回错误,则会删除dest文件 -func Zip(dest string, filepath ...string) (err error) { - if len(filepath) == 0 { - return errors.New("lack of file") - } - //创建文件 - fzip, err := os.Create(dest) +//压缩文件 +func Zip(source, target string) error { + zipFile, err := os.Create(target) if err != nil { return err } - defer fzip.Close() + defer zipFile.Close() - var filelist []filetil.FileList - for _, file := range filepath { - if info, err := os.Stat(file); err == nil { - if info.IsDir() { //目录,则扫描文件 - if f, _ := filetil.ScanFiles(file); len(f) > 0 { - filelist = append(filelist, f...) - } - } else { //文件 - filelist = append(filelist, filetil.FileList{ - IsDir: false, - Name: info.Name(), - Path: file, - }) - } - } else { + archive := zip.NewWriter(zipFile) + defer archive.Close() + source = strings.Replace(source, "\\", "/", -1) + + filepath.Walk(source, func(path string, info os.FileInfo, err error) error { + if err != nil { return err } - } - w := zip.NewWriter(fzip) - defer w.Close() - for _, file := range filelist { - if !file.IsDir { - if fw, err := w.Create(strings.TrimLeft(file.Path, "./")); err != nil { - return err - } else { - if fileContent, err := ioutil.ReadFile(file.Path); err != nil { - return err - } else { - if _, err = fw.Write(fileContent); err != nil { - return err - } - } - } + path = strings.Replace(path, "\\", "/", -1) + + if path == source { + return nil } - } - return + header, err := zip.FileInfoHeader(info) + if err != nil { + return err + } + + header.Name = strings.TrimPrefix(strings.TrimPrefix(strings.Replace(path, "\\", "/", -1), source), "/") + fmt.Println(header.Name) + + if info.IsDir() { + header.Name += "/" + } else { + header.Method = zip.Deflate + } + + writer, err := archive.CreateHeader(header) + if err != nil { + return err + } + + if info.IsDir() { + return nil + } + + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + _, err = io.Copy(writer, file) + return err + }) + + return err } -func Compress(dst string,src string) (err error) { +////压缩指定文件或文件夹 +////@param dest 压缩后的zip文件目标,如/usr/local/hello.zip +////@param filepath 需要压缩的文件或者文件夹 +////@return err 错误。如果返回错误,则会删除dest文件 +//func Zip(dest string, filepath ...string) (err error) { +// if len(filepath) == 0 { +// return errors.New("lack of file") +// } +// //创建文件 +// fzip, err := os.Create(dest) +// if err != nil { +// return err +// } +// defer fzip.Close() +// +// var filelist []filetil.FileList +// for _, file := range filepath { +// if info, err := os.Stat(file); err == nil { +// if info.IsDir() { //目录,则扫描文件 +// if f, _ := filetil.ScanFiles(file); len(f) > 0 { +// filelist = append(filelist, f...) +// } +// } else { //文件 +// filelist = append(filelist, filetil.FileList{ +// IsDir: false, +// Name: info.Name(), +// Path: file, +// }) +// } +// } else { +// return err +// } +// } +// w := zip.NewWriter(fzip) +// defer w.Close() +// for _, file := range filelist { +// if !file.IsDir { +// if fw, err := w.Create(strings.TrimLeft(file.Path, "./")); err != nil { +// return err +// } else { +// if fileContent, err := ioutil.ReadFile(file.Path); err != nil { +// return err +// } else { +// if _, err = fw.Write(fileContent); err != nil { +// return err +// } +// } +// } +// } +// } +// return +//} + +func Compress(dst string, src string) (err error) { d, _ := os.Create(dst) defer d.Close() w := zip.NewWriter(d) defer w.Close() - src = strings.Replace(src,"\\","/",-1) + src = strings.Replace(src, "\\", "/", -1) f, err := os.Open(src) if err != nil { @@ -124,7 +177,6 @@ func Compress(dst string,src string) (err error) { return nil } - func compress(file *os.File, prefix string, zw *zip.Writer) error { info, err := file.Stat() if err != nil { @@ -133,7 +185,7 @@ func compress(file *os.File, prefix string, zw *zip.Writer) error { if info.IsDir() { if prefix != "" { prefix = prefix + "/" + info.Name() - }else{ + } else { prefix = info.Name() } fileInfos, err := file.Readdir(-1) @@ -171,9 +223,3 @@ func compress(file *os.File, prefix string, zw *zip.Writer) error { } return nil } - - - - - - diff --git a/views/document/default_read.tpl b/views/document/default_read.tpl index 41311595..a2cadc59 100644 --- a/views/document/default_read.tpl +++ b/views/document/default_read.tpl @@ -23,10 +23,10 @@ {{if eq .Model.Editor "markdown"}} - + {{else}} - + {{end}} diff --git a/views/document/export.tpl b/views/document/export.tpl index 965e5c0e..d2b7df0a 100644 --- a/views/document/export.tpl +++ b/views/document/export.tpl @@ -1,41 +1,23 @@ - - - - + + + {{.Model.BookName}} - Powered by MinDoc - - - - - - - - - - {{if eq .Model.Editor "markdown"}} - - - - {{else}} - - {{end}} + + + + + + + + -
-
- -
-
-

{{.Lists.DocumentName}}

-
- {{str2html .Lists.Release}} -
-
- +

{{.Lists.DocumentName}}

+
+ {{str2html .Lists.Release}}
-
\ No newline at end of file diff --git a/views/document/markdown_edit_template.tpl b/views/document/markdown_edit_template.tpl index fa97b3ca..2838c283 100644 --- a/views/document/markdown_edit_template.tpl +++ b/views/document/markdown_edit_template.tpl @@ -27,10 +27,10 @@ - + - +