mirror of https://gitee.com/answerdev/answer.git
197 lines
6.0 KiB
Go
197 lines
6.0 KiB
Go
package rank
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/answerdev/answer/internal/base/data"
|
|
"github.com/answerdev/answer/internal/base/pager"
|
|
"github.com/answerdev/answer/internal/base/reason"
|
|
"github.com/answerdev/answer/internal/entity"
|
|
"github.com/answerdev/answer/internal/service/config"
|
|
"github.com/answerdev/answer/internal/service/rank"
|
|
"github.com/answerdev/answer/plugin"
|
|
"github.com/jinzhu/now"
|
|
"github.com/segmentfault/pacman/errors"
|
|
"github.com/segmentfault/pacman/log"
|
|
"xorm.io/builder"
|
|
"xorm.io/xorm"
|
|
)
|
|
|
|
// UserRankRepo user rank repository
|
|
type UserRankRepo struct {
|
|
data *data.Data
|
|
configService *config.ConfigService
|
|
}
|
|
|
|
// NewUserRankRepo new repository
|
|
func NewUserRankRepo(data *data.Data, configService *config.ConfigService) rank.UserRankRepo {
|
|
return &UserRankRepo{
|
|
data: data,
|
|
configService: configService,
|
|
}
|
|
}
|
|
|
|
func (ur *UserRankRepo) GetMaxDailyRank(ctx context.Context) (maxDailyRank int, err error) {
|
|
maxDailyRank, err = ur.configService.GetIntValue(ctx, "daily_rank_limit")
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return maxDailyRank, nil
|
|
}
|
|
|
|
func (ur *UserRankRepo) CheckReachLimit(ctx context.Context, session *xorm.Session,
|
|
userID string, maxDailyRank int) (
|
|
reach bool, err error) {
|
|
session.Where(builder.Eq{"user_id": userID})
|
|
session.Where(builder.Eq{"cancelled": 0})
|
|
session.Where(builder.Between{
|
|
Col: "updated_at",
|
|
LessVal: now.BeginningOfDay(),
|
|
MoreVal: now.EndOfDay(),
|
|
})
|
|
|
|
earned, err := session.SumInt(&entity.Activity{}, "`rank`")
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if int(earned) < maxDailyRank {
|
|
return false, nil
|
|
}
|
|
log.Infof("user %s today has rank %d is reach stand %d", userID, earned, maxDailyRank)
|
|
return true, nil
|
|
}
|
|
|
|
// ChangeUserRank change user rank
|
|
func (ur *UserRankRepo) ChangeUserRank(
|
|
ctx context.Context, session *xorm.Session, userID string, userCurrentScore, deltaRank int) (err error) {
|
|
// IMPORTANT: If user center enabled the rank agent, then we should not change user rank.
|
|
if plugin.RankAgentEnabled() || deltaRank == 0 {
|
|
return nil
|
|
}
|
|
|
|
// If user rank is lower than 1 after this action, then user rank will be set to 1 only.
|
|
if deltaRank < 0 && userCurrentScore+deltaRank < 1 {
|
|
deltaRank = 1 - userCurrentScore
|
|
}
|
|
|
|
_, err = session.ID(userID).Incr("`rank`", deltaRank).Update(&entity.User{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// TriggerUserRank trigger user rank change
|
|
// session is need provider, it means this action must be success or failure
|
|
// if outer action is failed then this action is need rollback
|
|
func (ur *UserRankRepo) TriggerUserRank(ctx context.Context,
|
|
session *xorm.Session, userID string, deltaRank int, activityType int,
|
|
) (isReachStandard bool, err error) {
|
|
// IMPORTANT: If user center enabled the rank agent, then we should not change user rank.
|
|
if plugin.RankAgentEnabled() || deltaRank == 0 {
|
|
return false, nil
|
|
}
|
|
|
|
if deltaRank < 0 {
|
|
// if user rank is lower than 1 after this action, then user rank will be set to 1 only.
|
|
var isReachMin bool
|
|
isReachMin, err = ur.checkUserMinRank(ctx, session, userID, deltaRank)
|
|
if err != nil {
|
|
return false, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
|
}
|
|
if isReachMin {
|
|
_, err = session.Where(builder.Eq{"id": userID}).Update(&entity.User{Rank: 1})
|
|
if err != nil {
|
|
return false, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
|
}
|
|
return true, nil
|
|
}
|
|
} else {
|
|
isReachStandard, err = ur.checkUserTodayRank(ctx, session, userID, activityType)
|
|
if err != nil {
|
|
return false, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
|
}
|
|
if isReachStandard {
|
|
return isReachStandard, nil
|
|
}
|
|
}
|
|
_, err = session.Where(builder.Eq{"id": userID}).Incr("`rank`", deltaRank).Update(&entity.User{})
|
|
if err != nil {
|
|
return false, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
|
}
|
|
return false, nil
|
|
}
|
|
|
|
func (ur *UserRankRepo) checkUserMinRank(ctx context.Context, session *xorm.Session, userID string, deltaRank int) (
|
|
isReachStandard bool, err error,
|
|
) {
|
|
bean := &entity.User{ID: userID}
|
|
_, err = session.Select("`rank`").Get(bean)
|
|
if err != nil {
|
|
return false, errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
|
}
|
|
if bean.Rank+deltaRank < 1 {
|
|
log.Infof("user %s is rank %d out of range before rank operation", userID, deltaRank)
|
|
return true, nil
|
|
}
|
|
return
|
|
}
|
|
|
|
func (ur *UserRankRepo) checkUserTodayRank(ctx context.Context,
|
|
session *xorm.Session, userID string, activityType int,
|
|
) (isReachStandard bool, err error) {
|
|
// exclude daily rank
|
|
exclude, _ := ur.configService.GetArrayStringValue(ctx, "daily_rank_limit.exclude")
|
|
for _, item := range exclude {
|
|
cfg, err := ur.configService.GetConfigByKey(ctx, item)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if activityType == cfg.ID {
|
|
return false, nil
|
|
}
|
|
}
|
|
|
|
// get user
|
|
start, end := now.BeginningOfDay(), now.EndOfDay()
|
|
session.Where(builder.Eq{"user_id": userID})
|
|
session.Where(builder.Eq{"cancelled": 0})
|
|
session.Where(builder.Between{
|
|
Col: "updated_at",
|
|
LessVal: start,
|
|
MoreVal: end,
|
|
})
|
|
earned, err := session.Sum(&entity.Activity{}, "`rank`")
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
// max rank
|
|
maxDailyRank, err := ur.configService.GetIntValue(ctx, "daily_rank_limit")
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
if int(earned) < maxDailyRank {
|
|
return false, nil
|
|
}
|
|
log.Infof("user %s today has rank %d is reach stand %d", userID, earned, maxDailyRank)
|
|
return true, nil
|
|
}
|
|
|
|
func (ur *UserRankRepo) UserRankPage(ctx context.Context, userID string, page, pageSize int) (
|
|
rankPage []*entity.Activity, total int64, err error,
|
|
) {
|
|
rankPage = make([]*entity.Activity, 0)
|
|
|
|
session := ur.data.DB.Context(ctx).Where(builder.Eq{"has_rank": 1}.And(builder.Eq{"cancelled": 0})).And(builder.Gt{"`rank`": 0})
|
|
session.Desc("created_at")
|
|
|
|
cond := &entity.Activity{UserID: userID}
|
|
total, err = pager.Help(page, pageSize, &rankPage, cond, session)
|
|
if err != nil {
|
|
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
|
}
|
|
return
|
|
}
|