blob: 7bc9ffe21626ef86521fc1c7ff57dcee19ef0976 [file] [log] [blame]
/*
* 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/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/siteinfo_common"
"github.com/apache/answer/pkg/converter"
"github.com/apache/answer/pkg/uid"
"github.com/gin-gonic/gin"
"github.com/segmentfault/pacman/errors"
"github.com/segmentfault/pacman/log"
"strings"
)
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)
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)
UpdateStatus(ctx context.Context, id string, status int8) (err error)
UpdateAwardCount(ctx context.Context, badgeID string, awardCount int) (err error)
}
type BadgeService struct {
badgeRepo BadgeRepo
badgeGroupRepo BadgeGroupRepo
badgeAwardRepo BadgeAwardRepo
badgeEventService *BadgeEventService
siteInfoCommonService siteinfo_common.SiteInfoCommonService
}
func NewBadgeService(
badgeRepo BadgeRepo,
badgeGroupRepo BadgeGroupRepo,
badgeAwardRepo BadgeAwardRepo,
badgeEventService *BadgeEventService,
siteInfoCommonService siteinfo_common.SiteInfoCommonService,
) *BadgeService {
return &BadgeService{
badgeRepo: badgeRepo,
badgeGroupRepo: badgeGroupRepo,
badgeAwardRepo: badgeAwardRepo,
badgeEventService: badgeEventService,
siteInfoCommonService: siteInfoCommonService,
}
}
// 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
badges []*entity.Badge
earnedCounts []*entity.BadgeEarnedCount
groupMap = make(map[int64]string, 0)
badgesMap = make(map[int64][]*schema.BadgeListInfo, 0)
)
resp = make([]*schema.GetBadgeListResp, 0)
groups, err = b.badgeGroupRepo.ListGroups(ctx)
if err != nil {
return
}
badges, _, err = b.badgeRepo.ListActivated(ctx, 0, 0)
if err != nil {
return
}
if len(userID) > 0 {
earnedCounts, err = b.badgeAwardRepo.SumUserEarnedGroupByBadgeID(ctx, userID)
if err != nil {
return
}
}
for _, group := range groups {
groupMap[converter.StringToInt64(group.ID)] = translator.Tr(handler.GetLangByCtx(ctx), group.Name)
}
for _, badge := range badges {
// check is earned
var earned int64 = 0
if len(earnedCounts) > 0 {
for _, earnedCount := range earnedCounts {
if badge.ID == earnedCount.BadgeID && earnedCount.EarnedCount > 0 {
earned = earnedCount.EarnedCount
break
}
}
}
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,
AwardCount: badge.AwardCount,
EarnedCount: earned,
Level: badge.Level,
})
}
for _, group := range groups {
resp = append(resp, &schema.GetBadgeListResp{
GroupName: translator.Tr(handler.GetLangByCtx(ctx), group.Name),
Badges: badgesMap[converter.StringToInt64(group.ID)],
})
}
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
badge *entity.Badge
exists bool
groupMap = make(map[int64]string, 0)
)
total = 0
if len(req.Query) > 0 {
isID := strings.Index(req.Query, "badge:")
if isID != 0 {
badges, err = b.searchByName(ctx, req.Query)
if err != nil {
return
}
// paged result
count := len(badges)
total = int64(count)
start := (req.Page - 1) * req.PageSize
end := req.Page * req.PageSize
if start >= count {
start = count
end = count
}
if end > count {
end = count
}
badges = badges[start:end]
} else {
req.Query = strings.TrimSpace(strings.TrimLeft(req.Query, "badge:"))
id := uid.DeShortID(req.Query)
if len(id) == 0 {
return
}
badge, exists, err = b.badgeRepo.GetByID(ctx, id)
if err != nil || !exists {
return
}
badges = append(badges, badge)
}
} else {
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))
general, siteErr := b.siteInfoCommonService.GetSiteGeneral(ctx)
var baseURL = ""
if siteErr != nil {
baseURL = ""
} else {
baseURL = general.SiteUrl
}
for i, badge := range badges {
resp[i] = &schema.GetBadgeListPagedResp{
ID: uid.EnShortID(badge.ID),
Name: translator.Tr(handler.GetLangByCtx(ctx), badge.Name),
Description: translator.TrWithData(handler.GetLangByCtx(ctx), badge.Description, &schema.BadgeTplData{ProfileURL: baseURL + "/users/settings/profile"}),
Icon: badge.Icon,
AwardCount: badge.AwardCount,
Level: badge.Level,
GroupName: groupMap[badge.BadgeGroupID],
Status: schema.BadgeStatusMap[badge.Status],
}
}
return
}
// searchByName
func (b *BadgeService) searchByName(ctx context.Context, name string) (result []*entity.Badge, err error) {
var badges []*entity.Badge
name = strings.ToLower(name)
result = make([]*entity.Badge, 0)
badges, _, err = b.badgeRepo.ListPaged(ctx, 0, 0)
for _, badge := range badges {
tn := strings.ToLower(translator.Tr(handler.GetLangByCtx(ctx), badge.Name))
if strings.Contains(tn, name) {
result = append(result, badge)
}
}
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)
}
general, siteErr := b.siteInfoCommonService.GetSiteGeneral(ctx)
var baseURL = ""
if siteErr != nil {
baseURL = ""
} else {
baseURL = general.SiteUrl
}
info = &schema.GetBadgeInfoResp{
ID: uid.EnShortID(badge.ID),
Name: translator.Tr(handler.GetLangByCtx(ctx), badge.Name),
Description: translator.TrWithData(handler.GetLangByCtx(ctx), badge.Description, &schema.BadgeTplData{ProfileURL: baseURL + "/users/settings/profile"}),
Icon: badge.Icon,
AwardCount: badge.AwardCount,
EarnedCount: earnedTotal,
IsSingle: badge.Single == entity.BadgeSingleAward,
Level: badge.Level,
}
return
}
// UpdateStatus update badge status
func (b *BadgeService) UpdateStatus(ctx *gin.Context, req *schema.UpdateBadgeStatusReq) (err error) {
req.ID = uid.DeShortID(req.ID)
badge, exists, err := b.badgeRepo.GetByID(ctx, req.ID)
if err != nil {
return err
}
if !exists {
return errors.BadRequest(reason.BadgeObjectNotFound)
}
// check duplicate action
status, ok := schema.BadgeStatusEMap[req.Status]
if !ok {
err = errors.BadRequest(reason.StatusInvalid)
return
}
if badge.Status == status {
return
}
err = b.badgeRepo.UpdateStatus(ctx, req.ID, status)
if err != nil {
return err
}
if status == entity.BadgeStatusActive {
count, err := b.badgeAwardRepo.CountByBadgeID(ctx, badge.ID)
if err != nil {
log.Errorf("count badge award failed: %v", err)
return nil
}
err = b.badgeRepo.UpdateAwardCount(ctx, badge.ID, int(count))
if err != nil {
log.Errorf("update badge award count failed: %v", err)
return nil
}
}
return nil
}