internal/service/badge/badge_award_service.go (239 lines of code) (raw):

/* * 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 badge import ( "context" "github.com/apache/answer/internal/base/constant" "github.com/apache/answer/internal/base/handler" "github.com/apache/answer/internal/base/reason" "github.com/apache/answer/internal/base/translator" "github.com/apache/answer/internal/entity" "github.com/apache/answer/internal/schema" "github.com/apache/answer/internal/service/notice_queue" "github.com/apache/answer/internal/service/object_info" usercommon "github.com/apache/answer/internal/service/user_common" "github.com/apache/answer/pkg/uid" "github.com/gin-gonic/gin" "github.com/jinzhu/copier" "github.com/segmentfault/pacman/errors" "github.com/segmentfault/pacman/log" ) type BadgeAwardRepo interface { CheckIsAward(ctx context.Context, badgeID string, userID string, awardKey string, singleOrMulti int8) (isAward bool, err error) AwardBadgeForUser(ctx context.Context, badgeAward *entity.BadgeAward) (err error) CountByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) (awardCount int64) CountByBadgeID(ctx context.Context, badgeID string) (awardCount int64, err error) SumUserEarnedGroupByBadgeID(ctx context.Context, userID string) (earnedCounts []*entity.BadgeEarnedCount, err error) 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) ListNewestEarned(ctx context.Context, userID string, limit int) (badgeAwards []*entity.BadgeAwardRecent, err error) GetByUserIdAndBadgeId(ctx context.Context, userID string, badgeID string) (badgeAward *entity.BadgeAward, exists bool, err error) GetByUserIdAndBadgeIdAndAwardKey(ctx context.Context, userID string, badgeID string, awardKey string) (badgeAward *entity.BadgeAward, exists bool, err error) DeleteUserBadgeAward(ctx context.Context, userID string) (err error) } type BadgeAwardService struct { badgeAwardRepo BadgeAwardRepo badgeRepo BadgeRepo userCommon *usercommon.UserCommon objectInfoService *object_info.ObjService notificationQueueService notice_queue.NotificationQueueService } func NewBadgeAwardService( badgeAwardRepo BadgeAwardRepo, badgeRepo BadgeRepo, userCommon *usercommon.UserCommon, objectInfoService *object_info.ObjService, notificationQueueService notice_queue.NotificationQueueService, ) *BadgeAwardService { return &BadgeAwardService{ badgeAwardRepo: badgeAwardRepo, badgeRepo: badgeRepo, userCommon: userCommon, objectInfoService: objectInfoService, notificationQueueService: notificationQueueService, } } // GetBadgeAwardList get badge award list func (bs *BadgeAwardService) GetBadgeAwardList( ctx context.Context, req *schema.GetBadgeAwardWithPageReq, ) (resp []*schema.GetBadgeAwardWithPageResp, total int64, err error) { var ( badgeAwardList []*entity.BadgeAward ) req.UserID, err = bs.validateUserByUsername(ctx, req.Username) if err != nil { badgeAwardList, total, err = bs.badgeAwardRepo.ListPagedByBadgeId(ctx, req.BadgeID, req.Page, req.PageSize) } else { badgeAwardList, total, err = bs.badgeAwardRepo.ListPagedByBadgeIdAndUserId(ctx, req.BadgeID, req.UserID, req.Page, req.PageSize) } if err != nil { return } resp = make([]*schema.GetBadgeAwardWithPageResp, len(badgeAwardList)) for i, badgeAward := range badgeAwardList { var ( objectID, questionID, answerID, commentID, objectType, urlTitle string ) // if exist object info objInfo, e := bs.objectInfoService.GetInfo(ctx, badgeAward.AwardKey) if e == nil && !objInfo.IsDeleted() { objectID = objInfo.ObjectID questionID = objInfo.QuestionID answerID = objInfo.AnswerID commentID = objInfo.CommentID objectType = objInfo.ObjectType urlTitle = objInfo.Title } row := &schema.GetBadgeAwardWithPageResp{ CreatedAt: badgeAward.CreatedAt.Unix(), ObjectID: objectID, QuestionID: questionID, AnswerID: answerID, CommentID: commentID, ObjectType: objectType, UrlTitle: urlTitle, AuthorUserInfo: schema.UserBasicInfo{}, } // get user info userInfo, exists, e := bs.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 } // Award award badge func (bs *BadgeAwardService) Award(ctx context.Context, badgeID string, userID string, awardKey string) (err error) { badgeData, exists, err := bs.badgeRepo.GetByID(ctx, badgeID) if err != nil { return err } if !exists || badgeData.Status == entity.BadgeStatusInactive { return errors.BadRequest(reason.BadgeObjectNotFound) } alreadyAwarded, err := bs.badgeAwardRepo.CheckIsAward(ctx, badgeID, userID, awardKey, badgeData.Single) if err != nil { return err } if alreadyAwarded { return nil } badgeAward := &entity.BadgeAward{ UserID: userID, BadgeID: badgeID, AwardKey: awardKey, BadgeGroupID: badgeData.BadgeGroupID, IsBadgeDeleted: entity.IsBadgeNotDeleted, } err = bs.badgeAwardRepo.AwardBadgeForUser(ctx, badgeAward) if err != nil { return err } msg := &schema.NotificationMsg{ TriggerUserID: badgeAward.UserID, ReceiverUserID: badgeAward.UserID, Type: schema.NotificationTypeAchievement, ObjectID: badgeAward.ID, ObjectType: constant.BadgeAwardObjectType, Title: badgeData.Name, ExtraInfo: map[string]string{"badge_id": badgeData.ID}, NotificationAction: constant.NotificationEarnedBadge, } bs.notificationQueueService.Send(ctx, msg) return nil } // GetUserBadgeAwardList get user badge award list func (bs *BadgeAwardService) GetUserBadgeAwardList( ctx *gin.Context, req *schema.GetUserBadgeAwardListReq, ) ( resp []*schema.GetUserBadgeAwardListResp, total int64, err error, ) { var ( earnedCounts []*entity.BadgeEarnedCount ) req.UserID, err = bs.validateUserByUsername(ctx, req.Username) if err != nil { return } earnedCounts, err = bs.badgeAwardRepo.SumUserEarnedGroupByBadgeID(ctx, req.UserID) if err != nil { return } total = int64(len(earnedCounts)) resp = make([]*schema.GetUserBadgeAwardListResp, total) for i, earnedCount := range earnedCounts { badge, exists, e := bs.badgeRepo.GetByID(ctx, earnedCount.BadgeID) if e != nil { err = e return } if !exists { continue } resp[i] = &schema.GetUserBadgeAwardListResp{ ID: uid.EnShortID(badge.ID), Name: translator.Tr(handler.GetLangByCtx(ctx), badge.Name), Icon: badge.Icon, EarnedCount: earnedCount.EarnedCount, Level: badge.Level, } } return } // GetUserRecentBadgeAwardList get user badge award list func (bs *BadgeAwardService) GetUserRecentBadgeAwardList(ctx *gin.Context, req *schema.GetUserBadgeAwardListReq) ( resp []*schema.GetUserBadgeAwardListResp, total int64, err error) { var ( earnedCounts []*entity.BadgeAwardRecent ) req.UserID, err = bs.validateUserByUsername(ctx, req.Username) if err != nil { return } earnedCounts, err = bs.badgeAwardRepo.ListNewestEarned(ctx, req.UserID, req.Limit) if err != nil { return } total = int64(len(earnedCounts)) resp = make([]*schema.GetUserBadgeAwardListResp, total) for i, earnedCount := range earnedCounts { badge, exists, e := bs.badgeRepo.GetByID(ctx, earnedCount.BadgeID) if e != nil { err = e return } if !exists { continue } resp[i] = &schema.GetUserBadgeAwardListResp{ ID: uid.EnShortID(badge.ID), Name: translator.Tr(handler.GetLangByCtx(ctx), badge.Name), Icon: badge.Icon, EarnedCount: earnedCount.EarnedCount, Level: badge.Level, } } return } func (bs *BadgeAwardService) validateUserByUsername(ctx context.Context, userName string) (userID string, err error) { var ( userInfo *schema.UserBasicInfo exist bool ) // validate user exists or not if len(userName) > 0 { userInfo, exist, err = bs.userCommon.GetUserBasicInfoByUserName(ctx, userName) if err != nil { return } if !exist { err = errors.BadRequest(reason.UserNotFound) return } userID = userInfo.ID } if len(userID) == 0 { err = errors.BadRequest(reason.UserNotFound) return } return }