feat(rank): Modify all permission restriction controls

This commit is contained in:
LinkinStar 2022-12-02 15:08:18 +08:00
parent 74015c13eb
commit 2b0634e2e6
27 changed files with 171 additions and 129 deletions

View File

@ -111,7 +111,11 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
userActiveActivityRepo := activity.NewUserActiveActivityRepo(dataData, activityRepo, userRankRepo, configRepo)
emailRepo := export.NewEmailRepo(dataData)
emailService := export2.NewEmailService(configRepo, emailRepo, siteInfoRepo)
userService := service.NewUserService(userRepo, userActiveActivityRepo, emailService, authService, serviceConf, siteInfoCommonService)
userRoleRelRepo := role.NewUserRoleRelRepo(dataData)
roleRepo := role.NewRoleRepo(dataData)
roleService := role2.NewRoleService(roleRepo)
userRoleRelService := role2.NewUserRoleRelService(userRoleRelRepo, roleService)
userService := service.NewUserService(userRepo, userActiveActivityRepo, emailService, authService, serviceConf, siteInfoCommonService, userRoleRelService)
captchaRepo := captcha.NewCaptchaRepo(dataData)
captchaService := action.NewCaptchaService(captchaRepo)
uploaderService := uploader.NewUploaderService(serviceConf, siteInfoCommonService)
@ -130,10 +134,6 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
objService := object_info.NewObjService(answerRepo, questionRepo, commentCommonRepo, tagCommonRepo, tagCommonService)
voteRepo := activity_common.NewVoteRepo(dataData, activityRepo)
commentService := comment2.NewCommentService(commentRepo, commentCommonRepo, userCommon, objService, voteRepo)
userRoleRelRepo := role.NewUserRoleRelRepo(dataData)
roleRepo := role.NewRoleRepo(dataData)
roleService := role2.NewRoleService(roleRepo)
userRoleRelService := role2.NewUserRoleRelService(userRoleRelRepo, roleService)
rolePowerRelRepo := role.NewRolePowerRelRepo(dataData)
rolePowerRelService := role2.NewRolePowerRelService(rolePowerRelRepo, userRoleRelService)
rankService := rank2.NewRankService(userCommon, userRankRepo, objService, userRoleRelService, rolePowerRelService, configRepo)

View File

@ -141,6 +141,8 @@ backend:
install:
create_config_failed:
other: "Cant create the config.yaml file."
cannot_update_your_role:
other: "You cannot modify your role."
report:
spam:
name:

View File

@ -105,7 +105,8 @@ backend:
other: "用户名已被使用"
set_avatar:
other: "头像设置错误"
cannot_update_your_role:
other: "你无法修改自己的角色"
report:
spam:
name:

View File

@ -57,4 +57,5 @@ const (
RecommendTagEnter = "error.tag.recommend_tag_enter"
RevisionReviewUnderway = "error.revision.review_underway"
RevisionNoPermission = "error.revision.no_permission"
UserCannotUpdateYourRole = "error.user.cannot_update_your_role"
)

View File

