mirror of https://gitee.com/answerdev/answer.git
302 lines
9.1 KiB
Go
302 lines
9.1 KiB
Go
package rank
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
"github.com/answerdev/answer/internal/base/constant"
|
|
"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/schema"
|
|
"github.com/answerdev/answer/internal/service/activity_type"
|
|
"github.com/answerdev/answer/internal/service/config"
|
|
"github.com/answerdev/answer/internal/service/object_info"
|
|
"github.com/answerdev/answer/internal/service/role"
|
|
usercommon "github.com/answerdev/answer/internal/service/user_common"
|
|
"github.com/segmentfault/pacman/errors"
|
|
"github.com/segmentfault/pacman/log"
|
|
"xorm.io/xorm"
|
|
)
|
|
|
|
const (
|
|
QuestionAddRank = "rank.question.add"
|
|
QuestionEditRank = "rank.question.edit"
|
|
QuestionEditWithoutReviewRank = "rank.question.edit_without_review"
|
|
QuestionDeleteRank = "rank.question.delete"
|
|
QuestionVoteUpRank = "rank.question.vote_up"
|
|
QuestionVoteDownRank = "rank.question.vote_down"
|
|
AnswerAddRank = "rank.answer.add"
|
|
AnswerEditRank = "rank.answer.edit"
|
|
AnswerEditWithoutReviewRank = "rank.answer.edit_without_review"
|
|
AnswerDeleteRank = "rank.answer.delete"
|
|
AnswerAcceptRank = "rank.answer.accept"
|
|
AnswerVoteUpRank = "rank.answer.vote_up"
|
|
AnswerVoteDownRank = "rank.answer.vote_down"
|
|
CommentAddRank = "rank.comment.add"
|
|
CommentEditRank = "rank.comment.edit"
|
|
CommentDeleteRank = "rank.comment.delete"
|
|
CommentVoteUpRank = "rank.comment.vote_up"
|
|
CommentVoteDownRank = "rank.comment.vote_down"
|
|
ReportAddRank = "rank.report.add"
|
|
TagAddRank = "rank.tag.add"
|
|
TagEditRank = "rank.tag.edit"
|
|
TagEditWithoutReviewRank = "rank.tag.edit_without_review"
|
|
TagDeleteRank = "rank.tag.delete"
|
|
TagSynonymRank = "rank.tag.synonym"
|
|
LinkUrlLimitRank = "rank.link.url_limit"
|
|
VoteDetailRank = "rank.vote.detail"
|
|
AnswerAuditRank = "rank.answer.audit"
|
|
QuestionAuditRank = "rank.question.audit"
|
|
TagAuditRank = "rank.tag.audit"
|
|
)
|
|
|
|
type UserRankRepo interface {
|
|
TriggerUserRank(ctx context.Context, session *xorm.Session, userId string, rank int, activityType int) (isReachStandard bool, err error)
|
|
UserRankPage(ctx context.Context, userId string, page, pageSize int) (rankPage []*entity.Activity, total int64, err error)
|
|
}
|
|
|
|
// RankService rank service
|
|
type RankService struct {
|
|
userCommon *usercommon.UserCommon
|
|
configRepo config.ConfigRepo
|
|
userRankRepo UserRankRepo
|
|
objectInfoService *object_info.ObjService
|
|
roleService *role.UserRoleRelService
|
|
rolePowerService *role.RolePowerRelService
|
|
}
|
|
|
|
// NewRankService new rank service
|
|
func NewRankService(
|
|
userCommon *usercommon.UserCommon,
|
|
userRankRepo UserRankRepo,
|
|
objectInfoService *object_info.ObjService,
|
|
roleService *role.UserRoleRelService,
|
|
rolePowerService *role.RolePowerRelService,
|
|
configRepo config.ConfigRepo) *RankService {
|
|
return &RankService{
|
|
userCommon: userCommon,
|
|
configRepo: configRepo,
|
|
userRankRepo: userRankRepo,
|
|
objectInfoService: objectInfoService,
|
|
roleService: roleService,
|
|
rolePowerService: rolePowerService,
|
|
}
|
|
}
|
|
|
|
// CheckOperationPermission verify that the user has permission
|
|
func (rs *RankService) CheckOperationPermission(ctx context.Context, userID string, action string, objectID string) (
|
|
can bool, err error) {
|
|
if len(userID) == 0 {
|
|
return false, nil
|
|
}
|
|
|
|
// get the rank of the current user
|
|
userInfo, exist, err := rs.userCommon.GetUserBasicInfoByID(ctx, userID)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if !exist {
|
|
return false, nil
|
|
}
|
|
powerMapping := rs.getUserPowerMapping(ctx, userID)
|
|
// TODO: remove
|
|
act := strings.TrimPrefix(action, "rank.")
|
|
if powerMapping[act] {
|
|
return true, nil
|
|
}
|
|
|
|
if len(objectID) > 0 {
|
|
objectInfo, err := rs.objectInfoService.GetInfo(ctx, objectID)
|
|
if err != nil {
|
|
return can, err
|
|
}
|
|
// if the user is this object creator, the user can operate this object.
|
|
if objectInfo != nil &&
|
|
objectInfo.ObjectCreatorUserID == userID {
|
|
return true, nil
|
|
}
|
|
}
|
|
|
|
return rs.checkUserRank(ctx, userInfo.ID, userInfo.Rank, action)
|
|
}
|
|
|
|
// CheckOperationPermissions verify that the user has permission
|
|
func (rs *RankService) CheckOperationPermissions(ctx context.Context, userID string, actions []string, objectID string) (
|
|
can []bool, err error) {
|
|
can = make([]bool, len(actions))
|
|
if len(userID) == 0 {
|
|
return can, nil
|
|
}
|
|
|
|
// get the rank of the current user
|
|
userInfo, exist, err := rs.userCommon.GetUserBasicInfoByID(ctx, userID)
|
|
if err != nil {
|
|
return can, err
|
|
}
|
|
if !exist {
|
|
return can, nil
|
|
}
|
|
|
|
objectOwner := false
|
|
if len(objectID) > 0 {
|
|
objectInfo, err := rs.objectInfoService.GetInfo(ctx, objectID)
|
|
if err != nil {
|
|
return can, err
|
|
}
|
|
// if the user is this object creator, the user can operate this object.
|
|
if objectInfo != nil &&
|
|
objectInfo.ObjectCreatorUserID == userID {
|
|
objectOwner = true
|
|
}
|
|
}
|
|
|
|
powerMapping := rs.getUserPowerMapping(ctx, userID)
|
|
|
|
for idx, action := range actions {
|
|
// TODO: remove
|
|
act := strings.TrimPrefix(action, "rank.")
|
|
if powerMapping[act] || objectOwner {
|
|
can[idx] = true
|
|
continue
|
|
}
|
|
meetRank, err := rs.checkUserRank(ctx, userInfo.ID, userInfo.Rank, action)
|
|
if err != nil {
|
|
log.Error(err)
|
|
}
|
|
can[idx] = meetRank
|
|
}
|
|
return can, nil
|
|
}
|
|
|
|
// CheckVotePermission verify that the user has vote permission
|
|
func (rs *RankService) CheckVotePermission(ctx context.Context, userID, objectID string, voteUp bool) (
|
|
can bool, err error) {
|
|
if len(userID) == 0 || len(objectID) == 0 {
|
|
return false, nil
|
|
}
|
|
|
|
// get the rank of the current user
|
|
userInfo, exist, err := rs.userCommon.GetUserBasicInfoByID(ctx, userID)
|
|
if err != nil {
|
|
return can, err
|
|
}
|
|
if !exist {
|
|
return can, nil
|
|
}
|
|
|
|
objectInfo, err := rs.objectInfoService.GetInfo(ctx, objectID)
|
|
if err != nil {
|
|
return can, err
|
|
}
|
|
|
|
action := ""
|
|
switch objectInfo.ObjectType {
|
|
case constant.QuestionObjectType:
|
|
if voteUp {
|
|
action = QuestionVoteUpRank
|
|
} else {
|
|
action = QuestionVoteDownRank
|
|
}
|
|
case constant.AnswerObjectType:
|
|
if voteUp {
|
|
action = AnswerVoteUpRank
|
|
} else {
|
|
action = AnswerVoteDownRank
|
|
}
|
|
case constant.CommentObjectType:
|
|
if voteUp {
|
|
action = CommentVoteUpRank
|
|
} else {
|
|
action = CommentVoteDownRank
|
|
}
|
|
}
|
|
meetRank, err := rs.checkUserRank(ctx, userInfo.ID, userInfo.Rank, action)
|
|
if err != nil {
|
|
log.Error(err)
|
|
}
|
|
return meetRank, nil
|
|
}
|
|
|
|
// getUserPowerMapping get user power mapping
|
|
func (rs *RankService) getUserPowerMapping(ctx context.Context, userID string) (powerMapping map[string]bool) {
|
|
powerMapping = make(map[string]bool, 0)
|
|
userRole, err := rs.roleService.GetUserRole(ctx, userID)
|
|
if err != nil {
|
|
log.Error(err)
|
|
return powerMapping
|
|
}
|
|
powers, err := rs.rolePowerService.GetRolePowerList(ctx, userRole)
|
|
if err != nil {
|
|
log.Error(err)
|
|
return powerMapping
|
|
}
|
|
|
|
for _, power := range powers {
|
|
powerMapping[power] = true
|
|
}
|
|
return powerMapping
|
|
}
|
|
|
|
// CheckRankPermission verify that the user meets the prestige criteria
|
|
func (rs *RankService) checkUserRank(ctx context.Context, userID string, userRank int, action string) (
|
|
can bool, err error) {
|
|
// get the amount of rank required for the current operation
|
|
requireRank, err := rs.configRepo.GetInt(action)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
if userRank < requireRank || requireRank < 0 {
|
|
log.Debugf("user %s want to do action %s, but rank %d < %d",
|
|
userID, action, userRank, requireRank)
|
|
return false, nil
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
// GetRankPersonalWithPage get personal comment list page
|
|
func (rs *RankService) GetRankPersonalWithPage(ctx context.Context, req *schema.GetRankPersonalWithPageReq) (
|
|
pageModel *pager.PageModel, err error) {
|
|
if len(req.Username) > 0 {
|
|
userInfo, exist, err := rs.userCommon.GetUserBasicInfoByUserName(ctx, req.Username)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !exist {
|
|
return nil, errors.BadRequest(reason.UserNotFound)
|
|
}
|
|
req.UserID = userInfo.ID
|
|
}
|
|
if len(req.UserID) == 0 {
|
|
return nil, errors.BadRequest(reason.UserNotFound)
|
|
}
|
|
|
|
userRankPage, total, err := rs.userRankRepo.UserRankPage(ctx, req.UserID, req.Page, req.PageSize)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
resp := make([]*schema.GetRankPersonalWithPageResp, 0)
|
|
for _, userRankInfo := range userRankPage {
|
|
commentResp := &schema.GetRankPersonalWithPageResp{
|
|
CreatedAt: userRankInfo.CreatedAt.Unix(),
|
|
ObjectID: userRankInfo.ObjectID,
|
|
Reputation: userRankInfo.Rank,
|
|
}
|
|
if len(userRankInfo.ObjectID) > 0 {
|
|
objInfo, err := rs.objectInfoService.GetInfo(ctx, userRankInfo.ObjectID)
|
|
if err != nil {
|
|
log.Error(err)
|
|
} else {
|
|
commentResp.RankType = activity_type.Format(userRankInfo.ActivityType)
|
|
commentResp.ObjectType = objInfo.ObjectType
|
|
commentResp.Title = objInfo.Title
|
|
commentResp.Content = objInfo.Content
|
|
commentResp.QuestionID = objInfo.QuestionID
|
|
commentResp.AnswerID = objInfo.AnswerID
|
|
}
|
|
}
|
|
resp = append(resp, commentResp)
|
|
}
|
|
return pager.NewPageModel(total, resp), nil
|
|
}
|