This is an automated email from the ASF dual-hosted git repository. robin0716 pushed a commit to branch develop/robin in repository https://gitbox.apache.org/repos/asf/incubator-answer.git
commit ba7a482885214c9f0caf7628d3236bf36aea3e68 Author: kumfo <ku...@sifou.com> AuthorDate: Fri Aug 9 10:33:03 2024 +0800 feat(badge): badge award --- internal/entity/badge_award_entity.go | 2 +- internal/entity/badge_entity.go | 2 +- internal/migrations/v22.go | 28 ++++---- internal/repo/badge/badge_repo.go | 6 ++ internal/repo/badge_award/badge_award_repo.go | 55 ++++++++++++---- internal/service/badge/badge_service.go | 5 +- .../service/badge_award/badge_award_service.go | 77 +++++++++++++++++----- 7 files changed, 129 insertions(+), 46 deletions(-) diff --git a/internal/entity/badge_award_entity.go b/internal/entity/badge_award_entity.go index 26369394..310c85a7 100644 --- a/internal/entity/badge_award_entity.go +++ b/internal/entity/badge_award_entity.go @@ -29,7 +29,7 @@ type BadgeAward struct { 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"` AwardKey string `json:"award_key" xorm:"not null index VARCHAR(64) award_key"` - BadgeGroupID int8 `json:"badge_group_id" xorm:"not null index BIGINT(20) badge_group_id"` + BadgeGroupID int64 `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/entity/badge_entity.go b/internal/entity/badge_entity.go index da6cd4dd..d2c426fa 100644 --- a/internal/entity/badge_entity.go +++ b/internal/entity/badge_entity.go @@ -46,7 +46,7 @@ type Badge struct { AwardCount int `json:"award_count" xorm:"not null default 0 INT(11) award_count"` Description string `json:"description" xorm:"not null default '' MEDIUMTEXT description"` Status int8 `json:"status" xorm:"not null default 1 INT(11) status"` - BadgeGroupId int64 `json:"badge_group_id" xorm:"not null default 0 BIGINT(20) badge_group_id"` + BadgeGroupID int64 `json:"badge_group_id" xorm:"not null default 0 BIGINT(20) badge_group_id"` Level BadgeLevel `json:"level" xorm:"not null default 1 TINYINT(4) level"` Single int8 `json:"single" xorm:"not null default 1 TINYINT(4) single"` Collect string `json:"collect" xorm:"not null default '' VARCHAR(64) collect"` diff --git a/internal/migrations/v22.go b/internal/migrations/v22.go index de15cea6..19ec1ce0 100644 --- a/internal/migrations/v22.go +++ b/internal/migrations/v22.go @@ -44,7 +44,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.autobiographer.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 1, + BadgeGroupID: 1, Level: entity.BadgeLevelBronze, Single: entity.BadgeSingleAward, Collect: "", @@ -59,7 +59,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.editor.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 1, + BadgeGroupID: 1, Level: entity.BadgeLevelBronze, Single: entity.BadgeSingleAward, Collect: "question", @@ -74,7 +74,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.first_flag.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 1, + BadgeGroupID: 1, Level: entity.BadgeLevelBronze, Single: entity.BadgeSingleAward, Collect: "", @@ -89,7 +89,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.first_upvote.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 1, + BadgeGroupID: 1, Level: entity.BadgeLevelBronze, Single: entity.BadgeSingleAward, Collect: "", @@ -104,7 +104,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.first_reaction.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 1, + BadgeGroupID: 1, Level: entity.BadgeLevelBronze, Single: entity.BadgeSingleAward, Collect: "", @@ -119,7 +119,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.first_share.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 1, + BadgeGroupID: 1, Level: entity.BadgeLevelBronze, Single: entity.BadgeSingleAward, Collect: "", @@ -134,7 +134,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.scholar.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 1, + BadgeGroupID: 1, Level: entity.BadgeLevelBronze, Single: entity.BadgeSingleAward, Collect: "", @@ -149,7 +149,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.solved.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 2, + BadgeGroupID: 2, Level: entity.BadgeLevelBronze, Single: entity.BadgeSingleAward, Collect: "", @@ -164,7 +164,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.nice_answer.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 3, + BadgeGroupID: 3, Level: entity.BadgeLevelBronze, Single: entity.BadgeMultiAward, Collect: "", @@ -179,7 +179,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.good_answer.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 3, + BadgeGroupID: 3, Level: entity.BadgeLevelSilver, Single: entity.BadgeMultiAward, Collect: "", @@ -194,7 +194,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.great_answer.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 3, + BadgeGroupID: 3, Level: entity.BadgeLevelGold, Single: entity.BadgeMultiAward, Collect: "", @@ -209,7 +209,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.nice_question.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 3, + BadgeGroupID: 3, Level: entity.BadgeLevelBronze, Single: entity.BadgeMultiAward, Collect: "", @@ -224,7 +224,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.good_question.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 3, + BadgeGroupID: 3, Level: entity.BadgeLevelSilver, Single: entity.BadgeSingleAward, Collect: "", @@ -239,7 +239,7 @@ var ( AwardCount: 0, Description: "badge.default_badges.great_question.desc", Status: entity.BadgeStatusActive, - BadgeGroupId: 3, + BadgeGroupID: 3, Level: entity.BadgeLevelGold, Single: entity.BadgeMultiAward, Collect: "", diff --git a/internal/repo/badge/badge_repo.go b/internal/repo/badge/badge_repo.go index 5030f0da..d4d2f992 100644 --- a/internal/repo/badge/badge_repo.go +++ b/internal/repo/badge/badge_repo.go @@ -109,3 +109,9 @@ func (r *badgeRepo) ListInactivated(ctx context.Context) (badges []*entity.Badge } return } + +// UpdateAwardCount updates the award count of a badge +func (r *badgeRepo) UpdateAwardCount(ctx context.Context, id string, count int64) (err error) { + _, err = r.data.DB.Context(ctx).Where("id = ?", id).Incr("award_count", count).Update(&entity.Badge{}) + return +} diff --git a/internal/repo/badge_award/badge_award_repo.go b/internal/repo/badge_award/badge_award_repo.go index 85d3ceac..92807d1d 100644 --- a/internal/repo/badge_award/badge_award_repo.go +++ b/internal/repo/badge_award/badge_award_repo.go @@ -28,7 +28,6 @@ import ( "github.com/apache/incubator-answer/internal/service/badge_award" "github.com/apache/incubator-answer/internal/service/unique" "github.com/segmentfault/pacman/errors" - "time" ) type badgeAwardRepo struct { @@ -43,10 +42,36 @@ func NewBadgeAwardRepo(data *data.Data, uniqueIDRepo unique.UniqueIDRepo) badge_ } } -func (r *badgeAwardRepo) Award(ctx context.Context, badgeID string, userID string, awardKey string, force bool, createdAt time.Time) { - return -} -func (r *badgeAwardRepo) CheckIsAward(ctx context.Context, badgeID string, userID string, awardKey string) (isAward bool) { +func (r *badgeAwardRepo) Add(ctx context.Context, badgeAward *entity.BadgeAward) (err error) { + badgeAward.ID, err = r.uniqueIDRepo.GenUniqueIDStr(ctx, entity.BadgeAward{}.TableName()) + if err != nil { + return + } + _, err = r.data.DB.Context(ctx).Insert(badgeAward) + return +} +func (r *badgeAwardRepo) CheckIsAward(ctx context.Context, badgeID string, userID string, awardKey string, singleOrMulti int8) (isAward bool) { + isAward = false + if singleOrMulti == entity.BadgeSingleAward { + _, exists, err := r.GetByUserIdAndBadgeId(ctx, userID, badgeID) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + return + } + if exists { + return true + } + } else { + _, exists, err := r.GetByUserIdAndBadgeIdAndObjectId(ctx, userID, badgeID, awardKey) + if err != nil { + err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack() + return + } + if exists { + return true + } + } + return } func (r *badgeAwardRepo) CountByUserIdAndBadgeLevel(ctx context.Context, userID string, badgeLevel entity.BadgeLevel) (awardCount int64) { @@ -62,13 +87,13 @@ func (r *badgeAwardRepo) CountByUserIdAndBadgeId(ctx context.Context, userID str } return } -func (r *badgeAwardRepo) CountByObjectId(ctx context.Context, objectID string) (awardCount int64) { +func (r *badgeAwardRepo) CountByObjectId(ctx context.Context, awardKey string) (awardCount int64) { return } -func (r *badgeAwardRepo) CountByObjectIdAndBadgeId(ctx context.Context, objectID string, badgeID string) (awardCount int64) { +func (r *badgeAwardRepo) CountByObjectIdAndBadgeId(ctx context.Context, awardKey string, badgeID string) (awardCount int64) { return } -func (r *badgeAwardRepo) CountBadgesByUserIdAndObjectId(ctx context.Context, userID string, objectID string, badgeID string) (awardCount int64) { +func (r *badgeAwardRepo) CountBadgesByUserIdAndObjectId(ctx context.Context, userID string, awardKey string, badgeID string) (awardCount int64) { return } func (r *badgeAwardRepo) SumUserEarnedGroupByBadgeID(ctx context.Context, userID string) (earnedCounts []*entity.BadgeEarnedCount, err error) { @@ -92,10 +117,10 @@ func (r *badgeAwardRepo) ListPagedByBadgeId(ctx context.Context, badgeID string, 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 int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) { +func (r *badgeAwardRepo) ListPagedByObjectId(ctx context.Context, badgeID string, awardKey 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 int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) { +func (r *badgeAwardRepo) ListPagedByObjectIdAndUserId(ctx context.Context, badgeID string, awardKey string, userID string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) { return } func (r *badgeAwardRepo) ListTagPagedByBadgeId(ctx context.Context, badgeIDs []string, page int, pageSize int, filterUserID string) (badgeAwards []*entity.BadgeAward, total int64, err error) { @@ -113,9 +138,15 @@ func (r *badgeAwardRepo) ListNewestEarnedByLevel(ctx context.Context, userID str 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) { + +// GetByUserIdAndBadgeId get badge award by user id and badge id +func (r *badgeAwardRepo) GetByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) (badgeAward *entity.BadgeAward, exists bool, err error) { + exists, err = r.data.DB.Context(ctx).Where("user_id = ? AND badge_id = ? AND is_badge_deleted = 0", userID, badgeID).Get(&badgeAward) return } -func (r *badgeAwardRepo) GetByUserIdAndBadgeIdAndObjectId(ctx context.Context, userID string, badgeID string, objectID string) (badgeAward *entity.BadgeAward) { + +// GetByUserIdAndBadgeIdAndObjectId get badge award by user id, badge id and object id +func (r *badgeAwardRepo) GetByUserIdAndBadgeIdAndObjectId(ctx context.Context, userID string, badgeID string, awardKey string) (badgeAward *entity.BadgeAward, exists bool, err error) { + exists, err = r.data.DB.Context(ctx).Where("user_id = ? AND badge_id = ? AND award_key = ? AND is_badge_deleted = 0", userID, badgeID, awardKey).Get(&badgeAward) return } diff --git a/internal/service/badge/badge_service.go b/internal/service/badge/badge_service.go index 16087f9c..faf97b11 100644 --- a/internal/service/badge/badge_service.go +++ b/internal/service/badge/badge_service.go @@ -37,11 +37,14 @@ import ( type BadgeRepo interface { GetByID(ctx context.Context, id string) (badge *entity.Badge, exists bool, err error) GetByIDs(ctx context.Context, ids []string) (badges []*entity.Badge, 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) ListActivated(ctx context.Context) ([]*entity.Badge, error) ListInactivated(ctx context.Context) ([]*entity.Badge, error) + + UpdateAwardCount(ctx context.Context, id string, count int64) error } type BadgeService struct { @@ -109,7 +112,7 @@ func (b *BadgeService) ListByGroup(ctx context.Context, userID string) (resp []* } } - badgesMap[badge.BadgeGroupId] = append(badgesMap[badge.BadgeGroupId], &schema.BadgeListInfo{ + badgesMap[badge.BadgeGroupID] = append(badgesMap[badge.BadgeGroupID], &schema.BadgeListInfo{ ID: uid.EnShortID(badge.ID), Name: translator.Tr(handler.GetLangByCtx(ctx), badge.Name), Icon: badge.Icon, diff --git a/internal/service/badge_award/badge_award_service.go b/internal/service/badge_award/badge_award_service.go index d94258b4..2c7c5ffa 100644 --- a/internal/service/badge_award/badge_award_service.go +++ b/internal/service/badge_award/badge_award_service.go @@ -21,66 +21,64 @@ 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/badge" "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/jinzhu/copier" + "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" "time" ) type BadgeAwardRepo interface { - Award(ctx context.Context, badgeID string, userID string, awardKey string, force bool, createdAt time.Time) - CheckIsAward(ctx context.Context, badgeID string, userID string, awardKey string) bool + Add(ctx context.Context, badgeAward *entity.BadgeAward) (err error) + CheckIsAward(ctx context.Context, badgeID string, userID string, awardKey string, singleOrMulti int8) bool CountByUserIdAndBadgeLevel(ctx context.Context, userID string, badgeLevel entity.BadgeLevel) (awardCount int64) 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) (awardCount int64) - CountBadgesByUserIdAndObjectId(ctx context.Context, userID string, objectID string, badgeID string) (awardCount int64) + CountByObjectId(ctx context.Context, awardKey string) (awardCount int64) + CountByObjectIdAndBadgeId(ctx context.Context, awardKey string, badgeID string) (awardCount int64) + CountBadgesByUserIdAndObjectId(ctx context.Context, userID string, awardKey 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 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) + ListPagedByObjectId(ctx context.Context, badgeID string, awardKey string, page int, pageSize int) (badgeAwards []*entity.BadgeAward, total int64, err error) + ListPagedByObjectIdAndUserId(ctx context.Context, badgeID string, awardKey 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) + GetByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) (badgeAward *entity.BadgeAward, exists bool, err error) + GetByUserIdAndBadgeIdAndObjectId(ctx context.Context, userID string, badgeID string, awardKey string) (badgeAward *entity.BadgeAward, exists bool, err error) } type BadgeAwardService struct { badgeAwardRepo BadgeAwardRepo + badgeRepo badge.BadgeRepo userCommon *usercommon.UserCommon objectInfoService *object_info.ObjService - questionRepo questioncommon.QuestionRepo - answerRepo answercommon.AnswerRepo } func NewBadgeAwardService( badgeAwardRepo BadgeAwardRepo, + badgeRepo badge.BadgeRepo, userCommon *usercommon.UserCommon, objectInfoService *object_info.ObjService, - questionRepo questioncommon.QuestionRepo, - answerRepo answercommon.AnswerRepo, ) *BadgeAwardService { return &BadgeAwardService{ badgeAwardRepo: badgeAwardRepo, + badgeRepo: badgeRepo, userCommon: userCommon, objectInfoService: objectInfoService, - questionRepo: questionRepo, - answerRepo: answerRepo, } } @@ -140,3 +138,48 @@ func (b *BadgeAwardService) GetBadgeAwardList( return } + +// Award award badge +func (b *BadgeAwardService) Award(ctx context.Context, badgeID string, userID string, awardKey string, force bool, createdAt time.Time) (err error) { + var ( + badgeData *entity.Badge + exists, awarded bool + ) + + badgeData, exists, err = b.badgeRepo.GetByID(ctx, badgeID) + if err != nil { + return + } + + if !exists || badgeData.Status == entity.BadgeStatusInactive { + err = errors.BadRequest(reason.BadgeObjectNotFound) + return + } + + awarded = b.badgeAwardRepo.CheckIsAward(ctx, badgeID, userID, awardKey, badgeData.Single) + if !force && awarded { + return + } + + if createdAt.IsZero() { + createdAt = time.Now() + } + + err = b.badgeAwardRepo.Add(ctx, &entity.BadgeAward{ + CreatedAt: createdAt, + UpdatedAt: createdAt, + UserID: userID, + BadgeID: badgeID, + AwardKey: awardKey, + BadgeGroupID: badgeData.BadgeGroupID, + IsBadgeDeleted: 0, + }) + if err != nil { + return + } + + // increment badge award count + err = b.badgeRepo.UpdateAwardCount(ctx, badgeID, 1) + + return +}