@ -9,6 +9,7 @@ import (
"github.com/answerdev/answer/internal/schema"
"github.com/answerdev/answer/internal/service"
"github.com/answerdev/answer/internal/service/dashboard"
"github.com/answerdev/answer/internal/service/permission"
"github.com/answerdev/answer/internal/service/rank"
"github.com/gin-gonic/gin"
"github.com/segmentfault/pacman/errors"
@ -51,7 +52,7 @@ func (ac *AnswerController) RemoveAnswer(ctx *gin.Context) {
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
req.IsAdmin = middleware.GetIsAdminFromContext(ctx)
can, err := ac.rankService.CheckOperationPermission(ctx, req.UserID, rank.AnswerDeleteRank, req.ID)
can, err := ac.rankService.CheckOperationPermission(ctx, req.UserID, permission.AnswerDelete, req.ID)
if err != nil {
handler.HandleResponse(ctx, err, nil)
return
@ -110,7 +111,7 @@ func (ac *AnswerController) Add(ctx *gin.Context) {
}
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
can, err := ac.rankService.CheckOperationPermission(ctx, req.UserID, rank.AnswerAddRank, "")
can, err := ac.rankService.CheckOperationPermission(ctx, req.UserID, permission.AnswerAdd, "")
if err != nil {
handler.HandleResponse(ctx, err, nil)
return
@ -159,8 +160,8 @@ func (ac *AnswerController) Update(ctx *gin.Context) {
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
canList, err := ac.rankService.CheckOperationPermissions(ctx, req.UserID, []string{
rank.AnswerEditRank,
rank.AnswerEditWithoutReviewRank,
permission.AnswerEdit,
permission.AnswerEditWithoutReview,
}, "")
if err != nil {
handler.HandleResponse(ctx, err, nil)
@ -204,8 +205,8 @@ func (ac *AnswerController) AnswerList(ctx *gin.Context) {
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
canList, err := ac.rankService.CheckOperationPermissions(ctx, req.UserID, []string{
rank.AnswerEditRank,
rank.AnswerDeleteRank,
permission.AnswerEdit,
permission.AnswerDelete,
}, "")
if err != nil {
handler.HandleResponse(ctx, err, nil)
@ -242,7 +243,7 @@ func (ac *AnswerController) Adopted(ctx *gin.Context) {
}
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
can, err := ac.rankService.CheckOperationPermission(ctx, req.UserID, rank.AnswerAcceptRank, req.QuestionID)
can, err := ac.rankService.CheckOperationPermission(ctx, req.UserID, permission.AnswerAccept, req.QuestionID)
if err != nil {
handler.HandleResponse(ctx, err, nil)
return

View File

@ -6,6 +6,7 @@ import (
"github.com/answerdev/answer/internal/base/reason"
"github.com/answerdev/answer/internal/schema"
"github.com/answerdev/answer/internal/service/comment"
"github.com/answerdev/answer/internal/service/permission"
"github.com/answerdev/answer/internal/service/rank"
"github.com/gin-gonic/gin"
"github.com/segmentfault/pacman/errors"
@ -42,9 +43,9 @@ func (cc *CommentController) AddComment(ctx *gin.Context) {
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
canList, err := cc.rankService.CheckOperationPermissions(ctx, req.UserID, []string{
rank.CommentAddRank,
rank.CommentEditRank,
rank.CommentDeleteRank,
permission.CommentAdd,
permission.CommentEdit,
permission.CommentDelete,
}, "")
if err != nil {
handler.HandleResponse(ctx, err, nil)
@ -79,7 +80,7 @@ func (cc *CommentController) RemoveComment(ctx *gin.Context) {
}
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
can, err := cc.rankService.CheckOperationPermission(ctx, req.UserID, rank.CommentDeleteRank, req.CommentID)
can, err := cc.rankService.CheckOperationPermission(ctx, req.UserID, permission.CommentDelete, req.CommentID)
if err != nil {
handler.HandleResponse(ctx, err, nil)
return
@ -110,7 +111,7 @@ func (cc *CommentController) UpdateComment(ctx *gin.Context) {
}
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
can, err := cc.rankService.CheckOperationPermission(ctx, req.UserID, rank.CommentEditRank, req.CommentID)
can, err := cc.rankService.CheckOperationPermission(ctx, req.UserID, permission.CommentEdit, req.CommentID)
if err != nil {
handler.HandleResponse(ctx, err, nil)
return
@ -143,8 +144,8 @@ func (cc *CommentController) GetCommentWithPage(ctx *gin.Context) {
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
canList, err := cc.rankService.CheckOperationPermissions(ctx, req.UserID, []string{
rank.CommentEditRank,
rank.CommentDeleteRank,
permission.CommentEdit,
permission.CommentDelete,
}, "")
if err != nil {
handler.HandleResponse(ctx, err, nil)
@ -195,8 +196,8 @@ func (cc *CommentController) GetComment(ctx *gin.Context) {
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
canList, err := cc.rankService.CheckOperationPermissions(ctx, req.UserID, []string{
rank.CommentEditRank,
rank.CommentDeleteRank,
permission.CommentEdit,
permission.CommentDelete,
}, "")
if err != nil {
handler.HandleResponse(ctx, err, nil)

View File

@ -5,6 +5,7 @@ import (
"github.com/answerdev/answer/internal/base/middleware"
"github.com/answerdev/answer/internal/schema"
"github.com/answerdev/answer/internal/service/notification"
"github.com/answerdev/answer/internal/service/permission"
"github.com/answerdev/answer/internal/service/rank"
"github.com/gin-gonic/gin"
)
@ -43,9 +44,9 @@ func (nc *NotificationController) GetRedDot(ctx *gin.Context) {
req.UserID = userID
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
canList, err := nc.rankService.CheckOperationPermissions(ctx, req.UserID, []string{
rank.QuestionAuditRank,
rank.AnswerAuditRank,
rank.TagAuditRank,
permission.QuestionAudit,
permission.AnswerAudit,
permission.TagAudit,
}, "")
if err != nil {
handler.HandleResponse(ctx, err, nil)
@ -76,9 +77,9 @@ func (nc *NotificationController) ClearRedDot(ctx *gin.Context) {
}
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
canList, err := nc.rankService.CheckOperationPermissions(ctx, req.UserID, []string{
rank.QuestionAuditRank,
rank.AnswerAuditRank,
rank.TagAuditRank,
permission.QuestionAudit,
permission.AnswerAudit,
permission.TagAudit,
}, "")
if err != nil {
handler.HandleResponse(ctx, err, nil)

View File

@ -9,6 +9,7 @@ import (
"github.com/answerdev/answer/internal/entity"
"github.com/answerdev/answer/internal/schema"
"github.com/answerdev/answer/internal/service"
"github.com/answerdev/answer/internal/service/permission"
"github.com/answerdev/answer/internal/service/rank"
"github.com/answerdev/answer/pkg/converter"
"github.com/gin-gonic/gin"
@ -43,7 +44,7 @@ func (qc *QuestionController) RemoveQuestion(ctx *gin.Context) {
}
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
req.IsAdmin = middleware.GetIsAdminFromContext(ctx)
can, err := qc.rankService.CheckOperationPermission(ctx, req.UserID, rank.QuestionDeleteRank, req.ID)
can, err := qc.rankService.CheckOperationPermission(ctx, req.UserID, permission.QuestionDelete, req.ID)
if err != nil {
handler.HandleResponse(ctx, err, nil)
return
@ -93,8 +94,10 @@ func (qc *QuestionController) GetQuestion(ctx *gin.Context) {
userID := middleware.GetLoginUserIDFromContext(ctx)
req := schema.QuestionPermission{}
canList, err := qc.rankService.CheckOperationPermissions(ctx, userID, []string{
rank.QuestionEditRank,
rank.QuestionDeleteRank,
permission.QuestionEdit,
permission.QuestionDelete,
permission.QuestionClose,
permission.QuestionReopen,
}, id)
if err != nil {
handler.HandleResponse(ctx, err, nil)
@ -102,7 +105,8 @@ func (qc *QuestionController) GetQuestion(ctx *gin.Context) {
}
req.CanEdit = canList[0]
req.CanDelete = canList[1]
req.CanClose = middleware.GetIsAdminFromContext(ctx)
req.CanClose = canList[2]
req.CanReopen = canList[3]
info, err := qc.questionService.GetQuestionAndAddPV(ctx, id, userID, req)
if err != nil {
@ -208,9 +212,11 @@ func (qc *QuestionController) AddQuestion(ctx *gin.Context) {
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
canList, err := qc.rankService.CheckOperationPermissions(ctx, req.UserID, []string{
rank.QuestionAddRank,
rank.QuestionEditRank,
rank.QuestionDeleteRank,
permission.QuestionAdd,
permission.QuestionEdit,
permission.QuestionDelete,
permission.QuestionClose,
permission.QuestionReopen,
}, "")
if err != nil {
handler.HandleResponse(ctx, err, nil)
@ -219,7 +225,8 @@ func (qc *QuestionController) AddQuestion(ctx *gin.Context) {
req.CanAdd = canList[0]
req.CanEdit = canList[1]
req.CanDelete = canList[2]
req.CanClose = middleware.GetIsAdminFromContext(ctx)
req.CanClose = canList[3]
req.CanReopen = canList[4]
if !req.CanAdd {
handler.HandleResponse(ctx, errors.Forbidden(reason.RankFailToMeetTheCondition), nil)
return
@ -247,9 +254,9 @@ func (qc *QuestionController) UpdateQuestion(ctx *gin.Context) {
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
canList, err := qc.rankService.CheckOperationPermissions(ctx, req.UserID, []string{
rank.QuestionEditRank,
rank.QuestionDeleteRank,
rank.QuestionEditWithoutReviewRank,
permission.QuestionEdit,
permission.QuestionDelete,
permission.QuestionEditWithoutReview,
}, req.ID)
if err != nil {
handler.HandleResponse(ctx, err, nil)

View File

@ -5,6 +5,7 @@ import (
"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/permission"
"github.com/answerdev/answer/internal/service/rank"
"github.com/answerdev/answer/internal/service/report"
"github.com/gin-gonic/gin"
@ -40,7 +41,7 @@ func (rc *ReportController) AddReport(ctx *gin.Context) {
}
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
can, err := rc.rankService.CheckOperationPermission(ctx, req.UserID, rank.ReportAddRank, "")
can, err := rc.rankService.CheckOperationPermission(ctx, req.UserID, permission.ReportAdd, "")
if err != nil {
handler.HandleResponse(ctx, err, nil)
return

View File

@ -7,6 +7,7 @@ import (
"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/permission"
"github.com/answerdev/answer/internal/service/rank"
"github.com/answerdev/answer/pkg/obj"
"github.com/gin-gonic/gin"
@ -70,9 +71,9 @@ func (rc *RevisionController) GetUnreviewedRevisionList(ctx *gin.Context) {
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
canList, err := rc.rankService.CheckOperationPermissions(ctx, req.UserID, []string{
rank.QuestionAuditRank,
rank.AnswerAuditRank,
rank.TagAuditRank,
permission.QuestionAudit,
permission.AnswerAudit,
permission.TagAudit,
}, "")
if err != nil {
handler.HandleResponse(ctx, err, nil)
@ -102,9 +103,9 @@ func (rc *RevisionController) RevisionAudit(ctx *gin.Context) {
}
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
canList, err := rc.rankService.CheckOperationPermissions(ctx, req.UserID, []string{
rank.QuestionAuditRank,
rank.AnswerAuditRank,
rank.TagAuditRank,
permission.QuestionAudit,
permission.AnswerAudit,
permission.TagAudit,
}, "")
if err != nil {
handler.HandleResponse(ctx, err, nil)
@ -139,11 +140,11 @@ func (rc *RevisionController) CheckCanUpdateRevision(ctx *gin.Context) {
objectTypeStr, _ := obj.GetObjectTypeStrByObjectID(req.ID)
switch objectTypeStr {
case constant.QuestionObjectType:
action = rank.QuestionEditRank
action = permission.QuestionEdit
case constant.AnswerObjectType:
action = rank.AnswerEditRank
action = permission.AnswerEdit
case constant.TagObjectType:
action = rank.TagEditRank
action = permission.TagEdit
default:
handler.HandleResponse(ctx, errors.BadRequest(reason.ObjectNotFound), nil)
return

View File

@ -5,6 +5,7 @@ import (
"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/permission"
"github.com/answerdev/answer/internal/service/rank"
"github.com/answerdev/answer/internal/service/tag"
"github.com/answerdev/answer/internal/service/tag_common"
@ -63,7 +64,7 @@ func (tc *TagController) RemoveTag(ctx *gin.Context) {
}
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
can, err := tc.rankService.CheckOperationPermission(ctx, req.UserID, rank.TagDeleteRank, "")
can, err := tc.rankService.CheckOperationPermission(ctx, req.UserID, permission.TagDelete, "")
if err != nil {
handler.HandleResponse(ctx, err, nil)
return
@ -94,8 +95,8 @@ func (tc *TagController) UpdateTag(ctx *gin.Context) {
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
canList, err := tc.rankService.CheckOperationPermissions(ctx, req.UserID, []string{
rank.TagEditRank,
rank.TagEditWithoutReviewRank,
permission.TagEdit,
permission.TagEditWithoutReview,
}, "")
if err != nil {
handler.HandleResponse(ctx, err, nil)
@ -133,8 +134,8 @@ func (tc *TagController) GetTagInfo(ctx *gin.Context) {
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
canList, err := tc.rankService.CheckOperationPermissions(ctx, req.UserID, []string{
rank.TagEditRank,
rank.TagDeleteRank,
permission.TagEdit,
permission.TagDelete,
}, "")
if err != nil {
handler.HandleResponse(ctx, err, nil)
@ -200,7 +201,7 @@ func (tc *TagController) GetTagSynonyms(ctx *gin.Context) {
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
canList, err := tc.rankService.CheckOperationPermissions(ctx, req.UserID, []string{
rank.TagSynonymRank,
permission.TagSynonym,
}, "")
if err != nil {
handler.HandleResponse(ctx, err, nil)
@ -228,7 +229,7 @@ func (tc *TagController) UpdateTagSynonym(ctx *gin.Context) {
}
req.UserID = middleware.GetLoginUserIDFromContext(ctx)
can, err := tc.rankService.CheckOperationPermission(ctx, req.UserID, rank.TagSynonymRank, "")
can, err := tc.rankService.CheckOperationPermission(ctx, req.UserID, permission.TagSynonym, "")
if err != nil {
handler.HandleResponse(ctx, err, nil)
return

View File

@ -44,8 +44,8 @@ type User struct {
Website string `xorm:"not null default '' VARCHAR(255) website"`
Location string `xorm:"not null default '' VARCHAR(100) location"`
IPInfo string `xorm:"not null default '' VARCHAR(255) ip_info"`
IsAdmin bool `xorm:"not null default false BOOL is_admin"`
Language string `xorm:"not null default '' VARCHAR(100) language"`
//IsAdmin bool `xorm:"not null default false BOOL is_admin"`
Language string `xorm:"not null default '' VARCHAR(100) language"`
}
// TableName user table name

View File

@ -70,6 +70,7 @@ func InitDB(dataConf *data.Database) (err error) {
func initAdminUser(engine *xorm.Engine) error {
_, err := engine.InsertOne(&entity.User{
ID: "1",
Username: "admin",
Pass: "$2a$10$.gnUnpW.8ssRNaEvx.XwvOR2NuPsGzFLWWX2rqSIVAdIvLNZZYs5y", // admin
EMail: "admin@admin.com",
@ -78,7 +79,13 @@ func initAdminUser(engine *xorm.Engine) error {
Status: 1,
Rank: 1,
DisplayName: "admin",
IsAdmin: true,
})
if err != nil {
return err
}
_, err = engine.InsertOne(&entity.UserRoleRel{
UserID: "1",
RoleID: 2,
})
return err
}

View File

@ -45,6 +45,7 @@ var migrations = []Migration{
NewMigration("add user language", addUserLanguage),
NewMigration("add recommend and reserved tag fields", addTagRecommendedAndReserved),
NewMigration("add activity timeline", addActivityTimeline),
NewMigration("add user role", addRoleFeatures),
}
// GetCurrentDBVersion returns the current db version

View File

@ -98,5 +98,14 @@ func addActivityTimeline(x *xorm.Engine) error {
type Tag struct {
UserID string `xorm:"not null default 0 BIGINT(20) user_id"`
}
return x.Sync(new(Activity), new(Revision), new(Tag))
type Question struct {
UpdatedAt time.Time `xorm:"updated_at TIMESTAMP"`
LastEditUserID string `xorm:"not null default 0 BIGINT(20) last_edit_user_id"`
PostUpdateTime time.Time `xorm:"post_update_time TIMESTAMP"`
}
type Answer struct {
UpdatedAt time.Time `xorm:"updated_at TIMESTAMP"`
LastEditUserID string `xorm:"not null default 0 BIGINT(20) last_edit_user_id"`
}
return x.Sync(new(Activity), new(Revision), new(Tag), new(Question), new(Answer))
}

View File

@ -40,7 +40,7 @@ func addRoleFeatures(x *xorm.Engine) error {
{ID: 4, Name: "question edit without review", PowerType: permission.QuestionEditWithoutReview, Description: "question edit without review"},
{ID: 5, Name: "question delete", PowerType: permission.QuestionDelete, Description: "question delete"},
{ID: 6, Name: "question close", PowerType: permission.QuestionClose, Description: "question close"},
{ID: 7, Name: "question open", PowerType: permission.QuestionOpen, Description: "question open"},
{ID: 7, Name: "question reopen", PowerType: permission.QuestionReopen, Description: "question reopen"},
{ID: 8, Name: "question vote up", PowerType: permission.QuestionVoteUp, Description: "question vote up"},
{ID: 9, Name: "question vote down", PowerType: permission.QuestionVoteDown, Description: "question vote down"},
{ID: 10, Name: "answer add", PowerType: permission.AnswerAdd, Description: "answer add"},
@ -70,14 +70,15 @@ func addRoleFeatures(x *xorm.Engine) error {
}
// insert default powers
for _, power := range powers {
exist, err := x.Get(&entity.Power{Name: power.Name})
exist, err := x.Get(&entity.Power{ID: power.ID})
if err != nil {
return err
}
if exist {
continue
_, err = x.ID(power.ID).Update(&power)
} else {
_, err = x.Insert(power)
}
_, err = x.Insert(power)
if err != nil {
return err
}
@ -90,7 +91,7 @@ func addRoleFeatures(x *xorm.Engine) error {
{RoleID: 2, PowerType: permission.QuestionEditWithoutReview},
{RoleID: 2, PowerType: permission.QuestionDelete},
{RoleID: 2, PowerType: permission.QuestionClose},
{RoleID: 2, PowerType: permission.QuestionOpen},
{RoleID: 2, PowerType: permission.QuestionReopen},
{RoleID: 2, PowerType: permission.QuestionVoteUp},
{RoleID: 2, PowerType: permission.QuestionVoteDown},
{RoleID: 2, PowerType: permission.AnswerAdd},
@ -123,7 +124,7 @@ func addRoleFeatures(x *xorm.Engine) error {
{RoleID: 3, PowerType: permission.QuestionEditWithoutReview},
{RoleID: 3, PowerType: permission.QuestionDelete},
{RoleID: 3, PowerType: permission.QuestionClose},
{RoleID: 3, PowerType: permission.QuestionOpen},
{RoleID: 3, PowerType: permission.QuestionReopen},
{RoleID: 3, PowerType: permission.QuestionVoteUp},
{RoleID: 3, PowerType: permission.QuestionVoteDown},
{RoleID: 3, PowerType: permission.AnswerAdd},

View File

@ -25,7 +25,8 @@ func NewRolePowerRelRepo(data *data.Data) role.RolePowerRelRepo {
// GetRolePowerTypeList get role power type list
func (rr *rolePowerRelRepo) GetRolePowerTypeList(ctx context.Context, roleID int) (powers []string, err error) {
powers = make([]string, 0)
err = rr.data.DB.Cols("power_type").Where(builder.Eq{"role_id": roleID}).Find(&powers)
err = rr.data.DB.Table("role_power_rel").
Cols("power_type").Where(builder.Eq{"role_id": roleID}).Find(&powers)
if err != nil {
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}

View File

@ -8,6 +8,7 @@ import (
"github.com/answerdev/answer/internal/entity"
"github.com/answerdev/answer/internal/service/role"
"github.com/segmentfault/pacman/errors"
"xorm.io/builder"
"xorm.io/xorm"
)
@ -33,7 +34,7 @@ func (ur *userRoleRelRepo) SaveUserRoleRel(ctx context.Context, userID string, r
}
if exist {
item.RoleID = roleID
_, err = ur.data.DB.Update(item)
_, err = ur.data.DB.ID(item.ID).Update(item)
} else {
_, err = ur.data.DB.Insert(&entity.UserRoleRel{UserID: userID, RoleID: roleID})
}
@ -61,9 +62,9 @@ func (ur *userRoleRelRepo) GetUserRoleRelList(ctx context.Context, userIDs []str
// GetUserRoleRel get user role
func (ur *userRoleRelRepo) GetUserRoleRel(ctx context.Context, userID string) (
rolePowerRel *entity.RolePowerRel, exist bool, err error) {
rolePowerRel = &entity.RolePowerRel{}
exist, err = ur.data.DB.Where("user_id", userID).Get(rolePowerRel)
rolePowerRel *entity.UserRoleRel, exist bool, err error) {
rolePowerRel = &entity.UserRoleRel{}
exist, err = ur.data.DB.Where(builder.Eq{"user_id": userID}).Get(rolePowerRel)
if err != nil {
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}

View File

@ -44,6 +44,8 @@ type QuestionPermission struct {
CanDelete bool `json:"-"`
// whether user can close it
CanClose bool `json:"-"`
// whether user can reopen it
CanReopen bool `json:"-"`
}
type CheckCanQuestionUpdate struct {

View File

@ -7,7 +7,7 @@ const (
QuestionEditWithoutReview = "question.edit_without_review"
QuestionDelete = "question.delete"
QuestionClose = "question.close"
QuestionOpen = "question.open"
QuestionReopen = "question.reopen"
QuestionVoteUp = "question.vote_up"
QuestionVoteDown = "question.vote_down"
AnswerAdd = "answer.add"

View File

@ -7,7 +7,8 @@ import (
)
// GetQuestionPermission get question permission
func GetQuestionPermission(ctx context.Context, userID string, creatorUserID string, canEdit, canDelete, canClose bool) (
func GetQuestionPermission(ctx context.Context, userID string, creatorUserID string,
canEdit, canDelete, canClose, canReopen bool) (
actions []*schema.PermissionMemberAction) {
actions = make([]*schema.PermissionMemberAction, 0)
if len(userID) > 0 {
@ -31,6 +32,13 @@ func GetQuestionPermission(ctx context.Context, userID string, creatorUserID str
Type: "confirm",
})
}
if canReopen {
actions = append(actions, &schema.PermissionMemberAction{
Action: "reopen",
Name: "Reopen",
Type: "confirm",
})
}
if canDelete || userID == creatorUserID {
actions = append(actions, &schema.PermissionMemberAction{
Action: "delete",

View File

@ -429,7 +429,7 @@ func (qs *QuestionService) GetQuestion(ctx context.Context, questionID, userID s
return
}
question.MemberActions = permission.GetQuestionPermission(ctx, userID, question.UserID,
per.CanEdit, per.CanDelete, per.CanClose)
per.CanEdit, per.CanDelete, per.CanClose, per.CanReopen)
return question, nil
}

View File

@ -2,7 +2,6 @@ package rank
import (
"context"
"strings"
"github.com/answerdev/answer/internal/base/constant"
"github.com/answerdev/answer/internal/base/pager"
@ -12,6 +11,7 @@ import (
"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/permission"
"github.com/answerdev/answer/internal/service/role"
usercommon "github.com/answerdev/answer/internal/service/user_common"
"github.com/segmentfault/pacman/errors"
@ -20,35 +20,7 @@ import (
)
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"
PermissionPrefix = "rank."
)
type UserRankRepo interface {
@ -100,9 +72,7 @@ func (rs *RankService) CheckOperationPermission(ctx context.Context, userID stri
return false, nil
}
powerMapping := rs.getUserPowerMapping(ctx, userID)
// TODO: remove
act := strings.TrimPrefix(action, "rank.")
if powerMapping[act] {
if powerMapping[action] {
return true, nil
}
@ -118,7 +88,7 @@ func (rs *RankService) CheckOperationPermission(ctx context.Context, userID stri
}
}
return rs.checkUserRank(ctx, userInfo.ID, userInfo.Rank, action)
return rs.checkUserRank(ctx, userInfo.ID, userInfo.Rank, PermissionPrefix+action)
}
// CheckOperationPermissions verify that the user has permission
@ -154,13 +124,11 @@ func (rs *RankService) CheckOperationPermissions(ctx context.Context, userID str
powerMapping := rs.getUserPowerMapping(ctx, userID)
for idx, action := range actions {
// TODO: remove
act := strings.TrimPrefix(action, "rank.")
if powerMapping[act] || objectOwner {
if powerMapping[action] || objectOwner {
can[idx] = true
continue
}
meetRank, err := rs.checkUserRank(ctx, userInfo.ID, userInfo.Rank, action)
meetRank, err := rs.checkUserRank(ctx, userInfo.ID, userInfo.Rank, PermissionPrefix+action)
if err != nil {
log.Error(err)
}
@ -194,24 +162,24 @@ func (rs *RankService) CheckVotePermission(ctx context.Context, userID, objectID
switch objectInfo.ObjectType {
case constant.QuestionObjectType:
if voteUp {
action = QuestionVoteUpRank
action = permission.QuestionVoteUp
} else {
action = QuestionVoteDownRank
action = permission.QuestionVoteDown
}
case constant.AnswerObjectType:
if voteUp {
action = AnswerVoteUpRank
action = permission.AnswerVoteUp
} else {
action = AnswerVoteDownRank
action = permission.AnswerVoteDown
}
case constant.CommentObjectType:
if voteUp {
action = CommentVoteUpRank
action = permission.CommentVoteUp
} else {
action = CommentVoteDownRank
action = permission.CommentVoteDown
}
}
meetRank, err := rs.checkUserRank(ctx, userInfo.ID, userInfo.Rank, action)
meetRank, err := rs.checkUserRank(ctx, userInfo.ID, userInfo.Rank, PermissionPrefix+action)
if err != nil {
log.Error(err)
}

View File

@ -15,6 +15,10 @@ const (
// the current role information is translated directly.
// Later on, when the relevant ability is available, it can be adjusted by the user himself.
RoleUserID = 1
RoleAdminID = 2
RoleModeratorID = 3
roleUserName = "User"
roleAdminName = "Admin"
roleModeratorName = "Moderator"

View File

@ -10,7 +10,7 @@ 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)
GetUserRoleRel(ctx context.Context, userID string) (rolePowerRel *entity.RolePowerRel, exist bool, err error)
GetUserRoleRel(ctx context.Context, userID string) (rolePowerRel *entity.UserRoleRel, exist bool, err error)
}
// UserRoleRelService user service
@ -87,7 +87,7 @@ func (us *UserRoleRelService) GetUserRole(ctx context.Context, userID string) (r
if err != nil {
return 0, err
}
if exist {
if !exist {
// set default role
return 1, nil
}

View File

@ -78,8 +78,7 @@ func (us *UserBackyardService) UpdateUserStatus(ctx context.Context, req *schema
func (us *UserBackyardService) UpdateUserRole(ctx context.Context, req *schema.UpdateUserRoleReq) (err error) {
// Users cannot modify their roles
if req.UserID == req.LoginUserID {
// TODO update user role error
return errors.BadRequest(reason.UnknownError)
return errors.BadRequest(reason.UserCannotUpdateYourRole)
}
return us.userRoleRelService.SaveUserRole(ctx, req.UserID, req.RoleID)
}

View File

@ -18,6 +18,7 @@ import (
"github.com/answerdev/answer/internal/service/activity"
"github.com/answerdev/answer/internal/service/auth"
"github.com/answerdev/answer/internal/service/export"
"github.com/answerdev/answer/internal/service/role"
"github.com/answerdev/answer/internal/service/service_config"
"github.com/answerdev/answer/internal/service/siteinfo_common"
usercommon "github.com/answerdev/answer/internal/service/user_common"
@ -38,6 +39,7 @@ type UserService struct {
emailService *export.EmailService
authService *auth.AuthService
siteInfoService *siteinfo_common.SiteInfoCommonService
userRoleService *role.UserRoleRelService
}
func NewUserService(userRepo usercommon.UserRepo,
@ -46,6 +48,7 @@ func NewUserService(userRepo usercommon.UserRepo,
authService *auth.AuthService,
serviceConfig *service_config.ServiceConfig,
siteInfoService *siteinfo_common.SiteInfoCommonService,
userRoleService *role.UserRoleRelService,
) *UserService {
return &UserService{
userRepo: userRepo,
@ -54,6 +57,7 @@ func NewUserService(userRepo usercommon.UserRepo,
serviceConfig: serviceConfig,
authService: authService,
siteInfoService: siteInfoService,
userRoleService: userRoleService,
}
}
@ -66,9 +70,14 @@ func (us *UserService) GetUserInfoByUserID(ctx context.Context, token, userID st
if !exist {
return nil, errors.BadRequest(reason.UserNotFound)
}
roleID, err := us.userRoleService.GetUserRole(ctx, userInfo.ID)
if err != nil {
log.Error(err)
}
resp = &schema.GetUserToSetShowResp{}
resp.GetFromUserEntity(userInfo)
resp.AccessToken = token
resp.IsAdmin = roleID == role.RoleAdminID
return resp, nil
}
@ -107,19 +116,24 @@ func (us *UserService) EmailLogin(ctx context.Context, req *schema.UserEmailLogi
log.Error("UpdateLastLoginDate", err.Error())
}
roleID, err := us.userRoleService.GetUserRole(ctx, userInfo.ID)
if err != nil {
log.Error(err)
}
resp = &schema.GetUserResp{}
resp.GetFromUserEntity(userInfo)
userCacheInfo := &entity.UserCacheInfo{
UserID: userInfo.ID,
EmailStatus: userInfo.MailStatus,
UserStatus: userInfo.Status,
IsAdmin: userInfo.IsAdmin,
IsAdmin: roleID == role.RoleAdminID,
}
resp.AccessToken, err = us.authService.SetUserCacheInfo(ctx, userCacheInfo)
if err != nil {
return nil, err
}
resp.IsAdmin = userInfo.IsAdmin
resp.IsAdmin = userCacheInfo.IsAdmin
if resp.IsAdmin {
err = us.authService.SetCmsUserCacheInfo(ctx, resp.AccessToken, userCacheInfo)
if err != nil {
@ -317,6 +331,11 @@ func (us *UserService) UserRegisterByEmail(ctx context.Context, registerUserInfo
}
go us.emailService.Send(ctx, userInfo.EMail, title, body, code, data.ToJSONString())
roleID, err := us.userRoleService.GetUserRole(ctx, userInfo.ID)
if err != nil {
log.Error(err)
}
// return user info and token
resp = &schema.GetUserResp{}
resp.GetFromUserEntity(userInfo)
@ -324,13 +343,13 @@ func (us *UserService) UserRegisterByEmail(ctx context.Context, registerUserInfo
UserID: userInfo.ID,
EmailStatus: userInfo.MailStatus,
UserStatus: userInfo.Status,
IsAdmin: userInfo.IsAdmin,
IsAdmin: roleID == role.RoleAdminID,
}
resp.AccessToken, err = us.authService.SetUserCacheInfo(ctx, userCacheInfo)
if err != nil {
return nil, err
}
resp.IsAdmin = userInfo.IsAdmin
resp.IsAdmin = userCacheInfo.IsAdmin
if resp.IsAdmin {
err = us.authService.SetCmsUserCacheInfo(ctx, resp.AccessToken, &entity.UserCacheInfo{UserID: userInfo.ID})
if err != nil {
@ -405,13 +424,18 @@ func (us *UserService) UserVerifyEmail(ctx context.Context, req *schema.UserVeri
log.Error(err)
}
roleID, err := us.userRoleService.GetUserRole(ctx, userInfo.ID)
if err != nil {
log.Error(err)
}
resp = &schema.GetUserResp{}
resp.GetFromUserEntity(userInfo)
userCacheInfo := &entity.UserCacheInfo{
UserID: userInfo.ID,
EmailStatus: userInfo.MailStatus,
UserStatus: userInfo.Status,
IsAdmin: userInfo.IsAdmin,
IsAdmin: roleID == role.RoleAdminID,
}
resp.AccessToken, err = us.authService.SetUserCacheInfo(ctx, userCacheInfo)
if err != nil {
@ -421,7 +445,7 @@ func (us *UserService) UserVerifyEmail(ctx context.Context, req *schema.UserVeri
if err = us.authService.SetUserStatus(ctx, userCacheInfo); err != nil {
return nil, err
}
resp.IsAdmin = userInfo.IsAdmin
resp.IsAdmin = userCacheInfo.IsAdmin
if resp.IsAdmin {
err = us.authService.SetCmsUserCacheInfo(ctx, resp.AccessToken, &entity.UserCacheInfo{UserID: userInfo.ID})
if err != nil {