This is an automated email from the ASF dual-hosted git repository.
kumfo pushed a commit to branch feat/1.4.0/badge
in repository https://gitbox.apache.org/repos/asf/incubator-answer.git
The following commit(s) were added to refs/heads/feat/1.4.0/badge by this push:
new 797ea9b9 feat(badge): badge info && badge award list
797ea9b9 is described below
commit 797ea9b9187847fde3dad778fd8c1715b0b5cd33
Author: kumfo <[email protected]>
AuthorDate: Thu Aug 8 16:41:17 2024 +0800
feat(badge): badge info && badge award list
---
cmd/wire_gen.go | 4 +-
docs/docs.go | 156 +++++++++++++++++++++
docs/swagger.json | 156 +++++++++++++++++++++
docs/swagger.yaml | 96 +++++++++++++
i18n/en_US.yaml | 3 +
internal/base/reason/reason.go | 1 +
internal/controller/badge_controller.go | 61 +++++++-
internal/entity/badge_award_entity.go | 8 +-
internal/repo/badge/badge_repo.go | 6 +
internal/repo/badge_award/badge_award_repo.go | 33 +++--
internal/router/answer_api_router.go | 2 +
internal/schema/badge.go | 34 -----
internal/schema/badge_schema.go | 70 +++++++++
internal/service/badge/badge_service.go | 52 ++++++-
.../service/badge_award/badge_award_service.go | 102 ++++++++++++--
15 files changed, 718 insertions(+), 66 deletions(-)
diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go
index c20aa2cf..30b3b65c 100644
--- a/cmd/wire_gen.go
+++ b/cmd/wire_gen.go
@@ -75,6 +75,7 @@ import (
"github.com/apache/incubator-answer/internal/service/answer_common"
auth2 "github.com/apache/incubator-answer/internal/service/auth"
badge2 "github.com/apache/incubator-answer/internal/service/badge"
+ badge_award2
"github.com/apache/incubator-answer/internal/service/badge_award"
collection2
"github.com/apache/incubator-answer/internal/service/collection"
"github.com/apache/incubator-answer/internal/service/collection_common"
comment2 "github.com/apache/incubator-answer/internal/service/comment"
@@ -261,7 +262,8 @@ func initApplication(debug bool, serverConf *conf.Server,
dbConf *data.Database,
badgeGroupRepo := badge_group.NewBadgeGroupRepo(dataData, uniqueIDRepo)
badgeAwardRepo := badge_award.NewBadgeAwardRepo(dataData, uniqueIDRepo)
badgeService := badge2.NewBadgeService(badgeRepo, badgeGroupRepo,
badgeAwardRepo)
- badgeController := controller.NewBadgeController(badgeService)
+ badgeAwardService := badge_award2.NewBadgeAwardService(badgeAwardRepo,
userCommon, objService, questionRepo, answerRepo)
+ 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, pluginCon [...]
swaggerRouter := router.NewSwaggerRouter(swaggerConf)
uiRouter := router.NewUIRouter(controllerSiteInfoController,
siteInfoCommonService)
diff --git a/docs/docs.go b/docs/docs.go
index 6fc76693..bda5a17b 100644
--- a/docs/docs.go
+++ b/docs/docs.go
@@ -2239,6 +2239,117 @@ const docTemplate = `{
}
}
},
+ "/answer/api/v1/badge": {
+ "get": {
+ "security": [
+ {
+ "ApiKeyAuth": []
+ }
+ ],
+ "description": "get badge info",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "api-badge"
+ ],
+ "summary": "get badge info",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "string",
+ "description": "id",
+ "name": "id",
+ "in": "query",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/handler.RespBody"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref":
"#/definitions/schema.GetBadgeInfoResp"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "/answer/api/v1/badge/awards/page": {
+ "get": {
+ "security": [
+ {
+ "ApiKeyAuth": []
+ }
+ ],
+ "description": "get badge award list",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "api-badge"
+ ],
+ "summary": "get badge award list",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "page",
+ "name": "page",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "page size",
+ "name": "page_size",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "badge id",
+ "name": "badge_id",
+ "in": "query",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/handler.RespBody"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref":
"#/definitions/schema.GetBadgeInfoResp"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
"/answer/api/v1/badges": {
"get": {
"security": [
@@ -6942,6 +7053,19 @@ const docTemplate = `{
}
}
},
+ "entity.BadgeLevel": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3
+ ],
+ "x-enum-varnames": [
+ "BadgeLevelBronze",
+ "BadgeLevelSilver",
+ "BadgeLevelGold"
+ ]
+ },
"handler.RespBody": {
"type": "object",
"properties": {
@@ -7400,6 +7524,9 @@ const docTemplate = `{
"id": {
"type": "string"
},
+ "level": {
+ "$ref": "#/definitions/entity.BadgeLevel"
+ },
"name": {
"type": "string"
}
@@ -7656,6 +7783,35 @@ const docTemplate = `{
}
}
},
+ "schema.GetBadgeInfoResp": {
+ "type": "object",
+ "properties": {
+ "award_count": {
+ "type": "integer"
+ },
+ "description": {
+ "type": "string"
+ },
+ "earned_count": {
+ "type": "integer"
+ },
+ "icon": {
+ "type": "string"
+ },
+ "id": {
+ "type": "string"
+ },
+ "is_single": {
+ "type": "boolean"
+ },
+ "level": {
+ "$ref": "#/definitions/entity.BadgeLevel"
+ },
+ "name": {
+ "type": "string"
+ }
+ }
+ },
"schema.GetBadgeListResp": {
"type": "object",
"properties": {
diff --git a/docs/swagger.json b/docs/swagger.json
index 45936363..5ea50e6b 100644
--- a/docs/swagger.json
+++ b/docs/swagger.json
@@ -2209,6 +2209,117 @@
}
}
},
+ "/answer/api/v1/badge": {
+ "get": {
+ "security": [
+ {
+ "ApiKeyAuth": []
+ }
+ ],
+ "description": "get badge info",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "api-badge"
+ ],
+ "summary": "get badge info",
+ "parameters": [
+ {
+ "type": "string",
+ "default": "string",
+ "description": "id",
+ "name": "id",
+ "in": "query",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/handler.RespBody"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref":
"#/definitions/schema.GetBadgeInfoResp"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
+ "/answer/api/v1/badge/awards/page": {
+ "get": {
+ "security": [
+ {
+ "ApiKeyAuth": []
+ }
+ ],
+ "description": "get badge award list",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "api-badge"
+ ],
+ "summary": "get badge award list",
+ "parameters": [
+ {
+ "type": "integer",
+ "description": "page",
+ "name": "page",
+ "in": "query"
+ },
+ {
+ "type": "integer",
+ "description": "page size",
+ "name": "page_size",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "badge id",
+ "name": "badge_id",
+ "in": "query",
+ "required": true
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "schema": {
+ "allOf": [
+ {
+ "$ref": "#/definitions/handler.RespBody"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref":
"#/definitions/schema.GetBadgeInfoResp"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ },
"/answer/api/v1/badges": {
"get": {
"security": [
@@ -6912,6 +7023,19 @@
}
}
},
+ "entity.BadgeLevel": {
+ "type": "integer",
+ "enum": [
+ 1,
+ 2,
+ 3
+ ],
+ "x-enum-varnames": [
+ "BadgeLevelBronze",
+ "BadgeLevelSilver",
+ "BadgeLevelGold"
+ ]
+ },
"handler.RespBody": {
"type": "object",
"properties": {
@@ -7370,6 +7494,9 @@
"id": {
"type": "string"
},
+ "level": {
+ "$ref": "#/definitions/entity.BadgeLevel"
+ },
"name": {
"type": "string"
}
@@ -7626,6 +7753,35 @@
}
}
},
+ "schema.GetBadgeInfoResp": {
+ "type": "object",
+ "properties": {
+ "award_count": {
+ "type": "integer"
+ },
+ "description": {
+ "type": "string"
+ },
+ "earned_count": {
+ "type": "integer"
+ },
+ "icon": {
+ "type": "string"
+ },
+ "id": {
+ "type": "string"
+ },
+ "is_single": {
+ "type": "boolean"
+ },
+ "level": {
+ "$ref": "#/definitions/entity.BadgeLevel"
+ },
+ "name": {
+ "type": "string"
+ }
+ }
+ },
"schema.GetBadgeListResp": {
"type": "object",
"properties": {
diff --git a/docs/swagger.yaml b/docs/swagger.yaml
index c91c987e..ca11b20f 100644
--- a/docs/swagger.yaml
+++ b/docs/swagger.yaml
@@ -32,6 +32,16 @@ definitions:
minimum: 1
type: integer
type: object
+ entity.BadgeLevel:
+ enum:
+ - 1
+ - 2
+ - 3
+ type: integer
+ x-enum-varnames:
+ - BadgeLevelBronze
+ - BadgeLevelSilver
+ - BadgeLevelGold
handler.RespBody:
properties:
code:
@@ -352,6 +362,8 @@ definitions:
type: string
id:
type: string
+ level:
+ $ref: '#/definitions/entity.BadgeLevel'
name:
type: string
type: object
@@ -526,6 +538,25 @@ definitions:
description: if user is followed object will be true,otherwise false
type: boolean
type: object
+ schema.GetBadgeInfoResp:
+ properties:
+ award_count:
+ type: integer
+ description:
+ type: string
+ earned_count:
+ type: integer
+ icon:
+ type: string
+ id:
+ type: string
+ is_single:
+ type: boolean
+ level:
+ $ref: '#/definitions/entity.BadgeLevel'
+ name:
+ type: string
+ type: object
schema.GetBadgeListResp:
properties:
badges:
@@ -4105,6 +4136,71 @@ paths:
summary: recover answer
tags:
- Answer
+ /answer/api/v1/badge:
+ get:
+ consumes:
+ - application/json
+ description: get badge info
+ parameters:
+ - default: string
+ description: id
+ in: query
+ name: id
+ required: true
+ type: string
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ allOf:
+ - $ref: '#/definitions/handler.RespBody'
+ - properties:
+ data:
+ $ref: '#/definitions/schema.GetBadgeInfoResp'
+ type: object
+ security:
+ - ApiKeyAuth: []
+ summary: get badge info
+ tags:
+ - api-badge
+ /answer/api/v1/badge/awards/page:
+ get:
+ consumes:
+ - application/json
+ description: get badge award list
+ parameters:
+ - description: page
+ in: query
+ name: page
+ type: integer
+ - description: page size
+ in: query
+ name: page_size
+ type: integer
+ - description: badge id
+ in: query
+ name: badge_id
+ required: true
+ type: string
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: OK
+ schema:
+ allOf:
+ - $ref: '#/definitions/handler.RespBody'
+ - properties:
+ data:
+ $ref: '#/definitions/schema.GetBadgeInfoResp'
+ type: object
+ security:
+ - ApiKeyAuth: []
+ summary: get badge award list
+ tags:
+ - api-badge
/answer/api/v1/badges:
get:
consumes:
diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml
index f50465c2..0d7f2ecf 100644
--- a/i18n/en_US.yaml
+++ b/i18n/en_US.yaml
@@ -312,6 +312,9 @@ backend:
site_info:
config_not_found:
other: Site config not found.
+ badge:
+ object_not_found:
+ other: Badge object not found
reason:
spam:
name:
diff --git a/internal/base/reason/reason.go b/internal/base/reason/reason.go
index 66ef1bed..a6168690 100644
--- a/internal/base/reason/reason.go
+++ b/internal/base/reason/reason.go
@@ -106,6 +106,7 @@ const (
AddBulkUsersAmountError =
"error.user.add_bulk_users_amount_error"
InvalidURLError = "error.common.invalid_url"
MetaObjectNotFound = "error.meta.object_not_found"
+ BadgeObjectNotFound = "error.badge.object_not_found"
)
// user external login reasons
diff --git a/internal/controller/badge_controller.go
b/internal/controller/badge_controller.go
index ebc534ce..c26d9205 100644
--- a/internal/controller/badge_controller.go
+++ b/internal/controller/badge_controller.go
@@ -22,17 +22,25 @@ package controller
import (
"github.com/apache/incubator-answer/internal/base/handler"
"github.com/apache/incubator-answer/internal/base/middleware"
+ "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/apache/incubator-answer/internal/service/badge_award"
+ "github.com/apache/incubator-answer/pkg/uid"
"github.com/gin-gonic/gin"
)
type BadgeController struct {
- badgeService *badge.BadgeService
+ badgeService *badge.BadgeService
+ badgeAwardService *badge_award.BadgeAwardService
}
-func NewBadgeController(badgeService *badge.BadgeService) *BadgeController {
+func NewBadgeController(
+ badgeService *badge.BadgeService,
+ badgeAwardService *badge_award.BadgeAwardService) *BadgeController {
return &BadgeController{
- badgeService: badgeService,
+ badgeService: badgeService,
+ badgeAwardService: badgeAwardService,
}
}
@@ -50,3 +58,50 @@ func (b *BadgeController) GetBadgeList(ctx *gin.Context) {
resp, err := b.badgeService.ListByGroup(ctx, userID)
handler.HandleResponse(ctx, err, resp)
}
+
+// GetBadgeInfo get badge info
+// @Summary get badge info
+// @Description get badge info
+// @Tags api-badge
+// @Accept json
+// @Produce json
+// @Security ApiKeyAuth
+// @Param id query string true "id" default(string)
+// @Success 200 {object} handler.RespBody{data=schema.GetBadgeInfoResp}
+// @Router /answer/api/v1/badge [get]
+func (b *BadgeController) GetBadgeInfo(ctx *gin.Context) {
+ id := ctx.Query("id")
+ id = uid.DeShortID(id)
+
+ userID := middleware.GetLoginUserIDFromContext(ctx)
+ resp, err := b.badgeService.GetBadgeInfo(ctx, id, userID)
+ handler.HandleResponse(ctx, err, resp)
+}
+
+// GetBadgeAwardList get badge award list
+// @Summary get badge award list
+// @Description get badge award list
+// @Tags api-badge
+// @Accept json
+// @Produce json
+// @Security ApiKeyAuth
+// @Param page query int false "page"
+// @Param page_size query int false "page size"
+// @Param badge_id query string true "badge id"
+// @Success 200 {object} handler.RespBody{data=schema.GetBadgeInfoResp}
+// @Router /answer/api/v1/badge/awards/page [get]
+func (b *BadgeController) GetBadgeAwardList(ctx *gin.Context) {
+ req := &schema.GetBadgeAwardWithPageReq{}
+ if handler.BindAndCheck(ctx, req) {
+ return
+ }
+ req.BadgeID = uid.DeShortID(req.BadgeID)
+ req.UserID = middleware.GetLoginUserIDFromContext(ctx)
+
+ resp, total, err := b.badgeAwardService.GetBadgeAwardList(ctx, req)
+ if err != nil {
+ handler.HandleResponse(ctx, err, nil)
+ return
+ }
+ handler.HandleResponse(ctx, nil, pager.NewPageModel(total, resp))
+}
diff --git a/internal/entity/badge_award_entity.go
b/internal/entity/badge_award_entity.go
index a852f6bd..a26fd8de 100644
--- a/internal/entity/badge_award_entity.go
+++ b/internal/entity/badge_award_entity.go
@@ -26,10 +26,10 @@ type BadgeAward struct {
ID string `json:"id" xorm:"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 int64 `json:"user_id" xorm:"not null index
BIGINT(20) user_id"`
- BadgeId int64 `json:"badge_id" xorm:"not null index
BIGINT(20) badge_id"`
- ObjectId int64 `json:"object_id" xorm:"not null index
BIGINT(20) object_id"`
- BadgeGroupId int8 `json:"badge_group_id" xorm:"not null index
BIGINT(20) badge_group_id"`
+ UserID string `json:"user_id" xorm:"not null index
BIGINT(20) user_id"`
+ BadgeID string `json:"badge_id" xorm:"not null index
BIGINT(20) badge_id"`
+ ObjectID string `json:"object_id" xorm:"not null index
BIGINT(20) object_id"`
+ BadgeGroupID int8 `json:"badge_group_id" xorm:"not null index
BIGINT(20) badge_group_id"`
IsBadgeDeleted int8 `json:"is_badge_deleted" xorm:"not null index
TINYINT(1) s_badge_deleted"`
}
diff --git a/internal/repo/badge/badge_repo.go
b/internal/repo/badge/badge_repo.go
index b4cd72f1..7651f95b 100644
--- a/internal/repo/badge/badge_repo.go
+++ b/internal/repo/badge/badge_repo.go
@@ -40,6 +40,12 @@ func NewBadgeRepo(data *data.Data, uniqueIDRepo
unique.UniqueIDRepo) badge.Badge
}
}
+func (r badgeRepo) GetByID(ctx context.Context, id string) (badge
*entity.Badge, exists bool, err error) {
+ badge = &entity.Badge{}
+ exists, err = r.data.DB.Context(ctx).Where("id = ?", id).Get(badge)
+ return
+}
+
// ListByLevel returns a list of badges by level
func (r *badgeRepo) ListByLevel(ctx context.Context, level entity.BadgeLevel)
(badges []*entity.Badge, err error) {
badges = make([]*entity.Badge, 0)
diff --git a/internal/repo/badge_award/badge_award_repo.go
b/internal/repo/badge_award/badge_award_repo.go
index b6f0e95e..0a460347 100644
--- a/internal/repo/badge_award/badge_award_repo.go
+++ b/internal/repo/badge_award/badge_award_repo.go
@@ -22,9 +22,12 @@ package badge_award
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_award"
"github.com/apache/incubator-answer/internal/service/unique"
+ "github.com/segmentfault/pacman/errors"
"time"
)
@@ -53,6 +56,10 @@ func (r *badgeAwardRepo) CountByUserId(ctx context.Context,
userID string) (awar
return
}
func (r *badgeAwardRepo) CountByUserIdAndBadgeId(ctx context.Context, userID
string, badgeID string) (awardCount int64) {
+ awardCount, err := r.data.DB.Context(ctx).Where("user_id = ? AND
badge_id = ?", userID, badgeID).Count(&entity.BadgeAward{})
+ if err != nil {
+ return 0
+ }
return
}
func (r *badgeAwardRepo) CountByObjectId(ctx context.Context, objectID string)
(awardCount int64) {
@@ -71,31 +78,39 @@ func (r *badgeAwardRepo) SumUserEarnedGroupByBadgeID(ctx
context.Context, userID
func (r *badgeAwardRepo) ListAllByUserId(ctx context.Context, userID string)
(badgeAwards []*entity.BadgeAward) {
return
}
-func (r *badgeAwardRepo) ListPagedByBadgeId(ctx context.Context, badgeID
string, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total
int64) {
+
+// ListPagedByBadgeId list badge awards by badge id
+func (r *badgeAwardRepo) ListPagedByBadgeId(ctx context.Context, badgeID
string, page int, pageSize int) (badgeAwardList []*entity.BadgeAward, total
int64, err error) {
+ session := r.data.DB.Context(ctx)
+ session.Where("badge_id = ?", badgeID)
+ total, err = pager.Help(page, pageSize, &badgeAwardList,
&entity.Question{}, session)
+ if err != nil {
+ err =
errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
+ }
return
}
-func (r *badgeAwardRepo) ListPagedByBadgeIdAndUserId(ctx context.Context,
badgeID string, userID string, page int64, pageSize int64) (badgeAwards
[]*entity.BadgeAward, total int64) {
+func (r *badgeAwardRepo) ListPagedByBadgeIdAndUserId(ctx context.Context,
badgeID string, userID string, page int, pageSize int) (badgeAwards
[]*entity.BadgeAward, total int64, err error) {
return
}
-func (r *badgeAwardRepo) ListPagedByObjectId(ctx context.Context, badgeID
string, objectID string, page int64, pageSize int64) (badgeAwards
[]*entity.BadgeAward, total int64) {
+func (r *badgeAwardRepo) ListPagedByObjectId(ctx context.Context, badgeID
string, objectID string, page int, pageSize int) (badgeAwards
[]*entity.BadgeAward, total int64, err error) {
return
}
-func (r *badgeAwardRepo) ListPagedByObjectIdAndUserId(ctx context.Context,
badgeID string, objectID string, userID string, page int64, pageSize int64)
(badgeAwards []*entity.BadgeAward, total int64) {
+func (r *badgeAwardRepo) ListPagedByObjectIdAndUserId(ctx context.Context,
badgeID string, objectID string, userID string, page int, pageSize int)
(badgeAwards []*entity.BadgeAward, total int64, err error) {
return
}
-func (r *badgeAwardRepo) ListTagPagedByBadgeId(ctx context.Context, badgeIDs
[]int64, page int64, pageSize int64, filterUserID int64) (badgeAwards
[]*entity.BadgeAward, total int64) {
+func (r *badgeAwardRepo) ListTagPagedByBadgeId(ctx context.Context, badgeIDs
[]string, page int, pageSize int, filterUserID string) (badgeAwards
[]*entity.BadgeAward, total int64, err error) {
return
}
-func (r *badgeAwardRepo) ListTagPagedByBadgeIdAndUserId(ctx context.Context,
badgeIDs []int64, userID string, page int64, pageSize int64) (badgeAwards
[]*entity.BadgeAward, total int64) {
+func (r *badgeAwardRepo) ListTagPagedByBadgeIdAndUserId(ctx context.Context,
badgeIDs []string, userID string, page int, pageSize int) (badgeAwards
[]*entity.BadgeAward, total int64, err error) {
return
}
-func (r *badgeAwardRepo) ListPagedLatest(ctx context.Context, page int64,
pageSize int64) (badgeAwards []*entity.BadgeAward, total int64) {
+func (r *badgeAwardRepo) ListPagedLatest(ctx context.Context, page int,
pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) {
return
}
-func (r *badgeAwardRepo) ListNewestEarnedByLevel(ctx context.Context, userID
string, level entity.BadgeLevel, num int64) (badgeAwards []*entity.BadgeAward,
total int64) {
+func (r *badgeAwardRepo) ListNewestEarnedByLevel(ctx context.Context, userID
string, level entity.BadgeLevel, num int) (badgeAwards []*entity.BadgeAward,
total int64, err error) {
return
}
-func (r *badgeAwardRepo) ListNewestByUserIdAndLevel(ctx context.Context,
userID string, level int64, page int64, pageSize int64) (badgeAwards
[]*entity.BadgeAward, total int64) {
+func (r *badgeAwardRepo) ListNewestByUserIdAndLevel(ctx context.Context,
userID string, level int, page int, pageSize int) (badgeAwards
[]*entity.BadgeAward, total int64, err error) {
return
}
func (r *badgeAwardRepo) GetByUserIdAndBadgeId(ctx context.Context, userID
string, badgeID string) (badgeAward *entity.BadgeAward) {
diff --git a/internal/router/answer_api_router.go
b/internal/router/answer_api_router.go
index dadf2a85..c7d4c38e 100644
--- a/internal/router/answer_api_router.go
+++ b/internal/router/answer_api_router.go
@@ -192,6 +192,8 @@ func (a *AnswerAPIRouter) RegisterUnAuthAnswerAPIRouter(r
*gin.RouterGroup) {
r.GET("/meta/reaction", a.metaController.GetReaction)
// badges
+ r.GET("/badge", a.badgeController.GetBadgeInfo)
+ r.GET("/badge/awards/page", a.badgeController.GetBadgeAwardList)
r.GET("/badges", a.badgeController.GetBadgeList)
}
diff --git a/internal/schema/badge.go b/internal/schema/badge.go
deleted file mode 100644
index c52a235b..00000000
--- a/internal/schema/badge.go
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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 schema
-
-// BadgeListInfo get badge list response
-type BadgeListInfo struct {
- ID string `json:"id" `
- Name string `json:"name" `
- Icon string `json:"icon" `
- AwardCount int `json:"award_count" `
- Earned bool `json:"earned" `
-}
-
-type GetBadgeListResp struct {
- Badges []*BadgeListInfo `json:"badges" `
- GroupName string `json:"group_name" `
-}
diff --git a/internal/schema/badge_schema.go b/internal/schema/badge_schema.go
new file mode 100644
index 00000000..06d92ecc
--- /dev/null
+++ b/internal/schema/badge_schema.go
@@ -0,0 +1,70 @@
+/*
+ * 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 schema
+
+import "github.com/apache/incubator-answer/internal/entity"
+
+// BadgeListInfo get badge list response
+type BadgeListInfo struct {
+ ID string `json:"id" `
+ Name string `json:"name" `
+ Icon string `json:"icon" `
+ AwardCount int `json:"award_count" `
+ Earned bool `json:"earned" `
+ Level entity.BadgeLevel `json:"level" `
+}
+
+type GetBadgeListResp struct {
+ Badges []*BadgeListInfo `json:"badges" `
+ GroupName string `json:"group_name" `
+}
+
+type GetBadgeInfoResp struct {
+ ID string `json:"id" `
+ Name string `json:"name" `
+ Description string `json:"description" `
+ Icon string `json:"icon" `
+ AwardCount int `json:"award_count" `
+ EarnedCount int64 `json:"earned_count" `
+ IsSingle bool `json:"is_single" `
+ Level entity.BadgeLevel `json:"level" `
+}
+
+type GetBadgeAwardWithPageReq struct {
+ // page
+ Page int `validate:"omitempty,min=1" form:"page"`
+ // page size
+ PageSize int `validate:"omitempty,min=1" form:"page_size"`
+ // badge id
+ BadgeID string `validate:"required" form:"badge_id"`
+ // user id
+ UserID string `json:"-"`
+}
+
+type GetBadgeAwardWithPageResp struct {
+ CreatedAt int64 `json:"created_at"`
+ ObjectID string `json:"object_id"`
+ QuestionID string `json:"question_id"`
+ AnswerID string `json:"answer_id"`
+ CommentID string `json:"comment_id"`
+ ObjectType string `json:"object_type"
enums:"question,answer,comment"`
+ UrlTitle string `json:"url_title"`
+ AuthorUserInfo UserBasicInfo `json:"author_user_info"`
+}
diff --git a/internal/service/badge/badge_service.go
b/internal/service/badge/badge_service.go
index 1109b444..94ba5b64 100644
--- a/internal/service/badge/badge_service.go
+++ b/internal/service/badge/badge_service.go
@@ -22,15 +22,20 @@ package badge
import (
"context"
"github.com/apache/incubator-answer/internal/base/handler"
+ "github.com/apache/incubator-answer/internal/base/reason"
"github.com/apache/incubator-answer/internal/base/translator"
"github.com/apache/incubator-answer/internal/entity"
"github.com/apache/incubator-answer/internal/schema"
"github.com/apache/incubator-answer/internal/service/badge_award"
"github.com/apache/incubator-answer/internal/service/badge_group"
"github.com/apache/incubator-answer/pkg/converter"
+ "github.com/apache/incubator-answer/pkg/uid"
+ "github.com/gin-gonic/gin"
+ "github.com/segmentfault/pacman/errors"
)
type BadgeRepo interface {
+ GetByID(ctx context.Context, id string) (badge *entity.Badge, exists
bool, err error)
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)
@@ -55,6 +60,7 @@ func NewBadgeService(
}
}
+// ListByGroup list all badges group by group
func (b *BadgeService) ListByGroup(ctx context.Context, userID string) (resp
[]*schema.GetBadgeListResp, err error) {
var (
groups []*entity.BadgeGroup
@@ -74,7 +80,13 @@ func (b *BadgeService) ListByGroup(ctx context.Context,
userID string) (resp []*
if err != nil {
return
}
- earnedCounts, err = b.badgeAwardRepo.SumUserEarnedGroupByBadgeID(ctx,
userID)
+
+ if len(userID) > 0 {
+ earnedCounts, err =
b.badgeAwardRepo.SumUserEarnedGroupByBadgeID(ctx, userID)
+ if err != nil {
+ return
+ }
+ }
for _, group := range groups {
groupMap[converter.StringToInt64(group.ID)] = group.Name
@@ -93,11 +105,12 @@ func (b *BadgeService) ListByGroup(ctx context.Context,
userID string) (resp []*
}
badgesMap[badge.BadgeGroupId] =
append(badgesMap[badge.BadgeGroupId], &schema.BadgeListInfo{
- ID: badge.ID,
+ ID: uid.EnShortID(badge.ID),
Name: translator.Tr(handler.GetLangByCtx(ctx),
badge.Name),
Icon: badge.Icon,
AwardCount: badge.AwardCount,
Earned: earned,
+ Level: badge.Level,
})
}
@@ -110,3 +123,38 @@ func (b *BadgeService) ListByGroup(ctx context.Context,
userID string) (resp []*
return
}
+
+// GetBadgeInfo get badge info
+func (b *BadgeService) GetBadgeInfo(ctx *gin.Context, id string, userID
string) (info *schema.GetBadgeInfoResp, err error) {
+ var (
+ badge *entity.Badge
+ earnedTotal int64 = 0
+ exists = false
+ )
+
+ badge, exists, err = b.badgeRepo.GetByID(ctx, id)
+ if err != nil {
+ return
+ }
+
+ if !exists || badge.Status == entity.BadgeStatusInactive {
+ err = errors.BadRequest(reason.BadgeObjectNotFound)
+ return
+ }
+
+ if len(userID) > 0 {
+ earnedTotal = b.badgeAwardRepo.CountByUserIdAndBadgeId(ctx,
userID, badge.ID)
+ }
+
+ info = &schema.GetBadgeInfoResp{
+ 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,
+ EarnedCount: earnedTotal,
+ IsSingle: badge.Single == entity.BadgeSingleAward,
+ Level: badge.Level,
+ }
+ return
+}
diff --git a/internal/service/badge_award/badge_award_service.go
b/internal/service/badge_award/badge_award_service.go
index 8f84453e..b8e96545 100644
--- a/internal/service/badge_award/badge_award_service.go
+++ b/internal/service/badge_award/badge_award_service.go
@@ -21,7 +21,17 @@ package badge_award
import (
"context"
+ "github.com/apache/incubator-answer/internal/base/reason"
"github.com/apache/incubator-answer/internal/entity"
+ "github.com/apache/incubator-answer/internal/schema"
+ answercommon
"github.com/apache/incubator-answer/internal/service/answer_common"
+ "github.com/apache/incubator-answer/internal/service/object_info"
+ questioncommon
"github.com/apache/incubator-answer/internal/service/question_common"
+ usercommon
"github.com/apache/incubator-answer/internal/service/user_common"
+ "github.com/apache/incubator-answer/pkg/htmltext"
+ "github.com/jinzhu/copier"
+ "github.com/segmentfault/pacman/errors"
+ "github.com/segmentfault/pacman/log"
"time"
)
@@ -33,32 +43,98 @@ type BadgeAwardRepo interface {
CountByUserId(ctx context.Context, userID string) (awardCount int64)
CountByUserIdAndBadgeId(ctx context.Context, userID string, badgeID
string) (awardCount int64)
CountByObjectId(ctx context.Context, objectID string) (awardCount int64)
- CountByObjectIdAndBadgeId(ctx context.Context, objectID string, badgeID
string) int64
+ CountByObjectIdAndBadgeId(ctx context.Context, objectID string, badgeID
string) (awardCount int64)
CountBadgesByUserIdAndObjectId(ctx context.Context, userID string,
objectID string, badgeID string) (awardCount int64)
SumUserEarnedGroupByBadgeID(ctx context.Context, userID string)
(earnedCounts []*entity.BadgeEarnedCount, err error)
ListAllByUserId(ctx context.Context, userID string) (badgeAwards
[]*entity.BadgeAward)
- ListPagedByBadgeId(ctx context.Context, badgeID string, page int64,
pageSize int64) (badgeAwards []*entity.BadgeAward, total int64)
- ListPagedByBadgeIdAndUserId(ctx context.Context, badgeID string, userID
string, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total
int64)
- ListPagedByObjectId(ctx context.Context, badgeID string, objectID
string, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total
int64)
- ListPagedByObjectIdAndUserId(ctx context.Context, badgeID string,
objectID string, userID string, page int64, pageSize int64) (badgeAwards
[]*entity.BadgeAward, total int64)
- ListTagPagedByBadgeId(ctx context.Context, badgeIDs []int64, page
int64, pageSize int64, filterUserID int64) (badgeAwards []*entity.BadgeAward,
total int64)
- ListTagPagedByBadgeIdAndUserId(ctx context.Context, badgeIDs []int64,
userID string, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward,
total int64)
- ListPagedLatest(ctx context.Context, page int64, pageSize int64)
(badgeAwards []*entity.BadgeAward, total int64)
- ListNewestEarnedByLevel(ctx context.Context, userID string, level
entity.BadgeLevel, num int64) (badgeAwards []*entity.BadgeAward, total int64)
- ListNewestByUserIdAndLevel(ctx context.Context, userID string, level
int64, page int64, pageSize int64) (badgeAwards []*entity.BadgeAward, total
int64)
+ ListPagedByBadgeId(ctx context.Context, badgeID string, page int,
pageSize int) (badgeAwardList []*entity.BadgeAward, total int64, err error)
+ ListPagedByBadgeIdAndUserId(ctx context.Context, badgeID string, userID
string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64,
err error)
+ ListPagedByObjectId(ctx context.Context, badgeID string, objectID
string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64,
err error)
+ ListPagedByObjectIdAndUserId(ctx context.Context, badgeID string,
objectID string, userID string, page int, pageSize int) (badgeAwards
[]*entity.BadgeAward, total int64, err error)
+ ListTagPagedByBadgeId(ctx context.Context, badgeIDs []string, page int,
pageSize int, filterUserID string) (badgeAwards []*entity.BadgeAward, total
int64, err error)
+ ListTagPagedByBadgeIdAndUserId(ctx context.Context, badgeIDs []string,
userID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total
int64, err error)
+ ListPagedLatest(ctx context.Context, page int, pageSize int)
(badgeAwards []*entity.BadgeAward, total int64, err error)
+ ListNewestEarnedByLevel(ctx context.Context, userID string, level
entity.BadgeLevel, num int) (badgeAwards []*entity.BadgeAward, total int64, err
error)
+ ListNewestByUserIdAndLevel(ctx context.Context, userID string, level
int, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64,
err error)
GetByUserIdAndBadgeId(ctx context.Context, userID string, badgeID
string) (badgeAward *entity.BadgeAward)
GetByUserIdAndBadgeIdAndObjectId(ctx context.Context, userID string,
badgeID string, objectID string) (badgeAward *entity.BadgeAward)
}
type BadgeAwardService struct {
- badgeAwardRepo BadgeAwardRepo
+ badgeAwardRepo BadgeAwardRepo
+ userCommon *usercommon.UserCommon
+ objectInfoService *object_info.ObjService
+ questionRepo questioncommon.QuestionRepo
+ answerRepo answercommon.AnswerRepo
}
-func NewBadgeAwardService(badgeAwardRepo BadgeAwardRepo) *BadgeAwardService {
+func NewBadgeAwardService(
+ badgeAwardRepo BadgeAwardRepo,
+ userCommon *usercommon.UserCommon,
+ objectInfoService *object_info.ObjService,
+ questionRepo questioncommon.QuestionRepo,
+ answerRepo answercommon.AnswerRepo,
+) *BadgeAwardService {
return &BadgeAwardService{
- badgeAwardRepo: badgeAwardRepo,
+ badgeAwardRepo: badgeAwardRepo,
+ userCommon: userCommon,
+ objectInfoService: objectInfoService,
+ questionRepo: questionRepo,
+ answerRepo: answerRepo,
}
}
+
+// GetBadgeAwardList get badge award list
+func (b *BadgeAwardService) GetBadgeAwardList(
+ ctx context.Context, req *schema.GetBadgeAwardWithPageReq,
+) (resp []*schema.GetBadgeAwardWithPageResp, total int64, err error) {
+ var (
+ badgeAwardList []*entity.BadgeAward
+ )
+
+ badgeAwardList, total, err = b.badgeAwardRepo.ListPagedByBadgeId(ctx,
req.BadgeID, req.Page, req.PageSize)
+ if err != nil {
+ return
+ }
+
+ resp = make([]*schema.GetBadgeAwardWithPageResp, 0, len(badgeAwardList))
+
+ for i, badgeAward := range badgeAwardList {
+ objInfo, e := b.objectInfoService.GetInfo(ctx,
badgeAward.ObjectID)
+ if e != nil {
+ err = e
+ return
+ }
+ if objInfo.IsDeleted() {
+ err = errors.BadRequest(reason.NewObjectAlreadyDeleted)
+ return
+ }
+
+ row := &schema.GetBadgeAwardWithPageResp{
+ CreatedAt: badgeAward.CreatedAt.Unix(),
+ ObjectID: badgeAward.ObjectID,
+ QuestionID: objInfo.QuestionID,
+ AnswerID: objInfo.AnswerID,
+ CommentID: objInfo.CommentID,
+ ObjectType: objInfo.ObjectType,
+ UrlTitle: htmltext.UrlTitle(objInfo.Title),
+ AuthorUserInfo: schema.UserBasicInfo{},
+ }
+
+ // get user info
+ userInfo, exists, e := b.userCommon.GetUserBasicInfoByID(ctx,
badgeAward.UserID)
+ if e != nil {
+ log.Errorf("user not found by id: %s, err: %v",
badgeAward.UserID, e)
+ }
+ if exists {
+ _ = copier.Copy(&row.AuthorUserInfo, userInfo)
+ }
+
+ resp[i] = row
+ }
+
+ return
+}