| @@ -1,7 +1,10 @@ | |||||
| package models | package models | ||||
| import ( | import ( | ||||
| "code.gitea.io/gitea/modules/setting" | |||||
| "code.gitea.io/gitea/modules/timeutil" | "code.gitea.io/gitea/modules/timeutil" | ||||
| "path/filepath" | |||||
| "strings" | |||||
| "xorm.io/builder" | "xorm.io/builder" | ||||
| ) | ) | ||||
| @@ -20,14 +23,15 @@ type Badge struct { | |||||
| func (m *Badge) ToUserShow() *Badge4UserShow { | func (m *Badge) ToUserShow() *Badge4UserShow { | ||||
| return &Badge4UserShow{ | return &Badge4UserShow{ | ||||
| Name: m.Name, | Name: m.Name, | ||||
| LightedIcon: m.LightedIcon, | |||||
| GreyedIcon: m.GreyedIcon, | |||||
| LightedIcon: GetIconOuterLink(m.LightedIcon), | |||||
| GreyedIcon: GetIconOuterLink(m.GreyedIcon), | |||||
| Url: m.Url, | Url: m.Url, | ||||
| } | } | ||||
| } | } | ||||
| type GetBadgeOpts struct { | type GetBadgeOpts struct { | ||||
| BadgeType BadgeType | BadgeType BadgeType | ||||
| LO ListOptions | |||||
| } | } | ||||
| type BadgeAndCategory struct { | type BadgeAndCategory struct { | ||||
| @@ -43,8 +47,8 @@ func (m *BadgeAndCategory) ToShow() *Badge4AdminShow { | |||||
| return &Badge4AdminShow{ | return &Badge4AdminShow{ | ||||
| ID: m.Badge.ID, | ID: m.Badge.ID, | ||||
| Name: m.Badge.Name, | Name: m.Badge.Name, | ||||
| LightedIcon: m.Badge.LightedIcon, | |||||
| GreyedIcon: m.Badge.GreyedIcon, | |||||
| LightedIcon: GetIconOuterLink(m.Badge.LightedIcon), | |||||
| GreyedIcon: GetIconOuterLink(m.Badge.GreyedIcon), | |||||
| Url: m.Badge.Url, | Url: m.Badge.Url, | ||||
| CategoryName: m.Category.Name, | CategoryName: m.Category.Name, | ||||
| CategoryId: m.Category.ID, | CategoryId: m.Category.ID, | ||||
| @@ -75,6 +79,25 @@ func (m Badge4AdminShow) ToDTO() Badge { | |||||
| } | } | ||||
| } | } | ||||
| type BadgeOperateReq struct { | |||||
| ID int64 | |||||
| Name string | |||||
| LightedIcon string | |||||
| GreyedIcon string | |||||
| Url string | |||||
| CategoryId int64 | |||||
| } | |||||
| func (m BadgeOperateReq) ToDTO() Badge { | |||||
| return Badge{ | |||||
| Name: m.Name, | |||||
| LightedIcon: m.LightedIcon, | |||||
| GreyedIcon: m.GreyedIcon, | |||||
| Url: m.Url, | |||||
| CategoryId: m.CategoryId, | |||||
| } | |||||
| } | |||||
| type Badge4UserShow struct { | type Badge4UserShow struct { | ||||
| Name string | Name string | ||||
| LightedIcon string | LightedIcon string | ||||
| @@ -94,17 +117,23 @@ type UserAllBadgeInCategory struct { | |||||
| Badges []*BadgeShowWithStatus | Badges []*BadgeShowWithStatus | ||||
| } | } | ||||
| func GetBadgeList(opts GetBadgeOpts) ([]*BadgeAndCategory, error) { | |||||
| func GetBadgeList(opts GetBadgeOpts) (int64, []*BadgeAndCategory, error) { | |||||
| if opts.LO.Page <= 0 { | |||||
| opts.LO.Page = 1 | |||||
| } | |||||
| var cond = builder.NewCond() | var cond = builder.NewCond() | ||||
| if opts.BadgeType > 0 { | if opts.BadgeType > 0 { | ||||
| cond = cond.And(builder.Eq{"badge_category.type": opts.BadgeType}) | cond = cond.And(builder.Eq{"badge_category.type": opts.BadgeType}) | ||||
| } | } | ||||
| n, err := x.Join("INNER", "badge_category", "badge_category.ID = badge.category_id").Where(cond).Count(&BadgeAndCategory{}) | |||||
| if err != nil { | |||||
| return 0, nil, err | |||||
| } | |||||
| r := make([]*BadgeAndCategory, 0) | r := make([]*BadgeAndCategory, 0) | ||||
| if err := x.Join("INNER", "badge_category", "badge_category.ID = badge.category_id").Where(cond).OrderBy("badge.created_unix desc").Find(&r); err != nil { | |||||
| return nil, err | |||||
| if err = x.Join("INNER", "badge_category", "badge_category.ID = badge.category_id").Where(cond).OrderBy("badge.created_unix desc").Limit(opts.LO.PageSize, (opts.LO.Page-1)*opts.LO.PageSize).Find(&r); err != nil { | |||||
| return 0, nil, err | |||||
| } | } | ||||
| return r, nil | |||||
| return n, r, nil | |||||
| } | } | ||||
| func AddBadge(m Badge) (int64, error) { | func AddBadge(m Badge) (int64, error) { | ||||
| @@ -135,3 +164,14 @@ func GetBadgeByCategoryId(categoryId int64) ([]*Badge, error) { | |||||
| err := x.Where("category_id = ?", categoryId).Find(&r) | err := x.Where("category_id = ?", categoryId).Find(&r) | ||||
| return r, err | return r, err | ||||
| } | } | ||||
| func GetCustomIconByHash(hash string) string { | |||||
| if len(hash) == 0 { | |||||
| return "" | |||||
| } | |||||
| return filepath.Join(setting.IconUploadPath, hash) | |||||
| } | |||||
| func GetIconOuterLink(hash string) string { | |||||
| return strings.TrimRight(setting.AppSubURL, "/") + "/show/icon/" + hash | |||||
| } | |||||
| @@ -47,6 +47,21 @@ func (m BadgeCategory4Show) ToDTO() BadgeCategory { | |||||
| } | } | ||||
| } | } | ||||
| func GetBadgeCategoryListPaging(opts ListOptions) (int64, []*BadgeCategory, error) { | |||||
| n, err := x.Count(&BadgeCategory{}) | |||||
| if err != nil { | |||||
| return 0, nil, err | |||||
| } | |||||
| if opts.Page <= 0 { | |||||
| opts.Page = 1 | |||||
| } | |||||
| r := make([]*BadgeCategory, 0) | |||||
| if err := x.OrderBy("position asc,created_unix desc").Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).Find(&r); err != nil { | |||||
| return 0, nil, err | |||||
| } | |||||
| return n, r, nil | |||||
| } | |||||
| func GetBadgeCategoryList() ([]*BadgeCategory, error) { | func GetBadgeCategoryList() ([]*BadgeCategory, error) { | ||||
| r := make([]*BadgeCategory, 0) | r := make([]*BadgeCategory, 0) | ||||
| if err := x.OrderBy("position asc,created_unix desc").Find(&r); err != nil { | if err := x.OrderBy("position asc,created_unix desc").Find(&r); err != nil { | ||||
| @@ -73,7 +88,7 @@ func GetBadgeCategoryById(id int64) (*BadgeCategory, error) { | |||||
| if err != nil { | if err != nil { | ||||
| return nil, err | return nil, err | ||||
| } else if !has { | } else if !has { | ||||
| return nil, &ErrRecordNotExist{} | |||||
| return nil, ErrRecordNotExist{} | |||||
| } | } | ||||
| return m, nil | return m, nil | ||||
| } | } | ||||
| @@ -12,8 +12,8 @@ const ( | |||||
| type BadgeUser struct { | type BadgeUser struct { | ||||
| ID int64 `xorm:"pk autoincr"` | ID int64 `xorm:"pk autoincr"` | ||||
| UserId int64 `xorm:"unique(user_id,badge_id)"` | |||||
| BadgeId int64 `xorm:"index"` | |||||
| UserId int64 `xorm:"unique(user_badge)"` | |||||
| BadgeId int64 `xorm:"unique(user_badge) index"` | |||||
| CreatedUnix timeutil.TimeStamp `xorm:"created index"` | CreatedUnix timeutil.TimeStamp `xorm:"created index"` | ||||
| } | } | ||||
| @@ -115,19 +115,23 @@ func DelBadgeUser(id int64) (int64, error) { | |||||
| return n, sess.Commit() | return n, sess.Commit() | ||||
| } | } | ||||
| func GetBadgeUsers(badgeId int64, opts ListOptions) ([]BadgeUserDetail, error) { | |||||
| func GetBadgeUsers(badgeId int64, opts ListOptions) (int64, []BadgeUserDetail, error) { | |||||
| n, err := x.Join("LEFT", "public.user", "public.user.ID = badge_user.user_id").Where("badge_user.badge_id = ?", badgeId).Count(&BadgeUserDetail{}) | |||||
| if err != nil { | |||||
| return 0, nil, err | |||||
| } | |||||
| if opts.Page <= 0 { | if opts.Page <= 0 { | ||||
| opts.Page = 1 | opts.Page = 1 | ||||
| } | } | ||||
| m := make([]BadgeUserDetail, 0) | m := make([]BadgeUserDetail, 0) | ||||
| err := x.Join("LEFT", "public.user", "public.user.ID = badge_user.user_id").Where("badge_user.badge_id = ?", badgeId).OrderBy("badge_user.created_unix desc").Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).Find(&m) | |||||
| err = x.Join("LEFT", "public.user", "public.user.ID = badge_user.user_id").Where("badge_user.badge_id = ?", badgeId).OrderBy("badge_user.id desc").Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).Find(&m) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, err | |||||
| return 0, nil, err | |||||
| } | } | ||||
| return m, nil | |||||
| return n, m, nil | |||||
| } | } | ||||
| func GetUserBadges(userId int64, opts GetUserBadgesOpts) ([]*Badge, error) { | |||||
| func GetUserBadgesPaging(userId int64, opts GetUserBadgesOpts) ([]*Badge, error) { | |||||
| cond := builder.NewCond() | cond := builder.NewCond() | ||||
| cond = cond.And(builder.Eq{"badge_user.user_id": userId}) | cond = cond.And(builder.Eq{"badge_user.user_id": userId}) | ||||
| if opts.CategoryId > 0 { | if opts.CategoryId > 0 { | ||||
| @@ -135,6 +139,18 @@ func GetUserBadges(userId int64, opts GetUserBadgesOpts) ([]*Badge, error) { | |||||
| } | } | ||||
| r := make([]*Badge, 0) | r := make([]*Badge, 0) | ||||
| err := x.Join("INNER", "badge_user", "badge_user.badge_id = badge.id").Where(cond).OrderBy("badge_user.created_unix desc").Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).Find(&r) | |||||
| err := x.Join("INNER", "badge_user", "badge_user.badge_id = badge.id").Where(cond).OrderBy("badge_user.id desc").Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).Find(&r) | |||||
| return r, err | |||||
| } | |||||
| func GetUserBadges(userId, categoryId int64) ([]*Badge, error) { | |||||
| cond := builder.NewCond() | |||||
| cond = cond.And(builder.Eq{"badge_user.user_id": userId}) | |||||
| if categoryId > 0 { | |||||
| cond = cond.And(builder.Eq{"badge.category_id": categoryId}) | |||||
| } | |||||
| r := make([]*Badge, 0) | |||||
| err := x.Join("INNER", "badge_user", "badge_user.badge_id = badge.id").Where(cond).OrderBy("badge_user.created_unix desc").Find(&r) | |||||
| return r, err | return r, err | ||||
| } | } | ||||
| @@ -622,6 +622,13 @@ var ( | |||||
| DeductTaskRange time.Duration | DeductTaskRange time.Duration | ||||
| DeductTaskRangeForFirst time.Duration | DeductTaskRangeForFirst time.Duration | ||||
| //badge config | |||||
| BadgeIconMaxFileSize int64 | |||||
| BadgeIconMaxWidth int | |||||
| BadgeIconMaxHeight int | |||||
| BadgeIconDefaultSize uint | |||||
| IconUploadPath string | |||||
| //wechat auto reply config | //wechat auto reply config | ||||
| UserNameOfWechatReply string | UserNameOfWechatReply string | ||||
| RepoNameOfWechatReply string | RepoNameOfWechatReply string | ||||
| @@ -1515,6 +1522,14 @@ func NewContext() { | |||||
| CloudBrainPayInterval = sec.Key("CLOUDBRAIN_PAY_INTERVAL").MustDuration(60 * time.Minute) | CloudBrainPayInterval = sec.Key("CLOUDBRAIN_PAY_INTERVAL").MustDuration(60 * time.Minute) | ||||
| DeductTaskRange = sec.Key("DEDUCT_TASK_RANGE").MustDuration(30 * time.Minute) | DeductTaskRange = sec.Key("DEDUCT_TASK_RANGE").MustDuration(30 * time.Minute) | ||||
| DeductTaskRangeForFirst = sec.Key("DEDUCT_TASK_RANGE_FOR_FIRST").MustDuration(3 * time.Hour) | DeductTaskRangeForFirst = sec.Key("DEDUCT_TASK_RANGE_FOR_FIRST").MustDuration(3 * time.Hour) | ||||
| sec = Cfg.Section("icons") | |||||
| BadgeIconMaxFileSize = sec.Key("BADGE_ICON_MAX_FILE_SIZE").MustInt64(1048576) | |||||
| BadgeIconMaxWidth = sec.Key("BADGE_ICON_MAX_WIDTH").MustInt(4096) | |||||
| BadgeIconMaxHeight = sec.Key("BADGE_ICON_MAX_HEIGHT").MustInt(3072) | |||||
| BadgeIconDefaultSize = sec.Key("BADGE_ICON_DEFAULT_SIZE").MustUint(200) | |||||
| IconUploadPath = sec.Key("ICON_UPLOAD_PATH").MustString(path.Join(AppDataPath, "icons")) | |||||
| SetRadarMapConfig() | SetRadarMapConfig() | ||||
| sec = Cfg.Section("warn_mail") | sec = Cfg.Section("warn_mail") | ||||
| @@ -4,15 +4,19 @@ import ( | |||||
| "code.gitea.io/gitea/models" | "code.gitea.io/gitea/models" | ||||
| "code.gitea.io/gitea/modules/context" | "code.gitea.io/gitea/modules/context" | ||||
| "code.gitea.io/gitea/modules/log" | "code.gitea.io/gitea/modules/log" | ||||
| "code.gitea.io/gitea/modules/setting" | |||||
| "code.gitea.io/gitea/routers/response" | "code.gitea.io/gitea/routers/response" | ||||
| "code.gitea.io/gitea/services/badge" | "code.gitea.io/gitea/services/badge" | ||||
| "errors" | "errors" | ||||
| "github.com/unknwon/com" | |||||
| "net/http" | "net/http" | ||||
| "strings" | "strings" | ||||
| ) | ) | ||||
| func GetCustomizeBadgeList(ctx *context.Context) { | func GetCustomizeBadgeList(ctx *context.Context) { | ||||
| r, err := badge.GetBadgeList(models.GetBadgeOpts{BadgeType: models.CustomizeBadge}) | |||||
| page := ctx.QueryInt("page") | |||||
| pageSize := 50 | |||||
| n, r, err := badge.GetBadgeList(models.GetBadgeOpts{BadgeType: models.CustomizeBadge, LO: models.ListOptions{PageSize: pageSize, Page: page}}) | |||||
| if err != nil { | if err != nil { | ||||
| log.Error("GetCustomizeBadgeList error.%v", err) | log.Error("GetCustomizeBadgeList error.%v", err) | ||||
| ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | ||||
| @@ -20,20 +24,22 @@ func GetCustomizeBadgeList(ctx *context.Context) { | |||||
| } | } | ||||
| m := make(map[string]interface{}) | m := make(map[string]interface{}) | ||||
| m["List"] = r | m["List"] = r | ||||
| m["Total"] = n | |||||
| m["PageSize"] = pageSize | |||||
| ctx.JSON(http.StatusOK, response.SuccessWithData(m)) | ctx.JSON(http.StatusOK, response.SuccessWithData(m)) | ||||
| } | } | ||||
| func OperateBadge(ctx *context.Context, category models.Badge4AdminShow) { | |||||
| func OperateBadge(ctx *context.Context, req models.BadgeOperateReq) { | |||||
| action := ctx.Params(":action") | action := ctx.Params(":action") | ||||
| var err error | var err error | ||||
| switch action { | switch action { | ||||
| case "edit": | case "edit": | ||||
| err = badge.EditBadge(category, ctx.User) | |||||
| err = badge.EditBadge(req, ctx.User) | |||||
| case "new": | case "new": | ||||
| err = badge.AddBadge(category, ctx.User) | |||||
| err = badge.AddBadge(req, ctx.User) | |||||
| case "del": | case "del": | ||||
| err = badge.DelBadge(category.ID, ctx.User) | |||||
| err = badge.DelBadge(req.ID, ctx.User) | |||||
| default: | default: | ||||
| err = errors.New("action type error") | err = errors.New("action type error") | ||||
| } | } | ||||
| @@ -49,7 +55,8 @@ func OperateBadge(ctx *context.Context, category models.Badge4AdminShow) { | |||||
| func GetBadgeUsers(ctx *context.Context) { | func GetBadgeUsers(ctx *context.Context) { | ||||
| page := ctx.QueryInt("page") | page := ctx.QueryInt("page") | ||||
| badgeId := ctx.QueryInt64("badge") | badgeId := ctx.QueryInt64("badge") | ||||
| r, err := badge.GetBadgeUsers(badgeId, models.ListOptions{PageSize: 20, Page: page}) | |||||
| pageSize := 50 | |||||
| n, r, err := badge.GetBadgeUsers(badgeId, models.ListOptions{PageSize: pageSize, Page: page}) | |||||
| if err != nil { | if err != nil { | ||||
| log.Error("GetBadgeUsers error.%v", err) | log.Error("GetBadgeUsers error.%v", err) | ||||
| ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | ||||
| @@ -57,6 +64,8 @@ func GetBadgeUsers(ctx *context.Context) { | |||||
| } | } | ||||
| m := make(map[string]interface{}) | m := make(map[string]interface{}) | ||||
| m["List"] = r | m["List"] = r | ||||
| m["Total"] = n | |||||
| m["PageSize"] = pageSize | |||||
| ctx.JSON(http.StatusOK, response.SuccessWithData(m)) | ctx.JSON(http.StatusOK, response.SuccessWithData(m)) | ||||
| } | } | ||||
| @@ -96,3 +105,30 @@ func DelBadgeUsers(ctx *context.Context, req models.DelBadgeUserReq) { | |||||
| } | } | ||||
| ctx.JSON(http.StatusOK, response.Success()) | ctx.JSON(http.StatusOK, response.Success()) | ||||
| } | } | ||||
| func UploadIcon(ctx *context.Context, form badge.IconUploadForm) { | |||||
| uploader := badge.NewIconUploader(badge.IconUploadConfig{ | |||||
| FileMaxSize: setting.BadgeIconMaxFileSize, | |||||
| FileMaxWidth: setting.BadgeIconMaxWidth, | |||||
| FileMaxHeight: setting.BadgeIconMaxHeight, | |||||
| }) | |||||
| iconName, err := uploader.Upload(form, ctx.User) | |||||
| if err != nil { | |||||
| log.Error("UploadIcon error.%v", err) | |||||
| ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | |||||
| return | |||||
| } | |||||
| m := make(map[string]string, 0) | |||||
| m["IconName"] = iconName | |||||
| ctx.JSON(http.StatusOK, response.SuccessWithData(m)) | |||||
| } | |||||
| func GetIcon(ctx *context.Context) { | |||||
| hash := ctx.Params(":hash") | |||||
| if !com.IsFile(models.GetCustomIconByHash(hash)) { | |||||
| ctx.NotFound(ctx.Req.URL.RequestURI(), nil) | |||||
| return | |||||
| } | |||||
| ctx.Redirect(setting.AppSubURL + "/icons/" + hash) | |||||
| } | |||||
| @@ -11,7 +11,9 @@ import ( | |||||
| ) | ) | ||||
| func GetBadgeCategoryList(ctx *context.Context) { | func GetBadgeCategoryList(ctx *context.Context) { | ||||
| r, err := badge.GetBadgeCategoryList() | |||||
| page := ctx.QueryInt("page") | |||||
| pageSize := 50 | |||||
| n, r, err := badge.GetBadgeCategoryList(models.ListOptions{Page: page, PageSize: pageSize}) | |||||
| if err != nil { | if err != nil { | ||||
| log.Error("GetCategoryList error.%v", err) | log.Error("GetCategoryList error.%v", err) | ||||
| ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | ctx.JSON(http.StatusOK, response.ServerError(err.Error())) | ||||
| @@ -19,6 +21,8 @@ func GetBadgeCategoryList(ctx *context.Context) { | |||||
| } | } | ||||
| m := make(map[string]interface{}) | m := make(map[string]interface{}) | ||||
| m["List"] = r | m["List"] = r | ||||
| m["Total"] = n | |||||
| m["PageSize"] = pageSize | |||||
| ctx.JSON(http.StatusOK, response.SuccessWithData(m)) | ctx.JSON(http.StatusOK, response.SuccessWithData(m)) | ||||
| } | } | ||||
| @@ -9,6 +9,7 @@ import ( | |||||
| "code.gitea.io/gitea/routers/badge" | "code.gitea.io/gitea/routers/badge" | ||||
| "code.gitea.io/gitea/routers/reward/point" | "code.gitea.io/gitea/routers/reward/point" | ||||
| "code.gitea.io/gitea/routers/task" | "code.gitea.io/gitea/routers/task" | ||||
| badge_service "code.gitea.io/gitea/services/badge" | |||||
| "code.gitea.io/gitea/services/reward" | "code.gitea.io/gitea/services/reward" | ||||
| "encoding/gob" | "encoding/gob" | ||||
| "net/http" | "net/http" | ||||
| @@ -194,6 +195,14 @@ func NewMacaron() *macaron.Macaron { | |||||
| ExpiresAfter: setting.StaticCacheTime, | ExpiresAfter: setting.StaticCacheTime, | ||||
| }, | }, | ||||
| )) | )) | ||||
| m.Use(public.StaticHandler( | |||||
| setting.IconUploadPath, | |||||
| &public.Options{ | |||||
| Prefix: "icons", | |||||
| SkipLogging: setting.DisableRouterLog, | |||||
| ExpiresAfter: setting.StaticCacheTime, | |||||
| }, | |||||
| )) | |||||
| m.Use(public.StaticHandler( | m.Use(public.StaticHandler( | ||||
| setting.RepositoryAvatarUploadPath, | setting.RepositoryAvatarUploadPath, | ||||
| &public.Options{ | &public.Options{ | ||||
| @@ -518,6 +527,8 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| m.Get("/avatar/:hash", user.AvatarByEmailHash) | m.Get("/avatar/:hash", user.AvatarByEmailHash) | ||||
| m.Get("/show/icon/:hash", badge.GetIcon) | |||||
| adminReq := context.Toggle(&context.ToggleOptions{SignInRequired: true, AdminRequired: true}) | adminReq := context.Toggle(&context.ToggleOptions{SignInRequired: true, AdminRequired: true}) | ||||
| // ***** START: Admin ***** | // ***** START: Admin ***** | ||||
| @@ -670,16 +681,15 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| }) | }) | ||||
| m.Group("/customize", func() { | m.Group("/customize", func() { | ||||
| m.Get("/list", badge.GetCustomizeBadgeList) | m.Get("/list", badge.GetCustomizeBadgeList) | ||||
| }) | }) | ||||
| m.Group("/users", func() { | m.Group("/users", func() { | ||||
| m.Get("", badge.GetBadgeUsers) | m.Get("", badge.GetBadgeUsers) | ||||
| m.Post("/add", bindIgnErr(models.AddBadgeUsersReq{}), badge.AddOperateBadgeUsers) | m.Post("/add", bindIgnErr(models.AddBadgeUsersReq{}), badge.AddOperateBadgeUsers) | ||||
| m.Post("/del", bindIgnErr(models.DelBadgeUserReq{}), badge.DelBadgeUsers) | m.Post("/del", bindIgnErr(models.DelBadgeUserReq{}), badge.DelBadgeUsers) | ||||
| }) | }) | ||||
| m.Post("/^:action(new|edit|del)$", bindIgnErr(models.Badge4AdminShow{}), badge.OperateBadge) | |||||
| m.Post("/^:action(new|edit|del)$", bindIgnErr(models.BadgeOperateReq{}), badge.OperateBadge) | |||||
| }) | }) | ||||
| m.Post("/icon/upload", bindIgnErr(badge_service.IconUploadForm{}), badge.UploadIcon) | |||||
| }, operationReq) | }, operationReq) | ||||
| // ***** END: Operation ***** | // ***** END: Operation ***** | ||||
| @@ -6,7 +6,9 @@ | |||||
| package user | package user | ||||
| import ( | import ( | ||||
| "code.gitea.io/gitea/modules/log" | |||||
| "code.gitea.io/gitea/services/badge" | "code.gitea.io/gitea/services/badge" | ||||
| "encoding/json" | |||||
| "errors" | "errors" | ||||
| "fmt" | "fmt" | ||||
| "path" | "path" | ||||
| @@ -103,6 +105,8 @@ func Profile(ctx *context.Context) { | |||||
| ctx.Data["Owner"] = ctxUser | ctx.Data["Owner"] = ctxUser | ||||
| ctx.Data["OpenIDs"] = openIDs | ctx.Data["OpenIDs"] = openIDs | ||||
| ctx.Data["RecentBadges"] = badges | ctx.Data["RecentBadges"] = badges | ||||
| b, _ := json.Marshal(badges) | |||||
| log.Info(string(b)) | |||||
| ctx.Data["EnableHeatmap"] = setting.Service.EnableUserHeatmap | ctx.Data["EnableHeatmap"] = setting.Service.EnableUserHeatmap | ||||
| ctx.Data["HeatmapUser"] = ctxUser.Name | ctx.Data["HeatmapUser"] = ctxUser.Name | ||||
| showPrivate := ctx.IsSigned && (ctx.User.IsAdmin || ctx.User.ID == ctxUser.ID) | showPrivate := ctx.IsSigned && (ctx.User.IsAdmin || ctx.User.ID == ctxUser.ID) | ||||
| @@ -312,6 +316,8 @@ func Profile(ctx *context.Context) { | |||||
| ctx.ServerError("GetUserAllBadges", err) | ctx.ServerError("GetUserAllBadges", err) | ||||
| return | return | ||||
| } | } | ||||
| ab, _ := json.Marshal(allBadges) | |||||
| log.Info(string(ab)) | |||||
| ctx.Data["AllBadges"] = allBadges | ctx.Data["AllBadges"] = allBadges | ||||
| default: | default: | ||||
| ctx.ServerError("tab error", errors.New("tab error")) | ctx.ServerError("tab error", errors.New("tab error")) | ||||
| @@ -7,24 +7,32 @@ import ( | |||||
| "errors" | "errors" | ||||
| ) | ) | ||||
| func GetBadgeList(opts models.GetBadgeOpts) ([]*models.Badge4AdminShow, error) { | |||||
| list, err := models.GetBadgeList(opts) | |||||
| func GetBadgeList(opts models.GetBadgeOpts) (int64, []*models.Badge4AdminShow, error) { | |||||
| total, list, err := models.GetBadgeList(opts) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, err | |||||
| return 0, nil, err | |||||
| } | } | ||||
| if len(list) == 0 { | if len(list) == 0 { | ||||
| return nil, nil | |||||
| return 0, nil, nil | |||||
| } | } | ||||
| r := make([]*models.Badge4AdminShow, len(list)) | r := make([]*models.Badge4AdminShow, len(list)) | ||||
| for i := 0; i < len(list); i++ { | for i := 0; i < len(list); i++ { | ||||
| r[i] = list[i].ToShow() | r[i] = list[i].ToShow() | ||||
| } | } | ||||
| return r, nil | |||||
| return total, r, nil | |||||
| } | } | ||||
| func AddBadge(m models.Badge4AdminShow, doer *models.User) error { | |||||
| _, err := models.AddBadge(m.ToDTO()) | |||||
| func AddBadge(m models.BadgeOperateReq, doer *models.User) error { | |||||
| _, err := models.GetBadgeCategoryById(m.CategoryId) | |||||
| if err != nil { | |||||
| if models.IsErrRecordNotExist(err) { | |||||
| return errors.New("badge category is not available") | |||||
| } | |||||
| return err | |||||
| } | |||||
| _, err = models.AddBadge(m.ToDTO()) | |||||
| if err != nil { | if err != nil { | ||||
| return err | return err | ||||
| } | } | ||||
| @@ -32,7 +40,7 @@ func AddBadge(m models.Badge4AdminShow, doer *models.User) error { | |||||
| return nil | return nil | ||||
| } | } | ||||
| func EditBadge(m models.Badge4AdminShow, doer *models.User) error { | |||||
| func EditBadge(m models.BadgeOperateReq, doer *models.User) error { | |||||
| if m.ID == 0 { | if m.ID == 0 { | ||||
| log.Error(" EditBadge param error") | log.Error(" EditBadge param error") | ||||
| return errors.New("param error") | return errors.New("param error") | ||||
| @@ -7,20 +7,20 @@ import ( | |||||
| "errors" | "errors" | ||||
| ) | ) | ||||
| func GetBadgeCategoryList() ([]*models.BadgeCategory4Show, error) { | |||||
| list, err := models.GetBadgeCategoryList() | |||||
| func GetBadgeCategoryList(opts models.ListOptions) (int64, []*models.BadgeCategory4Show, error) { | |||||
| total, list, err := models.GetBadgeCategoryListPaging(opts) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, err | |||||
| return 0, nil, err | |||||
| } | } | ||||
| if len(list) == 0 { | if len(list) == 0 { | ||||
| return nil, nil | |||||
| return 0, nil, nil | |||||
| } | } | ||||
| r := make([]*models.BadgeCategory4Show, len(list)) | r := make([]*models.BadgeCategory4Show, len(list)) | ||||
| for i := 0; i < len(list); i++ { | for i := 0; i < len(list); i++ { | ||||
| r[i] = list[i].ToShow() | r[i] = list[i].ToShow() | ||||
| } | } | ||||
| return r, nil | |||||
| return total, r, nil | |||||
| } | } | ||||
| func AddBadgeCategory(m models.BadgeCategory4Show, doer *models.User) error { | func AddBadgeCategory(m models.BadgeCategory4Show, doer *models.User) error { | ||||
| @@ -0,0 +1,109 @@ | |||||
| package badge | |||||
| import ( | |||||
| "bytes" | |||||
| "code.gitea.io/gitea/models" | |||||
| "code.gitea.io/gitea/modules/base" | |||||
| "code.gitea.io/gitea/modules/setting" | |||||
| "crypto/md5" | |||||
| "errors" | |||||
| "fmt" | |||||
| "image" | |||||
| "image/png" | |||||
| "io/ioutil" | |||||
| "mime/multipart" | |||||
| "os" | |||||
| ) | |||||
| type IconUploader struct { | |||||
| Config IconUploadConfig | |||||
| } | |||||
| type IconUploadForm struct { | |||||
| Icon *multipart.FileHeader | |||||
| } | |||||
| type IconUploadConfig struct { | |||||
| FileMaxSize int64 | |||||
| FileMaxWidth int | |||||
| FileMaxHeight int | |||||
| } | |||||
| func NewIconUploader(config IconUploadConfig) IconUploader { | |||||
| return IconUploader{Config: config} | |||||
| } | |||||
| func (u IconUploader) Upload(form IconUploadForm, user *models.User) (string, error) { | |||||
| if form.Icon == nil || form.Icon.Filename == "" { | |||||
| return "", errors.New("File or fileName is empty") | |||||
| } | |||||
| fr, err := form.Icon.Open() | |||||
| if err != nil { | |||||
| return "", fmt.Errorf("Icon.Open: %v", err) | |||||
| } | |||||
| defer fr.Close() | |||||
| if form.Icon.Size > u.Config.FileMaxSize { | |||||
| return "", errors.New("File is too large") | |||||
| } | |||||
| data, err := ioutil.ReadAll(fr) | |||||
| if err != nil { | |||||
| return "", fmt.Errorf("ioutil.ReadAll: %v", err) | |||||
| } | |||||
| if !base.IsImageFile(data) { | |||||
| return "", errors.New("File is not a image") | |||||
| } | |||||
| iconName, err := u.uploadIcon(data, user.ID) | |||||
| if err != nil { | |||||
| return "", fmt.Errorf("uploadIcon: %v", err) | |||||
| } | |||||
| return iconName, nil | |||||
| } | |||||
| func (u IconUploader) uploadIcon(data []byte, userId int64) (string, error) { | |||||
| m, err := u.prepare(data) | |||||
| if err != nil { | |||||
| return "", err | |||||
| } | |||||
| iconName := fmt.Sprintf("%x", md5.Sum([]byte(fmt.Sprintf("%d-%x", userId, md5.Sum(data))))) | |||||
| if err := os.MkdirAll(setting.IconUploadPath, os.ModePerm); err != nil { | |||||
| return "", fmt.Errorf("uploadIcon. Failed to create dir %s: %v", setting.AvatarUploadPath, err) | |||||
| } | |||||
| fw, err := os.Create(models.GetCustomIconByHash(iconName)) | |||||
| if err != nil { | |||||
| return "", fmt.Errorf("Create: %v", err) | |||||
| } | |||||
| defer fw.Close() | |||||
| if err = png.Encode(fw, *m); err != nil { | |||||
| return "", fmt.Errorf("Encode: %v", err) | |||||
| } | |||||
| return iconName, nil | |||||
| } | |||||
| func (u IconUploader) prepare(data []byte) (*image.Image, error) { | |||||
| imgCfg, _, err := image.DecodeConfig(bytes.NewReader(data)) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("DecodeConfig: %v", err) | |||||
| } | |||||
| if imgCfg.Width > u.Config.FileMaxWidth { | |||||
| return nil, fmt.Errorf("Image width is too large: %d > %d", imgCfg.Width, setting.AvatarMaxWidth) | |||||
| } | |||||
| if imgCfg.Height > u.Config.FileMaxHeight { | |||||
| return nil, fmt.Errorf("Image height is too large: %d > %d", imgCfg.Height, setting.AvatarMaxHeight) | |||||
| } | |||||
| img, _, err := image.Decode(bytes.NewReader(data)) | |||||
| if err != nil { | |||||
| return nil, fmt.Errorf("Decode: %v", err) | |||||
| } | |||||
| return &img, nil | |||||
| } | |||||
| @@ -5,20 +5,20 @@ import ( | |||||
| "code.gitea.io/gitea/modules/log" | "code.gitea.io/gitea/modules/log" | ||||
| ) | ) | ||||
| func GetBadgeUsers(badgeId int64, opts models.ListOptions) ([]*models.BadgeUser4SHow, error) { | |||||
| list, err := models.GetBadgeUsers(badgeId, opts) | |||||
| func GetBadgeUsers(badgeId int64, opts models.ListOptions) (int64, []*models.BadgeUser4SHow, error) { | |||||
| total, list, err := models.GetBadgeUsers(badgeId, opts) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, err | |||||
| return 0, nil, err | |||||
| } | } | ||||
| if len(list) == 0 { | if len(list) == 0 { | ||||
| return nil, nil | |||||
| return 0, nil, nil | |||||
| } | } | ||||
| r := make([]*models.BadgeUser4SHow, len(list)) | r := make([]*models.BadgeUser4SHow, len(list)) | ||||
| for i := 0; i < len(list); i++ { | for i := 0; i < len(list); i++ { | ||||
| r[i] = list[i].ToShow() | r[i] = list[i].ToShow() | ||||
| } | } | ||||
| return r, nil | |||||
| return total, r, nil | |||||
| } | } | ||||
| func AddBadgeUsers(badgeId int64, userNames []string) (int, error) { | func AddBadgeUsers(badgeId int64, userNames []string) (int, error) { | ||||
| @@ -49,7 +49,7 @@ func DelBadgeUser(id int64) error { | |||||
| //GetUserBadges Only Returns badges the user has earned | //GetUserBadges Only Returns badges the user has earned | ||||
| func GetUserBadges(userId int64, opts models.ListOptions) ([]*models.Badge4UserShow, error) { | func GetUserBadges(userId int64, opts models.ListOptions) ([]*models.Badge4UserShow, error) { | ||||
| badges, err := models.GetUserBadges(userId, models.GetUserBadgesOpts{ListOptions: opts}) | |||||
| badges, err := models.GetUserBadgesPaging(userId, models.GetUserBadgesOpts{ListOptions: opts}) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, err | return nil, err | ||||
| } | } | ||||
| @@ -68,7 +68,10 @@ func GetUserAllBadges(userId int64) ([]models.UserAllBadgeInCategory, error) { | |||||
| r := make([]models.UserAllBadgeInCategory, len(categoryList)) | r := make([]models.UserAllBadgeInCategory, len(categoryList)) | ||||
| for i, v := range categoryList { | for i, v := range categoryList { | ||||
| badges, err := models.GetBadgeByCategoryId(v.ID) | badges, err := models.GetBadgeByCategoryId(v.ID) | ||||
| userBadgeMap, err := getUserBadgesMap(userId, v.ID, 100, 1) | |||||
| if badges == nil || len(badges) == 0 { | |||||
| continue | |||||
| } | |||||
| userBadgeMap, err := getUserBadgesMap(userId, v.ID) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, err | return nil, err | ||||
| } | } | ||||
| @@ -91,8 +94,8 @@ func GetUserAllBadges(userId int64) ([]models.UserAllBadgeInCategory, error) { | |||||
| return r, nil | return r, nil | ||||
| } | } | ||||
| func getUserBadgesMap(userId, categoryId int64, pageSize, page int) (map[int64]*models.Badge, error) { | |||||
| userBadges, err := models.GetUserBadges(userId, models.GetUserBadgesOpts{ListOptions: models.ListOptions{PageSize: pageSize, Page: page}, CategoryId: categoryId}) | |||||
| func getUserBadgesMap(userId, categoryId int64) (map[int64]*models.Badge, error) { | |||||
| userBadges, err := models.GetUserBadges(userId, categoryId) | |||||
| if err != nil { | if err != nil { | ||||
| return nil, err | return nil, err | ||||
| } | } | ||||