1、实现富文本编辑器

2、实现文档转换为PDF、MOBI、EPUB、Word格式
3、实现登录后跳转到来源地址
pull/219/head
Minho 2018-01-26 17:17:38 +08:00
parent e1ec6bb788
commit 882d93e7b0
57 changed files with 1572 additions and 1475 deletions

View File

@ -6,11 +6,12 @@ import (
"net/url"
"os"
"time"
"log"
"flag"
"path/filepath"
"strings"
"encoding/json"
"github.com/astaxie/beego"
"github.com/astaxie/beego/logs"
"github.com/astaxie/beego/orm"
@ -19,14 +20,6 @@ import (
"github.com/lifei6671/mindoc/conf"
"github.com/lifei6671/mindoc/models"
"github.com/lifei6671/mindoc/utils"
"log"
"encoding/json"
)
var (
ConfigurationFile = "./conf/app.conf"
WorkingDirectory = "./"
LogFile = "./logs"
)
// RegisterDataBase 注册数据库
@ -55,7 +48,7 @@ func RegisterDataBase() {
} else if adapter == "sqlite3" {
database := beego.AppConfig.String("db_database")
if strings.HasPrefix(database, "./") {
database = filepath.Join(WorkingDirectory,string(database[1:]))
database = filepath.Join(conf.WorkingDirectory, string(database[1:]))
}
dbPath := filepath.Dir(database)
@ -188,62 +181,64 @@ func RegisterFunction() {
func ResolveCommand(args []string) {
flagSet := flag.NewFlagSet("MinDoc command: ", flag.ExitOnError)
flagSet.StringVar(&ConfigurationFile, "config", "", "MinDoc configuration file.")
flagSet.StringVar(&WorkingDirectory, "dir", "", "MinDoc working directory.")
flagSet.StringVar(&LogFile, "log", "", "MinDoc log file path.")
flagSet.StringVar(&conf.ConfigurationFile, "config", "", "MinDoc configuration file.")
flagSet.StringVar(&conf.WorkingDirectory, "dir", "", "MinDoc working directory.")
flagSet.StringVar(&conf.LogFile, "log", "", "MinDoc log file path.")
flagSet.Parse(args)
if WorkingDirectory == "" {
if conf.WorkingDirectory == "" {
if p, err := filepath.Abs(os.Args[0]); err == nil {
WorkingDirectory = filepath.Dir(p)
conf.WorkingDirectory = filepath.Dir(p)
}
}
if LogFile == "" {
LogFile = filepath.Join(WorkingDirectory,"logs")
if conf.LogFile == "" {
conf.LogFile = filepath.Join(conf.WorkingDirectory, "logs")
}
if ConfigurationFile == "" {
ConfigurationFile = filepath.Join(WorkingDirectory,"conf","app.conf")
config := filepath.Join(WorkingDirectory,"conf","app.conf.example")
if !utils.FileExists(ConfigurationFile) && utils.FileExists(config){
utils.CopyFile(ConfigurationFile,config)
if conf.ConfigurationFile == "" {
conf.ConfigurationFile = filepath.Join(conf.WorkingDirectory, "conf", "app.conf")
config := filepath.Join(conf.WorkingDirectory, "conf", "app.conf.example")
if !utils.FileExists(conf.ConfigurationFile) && utils.FileExists(config) {
utils.CopyFile(conf.ConfigurationFile, config)
}
}
gocaptcha.ReadFonts(filepath.Join(WorkingDirectory,"static","fonts"), ".ttf")
gocaptcha.ReadFonts(filepath.Join(conf.WorkingDirectory, "static", "fonts"), ".ttf")
err := beego.LoadAppConfig("ini", ConfigurationFile)
err := beego.LoadAppConfig("ini", conf.ConfigurationFile)
if err != nil {
log.Println("An error occurred:", err)
os.Exit(1)
}
uploads := filepath.Join(WorkingDirectory, "uploads")
uploads := filepath.Join(conf.WorkingDirectory, "uploads")
os.MkdirAll(uploads, 0666)
beego.BConfig.WebConfig.StaticDir["/static"] = filepath.Join(WorkingDirectory, "static")
beego.BConfig.WebConfig.StaticDir["/static"] = filepath.Join(conf.WorkingDirectory, "static")
beego.BConfig.WebConfig.StaticDir["/uploads"] = uploads
beego.BConfig.WebConfig.ViewsPath = filepath.Join(WorkingDirectory, "views")
beego.BConfig.WebConfig.ViewsPath = filepath.Join(conf.WorkingDirectory, "views")
fonts := filepath.Join(WorkingDirectory, "static", "fonts")
fonts := filepath.Join(conf.WorkingDirectory, "static", "fonts")
if !utils.FileExists(fonts) {
log.Fatal("Font path not exist.")
}
gocaptcha.ReadFonts(filepath.Join(WorkingDirectory, "static", "fonts"), ".ttf")
gocaptcha.ReadFonts(filepath.Join(conf.WorkingDirectory, "static", "fonts"), ".ttf")
RegisterDataBase()
RegisterModel()
RegisterLogger(LogFile)
RegisterLogger(conf.LogFile)
}
func init() {
if configPath ,err := filepath.Abs(conf.ConfigurationFile); err == nil {
conf.ConfigurationFile = configPath
}
gocaptcha.ReadFonts("./static/fonts", ".ttf")
gob.Register(models.Member{})
if p, err := filepath.Abs(os.Args[0]); err == nil {
WorkingDirectory = filepath.Dir(p)
conf.WorkingDirectory = filepath.Dir(p)
}
}

View File

@ -22,7 +22,7 @@ func NewDaemon() *Daemon {
Name: "mindocd", //服务显示名称
DisplayName: "MinDoc service", //服务名称
Description: "A document online management program.", //服务描述
WorkingDirectory: commands.WorkingDirectory,
WorkingDirectory: conf.WorkingDirectory,
Arguments: os.Args[1:],
}

View File

@ -16,19 +16,18 @@ package migrate
import (
"os"
"log"
"github.com/lifei6671/mindoc/models"
"container/list"
"fmt"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
"github.com/lifei6671/mindoc/models"
"log"
)
var (
migrationList = &migrationCache{}
)
type MigrationDatabase interface {
//获取当前的版本
Version() int64
@ -119,7 +118,8 @@ func ExportDatabaseTable() ([]string,error) {
o := orm.NewOrm()
switch db_adapter {
case "mysql":{
case "mysql":
{
var lists []orm.Params
_, err := o.Raw(fmt.Sprintf("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '%s'", db_database)).Values(&lists)
@ -135,9 +135,10 @@ func ExportDatabaseTable() ([]string,error) {
}
tables = append(tables, results[0]["Create Table"].(string))
}
break;
break
}
case "sqlite3": {
case "sqlite3":
{
var results []orm.Params
_, err := o.Raw("SELECT sql FROM sqlite_master WHERE sql IS NOT NULL ORDER BY rootpage ASC").Values(&results)
if err != nil {

View File

@ -2,17 +2,16 @@ package migrate
import (
"errors"
"fmt"
"github.com/astaxie/beego/orm"
"github.com/lifei6671/mindoc/models"
"time"
"fmt"
"strings"
"time"
)
type MigrationVersion03 struct {
isValid bool
tables []string
}
func NewMigrationVersion03() *MigrationVersion03 {
@ -39,7 +38,6 @@ func (m *MigrationVersion03) ValidForBackupTableSchema() error {
var err error
m.tables, err = ExportDatabaseTable()
return err
}
@ -129,11 +127,3 @@ func (m *MigrationVersion03) RollbackMigration() error {
return nil
}

View File

@ -20,7 +20,7 @@ const RegexpEmail = "^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-
const RegexpAccount = `^[a-zA-Z][a-zA-z0-9\.]{2,50}$`
// PageSize 默认分页条数.
const PageSize = 15
const PageSize = 10
// 用户权限
const (
@ -55,12 +55,20 @@ const (
//LDAP用户校验
AuthMethodLDAP = "ldap"
)
var (
VERSION string
BUILD_TIME string
GO_VERSION string
)
var (
ConfigurationFile = "./conf/app.conf"
WorkingDirectory = "./"
LogFile = "./logs"
BaseUrl = ""
)
// app_key
func GetAppKey() string {
return beego.AppConfig.DefaultString("app_key", "godoc")
@ -102,6 +110,7 @@ func GetUploadFileExt() []string {
}
return exts
}
// 获取上传文件允许的最大值
func GetUploadFileSize() int64 {
size := beego.AppConfig.DefaultString("upload_file_size", "0")

View File

@ -14,6 +14,7 @@ import (
"github.com/lifei6671/mindoc/conf"
"github.com/lifei6671/mindoc/models"
"github.com/lifei6671/mindoc/utils"
"net/url"
)
// AccountController 用户登录与注册
@ -32,13 +33,16 @@ func (c *AccountController) Login() {
Time time.Time
}
// 显式指定的 URL 参数优先;为了统一处理,将之更新到 Session 中
turl := c.GetString("turl", "")
if turl != "" {
c.SetSession("turl", turl)
if member, ok := c.GetSession(conf.LoginSessionName).(models.Member); ok && member.MemberId > 0 {
u := c.GetString("url")
if u == "" {
u = c.Ctx.Request.Header.Get("Referer")
}
if u == "" {
u = beego.URLFor("HomeController.Index")
}
c.Redirect(u,302)
}
beego.Info("AccountController.Login(): turl is: " + turl)
// 如果 Cookie 中存在登录信息
if cookie, ok := c.GetSecureCookie(conf.GetAppKey(), "login"); ok {
@ -81,26 +85,35 @@ func (c *AccountController) Login() {
c.SetSecureCookie(conf.GetAppKey(), "login", v)
}
}
u,_ := url.PathUnescape(c.GetString("url"))
if u == "" {
u = c.Ctx.Request.Header.Get("Referer")
}
if u == "" {
u = beego.URLFor("HomeController.Index")
}
data := c.LoggedIn(true)
c.JsonResult(0, "ok", data)
c.JsonResult(0, "ok", u)
} else {
logs.Error("用户登录 =>", err)
c.JsonResult(500, "账号或密码错误", nil)
}
}else{
u,_ := url.PathUnescape(c.GetString("url"))
if u == "" {
u = c.Ctx.Request.Header.Get("Referer")
}
if u == "" {
u = beego.URLFor("HomeController.Index")
}
c.Data["url"] = url.PathEscape(u)
}
}
// 登录成功后的操作,如重定向到原始请求页面
func (c *AccountController) LoggedIn(isPost bool) interface{} {
turl := ""
value := c.GetSession("turl")
if value != nil {
turl = value.(string)
}
c.DelSession("turl")
beego.Info("AccountController.LoggedIn(): turl is: " + turl)
turl := c.GetString("url")
if !isPost {
// 检查是否存在 turl 参数,如果有则重定向至 turl 处,否则进入 Home 页面
@ -111,7 +124,7 @@ func (c *AccountController) LoggedIn(isPost bool) interface{} {
return nil
} else {
var data struct {
TURL string `json:"turl"`
TURL string `json:"url"`
}
data.TURL = turl
return data
@ -369,7 +382,9 @@ func (c *AccountController) Logout() {
c.SetSecureCookie(conf.GetAppKey(), "login", "", -3600)
c.Redirect(beego.URLFor("AccountController.Login"), 302)
u := c.Ctx.Request.Header.Get("Referer")
c.Redirect(beego.URLFor("AccountController.Login","url",u), 302)
}
// 验证码

View File

@ -1,18 +1,16 @@
package controllers
import (
"bytes"
"github.com/lifei6671/mindoc/models"
"github.com/lifei6671/mindoc/conf"
"github.com/astaxie/beego"
"strings"
"encoding/json"
"github.com/astaxie/beego"
"github.com/lifei6671/mindoc/conf"
"github.com/lifei6671/mindoc/models"
"io"
"strings"
)
type BaseController struct {
beego.Controller
Member *models.Member
@ -37,7 +35,8 @@ func (c *BaseController) Prepare (){
//c.Member.Find(1)
//c.Data["Member"] = *c.Member
}
c.Data["BaseUrl"] = c.Ctx.Input.Scheme() + "://" + c.Ctx.Request.Host
conf.BaseUrl = c.BaseUrl()
c.Data["BaseUrl"] = c.BaseUrl()
if options, err := models.NewOption().All(); err == nil {
c.Option = make(map[string]string, len(options))

View File

@ -1,25 +1,24 @@
package controllers
import (
"strings"
"regexp"
"strconv"
"time"
"encoding/json"
"html/template"
"errors"
"fmt"
"path/filepath"
"html/template"
"os"
"path/filepath"
"regexp"
"strconv"
"strings"
"time"
"github.com/lifei6671/mindoc/models"
"github.com/lifei6671/mindoc/utils"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
"github.com/astaxie/beego/logs"
"github.com/astaxie/beego/orm"
"github.com/lifei6671/mindoc/conf"
"github.com/lifei6671/mindoc/graphics"
"github.com/lifei6671/mindoc/commands"
"github.com/lifei6671/mindoc/models"
"github.com/lifei6671/mindoc/utils"
)
type BookController struct {
@ -158,7 +157,6 @@ func (c *BookController) SaveBook() {
book.AutoRelease = 0
}
if err := book.Update(); err != nil {
c.JsonResult(6006, "保存失败")
}
@ -244,6 +242,7 @@ func (c *BookController) Transfer() {
}
c.JsonResult(0, "ok")
}
//上传项目封面.
func (c *BookController) UploadCover() {
@ -273,7 +272,6 @@ func (c *BookController) UploadCover() {
c.JsonResult(500, "不支持的图片格式")
}
x1, _ := strconv.ParseFloat(c.GetString("x"), 10)
y1, _ := strconv.ParseFloat(c.GetString("y"), 10)
w1, _ := strconv.ParseFloat(c.GetString("width"), 10)
@ -310,7 +308,7 @@ func (c *BookController) UploadCover() {
c.JsonResult(500, "图片剪切")
}
filePath = filepath.Join(commands.WorkingDirectory,"uploads",time.Now().Format("200601"),fileName + "_small" + ext)
filePath = filepath.Join(conf.WorkingDirectory, "uploads", time.Now().Format("200601"), fileName+"_small"+ext)
//生成缩略图并保存到磁盘
err = graphics.ImageResizeSaveFile(subImg, 175, 230, filePath)
@ -320,7 +318,7 @@ func (c *BookController) UploadCover() {
c.JsonResult(500, "保存图片失败")
}
url := "/" + strings.Replace(strings.TrimPrefix(filePath,commands.WorkingDirectory),"\\","/",-1)
url := "/" + strings.Replace(strings.TrimPrefix(filePath, conf.WorkingDirectory), "\\", "/", -1)
if strings.HasPrefix(url, "//") {
url = string(url[1:])
@ -524,14 +522,14 @@ func (c *BookController) Release() {
identify := c.GetString("identify")
book_id := 0
bookId := 0
if c.Member.IsAdministrator() {
book, err := models.NewBook().FindByFieldFirst("identify", identify)
if err != nil {
}
book_id = book.BookId
bookId = book.BookId
} else {
book, err := models.NewBookResult().FindByIdentify(identify, c.Member.MemberId)
@ -548,11 +546,14 @@ func (c *BookController) Release() {
if book.RoleId != conf.BookAdmin && book.RoleId != conf.BookFounder && book.RoleId != conf.BookEditor {
c.JsonResult(6003, "权限不足")
}
book_id = book.BookId
bookId = book.BookId
}
go func(identify string) {
models.NewDocument().ReleaseContent(book_id)
models.NewDocument().ReleaseContent(bookId)
//当文档发布后,需要删除已缓存的转换项目
outputPath := filepath.Join(beego.AppConfig.DefaultString("book_output_path", "cache"), strconv.Itoa(bookId))
os.RemoveAll(outputPath)
}(identify)
@ -588,7 +589,6 @@ func (c *BookController) SaveSort() {
book_id = bookResult.BookId
}
content := c.Ctx.Input.RequestBody
var docs []map[string]interface{}
@ -602,16 +602,16 @@ func (c *BookController) SaveSort() {
for _, item := range docs {
if doc_id, ok := item["id"].(float64); ok {
doc,err := models.NewDocument().Find(int(doc_id));
doc, err := models.NewDocument().Find(int(doc_id))
if err != nil {
beego.Error(err)
continue;
continue
}
if doc.BookId != book_id {
logs.Info("%s", "权限错误")
continue;
continue
}
sort,ok := item["sort"].(float64);
sort, ok := item["sort"].(float64)
if !ok {
beego.Info("排序数字转换失败 => ", item)
continue
@ -640,7 +640,6 @@ func (c *BookController) SaveSort() {
c.JsonResult(0, "ok")
}
func (c *BookController) IsPermission() (*models.BookResult, error) {
identify := c.GetString("identify")
@ -660,4 +659,3 @@ func (c *BookController) IsPermission() (*models.BookResult,error) {
}
return book, nil
}

View File

@ -3,10 +3,10 @@ package controllers
import (
"errors"
"github.com/lifei6671/mindoc/models"
"github.com/astaxie/beego/orm"
"github.com/astaxie/beego/logs"
"github.com/astaxie/beego/orm"
"github.com/lifei6671/mindoc/conf"
"github.com/lifei6671/mindoc/models"
)
type BookMemberController struct {
@ -53,7 +53,6 @@ func (c *BookMemberController) AddMember() {
memberRelationshipResult.BookId = book.BookId
memberRelationshipResult.ResolveRoleName()
c.JsonResult(0, "ok", memberRelationshipResult)
}
c.JsonResult(500, err.Error())
@ -95,7 +94,7 @@ func (c *BookMemberController) ChangeRole() {
c.JsonResult(6004, "用户已被禁用")
}
relationship,err := models.NewRelationship().UpdateRoleId(book.BookId,member_id,role);
relationship, err := models.NewRelationship().UpdateRoleId(book.BookId, member_id, role)
if err != nil {
logs.Error("变更用户在项目中的权限 => ", err)

View File

@ -11,7 +11,7 @@ import (
"strconv"
"strings"
"time"
"net/url"
"image/png"
"bytes"
@ -21,7 +21,6 @@ import (
"github.com/astaxie/beego/orm"
"github.com/boombuler/barcode"
"github.com/boombuler/barcode/qr"
"github.com/lifei6671/mindoc/commands"
"github.com/lifei6671/mindoc/conf"
"github.com/lifei6671/mindoc/models"
"github.com/lifei6671/mindoc/utils"
@ -101,12 +100,10 @@ func promptUserToLogIn(c *DocumentController) {
beego.Info("Access " + c.Ctx.Request.URL.RequestURI() + " not permitted.")
beego.Info(" Access will be redirected to login page(SessionId: " + c.CruSession.SessionID() + ").")
c.SetSession("turl", c.Ctx.Request.URL.RequestURI())
if c.IsAjax() {
c.JsonResult(6000, "需要[重]登录。")
c.JsonResult(6000, "请重新登录。")
} else {
c.Redirect(beego.URLFor("AccountController.Login"), 302)
c.Redirect(beego.URLFor("AccountController.Login")+ "?url=" + url.PathEscape(conf.BaseUrl+ c.Ctx.Request.URL.RequestURI()), 302)
}
}
@ -156,8 +153,7 @@ func (c *DocumentController) Read() {
token := c.GetString("token")
id := c.GetString(":id")
c.Data["DocumentId"] = id // added by dandycheung, 2017-12-08, for exporting
beego.Info("DocumentController.Read(): c.Data[\"DocumentId\"] = ", id, ", IsAjax = ", c.IsAjax())
c.Data["DocumentId"] = id
if identify == "" || id == "" {
c.Abort("404")
@ -393,7 +389,6 @@ func (c *DocumentController) Create() {
document.Identify = doc_identify
document.Version = time.Now().Unix()
document.DocumentName = doc_name
document.ParentId = parent_id
@ -442,7 +437,6 @@ func (c *DocumentController) Upload() {
c.JsonResult(6009, "查过文件允许的上传最大值")
}
ext := filepath.Ext(moreFile.Filename)
if ext == "" {
@ -498,7 +492,7 @@ func (c *DocumentController) Upload() {
}
fileName := "attach_" + strconv.FormatInt(time.Now().UnixNano(), 16)
filePath := filepath.Join(commands.WorkingDirectory, "uploads", time.Now().Format("200601"), fileName+ext)
filePath := filepath.Join(conf.WorkingDirectory, "uploads", time.Now().Format("200601"), fileName+ext)
path := filepath.Dir(filePath)
os.MkdirAll(path, os.ModePerm)
@ -515,7 +509,7 @@ func (c *DocumentController) Upload() {
attachment.FileName = moreFile.Filename
attachment.CreateAt = c.Member.MemberId
attachment.FileExt = ext
attachment.FilePath = strings.TrimPrefix(filePath, commands.WorkingDirectory)
attachment.FilePath = strings.TrimPrefix(filePath, conf.WorkingDirectory)
attachment.DocumentId = doc_id
if fileInfo, err := os.Stat(filePath); err == nil {
@ -527,7 +521,7 @@ func (c *DocumentController) Upload() {
}
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)
attachment.HttpPath = "/" + strings.Replace(strings.TrimPrefix(filePath, conf.WorkingDirectory), "\\", "/", -1)
if strings.HasPrefix(attachment.HttpPath, "//") {
attachment.HttpPath = string(attachment.HttpPath[1:])
}
@ -621,7 +615,7 @@ func (c *DocumentController) DownloadAttachment() {
c.Abort("404")
}
c.Ctx.Output.Download(filepath.Join(commands.WorkingDirectory, attachment.FilePath), attachment.FileName)
c.Ctx.Output.Download(filepath.Join(conf.WorkingDirectory, attachment.FilePath), attachment.FileName)
c.StopRun()
}
@ -666,7 +660,7 @@ func (c *DocumentController) RemoveAttachment() {
c.JsonResult(6005, "删除失败")
}
os.Remove(filepath.Join(commands.WorkingDirectory, attach.FilePath))
os.Remove(filepath.Join(conf.WorkingDirectory, attach.FilePath))
c.JsonResult(0, "ok", attach)
}
@ -823,11 +817,9 @@ func (c *DocumentController) Content() {
go func(identify string) {
models.NewDocument().ReleaseContent(book_id)
}(identify)
}
c.JsonResult(0, "ok", doc)
}
@ -844,7 +836,6 @@ func (c *DocumentController) Content() {
c.JsonResult(0, "ok", doc)
}
func (c *DocumentController) GetDocumentById(id string) (doc *models.Document, err error) {
doc = models.NewDocument()
if doc_id, err := strconv.Atoi(id); err == nil {
@ -894,10 +885,6 @@ func (c *DocumentController) Export() {
bookResult = isReadable(identify, token, c)
}
if bookResult.PrivatelyOwned == 0 {
// TODO: 私有项目禁止导出
}
if !strings.HasPrefix(bookResult.Cover, "http:://") && !strings.HasPrefix(bookResult.Cover, "https:://") {
bookResult.Cover = c.BaseUrl() + bookResult.Cover
}
@ -909,40 +896,22 @@ func (c *DocumentController) Export() {
c.Abort("500")
}
if output == "pdf" {
c.Ctx.Output.Download(eBookResult.PDFPath, identify + ".pdf")
c.Ctx.Output.Download(eBookResult.PDFPath, bookResult.BookName+".pdf")
//如果没有开启缓存则10分钟后删除
if !bookResult.IsCacheEBook {
defer func(pdfpath string) {
time.Sleep(time.Minute * 10)
os.Remove(filepath.Dir(pdfpath))
}(eBookResult.PDFPath)
}
c.StopRun()
c.Abort("200")
} else if output == "epub" {
c.Ctx.Output.Download(eBookResult.PDFPath, identify + ".epub")
c.Ctx.Output.Download(eBookResult.EpubPath, bookResult.BookName+".epub")
//如果没有开启缓存则10分钟后删除
if !bookResult.IsCacheEBook {
defer func(pdfpath string) {
time.Sleep(time.Minute * 10)
os.Remove(filepath.Dir(pdfpath))
}(eBookResult.EpubPath)
}
c.StopRun()
c.Abort("200")
} else if output == "mobi" {
c.Ctx.Output.Download(eBookResult.PDFPath, identify + ".epub")
c.Ctx.Output.Download(eBookResult.MobiPath, bookResult.BookName+".epub")
//如果没有开启缓存则10分钟后删除
if !bookResult.IsCacheEBook {
defer func(pdfpath string) {
time.Sleep(time.Minute * 10)
os.Remove(filepath.Dir(pdfpath))
}(eBookResult.MobiPath)
}
c.StopRun()
c.Abort("200")
} else if output == "docx" {
c.Ctx.Output.Download(eBookResult.WordPath, bookResult.BookName+".epub")
c.Abort("200")
}
c.Abort("404")

View File

@ -1,10 +1,12 @@
package controllers
import (
"net/url"
"github.com/astaxie/beego"
"github.com/lifei6671/mindoc/models"
"github.com/lifei6671/mindoc/utils"
"math"
"github.com/lifei6671/mindoc/conf"
)
type HomeController struct {
@ -16,7 +18,7 @@ func (c *HomeController) Index() {
c.TplName = "home/index.tpl"
//如果没有开启匿名访问,则跳转到登录页面
if !c.EnableAnonymous && c.Member == nil {
c.Redirect(beego.URLFor("AccountController.Login"),302)
c.Redirect(beego.URLFor("AccountController.Login") + "?url=" + url.PathEscape(conf.BaseUrl + c.Ctx.Request.URL.RequestURI()), 302)
}
pageIndex, _ := c.GetInt("page", 1)
pageSize := 18

View File

@ -1,10 +1,10 @@
package controllers
import (
"github.com/lifei6671/mindoc/models"
"github.com/astaxie/beego/orm"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
"github.com/lifei6671/mindoc/conf"
"github.com/lifei6671/mindoc/models"
"github.com/lifei6671/mindoc/utils"
"math"
)
@ -88,6 +88,3 @@ func (c *LabelController) List() {
c.Data["Labels"] = labels
}

View File

@ -13,7 +13,6 @@ import (
"github.com/lifei6671/mindoc/models"
"github.com/lifei6671/mindoc/utils"
"path/filepath"
"github.com/lifei6671/mindoc/commands"
"strconv"
)
@ -42,7 +41,7 @@ func (c *ManagerController) Users() {
pageIndex, _ := c.GetInt("page", 0)
members, totalCount, err := models.NewMember().FindToPager(pageIndex, 15)
members, totalCount, err := models.NewMember().FindToPager(pageIndex, conf.PageSize)
if err != nil {
c.Data["ErrorMessage"] = err.Error()
@ -50,7 +49,7 @@ func (c *ManagerController) Users() {
}
if totalCount > 0 {
html := utils.GetPagerHtml(c.Ctx.Request.RequestURI, pageIndex, 10, int(totalCount))
html := utils.GetPagerHtml(c.Ctx.Request.RequestURI, pageIndex, conf.PageSize, int(totalCount))
c.Data["PageHtml"] = html
} else {
@ -574,7 +573,7 @@ func (c *ManagerController) AttachList() {
for _, item := range attachList {
p := filepath.Join(commands.WorkingDirectory,item.FilePath)
p := filepath.Join(conf.WorkingDirectory, item.FilePath)
item.IsExist = utils.FileExists(p)
@ -603,7 +602,7 @@ func (c *ManagerController) AttachDetailed() {
}
}
attach.FilePath = filepath.Join(commands.WorkingDirectory,attach.FilePath)
attach.FilePath = filepath.Join(conf.WorkingDirectory, attach.FilePath)
attach.HttpPath = c.BaseUrl() + attach.HttpPath
attach.IsExist = utils.FileExists(attach.FilePath)
@ -631,24 +630,3 @@ func (c *ManagerController) AttachDelete() {
}
c.JsonResult(0, "ok")
}

View File

@ -1,13 +1,13 @@
package controllers
import (
"github.com/lifei6671/mindoc/models"
"github.com/lifei6671/mindoc/conf"
"github.com/lifei6671/mindoc/utils"
"github.com/astaxie/beego"
"strings"
"github.com/lifei6671/mindoc/conf"
"github.com/lifei6671/mindoc/models"
"github.com/lifei6671/mindoc/utils"
"regexp"
"strconv"
"strings"
)
type SearchController struct {

View File

@ -3,17 +3,16 @@ package controllers
import (
"fmt"
"os"
"strings"
"path/filepath"
"strconv"
"strings"
"time"
"github.com/astaxie/beego/logs"
"github.com/lifei6671/mindoc/conf"
"github.com/lifei6671/mindoc/graphics"
"github.com/lifei6671/mindoc/models"
"github.com/lifei6671/mindoc/utils"
"github.com/lifei6671/mindoc/graphics"
"github.com/lifei6671/mindoc/conf"
"github.com/lifei6671/mindoc/commands"
)
type SettingController struct {
@ -101,7 +100,6 @@ func (c *SettingController) Upload() {
c.JsonResult(500, "不支持的图片格式")
}
x1, _ := strconv.ParseFloat(c.GetString("x"), 10)
y1, _ := strconv.ParseFloat(c.GetString("y"), 10)
w1, _ := strconv.ParseFloat(c.GetString("width"), 10)
@ -116,7 +114,7 @@ func (c *SettingController) Upload() {
fileName := "avatar_" + strconv.FormatInt(time.Now().UnixNano(), 16)
filePath := filepath.Join(commands.WorkingDirectory,"uploads" , time.Now().Format("200601") , fileName + ext)
filePath := filepath.Join(conf.WorkingDirectory, "uploads", time.Now().Format("200601"), fileName+ext)
path := filepath.Dir(filePath)
@ -129,7 +127,6 @@ func (c *SettingController) Upload() {
c.JsonResult(500, "图片保存失败")
}
//剪切图片
subImg, err := graphics.ImageCopyFromFile(filePath, x, y, width, height)
@ -139,7 +136,7 @@ func (c *SettingController) Upload() {
}
os.Remove(filePath)
filePath = filepath.Join(commands.WorkingDirectory,"uploads" , time.Now().Format("200601") , fileName + "_small" + ext)
filePath = filepath.Join(conf.WorkingDirectory, "uploads", time.Now().Format("200601"), fileName+"_small"+ext)
err = graphics.ImageResizeSaveFile(subImg, 120, 120, filePath)
//err = graphics.SaveImage(filePath,subImg)
@ -149,7 +146,7 @@ func (c *SettingController) Upload() {
c.JsonResult(500, "保存文件失败")
}
url := "/" + strings.Replace(strings.TrimPrefix(filePath,commands.WorkingDirectory),"\\","/",-1)
url := "/" + strings.Replace(strings.TrimPrefix(filePath, conf.WorkingDirectory), "\\", "/", -1)
if strings.HasPrefix(url, "//") {
url = string(url[1:])
}
@ -158,10 +155,10 @@ func (c *SettingController) Upload() {
avater := member.Avatar
member.Avatar = url
err := member.Update();
err := member.Update()
if err == nil {
if strings.HasPrefix(avater, "/uploads/") {
os.Remove(filepath.Join(commands.WorkingDirectory,avater))
os.Remove(filepath.Join(conf.WorkingDirectory, avater))
}
c.SetMember(*member)
} else {

View File

@ -11,14 +11,12 @@ import (
"strings"
"time"
"os/exec"
"errors"
"github.com/TruthHun/gotil/cryptil"
"github.com/TruthHun/gotil/filetil"
"github.com/TruthHun/gotil/ziptil"
"github.com/lifei6671/mindoc/utils/filetil"
"github.com/lifei6671/mindoc/utils/ziptil"
"github.com/lifei6671/mindoc/utils/cryptil"
)
type Converter struct {
@ -67,6 +65,7 @@ var (
output = "output" //文档导出文件夹
ebookConvert = "ebook-convert"
)
// 接口文档 https://manual.calibre-ebook.com/generated/en/ebook-convert.html#table-of-contents
//根据json配置文件创建文档转化对象
func NewConverter(configFile string, debug ...bool) (converter *Converter, err error) {
@ -124,7 +123,8 @@ func (this *Converter) Convert() (err error) {
}
//将当前文件夹下的所有文件压缩成zip包然后直接改名成content.epub
f := this.BasePath + "/content.epub"
f := filepath.Join(this.BasePath, "content.epub")
fmt.Println("epub目录 " + f)
os.Remove(f) //如果原文件存在了,则删除;
if err = ziptil.Zip(f, this.BasePath); err == nil {
//创建导出文件夹
@ -144,6 +144,12 @@ func (this *Converter) Convert() (err error) {
}
case "pdf":
if err = this.convertToPdf(); err != nil {
fmt.Println(err)
errs = append(errs, err.Error())
}
case "docx":
if err = this.convertToDocx(); err != nil {
fmt.Println(err)
errs = append(errs, err.Error())
}
}
@ -157,6 +163,8 @@ func (this *Converter) Convert() (err error) {
fmt.Println(err)
}
}
} else {
fmt.Println("压缩目录出错" + err.Error())
}
return
}
@ -164,13 +172,13 @@ func (this *Converter) Convert() (err error) {
//删除生成导出文档而创建的文件
func (this *Converter) converterDefer() {
//删除不必要的文件
os.RemoveAll(this.BasePath + "/META-INF")
os.RemoveAll(this.BasePath + "/content.epub")
os.RemoveAll(this.BasePath + "/mimetype")
os.RemoveAll(this.BasePath + "/toc.ncx")
os.RemoveAll(this.BasePath + "/content.opf")
os.RemoveAll(this.BasePath + "/titlepage.xhtml") //封面图片待优化
os.RemoveAll(this.BasePath + "/summary.html") //文档目录
os.RemoveAll(filepath.Join(this.BasePath, "META-INF"))
os.RemoveAll(filepath.Join(this.BasePath, "content.epub"))
os.RemoveAll(filepath.Join(this.BasePath, "mimetype"))
os.RemoveAll(filepath.Join(this.BasePath, "toc.ncx"))
os.RemoveAll(filepath.Join(this.BasePath, "content.opf"))
os.RemoveAll(filepath.Join(this.BasePath, "titlepage.xhtml")) //封面图片待优化
os.RemoveAll(filepath.Join(this.BasePath, "summary.html")) //文档目录
}
//生成metainfo
@ -182,15 +190,15 @@ func (this *Converter) generateMetaInfo() (err error) {
</rootfiles>
</container>
`
folder := this.BasePath + "/META-INF"
folder := filepath.Join(this.BasePath, "META-INF")
os.MkdirAll(folder, os.ModePerm)
err = ioutil.WriteFile(folder+"/container.xml", []byte(xml), os.ModePerm)
err = ioutil.WriteFile(filepath.Join(folder, "container.xml"), []byte(xml), os.ModePerm)
return
}
//形成mimetyppe
func (this *Converter) generateMimeType() (err error) {
return ioutil.WriteFile(this.BasePath+"/mimetype", []byte("application/epub+zip"), os.ModePerm)
return ioutil.WriteFile(filepath.Join(this.BasePath, "mimetype"), []byte("application/epub+zip"), os.ModePerm)
}
//生成封面
@ -216,7 +224,7 @@ func (this *Converter) generateTitlePage() (err error) {
</body>
</html>
`
if err = ioutil.WriteFile(this.BasePath+"/titlepage.xhtml", []byte(xml), os.ModePerm); err == nil {
if err = ioutil.WriteFile(filepath.Join(this.BasePath, "titlepage.xhtml"), []byte(xml), os.ModePerm); err == nil {
this.GeneratedCover = "titlepage.xhtml"
}
}
@ -241,7 +249,7 @@ func (this *Converter) generateTocNcx() (err error) {
`
codes, _ := this.tocToXml(0, 1)
ncx = fmt.Sprintf(ncx, this.Config.Language, this.Config.Title, strings.Join(codes, ""))
return ioutil.WriteFile(this.BasePath+"/toc.ncx", []byte(ncx), os.ModePerm)
return ioutil.WriteFile(filepath.Join(this.BasePath, "toc.ncx"), []byte(ncx), os.ModePerm)
}
//生成文档目录即summary.html
@ -263,7 +271,7 @@ func (this *Converter) generateSummary() (err error) {
</body>
</html>`
summary = fmt.Sprintf(summary, strings.Join(this.tocToSummary(0), ""))
return ioutil.WriteFile(this.BasePath+"/summary.html", []byte(summary), os.ModePerm)
return ioutil.WriteFile(filepath.Join(this.BasePath, "summary.html"), []byte(summary), os.ModePerm)
}
//将toc转成toc.ncx文件
@ -380,6 +388,8 @@ func (this *Converter) generateContentOpf() (err error) {
manifestArr = append(manifestArr, fmt.Sprintf(`<item href="%v" id="%v" media-type="%v"/>`, sourcefile, id, mt))
}
}
} else {
fmt.Println(file.Path)
}
}
@ -415,14 +425,14 @@ func (this *Converter) generateContentOpf() (err error) {
guide = `<guide>` + guide + `</guide>`
}
pkg = fmt.Sprintf(pkg, meta, manifest, spine, guide)
return ioutil.WriteFile(this.BasePath+"/content.opf", []byte(pkg), os.ModePerm)
return ioutil.WriteFile(filepath.Join(this.BasePath, "content.opf"), []byte(pkg), os.ModePerm)
}
//转成epub
func (this *Converter) convertToEpub() (err error) {
args := []string{
this.BasePath + "/content.epub",
this.BasePath + "/" + output + "/book.epub",
filepath.Join(this.BasePath, "content.epub"),
filepath.Join(this.BasePath, output, "book.epub"),
}
cmd := exec.Command(ebookConvert, args...)
@ -435,8 +445,8 @@ func (this *Converter) convertToEpub() (err error) {
//转成mobi
func (this *Converter) convertToMobi() (err error) {
args := []string{
this.BasePath + "/content.epub",
this.BasePath + "/" + output + "/book.mobi",
filepath.Join(this.BasePath, "content.epub"),
filepath.Join(this.BasePath, output, "book.mobi"),
}
cmd := exec.Command(ebookConvert, args...)
if this.Debug {
@ -449,8 +459,8 @@ func (this *Converter) convertToMobi() (err error) {
//转成pdf
func (this *Converter) convertToPdf() (err error) {
args := []string{
this.BasePath + "/content.epub",
this.BasePath + "/" + output + "/book.pdf",
filepath.Join(this.BasePath, "content.epub"),
filepath.Join(this.BasePath, output, "book.pdf"),
}
//页面大小
if len(this.Config.PaperSize) > 0 {
@ -490,6 +500,40 @@ func (this *Converter) convertToPdf() (err error) {
}
cmd := exec.Command(ebookConvert, args...)
if this.Debug {
fmt.Println(cmd.Args)
}
return cmd.Run()
}
// 转成word
func (this *Converter) convertToDocx() (err error) {
args := []string{
this.BasePath + "/content.epub",
this.BasePath + "/" + output + "/book.docx",
}
args = append(args, "--docx-no-toc")
//页面大小
if len(this.Config.PaperSize) > 0 {
args = append(args, "--docx-page-size", this.Config.PaperSize)
}
if len(this.Config.MarginLeft) > 0 {
args = append(args, "--docx-page-margin-left", this.Config.MarginLeft)
}
if len(this.Config.MarginTop) > 0 {
args = append(args, "--docx-page-margin-top", this.Config.MarginTop)
}
if len(this.Config.MarginRight) > 0 {
args = append(args, "--docx-page-margin-right", this.Config.MarginRight)
}
if len(this.Config.MarginBottom) > 0 {
args = append(args, "--docx-page-margin-bottom", this.Config.MarginBottom)
}
cmd := exec.Command(ebookConvert, args...)
if this.Debug {
fmt.Println(cmd.Args)
}

View File

@ -1,6 +1,4 @@
package models
type Model struct {
}

View File

@ -3,11 +3,14 @@ package models
import (
"time"
"fmt"
"github.com/astaxie/beego"
"github.com/astaxie/beego/logs"
"github.com/astaxie/beego/orm"
"github.com/lifei6671/mindoc/conf"
"fmt"
"os"
"path/filepath"
"strconv"
)
// Book struct .
@ -24,8 +27,6 @@ type Book struct {
Description string `orm:"column(description);size(2000)" json:"description"`
//发行公司
Publisher string `orm:"column(publisher);size(500)" json:"publisher"`
//是否缓存导出的电子书,如果缓存可能会出现导出的文件不是最新的。 0 为不缓存
IsCacheEBook int `orm:"column(is_cache_ebook);type(int);default(0)" json:"is_cache_ebook"`
Label string `orm:"column(label);size(500)" json:"label"`
// PrivatelyOwned 项目私有: 0 公开/ 1 私有
PrivatelyOwned int `orm:"column(privately_owned);type(int);default(0)" json:"privately_owned"`
@ -261,6 +262,8 @@ func (m *Book) ThoroughDeleteBook(id int) error {
NewLabel().InsertOrUpdateMulti(m.Label)
}
os.RemoveAll(filepath.Join(conf.WorkingDirectory,"uploads","books",strconv.Itoa(id)))
return o.Commit()
}
@ -355,7 +358,6 @@ func (m *Book) FindForLabelToPager(keyword string, pageIndex, pageSize, member_i
}
}
//重置文档数量
func (m *Book) ResetDocumentNumber(book_id int) {
o := orm.NewOrm()

View File

@ -1,21 +1,23 @@
package models
import (
"time"
"bytes"
"github.com/astaxie/beego/orm"
"github.com/astaxie/beego/logs"
"github.com/lifei6671/mindoc/conf"
"strings"
"github.com/lifei6671/mindoc/converter"
"strconv"
"github.com/russross/blackfriday"
"path/filepath"
"github.com/astaxie/beego"
"time"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"encoding/base64"
"github.com/PuerkitoBio/goquery"
"github.com/astaxie/beego"
"github.com/astaxie/beego/logs"
"github.com/astaxie/beego/orm"
"github.com/lifei6671/mindoc/conf"
"github.com/lifei6671/mindoc/converter"
"github.com/lifei6671/mindoc/utils"
"github.com/russross/blackfriday"
)
type BookResult struct {
@ -25,7 +27,6 @@ type BookResult struct {
OrderIndex int `json:"order_index"`
Description string `json:"description"`
Publisher string `json:"publisher"`
IsCacheEBook bool `json:"is_cache_ebook"`
PrivatelyOwned int `json:"privately_owned"`
PrivateToken string `json:"private_token"`
DocCount int `json:"doc_count"`
@ -54,7 +55,6 @@ func NewBookResult() *BookResult {
return &BookResult{}
}
// 根据项目标识查询项目以及指定用户权限的信息.
func (m *BookResult) FindByIdentify(identify string, member_id int) (*BookResult, error) {
if identify == "" || member_id <= 0 {
@ -98,7 +98,6 @@ func (m *BookResult) FindByIdentify(identify string,member_id int) (*BookResult,
m.RoleId = relationship.RoleId
m.RelationshipId = relationship.RelationshipId
if m.RoleId == conf.BookFounder {
m.RoleName = "创始人"
} else if m.RoleId == conf.BookAdmin {
@ -169,7 +168,6 @@ func (m *BookResult) ToBookResult(book Book) *BookResult {
m.Theme = book.Theme
m.AutoRelease = book.AutoRelease == 1
m.Publisher = book.Publisher
m.IsCacheEBook = book.IsCacheEBook == 1
if book.Theme == "" {
m.Theme = "default"
@ -183,24 +181,31 @@ func (m *BookResult) ToBookResult(book Book) *BookResult {
func (m *BookResult) Converter(sessionId string) (ConvertBookResult, error) {
convertBookResult := ConvertBookResult{}
outputPath := filepath.Join(beego.AppConfig.DefaultString("book_output_path","cache"),sessionId,strconv.Itoa(m.BookId))
if m.IsCacheEBook {
outputPath = filepath.Join(beego.AppConfig.DefaultString("book_output_path","cache"),strconv.Itoa(m.BookId))
}
outputPath := filepath.Join(conf.WorkingDirectory,"uploads","books", strconv.Itoa(m.BookId))
viewPath := beego.BConfig.WebConfig.ViewsPath
if m.IsCacheEBook {
pdfpath := filepath.Join(outputPath,"output","book.pdf")
epubpath := filepath.Join(outputPath,"output","book.epub")
mobipath := filepath.Join(outputPath,"output","book.mobi")
pdfpath := filepath.Join(outputPath, "book.pdf")
epubpath := filepath.Join(outputPath, "book.epub")
mobipath := filepath.Join(outputPath, "book.mobi")
docxpath := filepath.Join(outputPath, "book.docx")
if utils.FileExists(pdfpath) && utils.FileExists(epubpath) && utils.FileExists(mobipath){
//先将转换的文件储存到临时目录
tempOutputPath := filepath.Join(os.TempDir(),"sessionId") //filepath.Abs(filepath.Join("cache", sessionId))
os.MkdirAll(outputPath, 0766)
os.MkdirAll(tempOutputPath, 0766)
if utils.FileExists(pdfpath) && utils.FileExists(epubpath) && utils.FileExists(mobipath) && utils.FileExists(docxpath) {
convertBookResult.EpubPath = epubpath
convertBookResult.MobiPath = mobipath
convertBookResult.PDFPath = pdfpath
convertBookResult.WordPath = docxpath
return convertBookResult, nil
}
}
docs, err := NewDocument().FindListByBookId(m.BookId)
if err != nil {
return convertBookResult, err
@ -245,7 +250,7 @@ func (m *BookResult) Converter(sessionId string) (ConvertBookResult,error) {
Publisher: m.Publisher,
Contributor: m.Publisher,
Title: m.BookName,
Format: []string{"epub", "mobi", "pdf"},
Format: []string{"epub", "mobi", "pdf", "docx"},
FontSize: "14",
PaperSize: "a4",
MarginLeft: "72",
@ -254,22 +259,16 @@ func (m *BookResult) Converter(sessionId string) (ConvertBookResult,error) {
MarginBottom: "72",
Toc: tocList,
More: []string{},
}
os.MkdirAll(outputPath, 0766)
if outputPath, err = filepath.Abs(outputPath); err != nil {
if tempOutputPath, err = filepath.Abs(tempOutputPath); err != nil {
beego.Error("导出目录配置错误:" + err.Error())
return convertBookResult, err
}
viewPath := beego.BConfig.WebConfig.ViewsPath
baseUrl := beego.AppConfig.DefaultString("baseurl","")
for _, item := range docs {
name := strconv.Itoa(item.DocumentId)
fpath := filepath.Join(outputPath,name + ".html")
fpath := filepath.Join(tempOutputPath, name+".html")
f, err := os.OpenFile(fpath, os.O_CREATE|os.O_RDWR, 0777)
if err != nil {
@ -277,12 +276,11 @@ func (m *BookResult) Converter(sessionId string) (ConvertBookResult,error) {
}
var buf bytes.Buffer
if err := beego.ExecuteViewPathTemplate(&buf,"document/export.tpl",viewPath,map[string]interface{}{"Model": m, "Lists": item, "BaseUrl": baseUrl}); err != nil {
if err := beego.ExecuteViewPathTemplate(&buf, "document/export.tpl", viewPath, map[string]interface{}{"Model": m, "Lists": item, "BaseUrl": conf.BaseUrl}); err != nil {
return convertBookResult, err
}
html := buf.String()
if err != nil {
f.Close()
@ -293,8 +291,19 @@ func (m *BookResult) Converter(sessionId string) (ConvertBookResult,error) {
doc, err := goquery.NewDocumentFromReader(bufio)
doc.Find("img").Each(func(i int, contentSelection *goquery.Selection) {
if src, ok := contentSelection.Attr("src"); ok && strings.HasPrefix(src, "/uploads/") {
contentSelection.SetAttr("src", baseUrl + src)
if src, ok := contentSelection.Attr("src"); ok && strings.HasPrefix(src, "/") {
//contentSelection.SetAttr("src", baseUrl + src)
spath := filepath.Join(conf.WorkingDirectory, src)
if ff, e := ioutil.ReadFile(spath); e == nil {
encodeString := base64.StdEncoding.EncodeToString(ff)
src = "data:image/" + filepath.Ext(src) + ";base64," + encodeString
contentSelection.SetAttr("src", src)
}
}
})
@ -310,35 +319,29 @@ func (m *BookResult) Converter(sessionId string) (ConvertBookResult,error) {
f.Close()
}
eBookConverter := &converter.Converter{
BasePath : outputPath,
BasePath: tempOutputPath,
Config: ebookConfig,
Debug : false,
Debug: true,
}
if err := eBookConverter.Convert(); err != nil {
beego.Error("转换文件错误:" + m.BookName + " => " + err.Error())
return convertBookResult, err
}
convertBookResult.MobiPath = filepath.Join(outputPath,"output","book.mobi")
convertBookResult.PDFPath = filepath.Join(outputPath,"output","book.pdf")
convertBookResult.EpubPath = filepath.Join(outputPath,"output","book.epub")
beego.Info("文档转换完成:" + m.BookName)
defer func(p string) {
os.RemoveAll(p)
}(tempOutputPath)
utils.CopyFile(mobipath, filepath.Join(tempOutputPath, "output", "book.mobi"))
utils.CopyFile(pdfpath, filepath.Join(tempOutputPath, "output", "book.pdf"))
utils.CopyFile(epubpath, filepath.Join(tempOutputPath, "output", "book.epub"))
utils.CopyFile(docxpath, filepath.Join(tempOutputPath, "output", "book.docx"))
convertBookResult.MobiPath = mobipath
convertBookResult.PDFPath = pdfpath
convertBookResult.EpubPath = epubpath
convertBookResult.WordPath = docxpath
return convertBookResult, nil
}

View File

@ -1,10 +1,10 @@
package models
import (
"time"
"github.com/lifei6671/mindoc/conf"
"github.com/astaxie/beego/orm"
"errors"
"github.com/astaxie/beego/orm"
"github.com/lifei6671/mindoc/conf"
"time"
)
//Comment struct
@ -38,6 +38,7 @@ type Comment struct {
func (m *Comment) TableName() string {
return "comments"
}
// TableEngine 获取数据使用的引擎.
func (m *Comment) TableEngine() string {
return "INNODB"
@ -92,7 +93,7 @@ func (m *Comment) Insert() error {
if _, err := document.Find(m.DocumentId); err != nil {
return err
}
book ,err := NewBook().Find(document.BookId);
book, err := NewBook().Find(document.BookId)
//如果评论的项目不存在
if err != nil {
return err
@ -133,36 +134,3 @@ func (m *Comment) Insert() error {
return err
}

View File

@ -25,7 +25,6 @@ FROM md_comments AS comment
WHERE comment.document_id = ? ORDER BY comment.comment_id DESC LIMIT 0,10`
offset := (page_index - 1) * page_size
_, err = o.Raw(sql1, doc_id, offset, page_size).QueryRows(&comments)
@ -38,4 +37,3 @@ WHERE comment.document_id = ? ORDER BY comment.comment_id DESC LIMIT 0,10`
return
}

View File

@ -1,9 +1,9 @@
package models
import (
"time"
"github.com/lifei6671/mindoc/conf"
"github.com/astaxie/beego/orm"
"github.com/lifei6671/mindoc/conf"
"time"
)
type CommentVote struct {
@ -19,6 +19,7 @@ type CommentVote struct {
func (m *CommentVote) TableName() string {
return "comment_votes"
}
// TableEngine 获取数据使用的引擎.
func (m *CommentVote) TableEngine() string {
return "INNODB"

View File

@ -5,4 +5,5 @@ type ConvertBookResult struct {
PDFPath string
EpubPath string
MobiPath string
WordPath string
}

View File

@ -14,7 +14,7 @@ func NewDashboard() *Dashboard {
return &Dashboard{}
}
func (m *Dashboard) Query() (*Dashboard) {
func (m *Dashboard) Query() *Dashboard {
o := orm.NewOrm()
book_number, _ := o.QueryTable(NewBook().TableNameWithPrefix()).Count()

View File

@ -9,6 +9,9 @@ import (
"github.com/astaxie/beego/orm"
"github.com/lifei6671/mindoc/conf"
"strings"
"os"
"path/filepath"
"strconv"
)
// Document struct.
@ -121,12 +124,12 @@ func (m *Document) RecursiveDocument(doc_id int) error {
}
//发布文档
func (m *Document) ReleaseContent(book_id int) {
func (m *Document) ReleaseContent(bookId int) {
o := orm.NewOrm()
var docs []*Document
_, err := o.QueryTable(m.TableNameWithPrefix()).Filter("book_id", book_id).All(&docs, "document_id", "content")
_, err := o.QueryTable(m.TableNameWithPrefix()).Filter("book_id", bookId).All(&docs, "document_id", "content")
if err != nil {
beego.Error("发布失败 => ", err)
@ -134,10 +137,10 @@ func (m *Document) ReleaseContent(book_id int) {
}
for _, item := range docs {
item.Release = item.Content
attach_list, err := NewAttachment().FindListByDocumentId(item.DocumentId)
if err == nil && len(attach_list) > 0 {
attachList, err := NewAttachment().FindListByDocumentId(item.DocumentId)
if err == nil && len(attachList) > 0 {
content := bytes.NewBufferString("<div class=\"attach-list\"><strong>附件</strong><ul>")
for _, attach := range attach_list {
for _, attach := range attachList {
if strings.HasPrefix(attach.HttpPath, "/") {
attach.HttpPath = strings.TrimSuffix(beego.AppConfig.DefaultString("baseurl", ""), "/") + attach.HttpPath
}
@ -151,6 +154,8 @@ func (m *Document) ReleaseContent(book_id int) {
_, err = o.Update(item, "release")
if err != nil {
beego.Error(fmt.Sprintf("发布失败 => %+v", item), err)
}else {
os.RemoveAll(filepath.Join(conf.WorkingDirectory,"uploads","books",strconv.Itoa(bookId)))
}
}
}

View File

@ -56,6 +56,7 @@ func (m *DocumentHistory) Find(id int) (*DocumentHistory,error) {
return m, err
}
//清空指定文档的历史.
func (m *DocumentHistory) Clear(doc_id int) error {
o := orm.NewOrm()
@ -124,6 +125,7 @@ func (m *DocumentHistory) InsertOrUpdate() (history *DocumentHistory,err error)
}
return
}
//分页查询指定文档的历史.
func (m *DocumentHistory) FindToPager(doc_id, page_index, page_size int) (docs []*DocumentHistorySimpleResult, totalCount int, err error) {

View File

@ -1,11 +1,12 @@
package models
import (
"github.com/astaxie/beego/orm"
"bytes"
"strconv"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
"html/template"
"math"
"strconv"
)
type DocumentTree struct {
@ -30,7 +31,7 @@ func (m *Document) FindDocumentTree(book_id int) ([]*DocumentTree,error){
var docs []*Document
count ,err := o.QueryTable(m).Filter("book_id",book_id).OrderBy("order_sort","document_id").All(&docs,"document_id","version","document_name","parent_id","identify")
count, err := o.QueryTable(m).Filter("book_id", book_id).OrderBy("order_sort", "document_id").Limit(math.MaxInt32).All(&docs, "document_id", "version", "document_name", "parent_id", "identify")
if err != nil {
return trees, err
@ -138,14 +139,3 @@ func getDocumentTree(array []*DocumentTree,parent_id int,selected_id int,selecte
}
buf.WriteString("</ul>")
}

View File

@ -1,8 +1,8 @@
package models
import (
"github.com/lifei6671/mindoc/conf"
"github.com/astaxie/beego/orm"
"github.com/lifei6671/mindoc/conf"
"strings"
)
@ -16,6 +16,7 @@ type Label struct {
func (m *Label) TableName() string {
return "label"
}
// TableEngine 获取数据使用的引擎.
func (m *Label) TableEngine() string {
return "INNODB"
@ -89,4 +90,3 @@ func (m *Label) FindToPager(pageIndex, pageSize int) (labels []*Label,totalCount
return
}

View File

@ -1,11 +1,11 @@
package models
import (
"time"
"errors"
"github.com/astaxie/beego/orm"
"github.com/lifei6671/mindoc/conf"
"sync/atomic"
"github.com/astaxie/beego/orm"
"errors"
"time"
)
var loggerQueue = &logQueue{channel: make(chan *Logger, 100), isRuning: 0}
@ -33,6 +33,7 @@ type Logger struct {
func (m *Logger) TableName() string {
return "logs"
}
// TableEngine 获取数据使用的引擎.
func (m *Logger) TableEngine() string {
return "INNODB"
@ -73,16 +74,3 @@ func addLoggerAsync() {
o.Insert(logger)
}
}

View File

@ -15,6 +15,7 @@ import (
"github.com/astaxie/beego/orm"
"github.com/lifei6671/mindoc/conf"
"github.com/lifei6671/mindoc/utils"
"math"
)
type Member struct {
@ -324,7 +325,6 @@ func (m *Member) Valid(is_hash_password bool) error {
}
}
return nil
}
@ -386,7 +386,7 @@ func (m *Member) Delete(oldId int,newId int) error {
//}
var relationship_list []*Relationship
_,err = o.QueryTable(NewRelationship().TableNameWithPrefix()).Filter("member_id",oldId).All(&relationship_list)
_, err = o.QueryTable(NewRelationship().TableNameWithPrefix()).Filter("member_id", oldId).Limit(math.MaxInt32).All(&relationship_list)
if err == nil {
for _, relationship := range relationship_list {
@ -420,19 +420,3 @@ func (m *Member) Delete(oldId int,newId int) error {
}
return nil
}

View File

@ -1,9 +1,9 @@
package models
import (
"time"
"github.com/astaxie/beego/orm"
"github.com/lifei6671/mindoc/conf"
"time"
)
type MemberRelationshipResult struct {
@ -84,9 +84,3 @@ func (m *MemberRelationshipResult) FindForUsersByBookId(book_id ,pageIndex, page
}
return members, total_count, nil
}

View File

@ -1,9 +1,9 @@
package models
import (
"time"
"github.com/lifei6671/mindoc/conf"
"github.com/astaxie/beego/orm"
"github.com/lifei6671/mindoc/conf"
"time"
)
type MemberToken struct {
@ -16,11 +16,11 @@ type MemberToken struct {
SendTime time.Time `orm:"column(send_time);auto_now_add;type(datetime)" json:"send_time"`
}
// TableName 获取对应数据库表名.
func (m *MemberToken) TableName() string {
return "member_token"
}
// TableEngine 获取数据使用的引擎.
func (m *MemberToken) TableEngine() string {
return "INNODB"

View File

@ -1,9 +1,9 @@
package models
import (
"time"
"github.com/lifei6671/mindoc/conf"
"github.com/astaxie/beego/orm"
"github.com/lifei6671/mindoc/conf"
"time"
)
type Migration struct {

View File

@ -5,7 +5,6 @@ import (
"github.com/lifei6671/mindoc/conf"
)
// Option struct .
type Option struct {
OptionId int `orm:"column(option_id);pk;auto;unique;" json:"option_id"`
@ -19,6 +18,7 @@ type Option struct {
func (m *Option) TableName() string {
return "options"
}
// TableEngine 获取数据使用的引擎.
func (m *Option) TableEngine() string {
return "INNODB"
@ -28,7 +28,6 @@ func (m *Option)TableNameWithPrefix() string {
return conf.GetDatabasePrefix() + m.TableName()
}
func NewOption() *Option {
return &Option{}
}
@ -68,7 +67,6 @@ func (p *Option) InsertOrUpdate() error {
var err error
if p.OptionId > 0 || o.QueryTable(p.TableNameWithPrefix()).Filter("option_name", p.OptionName).Exist() {
_, err = o.Update(p)
} else {
@ -77,7 +75,7 @@ func (p *Option) InsertOrUpdate() error {
return err
}
func (p *Option) InsertMulti(option... Option ) (error){
func (p *Option) InsertMulti(option ...Option) error {
o := orm.NewOrm()

View File

@ -1,10 +1,10 @@
package models
import (
"github.com/lifei6671/mindoc/conf"
"github.com/astaxie/beego/orm"
"errors"
"github.com/astaxie/beego/logs"
"github.com/astaxie/beego/orm"
"github.com/lifei6671/mindoc/conf"
)
type Relationship struct {
@ -15,7 +15,6 @@ type Relationship struct {
RoleId int `orm:"column(role_id);type(int)" json:"role_id"`
}
// TableName 获取对应数据库表名.
func (m *Relationship) TableName() string {
return "relationship"
@ -194,24 +193,3 @@ func (m *Relationship) Transfer(book_id,founder_id,receive_id int) error {
return o.Commit()
}

View File

@ -1,11 +1,12 @@
package routers
import (
"encoding/json"
"github.com/astaxie/beego"
"github.com/astaxie/beego/context"
"github.com/lifei6671/mindoc/conf"
"github.com/lifei6671/mindoc/models"
"encoding/json"
"net/url"
)
func init() {
@ -18,11 +19,12 @@ func init() {
jsonData["errcode"] = 403
jsonData["message"] = "请登录后再操作"
returnJSON, _ := json.Marshal(jsonData)
ctx.ResponseWriter.Write(returnJSON)
} else {
ctx.Redirect(302, beego.URLFor("AccountController.Login"))
ctx.Redirect(302, beego.URLFor("AccountController.Login") + "?url=" + url.PathEscape(ctx.Request.URL.RequestURI()))
}
}
}
@ -36,7 +38,7 @@ func init() {
var FinishRouter = func(ctx *context.Context) {
ctx.ResponseWriter.Header().Add("MinDoc-Version", conf.VERSION)
ctx.ResponseWriter.Header().Add("MinDoc-Site","http://www.iminho.me")
ctx.ResponseWriter.Header().Add("MinDoc-Site", "https://www.iminho.me")
}
beego.InsertFilter("/*", beego.BeforeRouter, FinishRouter, false)

View File

@ -141,7 +141,6 @@ $(function () {
$.get(window.editURL + $node.node.id ).done(function (res) {
layer.close(index);
resetEditor();
if (res.errcode === 0) {
window.isLoad = true;
try {
@ -153,7 +152,6 @@ $(function () {
}
var node = { "id": res.data.doc_id, 'parent': res.data.parent_id === 0 ? '#' : res.data.parent_id, "text": res.data.doc_name, "identify": res.data.identify, "version": res.data.version };
pushDocumentCategory(node);
console.log(node);
window.selectNode = node;
pushVueLists(res.data.attach);
} else {

View File

@ -0,0 +1,70 @@
package cryptil
import (
"crypto/hmac"
"crypto/md5"
"crypto/sha1"
"encoding/base64"
"fmt"
"strconv"
"strings"
"time"
)
//对称加密与解密之加密【从Beego中提取出来的】
//@param value 需要加密的字符串
//@param secret 加密密钥
//@return encrypt 返回的加密后的字符串
func Encrypt(value, secret string) (encrypt string) {
vs := base64.URLEncoding.EncodeToString([]byte(value))
timestamp := strconv.FormatInt(time.Now().UnixNano(), 10)
h := hmac.New(sha1.New, []byte(secret))
fmt.Fprintf(h, "%s%s", vs, timestamp)
sig := fmt.Sprintf("%02x", h.Sum(nil))
return strings.Join([]string{vs, timestamp, sig}, ".")
}
//对称加密与解密之解密【从Beego中提取出来的】
//@param value 需要解密的字符串
//@param secret 密钥
//@return decrypt 返回解密后的字符串
func Decrypt(value, secret string) (decrypt string) {
parts := strings.SplitN(value, ".", 3)
if len(parts) != 3 {
return ""
}
vs := parts[0]
timestamp := parts[1]
sig := parts[2]
h := hmac.New(sha1.New, []byte(secret))
fmt.Fprintf(h, "%s%s", vs, timestamp)
if fmt.Sprintf("%02x", h.Sum(nil)) != sig {
return ""
}
res, _ := base64.URLEncoding.DecodeString(vs)
return string(res)
}
//MD5加密
//@param str 需要加密的字符串
//@param salt 盐值
//@return CryptStr 加密后返回的字符串
func Md5Crypt(str string, salt ...interface{}) (CryptStr string) {
if l := len(salt); l > 0 {
slice := make([]string, l+1)
str = fmt.Sprintf(str+strings.Join(slice, "%v"), salt...)
}
return fmt.Sprintf("%x", md5.Sum([]byte(str)))
}
//SHA1加密
//@param str 需要加密的字符串
//@param salt 盐值
//@return CryptStr 加密后返回的字符串
func Sha1Crypt(str string, salt ...interface{}) (CryptStr string) {
if l := len(salt); l > 0 {
slice := make([]string, l+1)
str = fmt.Sprintf(str+strings.Join(slice, "%v"), salt...)
}
return fmt.Sprintf("%x", sha1.Sum([]byte(str)))
}

View File

@ -1,12 +1,12 @@
package utils
import (
"strings"
"os"
"fmt"
"path/filepath"
"io"
"math"
"os"
"path/filepath"
"strings"
)
func AbsolutePath(p string) (string, error) {
@ -62,14 +62,9 @@ func FormatBytes(size int64) string {
s /= 1024
}
return fmt.Sprintf("%.2f%s", s, units[i])
}
func Round(val float64, places int) float64 {
var t float64
f := math.Pow10(places)
@ -97,12 +92,3 @@ func Round(val float64, places int) float64 {
return t
}

View File

@ -0,0 +1,43 @@
package filetil
import (
"os"
"path/filepath"
"strings"
)
//==================================
//更多文件和目录的操作使用filepath包和os包
//==================================
//返回的目录扫描结果
type FileList struct {
IsDir bool //是否是目录
Path string //文件路径
Ext string //文件扩展名
Name string //文件名
Size int64 //文件大小
ModTime int64 //文件修改时间戳
}
//目录扫描
//@param dir 需要扫描的目录
//@return fl 文件列表
//@return err 错误
func ScanFiles(dir string) (fl []FileList, err error) {
err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err == nil {
path = strings.Replace(path, "\\", "/", -1) //文件路径处理
fl = append(fl, FileList{
IsDir: info.IsDir(),
Path: path,
Ext: strings.ToLower(filepath.Ext(path)),
Name: info.Name(),
Size: info.Size(),
ModTime: info.ModTime().Unix(),
})
}
return err
})
return
}

View File

@ -6,25 +6,25 @@ import (
)
//解码
func Decode(value string,r interface{}) (error) {
func Decode(value string, r interface{}) error {
network := bytes.NewBuffer([]byte(value));
network := bytes.NewBuffer([]byte(value))
dec := gob.NewDecoder(network)
return dec.Decode(r);
return dec.Decode(r)
}
//编码
func Encode(value interface{}) (string, error) {
network:= bytes.NewBuffer(nil);
network := bytes.NewBuffer(nil)
enc := gob.NewEncoder(network)
err := enc.Encode(value);
err := enc.Encode(value)
if err != nil {
return "",err;
return "", err
}
return network.String(),nil;
return network.String(), nil
}

View File

@ -1,11 +1,10 @@
package utils
import (
"time"
"math/rand"
"time"
)
const (
KC_RAND_KIND_NUM = 0 // 纯数字
KC_RAND_KIND_LOWER = 1 // 小写字母

View File

@ -1,11 +1,12 @@
package utils
import (
"gopkg.in/ldap.v2"
"fmt"
"errors"
"fmt"
"github.com/astaxie/beego"
"gopkg.in/ldap.v2"
)
/*
config
ldap:
@ -122,15 +123,3 @@ func ModifyPassword(account, old_password, new_password string) error {
}
return nil
}

View File

@ -6,8 +6,8 @@ import (
con "strconv"
"strings"
"github.com/astaxie/beego/orm"
"fmt"
"github.com/astaxie/beego/orm"
"math"
)
@ -94,13 +94,14 @@ func GetPagerLinks(po *PageOptions,requestURI string) (int, int, orm.RawSeter, h
return totalItem, totalpages, rs, html.HTML(str)
}
func GetPagerHtml(requestURI string,pageIndex, pageSize,totalCount int) (html.HTML){
func GetPagerHtml(requestURI string, pageIndex, pageSize, totalCount int) html.HTML {
po := &PageOptions{
CurrentPage: pageIndex,
PageSize: pageSize,
EnableFirstLastLink: true,
ParamName: "page",
TotalPages: int(math.Ceil(float64(totalCount) / float64(pageSize))),
LinkItemCount: pageSize,
}
totalPages := int(math.Ceil(float64(totalCount) / float64(pageSize)))
@ -167,8 +168,11 @@ func fun4(po *PageOptions, totalPages int) string {
rs := ""
rs += getHeader(po, totalPages)
rs += "<li><a href='" + po.Href + "&" + po.ParamName + "=" + con.Itoa(1) + "'>" + con.Itoa(1) + "</a></li>"
rs += "<li><a href=''>...</a></li>"
for i := totalPages - po.LinkItemCount; i <= totalPages; i++ {
rs += "<li><a href=\"#\" class=\"@3\">...</a></li>"
for i := totalPages - po.LinkItemCount-1; i <= totalPages; i++ {
if po.CurrentPage != i {
rs += "<li><a href='" + po.Href + "&" + po.ParamName + "=" + con.Itoa(i) + "'>" + con.Itoa(i) + "</a></li>"
} else {
@ -187,15 +191,15 @@ func fun3(po *PageOptions, totalpages int) string {
var rs string = ""
rs += getHeader(po, totalpages)
rs += "<li><a href='" + po.Href + "&" + po.ParamName + "=" + con.Itoa(1) + "'>" + con.Itoa(1) + "</a></li>"
rs += "<a href=''>...</a>"
rs += "<li><a href=\"#\" class=\"@1\">...</a></li>"
for i := po.CurrentPage - po.LinkItemCount/2 + 1; i <= po.CurrentPage+po.LinkItemCount/2-1; i++ {
if po.CurrentPage != i {
rs += "<a href='" + po.Href + "&" + po.ParamName + "=" + con.Itoa(i) + "'>" + con.Itoa(i) + "</a>"
rs += "<li><a href='" + po.Href + "&" + po.ParamName + "=" + con.Itoa(i) + "'>" + con.Itoa(i) + "</a></li>"
} else {
rs += "<li class=\"active\"><a href=\"###\">" + con.Itoa(i) + " <span class=\"sr-only\">(current)</span></a></li>"
}
}
rs += "<a href=''>...</a>"
rs += "<li><a href=\"#\" class=\"@2\">...</a></li>"
rs += "<li><a href='" + po.Href + "&" + po.ParamName + "=" + con.Itoa(totalpages) + "'>" + con.Itoa(totalpages) + "</a></li>"
rs += getFooter(po, totalpages)
return rs
@ -207,11 +211,11 @@ func fun3(po *PageOptions, totalpages int) string {
* 123456789...200
*/
func fun2(po *PageOptions, totalpages int) string {
var rs string = ""
rs := ""
rs += getHeader(po, totalpages)
for i := 1; i <= po.LinkItemCount+1; i++ {
if i == po.LinkItemCount {
rs += "<li><a href=\"" + po.Href + "&" + po.ParamName + "=" + con.Itoa(i) + "\">...</a></li>"
for i := 1; i <= po.LinkItemCount+2; i++ {
if i == po.LinkItemCount+2 {
rs += "<li class=\"@4\"><a href=\"" + po.Href + "&" + po.ParamName + "=" + con.Itoa(i) + "\">...</a></li>"
} else if i == po.LinkItemCount+1 {
rs += "<li><a href=\"" + po.Href + "&" + po.ParamName + "=" + con.Itoa(totalpages) + "\">" + con.Itoa(totalpages) + "</a></li>"
} else {

View File

@ -1,15 +1,14 @@
package utils
import (
"crypto/rand"
mt "math/rand"
"crypto/md5"
"crypto/rand"
"crypto/sha256"
"crypto/sha512"
"encoding/base64"
"encoding/hex"
"io"
mt "math/rand"
"strconv"
"strings"
)
@ -20,6 +19,7 @@ const (
stretching_password = 500
salt_local_secret = "ahfw*&TGdsfnbi*^Wt"
)
//加密密码
func PasswordHash(pass string) (string, error) {
@ -45,6 +45,7 @@ func PasswordHash(pass string) (string, error) {
return password, nil
}
//校验密码是否有效
func PasswordVerify(hashing string, pass string) (bool, error) {
data := trim_salt_hash(hashing)

View File

@ -1,5 +1,5 @@
package utils
func Asset(p string, cdn string) string {
return cdn + p;
return cdn + p
}

View File

@ -0,0 +1,101 @@
package ziptil
import (
"archive/zip"
"errors"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/lifei6671/mindoc/utils/filetil"
)
//解压zip文件
//@param zipFile 需要解压的zip文件
//@param dest 需要解压到的目录
//@return err 返回错误
func Unzip(zipFile, dest string) (err error) {
dest = strings.TrimSuffix(dest, "/") + "/"
// 打开一个zip格式文件
r, err := zip.OpenReader(zipFile)
if err != nil {
return err
}
defer r.Close()
// 迭代压缩文件中的文件,打印出文件中的内容
for _, f := range r.File {
if !f.FileInfo().IsDir() { //非目录且不包含__MACOSX
if folder := dest + filepath.Dir(f.Name); !strings.Contains(folder, "__MACOSX") {
os.MkdirAll(folder, 0777)
if fcreate, err := os.Create(dest + strings.TrimPrefix(f.Name, "./")); err == nil {
if rc, err := f.Open(); err == nil {
io.Copy(fcreate, rc)
rc.Close() //不要用defer来关闭如果文件太多的话会报too many open files 的错误
fcreate.Close()
} else {
fcreate.Close()
return err
}
} else {
return err
}
}
}
}
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)
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
}

View File

@ -131,7 +131,7 @@
return false;
} else {
$.ajax({
url: "{{urlfor "AccountController.Login"}}",
url: "{{urlfor "AccountController.Login" "url" .url}}",
data: $("form").serializeArray(),
dataType: "json",
type: "POST",
@ -142,7 +142,7 @@
layer.msg(res.message);
$btn.button('reset');
} else {
turl = res.data.turl;
turl = res.data;
if (turl === "") {
turl = "/";
}

View File

@ -65,6 +65,7 @@
<li><a href="{{urlfor "DocumentController.Export" ":key" .Model.Identify "output" "pdf"}}" target="_blank">PDF</a> </li>
<li><a href="{{urlfor "DocumentController.Export" ":key" .Model.Identify "output" "epub"}}" target="_blank">EPUB</a> </li>
<li><a href="{{urlfor "DocumentController.Export" ":key" .Model.Identify "output" "mobi"}}" target="_blank">MOBI</a> </li>
<li><a href="{{urlfor "DocumentController.Export" ":key" .Model.Identify "output" "docx"}}" target="_blank">Word</a> </li>
</ul>
</div>