From 820d87e318bffb9558af65de1c841469971ebbd0 Mon Sep 17 00:00:00 2001 From: LinkinStar Date: Fri, 25 Nov 2022 18:35:35 +0800 Subject: [PATCH] feat: Added a vote reputation limit --- cmd/answer/wire_gen.go | 2 +- go.mod | 2 + go.sum | 2 + internal/controller/vote_controller.go | 34 +++++++++++++--- internal/schema/vote_schema.go | 1 + internal/service/rank/rank_service.go | 54 +++++++++++++++++++++++++- 6 files changed, 87 insertions(+), 8 deletions(-) diff --git a/cmd/answer/wire_gen.go b/cmd/answer/wire_gen.go index 8ab960e5..a48ecaf2 100644 --- a/cmd/answer/wire_gen.go +++ b/cmd/answer/wire_gen.go @@ -135,7 +135,7 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database, reportController := controller.NewReportController(reportService, rankService) serviceVoteRepo := activity.NewVoteRepo(dataData, uniqueIDRepo, configRepo, activityRepo, userRankRepo, voteRepo) voteService := service.NewVoteService(serviceVoteRepo, uniqueIDRepo, configRepo, questionRepo, answerRepo, commentCommonRepo, objService) - voteController := controller.NewVoteController(voteService) + voteController := controller.NewVoteController(voteService, rankService) followRepo := activity_common.NewFollowRepo(dataData, uniqueIDRepo, activityRepo) tagService := tag2.NewTagService(tagRepo, tagCommonService, revisionService, followRepo, siteInfoCommonService) tagController := controller.NewTagController(tagService, tagCommonService, rankService) diff --git a/go.mod b/go.mod index 95796a93..13bd9f47 100644 --- a/go.mod +++ b/go.mod @@ -65,6 +65,7 @@ require ( github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect + github.com/google/subcommands v1.0.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.12 // indirect github.com/inconshreveable/mousetrap v1.0.1 // indirect @@ -105,6 +106,7 @@ require ( go.uber.org/multierr v1.8.0 // indirect go.uber.org/zap v1.23.0 // indirect golang.org/x/image v0.1.0 // indirect + golang.org/x/mod v0.6.0 // indirect golang.org/x/sys v0.1.0 // indirect golang.org/x/text v0.4.0 // indirect golang.org/x/tools v0.2.0 // indirect diff --git a/go.sum b/go.sum index f12aeb7a..8bfba639 100644 --- a/go.sum +++ b/go.sum @@ -284,6 +284,7 @@ github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLe github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= +github.com/google/subcommands v1.0.1 h1:/eqq+otEXm5vhfBrbREPCSVQbvofip6kIz+mX5TUH7k= github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -779,6 +780,7 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/internal/controller/vote_controller.go b/internal/controller/vote_controller.go index 7fcdf232..21783c86 100644 --- a/internal/controller/vote_controller.go +++ b/internal/controller/vote_controller.go @@ -3,20 +3,24 @@ package controller import ( "github.com/answerdev/answer/internal/base/handler" "github.com/answerdev/answer/internal/base/middleware" + "github.com/answerdev/answer/internal/base/reason" "github.com/answerdev/answer/internal/schema" "github.com/answerdev/answer/internal/service" + "github.com/answerdev/answer/internal/service/rank" "github.com/gin-gonic/gin" "github.com/jinzhu/copier" + "github.com/segmentfault/pacman/errors" ) // VoteController activity controller type VoteController struct { VoteService *service.VoteService + rankService *rank.RankService } // NewVoteController new controller -func NewVoteController(voteService *service.VoteService) *VoteController { - return &VoteController{VoteService: voteService} +func NewVoteController(voteService *service.VoteService, rankService *rank.RankService) *VoteController { + return &VoteController{VoteService: voteService, rankService: rankService} } // VoteUp godoc @@ -34,9 +38,19 @@ func (vc *VoteController) VoteUp(ctx *gin.Context) { if handler.BindAndCheck(ctx, req) { return } + req.UserID = middleware.GetLoginUserIDFromContext(ctx) + can, err := vc.rankService.CheckVotePermission(ctx, req.UserID, req.ObjectID, true) + if err != nil { + handler.HandleResponse(ctx, err, nil) + return + } + if !can { + handler.HandleResponse(ctx, errors.Forbidden(reason.RankFailToMeetTheCondition), nil) + return + } + dto := &schema.VoteDTO{} _ = copier.Copy(dto, req) - dto.UserID = middleware.GetLoginUserIDFromContext(ctx) resp, err := vc.VoteService.VoteUp(ctx, dto) if err != nil { handler.HandleResponse(ctx, err, schema.ErrTypeToast) @@ -60,10 +74,20 @@ func (vc *VoteController) VoteDown(ctx *gin.Context) { if handler.BindAndCheck(ctx, req) { return } + + req.UserID = middleware.GetLoginUserIDFromContext(ctx) + can, err := vc.rankService.CheckVotePermission(ctx, req.UserID, req.ObjectID, false) + if err != nil { + handler.HandleResponse(ctx, err, nil) + return + } + if !can { + handler.HandleResponse(ctx, errors.Forbidden(reason.RankFailToMeetTheCondition), nil) + return + } + dto := &schema.VoteDTO{} _ = copier.Copy(dto, req) - - dto.UserID = middleware.GetLoginUserIDFromContext(ctx) resp, err := vc.VoteService.VoteDown(ctx, dto) if err != nil { handler.HandleResponse(ctx, err, schema.ErrTypeToast) diff --git a/internal/schema/vote_schema.go b/internal/schema/vote_schema.go index ec37ebc8..8a17666f 100644 --- a/internal/schema/vote_schema.go +++ b/internal/schema/vote_schema.go @@ -3,6 +3,7 @@ package schema type VoteReq struct { ObjectID string `validate:"required" form:"object_id" json:"object_id"` // id IsCancel bool `validate:"omitempty" form:"is_cancel" json:"is_cancel"` // is cancel + UserID string `json:"-"` } type VoteDTO struct { diff --git a/internal/service/rank/rank_service.go b/internal/service/rank/rank_service.go index 7e828d20..22bae247 100644 --- a/internal/service/rank/rank_service.go +++ b/internal/service/rank/rank_service.go @@ -3,6 +3,7 @@ package rank import ( "context" + "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" @@ -75,7 +76,7 @@ func NewRankService( } } -// CheckOperationPermission verify that the user has operation +// 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 { @@ -110,7 +111,7 @@ func (rs *RankService) CheckOperationPermission(ctx context.Context, userID stri return rs.checkUserRank(ctx, userInfo.ID, userInfo.Rank, action) } -// CheckOperationPermissions verify that the user has operation +// 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)) @@ -154,6 +155,55 @@ func (rs *RankService) CheckOperationPermissions(ctx context.Context, userID str 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 +} + // 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) {