diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go index 309af935..d4034b6b 100644 --- a/cmd/wire_gen.go +++ b/cmd/wire_gen.go @@ -267,7 +267,8 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, badgeService := badge2.NewBadgeService(badgeRepo, badgeGroupRepo, badgeAwardRepo, badgeEventService) badgeAwardService := badge2.NewBadgeAwardService(badgeAwardRepo, badgeRepo, userCommon, objService) badgeController := controller.NewBadgeController(badgeService, badgeAwardService) - answerAPIRouter := router.NewAnswerAPIRouter(langController, userController, commentController, reportController, voteController, tagController, followController, collectionController, questionController, answerController, searchController, revisionController, rankController, userAdminController, reasonController, themeController, siteInfoController, controllerSiteInfoController, notificationController, dashboardController, uploadController, activityController, roleController, pluginController, permissionController, userPluginController, reviewController, metaController, badgeController) + controller_adminBadgeController := controller_admin.NewBadgeController(badgeService) + answerAPIRouter := router.NewAnswerAPIRouter(langController, userController, commentController, reportController, voteController, tagController, followController, collectionController, questionController, answerController, searchController, revisionController, rankController, userAdminController, reasonController, themeController, siteInfoController, controllerSiteInfoController, notificationController, dashboardController, uploadController, activityController, roleController, pluginController, permissionController, userPluginController, reviewController, metaController, badgeController, controller_adminBadgeController) swaggerRouter := router.NewSwaggerRouter(swaggerConf) uiRouter := router.NewUIRouter(controllerSiteInfoController, siteInfoCommonService) authUserMiddleware := middleware.NewAuthUserMiddleware(authService, siteInfoCommonService) diff --git a/docs/docs.go b/docs/docs.go index ecc62169..eaa7133a 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -154,6 +154,113 @@ const docTemplate = `{ } } }, + "/answer/admin/api/badge/status": { + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "update badge status", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AdminBadge" + ], + "summary": "update badge status", + "parameters": [ + { + "description": "UpdateBadgeStatusReq", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/schema.UpdateBadgeStatusReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handler.RespBody" + } + } + } + } + }, + "/answer/admin/api/badges": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "list all badges by page", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AdminBadge" + ], + "summary": "list all badges by page", + "parameters": [ + { + "type": "integer", + "description": "page", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "page size", + "name": "page_size", + "in": "query" + }, + { + "enum": [ + "", + "active", + "inactive" + ], + "type": "string", + "description": "badge status", + "name": "status", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/schema.GetBadgeListPagedResp" + } + } + } + } + ] + } + } + } + } + }, "/answer/admin/api/dashboard": { "get": { "security": [ @@ -7652,6 +7759,17 @@ const docTemplate = `{ } } }, + "schema.BadgeStatus": { + "type": "string", + "enum": [ + "active", + "inactive" + ], + "x-enum-varnames": [ + "BadgeStatusActive", + "BadgeStatusInactive" + ] + }, "schema.CloseQuestionReq": { "type": "object", "required": [ @@ -7944,6 +8062,55 @@ const docTemplate = `{ } } }, + "schema.GetBadgeListPagedResp": { + "type": "object", + "properties": { + "award_count": { + "description": "badge award count", + "type": "integer" + }, + "description": { + "description": "badge description", + "type": "string" + }, + "earned": { + "description": "badge earned count", + "type": "boolean" + }, + "group_name": { + "description": "badge group name", + "type": "string" + }, + "icon": { + "description": "badge icon", + "type": "string" + }, + "id": { + "description": "badge id", + "type": "string" + }, + "level": { + "description": "badge level", + "allOf": [ + { + "$ref": "#/definitions/entity.BadgeLevel" + } + ] + }, + "name": { + "description": "badge name", + "type": "string" + }, + "status": { + "description": "badge status", + "allOf": [ + { + "$ref": "#/definitions/schema.BadgeStatus" + } + ] + } + } + }, "schema.GetBadgeListResp": { "type": "object", "properties": { @@ -10446,6 +10613,27 @@ const docTemplate = `{ } } }, + "schema.UpdateBadgeStatusReq": { + "type": "object", + "required": [ + "id", + "status" + ], + "properties": { + "id": { + "description": "badge id", + "type": "string" + }, + "status": { + "description": "badge status", + "allOf": [ + { + "$ref": "#/definitions/schema.BadgeStatus" + } + ] + } + } + }, "schema.UpdateCommentReq": { "type": "object", "required": [ diff --git a/docs/swagger.json b/docs/swagger.json index 1412f179..116a3a6a 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -124,6 +124,113 @@ } } }, + "/answer/admin/api/badge/status": { + "put": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "update badge status", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AdminBadge" + ], + "summary": "update badge status", + "parameters": [ + { + "description": "UpdateBadgeStatusReq", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/schema.UpdateBadgeStatusReq" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handler.RespBody" + } + } + } + } + }, + "/answer/admin/api/badges": { + "get": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "list all badges by page", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "AdminBadge" + ], + "summary": "list all badges by page", + "parameters": [ + { + "type": "integer", + "description": "page", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "description": "page size", + "name": "page_size", + "in": "query" + }, + { + "enum": [ + "", + "active", + "inactive" + ], + "type": "string", + "description": "badge status", + "name": "status", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/handler.RespBody" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/schema.GetBadgeListPagedResp" + } + } + } + } + ] + } + } + } + } + }, "/answer/admin/api/dashboard": { "get": { "security": [ @@ -7622,6 +7729,17 @@ } } }, + "schema.BadgeStatus": { + "type": "string", + "enum": [ + "active", + "inactive" + ], + "x-enum-varnames": [ + "BadgeStatusActive", + "BadgeStatusInactive" + ] + }, "schema.CloseQuestionReq": { "type": "object", "required": [ @@ -7914,6 +8032,55 @@ } } }, + "schema.GetBadgeListPagedResp": { + "type": "object", + "properties": { + "award_count": { + "description": "badge award count", + "type": "integer" + }, + "description": { + "description": "badge description", + "type": "string" + }, + "earned": { + "description": "badge earned count", + "type": "boolean" + }, + "group_name": { + "description": "badge group name", + "type": "string" + }, + "icon": { + "description": "badge icon", + "type": "string" + }, + "id": { + "description": "badge id", + "type": "string" + }, + "level": { + "description": "badge level", + "allOf": [ + { + "$ref": "#/definitions/entity.BadgeLevel" + } + ] + }, + "name": { + "description": "badge name", + "type": "string" + }, + "status": { + "description": "badge status", + "allOf": [ + { + "$ref": "#/definitions/schema.BadgeStatus" + } + ] + } + } + }, "schema.GetBadgeListResp": { "type": "object", "properties": { @@ -10416,6 +10583,27 @@ } } }, + "schema.UpdateBadgeStatusReq": { + "type": "object", + "required": [ + "id", + "status" + ], + "properties": { + "id": { + "description": "badge id", + "type": "string" + }, + "status": { + "description": "badge status", + "allOf": [ + { + "$ref": "#/definitions/schema.BadgeStatus" + } + ] + } + } + }, "schema.UpdateCommentReq": { "type": "object", "required": [ diff --git a/docs/swagger.yaml b/docs/swagger.yaml index e2fc6682..116b5932 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -374,6 +374,14 @@ definitions: description: badge name type: string type: object + schema.BadgeStatus: + enum: + - active + - inactive + type: string + x-enum-varnames: + - BadgeStatusActive + - BadgeStatusInactive schema.CloseQuestionReq: properties: close_msg: @@ -573,6 +581,38 @@ definitions: description: badge name type: string type: object + schema.GetBadgeListPagedResp: + properties: + award_count: + description: badge award count + type: integer + description: + description: badge description + type: string + earned: + description: badge earned count + type: boolean + group_name: + description: badge group name + type: string + icon: + description: badge icon + type: string + id: + description: badge id + type: string + level: + allOf: + - $ref: '#/definitions/entity.BadgeLevel' + description: badge level + name: + description: badge name + type: string + status: + allOf: + - $ref: '#/definitions/schema.BadgeStatus' + description: badge status + type: object schema.GetBadgeListResp: properties: badges: @@ -2307,6 +2347,19 @@ definitions: url_title: type: string type: object + schema.UpdateBadgeStatusReq: + properties: + id: + description: badge id + type: string + status: + allOf: + - $ref: '#/definitions/schema.BadgeStatus' + description: badge status + required: + - id + - status + type: object schema.UpdateCommentReq: properties: captcha_code: @@ -2924,6 +2977,71 @@ paths: summary: update answer status tags: - admin + /answer/admin/api/badge/status: + put: + consumes: + - application/json + description: update badge status + parameters: + - description: UpdateBadgeStatusReq + in: body + name: data + required: true + schema: + $ref: '#/definitions/schema.UpdateBadgeStatusReq' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handler.RespBody' + security: + - ApiKeyAuth: [] + summary: update badge status + tags: + - AdminBadge + /answer/admin/api/badges: + get: + consumes: + - application/json + description: list all badges by page + parameters: + - description: page + in: query + name: page + type: integer + - description: page size + in: query + name: page_size + type: integer + - description: badge status + enum: + - "" + - active + - inactive + in: query + name: status + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/handler.RespBody' + - properties: + data: + items: + $ref: '#/definitions/schema.GetBadgeListPagedResp' + type: array + type: object + security: + - ApiKeyAuth: [] + summary: list all badges by page + tags: + - AdminBadge /answer/admin/api/dashboard: get: consumes: diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml index 0d7f2ecf..071644f4 100644 --- a/i18n/en_US.yaml +++ b/i18n/en_US.yaml @@ -146,6 +146,8 @@ backend: common: invalid_url: other: Invalid URL. + status_invalid: + other: Invalid status. password: space_invalid: other: Password cannot contain spaces. @@ -776,6 +778,16 @@ backend: other: Famous Link desc: other: Posted an external link with 100 clicks. + default_badge_groups: + getting_started: + name: + other: Getting Started + community: + name: + other: Community + posting: + name: + other: Posting # The following fields are used for interface presentation(Front-end) ui: diff --git a/internal/base/reason/reason.go b/internal/base/reason/reason.go index a6168690..24d7ab5f 100644 --- a/internal/base/reason/reason.go +++ b/internal/base/reason/reason.go @@ -107,6 +107,7 @@ const ( InvalidURLError = "error.common.invalid_url" MetaObjectNotFound = "error.meta.object_not_found" BadgeObjectNotFound = "error.badge.object_not_found" + StatusInvalid = "error.common.status_invalid" ) // user external login reasons diff --git a/internal/controller_admin/badge_controller.go b/internal/controller_admin/badge_controller.go new file mode 100644 index 00000000..8842592f --- /dev/null +++ b/internal/controller_admin/badge_controller.go @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package controller_admin + +import ( + "github.com/apache/incubator-answer/internal/base/handler" + "github.com/apache/incubator-answer/internal/base/pager" + "github.com/apache/incubator-answer/internal/schema" + "github.com/apache/incubator-answer/internal/service/badge" + "github.com/gin-gonic/gin" +) + +type BadgeController struct { + badgeService *badge.BadgeService +} + +func NewBadgeController(badgeService *badge.BadgeService) *BadgeController { + return &BadgeController{ + badgeService: badgeService, + } +} + +// GetBadgeList list all badges by page +// @Summary list all badges by page +// @Description list all badges by page +// @Tags AdminBadge +// @Accept json +// @Produce json +// @Security ApiKeyAuth +// @Param page query int false "page" +// @Param page_size query int false "page size" +// @Param status query string false "badge status" Enums(, active, inactive) +// @Success 200 {object} handler.RespBody{data=[]schema.GetBadgeListPagedResp} +// @Router /answer/admin/api/badges [get] +func (b *BadgeController) GetBadgeList(ctx *gin.Context) { + req := &schema.GetBadgeListPagedReq{} + if handler.BindAndCheck(ctx, req) { + return + } + + resp, total, err := b.badgeService.ListPaged(ctx, req) + if err != nil { + handler.HandleResponse(ctx, err, nil) + return + } + + handler.HandleResponse(ctx, nil, pager.NewPageModel(total, resp)) +} + +// UpdateBadgeStatus update badge status +// @Summary update badge status +// @Description update badge status +// @Tags AdminBadge +// @Accept json +// @Produce json +// @Security ApiKeyAuth +// @Param data body schema.UpdateBadgeStatusReq true "UpdateBadgeStatusReq" +// @Success 200 {object} handler.RespBody +// @Router /answer/admin/api/badge/status [put] +func (b *BadgeController) UpdateBadgeStatus(ctx *gin.Context) { + req := &schema.UpdateBadgeStatusReq{} + if handler.BindAndCheck(ctx, req) { + return + } + + err := b.badgeService.UpdateStatus(ctx, req) + handler.HandleResponse(ctx, err, nil) +} diff --git a/internal/controller_admin/controller.go b/internal/controller_admin/controller.go index de87d105..ebf32cbf 100644 --- a/internal/controller_admin/controller.go +++ b/internal/controller_admin/controller.go @@ -28,4 +28,5 @@ var ProviderSetController = wire.NewSet( NewSiteInfoController, NewRoleController, NewPluginController, + NewBadgeController, ) diff --git a/internal/entity/badge_award_entity.go b/internal/entity/badge_award_entity.go index 1d421623..0eb30227 100644 --- a/internal/entity/badge_award_entity.go +++ b/internal/entity/badge_award_entity.go @@ -28,7 +28,7 @@ const ( // BadgeAward badge_award type BadgeAward struct { - ID string `json:"id" xorm:"id"` + ID string `xorm:"not null pk BIGINT(20) id"` CreatedAt time.Time `json:"created_at" xorm:"created not null default CURRENT_TIMESTAMP TIMESTAMP created_at"` UpdatedAt time.Time `json:"updated_at" xorm:"updated not null default CURRENT_TIMESTAMP TIMESTAMP updated_at"` UserID string `json:"user_id" xorm:"not null index BIGINT(20) user_id"` diff --git a/internal/entity/badge_entity.go b/internal/entity/badge_entity.go index 96babcb9..5177c93c 100644 --- a/internal/entity/badge_entity.go +++ b/internal/entity/badge_entity.go @@ -41,7 +41,7 @@ const ( // Badge badge type Badge struct { - ID string `xorm:"not null pk autoincr BIGINT(20) id"` + ID string `xorm:"not null pk BIGINT(20) id"` CreatedAt time.Time `xorm:"created not null default CURRENT_TIMESTAMP TIMESTAMP created_at"` UpdatedAt time.Time `xorm:"updated not null default CURRENT_TIMESTAMP TIMESTAMP updated_at"` Name string `xorm:"not null default '' VARCHAR(256) name"` diff --git a/internal/migrations/v22.go b/internal/migrations/v22.go index f5793d4a..d3d81d84 100644 --- a/internal/migrations/v22.go +++ b/internal/migrations/v22.go @@ -30,9 +30,9 @@ import ( var ( defaultBadgeGroupTable = []*entity.BadgeGroup{ - {ID: "1", Name: "Getting Started"}, - {ID: "2", Name: "Community"}, - {ID: "3", Name: "Posting"}, + {ID: "1", Name: "badge.default_badge_groups.getting_started.name"}, + {ID: "2", Name: "badge.default_badge_groups.community.name"}, + {ID: "3", Name: "badge.default_badge_groups.posting.name"}, } defaultBadgeTable = []*entity.Badge{ diff --git a/internal/repo/badge/badge_repo.go b/internal/repo/badge/badge_repo.go index d4d2f992..ebdb0425 100644 --- a/internal/repo/badge/badge_repo.go +++ b/internal/repo/badge/badge_repo.go @@ -22,11 +22,13 @@ package badge import ( "context" "github.com/apache/incubator-answer/internal/base/data" + "github.com/apache/incubator-answer/internal/base/pager" "github.com/apache/incubator-answer/internal/base/reason" "github.com/apache/incubator-answer/internal/entity" "github.com/apache/incubator-answer/internal/service/badge" "github.com/apache/incubator-answer/internal/service/unique" "github.com/segmentfault/pacman/errors" + "xorm.io/xorm" ) type badgeRepo struct { @@ -90,10 +92,29 @@ func (r *badgeRepo) ListByLevelAndGroup(ctx context.Context, level entity.BadgeL return } -// ListActivated returns a list of activated badges -func (r *badgeRepo) ListActivated(ctx context.Context) (badges []*entity.Badge, err error) { +// ListPaged returns a list of activated badges +func (r *badgeRepo) ListPaged(ctx context.Context, page int, pageSize int) (badges []*entity.Badge, total int64, err error) { badges = make([]*entity.Badge, 0) - err = r.data.DB.Context(ctx).Where("status = ?", entity.BadgeStatusActive).Find(&badges) + session := r.data.DB.Context(ctx).Where("status <> ?", entity.BadgeStatusDeleted) + total, err = pager.Help(page, pageSize, &badges, &entity.Badge{}, session) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + } + return +} + +// ListActivated returns a list of activated badges +func (r *badgeRepo) ListActivated(ctx context.Context, page int, pageSize int) (badges []*entity.Badge, total int64, err error) { + badges = make([]*entity.Badge, 0) + total = 0 + + session := r.data.DB.Context(ctx).Where("status = ?", entity.BadgeStatusActive) + if page == 0 || pageSize == 0 { + err = session.Find(&badges) + } else { + total, err = pager.Help(page, pageSize, &badges, &entity.Badge{}, session) + } + if err != nil { err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() } @@ -101,9 +122,17 @@ func (r *badgeRepo) ListActivated(ctx context.Context) (badges []*entity.Badge, } // ListInactivated returns a list of inactivated badges -func (r *badgeRepo) ListInactivated(ctx context.Context) (badges []*entity.Badge, err error) { +func (r *badgeRepo) ListInactivated(ctx context.Context, page int, pageSize int) (badges []*entity.Badge, total int64, err error) { badges = make([]*entity.Badge, 0) - err = r.data.DB.Context(ctx).Where("status = ?", entity.BadgeStatusInactive).Find(&badges) + total = 0 + + session := r.data.DB.Context(ctx).Where("status = ?", entity.BadgeStatusInactive) + if page == 0 || pageSize == 0 { + err = session.Find(&badges) + } else { + total, err = pager.Help(page, pageSize, &badges, &entity.Badge{}, session) + } + if err != nil { err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() } @@ -115,3 +144,28 @@ func (r *badgeRepo) UpdateAwardCount(ctx context.Context, id string, count int64 _, err = r.data.DB.Context(ctx).Where("id = ?", id).Incr("award_count", count).Update(&entity.Badge{}) return } + +// UpdateStatus updates the award count of a badge +func (r *badgeRepo) UpdateStatus(ctx context.Context, id string, status int8) (err error) { + _, err = r.data.DB.Transaction(func(session *xorm.Session) (result any, err error) { + _, err = session.ID(id).Update(&entity.Badge{ + Status: status, + }) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(session.Rollback()).WithStack() + return + } + if status >= entity.BadgeStatusDeleted { + _, err = session.Where("badge_id = ?", id).Cols("is_badge_deleted").Update(&entity.BadgeAward{ + IsBadgeDeleted: entity.IsBadgeDeleted, + }) + } else { + _, err = session.Where("badge_id = ?", id).Cols("is_badge_deleted").Update(&entity.BadgeAward{ + IsBadgeDeleted: entity.IsBadgeNotDeleted, + }) + } + return + }) + + return +} diff --git a/internal/router/answer_api_router.go b/internal/router/answer_api_router.go index f343d7d1..b4ec3bdc 100644 --- a/internal/router/answer_api_router.go +++ b/internal/router/answer_api_router.go @@ -56,6 +56,7 @@ type AnswerAPIRouter struct { reviewController *controller.ReviewController metaController *controller.MetaController badgeController *controller.BadgeController + adminBadgeController *controller_admin.BadgeController } func NewAnswerAPIRouter( @@ -88,6 +89,7 @@ func NewAnswerAPIRouter( reviewController *controller.ReviewController, metaController *controller.MetaController, badgeController *controller.BadgeController, + adminBadgeController *controller_admin.BadgeController, ) *AnswerAPIRouter { return &AnswerAPIRouter{ langController: langController, @@ -119,6 +121,7 @@ func NewAnswerAPIRouter( reviewController: reviewController, metaController: metaController, badgeController: badgeController, + adminBadgeController: adminBadgeController, } } @@ -369,4 +372,8 @@ func (a *AnswerAPIRouter) RegisterAnswerAdminAPIRouter(r *gin.RouterGroup) { r.PUT("/plugin/status", a.pluginController.UpdatePluginStatus) r.GET("/plugin/config", a.pluginController.GetPluginConfig) r.PUT("/plugin/config", a.pluginController.UpdatePluginConfig) + + // badge + r.GET("/badges", a.adminBadgeController.GetBadgeList) + r.PUT("/badge/status", a.adminBadgeController.UpdateBadgeStatus) } diff --git a/internal/schema/badge_schema.go b/internal/schema/badge_schema.go index cae2aa66..39a2e2ae 100644 --- a/internal/schema/badge_schema.go +++ b/internal/schema/badge_schema.go @@ -21,6 +21,23 @@ package schema import "github.com/apache/incubator-answer/internal/entity" +const ( + BadgeStatusActive BadgeStatus = "active" + BadgeStatusInactive BadgeStatus = "inactive" +) + +type BadgeStatus string + +var BadgeStatusMap = map[int8]BadgeStatus{ + entity.BadgeStatusActive: BadgeStatusActive, + entity.BadgeStatusInactive: BadgeStatusInactive, +} + +var BadgeStatusEMap = map[BadgeStatus]int8{ + BadgeStatusActive: entity.BadgeStatusActive, + BadgeStatusInactive: entity.BadgeStatusInactive, +} + // BadgeListInfo get badge list response type BadgeListInfo struct { // badge id @@ -44,6 +61,43 @@ type GetBadgeListResp struct { GroupName string `json:"group_name" ` } +type UpdateBadgeStatusReq struct { + // badge id + ID string `validate:"required" json:"id"` + // badge status + Status BadgeStatus `validate:"required" json:"status"` +} + +type GetBadgeListPagedReq struct { + // page + Page int `validate:"omitempty,min=1" form:"page"` + // page size + PageSize int `validate:"omitempty,min=1" form:"page_size"` + // badge status + Status BadgeStatus `validate:"omitempty" form:"status"` +} + +type GetBadgeListPagedResp struct { + // badge id + ID string `json:"id" ` + // badge name + Name string `json:"name" ` + // badge description + Description string `json:"description" ` + // badge icon + Icon string `json:"icon" ` + // badge award count + AwardCount int `json:"award_count" ` + // badge earned count + Earned bool `json:"earned" ` + // badge level + Level entity.BadgeLevel `json:"level" ` + // badge group name + GroupName string `json:"group_name" ` + // badge status + Status BadgeStatus `json:"status"` +} + type GetBadgeInfoResp struct { // badge id ID string `json:"id" ` diff --git a/internal/service/badge/badge_service.go b/internal/service/badge/badge_service.go index 32a54a8d..7daab796 100644 --- a/internal/service/badge/badge_service.go +++ b/internal/service/badge/badge_service.go @@ -39,10 +39,12 @@ type BadgeRepo interface { ListByLevel(ctx context.Context, level entity.BadgeLevel) ([]*entity.Badge, error) ListByGroup(ctx context.Context, groupID int64) ([]*entity.Badge, error) ListByLevelAndGroup(ctx context.Context, level entity.BadgeLevel, groupID int64) ([]*entity.Badge, error) - ListActivated(ctx context.Context) ([]*entity.Badge, error) - ListInactivated(ctx context.Context) ([]*entity.Badge, error) + ListPaged(ctx context.Context, page int, pageSize int) (badges []*entity.Badge, total int64, err error) + ListActivated(ctx context.Context, page int, pageSize int) (badges []*entity.Badge, total int64, err error) + ListInactivated(ctx context.Context, page int, pageSize int) (badges []*entity.Badge, total int64, err error) - UpdateAwardCount(ctx context.Context, id string, count int64) error + UpdateAwardCount(ctx context.Context, id string, count int64) (err error) + UpdateStatus(ctx context.Context, id string, status int8) (err error) } type BadgeService struct { @@ -82,7 +84,7 @@ func (b *BadgeService) ListByGroup(ctx context.Context, userID string) (resp []* if err != nil { return } - badges, err = b.badgeRepo.ListActivated(ctx) + badges, _, err = b.badgeRepo.ListActivated(ctx, 0, 0) if err != nil { return } @@ -95,7 +97,7 @@ func (b *BadgeService) ListByGroup(ctx context.Context, userID string) (resp []* } for _, group := range groups { - groupMap[converter.StringToInt64(group.ID)] = group.Name + groupMap[converter.StringToInt64(group.ID)] = translator.Tr(handler.GetLangByCtx(ctx), group.Name) } for _, badge := range badges { @@ -122,7 +124,7 @@ func (b *BadgeService) ListByGroup(ctx context.Context, userID string) (resp []* for _, group := range groups { resp = append(resp, &schema.GetBadgeListResp{ - GroupName: group.Name, + GroupName: translator.Tr(handler.GetLangByCtx(ctx), group.Name), Badges: badgesMap[converter.StringToInt64(group.ID)], }) } @@ -130,6 +132,53 @@ func (b *BadgeService) ListByGroup(ctx context.Context, userID string) (resp []* return } +// ListPaged list all badges by page +func (b *BadgeService) ListPaged(ctx context.Context, req *schema.GetBadgeListPagedReq) (resp []*schema.GetBadgeListPagedResp, total int64, err error) { + var ( + groups []*entity.BadgeGroup + badges []*entity.Badge + groupMap = make(map[int64]string, 0) + ) + + switch req.Status { + case schema.BadgeStatusActive: + badges, total, err = b.badgeRepo.ListActivated(ctx, req.Page, req.PageSize) + case schema.BadgeStatusInactive: + badges, total, err = b.badgeRepo.ListInactivated(ctx, req.Page, req.PageSize) + default: + badges, total, err = b.badgeRepo.ListPaged(ctx, req.Page, req.PageSize) + } + + if err != nil { + return + } + + // find all group and build group map + groups, err = b.badgeGroupRepo.ListGroups(ctx) + if err != nil { + return + } + for _, group := range groups { + groupMap[converter.StringToInt64(group.ID)] = translator.Tr(handler.GetLangByCtx(ctx), group.Name) + } + + resp = make([]*schema.GetBadgeListPagedResp, len(badges)) + + for i, badge := range badges { + resp[i] = &schema.GetBadgeListPagedResp{ + ID: uid.EnShortID(badge.ID), + Name: translator.Tr(handler.GetLangByCtx(ctx), badge.Name), + Description: translator.Tr(handler.GetLangByCtx(ctx), badge.Description), + Icon: badge.Icon, + AwardCount: badge.AwardCount, + Level: badge.Level, + GroupName: groupMap[badge.BadgeGroupID], + Status: schema.BadgeStatusMap[badge.Status], + } + } + return +} + // GetBadgeInfo get badge info func (b *BadgeService) GetBadgeInfo(ctx *gin.Context, id string, userID string) (info *schema.GetBadgeInfoResp, err error) { var ( @@ -164,3 +213,35 @@ func (b *BadgeService) GetBadgeInfo(ctx *gin.Context, id string, userID string) } return } + +// UpdateStatus update badge status +func (b *BadgeService) UpdateStatus(ctx *gin.Context, req *schema.UpdateBadgeStatusReq) (err error) { + var ( + badge *entity.Badge + exists bool + ) + req.ID = uid.DeShortID(req.ID) + + badge, exists, err = b.badgeRepo.GetByID(ctx, req.ID) + if err != nil { + return + } + if !exists { + err = errors.BadRequest(reason.BadgeObjectNotFound) + return + } + + status, ok := schema.BadgeStatusEMap[req.Status] + // check duplicate action + if badge.Status == status { + return + } + + if !ok { + err = errors.BadRequest(reason.StatusInvalid) + return + } + + err = b.badgeRepo.UpdateStatus(ctx, req.ID, status) + return +}