mirror of https://gitee.com/answerdev/answer.git
feat(permission): add privileges API
This commit is contained in:
parent
1c235dbd9b
commit
4cfa0cd8fe
|
@ -65,6 +65,7 @@ const (
|
|||
SiteTypeLogin = "login"
|
||||
SiteTypeCustomCssHTML = "css-html"
|
||||
SiteTypeTheme = "theme"
|
||||
SiteTypePrivileges = "privileges"
|
||||
)
|
||||
|
||||
func ExistInPathIgnore(name string) bool {
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
package constant
|
||||
|
||||
type Privilege struct {
|
||||
Label string `json:"label"`
|
||||
Value int `json:"value"`
|
||||
Key string `json:"-"`
|
||||
}
|
||||
|
||||
const (
|
||||
RankQuestionAddKey = "rank.question.add"
|
||||
RankQuestionEditKey = "rank.question.edit"
|
||||
|
@ -35,39 +41,80 @@ const (
|
|||
RankTagUseReservedTagKey = "rank.tag.use_reserved_tag"
|
||||
)
|
||||
|
||||
//| Permission | Level 1 | Level 2 | Level 3 | Custom Level |
|
||||
//| -------------------------------------- | ------------------------------------------------ | --------------------------------------------- | --------------------------------------------- | ------------ |
|
||||
//| Description | less reputation required for private team, group | low reputation required for startup community | high reputation required for mature community | |
|
||||
//| Ask question | 1 | 1 | 1 | |
|
||||
//| Write answer | 1 | 1 | 1 | |
|
||||
//| Write comment | 1 | 1 | 1 | |
|
||||
//| Accept answer | 1 | 1 | 1 | |
|
||||
//| Flag | 1 | 1 | 1 | |
|
||||
//| Upvote comment | 1 | 1 | 1 | |
|
||||
//| Post more than 2 links at a time | 1 | 10 | 10 | |
|
||||
//| Upvote question | 1 | 1 | 15 | |
|
||||
//| Upvote answer | 1 | 1 | 15 | |
|
||||
//| Downvote question | 125 | 125 | 125 | |
|
||||
//| Downvote answer | 125 | 125 | 125 | |
|
||||
//| Create new tag | 1 | 750 | 1500 | |
|
||||
//| Edit tag description (need to review) | 1 | 50 | 100 | |
|
||||
//| Edit other's question (need to review) | 1 | 100 | 200 | |
|
||||
//| Edit other's answer (need to review) | 1 | 100 | 200 | |
|
||||
//| Edit other's question without review | 1 | 1000 | 2000 | |
|
||||
//| Edit other's answer without review | 1 | 1000 | 2000 | |
|
||||
//| Revew question edits | 1 | 1000 | 2000 | |
|
||||
//| Review answer edits | 1 | 1000 | 2000 | |
|
||||
//| Review tag edits | 1 | 2500 | 5000 | |
|
||||
//| Edit tag description without review | 1 | 10000 | 20000 | |
|
||||
//| Manage tag synonyms | 1 | 10000 | 20000 | |
|
||||
|
||||
const (
|
||||
RankQuestionAddLabel = "Ask question"
|
||||
RankAnswerAddLabel = "Write answer"
|
||||
RankCommentAddLabel = "Write comment"
|
||||
RankAnswerAcceptLabel = "Accept answer"
|
||||
RankReportAddLabel = "Flag"
|
||||
RankCommentVoteUpLabel = "Upvote comment"
|
||||
RankLinkUrlLimitLabel = "Post more than 2 links at a time"
|
||||
RankQuestionVoteUpLabel = "Upvote question"
|
||||
RankAnswerVoteUpLabel = "Upvote answer"
|
||||
RankQuestionVoteDownLabel = "Downvote question"
|
||||
RankAnswerVoteDownLabel = "Downvote answer"
|
||||
RankTagAddLabel = "Create new tag"
|
||||
RankTagEditLabel = "Edit tag description (need to review)"
|
||||
RankQuestionEditLabel = "Edit other's question (need to review)"
|
||||
RankAnswerEditLabel = "Edit other's answer (need to review)"
|
||||
RankQuestionEditWithoutReviewLabel = "Edit other's question without review"
|
||||
RankAnswerEditWithoutReviewLabel = "Edit other's answer without review"
|
||||
RankQuestionAuditLabel = "Review question edits"
|
||||
RankAnswerAuditLabel = "Review answer edits"
|
||||
RankTagAuditLabel = "Review tag edits"
|
||||
RankTagEditWithoutReviewLabel = "Edit tag description without review"
|
||||
RankTagSynonymLabel = "Manage tag synonyms"
|
||||
)
|
||||
|
||||
var (
|
||||
RankAllKeys = []string{
|
||||
RankQuestionAddKey,
|
||||
RankQuestionEditKey,
|
||||
RankQuestionDeleteKey,
|
||||
RankQuestionVoteUpKey,
|
||||
RankQuestionVoteDownKey,
|
||||
RankAnswerAddKey,
|
||||
RankAnswerEditKey,
|
||||
RankAnswerDeleteKey,
|
||||
RankAnswerAcceptKey,
|
||||
RankAnswerVoteUpKey,
|
||||
RankAnswerVoteDownKey,
|
||||
RankCommentAddKey,
|
||||
RankCommentEditKey,
|
||||
RankCommentDeleteKey,
|
||||
RankReportAddKey,
|
||||
RankTagAddKey,
|
||||
RankTagEditKey,
|
||||
RankTagDeleteKey,
|
||||
RankTagSynonymKey,
|
||||
RankLinkUrlLimitKey,
|
||||
RankVoteDetailKey,
|
||||
RankCommentVoteUpKey,
|
||||
RankCommentVoteDownKey,
|
||||
RankQuestionEditWithoutReviewKey,
|
||||
RankAnswerEditWithoutReviewKey,
|
||||
RankTagEditWithoutReviewKey,
|
||||
RankAnswerAuditKey,
|
||||
RankQuestionAuditKey,
|
||||
RankTagAuditKey,
|
||||
RankQuestionCloseKey,
|
||||
RankQuestionReopenKey,
|
||||
RankTagUseReservedTagKey,
|
||||
RankAllPrivileges = []*Privilege{
|
||||
{Label: RankQuestionAddLabel, Key: RankQuestionAddKey},
|
||||
{Label: RankAnswerAddLabel, Key: RankAnswerAddKey},
|
||||
{Label: RankCommentAddLabel, Key: RankCommentAddKey},
|
||||
{Label: RankAnswerAcceptLabel, Key: RankAnswerAcceptKey},
|
||||
{Label: RankReportAddLabel, Key: RankReportAddKey},
|
||||
{Label: RankCommentVoteUpLabel, Key: RankCommentVoteUpKey},
|
||||
{Label: RankLinkUrlLimitLabel, Key: RankLinkUrlLimitKey},
|
||||
{Label: RankQuestionVoteUpLabel, Key: RankQuestionVoteUpKey},
|
||||
{Label: RankAnswerVoteUpLabel, Key: RankAnswerVoteUpKey},
|
||||
{Label: RankQuestionVoteDownLabel, Key: RankQuestionVoteDownKey},
|
||||
{Label: RankAnswerVoteDownLabel, Key: RankAnswerVoteDownKey},
|
||||
{Label: RankTagAddLabel, Key: RankTagAddKey},
|
||||
{Label: RankTagEditLabel, Key: RankTagEditKey},
|
||||
{Label: RankQuestionEditLabel, Key: RankQuestionEditKey},
|
||||
{Label: RankAnswerEditLabel, Key: RankAnswerEditKey},
|
||||
{Label: RankQuestionEditWithoutReviewLabel, Key: RankQuestionEditWithoutReviewKey},
|
||||
{Label: RankAnswerEditWithoutReviewLabel, Key: RankAnswerEditWithoutReviewKey},
|
||||
{Label: RankQuestionAuditLabel, Key: RankQuestionAuditKey},
|
||||
{Label: RankAnswerAuditLabel, Key: RankAnswerAuditKey},
|
||||
{Label: RankTagAuditLabel, Key: RankTagAuditKey},
|
||||
{Label: RankTagEditWithoutReviewLabel, Key: RankTagEditWithoutReviewKey},
|
||||
{Label: RankTagSynonymLabel, Key: RankTagSynonymKey},
|
||||
}
|
||||
)
|
||||
|
|
|
@ -386,9 +386,9 @@ func (sc *SiteInfoController) GetPrivilegesConfig(ctx *gin.Context) {
|
|||
// @Security ApiKeyAuth
|
||||
// @Tags admin
|
||||
// @Produce json
|
||||
// @Param data body schema.UpdatePrivilegesConfigReq true "smtp config"
|
||||
// @Param data body schema.UpdatePrivilegesConfigReq true "config"
|
||||
// @Success 200 {object} handler.RespBody{}
|
||||
// @Router /answer/admin/api/setting/smtp [put]
|
||||
// @Router /answer/admin/api/setting/privileges [put]
|
||||
func (sc *SiteInfoController) UpdatePrivilegesConfig(ctx *gin.Context) {
|
||||
req := &schema.UpdatePrivilegesConfigReq{}
|
||||
if handler.BindAndCheck(ctx, req) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"net/mail"
|
||||
"net/url"
|
||||
|
||||
"github.com/answerdev/answer/internal/base/constant"
|
||||
"github.com/answerdev/answer/internal/base/handler"
|
||||
"github.com/answerdev/answer/internal/base/reason"
|
||||
"github.com/answerdev/answer/internal/base/translator"
|
||||
|
@ -234,12 +235,78 @@ type GetManifestJsonResp struct {
|
|||
BackgroundColor string `json:"background_color"`
|
||||
}
|
||||
|
||||
// GetPrivilegesConfigResp
|
||||
const (
|
||||
// PrivilegeLevel1 low
|
||||
PrivilegeLevel1 PrivilegeLevel = 1
|
||||
// PrivilegeLevel2 medium
|
||||
PrivilegeLevel2 PrivilegeLevel = 2
|
||||
// PrivilegeLevel3 high
|
||||
PrivilegeLevel3 PrivilegeLevel = 3
|
||||
)
|
||||
|
||||
type PrivilegeLevel int
|
||||
|
||||
// GetPrivilegesConfigResp get privileges config response
|
||||
type GetPrivilegesConfigResp struct {
|
||||
Privileges map[string]int `json:"privileges"`
|
||||
Options []*PrivilegeOption `json:"options"`
|
||||
SelectedLevel PrivilegeLevel `json:"selected_level"`
|
||||
}
|
||||
|
||||
// UpdatePrivilegesConfigReq
|
||||
type UpdatePrivilegesConfigReq struct {
|
||||
Privileges map[string]int `json:"privileges"`
|
||||
// PrivilegeOption privilege option
|
||||
type PrivilegeOption struct {
|
||||
Level PrivilegeLevel `json:"level"`
|
||||
Privileges []*constant.Privilege `json:"privileges"`
|
||||
}
|
||||
|
||||
// UpdatePrivilegesConfigReq update privileges config request
|
||||
type UpdatePrivilegesConfigReq struct {
|
||||
Level PrivilegeLevel `validate:"required,min=1,max=3" json:"level"`
|
||||
}
|
||||
|
||||
var (
|
||||
DefaultPrivilegeOptions []*PrivilegeOption
|
||||
privilegeOptionsLevelMapping = map[string][]int{
|
||||
constant.RankQuestionAddKey: {1, 1, 1},
|
||||
constant.RankAnswerAddKey: {1, 1, 1},
|
||||
constant.RankCommentAddKey: {1, 1, 1},
|
||||
constant.RankAnswerAcceptKey: {1, 1, 1},
|
||||
constant.RankReportAddKey: {1, 1, 1},
|
||||
constant.RankCommentVoteUpKey: {1, 1, 1},
|
||||
constant.RankLinkUrlLimitKey: {1, 10, 10},
|
||||
constant.RankQuestionVoteUpKey: {1, 1, 15},
|
||||
constant.RankAnswerVoteUpKey: {1, 1, 15},
|
||||
constant.RankQuestionVoteDownKey: {125, 125, 125},
|
||||
constant.RankAnswerVoteDownKey: {125, 125, 125},
|
||||
constant.RankTagAddKey: {1, 750, 1500},
|
||||
constant.RankTagEditKey: {1, 50, 100},
|
||||
constant.RankQuestionEditKey: {1, 100, 200},
|
||||
constant.RankAnswerEditKey: {1, 100, 200},
|
||||
constant.RankQuestionEditWithoutReviewKey: {1, 1000, 2000},
|
||||
constant.RankAnswerEditWithoutReviewKey: {1, 1000, 2000},
|
||||
constant.RankQuestionAuditKey: {1, 1000, 2000},
|
||||
constant.RankAnswerAuditKey: {1, 1000, 2000},
|
||||
constant.RankTagAuditKey: {1, 2500, 5000},
|
||||
constant.RankTagEditWithoutReviewKey: {1, 10000, 20000},
|
||||
constant.RankTagSynonymKey: {1, 10000, 20000},
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
for _, option := range []PrivilegeLevel{PrivilegeLevel1, PrivilegeLevel2, PrivilegeLevel3} {
|
||||
op := &PrivilegeOption{
|
||||
Level: option,
|
||||
}
|
||||
for _, privilege := range constant.RankAllPrivileges {
|
||||
if len(privilegeOptionsLevelMapping[privilege.Key]) == 0 {
|
||||
fmt.Println("privilege key not found: ", privilege.Key)
|
||||
continue
|
||||
}
|
||||
op.Privileges = append(op.Privileges, &constant.Privilege{
|
||||
Label: privilege.Label,
|
||||
Value: privilegeOptionsLevelMapping[privilege.Key][option-1],
|
||||
Key: privilege.Key,
|
||||
})
|
||||
}
|
||||
DefaultPrivilegeOptions = append(DefaultPrivilegeOptions, op)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -308,25 +308,49 @@ func (s *SiteInfoService) SaveSeo(ctx context.Context, req schema.SiteSeoReq) (e
|
|||
}
|
||||
|
||||
func (s *SiteInfoService) GetPrivilegesConfig(ctx context.Context) (resp *schema.GetPrivilegesConfigResp, err error) {
|
||||
privilege := &schema.UpdatePrivilegesConfigReq{}
|
||||
if err = s.siteInfoCommonService.GetSiteInfoByType(ctx, constant.SiteTypePrivileges, privilege); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp = &schema.GetPrivilegesConfigResp{
|
||||
Privileges: make(map[string]int, 0),
|
||||
Options: schema.DefaultPrivilegeOptions,
|
||||
SelectedLevel: schema.PrivilegeLevel2,
|
||||
}
|
||||
for _, key := range constant.RankAllKeys {
|
||||
v, err := s.configRepo.GetInt(key)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
continue
|
||||
}
|
||||
resp.Privileges[key] = v
|
||||
if privilege != nil && privilege.Level > 0 {
|
||||
resp.SelectedLevel = privilege.Level
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *SiteInfoService) UpdatePrivilegesConfig(ctx context.Context, req *schema.UpdatePrivilegesConfigReq) (err error) {
|
||||
for key, value := range req.Privileges {
|
||||
err = s.configRepo.SetConfig(key, fmt.Sprintf("%d", value))
|
||||
var chooseOption *schema.PrivilegeOption
|
||||
for _, option := range schema.DefaultPrivilegeOptions {
|
||||
if option.Level == req.Level {
|
||||
chooseOption = option
|
||||
break
|
||||
}
|
||||
}
|
||||
if chooseOption == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// update site info that user choose which privilege level
|
||||
content, _ := json.Marshal(req)
|
||||
data := &entity.SiteInfo{
|
||||
Type: constant.SiteTypePrivileges,
|
||||
Content: string(content),
|
||||
Status: 1,
|
||||
}
|
||||
err = s.siteInfoRepo.SaveByType(ctx, constant.SiteTypePrivileges, data)
|
||||
if err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
// update privilege in config
|
||||
for _, privilege := range chooseOption.Privileges {
|
||||
err = s.configRepo.SetConfig(privilege.Key, fmt.Sprintf("%d", privilege.Value))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return
|
||||
|
|
|
@ -43,7 +43,7 @@ func NewSiteInfoCommonService(siteInfoRepo SiteInfoRepo) *SiteInfoCommonService
|
|||
// GetSiteGeneral get site info general
|
||||
func (s *SiteInfoCommonService) GetSiteGeneral(ctx context.Context) (resp *schema.SiteGeneralResp, err error) {
|
||||
resp = &schema.SiteGeneralResp{}
|
||||
if err = s.getSiteInfoByType(ctx, constant.SiteTypeGeneral, resp); err != nil {
|
||||
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeGeneral, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
|
@ -52,7 +52,7 @@ func (s *SiteInfoCommonService) GetSiteGeneral(ctx context.Context) (resp *schem
|
|||
// GetSiteInterface get site info interface
|
||||
func (s *SiteInfoCommonService) GetSiteInterface(ctx context.Context) (resp *schema.SiteInterfaceResp, err error) {
|
||||
resp = &schema.SiteInterfaceResp{}
|
||||
if err = s.getSiteInfoByType(ctx, constant.SiteTypeInterface, resp); err != nil {
|
||||
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeInterface, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
|
@ -61,7 +61,7 @@ func (s *SiteInfoCommonService) GetSiteInterface(ctx context.Context) (resp *sch
|
|||
// GetSiteBranding get site info branding
|
||||
func (s *SiteInfoCommonService) GetSiteBranding(ctx context.Context) (resp *schema.SiteBrandingResp, err error) {
|
||||
resp = &schema.SiteBrandingResp{}
|
||||
if err = s.getSiteInfoByType(ctx, constant.SiteTypeBranding, resp); err != nil {
|
||||
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeBranding, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
|
@ -70,7 +70,7 @@ func (s *SiteInfoCommonService) GetSiteBranding(ctx context.Context) (resp *sche
|
|||
// GetSiteWrite get site info write
|
||||
func (s *SiteInfoCommonService) GetSiteWrite(ctx context.Context) (resp *schema.SiteWriteResp, err error) {
|
||||
resp = &schema.SiteWriteResp{}
|
||||
if err = s.getSiteInfoByType(ctx, constant.SiteTypeWrite, resp); err != nil {
|
||||
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeWrite, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
|
@ -79,7 +79,7 @@ func (s *SiteInfoCommonService) GetSiteWrite(ctx context.Context) (resp *schema.
|
|||
// GetSiteLegal get site info write
|
||||
func (s *SiteInfoCommonService) GetSiteLegal(ctx context.Context) (resp *schema.SiteLegalResp, err error) {
|
||||
resp = &schema.SiteLegalResp{}
|
||||
if err = s.getSiteInfoByType(ctx, constant.SiteTypeLegal, resp); err != nil {
|
||||
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeLegal, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
|
@ -88,7 +88,7 @@ func (s *SiteInfoCommonService) GetSiteLegal(ctx context.Context) (resp *schema.
|
|||
// GetSiteLogin get site login config
|
||||
func (s *SiteInfoCommonService) GetSiteLogin(ctx context.Context) (resp *schema.SiteLoginResp, err error) {
|
||||
resp = &schema.SiteLoginResp{}
|
||||
if err = s.getSiteInfoByType(ctx, constant.SiteTypeLogin, resp); err != nil {
|
||||
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeLogin, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
|
@ -97,7 +97,7 @@ func (s *SiteInfoCommonService) GetSiteLogin(ctx context.Context) (resp *schema.
|
|||
// GetSiteCustomCssHTML get site custom css html config
|
||||
func (s *SiteInfoCommonService) GetSiteCustomCssHTML(ctx context.Context) (resp *schema.SiteCustomCssHTMLResp, err error) {
|
||||
resp = &schema.SiteCustomCssHTMLResp{}
|
||||
if err = s.getSiteInfoByType(ctx, constant.SiteTypeCustomCssHTML, resp); err != nil {
|
||||
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeCustomCssHTML, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
|
@ -108,7 +108,7 @@ func (s *SiteInfoCommonService) GetSiteTheme(ctx context.Context) (resp *schema.
|
|||
resp = &schema.SiteThemeResp{
|
||||
ThemeOptions: schema.GetThemeOptions,
|
||||
}
|
||||
if err = s.getSiteInfoByType(ctx, constant.SiteTypeTheme, resp); err != nil {
|
||||
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeTheme, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.TrTheme(ctx)
|
||||
|
@ -118,13 +118,13 @@ func (s *SiteInfoCommonService) GetSiteTheme(ctx context.Context) (resp *schema.
|
|||
// GetSiteSeo get site seo
|
||||
func (s *SiteInfoCommonService) GetSiteSeo(ctx context.Context) (resp *schema.SiteSeoReq, err error) {
|
||||
resp = &schema.SiteSeoReq{}
|
||||
if err = s.getSiteInfoByType(ctx, constant.SiteTypeSeo, resp); err != nil {
|
||||
if err = s.GetSiteInfoByType(ctx, constant.SiteTypeSeo, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *SiteInfoCommonService) getSiteInfoByType(ctx context.Context, siteType string, resp interface{}) (err error) {
|
||||
func (s *SiteInfoCommonService) GetSiteInfoByType(ctx context.Context, siteType string, resp interface{}) (err error) {
|
||||
siteInfo, exist, err := s.siteInfoRepo.GetByType(ctx, siteType)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
Loading…
Reference in New Issue