mirror of https://gitee.com/answerdev/answer.git
feat(user): add user ranking api
This commit is contained in:
parent
18ca572a38
commit
79158f54bd
|
@ -117,7 +117,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
|
|||
roleService := role2.NewRoleService(roleRepo)
|
||||
userRoleRelService := role2.NewUserRoleRelService(userRoleRelRepo, roleService)
|
||||
userCommon := usercommon.NewUserCommon(userRepo)
|
||||
userService := service.NewUserService(userRepo, userActiveActivityRepo, emailService, authService, serviceConf, siteInfoCommonService, userRoleRelService, userCommon)
|
||||
userService := service.NewUserService(userRepo, userActiveActivityRepo, activityRepo, emailService, authService, serviceConf, siteInfoCommonService, userRoleRelService, userCommon)
|
||||
captchaRepo := captcha.NewCaptchaRepo(dataData)
|
||||
captchaService := action.NewCaptchaService(captchaRepo)
|
||||
uploaderService := uploader.NewUploaderService(serviceConf, siteInfoCommonService)
|
||||
|
|
|
@ -28,6 +28,16 @@ type ActivityRankSum struct {
|
|||
Rank int `xorm:"not null default 0 INT(11) rank"`
|
||||
}
|
||||
|
||||
type ActivityUserRankStat struct {
|
||||
UserID string `xorm:"user_id"`
|
||||
Rank int `xorm:"rank_amount"`
|
||||
}
|
||||
|
||||
type ActivityUserVoteStat struct {
|
||||
UserID string `xorm:"user_id"`
|
||||
VoteCount int `xorm:"vote_count"`
|
||||
}
|
||||
|
||||
// TableName activity table name
|
||||
func (Activity) TableName() string {
|
||||
return "activity"
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"github.com/answerdev/answer/internal/entity"
|
||||
"github.com/answerdev/answer/internal/service/activity_common"
|
||||
"github.com/answerdev/answer/internal/service/activity_type"
|
||||
"github.com/answerdev/answer/pkg/obj"
|
||||
"xorm.io/builder"
|
||||
"xorm.io/xorm"
|
||||
|
@ -110,6 +111,46 @@ func (ar *ActivityRepo) AddActivity(ctx context.Context, activity *entity.Activi
|
|||
|
||||
// GetUsersWhoHasGainedTheMostReputation get users who has gained the most reputation over a period of time
|
||||
func (ar *ActivityRepo) GetUsersWhoHasGainedTheMostReputation(
|
||||
ctx context.Context, startTime, endTime time.Time, limit int) (userIDs []string, err error) {
|
||||
ctx context.Context, startTime, endTime time.Time, limit int) (rankStat []*entity.ActivityUserRankStat, err error) {
|
||||
rankStat = make([]*entity.ActivityUserRankStat, 0)
|
||||
session := ar.data.DB.Select("user_id, SUM(rank) AS rank_amount").Table("activity")
|
||||
session.Where("has_rank = 1 AND cancelled = 0")
|
||||
session.Where("created_at >= ?", startTime)
|
||||
session.Where("created_at <= ?", endTime)
|
||||
session.GroupBy("user_id")
|
||||
session.Desc("rank_amount")
|
||||
session.Limit(limit)
|
||||
err = session.Find(&rankStat)
|
||||
if err != nil {
|
||||
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetUsersWhoHasVoteMost get users who has vote most
|
||||
func (ar *ActivityRepo) GetUsersWhoHasVoteMost(
|
||||
ctx context.Context, startTime, endTime time.Time, limit int) (voteStat []*entity.ActivityUserVoteStat, err error) {
|
||||
voteStat = make([]*entity.ActivityUserVoteStat, 0)
|
||||
|
||||
actIDs := make([]int, 0)
|
||||
for _, act := range activity_type.ActivityTypeList {
|
||||
configType, err := ar.configRepo.GetConfigType(act)
|
||||
if err == nil {
|
||||
actIDs = append(actIDs, configType)
|
||||
}
|
||||
}
|
||||
|
||||
session := ar.data.DB.Select("user_id, COUNT(*) AS vote_count").Table("activity")
|
||||
session.Where("cancelled = 0")
|
||||
session.In("activity_type", actIDs)
|
||||
session.Where("created_at >= ?", startTime)
|
||||
session.Where("created_at <= ?", endTime)
|
||||
session.GroupBy("user_id")
|
||||
session.Desc("vote_count")
|
||||
session.Limit(limit)
|
||||
err = session.Find(&voteStat)
|
||||
if err != nil {
|
||||
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -60,6 +60,17 @@ func (ur *userRoleRelRepo) GetUserRoleRelList(ctx context.Context, userIDs []str
|
|||
return
|
||||
}
|
||||
|
||||
// GetUserRoleRelListByRoleID get user role all by role id
|
||||
func (ur *userRoleRelRepo) GetUserRoleRelListByRoleID(ctx context.Context, roleIDs []int) (
|
||||
userRoleRelList []*entity.UserRoleRel, err error) {
|
||||
userRoleRelList = make([]*entity.UserRoleRel, 0)
|
||||
err = ur.data.DB.In("role_id", roleIDs).Find(&userRoleRelList)
|
||||
if err != nil {
|
||||
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetUserRoleRel get user role
|
||||
func (ur *userRoleRelRepo) GetUserRoleRel(ctx context.Context, userID string) (
|
||||
rolePowerRel *entity.UserRoleRel, exist bool, err error) {
|
||||
|
|
|
@ -106,16 +106,16 @@ func FormatAvatarInfo(avatarJson string) string {
|
|||
if avatarJson == "" {
|
||||
return ""
|
||||
}
|
||||
AvatarInfo := &AvatarInfo{}
|
||||
err := json.Unmarshal([]byte(avatarJson), AvatarInfo)
|
||||
avatarInfo := &AvatarInfo{}
|
||||
err := json.Unmarshal([]byte(avatarJson), avatarInfo)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
switch AvatarInfo.Type {
|
||||
switch avatarInfo.Type {
|
||||
case "gravatar":
|
||||
return AvatarInfo.Gravatar
|
||||
return avatarInfo.Gravatar
|
||||
case "custom":
|
||||
return AvatarInfo.Custom
|
||||
return avatarInfo.Custom
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
|
@ -431,6 +431,8 @@ type UserRankingSimpleInfo struct {
|
|||
Username string `json:"username"`
|
||||
// rank
|
||||
Rank int `json:"rank"`
|
||||
// vote
|
||||
VoteCount int `json:"vote_count"`
|
||||
// display name
|
||||
DisplayName string `json:"display_name"`
|
||||
// avatar
|
||||
|
|
|
@ -2,6 +2,7 @@ package activity_common
|
|||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/answerdev/answer/internal/entity"
|
||||
"github.com/answerdev/answer/internal/service/activity_queue"
|
||||
|
@ -18,6 +19,10 @@ type ActivityRepo interface {
|
|||
GetUserIDObjectIDActivitySum(ctx context.Context, userID, objectID string) (int, error)
|
||||
GetActivityTypeByConfigKey(ctx context.Context, configKey string) (activityType int, err error)
|
||||
AddActivity(ctx context.Context, activity *entity.Activity) (err error)
|
||||
GetUsersWhoHasGainedTheMostReputation(
|
||||
ctx context.Context, startTime, endTime time.Time, limit int) (rankStat []*entity.ActivityUserRankStat, err error)
|
||||
GetUsersWhoHasVoteMost(
|
||||
ctx context.Context, startTime, endTime time.Time, limit int) (voteStat []*entity.ActivityUserVoteStat, err error)
|
||||
}
|
||||
|
||||
type ActivityCommon struct {
|
||||
|
|
|
@ -12,6 +12,14 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
ActivityTypeList = []string{
|
||||
QuestionVoteUp,
|
||||
QuestionVoteDown,
|
||||
AnswerVoteUp,
|
||||
AnswerVoteDown,
|
||||
CommentVoteUp,
|
||||
CommentVoteDown,
|
||||
}
|
||||
activityTypeFlagMapping = map[string]string{
|
||||
QuestionVoteUp: "upvote",
|
||||
QuestionVoteDown: "downvote",
|
||||
|
|
|
@ -10,6 +10,8 @@ import (
|
|||
type UserRoleRelRepo interface {
|
||||
SaveUserRoleRel(ctx context.Context, userID string, roleID int) (err error)
|
||||
GetUserRoleRelList(ctx context.Context, userIDs []string) (userRoleRelList []*entity.UserRoleRel, err error)
|
||||
GetUserRoleRelListByRoleID(ctx context.Context, roleIDs []int) (
|
||||
userRoleRelList []*entity.UserRoleRel, err error)
|
||||
GetUserRoleRel(ctx context.Context, userID string) (rolePowerRel *entity.UserRoleRel, exist bool, err error)
|
||||
}
|
||||
|
||||
|
@ -93,3 +95,12 @@ func (us *UserRoleRelService) GetUserRole(ctx context.Context, userID string) (r
|
|||
}
|
||||
return rolePowerRel.RoleID, nil
|
||||
}
|
||||
|
||||
// GetUserByRoleID get user by role id
|
||||
func (us *UserRoleRelService) GetUserByRoleID(ctx context.Context, roleIDs []int) (rel []*entity.UserRoleRel, err error) {
|
||||
rolePowerRels, err := us.userRoleRelRepo.GetUserRoleRelListByRoleID(ctx, roleIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rolePowerRels, nil
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/answerdev/answer/internal/base/handler"
|
||||
"github.com/answerdev/answer/internal/base/reason"
|
||||
|
@ -12,6 +13,7 @@ import (
|
|||
"github.com/answerdev/answer/internal/entity"
|
||||
"github.com/answerdev/answer/internal/schema"
|
||||
"github.com/answerdev/answer/internal/service/activity"
|
||||
"github.com/answerdev/answer/internal/service/activity_common"
|
||||
"github.com/answerdev/answer/internal/service/auth"
|
||||
"github.com/answerdev/answer/internal/service/export"
|
||||
"github.com/answerdev/answer/internal/service/role"
|
||||
|
@ -31,6 +33,7 @@ type UserService struct {
|
|||
userCommonService *usercommon.UserCommon
|
||||
userRepo usercommon.UserRepo
|
||||
userActivity activity.UserActiveActivityRepo
|
||||
activityRepo activity_common.ActivityRepo
|
||||
serviceConfig *service_config.ServiceConfig
|
||||
emailService *export.EmailService
|
||||
authService *auth.AuthService
|
||||
|
@ -40,6 +43,7 @@ type UserService struct {
|
|||
|
||||
func NewUserService(userRepo usercommon.UserRepo,
|
||||
userActivity activity.UserActiveActivityRepo,
|
||||
activityRepo activity_common.ActivityRepo,
|
||||
emailService *export.EmailService,
|
||||
authService *auth.AuthService,
|
||||
serviceConfig *service_config.ServiceConfig,
|
||||
|
@ -51,6 +55,7 @@ func NewUserService(userRepo usercommon.UserRepo,
|
|||
userCommonService: userCommonService,
|
||||
userRepo: userRepo,
|
||||
userActivity: userActivity,
|
||||
activityRepo: activityRepo,
|
||||
emailService: emailService,
|
||||
serviceConfig: serviceConfig,
|
||||
authService: authService,
|
||||
|
@ -557,7 +562,119 @@ func (us *UserService) getSiteUrl(ctx context.Context) string {
|
|||
}
|
||||
|
||||
// UserRanking get user ranking
|
||||
func (us *UserService) UserRanking(ctx context.Context) (resp []*schema.UserRankingResp, err error) {
|
||||
//us.userRepo.GetByUserID()
|
||||
func (us *UserService) UserRanking(ctx context.Context) (resp *schema.UserRankingResp, err error) {
|
||||
resp = &schema.UserRankingResp{
|
||||
UsersWithTheMostReputation: make([]*schema.UserRankingSimpleInfo, 0),
|
||||
UsersWithTheMostVote: make([]*schema.UserRankingSimpleInfo, 0),
|
||||
Staffs: make([]*schema.UserRankingSimpleInfo, 0),
|
||||
}
|
||||
endTime := time.Now()
|
||||
startTime := endTime.AddDate(0, 0, -7)
|
||||
limit := 20
|
||||
|
||||
userIDs := make([]string, 0)
|
||||
userIDExist := make(map[string]bool, 0)
|
||||
userInfoMapping := make(map[string]*entity.User, 0)
|
||||
|
||||
// get most reputation users
|
||||
rankStat, err := us.activityRepo.GetUsersWhoHasGainedTheMostReputation(ctx, startTime, endTime, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, stat := range rankStat {
|
||||
if stat.Rank == 0 {
|
||||
continue
|
||||
}
|
||||
if userIDExist[stat.UserID] {
|
||||
continue
|
||||
}
|
||||
userIDs = append(userIDs, stat.UserID)
|
||||
userIDExist[stat.UserID] = true
|
||||
}
|
||||
|
||||
voteStat, err := us.activityRepo.GetUsersWhoHasVoteMost(ctx, startTime, endTime, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, stat := range voteStat {
|
||||
if stat.VoteCount == 0 {
|
||||
continue
|
||||
}
|
||||
if userIDExist[stat.UserID] {
|
||||
continue
|
||||
}
|
||||
userIDs = append(userIDs, stat.UserID)
|
||||
userIDExist[stat.UserID] = true
|
||||
}
|
||||
|
||||
// get all staff members
|
||||
userRoleRels, err := us.userRoleService.GetUserByRoleID(ctx, []int{role.RoleAdminID, role.RoleModeratorID})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, rel := range userRoleRels {
|
||||
if userIDExist[rel.UserID] {
|
||||
continue
|
||||
}
|
||||
userIDs = append(userIDs, rel.UserID)
|
||||
userIDExist[rel.UserID] = true
|
||||
}
|
||||
|
||||
if len(userIDs) == 0 {
|
||||
return resp, nil
|
||||
}
|
||||
userInfoList, err := us.userRepo.BatchGetByID(ctx, userIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, user := range userInfoList {
|
||||
user.Avatar = schema.FormatAvatarInfo(user.Avatar)
|
||||
userInfoMapping[user.ID] = user
|
||||
}
|
||||
|
||||
for _, stat := range rankStat {
|
||||
if stat.Rank == 0 {
|
||||
continue
|
||||
}
|
||||
userInfo := userInfoMapping[stat.UserID]
|
||||
if userInfo == nil {
|
||||
continue
|
||||
}
|
||||
resp.UsersWithTheMostReputation = append(resp.UsersWithTheMostReputation, &schema.UserRankingSimpleInfo{
|
||||
Username: userInfo.Username,
|
||||
Rank: stat.Rank,
|
||||
DisplayName: userInfo.DisplayName,
|
||||
Avatar: userInfo.Avatar,
|
||||
})
|
||||
}
|
||||
|
||||
for _, stat := range voteStat {
|
||||
if stat.VoteCount == 0 {
|
||||
continue
|
||||
}
|
||||
userInfo := userInfoMapping[stat.UserID]
|
||||
if userInfo == nil {
|
||||
continue
|
||||
}
|
||||
resp.UsersWithTheMostVote = append(resp.UsersWithTheMostVote, &schema.UserRankingSimpleInfo{
|
||||
Username: userInfo.Username,
|
||||
VoteCount: stat.VoteCount,
|
||||
DisplayName: userInfo.DisplayName,
|
||||
Avatar: userInfo.Avatar,
|
||||
})
|
||||
}
|
||||
|
||||
for _, rel := range userRoleRels {
|
||||
userInfo := userInfoMapping[rel.UserID]
|
||||
if userInfo == nil {
|
||||
continue
|
||||
}
|
||||
resp.Staffs = append(resp.Staffs, &schema.UserRankingSimpleInfo{
|
||||
Username: userInfo.Username,
|
||||
Rank: userInfo.Rank,
|
||||
DisplayName: userInfo.DisplayName,
|
||||
Avatar: userInfo.Avatar,
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue