From f91ad51e3f7bdc41b3483c4d3ac769741c05499a Mon Sep 17 00:00:00 2001 From: Minho Date: Tue, 25 Apr 2017 20:05:59 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- conf/app.conf.example | 10 +- conf/enumerate.go | 8 + controllers/book.go | 338 ++++++++++++++++++++++++++++------- controllers/manager.go | 117 +++++++++++- controllers/setting.go | 64 ++----- graphics/copy.go | 49 ++++++ graphics/file.go | 32 ++++ models/base.go | 14 -- models/book.go | 13 +- models/book_result.go | 10 +- models/comment.go | 6 +- models/dashboard.go | 38 ++++ models/member.go | 24 +-- models/relationship.go | 48 +++++ routers/router.go | 17 +- static/css/main.css | 26 +++ static/js/main.js | 14 +- utils/file.go | 25 +++ views/book/create.tpl | 2 + views/book/dashboard.tpl | 5 + views/book/index.tpl | 9 +- views/book/setting.tpl | 342 +++++++++++++++++++++++++++++++++--- views/book/users.tpl | 27 ++- views/manager/books.tpl | 7 +- views/manager/comments.tpl | 51 ++++++ views/manager/edit_book.tpl | 128 ++++++++++++-- views/manager/index.tpl | 34 ++++ views/manager/users.tpl | 52 ++++-- 28 files changed, 1292 insertions(+), 218 deletions(-) create mode 100644 graphics/copy.go create mode 100644 graphics/file.go create mode 100644 models/dashboard.go create mode 100644 utils/file.go create mode 100644 views/manager/comments.tpl diff --git a/conf/app.conf.example b/conf/app.conf.example index cc45e5b0..9b371d9f 100644 --- a/conf/app.conf.example +++ b/conf/app.conf.example @@ -18,5 +18,13 @@ db_port=3306 db_database=webhook_db db_username=root db_password=123456 +db_prefix=md_ -queue_size=50 \ No newline at end of file +#项目默认封面 +cover=/static/images/book.jpg + +#默认头像 +avatar=/static/images/headimgurl.jpg + +#默认阅读令牌长度 +token_size=12 \ No newline at end of file diff --git a/conf/enumerate.go b/conf/enumerate.go index 471c6c3b..a4c9b198 100644 --- a/conf/enumerate.go +++ b/conf/enumerate.go @@ -45,4 +45,12 @@ func GetDatabasePrefix() string { //获取默认头像 func GetDefaultAvatar() string { return beego.AppConfig.DefaultString("avatar","/static/images/headimgurl.jpg") +} + +func GetTokenSize() int { + return beego.AppConfig.DefaultInt("token_size",12) +} + +func GetDefaultCover() string { + return beego.AppConfig.DefaultString("cover","/static/images/book.jpg") } \ No newline at end of file diff --git a/controllers/book.go b/controllers/book.go index 49c9127d..abc1a295 100644 --- a/controllers/book.go +++ b/controllers/book.go @@ -7,6 +7,10 @@ import ( "time" "encoding/json" "html/template" + "errors" + "fmt" + "path/filepath" + "os" "github.com/lifei6671/godoc/models" "github.com/lifei6671/godoc/utils" @@ -14,6 +18,7 @@ import ( "github.com/astaxie/beego/orm" "github.com/astaxie/beego/logs" "github.com/lifei6671/godoc/conf" + "github.com/lifei6671/godoc/graphics" ) type BookController struct { @@ -83,14 +88,235 @@ func (c *BookController) Setting() { book,err := models.NewBookResult().FindByIdentify(key,c.Member.MemberId) if err != nil { + if err == orm.ErrNoRows { + c.Abort("404") + } if err == models.ErrPermissionDenied { c.Abort("403") } c.Abort("500") } + //如果不是创始人也不是管理员则不能操作 + if book.RoleId != conf.BookFounder && book.RoleId != conf.BookAdmin { + c.Abort("403") + } + if book.PrivateToken != "" { + book.PrivateToken = c.BaseUrl() + beego.URLFor("DocumentController.Index",":key",book.Identify,"token",book.PrivateToken) + } + c.Data["Model"] = book - c.Data["Model"] = *book +} +//保存项目信息 +func (c *BookController) SaveBook() { + bookResult,err := c.IsPermission() + + if err != nil { + c.JsonResult(6001,err.Error()) + } + book,err := models.NewBook().Find(bookResult.BookId) + + if err != nil { + logs.Error("SaveBook => ",err) + c.JsonResult(6002,err.Error()) + } + + book_name := strings.TrimSpace(c.GetString("book_name")) + description := strings.TrimSpace(c.GetString("description","")) + comment_status := c.GetString("comment_status") + tag := strings.TrimSpace(c.GetString("label")) + + 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 len(tags) > 10 { + c.JsonResult(6005,"最多允许添加10个标签") + } + } + + + book.BookName = book_name + book.Description = description + book.CommentStatus = comment_status + book.Label = tag + + 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) +} + +func (c *BookController) PrivatelyOwned() { + + status := c.GetString("status") + + if status != "open" && status != "close" { + c.JsonResult(6003,"参数错误") + } + state := 0 + if status == "open" { + state = 0 + }else{ + state = 1 + } + + bookResult,err := c.IsPermission() + + if err != nil { + c.JsonResult(6001,err.Error()) + } + //只有创始人才能变更私有状态 + if bookResult.RoleId != conf.BookFounder { + c.JsonResult(6002,"权限不足") + } + fmt.Printf("%+v",bookResult) + + book,err := models.NewBook().Find(bookResult.BookId) + + if err != nil { + c.JsonResult(6005,"项目不存在") + } + book.PrivatelyOwned = state + + logs.Info("",state,status) + + err = book.Update() + + if err != nil { + logs.Error("PrivatelyOwned => ",err) + c.JsonResult(6004,"保存失败") + } + c.JsonResult(0,"ok") +} + +// Transfer 转让项目. +func (c *BookController) Transfer() { + c.Prepare() + account := c.GetString("account") + + if account == "" { + c.JsonResult(6004,"接受者账号不能为空") + } + member,err := models.NewMember().FindByAccount(account) + + if err != nil { + logs.Error("FindByAccount => ",err) + c.JsonResult(6005,"接受用户不存在") + } + if member.Status != 0 { + c.JsonResult(6006,"接受用户已被禁用") + } + if member.MemberId == c.Member.MemberId { + c.JsonResult(6007,"不能转让给自己") + } + bookResult,err := c.IsPermission() + + if err != nil { + c.JsonResult(6001,err.Error()) + } + + err = models.NewRelationship().Transfer(bookResult.BookId,c.Member.MemberId,member.MemberId) + + if err != nil { + logs.Error("Transfer => ",err) + c.JsonResult(6008,err.Error()) + } + c.JsonResult(0,"ok") +} +//上传项目封面. +func (c *BookController) UploadCover() { + + bookResult,err := c.IsPermission() + + if err != nil { + c.JsonResult(6001,err.Error()) + } + book,err := models.NewBook().Find(bookResult.BookId) + + if err != nil { + logs.Error("SaveBook => ",err) + c.JsonResult(6002,err.Error()) + } + + file,moreFile,err := c.GetFile("image-file") + defer file.Close() + + if err != nil { + 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,"不支持的图片格式") + } + + + 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) + + filePath := "uploads/" + time.Now().Format("200601") + "/" + fileName + ext + + path := filepath.Dir(filePath) + + os.MkdirAll(path, os.ModePerm) + + err = c.SaveToFile("image-file",filePath) + + if err != nil { + logs.Error("",err) + c.JsonResult(500,"图片保存失败") + } + + //剪切图片 + subImg,err := graphics.ImageCopyFromFile(filePath,x,y,width,height) + + if err != nil{ + logs.Error("graphics.ImageCopyFromFile => ",err) + c.JsonResult(500,"图片剪切") + } + //生成缩略图并保存到磁盘 + err = graphics.ImageResizeSaveFile(subImg,175,230,filePath) + + if err != nil { + logs.Error("ImageResizeSaveFile => ",err.Error()) + c.JsonResult(500,"保存图片失败") + } + + url := "/" + filePath + + old_cover := book.Cover + + book.Cover = url + + if err := book.Update() ; err != nil { + c.JsonResult(6001,"保存图片失败") + } + //如果原封面不是默认封面则删除 + if old_cover != conf.GetDefaultCover() { + os.Remove("." + old_cover) + } + + c.JsonResult(0,"ok",url) } // Users 用户列表. @@ -142,24 +368,15 @@ func (c *BookController) AddMember() { if identify == "" || account == ""{ c.JsonResult(6001,"参数错误") } - book ,err := models.NewBookResult().FindByIdentify(identify,c.Member.MemberId) + book ,err := c.IsPermission() if err != nil { - if err == models.ErrPermissionDenied { - c.JsonResult(403,"权限不足") - } - if err == orm.ErrNoRows { - c.JsonResult(404,"项目不存在") - } - c.JsonResult(6002,err.Error()) - } - if book.RoleId != 0 && book.RoleId != 1 { - c.JsonResult(403,"权限不足") + c.JsonResult(6001,err.Error()) } member := models.NewMember() - if err := member.FindByAccount(account) ; err != nil { + if _,err := member.FindByAccount(account) ; err != nil { c.JsonResult(404,"用户不存在") } if member.Status == 1 { @@ -249,7 +466,7 @@ func (c *BookController) RemoveMember() { c.JsonResult(6001,"参数错误") } if member_id == c.Member.MemberId { - c.JsonResult(6006,"不能变更自己的权限") + c.JsonResult(6006,"不能删除自己") } book ,err := models.NewBookResult().FindByIdentify(identify,c.Member.MemberId) @@ -262,7 +479,8 @@ func (c *BookController) RemoveMember() { } c.JsonResult(6002,err.Error()) } - if book.RoleId != 0 && book.RoleId != 1 { + //如果不是创始人也不是管理员则不能操作 + if book.RoleId != conf.BookFounder && book.RoleId != conf.BookAdmin { c.JsonResult(403,"权限不足") } err = models.NewRelationship().DeleteByBookIdAndMemberId(book.BookId,member_id) @@ -344,18 +562,10 @@ func (p *BookController) Edit() { // CreateToken 创建访问来令牌. func (c *BookController) CreateToken() { - book_id,_ := c.GetInt("book_id",0) - if book_id <= 0{ - c.JsonResult(6001,"参数错误") - } + action := c.GetString("action") - book := models.NewBook() - - if err := book.Find(book_id);err != nil { - c.JsonResult(6001,"项目不存在") - } - bookResult ,err := models.NewBookResult().FindByIdentify("identify",c.Member.MemberId) + bookResult ,err := c.IsPermission() if err != nil { if err == models.ErrPermissionDenied { @@ -367,50 +577,46 @@ func (c *BookController) CreateToken() { logs.Error("生成阅读令牌失败 =>",err) c.JsonResult(6002,err.Error()) } - //必须是管理员或创始人才能删除项目 - if bookResult.RoleId != 0 && bookResult.RoleId != 1 { - c.JsonResult(403,"权限不足") - } - if bookResult.PrivatelyOwned == 0 { - c.JsonResult(6001,"公开项目不能创建阅读令牌") - } + book := models.NewBook() - book.PrivateToken = string(utils.Krand(20,utils.KC_RAND_KIND_ALL)) - if err := book.Update(); err != nil { - logs.Error("生成阅读令牌失败 => ",err) - c.JsonResult(6003,"生成阅读令牌失败") + if _,err := book.Find(bookResult.BookId);err != nil { + c.JsonResult(6001,"项目不存在") + } + if action == "create" { + if bookResult.PrivatelyOwned == 0 { + c.JsonResult(6001, "公开项目不能创建阅读令牌") + } + + book.PrivateToken = string(utils.Krand(conf.GetTokenSize(), utils.KC_RAND_KIND_ALL)) + if err := book.Update(); err != nil { + logs.Error("生成阅读令牌失败 => ", err) + c.JsonResult(6003, "生成阅读令牌失败") + } + 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,"删除令牌失败") + } + c.JsonResult(0,"ok","") } - c.JsonResult(0,"ok", c.BaseUrl() + "?token="+ book.PrivateToken) } // Delete 删除项目. func (c *BookController) Delete() { c.Prepare() - book_id,_ := c.GetInt("book_id",0) - - if book_id <= 0{ - c.JsonResult(6001,"参数错误") - } - - book ,err := models.NewBookResult().FindByIdentify("identify",c.Member.MemberId) + bookResult ,err := c.IsPermission() if err != nil { - if err == models.ErrPermissionDenied { - c.JsonResult(403,"权限不足") - } - if err == orm.ErrNoRows { - c.JsonResult(404,"项目不存在") - } - logs.Error("删除项目 =>",err) - c.JsonResult(6002,err.Error()) - } - //必须是管理员或创始人才能删除项目 - if book.RoleId != 0 && book.RoleId != 1 { - c.JsonResult(403,"权限不足") + c.JsonResult(6001,err.Error()) } - err = models.NewBook().ThoroughDeleteBook(book_id) + if bookResult.RoleId != conf.BookFounder { + c.JsonResult(6002,"只有创始人才能删除项目") + } + err = models.NewBook().ThoroughDeleteBook(bookResult.BookId) if err == orm.ErrNoRows { c.JsonResult(6002,"项目不存在") @@ -422,7 +628,21 @@ func (c *BookController) Delete() { c.JsonResult(0,"ok") } -// Transfer 转让项目. -func (p *BookController)Transfer() { +func (c *BookController) IsPermission() (*models.BookResult,error) { + identify := c.GetString("identify") + book ,err := models.NewBookResult().FindByIdentify(identify,c.Member.MemberId) + if err != nil { + if err == models.ErrPermissionDenied { + return book,errors.New("权限不足") + } + if err == orm.ErrNoRows { + return book,errors.New("项目不存在") + } + return book,err + } + if book.RoleId != conf.BookAdmin && book.RoleId != conf.BookFounder { + return book,errors.New("权限不足") + } + return book,nil } \ No newline at end of file diff --git a/controllers/manager.go b/controllers/manager.go index 358efd8d..e7b185ee 100644 --- a/controllers/manager.go +++ b/controllers/manager.go @@ -12,14 +12,20 @@ import ( "github.com/lifei6671/godoc/utils" "github.com/lifei6671/godoc/models" "github.com/astaxie/beego/orm" + "github.com/astaxie/beego" ) type ManagerController struct { BaseController } -func (p *ManagerController) Index() { - p.TplName = "manager/index.tpl" +func (c *ManagerController) Index() { + c.TplName = "manager/index.tpl" + if !c.Member.IsAdministrator() { + c.Abort("403") + } + + c.Data["Model"] = models.NewDashboard().Query() } // 用户列表. @@ -93,7 +99,7 @@ func (c *ManagerController) CreateMember() { member := models.NewMember() - if err := member.FindByAccount(account); err == nil && member.MemberId > 0 { + if _,err := member.FindByAccount(account); err == nil && member.MemberId > 0 { c.JsonResult(6005,"账号已存在") } @@ -145,6 +151,36 @@ func (c *ManagerController) UpdateMemberStatus() { c.JsonResult(0,"ok",member) } +func (c *ManagerController) ChangeMemberRole() { + c.Prepare() + + if !c.Member.IsAdministrator() { + c.Abort("403") + } + + member_id,_ := c.GetInt("member_id",0) + role ,_ := c.GetInt("role",0) + if member_id <= 0 { + c.JsonResult(6001,"参数错误") + } + if role != conf.MemberAdminRole && role != conf.MemberGeneralRole { + c.JsonResult(6001,"用户权限不正确") + } + member := models.NewMember() + + if err := member.Find(member_id); err != nil { + c.JsonResult(6002,"用户不存在") + } + member.Role = role + + if err := member.Update();err != nil { + logs.Error("",err) + c.JsonResult(6003,"用户权限设置失败") + } + member.ResolveRoleName() + c.JsonResult(0,"ok",member) +} + func (c *ManagerController) Books() { c.Prepare() c.TplName = "manager/books.tpl" @@ -168,6 +204,7 @@ func (c *ManagerController) Books() { c.Data["Lists"] = books } +//编辑项目 func (c *ManagerController) EditBook() { c.TplName = "manager/edit_book.tpl" identify := c.GetString(":key") @@ -179,9 +216,44 @@ func (c *ManagerController) EditBook() { if err != nil { c.Abort("500") } + if c.Ctx.Input.IsPost() { + + book_name := strings.TrimSpace(c.GetString("book_name")) + description := strings.TrimSpace(c.GetString("description","")) + comment_status := c.GetString("comment_status") + tag := strings.TrimSpace(c.GetString("label")) + + 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 len(tags) > 10 { + c.JsonResult(6005,"最多允许添加10个标签") + } + } + + + book.BookName = book_name + book.Description = description + book.CommentStatus = comment_status + book.Label = tag + + if err := book.Update();err != nil { + c.JsonResult(6006,"保存失败") + } + c.JsonResult(0,"ok") + } + if book.PrivateToken != "" { + book.PrivateToken = c.BaseUrl() + beego.URLFor("DocumentController.Index",":key",book.Identify,"token",book.PrivateToken) + } c.Data["Model"] = book } + // 删除项目. func (c *ManagerController) DeleteBook() { c.Prepare() @@ -202,17 +274,54 @@ func (c *ManagerController) DeleteBook() { c.JsonResult(6002,"项目不存在") } if err != nil { - logs.Error("",err) + logs.Error("DeleteBook => ",err) c.JsonResult(6003,"删除失败") } c.JsonResult(0,"ok") } + +// CreateToken 创建访问来令牌. +func (c *ManagerController) CreateToken() { + + action := c.GetString("action") + + identify := c.GetString("identify") + + book,err := models.NewBook().FindByFieldFirst("identify",identify); + + if err != nil { + c.JsonResult(6001,"项目不存在") + } + if action == "create" { + + if book.PrivatelyOwned == 0 { + c.JsonResult(6001, "公开项目不能创建阅读令牌") + } + + book.PrivateToken = string(utils.Krand(conf.GetTokenSize(), utils.KC_RAND_KIND_ALL)) + if err := book.Update(); err != nil { + logs.Error("生成阅读令牌失败 => ", err) + c.JsonResult(6003, "生成阅读令牌失败") + } + 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,"删除令牌失败") + } + c.JsonResult(0,"ok","") + } +} + func (c *ManagerController) Comments() { c.Prepare() + c.TplName = "manager/comments.tpl" if !c.Member.IsAdministrator() { c.Abort("403") } + } //DeleteComment 标记评论为已删除 diff --git a/controllers/setting.go b/controllers/setting.go index a58574a3..98be7ec8 100644 --- a/controllers/setting.go +++ b/controllers/setting.go @@ -1,22 +1,17 @@ package controllers import ( - "image" "fmt" "os" "strings" - "image/jpeg" - "image/png" - "image/gif" "path/filepath" "strconv" "time" - "io/ioutil" - "bytes" "github.com/astaxie/beego/logs" "github.com/lifei6671/godoc/models" "github.com/lifei6671/godoc/utils" + "github.com/lifei6671/godoc/graphics" ) type SettingController struct { @@ -113,9 +108,9 @@ func (c *SettingController) Upload() { fmt.Println(x,x1,y,y1) - fileName := "avatar_" + strconv.FormatInt(int64(time.Now().Nanosecond()), 16) + fileName := "avatar_" + strconv.FormatInt(time.Now().UnixNano(), 16) - filePath := "static/uploads/" + time.Now().Format("200601") + "/" + fileName + ext + filePath := "uploads/" + time.Now().Format("200601") + "/" + fileName + ext path := filepath.Dir(filePath) @@ -128,61 +123,22 @@ func (c *SettingController) Upload() { c.JsonResult(500,"图片保存失败") } - fileBytes,err := ioutil.ReadFile(filePath) + + //剪切图片 + subImg,err := graphics.ImageCopyFromFile(filePath,x,y,width,height) if err != nil { - logs.Error("",err) - c.JsonResult(500,"图片保存失败") - } - - buf := bytes.NewBuffer(fileBytes) - - m,_,err := image.Decode(buf) - - if err != nil{ - logs.Error("image.Decode => ",err) - c.JsonResult(500,"图片解码失败") - } - - - var subImg image.Image - - if rgbImg,ok := m.(*image.YCbCr); ok { - subImg = rgbImg.SubImage(image.Rect(x, y, x+width, y+height)).(*image.YCbCr) //图片裁剪x0 y0 x1 y1 - }else if rgbImg,ok := m.(*image.RGBA); ok { - subImg = rgbImg.SubImage(image.Rect(x, y, x+width, y+height)).(*image.YCbCr) //图片裁剪x0 y0 x1 y1 - }else if rgbImg,ok := m.(*image.NRGBA); ok { - subImg = rgbImg.SubImage(image.Rect(x, y, x+width, y+height)).(*image.YCbCr) //图片裁剪x0 y0 x1 y1 - } else { - fmt.Println(m) - c.JsonResult(500,"图片解码失败") - } - - f, err := os.OpenFile("./" + filePath, os.O_SYNC | os.O_RDWR, 0666) - - if err != nil{ - c.JsonResult(500,"保存图片失败") - } - defer f.Close() - - if strings.EqualFold(ext,".jpg") || strings.EqualFold(ext,".jpeg"){ - - err = jpeg.Encode(f,subImg,&jpeg.Options{ Quality : 100 }) - }else if strings.EqualFold(ext,".png") { - err = png.Encode(f,subImg) - }else if strings.EqualFold(ext,".gif") { - err = gif.Encode(f,subImg,&gif.Options{ NumColors : 256}) - } - if err != nil { - logs.Error("图片剪切失败 => ",err.Error()) - c.JsonResult(500,"图片剪切失败") + logs.Error("ImageCopyFromFile => ",err) + c.JsonResult(6001,"头像剪切失败") } + err = graphics.SaveImage(filePath,subImg) if err != nil { logs.Error("保存文件失败 => ",err.Error()) c.JsonResult(500,"保存文件失败") } + url := "/" + filePath member := models.NewMember() diff --git a/graphics/copy.go b/graphics/copy.go new file mode 100644 index 00000000..1deed8be --- /dev/null +++ b/graphics/copy.go @@ -0,0 +1,49 @@ +package graphics + +import ( + "image" + "os" + "errors" + + "github.com/nfnt/resize" +) + +func ImageCopy(src image.Image,x, y ,w, h int) (image.Image,error) { + + var subImg image.Image + + if rgbImg,ok := src.(*image.YCbCr); ok { + subImg = rgbImg.SubImage(image.Rect(x, y, x+w, y+h)).(*image.YCbCr) //图片裁剪x0 y0 x1 y1 + }else if rgbImg,ok := src.(*image.RGBA); ok { + subImg = rgbImg.SubImage(image.Rect(x, y, x+w, y+h)).(*image.YCbCr) //图片裁剪x0 y0 x1 y1 + }else if rgbImg,ok := src.(*image.NRGBA); ok { + subImg = rgbImg.SubImage(image.Rect(x, y, x+w, y+h)).(*image.YCbCr) //图片裁剪x0 y0 x1 y1 + } else { + + return subImg,errors.New("图片解码失败") + } + + return subImg,nil +} + +func ImageCopyFromFile(p string,x, y ,w, h int) (image.Image,error) { + var src image.Image + + file, err := os.Open(p) + if err != nil { + return src, err + } + defer file.Close() + src, _, err = image.Decode(file) + + return ImageCopy(src, x, y, w, h) +} + +func ImageResize(src image.Image,w,h int) (image.Image) { + return resize.Resize(uint(w), uint(h), src, resize.Lanczos3) +} +func ImageResizeSaveFile(src image.Image,width,height int,p string) error { + dst := resize.Resize(uint(width), uint(height), src, resize.Lanczos3) + + return SaveImage(p,dst) +} \ No newline at end of file diff --git a/graphics/file.go b/graphics/file.go new file mode 100644 index 00000000..da4721ec --- /dev/null +++ b/graphics/file.go @@ -0,0 +1,32 @@ +package graphics + +import ( + "image" + "os" + "path/filepath" + "strings" + "image/jpeg" + "image/png" + "image/gif" +) +// 将图片保存到指定的路径 +func SaveImage(p string, src image.Image) error { + + f, err := os.OpenFile( p, os.O_SYNC | os.O_RDWR | os.O_CREATE, 0666) + + if err != nil { + return err + } + defer f.Close() + ext := filepath.Ext(p) + + if strings.EqualFold(ext, ".jpg") || strings.EqualFold(ext, ".jpeg") { + + err = jpeg.Encode(f, src, &jpeg.Options{Quality : 100 }) + } else if strings.EqualFold(ext, ".png") { + err = png.Encode(f, src) + } else if strings.EqualFold(ext, ".gif") { + err = gif.Encode(f, src, &gif.Options{NumColors : 256}) + } + return err +} diff --git a/models/base.go b/models/base.go index 081606ff..23e1ee6b 100644 --- a/models/base.go +++ b/models/base.go @@ -1,20 +1,6 @@ package models -import "github.com/astaxie/beego/orm" - type Model struct { } -func (m *Model) Find(id int) error { - o := orm.NewOrm() - - return o.Read(m) -} - -func (m *Model) Insert() error { - o := orm.NewOrm() - _,err := o.Insert(m) - - return err -} \ No newline at end of file diff --git a/models/book.go b/models/book.go index f9339d86..69c0f3cf 100644 --- a/models/book.go +++ b/models/book.go @@ -71,13 +71,16 @@ func (m *Book) Insert() error { return err } -func (m *Book) Find(id int) error { +func (m *Book) Find(id int) (*Book,error) { if id <= 0 { - return ErrInvalidParameter + return m,ErrInvalidParameter } o := orm.NewOrm() - return o.Read(m) + + err := o.QueryTable(m.TableNameWithPrefix()).Filter("book_id",id).One(m) + + return m,err } func (m *Book) Update(cols... string) error { @@ -201,7 +204,7 @@ func (m *Book) ThoroughDeleteBook(id int) error { } sql3 := "DELETE FROM " + m.TableNameWithPrefix() + " WHERE book_id = ?" - _,err = o.Raw(sql3).Exec() + _,err = o.Raw(sql3,m.BookId).Exec() if err != nil { o.Rollback() @@ -209,7 +212,7 @@ func (m *Book) ThoroughDeleteBook(id int) error { } sql4 := "DELETE FROM " + NewRelationship().TableNameWithPrefix() + " WHERE book_id = ?" - _,err = o.Raw(sql4).Exec() + _,err = o.Raw(sql4,m.BookId).Exec() if err != nil { o.Rollback() diff --git a/models/book_result.go b/models/book_result.go index 2857f705..4d6c843e 100644 --- a/models/book_result.go +++ b/models/book_result.go @@ -5,6 +5,7 @@ import ( "github.com/astaxie/beego/orm" "strings" "github.com/astaxie/beego/logs" + "github.com/lifei6671/godoc/conf" ) type BookResult struct { @@ -93,17 +94,18 @@ func (m *BookResult) FindByIdentify(identify string,member_id int) (*BookResult, m.RoleId = relationship.RoleId m.RelationshipId = relationship.RelationshipId - if m.RoleId == 0{ + if m.RoleId == conf.BookFounder { m.RoleName = "创始人" - }else if m.RoleId == 1 { + }else if m.RoleId == conf.BookAdmin { m.RoleName = "管理员" - }else if m.RoleId == 2 { + }else if m.RoleId == conf.BookEditor { m.RoleName = "编辑者" - }else if m.RoleId == 2 { + }else if m.RoleId == conf.BookObserver { m.RoleName = "观察者" } + doc := NewDocument() err = o.QueryTable(doc.TableNameWithPrefix()).Filter("book_id",book.BookId).OrderBy("modify_time").One(doc) diff --git a/models/comment.go b/models/comment.go index a2e31f59..5ab0b206 100644 --- a/models/comment.go +++ b/models/comment.go @@ -87,9 +87,9 @@ func (m *Comment) Insert() error { if err := document.Find(m.DocumentId); err != nil { return err } - book := NewBook() + book ,err := NewBook().Find(document.BookId); //如果评论的项目不存在 - if err := book.Find(document.BookId); err != nil { + if err != nil { return err } //如果已关闭评论 @@ -124,7 +124,7 @@ func (m *Comment) Insert() error { m.Author = "[匿名用户]" } m.BookId = book.BookId - _,err := o.Insert(m) + _,err = o.Insert(m) return err } diff --git a/models/dashboard.go b/models/dashboard.go new file mode 100644 index 00000000..3529888d --- /dev/null +++ b/models/dashboard.go @@ -0,0 +1,38 @@ +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"` +} + +func NewDashboard() *Dashboard { + return &Dashboard{} +} + +func (m *Dashboard) Query() (*Dashboard) { + o := orm.NewOrm() + + book_number,_ := o.QueryTable(NewBook().TableNameWithPrefix()).Count() + + m.BookNumber = book_number + + document_count,_ := o.QueryTable(NewDocument().TableNameWithPrefix()).Count() + m.DocumentNumber = document_count + + member_number,_ := o.QueryTable(NewMember().TableNameWithPrefix()).Count() + m.MemberNumber = member_number + + comment_number,_ := o.QueryTable(NewComment().TableNameWithPrefix()).Count() + m.CommentNumber = comment_number + + attachment_number,_ := o.QueryTable(NewAttachment().TableNameWithPrefix()).Count() + + m.AttachmentNumber = attachment_number + + return m +} diff --git a/models/member.go b/models/member.go index bc03cb77..2fb0a0ab 100644 --- a/models/member.go +++ b/models/member.go @@ -103,6 +103,17 @@ func (m *Member) Find(id int) error{ if err := o.Read(m); err != nil { return err } + if m.Role == conf.MemberSuperRole { + m.RoleName = "超级管理员" + }else if m.Role == conf.MemberAdminRole { + m.RoleName = "管理员" + }else if m.Role == conf.MemberGeneralRole { + m.RoleName = "普通用户" + } + return nil +} + +func (m *Member) ResolveRoleName (){ if m.Role == 0 { m.RoleName = "超级管理员" }else if m.Role == 1 { @@ -110,24 +121,17 @@ func (m *Member) Find(id int) error{ }else if m.Role == 2 { m.RoleName = "普通用户" } - return nil } -func (m *Member) FindByAccount (account string) error { +func (m *Member) FindByAccount (account string) (*Member,error) { o := orm.NewOrm() err := o.QueryTable(m.TableNameWithPrefix()).Filter("account",account).One(m) if err == nil { - if m.Role == 0 { - m.RoleName = "超级管理员" - }else if m.Role == 1 { - m.RoleName = "管理员" - }else if m.Role == 2 { - m.RoleName = "普通用户" - } + m.ResolveRoleName() } - return err + return m,err } func (m *Member) FindToPager(pageIndex, pageSize int) ([]*Member,int64,error) { diff --git a/models/relationship.go b/models/relationship.go index 65158962..fb95ade5 100644 --- a/models/relationship.go +++ b/models/relationship.go @@ -90,6 +90,14 @@ func (m *Relationship) FindForRoleId(book_id ,member_id int) (int,error) { return relationship.RoleId,nil } +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) + + return m,err +} + func (m *Relationship) Insert() error { o := orm.NewOrm() @@ -127,6 +135,46 @@ func (m *Relationship) DeleteByBookIdAndMemberId(book_id,member_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) + + if err != nil { + return err + } + if founder.RoleId != conf.BookFounder { + return errors.New("转让者不是创始人") + } + receive := NewRelationship() + + 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 + } + o.Begin() + + founder.RoleId = conf.BookAdmin + + receive.MemberId = receive_id + receive.RoleId = conf.BookFounder + receive.BookId = book_id + + if err := founder.Update();err != nil { + o.Rollback() + return err + } + if _,err := o.InsertOrUpdate(receive);err != nil { + o.Rollback() + return err + } + return o.Commit() +} + + diff --git a/routers/router.go b/routers/router.go index ae43eee8..317fba22 100644 --- a/routers/router.go +++ b/routers/router.go @@ -17,9 +17,11 @@ func init() { beego.Router("/manager/users", &controllers.ManagerController{},"*:Users") beego.Router("/manager/member/create", &controllers.ManagerController{},"post:CreateMember") beego.Router("/manager/member/update-member-status",&controllers.ManagerController{},"post:UpdateMemberStatus") + beego.Router("/manager/member/change-member-role", &controllers.ManagerController{},"post:ChangeMemberRole") beego.Router("/manager/books", &controllers.ManagerController{},"*:Books") beego.Router("/manager/books/edit/:key", &controllers.ManagerController{},"*:EditBook") beego.Router("/manager/comments", &controllers.ManagerController{},"*:Comments") + beego.Router("/manager/books/token", &controllers.ManagerController{},"post:CreateToken") beego.Router("/setting", &controllers.SettingController{},"*:Index") beego.Router("/setting/password", &controllers.SettingController{},"*:Password") @@ -31,12 +33,17 @@ func init() { beego.Router("/book/:key/users", &controllers.BookController{},"*:Users") beego.Router("/book/:key/edit", &controllers.BookController{},"*:Edit") beego.Router("/book/create", &controllers.BookController{},"*:Create") - beego.Router("/book/member/create", &controllers.BookController{},"post:AddMember") - beego.Router("/book/member/change-role", &controllers.BookController{},"post:ChangeRole") + beego.Router("/book/users/create", &controllers.BookController{},"post:AddMember") + beego.Router("/book/users/change", &controllers.BookController{},"post:ChangeRole") + beego.Router("/book/users/delete", &controllers.BookController{},"post:RemoveMember") + + beego.Router("/book/setting/save", &controllers.BookController{},"post:SaveBook") + beego.Router("/book/setting/open", &controllers.BookController{},"post:PrivatelyOwned") + beego.Router("/book/setting/transfer", &controllers.BookController{},"post:Transfer") + beego.Router("/book/setting/upload", &controllers.BookController{},"post:UploadCover") + beego.Router("/book/setting/token", &controllers.BookController{},"post:CreateToken") + beego.Router("/book/setting/delete", &controllers.BookController{},"post:Delete") - beego.Router("/book/:key/users/create", &controllers.BookMemberController{},"*:Create") - beego.Router("/book/:key/users/change", &controllers.BookMemberController{},"*:Change") - beego.Router("/book/:key/users/delete", &controllers.BookMemberController{},"*:Delete") beego.Router("/docs/:key", &controllers.DocumentController{},"*:Index") beego.Router("/docs/:key/:id", &controllers.DocumentController{},"*:Read") diff --git a/static/css/main.css b/static/css/main.css index 99acf79c..dcade317 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -382,6 +382,32 @@ textarea{ display: inline-block; height: 40px; } +.manager .dashboard-item{ + float: left; + width: 100px; + height: 115px; + padding: 10px; + font-size: 10px; + line-height: 1.4; + text-align: center; + background-color: #f9f9f9; + border: 1px solid #fff; + cursor: pointer; +} +.manager .dashboard-item:hover{ + background-color: #563D7C; + color: #ffffff; +} +.manager .dashboard-item .fa{ + margin-top: 5px; + margin-bottom: 10px; + font-size: 24px; +} +.manager .dashboard-item .fa-class { + display: block; + text-align: center; + word-wrap: break-word; /* Help out IE10+ with class names */ +} /**************网站底部样式*************************/ .footer{ diff --git a/static/js/main.js b/static/js/main.js index a98557cf..5b3f6b2a 100644 --- a/static/js/main.js +++ b/static/js/main.js @@ -2,13 +2,19 @@ $("[data-toggle='tooltip']").tooltip(); })(); -function showError($msg) { - $("#form-error-message").addClass("error-message").removeClass("success-message").text($msg); +function showError($msg,$id) { + if(!$id){ + $id = "#form-error-message" + } + $($id).addClass("error-message").removeClass("success-message").text($msg); return false; } -function showSuccess($msg) { - $("#form-error-message").addClass("success-message").removeClass("error-message").text($msg); +function showSuccess($msg,$id) { + if(!$id){ + $id = "#form-error-message" + } + $($id).addClass("success-message").removeClass("error-message").text($msg); return true; } diff --git a/utils/file.go b/utils/file.go new file mode 100644 index 00000000..3014f7af --- /dev/null +++ b/utils/file.go @@ -0,0 +1,25 @@ +package utils + +import ( + "strings" + "os" + "fmt" + "path/filepath" +) + +func AbsolutePath(p string) (string,error) { + + if strings.HasPrefix(p, "~") { + home := os.Getenv("HOME") + if home == "" { + panic(fmt.Sprintf("can not found HOME in envs, '%s' AbsPh Failed!", p)) + } + p = fmt.Sprint(home, string(p[1:])) + } + s, err := filepath.Abs(p) + + if nil != err { + return "",err + } + return s,nil +} diff --git a/views/book/create.tpl b/views/book/create.tpl index 1b6cb10b..88932d58 100644 --- a/views/book/create.tpl +++ b/views/book/create.tpl @@ -28,7 +28,9 @@ diff --git a/views/book/dashboard.tpl b/views/book/dashboard.tpl index d2f30550..4fe7eb55 100644 --- a/views/book/dashboard.tpl +++ b/views/book/dashboard.tpl @@ -28,7 +28,9 @@ @@ -45,7 +47,10 @@ {{if ne .Model.RoleId 3}} 编辑 + {{end}} 阅读 + + {{if eq .Model.RoleId 0 1 2}} 发布 {{end}} diff --git a/views/book/index.tpl b/views/book/index.tpl index 2f921047..64d9967c 100644 --- a/views/book/index.tpl +++ b/views/book/index.tpl @@ -47,7 +47,14 @@
diff --git a/views/book/setting.tpl b/views/book/setting.tpl index d09b93d0..f66b8cce 100644 --- a/views/book/setting.tpl +++ b/views/book/setting.tpl @@ -10,7 +10,8 @@ - + + @@ -36,25 +37,26 @@
项目设置 - {{if eq .Model.RoleId 0 1}} {{if eq .Model.RoleId 0}} - - {{end}} - - {{end}} + {{if eq .Model.PrivatelyOwned 1}} - + {{else}} - + {{end}} + + + {{end}} +
-
+ +
- +
@@ -63,11 +65,11 @@
-

描述信息不超过300个字符

+

描述信息不超过500个字符

- +

最多允许添加10个标签,多个标签请用“;”分割

@@ -91,18 +93,18 @@
-
- +
+
-
- - +
+ +
{{end}}
- +
@@ -122,9 +124,307 @@
{{template "widgets/footer.tpl" .}}
- - - + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/views/book/users.tpl b/views/book/users.tpl index b0a6c253..e18bdc6c 100644 --- a/views/book/users.tpl +++ b/views/book/users.tpl @@ -28,7 +28,9 @@
@@ -36,7 +38,9 @@
成员管理 + {{if eq .Model.RoleId 0 1}} + {{end}}
@@ -64,7 +68,7 @@
  • 观察者
  • - +