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 注册数据库
@ -54,8 +47,8 @@ func RegisterDataBase() {
}
} else if adapter == "sqlite3" {
database := beego.AppConfig.String("db_database")
if strings.HasPrefix(database,"./") {
database = filepath.Join(WorkingDirectory,string(database[1:]))
if strings.HasPrefix(database, "./") {
database = filepath.Join(conf.WorkingDirectory, string(database[1:]))
}
dbPath := filepath.Dir(database)
@ -99,11 +92,11 @@ func RegisterLogger(log string) {
if f, err := os.Create(logPath); err == nil {
f.Close()
config := make(map[string]interface{},1)
config := make(map[string]interface{}, 1)
config["filename"] = logPath
b,_ := json.Marshal(config)
b, _ := json.Marshal(config)
beego.SetLogger("file", string(b))
}
@ -133,7 +126,7 @@ func RegisterFunction() {
beego.AddFuncMap("cdn", func(p string) string {
cdn := beego.AppConfig.DefaultString("cdn", "")
if strings.HasPrefix(p,"http://") || strings.HasPrefix(p,"https://") {
if strings.HasPrefix(p, "http://") || strings.HasPrefix(p, "https://") {
return p
}
if strings.HasPrefix(p, "/") && strings.HasSuffix(cdn, "/") {
@ -147,7 +140,7 @@ func RegisterFunction() {
beego.AddFuncMap("cdnjs", func(p string) string {
cdn := beego.AppConfig.DefaultString("cdnjs", "")
if strings.HasPrefix(p,"http://") || strings.HasPrefix(p,"https://") {
if strings.HasPrefix(p, "http://") || strings.HasPrefix(p, "https://") {
return p
}
if strings.HasPrefix(p, "/") && strings.HasSuffix(cdn, "/") {
@ -160,7 +153,7 @@ func RegisterFunction() {
})
beego.AddFuncMap("cdncss", func(p string) string {
cdn := beego.AppConfig.DefaultString("cdncss", "")
if strings.HasPrefix(p,"http://") || strings.HasPrefix(p,"https://") {
if strings.HasPrefix(p, "http://") || strings.HasPrefix(p, "https://") {
return p
}
if strings.HasPrefix(p, "/") && strings.HasSuffix(cdn, "/") {
@ -172,7 +165,7 @@ func RegisterFunction() {
return cdn + p
})
beego.AddFuncMap("cdnimg", func(p string) string {
if strings.HasPrefix(p,"http://") || strings.HasPrefix(p,"https://") {
if strings.HasPrefix(p, "http://") || strings.HasPrefix(p, "https://") {
return p
}
cdn := beego.AppConfig.DefaultString("cdnimg", "")
@ -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)
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)
if p, err := filepath.Abs(os.Args[0]); err == nil {
conf.WorkingDirectory = filepath.Dir(p)
}
}

View File

@ -19,10 +19,10 @@ type Daemon struct {
func NewDaemon() *Daemon {
config := &service.Config{
Name: "mindocd", //服务显示名称
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{ }
migrationList = &migrationCache{}
)
type MigrationDatabase interface {
//获取当前的版本
Version() int64
@ -58,7 +57,7 @@ func RunMigration() {
if len(os.Args) >= 2 && os.Args[1] == "migrate" {
migrate,err := models.NewMigration().FindFirst()
migrate, err := models.NewMigration().FindFirst()
if err != nil {
//log.Fatalf("migrations table %s", err)
@ -66,10 +65,10 @@ func RunMigration() {
}
fmt.Println("Start migration databae... ")
for el := migrationList.items.Front(); el != nil ; el = el.Next() {
for el := migrationList.items.Front(); el != nil; el = el.Next() {
//如果存在比当前版本大的版本,则依次升级
if item,ok := el.Value.(MigrationDatabase); ok && item.Version() > migrate.Version {
if item, ok := el.Value.(MigrationDatabase); ok && item.Version() > migrate.Version {
err := item.ValidUpdate(migrate.Version)
if err != nil {
log.Fatal(err)
@ -112,51 +111,53 @@ func RunMigration() {
}
//导出数据库的表结构
func ExportDatabaseTable() ([]string,error) {
func ExportDatabaseTable() ([]string, error) {
db_adapter := beego.AppConfig.String("db_adapter")
db_database := beego.AppConfig.String("db_database")
tables := make([]string,0)
tables := make([]string, 0)
o := orm.NewOrm()
switch db_adapter {
case "mysql":{
var lists []orm.Params
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)
if err != nil {
return tables,err
}
for _,table := range lists {
var results []orm.Params
_,err = o.Raw(fmt.Sprintf("show create table %s",table["TABLE_NAME"])).Values(&results)
_, err := o.Raw(fmt.Sprintf("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '%s'", db_database)).Values(&lists)
if err != nil {
return tables,err
return tables, err
}
tables = append(tables,results[0]["Create Table"].(string))
}
break;
}
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 {
return tables,err
}
for _,item := range results {
if sql,ok := item["sql"]; ok {
tables = append(tables,sql.(string))
for _, table := range lists {
var results []orm.Params
_, err = o.Raw(fmt.Sprintf("show create table %s", table["TABLE_NAME"])).Values(&results)
if err != nil {
return tables, err
}
tables = append(tables, results[0]["Create Table"].(string))
}
break
}
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 {
return tables, err
}
for _, item := range results {
if sql, ok := item["sql"]; ok {
tables = append(tables, sql.(string))
}
}
break
}
break
}
}
return tables,nil
return tables, nil
}
func RegisterMigration() {
func RegisterMigration() {
migrationList.items = list.New()
migrationList.items.PushBack(NewMigrationVersion03())
}
migrationList.items.PushBack(NewMigrationVersion03())
}

View File

@ -2,21 +2,20 @@ 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
tables []string
}
func NewMigrationVersion03() *MigrationVersion03 {
return &MigrationVersion03{ isValid: false, tables: make([]string,0)}
return &MigrationVersion03{isValid: false, tables: make([]string, 0)}
}
func (m *MigrationVersion03) Version() int64 {
@ -37,8 +36,7 @@ func (m *MigrationVersion03) ValidForBackupTableSchema() error {
return errors.New("The current version failed to verify.")
}
var err error
m.tables,err = ExportDatabaseTable()
m.tables, err = ExportDatabaseTable()
return err
}
@ -72,11 +70,11 @@ func (m *MigrationVersion03) MigrationNewTableData() error {
}
o := orm.NewOrm()
_,err := o.Raw("UPDATE md_members SET auth_method = 'local'").Exec()
_, err := o.Raw("UPDATE md_members SET auth_method = 'local'").Exec()
if err != nil {
return err
}
_,err = o.Raw("INSERT INTO md_options (option_title, option_name, option_value) SELECT '是否启用文档历史','ENABLE_DOCUMENT_HISTORY','true' WHERE NOT exists(SELECT * FROM md_options WHERE option_name = 'ENABLE_DOCUMENT_HISTORY');").Exec()
_, err = o.Raw("INSERT INTO md_options (option_title, option_name, option_value) SELECT '是否启用文档历史','ENABLE_DOCUMENT_HISTORY','true' WHERE NOT exists(SELECT * FROM md_options WHERE option_name = 'ENABLE_DOCUMENT_HISTORY');").Exec()
if err != nil {
return err
}
@ -85,24 +83,24 @@ func (m *MigrationVersion03) MigrationNewTableData() error {
func (m *MigrationVersion03) AddMigrationRecord(version int64) error {
o := orm.NewOrm()
tables,err := ExportDatabaseTable()
tables, err := ExportDatabaseTable()
if err != nil {
return err
return err
}
migration := models.NewMigration()
migration.Version = version
migration.Status = "update"
migration.CreateTime = time.Now()
migration.Name = fmt.Sprintf("update_%d",version)
migration.Statements = strings.Join(tables,"\r\n")
migration.Name = fmt.Sprintf("update_%d", version)
migration.Statements = strings.Join(tables, "\r\n")
_, err = o.Insert(migration)
return err
}
func (m *MigrationVersion03) MigrationCleanup() error {
func (m *MigrationVersion03) MigrationCleanup() error {
return nil
}
@ -112,16 +110,16 @@ func (m *MigrationVersion03) RollbackMigration() error {
return errors.New("The current version failed to verify.")
}
o := orm.NewOrm()
_,err := o.Raw("ALTER TABLE md_members DROP COLUMN auth_method").Exec()
_, err := o.Raw("ALTER TABLE md_members DROP COLUMN auth_method").Exec()
if err != nil {
return err
}
_,err = o.Raw("DROP TABLE md_document_history").Exec()
_, err = o.Raw("DROP TABLE md_document_history").Exec()
if err != nil {
return err
}
_,err = o.Raw("DELETE md_options WHERE option_name = 'ENABLE_DOCUMENT_HISTORY'").Exec()
_, err = o.Raw("DELETE md_options WHERE option_name = 'ENABLE_DOCUMENT_HISTORY'").Exec()
if err != nil {
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 (
@ -44,23 +44,31 @@ const (
)
const (
LoggerOperate = "operate"
LoggerSystem = "system"
LoggerOperate = "operate"
LoggerSystem = "system"
LoggerException = "exception"
LoggerDocument = "document"
LoggerDocument = "document"
)
const (
//本地账户校验
AuthMethodLocal = "local"
//LDAP用户校验
AuthMethodLDAP = "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,29 +110,30 @@ func GetUploadFileExt() []string {
}
return exts
}
// 获取上传文件允许的最大值
func GetUploadFileSize() int64 {
size := beego.AppConfig.DefaultString("upload_file_size","0")
size := beego.AppConfig.DefaultString("upload_file_size", "0")
if strings.HasSuffix(size,"MB") {
if s,e := strconv.ParseInt(size[0:len(size) - 2], 10, 64);e == nil {
if strings.HasSuffix(size, "MB") {
if s, e := strconv.ParseInt(size[0:len(size)-2], 10, 64); e == nil {
return s * 1024 * 1024
}
}
if strings.HasSuffix(size,"GB") {
if s,e := strconv.ParseInt(size[0:len(size) - 2], 10, 64);e == nil {
if strings.HasSuffix(size, "GB") {
if s, e := strconv.ParseInt(size[0:len(size)-2], 10, 64); e == nil {
return s * 1024 * 1024 * 1024
}
}
if strings.HasSuffix(size,"KB") {
if s,e := strconv.ParseInt(size[0:len(size) - 2], 10, 64);e == nil {
if strings.HasSuffix(size, "KB") {
if s, e := strconv.ParseInt(size[0:len(size)-2], 10, 64); e == nil {
return s * 1024
}
}
if s,e := strconv.ParseInt(size, 10, 64);e == nil {
if s, e := strconv.ParseInt(size, 10, 64); e == nil {
return s * 1024
}
return 0
return 0
}
//判断是否是允许商城的文件类型.

View File

@ -6,33 +6,33 @@ import (
)
type SmtpConf struct {
EnableMail bool
MailNumber int
EnableMail bool
MailNumber int
SmtpUserName string
SmtpHost string
SmtpHost string
SmtpPassword string
SmtpPort int
SmtpPort int
FormUserName string
MailExpired int
MailExpired int
}
func GetMailConfig() *SmtpConf {
user_name := beego.AppConfig.String("smtp_user_name")
password := beego.AppConfig.String("smtp_password")
smtp_host := beego.AppConfig.String("smtp_host")
smtp_port := beego.AppConfig.DefaultInt("smtp_port",25)
smtp_port := beego.AppConfig.DefaultInt("smtp_port", 25)
form_user_name := beego.AppConfig.String("form_user_name")
enable_mail := beego.AppConfig.String("enable_mail")
mail_number := beego.AppConfig.DefaultInt("mail_number",5)
mail_number := beego.AppConfig.DefaultInt("mail_number", 5)
c := &SmtpConf{
EnableMail : strings.EqualFold(enable_mail,"true"),
MailNumber: mail_number,
SmtpUserName:user_name,
SmtpHost:smtp_host,
SmtpPassword:password,
FormUserName:form_user_name,
SmtpPort:smtp_port,
EnableMail: strings.EqualFold(enable_mail, "true"),
MailNumber: mail_number,
SmtpUserName: user_name,
SmtpHost: smtp_host,
SmtpPassword: password,
FormUserName: form_user_name,
SmtpPort: smtp_port,
}
return c
}
}

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,14 +33,17 @@ 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 {
if err := utils.Decode(cookie, &remember); err == nil {
@ -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,53 +1,52 @@
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
Option map[string]string
EnableAnonymous bool
Member *models.Member
Option map[string]string
EnableAnonymous bool
EnableDocumentHistory bool
}
// Prepare 预处理.
func (c *BaseController) Prepare (){
func (c *BaseController) Prepare() {
c.Data["SiteName"] = "MinDoc"
c.Data["Member"] = models.Member{}
c.EnableAnonymous = false
c.EnableDocumentHistory = false
if member,ok := c.GetSession(conf.LoginSessionName).(models.Member); ok && member.MemberId > 0{
if member, ok := c.GetSession(conf.LoginSessionName).(models.Member); ok && member.MemberId > 0 {
c.Member = &member
c.Data["Member"] = c.Member
}else{
} else {
//c.Member = models.NewMember()
//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))
for _,item := range options {
if options, err := models.NewOption().All(); err == nil {
c.Option = make(map[string]string, len(options))
for _, item := range options {
c.Data[item.OptionName] = item.OptionValue
c.Option[item.OptionName] = item.OptionValue
if strings.EqualFold(item.OptionName,"ENABLE_ANONYMOUS") && item.OptionValue == "true" {
if strings.EqualFold(item.OptionName, "ENABLE_ANONYMOUS") && item.OptionValue == "true" {
c.EnableAnonymous = true
}
if strings.EqualFold(item.OptionName,"ENABLE_DOCUMENT_HISTORY") && item.OptionValue == "true" {
if strings.EqualFold(item.OptionName, "ENABLE_DOCUMENT_HISTORY") && item.OptionValue == "true" {
c.EnableDocumentHistory = true
}
}
@ -68,13 +67,13 @@ func (c *BaseController) SetMember(member models.Member) {
}
// JsonResult 响应 json 结果
func (c *BaseController) JsonResult(errCode int,errMsg string,data ...interface{}){
jsonData := make(map[string]interface{},3)
func (c *BaseController) JsonResult(errCode int, errMsg string, data ...interface{}) {
jsonData := make(map[string]interface{}, 3)
jsonData["errcode"] = errCode
jsonData["message"] = errMsg
if len(data) > 0 && data[0] != nil{
if len(data) > 0 && data[0] != nil {
jsonData["data"] = data[0]
}
@ -86,13 +85,13 @@ func (c *BaseController) JsonResult(errCode int,errMsg string,data ...interface{
c.Ctx.ResponseWriter.Header().Set("Content-Type", "application/json; charset=utf-8")
io.WriteString(c.Ctx.ResponseWriter,string(returnJSON))
io.WriteString(c.Ctx.ResponseWriter, string(returnJSON))
c.StopRun()
}
// ExecuteViewPathTemplate 执行指定的模板并返回执行结果.
func (c *BaseController) ExecuteViewPathTemplate(tplName string,data interface{}) (string,error){
func (c *BaseController) ExecuteViewPathTemplate(tplName string, data interface{}) (string, error) {
var buf bytes.Buffer
viewPath := c.ViewPath
@ -102,28 +101,28 @@ func (c *BaseController) ExecuteViewPathTemplate(tplName string,data interface{}
}
if err := beego.ExecuteViewPathTemplate(&buf,tplName,viewPath,data); err != nil {
return "",err
if err := beego.ExecuteViewPathTemplate(&buf, tplName, viewPath, data); err != nil {
return "", err
}
return buf.String(),nil
return buf.String(), nil
}
func (c *BaseController) BaseUrl() string {
baseUrl := beego.AppConfig.DefaultString("baseurl","")
baseUrl := beego.AppConfig.DefaultString("baseurl", "")
if baseUrl != "" {
if strings.HasSuffix(baseUrl,"/"){
baseUrl = strings.TrimSuffix(baseUrl,"/")
if strings.HasSuffix(baseUrl, "/") {
baseUrl = strings.TrimSuffix(baseUrl, "/")
}
}else{
} else {
baseUrl = c.Ctx.Input.Scheme() + "://" + c.Ctx.Request.Host
}
return baseUrl
}
//显示错误信息页面.
func (c *BaseController) ShowErrorPage(errCode int,errMsg string) {
func (c *BaseController) ShowErrorPage(errCode int, errMsg string) {
c.TplName = "errors/error.tpl"
c.Data["ErrorMessage"] = errMsg
c.Data["ErrorCode"] = errCode
c.StopRun()
}
}

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 {
@ -32,10 +31,10 @@ func (c *BookController) Index() {
pageIndex, _ := c.GetInt("page", 1)
books,totalCount,err := models.NewBook().FindToPager(pageIndex,conf.PageSize,c.Member.MemberId)
books, totalCount, err := models.NewBook().FindToPager(pageIndex, conf.PageSize, c.Member.MemberId)
if err != nil {
logs.Error("BookController.Index => ",err)
logs.Error("BookController.Index => ", err)
c.Abort("500")
}
@ -43,14 +42,14 @@ func (c *BookController) Index() {
html := utils.GetPagerHtml(c.Ctx.Request.RequestURI, pageIndex, conf.PageSize, totalCount)
c.Data["PageHtml"] = html
}else {
} else {
c.Data["PageHtml"] = ""
}
b,err := json.Marshal(books)
b, err := json.Marshal(books)
if err != nil || len(books) <= 0{
if err != nil || len(books) <= 0 {
c.Data["Result"] = template.JS("[]")
}else{
} else {
c.Data["Result"] = template.JS(string(b))
}
}
@ -62,11 +61,11 @@ func (c *BookController) Dashboard() {
key := c.Ctx.Input.Param(":key")
if key == ""{
if key == "" {
c.Abort("404")
}
book,err := models.NewBookResult().FindByIdentify(key,c.Member.MemberId)
book, err := models.NewBookResult().FindByIdentify(key, c.Member.MemberId)
if err != nil {
if err == models.ErrPermissionDenied {
c.Abort("403")
@ -79,17 +78,17 @@ func (c *BookController) Dashboard() {
}
// Setting 项目设置 .
func (c *BookController) Setting() {
func (c *BookController) Setting() {
c.Prepare()
c.TplName = "book/setting.tpl"
key := c.Ctx.Input.Param(":key")
if key == ""{
if key == "" {
c.Abort("404")
}
book,err := models.NewBookResult().FindByIdentify(key,c.Member.MemberId)
book, err := models.NewBookResult().FindByIdentify(key, c.Member.MemberId)
if err != nil {
if err == orm.ErrNoRows {
c.Abort("404")
@ -104,225 +103,224 @@ func (c *BookController) Setting() {
c.Abort("403")
}
if book.PrivateToken != "" {
book.PrivateToken = c.BaseUrl() + beego.URLFor("DocumentController.Index",":key",book.Identify,"token",book.PrivateToken)
book.PrivateToken = c.BaseUrl() + beego.URLFor("DocumentController.Index", ":key", book.Identify, "token", book.PrivateToken)
}
c.Data["Model"] = book
}
//保存项目信息
func (c *BookController) SaveBook() {
bookResult,err := c.IsPermission()
func (c *BookController) SaveBook() {
bookResult, err := c.IsPermission()
if err != nil {
c.JsonResult(6001,err.Error())
c.JsonResult(6001, err.Error())
}
book,err := models.NewBook().Find(bookResult.BookId)
book, err := models.NewBook().Find(bookResult.BookId)
if err != nil {
logs.Error("SaveBook => ",err)
c.JsonResult(6002,err.Error())
logs.Error("SaveBook => ", err)
c.JsonResult(6002, err.Error())
}
book_name := strings.TrimSpace(c.GetString("book_name"))
description := strings.TrimSpace(c.GetString("description",""))
description := strings.TrimSpace(c.GetString("description", ""))
comment_status := c.GetString("comment_status")
tag := strings.TrimSpace(c.GetString("label"))
editor := strings.TrimSpace(c.GetString("editor"))
auto_release := strings.TrimSpace(c.GetString("auto_release")) == "on"
if strings.Count(description,"") > 500 {
c.JsonResult(6004,"项目描述不能大于500字")
if strings.Count(description, "") > 500 {
c.JsonResult(6004, "项目描述不能大于500字")
}
if comment_status != "open" && comment_status != "closed" && comment_status != "group_only" && comment_status != "registered_only" {
comment_status = "closed"
}
if tag != ""{
tags := strings.Split(tag,",")
if tag != "" {
tags := strings.Split(tag, ",")
if len(tags) > 10 {
c.JsonResult(6005,"最多允许添加10个标签")
c.JsonResult(6005, "最多允许添加10个标签")
}
}
if editor != "markdown" && editor != "html" {
editor = "markdown"
}
book.BookName = book_name
book.Description = description
book.CommentStatus = comment_status
book.Label = tag
book.Editor = editor
book.BookName = book_name
book.Description = description
book.CommentStatus = comment_status
book.Label = tag
book.Editor = editor
if auto_release {
book.AutoRelease = 1
}else{
} else {
book.AutoRelease = 0
}
if err := book.Update();err != nil {
c.JsonResult(6006,"保存失败")
if err := book.Update(); err != nil {
c.JsonResult(6006, "保存失败")
}
bookResult.BookName = book_name
bookResult.Description = description
bookResult.CommentStatus = comment_status
bookResult.Label = tag
c.JsonResult(0,"ok",bookResult)
c.JsonResult(0, "ok", bookResult)
}
//设置项目私有状态.
func (c *BookController) PrivatelyOwned() {
func (c *BookController) PrivatelyOwned() {
status := c.GetString("status")
if status != "open" && status != "close" {
c.JsonResult(6003,"参数错误")
c.JsonResult(6003, "参数错误")
}
state := 0
if status == "open" {
state = 0
}else{
} else {
state = 1
}
bookResult,err := c.IsPermission()
bookResult, err := c.IsPermission()
if err != nil {
c.JsonResult(6001,err.Error())
c.JsonResult(6001, err.Error())
}
//只有创始人才能变更私有状态
if bookResult.RoleId != conf.BookFounder {
c.JsonResult(6002,"权限不足")
c.JsonResult(6002, "权限不足")
}
book,err := models.NewBook().Find(bookResult.BookId)
book, err := models.NewBook().Find(bookResult.BookId)
if err != nil {
c.JsonResult(6005,"项目不存在")
c.JsonResult(6005, "项目不存在")
}
book.PrivatelyOwned = state
err = book.Update()
if err != nil {
logs.Error("PrivatelyOwned => ",err)
c.JsonResult(6004,"保存失败")
logs.Error("PrivatelyOwned => ", err)
c.JsonResult(6004, "保存失败")
}
c.JsonResult(0,"ok")
c.JsonResult(0, "ok")
}
// Transfer 转让项目.
func (c *BookController) Transfer() {
func (c *BookController) Transfer() {
c.Prepare()
account := c.GetString("account")
if account == "" {
c.JsonResult(6004,"接受者账号不能为空")
c.JsonResult(6004, "接受者账号不能为空")
}
member,err := models.NewMember().FindByAccount(account)
member, err := models.NewMember().FindByAccount(account)
if err != nil {
logs.Error("FindByAccount => ",err)
c.JsonResult(6005,"接受用户不存在")
logs.Error("FindByAccount => ", err)
c.JsonResult(6005, "接受用户不存在")
}
if member.Status != 0 {
c.JsonResult(6006,"接受用户已被禁用")
c.JsonResult(6006, "接受用户已被禁用")
}
if member.MemberId == c.Member.MemberId {
c.JsonResult(6007,"不能转让给自己")
c.JsonResult(6007, "不能转让给自己")
}
bookResult,err := c.IsPermission()
bookResult, err := c.IsPermission()
if err != nil {
c.JsonResult(6001,err.Error())
c.JsonResult(6001, err.Error())
}
err = models.NewRelationship().Transfer(bookResult.BookId,c.Member.MemberId,member.MemberId)
err = models.NewRelationship().Transfer(bookResult.BookId, c.Member.MemberId, member.MemberId)
if err != nil {
logs.Error("Transfer => ",err)
c.JsonResult(6008,err.Error())
logs.Error("Transfer => ", err)
c.JsonResult(6008, err.Error())
}
c.JsonResult(0,"ok")
c.JsonResult(0, "ok")
}
//上传项目封面.
func (c *BookController) UploadCover() {
func (c *BookController) UploadCover() {
bookResult,err := c.IsPermission()
bookResult, err := c.IsPermission()
if err != nil {
c.JsonResult(6001,err.Error())
c.JsonResult(6001, err.Error())
}
book,err := models.NewBook().Find(bookResult.BookId)
book, err := models.NewBook().Find(bookResult.BookId)
if err != nil {
logs.Error("SaveBook => ",err)
c.JsonResult(6002,err.Error())
logs.Error("SaveBook => ", err)
c.JsonResult(6002, err.Error())
}
file,moreFile,err := c.GetFile("image-file")
file, moreFile, err := c.GetFile("image-file")
defer file.Close()
if err != nil {
logs.Error("",err.Error())
c.JsonResult(500,"读取文件异常")
logs.Error("", err.Error())
c.JsonResult(500, "读取文件异常")
}
ext := filepath.Ext(moreFile.Filename)
if !strings.EqualFold(ext,".png") && !strings.EqualFold(ext,".jpg") && !strings.EqualFold(ext,".gif") && !strings.EqualFold(ext,".jpeg") {
c.JsonResult(500,"不支持的图片格式")
if !strings.EqualFold(ext, ".png") && !strings.EqualFold(ext, ".jpg") && !strings.EqualFold(ext, ".gif") && !strings.EqualFold(ext, ".jpeg") {
c.JsonResult(500, "不支持的图片格式")
}
x1 ,_ := strconv.ParseFloat(c.GetString("x"),10)
y1 ,_ := strconv.ParseFloat(c.GetString("y"),10)
w1 ,_ := strconv.ParseFloat(c.GetString("width"),10)
h1 ,_ := strconv.ParseFloat(c.GetString("height"),10)
x1, _ := strconv.ParseFloat(c.GetString("x"), 10)
y1, _ := strconv.ParseFloat(c.GetString("y"), 10)
w1, _ := strconv.ParseFloat(c.GetString("width"), 10)
h1, _ := strconv.ParseFloat(c.GetString("height"), 10)
x := int(x1)
y := int(y1)
width := int(w1)
height := int(h1)
fileName := "cover_" + strconv.FormatInt(time.Now().UnixNano(), 16)
fileName := "cover_" + strconv.FormatInt(time.Now().UnixNano(), 16)
filePath := filepath.Join("uploads",time.Now().Format("200601"),fileName + ext)
filePath := filepath.Join("uploads", time.Now().Format("200601"), fileName+ext)
path := filepath.Dir(filePath)
os.MkdirAll(path, os.ModePerm)
err = c.SaveToFile("image-file",filePath)
err = c.SaveToFile("image-file", filePath)
if err != nil {
logs.Error("",err)
c.JsonResult(500,"图片保存失败")
logs.Error("", err)
c.JsonResult(500, "图片保存失败")
}
defer func(filePath string) {
os.Remove(filePath)
}(filePath)
//剪切图片
subImg,err := graphics.ImageCopyFromFile(filePath,x,y,width,height)
if err != nil{
logs.Error("graphics.ImageCopyFromFile => ",err)
c.JsonResult(500,"图片剪切")
}
filePath = filepath.Join(commands.WorkingDirectory,"uploads",time.Now().Format("200601"),fileName + "_small" + ext)
//生成缩略图并保存到磁盘
err = graphics.ImageResizeSaveFile(subImg,175,230,filePath)
subImg, err := graphics.ImageCopyFromFile(filePath, x, y, width, height)
if err != nil {
logs.Error("ImageResizeSaveFile => ",err.Error())
c.JsonResult(500,"保存图片失败")
logs.Error("graphics.ImageCopyFromFile => ", err)
c.JsonResult(500, "图片剪切")
}
url := "/" + strings.Replace(strings.TrimPrefix(filePath,commands.WorkingDirectory),"\\","/",-1)
filePath = filepath.Join(conf.WorkingDirectory, "uploads", time.Now().Format("200601"), fileName+"_small"+ext)
if strings.HasPrefix(url,"//") {
//生成缩略图并保存到磁盘
err = graphics.ImageResizeSaveFile(subImg, 175, 230, filePath)
if err != nil {
logs.Error("ImageResizeSaveFile => ", err.Error())
c.JsonResult(500, "保存图片失败")
}
url := "/" + strings.Replace(strings.TrimPrefix(filePath, conf.WorkingDirectory), "\\", "/", -1)
if strings.HasPrefix(url, "//") {
url = string(url[1:])
}
@ -330,15 +328,15 @@ func (c *BookController) UploadCover() {
book.Cover = url
if err := book.Update() ; err != nil {
c.JsonResult(6001,"保存图片失败")
if err := book.Update(); err != nil {
c.JsonResult(6001, "保存图片失败")
}
//如果原封面不是默认封面则删除
if old_cover != conf.GetDefaultCover() {
os.Remove("." + old_cover)
}
c.JsonResult(0,"ok",url)
c.JsonResult(0, "ok", url)
}
// Users 用户列表.
@ -347,13 +345,13 @@ func (c *BookController) Users() {
c.TplName = "book/users.tpl"
key := c.Ctx.Input.Param(":key")
pageIndex,_ := c.GetInt("page",1)
pageIndex, _ := c.GetInt("page", 1)
if key == ""{
if key == "" {
c.Abort("404")
}
book,err := models.NewBookResult().FindByIdentify(key,c.Member.MemberId)
book, err := models.NewBookResult().FindByIdentify(key, c.Member.MemberId)
if err != nil {
if err == models.ErrPermissionDenied {
c.Abort("403")
@ -363,20 +361,20 @@ func (c *BookController) Users() {
c.Data["Model"] = *book
members,totalCount,err := models.NewMemberRelationshipResult().FindForUsersByBookId(book.BookId,pageIndex,15)
members, totalCount, err := models.NewMemberRelationshipResult().FindForUsersByBookId(book.BookId, pageIndex, 15)
if totalCount > 0 {
html := utils.GetPagerHtml(c.Ctx.Request.RequestURI, pageIndex, 10, totalCount)
c.Data["PageHtml"] = html
}else{
} else {
c.Data["PageHtml"] = ""
}
b,err := json.Marshal(members)
b, err := json.Marshal(members)
if err != nil {
c.Data["Result"] = template.JS("[]")
}else{
} else {
c.Data["Result"] = template.JS(string(b))
}
}
@ -385,28 +383,28 @@ func (c *BookController) Users() {
func (c *BookController) Create() {
if c.Ctx.Input.IsPost() {
book_name := strings.TrimSpace(c.GetString("book_name",""))
identify := strings.TrimSpace(c.GetString("identify",""))
description := strings.TrimSpace(c.GetString("description",""))
privately_owned,_ := strconv.Atoi(c.GetString("privately_owned"))
book_name := strings.TrimSpace(c.GetString("book_name", ""))
identify := strings.TrimSpace(c.GetString("identify", ""))
description := strings.TrimSpace(c.GetString("description", ""))
privately_owned, _ := strconv.Atoi(c.GetString("privately_owned"))
comment_status := c.GetString("comment_status")
if book_name == "" {
c.JsonResult(6001,"项目名称不能为空")
c.JsonResult(6001, "项目名称不能为空")
}
if identify == "" {
c.JsonResult(6002,"项目标识不能为空")
c.JsonResult(6002, "项目标识不能为空")
}
if ok,err := regexp.MatchString(`^[a-z]+[a-zA-Z0-9_\-]*$`,identify); !ok || err != nil {
c.JsonResult(6003,"项目标识只能包含小写字母、数字,以及“-”和“_”符号,并且只能小写字母开头")
if ok, err := regexp.MatchString(`^[a-z]+[a-zA-Z0-9_\-]*$`, identify); !ok || err != nil {
c.JsonResult(6003, "项目标识只能包含小写字母、数字,以及“-”和“_”符号,并且只能小写字母开头")
}
if strings.Count(identify,"") > 50 {
c.JsonResult(6004,"文档标识不能超过50字")
if strings.Count(identify, "") > 50 {
c.JsonResult(6004, "文档标识不能超过50字")
}
if strings.Count(description,"") > 500 {
c.JsonResult(6004,"项目描述不能大于500字")
if strings.Count(description, "") > 500 {
c.JsonResult(6004, "项目描述不能大于500字")
}
if privately_owned !=0 && privately_owned != 1 {
if privately_owned != 0 && privately_owned != 1 {
privately_owned = 1
}
if comment_status != "open" && comment_status != "closed" && comment_status != "group_only" && comment_status != "registered_only" {
@ -415,39 +413,39 @@ func (c *BookController) Create() {
book := models.NewBook()
if books,_ := book.FindByField("identify",identify); len(books) > 0 {
c.JsonResult(6006,"项目标识已存在")
if books, _ := book.FindByField("identify", identify); len(books) > 0 {
c.JsonResult(6006, "项目标识已存在")
}
book.BookName = book_name
book.BookName = book_name
book.Description = description
book.CommentCount = 0
book.PrivatelyOwned = privately_owned
book.CommentStatus = comment_status
book.Identify = identify
book.DocCount = 0
book.MemberId = c.Member.MemberId
book.Identify = identify
book.DocCount = 0
book.MemberId = c.Member.MemberId
book.CommentCount = 0
book.Version = time.Now().Unix()
book.Cover = conf.GetDefaultCover()
book.Editor = "markdown"
book.Theme = "default"
book.Version = time.Now().Unix()
book.Cover = conf.GetDefaultCover()
book.Editor = "markdown"
book.Theme = "default"
err := book.Insert()
if err != nil {
logs.Error("Insert => ",err)
c.JsonResult(6005,"保存项目失败")
logs.Error("Insert => ", err)
c.JsonResult(6005, "保存项目失败")
}
bookResult,err := models.NewBookResult().FindByIdentify(book.Identify,c.Member.MemberId)
bookResult, err := models.NewBookResult().FindByIdentify(book.Identify, c.Member.MemberId)
if err != nil {
beego.Error(err)
}
c.JsonResult(0,"ok",bookResult)
c.JsonResult(0, "ok", bookResult)
}
c.JsonResult(6001,"error")
c.JsonResult(6001, "error")
}
// CreateToken 创建访问来令牌.
@ -455,22 +453,22 @@ func (c *BookController) CreateToken() {
action := c.GetString("action")
bookResult ,err := c.IsPermission()
bookResult, err := c.IsPermission()
if err != nil {
if err == models.ErrPermissionDenied {
c.JsonResult(403,"权限不足")
c.JsonResult(403, "权限不足")
}
if err == orm.ErrNoRows {
c.JsonResult(404,"项目不存在")
c.JsonResult(404, "项目不存在")
}
logs.Error("生成阅读令牌失败 =>",err)
c.JsonResult(6002,err.Error())
logs.Error("生成阅读令牌失败 =>", err)
c.JsonResult(6002, err.Error())
}
book := models.NewBook()
if _,err := book.Find(bookResult.BookId);err != nil {
c.JsonResult(6001,"项目不存在")
if _, err := book.Find(bookResult.BookId); err != nil {
c.JsonResult(6001, "项目不存在")
}
if action == "create" {
if bookResult.PrivatelyOwned == 0 {
@ -482,14 +480,14 @@ func (c *BookController) CreateToken() {
logs.Error("生成阅读令牌失败 => ", err)
c.JsonResult(6003, "生成阅读令牌失败")
}
c.JsonResult(0, "ok", c.BaseUrl() + beego.URLFor("DocumentController.Index",":key",book.Identify,"token",book.PrivateToken))
}else{
c.JsonResult(0, "ok", c.BaseUrl()+beego.URLFor("DocumentController.Index", ":key", book.Identify, "token", book.PrivateToken))
} else {
book.PrivateToken = ""
if err := book.Update();err != nil {
logs.Error("CreateToken => ",err)
c.JsonResult(6004,"删除令牌失败")
if err := book.Update(); err != nil {
logs.Error("CreateToken => ", err)
c.JsonResult(6004, "删除令牌失败")
}
c.JsonResult(0,"ok","")
c.JsonResult(0, "ok", "")
}
}
@ -497,25 +495,25 @@ func (c *BookController) CreateToken() {
func (c *BookController) Delete() {
c.Prepare()
bookResult ,err := c.IsPermission()
bookResult, err := c.IsPermission()
if err != nil {
c.JsonResult(6001,err.Error())
c.JsonResult(6001, err.Error())
}
if bookResult.RoleId != conf.BookFounder {
c.JsonResult(6002,"只有创始人才能删除项目")
c.JsonResult(6002, "只有创始人才能删除项目")
}
err = models.NewBook().ThoroughDeleteBook(bookResult.BookId)
if err == orm.ErrNoRows {
c.JsonResult(6002,"项目不存在")
c.JsonResult(6002, "项目不存在")
}
if err != nil {
logs.Error("删除项目 => ",err)
c.JsonResult(6003,"删除失败")
logs.Error("删除项目 => ", err)
c.JsonResult(6003, "删除失败")
}
c.JsonResult(0,"ok")
c.JsonResult(0, "ok")
}
//发布项目.
@ -524,15 +522,15 @@ func (c *BookController) Release() {
identify := c.GetString("identify")
book_id := 0
bookId := 0
if c.Member.IsAdministrator() {
book,err := models.NewBook().FindByFieldFirst("identify",identify)
book, err := models.NewBook().FindByFieldFirst("identify", identify)
if err != nil {
}
book_id = book.BookId
}else {
bookId = book.BookId
} else {
book, err := models.NewBookResult().FindByIdentify(identify, c.Member.MemberId)
if err != nil {
@ -548,15 +546,18 @@ 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)
c.JsonResult(0,"发布任务已推送到任务队列,稍后将在后台执行。")
c.JsonResult(0, "发布任务已推送到任务队列,稍后将在后台执行。")
}
//文档排序.
@ -570,94 +571,91 @@ func (c *BookController) SaveSort() {
book_id := 0
if c.Member.IsAdministrator() {
book,err := models.NewBook().FindByFieldFirst("identify",identify)
book, err := models.NewBook().FindByFieldFirst("identify", identify)
if err != nil {
}
book_id = book.BookId
}else{
bookResult,err := models.NewBookResult().FindByIdentify(identify,c.Member.MemberId)
} else {
bookResult, err := models.NewBookResult().FindByIdentify(identify, c.Member.MemberId)
if err != nil {
beego.Error("DocumentController.Edit => ",err)
beego.Error("DocumentController.Edit => ", err)
c.Abort("403")
}
if bookResult.RoleId == conf.BookObserver {
c.JsonResult(6002,"项目不存在或权限不足")
c.JsonResult(6002, "项目不存在或权限不足")
}
book_id = bookResult.BookId
}
content := c.Ctx.Input.RequestBody
var docs []map[string]interface{}
err := json.Unmarshal(content,&docs)
err := json.Unmarshal(content, &docs)
if err != nil {
beego.Error(err)
c.JsonResult(6003,"数据错误")
c.JsonResult(6003, "数据错误")
}
for _,item := range docs {
if doc_id,ok := item["id"].(float64);ok {
doc,err := models.NewDocument().Find(int(doc_id));
for _, item := range docs {
if doc_id, ok := item["id"].(float64); ok {
doc, err := models.NewDocument().Find(int(doc_id))
if err != nil {
beego.Error(err)
continue;
}
if doc.BookId != book_id {
logs.Info("%s","权限错误")
continue;
}
sort,ok := item["sort"].(float64);
if !ok {
beego.Info("排序数字转换失败 => ",item)
continue
}
parent_id,ok := item["parent"].(float64)
if doc.BookId != book_id {
logs.Info("%s", "权限错误")
continue
}
sort, ok := item["sort"].(float64)
if !ok {
beego.Info("父分类转换失败 => ",item)
beego.Info("排序数字转换失败 => ", item)
continue
}
parent_id, ok := item["parent"].(float64)
if !ok {
beego.Info("父分类转换失败 => ", item)
continue
}
if parent_id > 0 {
if parent,err := models.NewDocument().Find(int(parent_id)); err != nil || parent.BookId != book_id {
if parent, err := models.NewDocument().Find(int(parent_id)); err != nil || parent.BookId != book_id {
continue
}
}
doc.OrderSort = int(sort)
doc.ParentId = int(parent_id)
if err := doc.InsertOrUpdate(); err != nil {
fmt.Printf("%s",err.Error())
fmt.Printf("%s", err.Error())
beego.Error(err)
}
}else{
fmt.Printf("文档ID转换失败 => %+v",item)
} else {
fmt.Printf("文档ID转换失败 => %+v", item)
}
}
c.JsonResult(0,"ok")
c.JsonResult(0, "ok")
}
func (c *BookController) IsPermission() (*models.BookResult,error) {
func (c *BookController) IsPermission() (*models.BookResult, error) {
identify := c.GetString("identify")
book ,err := models.NewBookResult().FindByIdentify(identify,c.Member.MemberId)
book, err := models.NewBookResult().FindByIdentify(identify, c.Member.MemberId)
if err != nil {
if err == models.ErrPermissionDenied {
return book,errors.New("权限不足")
return book, errors.New("权限不足")
}
if err == orm.ErrNoRows {
return book,errors.New("项目不存在")
return book, errors.New("项目不存在")
}
return book,err
return book, err
}
if book.RoleId != conf.BookAdmin && book.RoleId != conf.BookFounder {
return book,errors.New("权限不足")
return book, errors.New("权限不足")
}
return book,nil
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 {
@ -14,31 +14,31 @@ type BookMemberController struct {
}
// AddMember 参加参与用户.
func (c *BookMemberController) AddMember() {
func (c *BookMemberController) AddMember() {
identify := c.GetString("identify")
account := c.GetString("account")
role_id,_ := c.GetInt("role_id",3)
role_id, _ := c.GetInt("role_id", 3)
if identify == "" || account == ""{
c.JsonResult(6001,"参数错误")
if identify == "" || account == "" {
c.JsonResult(6001, "参数错误")
}
book ,err := c.IsPermission()
book, err := c.IsPermission()
if err != nil {
c.JsonResult(6001,err.Error())
c.JsonResult(6001, err.Error())
}
member := models.NewMember()
if _,err := member.FindByAccount(account) ; err != nil {
c.JsonResult(404,"用户不存在")
if _, err := member.FindByAccount(account); err != nil {
c.JsonResult(404, "用户不存在")
}
if member.Status == 1 {
c.JsonResult(6003,"用户已被禁用")
c.JsonResult(6003, "用户已被禁用")
}
if _,err := models.NewRelationship().FindForRoleId(book.BookId,member.MemberId);err == nil {
c.JsonResult(6003,"用户已存在该项目中")
if _, err := models.NewRelationship().FindForRoleId(book.BookId, member.MemberId); err == nil {
c.JsonResult(6003, "用户已存在该项目中")
}
relationship := models.NewRelationship()
@ -53,53 +53,52 @@ func (c *BookMemberController) AddMember() {
memberRelationshipResult.BookId = book.BookId
memberRelationshipResult.ResolveRoleName()
c.JsonResult(0,"ok",memberRelationshipResult)
c.JsonResult(0, "ok", memberRelationshipResult)
}
c.JsonResult(500,err.Error())
c.JsonResult(500, err.Error())
}
// 变更指定用户在指定项目中的权限
func (c *BookMemberController) ChangeRole() {
identify := c.GetString("identify")
member_id,_ := c.GetInt("member_id",0)
role,_ := c.GetInt("role_id",0)
member_id, _ := c.GetInt("member_id", 0)
role, _ := c.GetInt("role_id", 0)
if identify == "" || member_id <=0 {
c.JsonResult(6001,"参数错误")
if identify == "" || member_id <= 0 {
c.JsonResult(6001, "参数错误")
}
if member_id == c.Member.MemberId {
c.JsonResult(6006,"不能变更自己的权限")
c.JsonResult(6006, "不能变更自己的权限")
}
book ,err := models.NewBookResult().FindByIdentify(identify,c.Member.MemberId)
book, err := models.NewBookResult().FindByIdentify(identify, c.Member.MemberId)
if err != nil {
if err == models.ErrPermissionDenied {
c.JsonResult(403,"权限不足")
c.JsonResult(403, "权限不足")
}
if err == orm.ErrNoRows {
c.JsonResult(404,"项目不存在")
c.JsonResult(404, "项目不存在")
}
c.JsonResult(6002,err.Error())
c.JsonResult(6002, err.Error())
}
if book.RoleId != 0 && book.RoleId != 1 {
c.JsonResult(403,"权限不足")
c.JsonResult(403, "权限不足")
}
member := models.NewMember()
if _,err := member.Find(member_id); err != nil {
c.JsonResult(6003,"用户不存在")
if _, err := member.Find(member_id); err != nil {
c.JsonResult(6003, "用户不存在")
}
if member.Status == 1 {
c.JsonResult(6004,"用户已被禁用")
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)
c.JsonResult(6005,err.Error())
logs.Error("变更用户在项目中的权限 => ", err)
c.JsonResult(6005, err.Error())
}
memberRelationshipResult := models.NewMemberRelationshipResult().FromMember(member)
@ -108,58 +107,58 @@ func (c *BookMemberController) ChangeRole() {
memberRelationshipResult.BookId = book.BookId
memberRelationshipResult.ResolveRoleName()
c.JsonResult(0,"ok",memberRelationshipResult)
c.JsonResult(0, "ok", memberRelationshipResult)
}
// 删除参与者.
func (c *BookMemberController) RemoveMember() {
func (c *BookMemberController) RemoveMember() {
identify := c.GetString("identify")
member_id,_ := c.GetInt("member_id",0)
member_id, _ := c.GetInt("member_id", 0)
if identify == "" || member_id <=0 {
c.JsonResult(6001,"参数错误")
if identify == "" || member_id <= 0 {
c.JsonResult(6001, "参数错误")
}
if member_id == c.Member.MemberId {
c.JsonResult(6006,"不能删除自己")
c.JsonResult(6006, "不能删除自己")
}
book ,err := models.NewBookResult().FindByIdentify(identify,c.Member.MemberId)
book, err := models.NewBookResult().FindByIdentify(identify, c.Member.MemberId)
if err != nil {
if err == models.ErrPermissionDenied {
c.JsonResult(403,"权限不足")
c.JsonResult(403, "权限不足")
}
if err == orm.ErrNoRows {
c.JsonResult(404,"项目不存在")
c.JsonResult(404, "项目不存在")
}
c.JsonResult(6002,err.Error())
c.JsonResult(6002, err.Error())
}
//如果不是创始人也不是管理员则不能操作
if book.RoleId != conf.BookFounder && book.RoleId != conf.BookAdmin {
c.JsonResult(403,"权限不足")
c.JsonResult(403, "权限不足")
}
err = models.NewRelationship().DeleteByBookIdAndMemberId(book.BookId,member_id)
err = models.NewRelationship().DeleteByBookIdAndMemberId(book.BookId, member_id)
if err != nil {
c.JsonResult(6007,err.Error())
c.JsonResult(6007, err.Error())
}
c.JsonResult(0,"ok")
c.JsonResult(0, "ok")
}
func (c *BookMemberController) IsPermission() (*models.BookResult,error) {
func (c *BookMemberController) IsPermission() (*models.BookResult, error) {
identify := c.GetString("identify")
book ,err := models.NewBookResult().FindByIdentify(identify,c.Member.MemberId)
book, err := models.NewBookResult().FindByIdentify(identify, c.Member.MemberId)
if err != nil {
if err == models.ErrPermissionDenied {
return book,errors.New("权限不足")
return book, errors.New("权限不足")
}
if err == orm.ErrNoRows {
return book,errors.New("项目不存在")
return book, errors.New("项目不存在")
}
return book,err
return book, err
}
if book.RoleId != conf.BookAdmin && book.RoleId != conf.BookFounder {
return book,errors.New("权限不足")
return book, errors.New("权限不足")
}
return book,nil
}
return book, nil
}

View File

@ -4,16 +4,16 @@ type CommentController struct {
BaseController
}
func (c *CommentController) Lists() {
func (c *CommentController) Lists() {
}
func (c *CommentController) Create() {
c.JsonResult(0,"ok")
c.JsonResult(0, "ok")
}
func (c *CommentController) Index() {
func (c *CommentController) Index() {
c.Prepare()
c.TplName = "comment/index.tpl"
}
}

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
@ -438,11 +433,10 @@ func (c *DocumentController) Upload() {
}
beego.Info(conf.GetUploadFileSize())
beego.Info(moreFile.Size)
if conf.GetUploadFileSize() > 0 && moreFile.Size > conf.GetUploadFileSize() {
c.JsonResult(6009,"查过文件允许的上传最大值")
if conf.GetUploadFileSize() > 0 && moreFile.Size > conf.GetUploadFileSize() {
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)
}
@ -819,15 +813,13 @@ func (c *DocumentController) Content() {
beego.Error("DocumentHistory InsertOrUpdate => ", err)
}
}
if auto_release {
if auto_release {
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,55 +885,33 @@ 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:://"){
if !strings.HasPrefix(bookResult.Cover, "http:://") && !strings.HasPrefix(bookResult.Cover, "https:://") {
bookResult.Cover = c.BaseUrl() + bookResult.Cover
}
eBookResult,err := bookResult.Converter(c.CruSession.SessionID())
eBookResult, err := bookResult.Converter(c.CruSession.SessionID())
if err != nil {
beego.Error("转换文档失败:" + bookResult.BookName + " -> " + err.Error())
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()
}else if output == "epub" {
c.Ctx.Output.Download(eBookResult.PDFPath, identify + ".epub")
c.Abort("200")
} else if output == "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()
}else if output == "mobi" {
c.Ctx.Output.Download(eBookResult.PDFPath, identify + ".epub")
c.Abort("200")
} else if output == "mobi" {
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,9 +18,9 @@ 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)
pageIndex, _ := c.GetInt("page", 1)
pageSize := 18
member_id := 0
@ -26,7 +28,7 @@ func (c *HomeController) Index() {
if c.Member != nil {
member_id = c.Member.MemberId
}
books,totalCount,err := models.NewBook().FindForHomeToPager(pageIndex,pageSize,member_id)
books, totalCount, err := models.NewBook().FindForHomeToPager(pageIndex, pageSize, member_id)
if err != nil {
beego.Error(err)
@ -36,18 +38,18 @@ func (c *HomeController) Index() {
html := utils.GetPagerHtml(c.Ctx.Request.RequestURI, pageIndex, pageSize, totalCount)
c.Data["PageHtml"] = html
}else {
} else {
c.Data["PageHtml"] = ""
}
c.Data["TotalPages"] = int(math.Ceil(float64(totalCount) / float64(pageSize)))
c.Data["Lists"] = books
labels ,totalCount,err := models.NewLabel().FindToPager(1,10)
labels, totalCount, err := models.NewLabel().FindToPager(1, 10)
if err != nil {
c.Data["Labels"] = make([]*models.Label,0)
}else{
c.Data["Labels"] = make([]*models.Label, 0)
} else {
c.Data["Labels"] = labels
}
}

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"
)
@ -18,7 +18,7 @@ func (c *LabelController) Prepare() {
//如果没有开启你们访问则跳转到登录
if !c.EnableAnonymous && c.Member == nil {
c.Redirect(beego.URLFor("AccountController.Login"),302)
c.Redirect(beego.URLFor("AccountController.Login"), 302)
return
}
}
@ -29,16 +29,16 @@ func (c *LabelController) Index() {
c.TplName = "label/index.tpl"
labelName := c.Ctx.Input.Param(":key")
pageIndex,_ := c.GetInt("page",1)
pageIndex, _ := c.GetInt("page", 1)
if labelName == "" {
c.Abort("404")
}
_,err := models.NewLabel().FindFirst("label_name",labelName)
_, err := models.NewLabel().FindFirst("label_name", labelName)
if err != nil {
if err == orm.ErrNoRows {
c.Abort("404")
}else{
} else {
beego.Error(err)
c.Abort("500")
}
@ -47,7 +47,7 @@ func (c *LabelController) Index() {
if c.Member != nil {
member_id = c.Member.MemberId
}
search_result,totalCount,err := models.NewBook().FindForLabelToPager(labelName,pageIndex,conf.PageSize,member_id)
search_result, totalCount, err := models.NewBook().FindForLabelToPager(labelName, pageIndex, conf.PageSize, member_id)
if err != nil {
beego.Error(err)
@ -57,7 +57,7 @@ func (c *LabelController) Index() {
html := utils.GetPagerHtml(c.Ctx.Request.RequestURI, pageIndex, conf.PageSize, totalCount)
c.Data["PageHtml"] = html
}else {
} else {
c.Data["PageHtml"] = ""
}
c.Data["Lists"] = search_result
@ -69,25 +69,22 @@ func (c *LabelController) List() {
c.Prepare()
c.TplName = "label/list.tpl"
pageIndex,_ := c.GetInt("page",1)
pageIndex, _ := c.GetInt("page", 1)
pageSize := 200
labels ,totalCount,err := models.NewLabel().FindToPager(pageIndex,pageSize)
labels, totalCount, err := models.NewLabel().FindToPager(pageIndex, pageSize)
if err != nil {
c.ShowErrorPage(50001,err.Error())
c.ShowErrorPage(50001, err.Error())
}
if totalCount > 0 {
html := utils.GetPagerHtml(c.Ctx.Request.RequestURI, pageIndex, pageSize, totalCount)
c.Data["PageHtml"] = html
}else {
} else {
c.Data["PageHtml"] = ""
}
c.Data["TotalPages"] = int(math.Ceil(float64(totalCount) / float64(pageSize)))
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"
)
@ -21,7 +20,7 @@ type ManagerController struct {
BaseController
}
func (c *ManagerController) Prepare (){
func (c *ManagerController) Prepare() {
c.BaseController.Prepare()
if !c.Member.IsAdministrator() {
@ -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 {
@ -139,10 +138,10 @@ func (c *ManagerController) UpdateMemberStatus() {
c.JsonResult(6002, "用户不存在")
}
if member.MemberId == c.Member.MemberId {
c.JsonResult(6004,"不能变更自己的状态")
c.JsonResult(6004, "不能变更自己的状态")
}
if member.Role == conf.MemberSuperRole {
c.JsonResult(6005,"不能变更超级管理员的状态")
c.JsonResult(6005, "不能变更超级管理员的状态")
}
member.Status = status
@ -171,10 +170,10 @@ func (c *ManagerController) ChangeMemberRole() {
c.JsonResult(6002, "用户不存在")
}
if member.MemberId == c.Member.MemberId {
c.JsonResult(6004,"不能变更自己的权限")
c.JsonResult(6004, "不能变更自己的权限")
}
if member.Role == conf.MemberSuperRole {
c.JsonResult(6005,"不能变更超级管理员的权限")
c.JsonResult(6005, "不能变更超级管理员的权限")
}
member.Role = role
@ -191,13 +190,13 @@ func (c *ManagerController) EditMember() {
c.Prepare()
c.TplName = "manager/edit_users.tpl"
member_id,_ := c.GetInt(":id",0)
member_id, _ := c.GetInt(":id", 0)
if member_id <= 0 {
c.Abort("404")
}
member ,err := models.NewMember().Find(member_id)
member, err := models.NewMember().Find(member_id)
if err != nil {
beego.Error(err)
@ -213,64 +212,64 @@ func (c *ManagerController) EditMember() {
member.Phone = phone
member.Description = description
if password1 != "" && password2 != password1 {
c.JsonResult(6001,"确认密码不正确")
c.JsonResult(6001, "确认密码不正确")
}
if password1 != "" && member.AuthMethod != conf.AuthMethodLDAP{
if password1 != "" && member.AuthMethod != conf.AuthMethodLDAP {
member.Password = password1
}
if err := member.Valid(password1 == "");err != nil {
c.JsonResult(6002,err.Error())
if err := member.Valid(password1 == ""); err != nil {
c.JsonResult(6002, err.Error())
}
if password1 != "" {
password,err := utils.PasswordHash(password1)
password, err := utils.PasswordHash(password1)
if err != nil {
beego.Error(err)
c.JsonResult(6003,"对用户密码加密时出错")
c.JsonResult(6003, "对用户密码加密时出错")
}
member.Password = password
}
if err := member.Update();err != nil {
if err := member.Update(); err != nil {
beego.Error(err)
c.JsonResult(6004,"保存失败")
c.JsonResult(6004, "保存失败")
}
c.JsonResult(0,"ok")
c.JsonResult(0, "ok")
}
c.Data["Model"] = member
}
//删除一个用户,并将该用户的所有信息转移到超级管理员上.
func (c *ManagerController) DeleteMember() {
func (c *ManagerController) DeleteMember() {
c.Prepare()
member_id,_ := c.GetInt("id",0)
member_id, _ := c.GetInt("id", 0)
if member_id <= 0 {
c.JsonResult(404,"参数错误")
c.JsonResult(404, "参数错误")
}
member ,err := models.NewMember().Find(member_id)
member, err := models.NewMember().Find(member_id)
if err != nil {
beego.Error(err)
c.JsonResult(500,"用户不存在")
c.JsonResult(500, "用户不存在")
}
if member.Role == conf.MemberSuperRole {
c.JsonResult(500,"不能删除超级管理员")
c.JsonResult(500, "不能删除超级管理员")
}
superMember,err := models.NewMember().FindByFieldFirst("role",0)
superMember, err := models.NewMember().FindByFieldFirst("role", 0)
if err != nil {
beego.Error(err)
c.JsonResult(5001,"未能找到超级管理员")
c.JsonResult(5001, "未能找到超级管理员")
}
err = models.NewMember().Delete(member_id,superMember.MemberId)
err = models.NewMember().Delete(member_id, superMember.MemberId)
if err != nil {
beego.Error(err)
c.JsonResult(5002,"删除失败")
c.JsonResult(5002, "删除失败")
}
c.JsonResult(0,"ok")
c.JsonResult(0, "ok")
}
//项目列表.
@ -572,9 +571,9 @@ func (c *ManagerController) AttachList() {
c.Data["PageHtml"] = ""
}
for _,item := range attachList {
for _, item := range attachList {
p := filepath.Join(commands.WorkingDirectory,item.FilePath)
p := filepath.Join(conf.WorkingDirectory, item.FilePath)
item.IsExist = utils.FileExists(p)
@ -583,27 +582,27 @@ func (c *ManagerController) AttachList() {
}
//附件详情.
func (c *ManagerController) AttachDetailed() {
func (c *ManagerController) AttachDetailed() {
c.Prepare()
c.TplName = "manager/attach_detailed.tpl"
attach_id,_ := strconv.Atoi(c.Ctx.Input.Param(":id"))
attach_id, _ := strconv.Atoi(c.Ctx.Input.Param(":id"))
if attach_id <= 0 {
c.Abort("404")
}
attach,err := models.NewAttachmentResult().Find(attach_id)
attach, err := models.NewAttachmentResult().Find(attach_id)
if err != nil {
beego.Error("AttachDetailed => ",err)
beego.Error("AttachDetailed => ", err)
if err == orm.ErrNoRows {
c.Abort("404")
}else{
} else {
c.Abort("500")
}
}
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)
@ -612,43 +611,22 @@ func (c *ManagerController) AttachDetailed() {
}
//删除附件.
func (c *ManagerController) AttachDelete() {
func (c *ManagerController) AttachDelete() {
c.Prepare()
attach_id,_ := c.GetInt("attach_id")
attach_id, _ := c.GetInt("attach_id")
if attach_id <= 0 {
c.Abort("404")
}
attach,err := models.NewAttachment().Find(attach_id)
attach, err := models.NewAttachment().Find(attach_id)
if err != nil {
beego.Error("AttachDelete => ",err)
c.JsonResult(6001,err.Error())
beego.Error("AttachDelete => ", err)
c.JsonResult(6001, err.Error())
}
if err := attach.Delete();err != nil {
beego.Error("AttachDelete => ",err)
c.JsonResult(6002,err.Error())
if err := attach.Delete(); err != nil {
beego.Error("AttachDelete => ", err)
c.JsonResult(6002, err.Error())
}
c.JsonResult(0,"ok")
c.JsonResult(0, "ok")
}

View File

@ -1,31 +1,31 @@
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 {
BaseController
}
func (c *SearchController) Index() {
func (c *SearchController) Index() {
c.Prepare()
c.TplName = "search/index.tpl"
//如果没有开启你们访问则跳转到登录
if !c.EnableAnonymous && c.Member == nil {
c.Redirect(beego.URLFor("AccountController.Login"),302)
c.Redirect(beego.URLFor("AccountController.Login"), 302)
return
}
keyword := c.GetString("keyword")
pageIndex,_ := c.GetInt("page",1)
pageIndex, _ := c.GetInt("page", 1)
c.Data["BaseUrl"] = c.BaseUrl()
@ -35,7 +35,7 @@ func (c *SearchController) Index() {
if c.Member != nil {
member_id = c.Member.MemberId
}
search_result,totalCount,err := models.NewDocumentSearchResult().FindToPager(keyword,pageIndex,conf.PageSize,member_id)
search_result, totalCount, err := models.NewDocumentSearchResult().FindToPager(keyword, pageIndex, conf.PageSize, member_id)
if err != nil {
beego.Error(err)
@ -45,12 +45,12 @@ func (c *SearchController) Index() {
html := utils.GetPagerHtml(c.Ctx.Request.RequestURI, pageIndex, conf.PageSize, totalCount)
c.Data["PageHtml"] = html
}else {
} else {
c.Data["PageHtml"] = ""
}
if len(search_result) > 0 {
for _,item := range search_result {
item.DocumentName = strings.Replace(item.DocumentName,keyword,"<em>" + keyword + "</em>",-1)
for _, item := range search_result {
item.DocumentName = strings.Replace(item.DocumentName, keyword, "<em>"+keyword+"</em>", -1)
if item.Description != "" {
src := item.Description
@ -79,13 +79,13 @@ func (c *SearchController) Index() {
if len(r) > 100 {
src = string(r[:100])
}else{
} else {
src = string(r)
}
item.Description = strings.Replace(src, keyword, "<em>" + keyword + "</em>", -1)
item.Description = strings.Replace(src, keyword, "<em>"+keyword+"</em>", -1)
}
if item.Identify == ""{
if item.Identify == "" {
item.Identify = strconv.Itoa(item.DocumentId)
}
if item.ModifyTime.IsZero() {

View File

@ -3,24 +3,23 @@ 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 {
BaseController
}
func (c *SettingController) Index() {
func (c *SettingController) Index() {
c.TplName = "setting/index.tpl"
if c.Ctx.Input.IsPost() {
@ -43,131 +42,129 @@ func (c *SettingController) Index() {
}
}
func (c *SettingController) Password() {
func (c *SettingController) Password() {
c.TplName = "setting/password.tpl"
if c.Ctx.Input.IsPost() {
if c.Member.AuthMethod == conf.AuthMethodLDAP {
c.JsonResult(6009,"当前用户不支持修改密码")
c.JsonResult(6009, "当前用户不支持修改密码")
}
password1 := c.GetString("password1")
password2 := c.GetString("password2")
password3 := c.GetString("password3")
if password1 == "" {
c.JsonResult(6003,"原密码不能为空")
c.JsonResult(6003, "原密码不能为空")
}
if password2 == "" {
c.JsonResult(6004,"新密码不能为空")
c.JsonResult(6004, "新密码不能为空")
}
if count := strings.Count(password2,""); count < 6 || count > 18 {
c.JsonResult(6009,"密码必须在6-18字之间")
if count := strings.Count(password2, ""); count < 6 || count > 18 {
c.JsonResult(6009, "密码必须在6-18字之间")
}
if password2 != password3 {
c.JsonResult(6003,"确认密码不正确")
c.JsonResult(6003, "确认密码不正确")
}
if ok,_ := utils.PasswordVerify(c.Member.Password,password1) ; !ok {
c.JsonResult(6005,"原始密码不正确")
if ok, _ := utils.PasswordVerify(c.Member.Password, password1); !ok {
c.JsonResult(6005, "原始密码不正确")
}
if password1 == password2 {
c.JsonResult(6006,"新密码不能和原始密码相同")
c.JsonResult(6006, "新密码不能和原始密码相同")
}
pwd,err := utils.PasswordHash(password2)
pwd, err := utils.PasswordHash(password2)
if err != nil {
c.JsonResult(6007,"密码加密失败")
c.JsonResult(6007, "密码加密失败")
}
c.Member.Password = pwd
if err := c.Member.Update();err != nil {
c.JsonResult(6008,err.Error())
if err := c.Member.Update(); err != nil {
c.JsonResult(6008, err.Error())
}
c.JsonResult(0,"ok")
c.JsonResult(0, "ok")
}
}
// Upload 上传图片
func (c *SettingController) Upload() {
file,moreFile,err := c.GetFile("image-file")
file, moreFile, err := c.GetFile("image-file")
defer file.Close()
if err != nil {
logs.Error("",err.Error())
c.JsonResult(500,"读取文件异常")
logs.Error("", err.Error())
c.JsonResult(500, "读取文件异常")
}
ext := filepath.Ext(moreFile.Filename)
if !strings.EqualFold(ext,".png") && !strings.EqualFold(ext,".jpg") && !strings.EqualFold(ext,".gif") && !strings.EqualFold(ext,".jpeg") {
c.JsonResult(500,"不支持的图片格式")
if !strings.EqualFold(ext, ".png") && !strings.EqualFold(ext, ".jpg") && !strings.EqualFold(ext, ".gif") && !strings.EqualFold(ext, ".jpeg") {
c.JsonResult(500, "不支持的图片格式")
}
x1 ,_ := strconv.ParseFloat(c.GetString("x"),10)
y1 ,_ := strconv.ParseFloat(c.GetString("y"),10)
w1 ,_ := strconv.ParseFloat(c.GetString("width"),10)
h1 ,_ := strconv.ParseFloat(c.GetString("height"),10)
x1, _ := strconv.ParseFloat(c.GetString("x"), 10)
y1, _ := strconv.ParseFloat(c.GetString("y"), 10)
w1, _ := strconv.ParseFloat(c.GetString("width"), 10)
h1, _ := strconv.ParseFloat(c.GetString("height"), 10)
x := int(x1)
y := int(y1)
width := int(w1)
height := int(h1)
fmt.Println(x,x1,y,y1)
fmt.Println(x, x1, y, y1)
fileName := "avatar_" + strconv.FormatInt(time.Now().UnixNano(), 16)
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)
os.MkdirAll(path, os.ModePerm)
err = c.SaveToFile("image-file",filePath)
err = c.SaveToFile("image-file", filePath)
if err != nil {
logs.Error("",err)
c.JsonResult(500,"图片保存失败")
logs.Error("", err)
c.JsonResult(500, "图片保存失败")
}
//剪切图片
subImg,err := graphics.ImageCopyFromFile(filePath,x,y,width,height)
subImg, err := graphics.ImageCopyFromFile(filePath, x, y, width, height)
if err != nil {
logs.Error("ImageCopyFromFile => ",err)
c.JsonResult(6001,"头像剪切失败")
logs.Error("ImageCopyFromFile => ", err)
c.JsonResult(6001, "头像剪切失败")
}
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.ImageResizeSaveFile(subImg, 120, 120, filePath)
//err = graphics.SaveImage(filePath,subImg)
if err != nil {
logs.Error("保存文件失败 => ",err.Error())
c.JsonResult(500,"保存文件失败")
logs.Error("保存文件失败 => ", err.Error())
c.JsonResult(500, "保存文件失败")
}
url := "/" + strings.Replace(strings.TrimPrefix(filePath,commands.WorkingDirectory),"\\","/",-1)
if strings.HasPrefix(url,"//") {
url := "/" + strings.Replace(strings.TrimPrefix(filePath, conf.WorkingDirectory), "\\", "/", -1)
if strings.HasPrefix(url, "//") {
url = string(url[1:])
}
if member,err := models.NewMember().Find(c.Member.MemberId);err == nil {
if member, err := models.NewMember().Find(c.Member.MemberId); err == nil {
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))
if strings.HasPrefix(avater, "/uploads/") {
os.Remove(filepath.Join(conf.WorkingDirectory, avater))
}
c.SetMember(*member)
}else{
c.JsonResult(60001,"保存头像失败")
} else {
c.JsonResult(60001, "保存头像失败")
}
}
c.JsonResult(0,"ok",url)
}
c.JsonResult(0, "ok", url)
}

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

@ -13,7 +13,7 @@ import (
// 将图片保存到指定的路径
func SaveImage(p string, src image.Image) error {
os.MkdirAll(filepath.Dir(p),0666)
os.MkdirAll(filepath.Dir(p), 0666)
f, err := os.OpenFile(p, os.O_SYNC|os.O_RDWR|os.O_CREATE, 0666)

View File

@ -127,7 +127,7 @@ func (m *Attachment) FindToPager(pageIndex, pageSize int) (attachList []*Attachm
} else {
attach.DocumentName = "[不存在]"
}
attach.LocalHttpPath = strings.Replace(item.FilePath,"\\","/",-1)
attach.LocalHttpPath = strings.Replace(item.FilePath, "\\", "/", -1)
attachList = append(attachList, attach)
}

View File

@ -8,27 +8,27 @@ import (
type AttachmentResult struct {
Attachment
IsExist bool
BookName string
DocumentName string
IsExist bool
BookName string
DocumentName string
FileShortSize string
Account string
Account string
LocalHttpPath string
}
func NewAttachmentResult() *AttachmentResult {
return &AttachmentResult{ IsExist : false }
return &AttachmentResult{IsExist: false}
}
func (m *AttachmentResult) Find(id int) (*AttachmentResult,error) {
func (m *AttachmentResult) Find(id int) (*AttachmentResult, error) {
o := orm.NewOrm()
attach := NewAttachment()
err := o.QueryTable(m.TableNameWithPrefix()).Filter("attachment_id",id).One(attach)
err := o.QueryTable(m.TableNameWithPrefix()).Filter("attachment_id", id).One(attach)
if err != nil {
return m,err
return m, err
}
m.Attachment = *attach
@ -50,12 +50,12 @@ func (m *AttachmentResult) Find(id int) (*AttachmentResult,error) {
if attach.CreateAt > 0 {
member := NewMember()
if e := o.QueryTable(member.TableNameWithPrefix()).Filter("member_id",attach.CreateAt).One(member,"account");e == nil {
if e := o.QueryTable(member.TableNameWithPrefix()).Filter("member_id", attach.CreateAt).One(member, "account"); e == nil {
m.Account = member.Account
}
}
m.FileShortSize = utils.FormatBytes(int64(attach.FileSize))
m.LocalHttpPath = strings.Replace(m.FilePath,"\\","/",-1)
m.LocalHttpPath = strings.Replace(m.FilePath, "\\", "/", -1)
return m,nil
}
return m, nil
}

View File

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

View File

@ -4,9 +4,9 @@ import "time"
//博文表
type Blog struct {
BlogId int
BlogId int
BlogTitle string
MemberId int
MemberId int
//文字摘要
BlogExcerpt string
//文章内容
@ -22,4 +22,4 @@ type Blog struct {
ModifyAt int
//创建时间
Created time.Time
}
}

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 .
@ -16,17 +19,15 @@ type Book struct {
// BookName 项目名称.
BookName string `orm:"column(book_name);size(500)" json:"book_name"`
// Identify 项目唯一标识.
Identify string `orm:"column(identify);size(100);unique" json:"identify"`
Identify string `orm:"column(identify);size(100);unique" json:"identify"`
//是否是自动发布 0 否/1 是
AutoRelease int `orm:"column(auto_release);type(int);default(0)" json:"auto_release"`
OrderIndex int `orm:"column(order_index);type(int);default(0)" json:"order_index"`
OrderIndex int `orm:"column(order_index);type(int);default(0)" json:"order_index"`
// Description 项目描述.
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"`
Publisher string `orm:"column(publisher);size(500)" json:"publisher"`
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"`
// 当项目是私有时的访问Token.
@ -122,7 +123,7 @@ func (m *Book) Update(cols ...string) error {
temp := NewBook()
temp.BookId = m.BookId
if err := o.Read(temp);err != nil {
if err := o.Read(temp); err != nil {
return err
}
@ -185,7 +186,7 @@ func (m *Book) FindToPager(pageIndex, pageSize, memberId int) (books []*BookResu
" 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)
" WHERE rel.relationship_id > 0 ORDER BY book.order_index DESC,book.book_id DESC LIMIT " + fmt.Sprintf("%d,%d", offset, pageSize)
_, err = o.Raw(sql2, memberId).QueryRows(&books)
if err != nil {
@ -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()
}
@ -320,7 +323,7 @@ func (m *Book) FindForLabelToPager(keyword string, pageIndex, pageSize, member_i
if member_id > 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 = ? WHERE (relationship_id > 0 OR book.privately_owned = 0) AND book.label LIKE ?"
err = o.Raw(sql1, member_id,keyword).QueryRow(&totalCount)
err = o.Raw(sql1, member_id, keyword).QueryRow(&totalCount)
if err != nil {
return
}
@ -330,12 +333,12 @@ func (m *Book) FindForLabelToPager(keyword string, pageIndex, pageSize, member_i
LEFT JOIN md_members AS member ON rel1.member_id = member.member_id
WHERE (rel.relationship_id > 0 OR book.privately_owned = 0) AND book.label LIKE ? ORDER BY order_index DESC ,book.book_id DESC LIMIT ?,?`
_, err = o.Raw(sql2, member_id,keyword, offset, pageSize).QueryRows(&books)
_, err = o.Raw(sql2, member_id, keyword, offset, pageSize).QueryRows(&books)
return
} else {
count, err1 := o.QueryTable(NewBook().TableNameWithPrefix()).Filter("privately_owned", 0).Filter("label__icontains",keyword).Count()
count, err1 := o.QueryTable(NewBook().TableNameWithPrefix()).Filter("privately_owned", 0).Filter("label__icontains", keyword).Count()
if err1 != nil {
err = err1
@ -348,14 +351,13 @@ func (m *Book) FindForLabelToPager(keyword string, pageIndex, pageSize, member_i
LEFT JOIN md_members AS member ON rel.member_id = member.member_id
WHERE book.privately_owned = 0 AND book.label LIKE ? ORDER BY order_index DESC ,book.book_id DESC LIMIT ?,?`
_, err = o.Raw(sql,keyword, offset, pageSize).QueryRows(&books)
_, err = o.Raw(sql, keyword, offset, pageSize).QueryRows(&books)
return
}
}
//重置文档数量
func (m *Book) ResetDocumentNumber(book_id int) {
o := orm.NewOrm()

View File

@ -1,64 +1,64 @@
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 {
BookId int `json:"book_id"`
BookName string `json:"book_name"`
Identify string `json:"identify"`
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"`
CommentStatus string `json:"comment_status"`
CommentCount int `json:"comment_count"`
CreateTime time.Time `json:"create_time"`
CreateName string `json:"create_name"`
ModifyTime time.Time `json:"modify_time"`
Cover string `json:"cover"`
Theme string `json:"theme"`
Label string `json:"label"`
MemberId int `json:"member_id"`
Editor string `json:"editor"`
AutoRelease bool `json:"auto_release"`
BookId int `json:"book_id"`
BookName string `json:"book_name"`
Identify string `json:"identify"`
OrderIndex int `json:"order_index"`
Description string `json:"description"`
Publisher string `json:"publisher"`
PrivatelyOwned int `json:"privately_owned"`
PrivateToken string `json:"private_token"`
DocCount int `json:"doc_count"`
CommentStatus string `json:"comment_status"`
CommentCount int `json:"comment_count"`
CreateTime time.Time `json:"create_time"`
CreateName string `json:"create_name"`
ModifyTime time.Time `json:"modify_time"`
Cover string `json:"cover"`
Theme string `json:"theme"`
Label string `json:"label"`
MemberId int `json:"member_id"`
Editor string `json:"editor"`
AutoRelease bool `json:"auto_release"`
RelationshipId int `json:"relationship_id"`
RoleId int `json:"role_id"`
RoleName string `json:"role_name"`
Status int
RelationshipId int `json:"relationship_id"`
RoleId int `json:"role_id"`
RoleName string `json:"role_name"`
Status int
LastModifyText string `json:"last_modify_text"`
IsDisplayComment bool `json:"is_display_comment"`
LastModifyText string `json:"last_modify_text"`
IsDisplayComment bool `json:"is_display_comment"`
}
func NewBookResult() *BookResult {
return &BookResult{}
}
// 根据项目标识查询项目以及指定用户权限的信息.
func (m *BookResult) FindByIdentify(identify string,member_id int) (*BookResult,error) {
func (m *BookResult) FindByIdentify(identify string, member_id int) (*BookResult, error) {
if identify == "" || member_id <= 0 {
return m,ErrInvalidParameter
return m, ErrInvalidParameter
}
o := orm.NewOrm()
@ -93,11 +93,10 @@ func (m *BookResult) FindByIdentify(identify string,member_id int) (*BookResult,
m = NewBookResult().ToBookResult(*book)
m.CreateName = member.Account
m.MemberId = relationship.MemberId
m.RoleId = relationship.RoleId
m.RelationshipId = relationship.RelationshipId
m.CreateName = member.Account
m.MemberId = relationship.MemberId
m.RoleId = relationship.RoleId
m.RelationshipId = relationship.RelationshipId
if m.RoleId == conf.BookFounder {
m.RoleName = "创始人"
@ -123,10 +122,10 @@ func (m *BookResult) FindByIdentify(identify string,member_id int) (*BookResult,
return m, nil
}
func (m *BookResult) FindToPager(pageIndex, pageSize int) (books []*BookResult,totalCount int,err error) {
func (m *BookResult) FindToPager(pageIndex, pageSize int) (books []*BookResult, totalCount int, err error) {
o := orm.NewOrm()
count,err := o.QueryTable(NewBook().TableNameWithPrefix()).Count()
count, err := o.QueryTable(NewBook().TableNameWithPrefix()).Count()
if err != nil {
return
@ -140,9 +139,9 @@ func (m *BookResult) FindToPager(pageIndex, pageSize int) (books []*BookResult,t
LEFT JOIN md_members AS m ON rel.member_id = m.member_id
ORDER BY book.order_index DESC ,book.book_id DESC LIMIT ?,?`
offset := (pageIndex -1 )* pageSize
offset := (pageIndex - 1) * pageSize
_,err = o.Raw(sql,offset,pageSize).QueryRows(&books)
_, err = o.Raw(sql, offset, pageSize).QueryRows(&books)
return
}
@ -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"
@ -180,128 +178,139 @@ func (m *BookResult) ToBookResult(book Book) *BookResult {
return m
}
func (m *BookResult) Converter(sessionId string) (ConvertBookResult,error) {
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
pdfpath := filepath.Join(outputPath, "book.pdf")
epubpath := filepath.Join(outputPath, "book.epub")
mobipath := filepath.Join(outputPath, "book.mobi")
docxpath := filepath.Join(outputPath, "book.docx")
//先将转换的文件储存到临时目录
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
}
if m.IsCacheEBook {
pdfpath := filepath.Join(outputPath,"output","book.pdf")
epubpath := filepath.Join(outputPath,"output","book.epub")
mobipath := filepath.Join(outputPath,"output","book.mobi")
if utils.FileExists(pdfpath) && utils.FileExists(epubpath) && utils.FileExists(mobipath){
convertBookResult.EpubPath = epubpath
convertBookResult.MobiPath = mobipath
convertBookResult.PDFPath = pdfpath
return convertBookResult,nil
}
}
docs, err := NewDocument().FindListByBookId(m.BookId)
if err != nil {
return convertBookResult,err
return convertBookResult, err
}
tocList := make([]converter.Toc,0)
tocList := make([]converter.Toc, 0)
for _, item := range docs {
if item.ParentId == 0 {
toc := converter.Toc{
Id: item.DocumentId,
Link: strconv.Itoa(item.DocumentId) + ".html",
Pid: item.ParentId,
Id: item.DocumentId,
Link: strconv.Itoa(item.DocumentId) + ".html",
Pid: item.ParentId,
Title: item.DocumentName,
}
tocList = append(tocList,toc)
tocList = append(tocList, toc)
}
}
for _, item := range docs {
if item.ParentId != 0 {
toc := converter.Toc{
Id: item.DocumentId,
Link: strconv.Itoa(item.DocumentId) + ".html",
Pid: item.ParentId,
Id: item.DocumentId,
Link: strconv.Itoa(item.DocumentId) + ".html",
Pid: item.ParentId,
Title: item.DocumentName,
}
tocList = append(tocList,toc)
tocList = append(tocList, toc)
}
}
ebookConfig := converter.Config{
Charset : "utf-8",
Cover : m.Cover,
Timestamp : time.Now().Format("2006-01-02 15:04:05"),
Description : string(blackfriday.MarkdownBasic([]byte(m.Description))),
Footer : "<p style='color:#8E8E8E;font-size:12px;'>本文档使用 <a href='https://www.iminho.me' style='text-decoration:none;color:#1abc9c;font-weight:bold;'>MinDoc</a> 构建 <span style='float:right'>- _PAGENUM_ -</span></p>",
Header : "<p style='color:#8E8E8E;font-size:12px;'>_SECTION_</p>",
Identifier : "",
Language : "zh-CN",
Creator : m.CreateName,
Publisher : m.Publisher,
Contributor : m.Publisher,
Title : m.BookName,
Format: []string{"epub", "mobi", "pdf"},
FontSize : "14",
PaperSize : "a4",
MarginLeft : "72",
MarginRight : "72",
MarginTop : "72",
MarginBottom : "72",
Toc : tocList,
More : []string{},
Charset: "utf-8",
Cover: m.Cover,
Timestamp: time.Now().Format("2006-01-02 15:04:05"),
Description: string(blackfriday.MarkdownBasic([]byte(m.Description))),
Footer: "<p style='color:#8E8E8E;font-size:12px;'>本文档使用 <a href='https://www.iminho.me' style='text-decoration:none;color:#1abc9c;font-weight:bold;'>MinDoc</a> 构建 <span style='float:right'>- _PAGENUM_ -</span></p>",
Header: "<p style='color:#8E8E8E;font-size:12px;'>_SECTION_</p>",
Identifier: "",
Language: "zh-CN",
Creator: m.CreateName,
Publisher: m.Publisher,
Contributor: m.Publisher,
Title: m.BookName,
Format: []string{"epub", "mobi", "pdf", "docx"},
FontSize: "14",
PaperSize: "a4",
MarginLeft: "72",
MarginRight: "72",
MarginTop: "72",
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
return convertBookResult, err
}
viewPath := beego.BConfig.WebConfig.ViewsPath
baseUrl := beego.AppConfig.DefaultString("baseurl","")
for _,item := range docs {
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 {
return convertBookResult,err
return convertBookResult, err
}
var buf bytes.Buffer
if err := beego.ExecuteViewPathTemplate(&buf,"document/export.tpl",viewPath,map[string]interface{}{"Model": m, "Lists": item, "BaseUrl": baseUrl}); err != nil {
return convertBookResult,err
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()
return convertBookResult,err
return convertBookResult, err
}
bufio := bytes.NewReader(buf.Bytes())
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)
}
}
})
html, err = doc.Html()
if err != nil {
f.Close()
return convertBookResult,err
return convertBookResult, err
}
// html = strings.Replace(html, "<img src=\"/uploads", "<img src=\"" + c.BaseUrl() + "/uploads", -1)
@ -310,35 +319,29 @@ func (m *BookResult) Converter(sessionId string) (ConvertBookResult,error) {
f.Close()
}
eBookConverter := &converter.Converter{
BasePath : outputPath,
Config : ebookConfig,
Debug : false,
BasePath: tempOutputPath,
Config: ebookConfig,
Debug: true,
}
if err := eBookConverter.Convert();err != nil {
beego.Error("转换文件错误:" + m.BookName +" => "+ err.Error())
return convertBookResult,err
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")
return convertBookResult,nil
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,76 +1,77 @@
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
type Comment struct {
CommentId int `orm:"pk;auto;unique;column(comment_id)" json:"comment_id"`
Floor int `orm:"column(floor);type(unsigned);default(0)" json:"floor"`
BookId int `orm:"column(book_id);type(int)" json:"book_id"`
CommentId int `orm:"pk;auto;unique;column(comment_id)" json:"comment_id"`
Floor int `orm:"column(floor);type(unsigned);default(0)" json:"floor"`
BookId int `orm:"column(book_id);type(int)" json:"book_id"`
// DocumentId 评论所属的文档.
DocumentId int `orm:"column(document_id);type(int)" json:"document_id"`
DocumentId int `orm:"column(document_id);type(int)" json:"document_id"`
// Author 评论作者.
Author string `orm:"column(author);size(100)" json:"author"`
Author string `orm:"column(author);size(100)" json:"author"`
//MemberId 评论用户ID.
MemberId int `orm:"column(member_id);type(int)" json:"member_id"`
MemberId int `orm:"column(member_id);type(int)" json:"member_id"`
// IPAddress 评论者的IP地址
IPAddress string `orm:"column(ip_address);size(100)" json:"ip_address"`
IPAddress string `orm:"column(ip_address);size(100)" json:"ip_address"`
// 评论日期.
CommentDate time.Time `orm:"type(datetime);column(comment_date);auto_now_add" json:"comment_date"`
CommentDate time.Time `orm:"type(datetime);column(comment_date);auto_now_add" json:"comment_date"`
//Content 评论内容.
Content string `orm:"column(content);size(2000)" json:"content"`
Content string `orm:"column(content);size(2000)" json:"content"`
// Approved 评论状态0 待审核/1 已审核/2 垃圾评论/ 3 已删除
Approved int `orm:"column(approved);type(int)" json:"approved"`
Approved int `orm:"column(approved);type(int)" json:"approved"`
// UserAgent 评论者浏览器内容
UserAgent string `orm:"column(user_agent);size(500)" json:"user_agent"`
UserAgent string `orm:"column(user_agent);size(500)" json:"user_agent"`
// Parent 评论所属父级
ParentId int `orm:"column(parent_id);type(int);default(0)" json:"parent_id"`
AgreeCount int `orm:"column(agree_count);type(int);default(0)" json:"agree_count"`
AgainstCount int `orm:"column(against_count);type(int);default(0)" json:"against_count"`
ParentId int `orm:"column(parent_id);type(int);default(0)" json:"parent_id"`
AgreeCount int `orm:"column(agree_count);type(int);default(0)" json:"agree_count"`
AgainstCount int `orm:"column(against_count);type(int);default(0)" json:"against_count"`
}
// TableName 获取对应数据库表名.
func (m *Comment) TableName() string {
return "comments"
}
// TableEngine 获取数据使用的引擎.
func (m *Comment) TableEngine() string {
return "INNODB"
}
func (m *Comment) TableNameWithPrefix() string {
func (m *Comment) TableNameWithPrefix() string {
return conf.GetDatabasePrefix() + m.TableName()
}
func NewComment() *Comment {
return &Comment{}
}
func (m *Comment) Find(id int) (*Comment,error) {
func (m *Comment) Find(id int) (*Comment, error) {
if id <= 0 {
return m,ErrInvalidParameter
return m, ErrInvalidParameter
}
o := orm.NewOrm()
err := o.Read(m)
err := o.Read(m)
return m,err
return m, err
}
func (m *Comment) Update(cols... string) error {
func (m *Comment) Update(cols ...string) error {
o := orm.NewOrm()
_,err := o.Update(m,cols...)
_, err := o.Update(m, cols...)
return err
}
//Insert 添加一条评论.
func (m *Comment) Insert() error {
if m.DocumentId <= 0{
if m.DocumentId <= 0 {
return errors.New("评论文档不存在")
}
if m.Content == "" {
@ -89,28 +90,28 @@ func (m *Comment) Insert() error {
document := NewDocument()
//如果评论的文档不存在
if _,err := document.Find(m.DocumentId); err != nil {
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
}
//如果已关闭评论
if book.CommentStatus == "closed"{
if book.CommentStatus == "closed" {
return ErrCommentClosed
}
if book.CommentStatus == "registered_only" && m.MemberId <= 0{
if book.CommentStatus == "registered_only" && m.MemberId <= 0 {
return ErrPermissionDenied
}
//如果仅参与者评论
if book.CommentStatus == "group_only" {
if m.MemberId <= 0{
if m.MemberId <= 0 {
return ErrPermissionDenied
}
rel := NewRelationship()
if _,err := rel.FindForRoleId(book.BookId,m.MemberId);err != nil {
if _, err := rel.FindForRoleId(book.BookId, m.MemberId); err != nil {
return ErrPermissionDenied
}
}
@ -118,51 +119,18 @@ func (m *Comment) Insert() error {
if m.MemberId > 0 {
member := NewMember()
//如果用户不存在
if _,err := member.Find(m.MemberId) ; err != nil {
if _, err := member.Find(m.MemberId); err != nil {
return ErrMemberNoExist
}
//如果用户被禁用
if member.Status == 1 {
return ErrMemberDisabled
}
}else if m.Author == "" {
} else if m.Author == "" {
m.Author = "[匿名用户]"
}
m.BookId = book.BookId
_,err = o.Insert(m)
_, err = o.Insert(m)
return err
}

View File

@ -4,11 +4,11 @@ import "github.com/astaxie/beego/orm"
type CommentResult struct {
Comment
Author string `json:"author"`
ReplyAccount string `json:"reply_account"`
Author string `json:"author"`
ReplyAccount string `json:"reply_account"`
}
func (m *CommentResult) FindForDocumentToPager(doc_id, page_index,page_size int) (comments []*CommentResult,totalCount int,err error) {
func (m *CommentResult) FindForDocumentToPager(doc_id, page_index, page_size int) (comments []*CommentResult, totalCount int, err error) {
o := orm.NewOrm()
@ -25,12 +25,11 @@ 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)
_, err = o.Raw(sql1, doc_id, offset, page_size).QueryRows(&comments)
v,err := o.QueryTable(m.TableNameWithPrefix()).Filter("document_id",doc_id).Count()
v, err := o.QueryTable(m.TableNameWithPrefix()).Filter("document_id", doc_id).Count()
if err == nil {
totalCount = int(v)
@ -38,4 +37,3 @@ WHERE comment.document_id = ? ORDER BY comment.comment_id DESC LIMIT 0,10`
return
}

View File

@ -1,30 +1,31 @@
package models
import (
"time"
"github.com/lifei6671/mindoc/conf"
"github.com/astaxie/beego/orm"
"github.com/lifei6671/mindoc/conf"
"time"
)
type CommentVote struct {
VoteId int `orm:"column(vote_id);pk;auto;unique" json:"vote_id"`
CommentId int `orm:"column(comment_id);type(int);index" json:"comment_id"`
CommentMemberId int `orm:"column(comment_member_id);type(int);index;default(0)" json:"comment_member_id"`
VoteMemberId int `orm:"column(vote_member_id);type(int);index" json:"vote_member_id"`
VoteState int `orm:"column(vote_state);type(int)" json:"vote_state"`
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
VoteId int `orm:"column(vote_id);pk;auto;unique" json:"vote_id"`
CommentId int `orm:"column(comment_id);type(int);index" json:"comment_id"`
CommentMemberId int `orm:"column(comment_member_id);type(int);index;default(0)" json:"comment_member_id"`
VoteMemberId int `orm:"column(vote_member_id);type(int);index" json:"vote_member_id"`
VoteState int `orm:"column(vote_state);type(int)" json:"vote_state"`
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
}
// TableName 获取对应数据库表名.
func (m *CommentVote) TableName() string {
return "comment_votes"
}
// TableEngine 获取数据使用的引擎.
func (m *CommentVote) TableEngine() string {
return "INNODB"
}
func (m *CommentVote) TableNameWithPrefix() string {
func (m *CommentVote) TableNameWithPrefix() string {
return conf.GetDatabasePrefix() + m.TableName()
}
func (u *CommentVote) TableUnique() [][]string {
@ -35,15 +36,15 @@ func (u *CommentVote) TableUnique() [][]string {
func NewCommentVote() *CommentVote {
return &CommentVote{}
}
func (m *CommentVote) InsertOrUpdate() (*CommentVote,error) {
func (m *CommentVote) InsertOrUpdate() (*CommentVote, error) {
o := orm.NewOrm()
if m.VoteId > 0 {
_,err := o.Update(m)
return m,err
}else{
_,err := o.Insert(m)
_, err := o.Update(m)
return m, err
} else {
_, err := o.Insert(m)
return m,err
return m, err
}
}
}

View File

@ -2,7 +2,8 @@ package models
// 转换结果
type ConvertBookResult struct {
PDFPath string
PDFPath string
EpubPath string
MobiPath string
WordPath string
}

View File

@ -3,34 +3,34 @@ package models
import "github.com/astaxie/beego/orm"
type Dashboard struct {
BookNumber int64 `json:"book_number"`
DocumentNumber int64 `json:"document_number"`
MemberNumber int64 `json:"member_number"`
CommentNumber int64 `json:"comment_number"`
AttachmentNumber int64 `json:"attachment_number"`
BookNumber int64 `json:"book_number"`
DocumentNumber int64 `json:"document_number"`
MemberNumber int64 `json:"member_number"`
CommentNumber int64 `json:"comment_number"`
AttachmentNumber int64 `json:"attachment_number"`
}
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()
book_number, _ := o.QueryTable(NewBook().TableNameWithPrefix()).Count()
m.BookNumber = book_number
document_count,_ := o.QueryTable(NewDocument().TableNameWithPrefix()).Count()
document_count, _ := o.QueryTable(NewDocument().TableNameWithPrefix()).Count()
m.DocumentNumber = document_count
member_number,_ := o.QueryTable(NewMember().TableNameWithPrefix()).Count()
member_number, _ := o.QueryTable(NewMember().TableNameWithPrefix()).Count()
m.MemberNumber = member_number
//comment_number,_ := o.QueryTable(NewComment().TableNameWithPrefix()).Count()
m.CommentNumber = 0
attachment_number,_ := o.QueryTable(NewAttachment().TableNameWithPrefix()).Count()
attachment_number, _ := o.QueryTable(NewAttachment().TableNameWithPrefix()).Count()
m.AttachmentNumber = attachment_number

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,12 +137,12 @@ 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 {
if strings.HasPrefix(attach.HttpPath,"/"){
attach.HttpPath = strings.TrimSuffix(beego.AppConfig.DefaultString("baseurl",""),"/") + attach.HttpPath
for _, attach := range attachList {
if strings.HasPrefix(attach.HttpPath, "/") {
attach.HttpPath = strings.TrimSuffix(beego.AppConfig.DefaultString("baseurl", ""), "/") + attach.HttpPath
}
li := fmt.Sprintf("<li><a href=\"%s\" target=\"_blank\" title=\"%s\">%s</a></li>", attach.HttpPath, attach.FileName, attach.FileName)
@ -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

@ -23,14 +23,14 @@ type DocumentHistory struct {
}
type DocumentHistorySimpleResult struct {
HistoryId int `json:"history_id"`
ActionName string `json:"action_name"`
MemberId int `json:"member_id"`
Account string `json:"account"`
ModifyAt int `json:"modify_at"`
ModifyName string `json:"modify_name"`
ModifyTime time.Time `json:"modify_time"`
Version int64 `json:"version"`
HistoryId int `json:"history_id"`
ActionName string `json:"action_name"`
MemberId int `json:"member_id"`
Account string `json:"account"`
ModifyAt int `json:"modify_at"`
ModifyName string `json:"modify_name"`
ModifyTime time.Time `json:"modify_time"`
Version int64 `json:"version"`
}
// TableName 获取对应数据库表名.
@ -50,12 +50,13 @@ func (m *DocumentHistory) TableNameWithPrefix() string {
func NewDocumentHistory() *DocumentHistory {
return &DocumentHistory{}
}
func (m *DocumentHistory) Find(id int) (*DocumentHistory,error) {
func (m *DocumentHistory) Find(id int) (*DocumentHistory, error) {
o := orm.NewOrm()
err := o.QueryTable(m.TableNameWithPrefix()).Filter("history_id",id).One(m)
err := o.QueryTable(m.TableNameWithPrefix()).Filter("history_id", id).One(m)
return m,err
return m, err
}
//清空指定文档的历史.
func (m *DocumentHistory) Clear(doc_id int) error {
o := orm.NewOrm()
@ -66,19 +67,19 @@ func (m *DocumentHistory) Clear(doc_id int) error {
}
//删除历史.
func (m *DocumentHistory) Delete(history_id,doc_id int) error {
func (m *DocumentHistory) Delete(history_id, doc_id int) error {
o := orm.NewOrm()
_, err := o.QueryTable(m.TableNameWithPrefix()).Filter("history_id",history_id).Filter("document_id",doc_id).Delete()
_, err := o.QueryTable(m.TableNameWithPrefix()).Filter("history_id", history_id).Filter("document_id", doc_id).Delete()
return err
}
//恢复指定历史的文档.
func (m *DocumentHistory) Restore(history_id,doc_id,uid int) error {
func (m *DocumentHistory) Restore(history_id, doc_id, uid int) error {
o := orm.NewOrm()
err := o.QueryTable(m.TableNameWithPrefix()).Filter("history_id", history_id).Filter("document_id",doc_id).One(m)
err := o.QueryTable(m.TableNameWithPrefix()).Filter("history_id", history_id).Filter("document_id", doc_id).One(m)
if err != nil {
return err
@ -113,17 +114,18 @@ func (m *DocumentHistory) Restore(history_id,doc_id,uid int) error {
return err
}
func (m *DocumentHistory) InsertOrUpdate() (history *DocumentHistory,err error) {
func (m *DocumentHistory) InsertOrUpdate() (history *DocumentHistory, err error) {
o := orm.NewOrm()
history = m
if m.HistoryId > 0 {
_,err = o.Update(m)
}else{
_,err = o.Insert(m)
_, err = o.Update(m)
} else {
_, err = o.Insert(m)
}
return
}
//分页查询指定文档的历史.
func (m *DocumentHistory) FindToPager(doc_id, page_index, page_size int) (docs []*DocumentHistorySimpleResult, totalCount int, err error) {
@ -139,7 +141,7 @@ LEFT JOIN md_members AS m1 ON history.member_id = m1.member_id
LEFT JOIN md_members AS m2 ON history.modify_at = m2.member_id
WHERE history.document_id = ? ORDER BY history.history_id DESC LIMIT ?,?;`
_, err = o.Raw(sql,doc_id,offset,page_size).QueryRows(&docs)
_, err = o.Raw(sql, doc_id, offset, page_size).QueryRows(&docs)
if err != nil {
return

View File

@ -1,48 +1,49 @@
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 {
DocumentId int `json:"id"`
DocumentName string `json:"text"`
ParentId interface{} `json:"parent"`
Identify string `json:"identify"`
BookIdentify string `json:"-"`
Version int64 `json:"version"`
State *DocumentSelected `json:"state,omitempty"`
DocumentId int `json:"id"`
DocumentName string `json:"text"`
ParentId interface{} `json:"parent"`
Identify string `json:"identify"`
BookIdentify string `json:"-"`
Version int64 `json:"version"`
State *DocumentSelected `json:"state,omitempty"`
}
type DocumentSelected struct {
Selected bool `json:"selected"`
Opened bool `json:"opened"`
Selected bool `json:"selected"`
Opened bool `json:"opened"`
}
//获取项目的文档树状结构
func (m *Document) FindDocumentTree(book_id int) ([]*DocumentTree,error){
func (m *Document) FindDocumentTree(book_id int) ([]*DocumentTree, error) {
o := orm.NewOrm()
trees := make([]*DocumentTree,0)
trees := make([]*DocumentTree, 0)
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
return trees, err
}
book,_ := NewBook().Find(book_id)
book, _ := NewBook().Find(book_id)
trees = make([]*DocumentTree,count)
trees = make([]*DocumentTree, count)
for index,item := range docs {
for index, item := range docs {
tree := &DocumentTree{}
if index == 0{
tree.State = &DocumentSelected{ Selected: true, Opened: true }
if index == 0 {
tree.State = &DocumentSelected{Selected: true, Opened: true}
}
tree.DocumentId = item.DocumentId
tree.Identify = item.Identify
@ -50,7 +51,7 @@ func (m *Document) FindDocumentTree(book_id int) ([]*DocumentTree,error){
tree.BookIdentify = book.Identify
if item.ParentId > 0 {
tree.ParentId = item.ParentId
}else{
} else {
tree.ParentId = "#"
}
@ -59,41 +60,41 @@ func (m *Document) FindDocumentTree(book_id int) ([]*DocumentTree,error){
trees[index] = tree
}
return trees,nil
return trees, nil
}
func (m *Document) CreateDocumentTreeForHtml(book_id, selected_id int) (string,error) {
trees,err := m.FindDocumentTree(book_id)
func (m *Document) CreateDocumentTreeForHtml(book_id, selected_id int) (string, error) {
trees, err := m.FindDocumentTree(book_id)
if err != nil {
return "",err
return "", err
}
parent_id := getSelectedNode(trees,selected_id)
parent_id := getSelectedNode(trees, selected_id)
buf := bytes.NewBufferString("")
getDocumentTree(trees,0,selected_id,parent_id,buf)
getDocumentTree(trees, 0, selected_id, parent_id, buf)
return buf.String(), nil
return buf.String(),nil
}
//使用递归的方式获取指定ID的顶级ID
func getSelectedNode(array []*DocumentTree, parent_id int) int {
for _,item := range array {
if _,ok := item.ParentId.(string); ok && item.DocumentId == parent_id {
for _, item := range array {
if _, ok := item.ParentId.(string); ok && item.DocumentId == parent_id {
return item.DocumentId
}else if pid,ok := item.ParentId.(int); ok && item.DocumentId == parent_id{
return getSelectedNode(array,pid)
} else if pid, ok := item.ParentId.(int); ok && item.DocumentId == parent_id {
return getSelectedNode(array, pid)
}
}
return 0
return 0
}
func getDocumentTree(array []*DocumentTree,parent_id int,selected_id int,selected_parent_id int,buf *bytes.Buffer) {
func getDocumentTree(array []*DocumentTree, parent_id int, selected_id int, selected_parent_id int, buf *bytes.Buffer) {
buf.WriteString("<ul>")
for _,item := range array {
for _, item := range array {
pid := 0
if p, ok := item.ParentId.(int); ok {
@ -138,14 +139,3 @@ func getDocumentTree(array []*DocumentTree,parent_id int,selected_id int,selecte
}
buf.WriteString("</ul>")
}

View File

@ -5,16 +5,16 @@ import "errors"
var (
// ErrMemberNoExist 用户不存在.
ErrMemberNoExist = errors.New("用户不存在")
ErrMemberExist = errors.New("用户已存在")
ErrMemberDisabled = errors.New("用户被禁用")
ErrMemberEmailEmpty = errors.New("用户邮箱不能为空")
ErrMemberEmailExist = errors.New("用户邮箱已被使用")
ErrMemberDescriptionTooLong = errors.New("用户描述必须小于500字")
ErrMemberEmailFormatError = errors.New("邮箱格式不正确")
ErrMemberNoExist = errors.New("用户不存在")
ErrMemberExist = errors.New("用户已存在")
ErrMemberDisabled = errors.New("用户被禁用")
ErrMemberEmailEmpty = errors.New("用户邮箱不能为空")
ErrMemberEmailExist = errors.New("用户邮箱已被使用")
ErrMemberDescriptionTooLong = errors.New("用户描述必须小于500字")
ErrMemberEmailFormatError = errors.New("邮箱格式不正确")
ErrMemberPasswordFormatError = errors.New("密码必须在6-50个字符之间")
ErrMemberAccountFormatError = errors.New("账号只能由英文字母数字组成且在3-50个字符")
ErrMemberRoleError = errors.New("用户权限不正确")
ErrMemberAccountFormatError = errors.New("账号只能由英文字母数字组成且在3-50个字符")
ErrMemberRoleError = errors.New("用户权限不正确")
// ErrorMemberPasswordError 密码错误.
ErrorMemberPasswordError = errors.New("用户密码错误")
//ErrorMemberAuthMethodInvalid 不支持此认证方式

View File

@ -1,35 +1,36 @@
package models
import (
"github.com/lifei6671/mindoc/conf"
"github.com/astaxie/beego/orm"
"github.com/lifei6671/mindoc/conf"
"strings"
)
type Label struct {
LabelId int `orm:"column(label_id);pk;auto;unique;" json:"label_id"`
LabelName string `orm:"column(label_name);size(50);unique" json:"label_name"`
BookNumber int `orm:"column(book_number)" json:"book_number"`
LabelId int `orm:"column(label_id);pk;auto;unique;" json:"label_id"`
LabelName string `orm:"column(label_name);size(50);unique" json:"label_name"`
BookNumber int `orm:"column(book_number)" json:"book_number"`
}
// TableName 获取对应数据库表名.
func (m *Label) TableName() string {
return "label"
}
// TableEngine 获取数据使用的引擎.
func (m *Label) TableEngine() string {
return "INNODB"
}
func (m *Label)TableNameWithPrefix() string {
return conf.GetDatabasePrefix() + m.TableName()
func (m *Label) TableNameWithPrefix() string {
return conf.GetDatabasePrefix() + m.TableName()
}
func NewLabel() *Label {
return &Label{}
}
func (m *Label) FindFirst(field string, value interface{}) (*Label,error){
func (m *Label) FindFirst(field string, value interface{}) (*Label, error) {
o := orm.NewOrm()
err := o.QueryTable(m.TableNameWithPrefix()).Filter(field, value).One(m)
@ -41,27 +42,27 @@ func (m *Label) FindFirst(field string, value interface{}) (*Label,error){
func (m *Label) InsertOrUpdate(labelName string) error {
o := orm.NewOrm()
err := o.QueryTable(m.TableNameWithPrefix()).Filter("label_name",labelName).One(m)
err := o.QueryTable(m.TableNameWithPrefix()).Filter("label_name", labelName).One(m)
if err != nil && err != orm.ErrNoRows {
return err
}
count,_ := o.QueryTable(NewBook().TableNameWithPrefix()).Filter("label__icontains",labelName).Count()
count, _ := o.QueryTable(NewBook().TableNameWithPrefix()).Filter("label__icontains", labelName).Count()
m.BookNumber = int(count)
m.LabelName = labelName
if err == orm.ErrNoRows {
err = nil
m.LabelName = labelName
_,err = o.Insert(m)
}else{
_,err = o.Update(m)
_, err = o.Insert(m)
} else {
_, err = o.Update(m)
}
return err
}
//批量插入或更新标签.
func (m *Label) InsertOrUpdateMulti(labels string) {
if labels != "" {
func (m *Label) InsertOrUpdateMulti(labels string) {
if labels != "" {
labelArray := strings.Split(labels, ",")
for _, label := range labelArray {
@ -73,10 +74,10 @@ func (m *Label) InsertOrUpdateMulti(labels string) {
}
//分页查找标签.
func (m *Label) FindToPager(pageIndex, pageSize int) (labels []*Label,totalCount int,err error) {
func (m *Label) FindToPager(pageIndex, pageSize int) (labels []*Label, totalCount int, err error) {
o := orm.NewOrm()
count,err := o.QueryTable(m.TableNameWithPrefix()).Count()
count, err := o.QueryTable(m.TableNameWithPrefix()).Count()
if err != nil {
return
@ -85,8 +86,7 @@ func (m *Label) FindToPager(pageIndex, pageSize int) (labels []*Label,totalCount
offset := (pageIndex - 1) * pageSize
_,err = o.QueryTable(m.TableNameWithPrefix()).OrderBy("-book_number").Offset(offset).Limit(pageSize).All(&labels)
_, err = o.QueryTable(m.TableNameWithPrefix()).OrderBy("-book_number").Offset(offset).Limit(pageSize).All(&labels)
return
}

View File

@ -1,38 +1,39 @@
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 }
var loggerQueue = &logQueue{channel: make(chan *Logger, 100), isRuning: 0}
type logQueue struct {
channel chan *Logger
channel chan *Logger
isRuning int32
}
// Logger struct .
type Logger struct {
LoggerId int64 `orm:"pk;auto;unique;column(log_id)" json:"log_id"`
MemberId int `orm:"column(member_id);type(int)" json:"member_id"`
LoggerId int64 `orm:"pk;auto;unique;column(log_id)" json:"log_id"`
MemberId int `orm:"column(member_id);type(int)" json:"member_id"`
// 日志类别operate 操作日志/ system 系统日志/ exception 异常日志 / document 文档操作日志
Category string `orm:"column(category);size(255);default(operate)" json:"category"`
Content string `orm:"column(content);type(text)" json:"content"`
OriginalData string `orm:"column(original_data);type(text)" json:"original_data"`
PresentData string `orm:"column(present_data);type(text)" json:"present_data"`
CreateTime time.Time `orm:"type(datetime);column(create_time);auto_now_add" json:"create_time"`
UserAgent string `orm:"column(user_agent);size(500)" json:"user_agent"`
IPAddress string `orm:"column(ip_address);size(255)" json:"ip_address"`
Category string `orm:"column(category);size(255);default(operate)" json:"category"`
Content string `orm:"column(content);type(text)" json:"content"`
OriginalData string `orm:"column(original_data);type(text)" json:"original_data"`
PresentData string `orm:"column(present_data);type(text)" json:"present_data"`
CreateTime time.Time `orm:"type(datetime);column(create_time);auto_now_add" json:"create_time"`
UserAgent string `orm:"column(user_agent);size(500)" json:"user_agent"`
IPAddress string `orm:"column(ip_address);size(255)" json:"ip_address"`
}
// TableName 获取对应数据库表名.
func (m *Logger) TableName() string {
return "logs"
}
// TableEngine 获取数据使用的引擎.
func (m *Logger) TableEngine() string {
return "INNODB"
@ -57,32 +58,19 @@ func (m *Logger) Add() error {
}
loggerQueue.channel <- m
if atomic.LoadInt32(&(loggerQueue.isRuning)) <= 0 {
atomic.AddInt32(&(loggerQueue.isRuning),1)
atomic.AddInt32(&(loggerQueue.isRuning), 1)
go addLoggerAsync()
}
return nil
}
func addLoggerAsync() {
defer atomic.AddInt32(&(loggerQueue.isRuning),-1)
func addLoggerAsync() {
defer atomic.AddInt32(&(loggerQueue.isRuning), -1)
o := orm.NewOrm()
for{
logger := <- loggerQueue.channel
for {
logger := <-loggerQueue.channel
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 {
@ -108,7 +109,7 @@ func (m *Member) ldapLogin(account string, password string) (*Member, error) {
beego.AppConfig.String("ldap_base"),
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
//修改objectClass通过配置文件获取值
fmt.Sprintf("(&(%s)(%s=%s))",beego.AppConfig.String("ldap_filter"), beego.AppConfig.String("ldap_attribute"), account),
fmt.Sprintf("(&(%s)(%s=%s))", beego.AppConfig.String("ldap_filter"), beego.AppConfig.String("ldap_attribute"), account),
[]string{"dn", "mail"},
nil,
)
@ -279,7 +280,7 @@ func (m *Member) Valid(is_hash_password bool) error {
return ErrMemberEmailEmpty
}
//用户描述必须小于500字
if strings.Count(m.Description,"") > 500 {
if strings.Count(m.Description, "") > 500 {
return ErrMemberDescriptionTooLong
}
if m.Role != conf.MemberGeneralRole && m.Role != conf.MemberSuperRole && m.Role != conf.MemberAdminRole {
@ -289,48 +290,47 @@ func (m *Member) Valid(is_hash_password bool) error {
m.Status = 0
}
//邮箱格式校验
if ok,err := regexp.MatchString(conf.RegexpEmail,m.Email); !ok || err != nil || m.Email == "" {
if ok, err := regexp.MatchString(conf.RegexpEmail, m.Email); !ok || err != nil || m.Email == "" {
return ErrMemberEmailFormatError
}
//如果是未加密密码,需要校验密码格式
if !is_hash_password {
if l := strings.Count(m.Password,"") ; m.Password == "" || l > 50 || l < 6{
if l := strings.Count(m.Password, ""); m.Password == "" || l > 50 || l < 6 {
return ErrMemberPasswordFormatError
}
}
//校验邮箱是否呗使用
if member,err := NewMember().FindByFieldFirst("email",m.Account); err == nil && member.MemberId > 0 {
if member, err := NewMember().FindByFieldFirst("email", m.Account); err == nil && member.MemberId > 0 {
if m.MemberId > 0 && m.MemberId != member.MemberId {
return ErrMemberEmailExist
}
if m.MemberId <= 0{
return ErrMemberEmailExist
if m.MemberId <= 0 {
return ErrMemberEmailExist
}
}
if m.MemberId > 0{
if m.MemberId > 0 {
//校验用户是否存在
if _,err := NewMember().Find(m.MemberId);err != nil {
if _, err := NewMember().Find(m.MemberId); err != nil {
return err
}
}else{
} else {
//校验账号格式是否正确
if ok,err := regexp.MatchString(conf.RegexpAccount,m.Account); m.Account == "" || !ok || err != nil {
if ok, err := regexp.MatchString(conf.RegexpAccount, m.Account); m.Account == "" || !ok || err != nil {
return ErrMemberAccountFormatError
}
//校验账号是否被使用
if member,err := NewMember().FindByAccount(m.Account); err == nil && member.MemberId > 0 {
if member, err := NewMember().FindByAccount(m.Account); err == nil && member.MemberId > 0 {
return ErrMemberExist
}
}
return nil
}
//删除一个用户.
func (m *Member) Delete(oldId int,newId int) error {
func (m *Member) Delete(oldId int, newId int) error {
o := orm.NewOrm()
err := o.Begin()
@ -339,39 +339,39 @@ func (m *Member) Delete(oldId int,newId int) error {
return err
}
_,err = o.Raw("DELETE FROM md_members WHERE member_id = ?",oldId).Exec()
_, err = o.Raw("DELETE FROM md_members WHERE member_id = ?", oldId).Exec()
if err != nil {
o.Rollback()
return err
}
_,err = o.Raw("UPDATE md_attachment SET `create_at` = ? WHERE `create_at` = ?",newId,oldId).Exec()
_, err = o.Raw("UPDATE md_attachment SET `create_at` = ? WHERE `create_at` = ?", newId, oldId).Exec()
if err != nil {
o.Rollback()
return err
}
_,err = o.Raw("UPDATE md_books SET member_id = ? WHERE member_id = ?",newId,oldId).Exec()
_, err = o.Raw("UPDATE md_books SET member_id = ? WHERE member_id = ?", newId, oldId).Exec()
if err != nil {
o.Rollback()
return err
}
_,err = o.Raw("UPDATE md_document_history SET member_id=? WHERE member_id = ?",newId,oldId).Exec()
_, err = o.Raw("UPDATE md_document_history SET member_id=? WHERE member_id = ?", newId, oldId).Exec()
if err != nil {
o.Rollback()
return err
}
_,err = o.Raw("UPDATE md_document_history SET modify_at=? WHERE modify_at = ?",newId,oldId).Exec()
_, err = o.Raw("UPDATE md_document_history SET modify_at=? WHERE modify_at = ?", newId, oldId).Exec()
if err != nil {
o.Rollback()
return err
}
_,err = o.Raw("UPDATE md_documents SET member_id = ? WHERE member_id = ?;",newId,oldId).Exec()
_, err = o.Raw("UPDATE md_documents SET member_id = ? WHERE member_id = ?;", newId, oldId).Exec()
if err != nil {
o.Rollback()
return err
}
_,err = o.Raw("UPDATE md_documents SET modify_at = ? WHERE modify_at = ?",newId,oldId).Exec()
_, err = o.Raw("UPDATE md_documents SET modify_at = ? WHERE modify_at = ?", newId, oldId).Exec()
if err != nil {
o.Rollback()
return err
@ -386,53 +386,37 @@ 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 {
for _, relationship := range relationship_list {
//如果存在创始人,则删除
if relationship.RoleId == 0 {
rel := NewRelationship()
err = o.QueryTable(relationship.TableNameWithPrefix()).Filter("book_id",relationship.BookId).Filter("member_id",newId).One(rel)
err = o.QueryTable(relationship.TableNameWithPrefix()).Filter("book_id", relationship.BookId).Filter("member_id", newId).One(rel)
if err == nil {
if _,err := o.Delete(relationship) ; err != nil{
if _, err := o.Delete(relationship); err != nil {
beego.Error(err)
}
relationship.RelationshipId = rel.RelationshipId
}
relationship.MemberId = newId
relationship.RoleId = 0
if _,err := o.Update(relationship) ; err != nil{
if _, err := o.Update(relationship); err != nil {
beego.Error(err)
}
}else{
if _,err := o.Delete(relationship) ; err != nil{
} else {
if _, err := o.Delete(relationship); err != nil {
beego.Error(err)
}
}
}
}
if err = o.Commit();err != nil {
if err = o.Commit(); err != nil {
o.Rollback()
return err
}
return nil
}

View File

@ -1,27 +1,27 @@
package models
import (
"time"
"github.com/astaxie/beego/orm"
"github.com/lifei6671/mindoc/conf"
"time"
)
type MemberRelationshipResult struct {
MemberId int `json:"member_id"`
Account string `json:"account"`
Description string `json:"description"`
Email string `json:"email"`
Phone string `json:"phone"`
Avatar string `json:"avatar"`
Role int `json:"role"` //用户角色0 管理员/ 1 普通用户
Status int `json:"status"` //用户状态0 正常/1 禁用
CreateTime time.Time `json:"create_time"`
CreateAt int `json:"create_at"`
RelationshipId int `json:"relationship_id"`
BookId int `json:"book_id"`
MemberId int `json:"member_id"`
Account string `json:"account"`
Description string `json:"description"`
Email string `json:"email"`
Phone string `json:"phone"`
Avatar string `json:"avatar"`
Role int `json:"role"` //用户角色0 管理员/ 1 普通用户
Status int `json:"status"` //用户状态0 正常/1 禁用
CreateTime time.Time `json:"create_time"`
CreateAt int `json:"create_at"`
RelationshipId int `json:"relationship_id"`
BookId int `json:"book_id"`
// RoleId 角色0 创始人(创始人不能被移除) / 1 管理员/2 编辑者/3 观察者
RoleId int `json:"role_id"`
RoleName string `json:"role_name"`
RoleId int `json:"role_id"`
RoleName string `json:"role_name"`
}
func NewMemberRelationshipResult() *MemberRelationshipResult {
@ -43,18 +43,18 @@ func (m *MemberRelationshipResult) FromMember(member *Member) *MemberRelationshi
return m
}
func (m *MemberRelationshipResult) ResolveRoleName () *MemberRelationshipResult {
func (m *MemberRelationshipResult) ResolveRoleName() *MemberRelationshipResult {
if m.RoleId == conf.BookAdmin {
m.RoleName = "管理者"
}else if m.RoleId == conf.BookEditor {
} else if m.RoleId == conf.BookEditor {
m.RoleName = "编辑者"
}else if m.RoleId == conf.BookObserver {
} else if m.RoleId == conf.BookObserver {
m.RoleName = "观察者"
}
return m
}
func (m *MemberRelationshipResult) FindForUsersByBookId(book_id ,pageIndex, pageSize int) ([]*MemberRelationshipResult,int,error) {
func (m *MemberRelationshipResult) FindForUsersByBookId(book_id, pageIndex, pageSize int) ([]*MemberRelationshipResult, int, error) {
o := orm.NewOrm()
var members []*MemberRelationshipResult
@ -65,28 +65,22 @@ func (m *MemberRelationshipResult) FindForUsersByBookId(book_id ,pageIndex, page
var total_count int
err := o.Raw(sql2,book_id).QueryRow(&total_count)
err := o.Raw(sql2, book_id).QueryRow(&total_count)
if err != nil {
return members,0,err
return members, 0, err
}
offset := (pageIndex-1) * pageSize
offset := (pageIndex - 1) * pageSize
_,err = o.Raw(sql1,book_id,offset,pageSize).QueryRows(&members)
_, err = o.Raw(sql1, book_id, offset, pageSize).QueryRows(&members)
if err != nil {
return members,0,err
return members, 0, err
}
for _,item := range members {
for _, item := range members {
item.ResolveRoleName()
}
return members,total_count,nil
return members, total_count, nil
}

View File

@ -1,66 +1,66 @@
package models
import (
"time"
"github.com/lifei6671/mindoc/conf"
"github.com/astaxie/beego/orm"
"github.com/lifei6671/mindoc/conf"
"time"
)
type MemberToken struct {
TokenId int `orm:"column(token_id);pk;auto;unique" json:"token_id"`
MemberId int `orm:"column(member_id);type(int)" json:"member_id"`
Token string `orm:"column(token);size(150);index" json:"token"`
Email string `orm:"column(email);size(255)" json:"email"`
IsValid bool `orm:"column(is_valid)" json:"is_valid"`
ValidTime time.Time `orm:"column(valid_time);null" json:"valid_time"`
SendTime time.Time `orm:"column(send_time);auto_now_add;type(datetime)" json:"send_time"`
TokenId int `orm:"column(token_id);pk;auto;unique" json:"token_id"`
MemberId int `orm:"column(member_id);type(int)" json:"member_id"`
Token string `orm:"column(token);size(150);index" json:"token"`
Email string `orm:"column(email);size(255)" json:"email"`
IsValid bool `orm:"column(is_valid)" json:"is_valid"`
ValidTime time.Time `orm:"column(valid_time);null" json:"valid_time"`
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"
}
func (m *MemberToken)TableNameWithPrefix() string {
return conf.GetDatabasePrefix() + m.TableName()
func (m *MemberToken) TableNameWithPrefix() string {
return conf.GetDatabasePrefix() + m.TableName()
}
func NewMemberToken() *MemberToken {
return &MemberToken{}
}
func (m *MemberToken) InsertOrUpdate() (*MemberToken,error){
func (m *MemberToken) InsertOrUpdate() (*MemberToken, error) {
o := orm.NewOrm()
if m.TokenId > 0 {
_,err := o.Update(m)
return m,err
_, err := o.Update(m)
return m, err
}
_,err := o.Insert(m)
_, err := o.Insert(m)
return m,err
return m, err
}
func (m *MemberToken) FindByFieldFirst(field string,value interface{}) (*MemberToken,error) {
func (m *MemberToken) FindByFieldFirst(field string, value interface{}) (*MemberToken, error) {
o := orm.NewOrm()
err := o.QueryTable(m.TableNameWithPrefix()).Filter(field,value).OrderBy("-token_id").One(m)
err := o.QueryTable(m.TableNameWithPrefix()).Filter(field, value).OrderBy("-token_id").One(m)
return m,err
return m, err
}
func (m *MemberToken) FindSendCount(mail string,start_time time.Time,end_time time.Time) (int ,error) {
func (m *MemberToken) FindSendCount(mail string, start_time time.Time, end_time time.Time) (int, error) {
o := orm.NewOrm()
c,err := o.QueryTable(m.TableNameWithPrefix()).Filter("send_time__gte",start_time.Format("2006-01-02 15:04:05")).Filter("send_time__lte",end_time.Format("2006-01-02 15:04:05")).Count()
c, err := o.QueryTable(m.TableNameWithPrefix()).Filter("send_time__gte", start_time.Format("2006-01-02 15:04:05")).Filter("send_time__lte", end_time.Format("2006-01-02 15:04:05")).Count()
if err != nil {
return 0,err
return 0, err
}
return int(c),nil
}
return int(c), nil
}

View File

@ -1,18 +1,18 @@
package models
import (
"time"
"github.com/lifei6671/mindoc/conf"
"github.com/astaxie/beego/orm"
"github.com/lifei6671/mindoc/conf"
"time"
)
type Migration struct {
MigrationId int `orm:"column(migration_id);pk;auto;unique;" json:"migration_id"`
Name string `orm:"column(name);size(500)" json:"name"`
Statements string `orm:"column(statements);type(text);null" json:"statements"`
Status string `orm:"column(status);default(update)" json:"status"`
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
Version int64 `orm:"type(bigint);column(version);unique" json:"version"`
MigrationId int `orm:"column(migration_id);pk;auto;unique;" json:"migration_id"`
Name string `orm:"column(name);size(500)" json:"name"`
Statements string `orm:"column(statements);type(text);null" json:"statements"`
Status string `orm:"column(status);default(update)" json:"status"`
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
Version int64 `orm:"type(bigint);column(version);unique" json:"version"`
}
// TableName 获取对应数据库表名.
@ -33,10 +33,10 @@ func NewMigration() *Migration {
return &Migration{}
}
func (m *Migration) FindFirst() (*Migration,error) {
func (m *Migration) FindFirst() (*Migration, error) {
o := orm.NewOrm()
err := o.QueryTable(m.TableNameWithPrefix()).OrderBy("-migration_id").One(m)
return m,err
}
return m, err
}

View File

@ -5,147 +5,145 @@ import (
"github.com/lifei6671/mindoc/conf"
)
// Option struct .
type Option struct {
OptionId int `orm:"column(option_id);pk;auto;unique;" json:"option_id"`
OptionTitle string `orm:"column(option_title);size(500)" json:"option_title"`
OptionName string `orm:"column(option_name);unique;size(80)" json:"option_name"`
OptionValue string `orm:"column(option_value);type(text);null" json:"option_value"`
Remark string `orm:"column(remark);type(text);null" json:"remark"`
OptionId int `orm:"column(option_id);pk;auto;unique;" json:"option_id"`
OptionTitle string `orm:"column(option_title);size(500)" json:"option_title"`
OptionName string `orm:"column(option_name);unique;size(80)" json:"option_name"`
OptionValue string `orm:"column(option_value);type(text);null" json:"option_value"`
Remark string `orm:"column(remark);type(text);null" json:"remark"`
}
// TableName 获取对应数据库表名.
func (m *Option) TableName() string {
return "options"
}
// TableEngine 获取数据使用的引擎.
func (m *Option) TableEngine() string {
return "INNODB"
}
func (m *Option)TableNameWithPrefix() string {
return conf.GetDatabasePrefix() + m.TableName()
func (m *Option) TableNameWithPrefix() string {
return conf.GetDatabasePrefix() + m.TableName()
}
func NewOption() *Option {
func NewOption() *Option {
return &Option{}
}
func (p *Option) Find(id int) (*Option,error) {
func (p *Option) Find(id int) (*Option, error) {
o := orm.NewOrm()
p.OptionId = id
if err := o.Read(p);err != nil {
return p,err
if err := o.Read(p); err != nil {
return p, err
}
return p,nil
return p, nil
}
func (p *Option) FindByKey(key string) (*Option,error) {
func (p *Option) FindByKey(key string) (*Option, error) {
o := orm.NewOrm()
p.OptionName = key
if err := o.Read(p);err != nil {
return p,err
if err := o.Read(p); err != nil {
return p, err
}
return p,nil
return p, nil
}
func GetOptionValue(key, def string) string {
if option,err := NewOption().FindByKey(key); err == nil {
if option, err := NewOption().FindByKey(key); err == nil {
return option.OptionValue
}
return def
}
func (p *Option) InsertOrUpdate() error {
func (p *Option) InsertOrUpdate() error {
o := orm.NewOrm()
var err error
if p.OptionId > 0 || o.QueryTable(p.TableNameWithPrefix()).Filter("option_name",p.OptionName).Exist() {
_,err = o.Update(p)
}else{
_,err = o.Insert(p)
if p.OptionId > 0 || o.QueryTable(p.TableNameWithPrefix()).Filter("option_name", p.OptionName).Exist() {
_, err = o.Update(p)
} else {
_, err = o.Insert(p)
}
return err
}
func (p *Option) InsertMulti(option... Option ) (error){
func (p *Option) InsertMulti(option ...Option) error {
o := orm.NewOrm()
_,err := o.InsertMulti(len(option),option)
_, err := o.InsertMulti(len(option), option)
return err
}
func (p *Option) All() ([]*Option,error) {
func (p *Option) All() ([]*Option, error) {
o := orm.NewOrm()
var options []*Option
_,err := o.QueryTable(p.TableNameWithPrefix()).All(&options)
_, err := o.QueryTable(p.TableNameWithPrefix()).All(&options)
if err != nil {
return options,err
return options, err
}
return options,nil
return options, nil
}
func (m *Option) Init() error {
o := orm.NewOrm()
if !o.QueryTable(m.TableNameWithPrefix()).Filter("option_name","ENABLED_REGISTER").Exist() {
if !o.QueryTable(m.TableNameWithPrefix()).Filter("option_name", "ENABLED_REGISTER").Exist() {
option := NewOption()
option.OptionValue = "false"
option.OptionName = "ENABLED_REGISTER"
option.OptionTitle = "是否启用注册"
if _,err := o.Insert(option);err != nil {
if _, err := o.Insert(option); err != nil {
return err
}
}
if !o.QueryTable(m.TableNameWithPrefix()).Filter("option_name","ENABLE_DOCUMENT_HISTORY").Exist() {
if !o.QueryTable(m.TableNameWithPrefix()).Filter("option_name", "ENABLE_DOCUMENT_HISTORY").Exist() {
option := NewOption()
option.OptionValue = "true"
option.OptionName = "ENABLE_DOCUMENT_HISTORY"
option.OptionTitle = "是否启用文档历史"
if _,err := o.Insert(option);err != nil {
if _, err := o.Insert(option); err != nil {
return err
}
}
if !o.QueryTable(m.TableNameWithPrefix()).Filter("option_name","ENABLED_CAPTCHA").Exist() {
if !o.QueryTable(m.TableNameWithPrefix()).Filter("option_name", "ENABLED_CAPTCHA").Exist() {
option := NewOption()
option.OptionValue = "true"
option.OptionName = "ENABLED_CAPTCHA"
option.OptionTitle = "是否启用验证码"
if _,err := o.Insert(option);err != nil {
if _, err := o.Insert(option); err != nil {
return err
}
}
if !o.QueryTable(m.TableNameWithPrefix()).Filter("option_name","ENABLE_ANONYMOUS").Exist() {
if !o.QueryTable(m.TableNameWithPrefix()).Filter("option_name", "ENABLE_ANONYMOUS").Exist() {
option := NewOption()
option.OptionValue = "false"
option.OptionName = "ENABLE_ANONYMOUS"
option.OptionTitle = "启用匿名访问"
if _,err := o.Insert(option);err != nil {
if _, err := o.Insert(option); err != nil {
return err
}
}
if !o.QueryTable(m.TableNameWithPrefix()).Filter("option_name","SITE_NAME").Exist() {
if !o.QueryTable(m.TableNameWithPrefix()).Filter("option_name", "SITE_NAME").Exist() {
option := NewOption()
option.OptionValue = "MinDoc"
option.OptionName = "SITE_NAME"
option.OptionTitle = "站点名称"
if _,err := o.Insert(option);err != nil {
if _, err := o.Insert(option); err != nil {
return err
}
}
return nil
}
}

View File

@ -1,21 +1,20 @@
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 {
RelationshipId int `orm:"pk;auto;unique;column(relationship_id)" json:"relationship_id"`
MemberId int `orm:"column(member_id);type(int)" json:"member_id"`
BookId int `orm:"column(book_id);type(int)" json:"book_id"`
RelationshipId int `orm:"pk;auto;unique;column(relationship_id)" json:"relationship_id"`
MemberId int `orm:"column(member_id);type(int)" json:"member_id"`
BookId int `orm:"column(book_id);type(int)" json:"book_id"`
// RoleId 角色0 创始人(创始人不能被移除) / 1 管理员/2 编辑者/3 观察者
RoleId int `orm:"column(role_id);type(int)" json:"role_id"`
RoleId int `orm:"column(role_id);type(int)" json:"role_id"`
}
// TableName 获取对应数据库表名.
func (m *Relationship) TableName() string {
return "relationship"
@ -40,97 +39,97 @@ func NewRelationship() *Relationship {
return &Relationship{}
}
func (m *Relationship) Find(id int) (*Relationship,error) {
func (m *Relationship) Find(id int) (*Relationship, error) {
o := orm.NewOrm()
err := o.QueryTable(m.TableNameWithPrefix()).Filter("relationship_id",id).One(m)
return m,err
err := o.QueryTable(m.TableNameWithPrefix()).Filter("relationship_id", id).One(m)
return m, err
}
//查询指定项目的创始人.
func (m *Relationship) FindFounder(book_id int) (*Relationship,error) {
func (m *Relationship) FindFounder(book_id int) (*Relationship, error) {
o := orm.NewOrm()
err := o.QueryTable(m.TableNameWithPrefix()).Filter("book_id",book_id).Filter("role_id",0).One(m)
err := o.QueryTable(m.TableNameWithPrefix()).Filter("book_id", book_id).Filter("role_id", 0).One(m)
return m,err
return m, err
}
func (m *Relationship) UpdateRoleId(book_id,member_id, role_id int) (*Relationship,error) {
func (m *Relationship) UpdateRoleId(book_id, member_id, role_id int) (*Relationship, error) {
o := orm.NewOrm()
book := NewBook()
book.BookId = book_id
if err := o.Read(book); err != nil {
logs.Error("UpdateRoleId => ", err)
return m,errors.New("项目不存在")
return m, errors.New("项目不存在")
}
err := o.QueryTable(m.TableNameWithPrefix()).Filter("member_id",member_id).Filter("book_id",book_id).One(m)
err := o.QueryTable(m.TableNameWithPrefix()).Filter("member_id", member_id).Filter("book_id", book_id).One(m)
if err == orm.ErrNoRows {
m = NewRelationship()
m.BookId = book_id
m.MemberId = member_id
m.RoleId = role_id
}else if err != nil {
return m,err
}else if m.RoleId == conf.BookFounder{
return m,errors.New("不能变更创始人的权限")
} else if err != nil {
return m, err
} else if m.RoleId == conf.BookFounder {
return m, errors.New("不能变更创始人的权限")
}
m.RoleId = role_id
if m.RelationshipId > 0 {
_,err = o.Update(m)
}else{
_,err = o.Insert(m)
_, err = o.Update(m)
} else {
_, err = o.Insert(m)
}
return m,err
return m, err
}
func (m *Relationship) FindForRoleId(book_id ,member_id int) (int,error) {
func (m *Relationship) FindForRoleId(book_id, member_id int) (int, error) {
o := orm.NewOrm()
relationship := NewRelationship()
err := o.QueryTable(m.TableNameWithPrefix()).Filter("book_id",book_id).Filter("member_id",member_id).One(relationship)
err := o.QueryTable(m.TableNameWithPrefix()).Filter("book_id", book_id).Filter("member_id", member_id).One(relationship)
if err != nil {
return 0,err
return 0, err
}
return relationship.RoleId,nil
return relationship.RoleId, nil
}
func (m *Relationship) FindByBookIdAndMemberId(book_id ,member_id int) (*Relationship,error) {
func (m *Relationship) FindByBookIdAndMemberId(book_id, member_id int) (*Relationship, error) {
o := orm.NewOrm()
err := o.QueryTable(m.TableNameWithPrefix()).Filter("book_id",book_id).Filter("member_id",member_id).One(m)
err := o.QueryTable(m.TableNameWithPrefix()).Filter("book_id", book_id).Filter("member_id", member_id).One(m)
return m,err
return m, err
}
func (m *Relationship) Insert() error {
func (m *Relationship) Insert() error {
o := orm.NewOrm()
_,err := o.Insert(m)
_, err := o.Insert(m)
return err
}
func (m *Relationship) Update() error {
func (m *Relationship) Update() error {
o := orm.NewOrm()
_,err := o.Update(m)
_, err := o.Update(m)
return err
}
func (m *Relationship) DeleteByBookIdAndMemberId(book_id,member_id int) error {
func (m *Relationship) DeleteByBookIdAndMemberId(book_id, member_id int) error {
o := orm.NewOrm()
err := o.QueryTable(m.TableNameWithPrefix()).Filter("book_id",book_id).Filter("member_id",member_id).One(m)
err := o.QueryTable(m.TableNameWithPrefix()).Filter("book_id", book_id).Filter("member_id", member_id).One(m)
if err == orm.ErrNoRows {
return errors.New("用户未参与该项目")
@ -138,22 +137,22 @@ func (m *Relationship) DeleteByBookIdAndMemberId(book_id,member_id int) error {
if m.RoleId == conf.BookFounder {
return errors.New("不能删除创始人")
}
_,err = o.Delete(m)
_, err = o.Delete(m)
if err != nil {
logs.Error("删除项目参与者 => ",err)
logs.Error("删除项目参与者 => ", err)
return errors.New("删除失败")
}
return nil
}
func (m *Relationship) Transfer(book_id,founder_id,receive_id int) error {
func (m *Relationship) Transfer(book_id, founder_id, receive_id int) error {
o := orm.NewOrm()
founder := NewRelationship()
err := o.QueryTable(m.TableNameWithPrefix()).Filter("book_id",book_id).Filter("member_id",founder_id).One(founder)
err := o.QueryTable(m.TableNameWithPrefix()).Filter("book_id", book_id).Filter("member_id", founder_id).One(founder)
if err != nil {
return err
@ -163,7 +162,7 @@ func (m *Relationship) Transfer(book_id,founder_id,receive_id int) error {
}
receive := NewRelationship()
err = o.QueryTable(m.TableNameWithPrefix()).Filter("book_id",book_id).Filter("member_id",receive_id).One(receive)
err = o.QueryTable(m.TableNameWithPrefix()).Filter("book_id", book_id).Filter("member_id", receive_id).One(receive)
if err != orm.ErrNoRows && err != nil {
return err
@ -176,17 +175,17 @@ func (m *Relationship) Transfer(book_id,founder_id,receive_id int) error {
receive.RoleId = conf.BookFounder
receive.BookId = book_id
if err := founder.Update();err != nil {
if err := founder.Update(); err != nil {
o.Rollback()
return err
}
if receive.RelationshipId > 0 {
if _,err := o.Update(receive);err != nil {
if _, err := o.Update(receive); err != nil {
o.Rollback()
return err
}
}else{
if _,err := o.Insert(receive);err != nil {
} else {
if _, err := o.Insert(receive); err != nil {
o.Rollback()
return err
}
@ -194,24 +193,3 @@ func (m *Relationship) Transfer(book_id,founder_id,receive_id int) error {
return o.Commit()
}

View File

@ -1,43 +1,45 @@
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() {
func init() {
var FilterUser = func(ctx *context.Context) {
_, ok := ctx.Input.Session(conf.LoginSessionName).(models.Member)
if !ok {
if ctx.Input.IsAjax() {
jsonData := make(map[string]interface{},3)
jsonData := make(map[string]interface{}, 3)
jsonData["errcode"] = 403
jsonData["message"] = "请登录后再操作"
returnJSON, _ := json.Marshal(jsonData)
ctx.ResponseWriter.Write(returnJSON)
}else{
ctx.Redirect(302, beego.URLFor("AccountController.Login"))
} else {
ctx.Redirect(302, beego.URLFor("AccountController.Login") + "?url=" + url.PathEscape(ctx.Request.URL.RequestURI()))
}
}
}
beego.InsertFilter("/manager",beego.BeforeRouter,FilterUser)
beego.InsertFilter("/manager/*",beego.BeforeRouter,FilterUser)
beego.InsertFilter("/setting",beego.BeforeRouter,FilterUser)
beego.InsertFilter("/setting/*",beego.BeforeRouter,FilterUser)
beego.InsertFilter("/book",beego.BeforeRouter,FilterUser)
beego.InsertFilter("/book/*",beego.BeforeRouter,FilterUser)
beego.InsertFilter("/api/*",beego.BeforeRouter,FilterUser)
beego.InsertFilter("/manager", beego.BeforeRouter, FilterUser)
beego.InsertFilter("/manager/*", beego.BeforeRouter, FilterUser)
beego.InsertFilter("/setting", beego.BeforeRouter, FilterUser)
beego.InsertFilter("/setting/*", beego.BeforeRouter, FilterUser)
beego.InsertFilter("/book", beego.BeforeRouter, FilterUser)
beego.InsertFilter("/book/*", beego.BeforeRouter, FilterUser)
beego.InsertFilter("/api/*", beego.BeforeRouter, FilterUser)
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-Version", conf.VERSION)
ctx.ResponseWriter.Header().Add("MinDoc-Site", "https://www.iminho.me")
}
beego.InsertFilter("/*",beego.BeforeRouter ,FinishRouter, false)
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,15 +1,15 @@
package utils
import (
"strings"
"os"
"fmt"
"path/filepath"
"io"
"math"
"os"
"path/filepath"
"strings"
)
func AbsolutePath(p string) (string,error) {
func AbsolutePath(p string) (string, error) {
if strings.HasPrefix(p, "~") {
home := os.Getenv("HOME")
@ -21,9 +21,9 @@ func AbsolutePath(p string) (string,error) {
s, err := filepath.Abs(p)
if nil != err {
return "",err
return "", err
}
return s,nil
return s, nil
}
// FileExists reports whether the named file or directory exists.
@ -58,18 +58,13 @@ func FormatBytes(size int64) string {
i := 0
for ; s >= 1024 && i < 4 ; i ++ {
for ; s >= 1024 && i < 4; i++ {
s /= 1024
}
return fmt.Sprintf("%.2f%s",s,units[i])
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);
func Encode(value interface{}) (string, error) {
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,16 +1,15 @@
package utils
import (
"time"
"math/rand"
"time"
)
const (
KC_RAND_KIND_NUM = 0 // 纯数字
KC_RAND_KIND_LOWER = 1 // 小写字母
KC_RAND_KIND_UPPER = 2 // 大写字母
KC_RAND_KIND_ALL = 3 // 数字、大小写字母
KC_RAND_KIND_NUM = 0 // 纯数字
KC_RAND_KIND_LOWER = 1 // 小写字母
KC_RAND_KIND_UPPER = 2 // 大写字母
KC_RAND_KIND_ALL = 3 // 数字、大小写字母
)
// 随机字符串
@ -18,12 +17,12 @@ func Krand(size int, kind int) []byte {
ikind, kinds, result := kind, [][]int{[]int{10, 48}, []int{26, 97}, []int{26, 65}}, make([]byte, size)
is_all := kind > 2 || kind < 0
rand.Seed(time.Now().UnixNano())
for i :=0; i < size; i++ {
for i := 0; i < size; i++ {
if is_all { // random ikind
ikind = rand.Intn(3)
}
scope, base := kinds[ikind][0], kinds[ikind][1]
result[i] = uint8(base+rand.Intn(scope))
result[i] = uint8(base + rand.Intn(scope))
}
return result

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:
@ -23,20 +24,20 @@ func ValidLDAPLogin(password string) (result bool, err error) {
err = nil
lc, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "192.168.3.104", 389))
if err != nil {
beego.Error("Dial => ",err)
beego.Error("Dial => ", err)
return
}
defer lc.Close()
err = lc.Bind("cn=admin,dc=minho,dc=com", "123456")
if err != nil {
beego.Error("Bind => ",err)
beego.Error("Bind => ", err)
return
}
searchRequest := ldap.NewSearchRequest(
"DC=minho,DC=com",
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
fmt.Sprintf("(&(objectClass=User)(%s=%s))","mail", "longfei6671@163.com"),
fmt.Sprintf("(&(objectClass=User)(%s=%s))", "mail", "longfei6671@163.com"),
[]string{"dn"},
nil,
)
@ -49,7 +50,7 @@ func ValidLDAPLogin(password string) (result bool, err error) {
err = errors.New("ldap.no_user_found_or_many_users_found")
return
}
fmt.Printf("%+v = %d",searchResult.Entries,len(searchResult.Entries))
fmt.Printf("%+v = %d", searchResult.Entries, len(searchResult.Entries))
userdn := searchResult.Entries[0].DN
@ -57,7 +58,7 @@ func ValidLDAPLogin(password string) (result bool, err error) {
if err == nil {
result = true
} else {
beego.Error("Bind2 => ",err)
beego.Error("Bind2 => ", err)
err = nil
}
return
@ -66,12 +67,12 @@ func ValidLDAPLogin(password string) (result bool, err error) {
func AddMember(account, password string) error {
lc, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "192.168.3.104", 389))
if err != nil {
beego.Error("Dial => ",err)
beego.Error("Dial => ", err)
return err
}
defer lc.Close()
user := fmt.Sprintf("cn=%s,dc=minho,dc=com",account)
user := fmt.Sprintf("cn=%s,dc=minho,dc=com", account)
member := ldap.NewAddRequest(user)
@ -81,35 +82,35 @@ func AddMember(account, password string) error {
if err == nil {
err = lc.Bind(user,"")
err = lc.Bind(user, "")
if err != nil {
beego.Error("Bind => ",err)
beego.Error("Bind => ", err)
return err
}
passwordModifyRequest := ldap.NewPasswordModifyRequest(user, "", "1q2w3e__ABC")
_, err = lc.PasswordModify(passwordModifyRequest)
if err != nil {
beego.Error("PasswordModify => ",err)
beego.Error("PasswordModify => ", err)
return err
}
return nil
}
beego.Error("Add => ",err)
beego.Error("Add => ", err)
return err
}
func ModifyPassword(account, old_password, new_password string) error {
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "192.168.3.104", 389))
if err != nil {
beego.Error("Dial => ",err)
beego.Error("Dial => ", err)
}
defer l.Close()
user := fmt.Sprintf("cn=%s,dc=minho,dc=com",account)
user := fmt.Sprintf("cn=%s,dc=minho,dc=com", account)
err = l.Bind(user, old_password)
if err != nil {
beego.Error("Bind => ",err)
beego.Error("Bind => ", err)
return err
}
@ -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"
)
@ -25,7 +25,7 @@ type PageOptions struct {
NextPageText string //下一页文字 默认"下一页"
EnableFirstLastLink bool //是否启用首尾连接 默认false 建议开启
EnablePreNexLink bool //是否启用上一页,下一页连接 默认false 建议开启
TotalPages int
TotalPages int
}
/**
@ -42,7 +42,7 @@ func GetPagesInfo(tableName string, currentpage int, pagesize int, conditions st
}
var rs orm.RawSeter
o := orm.NewOrm()
var totalItem, totalpages int = 0, 0 //总条数,总页数
var totalItem, totalpages int = 0, 0 //总条数,总页数
o.Raw("SELECT count(*) FROM " + tableName + " where 1 > 0 " + conditions).QueryRow(&totalItem) //获取总条数
if totalItem <= pagesize {
totalpages = 1
@ -58,22 +58,22 @@ func GetPagesInfo(tableName string, currentpage int, pagesize int, conditions st
}
/**
* ,,,html
* , :
func (this *MainController) Test() {
var po util.PageOptions
po.EnablePreNexLink = true
po.EnableFirstLastLink = true
po.LinkItemCount = 7
po.TableName = "help_topic"
cp, _ := this.GetInt("pno")
po.CurrentPage = int(cp)
_,_,_ pager := util.GetPagerLinks(&po, this.Ctx)
this.Data["Email"] = html.HTML(pager)
this.TplName = "test.html"
}
* ,,,html
* , :
func (this *MainController) Test() {
var po util.PageOptions
po.EnablePreNexLink = true
po.EnableFirstLastLink = true
po.LinkItemCount = 7
po.TableName = "help_topic"
cp, _ := this.GetInt("pno")
po.CurrentPage = int(cp)
_,_,_ pager := util.GetPagerLinks(&po, this.Ctx)
this.Data["Email"] = html.HTML(pager)
this.TplName = "test.html"
}
*/
func GetPagerLinks(po *PageOptions,requestURI string) (int, int, orm.RawSeter, html.HTML) {
func GetPagerLinks(po *PageOptions, requestURI string) (int, int, orm.RawSeter, html.HTML) {
str := ""
totalItem, totalpages, rs := GetPagesInfo(po.TableName, po.CurrentPage, po.PageSize, po.Conditions)
po = setDefault(po, totalpages)
@ -84,7 +84,7 @@ func GetPagerLinks(po *PageOptions,requestURI string) (int, int, orm.RawSeter, h
if po.CurrentPage < po.LinkItemCount {
str = fun2(po, totalpages) //123456789...200
} else {
if po.CurrentPage + po.LinkItemCount < totalpages {
if po.CurrentPage+po.LinkItemCount < totalpages {
str = fun3(po, totalpages)
} else {
str = fun4(po, totalpages)
@ -94,18 +94,19 @@ 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))),
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)))
setDefault(po,totalPages)
DealUri(po,requestURI)
setDefault(po, totalPages)
DealUri(po, requestURI)
str := ""
if totalPages <= po.LinkItemCount {
str = fun1(po, totalPages) //显示完全 12345678910
@ -113,16 +114,16 @@ func GetPagerHtml(requestURI string,pageIndex, pageSize,totalCount int) (html.HT
if po.CurrentPage < po.LinkItemCount {
str = fun2(po, totalPages) //123456789...200
} else {
if po.CurrentPage + po.LinkItemCount < totalPages {
if po.CurrentPage+po.LinkItemCount < totalPages {
str = fun3(po, totalPages)
} else {
str = fun4(po, totalPages)
}
}
}
str = strings.Replace(str,"?&","?",-1)
str = strings.Replace(str, "?&", "?", -1)
//str = strings.Replace(str,"&&","&",-1)
return html.HTML(str)
return html.HTML(str)
}
/**
@ -136,19 +137,19 @@ func DealUri(po *PageOptions, requestURI string) {
arr2 := strings.Split(arr[1], "&")
for _, v := range arr2 {
if !strings.Contains(v, po.ParamName) {
if strings.HasSuffix(rs,"&") {
rs += v
}else{
rs += v + "&"
if strings.HasSuffix(rs, "&") {
rs += v
} else {
rs += v + "&"
}
//rs += "&" + v
}
}
if strings.HasPrefix(rs,"&") {
if strings.HasPrefix(rs, "&") {
rs = string(rs[1:])
}
if strings.HasSuffix(rs,"&"){
rs = string(rs[0:strings.Count(rs,"")-1])
if strings.HasSuffix(rs, "&") {
rs = string(rs[0 : strings.Count(rs, "")-1])
}
rs = arr[0] + "?" + rs
fmt.Println(rs)
@ -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 += "<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,18 +211,18 @@ 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 {
if po.CurrentPage != i {
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 += "<li class=\"active\"><a href=\"###\">" + con.Itoa(i) + " <span class=\"sr-only\">(current)</span></a></li>"
}
}
}
@ -239,7 +243,7 @@ func fun1(po *PageOptions, totalpages int) string {
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 += "<li class=\"active\"><a href=\"###\">" + con.Itoa(i) + " <span class=\"sr-only\">(current)</span></a></li>"
}
}
rs += getFooter(po, totalpages)
@ -255,7 +259,7 @@ func getHeader(po *PageOptions, totalpages int) string {
if po.EnableFirstLastLink { //当首页,尾页都设定的时候,就显示
if po.CurrentPage == 1 {
rs += "<li" + judgeDisable(po, totalpages, 0) + " class=\"disabled\"><a href=\"###\">" + po.FirstPageText + "</a></li>"
}else{
} else {
rs += "<li" + judgeDisable(po, totalpages, 0) + " ><a href='" + po.Href + "&" + po.ParamName + "=" + con.Itoa(1) + "'>" + po.FirstPageText + "</a></li>"
}
}
@ -281,7 +285,7 @@ func getFooter(po *PageOptions, totalpages int) string {
if po.EnableFirstLastLink { //当首页,尾页都设定的时候,就显示
if po.CurrentPage == totalpages {
rs += "<li " + judgeDisable(po, totalpages, 1) + " class=\"disabled\"><a href=\"###\">" + po.LastPageText + "</a></li>"
}else{
} else {
rs += "<li " + judgeDisable(po, totalpages, 1) + " ><a href=\"" + po.Href + "&" + po.ParamName + "=" + con.Itoa(totalpages) + "\">" + po.LastPageText + "</a></li>"
}
}
@ -339,4 +343,4 @@ func judgeDisable(po *PageOptions, totalpages int, h_f int) string {
}
}
return rs
}
}

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,8 +45,9 @@ func PasswordHash(pass string) (string, error) {
return password, nil
}
//校验密码是否有效
func PasswordVerify(hashing string, pass string) (bool, error) {
func PasswordVerify(hashing string, pass string) (bool, error) {
data := trim_salt_hash(hashing)
interation, _ := strconv.ParseInt(data["interation_string"], 10, 64)
@ -56,7 +57,7 @@ func PasswordVerify(hashing string, pass string) (bool, error) {
return false, err
}
if (data["salt_secret"]+delmiter+data["interation_string"]+delmiter+has+delmiter+data["salt"]) == hashing {
if (data["salt_secret"] + delmiter + data["interation_string"] + delmiter + has + delmiter + data["salt"]) == hashing {
return true, nil
} else {
return false, nil
@ -110,7 +111,7 @@ func trim_salt_hash(hash string) map[string]string {
}
func salt(secret string) (string, error) {
buf := make([]byte, saltSize, saltSize + md5.Size)
buf := make([]byte, saltSize, saltSize+md5.Size)
_, err := io.ReadFull(rand.Reader, buf)
if err != nil {
return "", err
@ -134,4 +135,4 @@ func salt_secret() (string, error) {
func randInt(min int, max int) int {
return min + mt.Intn(max-min)
}
}

View File

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

View File

@ -8,17 +8,17 @@ func JoinURI(elem ...string) string {
}
uri := ""
for i,u := range elem {
u = strings.Replace(u,"\\","/",-1)
for i, u := range elem {
u = strings.Replace(u, "\\", "/", -1)
if i == 0 {
if !strings.HasSuffix(u,"/") {
if !strings.HasSuffix(u, "/") {
u = u + "/"
}
uri = u
}else{
u = strings.Replace(u,"//","/",-1)
if strings.HasPrefix(u,"/") {
} else {
u = strings.Replace(u, "//", "/", -1)
if strings.HasPrefix(u, "/") {
u = string(u[1:])
}
uri += u

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>