feat(user): add role and role power

This commit is contained in:
LinkinStar 2022-11-29 15:10:57 +08:00
parent 661d8a7f8f
commit 6a9408657c
33 changed files with 1258 additions and 48 deletions

View File

@ -31,6 +31,7 @@ import (
"github.com/answerdev/answer/internal/repo/reason"
"github.com/answerdev/answer/internal/repo/report"
"github.com/answerdev/answer/internal/repo/revision"
"github.com/answerdev/answer/internal/repo/role"
"github.com/answerdev/answer/internal/repo/search_common"
"github.com/answerdev/answer/internal/repo/site_info"
"github.com/answerdev/answer/internal/repo/tag"
@ -59,6 +60,7 @@ import (
"github.com/answerdev/answer/internal/service/report_backyard"
"github.com/answerdev/answer/internal/service/report_handle_backyard"
"github.com/answerdev/answer/internal/service/revision_common"
role2 "github.com/answerdev/answer/internal/service/role"
"github.com/answerdev/answer/internal/service/search_parser"
"github.com/answerdev/answer/internal/service/service_config"
"github.com/answerdev/answer/internal/service/siteinfo"
@ -169,7 +171,11 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
reportBackyardService := report_backyard.NewReportBackyardService(reportRepo, userCommon, commonRepo, answerRepo, questionRepo, commentCommonRepo, reportHandle, configRepo)
controller_backyardReportController := controller_backyard.NewReportController(reportBackyardService)
userBackyardRepo := user.NewUserBackyardRepo(dataData, authRepo)
userBackyardService := user_backyard.NewUserBackyardService(userBackyardRepo)
userRoleRelRepo := role.NewUserRoleRelRepo(dataData)
roleRepo := role.NewRoleRepo(dataData)
roleService := role2.NewRoleService(roleRepo)
userRoleRelService := role2.NewUserRoleRelService(userRoleRelRepo, roleService)
userBackyardService := user_backyard.NewUserBackyardService(userBackyardRepo, userRoleRelService)
userBackyardController := controller_backyard.NewUserBackyardController(userBackyardService)
reasonRepo := reason.NewReasonRepo(configRepo)
reasonService := reason2.NewReasonService(reasonRepo)
@ -184,7 +190,8 @@ func initApplication(debug bool, serverConf *conf.Server, dbConf *data.Database,
notificationController := controller.NewNotificationController(notificationService)
dashboardController := controller.NewDashboardController(dashboardService)
uploadController := controller.NewUploadController(uploaderService)
answerAPIRouter := router.NewAnswerAPIRouter(langController, userController, commentController, reportController, voteController, tagController, followController, collectionController, questionController, answerController, searchController, revisionController, rankController, controller_backyardReportController, userBackyardController, reasonController, themeController, siteInfoController, siteinfoController, notificationController, dashboardController, uploadController)
roleController := controller_backyard.NewRoleController(roleService)
answerAPIRouter := router.NewAnswerAPIRouter(langController, userController, commentController, reportController, voteController, tagController, followController, collectionController, questionController, answerController, searchController, revisionController, rankController, controller_backyardReportController, userBackyardController, reasonController, themeController, siteInfoController, siteinfoController, notificationController, dashboardController, uploadController, roleController)
swaggerRouter := router.NewSwaggerRouter(swaggerConf)
uiRouter := router.NewUIRouter()
authUserMiddleware := middleware.NewAuthUserMiddleware(authService)

View File

@ -432,6 +432,41 @@ const docTemplate = `{
}
}
},
"/answer/admin/api/roles": {
"get": {
"description": "get role list",
"produces": [
"application/json"
],
"tags": [
"admin"
],
"summary": "get role list",
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/handler.RespBody"
},
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/definitions/schema.GetRoleResp"
}
}
}
}
]
}
}
}
}
},
"/answer/admin/api/setting/smtp": {
"get": {
"security": [
@ -883,6 +918,45 @@ const docTemplate = `{
}
}
},
"/answer/admin/api/user/role": {
"put": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "update user role",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"admin"
],
"summary": "update user role",
"parameters": [
{
"description": "user",
"name": "data",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/schema.UpdateUserRoleReq"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handler.RespBody"
}
}
}
}
},
"/answer/admin/api/user/status": {
"put": {
"security": [
@ -956,6 +1030,12 @@ const docTemplate = `{
"name": "query",
"in": "query"
},
{
"type": "boolean",
"description": "staff user",
"name": "staff",
"in": "query"
},
{
"enum": [
"suspended",
@ -5077,6 +5157,20 @@ const docTemplate = `{
}
}
},
"schema.GetRoleResp": {
"type": "object",
"properties": {
"description": {
"type": "string"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
}
}
},
"schema.GetSMTPConfigResp": {
"type": "object",
"properties": {
@ -5293,6 +5387,14 @@ const docTemplate = `{
"description": "rank",
"type": "integer"
},
"role_id": {
"description": "role id",
"type": "integer"
},
"role_name": {
"description": "role name",
"type": "string"
},
"status": {
"description": "user status(normal,suspended,deleted,inactive)",
"type": "string"
@ -6293,6 +6395,23 @@ const docTemplate = `{
}
}
},
"schema.UpdateUserRoleReq": {
"type": "object",
"required": [
"role_id",
"user_id"
],
"properties": {
"role_id": {
"description": "role id",
"type": "integer"
},
"user_id": {
"description": "user id",
"type": "string"
}
}
},
"schema.UpdateUserStatusReq": {
"type": "object",
"required": [

View File

@ -420,6 +420,41 @@
}
}
},
"/answer/admin/api/roles": {
"get": {
"description": "get role list",
"produces": [
"application/json"
],
"tags": [
"admin"
],
"summary": "get role list",
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/handler.RespBody"
},
{
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/definitions/schema.GetRoleResp"
}
}
}
}
]
}
}
}
}
},
"/answer/admin/api/setting/smtp": {
"get": {
"security": [
@ -871,6 +906,45 @@
}
}
},
"/answer/admin/api/user/role": {
"put": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "update user role",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"admin"
],
"summary": "update user role",
"parameters": [
{
"description": "user",
"name": "data",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/schema.UpdateUserRoleReq"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/handler.RespBody"
}
}
}
}
},
"/answer/admin/api/user/status": {
"put": {
"security": [
@ -944,6 +1018,12 @@
"name": "query",
"in": "query"
},
{
"type": "boolean",
"description": "staff user",
"name": "staff",
"in": "query"
},
{
"enum": [
"suspended",
@ -5065,6 +5145,20 @@
}
}
},
"schema.GetRoleResp": {
"type": "object",
"properties": {
"description": {
"type": "string"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
}
}
},
"schema.GetSMTPConfigResp": {
"type": "object",
"properties": {
@ -5281,6 +5375,14 @@
"description": "rank",
"type": "integer"
},
"role_id": {
"description": "role id",
"type": "integer"
},
"role_name": {
"description": "role name",
"type": "string"
},
"status": {
"description": "user status(normal,suspended,deleted,inactive)",
"type": "string"
@ -6281,6 +6383,23 @@
}
}
},
"schema.UpdateUserRoleReq": {
"type": "object",
"required": [
"role_id",
"user_id"
],
"properties": {
"role_id": {
"description": "role id",
"type": "integer"
},
"user_id": {
"description": "user id",
"type": "string"
}
}
},
"schema.UpdateUserStatusReq": {
"type": "object",
"required": [

View File

@ -528,6 +528,15 @@ definitions:
user_info:
$ref: '#/definitions/schema.UserBasicInfo'
type: object
schema.GetRoleResp:
properties:
description:
type: string
id:
type: integer
name:
type: string
type: object
schema.GetSMTPConfigResp:
properties:
encryption:
@ -684,6 +693,12 @@ definitions:
rank:
description: rank
type: integer
role_id:
description: role id
type: integer
role_name:
description: role name
type: string
status:
description: user status(normal,suspended,deleted,inactive)
type: string
@ -1404,6 +1419,18 @@ definitions:
required:
- language
type: object
schema.UpdateUserRoleReq:
properties:
role_id:
description: role id
type: integer
user_id:
description: user id
type: string
required:
- role_id
- user_id
type: object
schema.UpdateUserStatusReq:
properties:
status:
@ -1856,6 +1883,26 @@ paths:
summary: list report page
tags:
- admin
/answer/admin/api/roles:
get:
description: get role list
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/handler.RespBody'
- properties:
data:
items:
$ref: '#/definitions/schema.GetRoleResp'
type: array
type: object
summary: get role list
tags:
- admin
/answer/admin/api/setting/smtp:
get:
description: GetSMTPConfig get smtp config
@ -2117,6 +2164,30 @@ paths:
summary: Get theme options
tags:
- admin
/answer/admin/api/user/role:
put:
consumes:
- application/json
description: update user role
parameters:
- description: user
in: body
name: data
required: true
schema:
$ref: '#/definitions/schema.UpdateUserRoleReq'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/handler.RespBody'
security:
- ApiKeyAuth: []
summary: update user role
tags:
- admin
/answer/admin/api/user/status:
put:
consumes:
@ -2157,6 +2228,10 @@ paths:
in: query
name: query
type: string
- description: staff user
in: query
name: staff
type: boolean
- description: user status
enum:
- suspended

View File

@ -12,6 +12,22 @@ backend:
database_error:
other: "Data server error."
role:
name:
user:
other: "User"
admin:
other: "Admin"
Moderator:
other: "Moderator"
description:
user:
other: "Default with no special access."
admin:
other: "Have the full power to access the site."
Moderator:
other: "Has access to all posts except admin settings."
email:
other: "Email"
password:

View File

@ -11,6 +11,22 @@ backend:
database_error:
other: "数据服务异常"
role:
name:
user:
other: "用户"
admin:
other: "管理员"
moderator:
other: "版主"
description:
user:
other: "默认没有特殊访问权限。"
admin:
other: "拥有进入网站的全部权限。"
moderator:
other: "有权访问所有的帖子,无法进入管理员设置页面。"
email:
other: "邮箱"
password:

View File

@ -1,6 +1,8 @@
package handler
import (
"context"
"github.com/answerdev/answer/internal/base/constant"
"github.com/gin-gonic/gin"
"github.com/segmentfault/pacman/i18n"
@ -18,3 +20,12 @@ func GetLang(ctx *gin.Context) i18n.Language {
return i18n.DefaultLang
}
}
// GetLangByCtx get language from header
func GetLangByCtx(ctx context.Context) i18n.Language {
acceptLanguage, ok := ctx.Value(constant.AcceptLanguageFlag).(i18n.Language)
if ok {
return acceptLanguage
}
return i18n.DefaultLang
}

View File

@ -8,4 +8,5 @@ var ProviderSetController = wire.NewSet(
NewUserBackyardController,
NewThemeController,
NewSiteInfoController,
NewRoleController,
)

View File

@ -0,0 +1,34 @@
package controller_backyard
import (
"github.com/answerdev/answer/internal/base/handler"
"github.com/answerdev/answer/internal/schema"
service "github.com/answerdev/answer/internal/service/role"
"github.com/gin-gonic/gin"
)
// RoleController role controller
type RoleController struct {
roleService *service.RoleService
}
// NewRoleController new controller
func NewRoleController(roleService *service.RoleService) *RoleController {
return &RoleController{roleService: roleService}
}
// GetRoleList get role list
// @Summary get role list
// @Description get role list
// @Tags admin
// @Produce json
// @Success 200 {object} handler.RespBody{data=[]schema.GetRoleResp}
// @Router /answer/admin/api/roles [get]
func (rc *RoleController) GetRoleList(ctx *gin.Context) {
req := &schema.GetRoleResp{}
if handler.BindAndCheck(ctx, req) {
return
}
resp, err := rc.roleService.GetRoleList(ctx)
handler.HandleResponse(ctx, err, resp)
}

View File

@ -2,6 +2,7 @@ package controller_backyard
import (
"github.com/answerdev/answer/internal/base/handler"
"github.com/answerdev/answer/internal/base/middleware"
"github.com/answerdev/answer/internal/schema"
"github.com/answerdev/answer/internal/service/user_backyard"
"github.com/gin-gonic/gin"
@ -37,6 +38,28 @@ func (uc *UserBackyardController) UpdateUserStatus(ctx *gin.Context) {
handler.HandleResponse(ctx, err, nil)
}
// UpdateUserRole update user role
// @Summary update user role
// @Description update user role
// @Security ApiKeyAuth
// @Tags admin
// @Accept json
// @Produce json
// @Param data body schema.UpdateUserRoleReq true "user"
// @Success 200 {object} handler.RespBody
// @Router /answer/admin/api/user/role [put]
func (uc *UserBackyardController) UpdateUserRole(ctx *gin.Context) {
req := &schema.UpdateUserRoleReq{}
if handler.BindAndCheck(ctx, req) {
return
}
req.LoginUserID = middleware.GetLoginUserIDFromContext(ctx)
err := uc.userService.UpdateUserRole(ctx, req)
handler.HandleResponse(ctx, err, nil)
}
// GetUserPage get user page
// @Summary get user page
// @Description get user page
@ -46,6 +69,7 @@ func (uc *UserBackyardController) UpdateUserStatus(ctx *gin.Context) {
// @Param page query int false "page size"
// @Param page_size query int false "page size"
// @Param query query string false "search query: email, username or id:[id]"
// @Param staff query bool false "staff user"
// @Param status query string false "user status" Enums(suspended, deleted, inactive)
// @Success 200 {object} handler.RespBody{data=pager.PageModel{records=[]schema.GetUserPageResp}}
// @Router /answer/admin/api/users/page [get]

View File

@ -0,0 +1,18 @@
package entity
import "time"
// Power power
type Power struct {
ID int `xorm:"not null pk autoincr INT(11) id"`
CreatedAt time.Time `xorm:"created TIMESTAMP created_at"`
UpdatedAt time.Time `xorm:"updated TIMESTAMP updated_at"`
Name string `xorm:"not null default '' VARCHAR(50) name"`
PowerType string `xorm:"not null default '' VARCHAR(100) power_type"`
Description string `xorm:"not null default '' VARCHAR(200) description"`
}
// TableName power table name
func (Power) TableName() string {
return "power"
}

View File

@ -0,0 +1,17 @@
package entity
import "time"
// Role role
type Role struct {
ID int `xorm:"not null pk autoincr INT(11) id"`
CreatedAt time.Time `xorm:"created TIMESTAMP created_at"`
UpdatedAt time.Time `xorm:"updated TIMESTAMP updated_at"`
Name string `xorm:"not null default '' VARCHAR(50) name"`
Description string `xorm:"not null default '' VARCHAR(200) description"`
}
// TableName user table name
func (Role) TableName() string {
return "role"
}

View File

@ -0,0 +1,17 @@
package entity
import "time"
// RolePowerRel role power rel
type RolePowerRel struct {
ID int `xorm:"not null pk autoincr INT(11) id"`
CreatedAt time.Time `xorm:"created TIMESTAMP created_at"`
UpdatedAt time.Time `xorm:"updated TIMESTAMP updated_at"`
RoleID int `xorm:"not null default 0 INT(11) role_id"`
PowerType string `xorm:"not null default '' VARCHAR(200) power_type"`
}
// TableName role power rel table name
func (RolePowerRel) TableName() string {
return "role_power_rel"
}

View File

@ -0,0 +1,17 @@
package entity
import "time"
// UserRoleRel role
type UserRoleRel struct {
ID int `xorm:"not null pk autoincr INT(11) id"`
CreatedAt time.Time `xorm:"created TIMESTAMP created_at"`
UpdatedAt time.Time `xorm:"updated TIMESTAMP updated_at"`
UserID string `xorm:"not null default 0 BIGINT(20) user_id"`
RoleID int `xorm:"not null default 0 INT(11) role_id"`
}
// TableName user role rel table name
func (UserRoleRel) TableName() string {
return "user_role_rel"
}

View File

@ -28,6 +28,10 @@ var tables = []interface{}{
&entity.Uniqid{},
&entity.User{},
&entity.Version{},
&entity.Role{},
&entity.RolePowerRel{},
&entity.Power{},
&entity.UserRoleRel{},
}
// InitDB init db

186
internal/migrations/v4.go Normal file
View File

@ -0,0 +1,186 @@
package migrations
import (
"github.com/answerdev/answer/internal/entity"
"github.com/answerdev/answer/internal/service/permission"
"xorm.io/xorm"
)
func addRoleFeatures(x *xorm.Engine) error {
err := x.Sync(new(entity.Role), new(entity.RolePowerRel), new(entity.Power), new(entity.UserRoleRel))
if err != nil {
return err
}
roles := []*entity.Role{
{ID: 1, Name: "User", Description: "Default with no special access."},
{ID: 2, Name: "Admin", Description: "Have the full power to access the site."},
{ID: 3, Name: "Moderator", Description: "Has access to all posts except admin settings."},
}
// insert default roles
for _, role := range roles {
exist, err := x.Get(&entity.Role{ID: role.ID, Name: role.Name})
if err != nil {
return err
}
if exist {
continue
}
_, err = x.Insert(role)
if err != nil {
return err
}
}
powers := []*entity.Power{
{ID: 1, Name: "admin access", PowerType: permission.AdminAccess, Description: "admin access"},
{ID: 2, Name: "question add", PowerType: permission.QuestionAdd, Description: "question add"},
{ID: 3, Name: "question edit", PowerType: permission.QuestionEdit, Description: "question edit"},
{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: 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"},
{ID: 11, Name: "answer edit", PowerType: permission.AnswerEdit, Description: "answer edit"},
{ID: 12, Name: "answer edit without review", PowerType: permission.AnswerEditWithoutReview, Description: "answer edit without review"},
{ID: 13, Name: "answer delete", PowerType: permission.AnswerDelete, Description: "answer delete"},
{ID: 14, Name: "answer accept", PowerType: permission.AnswerAccept, Description: "answer accept"},
{ID: 15, Name: "answer vote up", PowerType: permission.AnswerVoteUp, Description: "answer vote up"},
{ID: 16, Name: "answer vote down", PowerType: permission.AnswerVoteDown, Description: "answer vote down"},
{ID: 17, Name: "comment add", PowerType: permission.CommentAdd, Description: "comment add"},
{ID: 18, Name: "comment edit", PowerType: permission.CommentEdit, Description: "comment edit"},
{ID: 19, Name: "comment delete", PowerType: permission.CommentDelete, Description: "comment delete"},
{ID: 20, Name: "comment vote up", PowerType: permission.CommentVoteUp, Description: "comment vote up"},
{ID: 21, Name: "comment vote down", PowerType: permission.CommentVoteDown, Description: "comment vote down"},
{ID: 22, Name: "report add", PowerType: permission.ReportAdd, Description: "report add"},
{ID: 23, Name: "tag add", PowerType: permission.TagAdd, Description: "tag add"},
{ID: 24, Name: "tag edit", PowerType: permission.TagEdit, Description: "tag edit"},
{ID: 25, Name: "tag edit without review", PowerType: permission.TagEditWithoutReview, Description: "tag edit without review"},
{ID: 26, Name: "tag edit slug name", PowerType: permission.TagEditSlugName, Description: "tag edit slug name"},
{ID: 27, Name: "tag delete", PowerType: permission.TagDelete, Description: "tag delete"},
{ID: 28, Name: "tag synonym", PowerType: permission.TagSynonym, Description: "tag synonym"},
{ID: 29, Name: "link url limit", PowerType: permission.LinkUrlLimit, Description: "link url limit"},
{ID: 30, Name: "vote detail", PowerType: permission.VoteDetail, Description: "vote detail"},
{ID: 31, Name: "answer audit", PowerType: permission.AnswerAudit, Description: "answer audit"},
{ID: 32, Name: "question audit", PowerType: permission.QuestionAudit, Description: "question audit"},
{ID: 33, Name: "tag audit", PowerType: permission.TagAudit, Description: "tag audit"},
}
// insert default powers
for _, power := range powers {
exist, err := x.Get(&entity.Power{Name: power.Name})
if err != nil {
return err
}
if exist {
continue
}
_, err = x.Insert(power)
if err != nil {
return err
}
}
rolePowerRels := []*entity.RolePowerRel{
{RoleID: 2, PowerType: permission.AdminAccess},
{RoleID: 2, PowerType: permission.QuestionAdd},
{RoleID: 2, PowerType: permission.QuestionEdit},
{RoleID: 2, PowerType: permission.QuestionEditWithoutReview},
{RoleID: 2, PowerType: permission.QuestionDelete},
{RoleID: 2, PowerType: permission.QuestionClose},
{RoleID: 2, PowerType: permission.QuestionOpen},
{RoleID: 2, PowerType: permission.QuestionVoteUp},
{RoleID: 2, PowerType: permission.QuestionVoteDown},
{RoleID: 2, PowerType: permission.AnswerAdd},
{RoleID: 2, PowerType: permission.AnswerEdit},
{RoleID: 2, PowerType: permission.AnswerEditWithoutReview},
{RoleID: 2, PowerType: permission.AnswerDelete},
{RoleID: 2, PowerType: permission.AnswerAccept},
{RoleID: 2, PowerType: permission.AnswerVoteUp},
{RoleID: 2, PowerType: permission.AnswerVoteDown},
{RoleID: 2, PowerType: permission.CommentAdd},
{RoleID: 2, PowerType: permission.CommentEdit},
{RoleID: 2, PowerType: permission.CommentDelete},
{RoleID: 2, PowerType: permission.CommentVoteUp},
{RoleID: 2, PowerType: permission.CommentVoteDown},
{RoleID: 2, PowerType: permission.ReportAdd},
{RoleID: 2, PowerType: permission.TagAdd},
{RoleID: 2, PowerType: permission.TagEdit},
{RoleID: 2, PowerType: permission.TagEditSlugName},
{RoleID: 2, PowerType: permission.TagEditWithoutReview},
{RoleID: 2, PowerType: permission.TagDelete},
{RoleID: 2, PowerType: permission.TagSynonym},
{RoleID: 2, PowerType: permission.LinkUrlLimit},
{RoleID: 2, PowerType: permission.VoteDetail},
{RoleID: 2, PowerType: permission.AnswerAudit},
{RoleID: 2, PowerType: permission.QuestionAudit},
{RoleID: 2, PowerType: permission.TagAudit},
{RoleID: 3, PowerType: permission.QuestionAdd},
{RoleID: 3, PowerType: permission.QuestionEdit},
{RoleID: 3, PowerType: permission.QuestionEditWithoutReview},
{RoleID: 3, PowerType: permission.QuestionDelete},
{RoleID: 3, PowerType: permission.QuestionClose},
{RoleID: 3, PowerType: permission.QuestionOpen},
{RoleID: 3, PowerType: permission.QuestionVoteUp},
{RoleID: 3, PowerType: permission.QuestionVoteDown},
{RoleID: 3, PowerType: permission.AnswerAdd},
{RoleID: 3, PowerType: permission.AnswerEdit},
{RoleID: 3, PowerType: permission.AnswerEditWithoutReview},
{RoleID: 3, PowerType: permission.AnswerDelete},
{RoleID: 3, PowerType: permission.AnswerAccept},
{RoleID: 3, PowerType: permission.AnswerVoteUp},
{RoleID: 3, PowerType: permission.AnswerVoteDown},
{RoleID: 3, PowerType: permission.CommentAdd},
{RoleID: 3, PowerType: permission.CommentEdit},
{RoleID: 3, PowerType: permission.CommentDelete},
{RoleID: 3, PowerType: permission.CommentVoteUp},
{RoleID: 3, PowerType: permission.CommentVoteDown},
{RoleID: 3, PowerType: permission.ReportAdd},
{RoleID: 3, PowerType: permission.TagAdd},
{RoleID: 3, PowerType: permission.TagEdit},
{RoleID: 3, PowerType: permission.TagEditSlugName},
{RoleID: 3, PowerType: permission.TagEditWithoutReview},
{RoleID: 3, PowerType: permission.TagDelete},
{RoleID: 3, PowerType: permission.TagSynonym},
{RoleID: 3, PowerType: permission.LinkUrlLimit},
{RoleID: 3, PowerType: permission.VoteDetail},
{RoleID: 3, PowerType: permission.AnswerAudit},
{RoleID: 3, PowerType: permission.QuestionAudit},
{RoleID: 3, PowerType: permission.TagAudit},
}
// insert default powers
for _, rel := range rolePowerRels {
exist, err := x.Get(&entity.RolePowerRel{RoleID: rel.RoleID, PowerType: rel.PowerType})
if err != nil {
return err
}
if exist {
continue
}
_, err = x.Insert(rel)
if err != nil {
return err
}
}
adminUserRoleRel := &entity.UserRoleRel{
UserID: "1",
RoleID: 2,
}
exist, err := x.Get(adminUserRoleRel)
if err != nil {
return err
}
if !exist {
_, err = x.Insert(adminUserRoleRel)
if err != nil {
return err
}
}
return nil
}

View File

@ -19,6 +19,7 @@ import (
"github.com/answerdev/answer/internal/repo/reason"
"github.com/answerdev/answer/internal/repo/report"
"github.com/answerdev/answer/internal/repo/revision"
"github.com/answerdev/answer/internal/repo/role"
"github.com/answerdev/answer/internal/repo/search_common"
"github.com/answerdev/answer/internal/repo/site_info"
"github.com/answerdev/answer/internal/repo/tag"
@ -66,4 +67,8 @@ var ProviderSetRepo = wire.NewSet(
reason.NewReasonRepo,
site_info.NewSiteInfo,
notification.NewNotificationRepo,
role.NewRoleRepo,
role.NewUserRoleRelRepo,
role.NewRolePowerRelRepo,
role.NewPowerRepo,
)

View File

@ -0,0 +1,33 @@
package role
import (
"context"
"github.com/answerdev/answer/internal/base/data"
"github.com/answerdev/answer/internal/base/reason"
"github.com/answerdev/answer/internal/entity"
"github.com/answerdev/answer/internal/service/role"
"github.com/segmentfault/pacman/errors"
)
// powerRepo power repository
type powerRepo struct {
data *data.Data
}
// NewPowerRepo new repository
func NewPowerRepo(data *data.Data) role.PowerRepo {
return &powerRepo{
data: data,
}
}
// GetPowerList get list all
func (pr *powerRepo) GetPowerList(ctx context.Context, power *entity.Power) (powerList []*entity.Power, err error) {
powerList = make([]*entity.Power, 0)
err = pr.data.DB.Find(powerList, power)
if err != nil {
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
return
}

View File

@ -0,0 +1,33 @@
package role
import (
"context"
"github.com/answerdev/answer/internal/base/data"
"github.com/answerdev/answer/internal/base/reason"
"github.com/answerdev/answer/internal/service/role"
"github.com/segmentfault/pacman/errors"
"xorm.io/builder"
)
// rolePowerRelRepo rolePowerRel repository
type rolePowerRelRepo struct {
data *data.Data
}
// NewRolePowerRelRepo new repository
func NewRolePowerRelRepo(data *data.Data) role.RolePowerRelRepo {
return &rolePowerRelRepo{
data: data,
}
}
// 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)
if err != nil {
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
return
}

View File

@ -0,0 +1,46 @@
package role
import (
"context"
"github.com/answerdev/answer/internal/base/data"
"github.com/answerdev/answer/internal/base/reason"
"github.com/answerdev/answer/internal/entity"
service "github.com/answerdev/answer/internal/service/role"
"github.com/segmentfault/pacman/errors"
)
// roleRepo role repository
type roleRepo struct {
data *data.Data
}
// NewRoleRepo new repository
func NewRoleRepo(data *data.Data) service.RoleRepo {
return &roleRepo{
data: data,
}
}
// GetRoleAllList get role list all
func (rr *roleRepo) GetRoleAllList(ctx context.Context) (roleList []*entity.Role, err error) {
roleList = make([]*entity.Role, 0)
err = rr.data.DB.Find(&roleList)
if err != nil {
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
return
}
// GetRoleAllMapping get role all mapping
func (rr *roleRepo) GetRoleAllMapping(ctx context.Context) (roleMapping map[int]*entity.Role, err error) {
roleList, err := rr.GetRoleAllList(ctx)
if err != nil {
return nil, err
}
roleMapping = make(map[int]*entity.Role, 0)
for _, role := range roleList {
roleMapping[role.ID] = role
}
return roleMapping, nil
}

View File

@ -0,0 +1,60 @@
package role
import (
"context"
"github.com/answerdev/answer/internal/base/data"
"github.com/answerdev/answer/internal/base/reason"
"github.com/answerdev/answer/internal/entity"
"github.com/answerdev/answer/internal/service/role"
"github.com/segmentfault/pacman/errors"
"xorm.io/xorm"
)
// userRoleRelRepo userRoleRel repository
type userRoleRelRepo struct {
data *data.Data
}
// NewUserRoleRelRepo new repository
func NewUserRoleRelRepo(data *data.Data) role.UserRoleRelRepo {
return &userRoleRelRepo{
data: data,
}
}
// SaveUserRoleRel save user role rel
func (ur *userRoleRelRepo) SaveUserRoleRel(ctx context.Context, userID string, roleID int) (err error) {
_, err = ur.data.DB.Transaction(func(session *xorm.Session) (interface{}, error) {
item := &entity.UserRoleRel{UserID: userID}
exist, err := ur.data.DB.Get(item)
if err != nil {
return nil, err
}
if exist {
item.RoleID = roleID
_, err = ur.data.DB.Update(item)
} else {
_, err = ur.data.DB.Insert(&entity.UserRoleRel{UserID: userID, RoleID: roleID})
}
if err != nil {
return nil, err
}
return nil, nil
})
if err != nil {
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
return
}
// GetUserRoleRelList get user role all
func (ur *userRoleRelRepo) GetUserRoleRelList(ctx context.Context, userIDs []string) (
userRoleRelList []*entity.UserRoleRel, err error) {
userRoleRelList = make([]*entity.UserRoleRel, 0)
err = ur.data.DB.In("user_id", userIDs).Find(&userRoleRelList)
if err != nil {
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
}
return
}

View File

@ -3,10 +3,7 @@ package user
import (
"context"
"encoding/json"
"net/mail"
"strings"
"time"
"unicode"
"xorm.io/builder"
@ -75,49 +72,27 @@ func (ur *userBackyardRepo) GetUserInfo(ctx context.Context, userID string) (use
}
// GetUserPage get user page
func (ur *userBackyardRepo) GetUserPage(ctx context.Context, page, pageSize int, user *entity.User, query string) (users []*entity.User, total int64, err error) {
func (ur *userBackyardRepo) GetUserPage(ctx context.Context, page, pageSize int, user *entity.User,
usernameOrDisplayName string, isStaff bool) (users []*entity.User, total int64, err error) {
users = make([]*entity.User, 0)
session := ur.data.DB.NewSession()
switch user.Status {
case entity.UserStatusDeleted:
session.Desc("deleted_at")
session.Desc("user.deleted_at")
case entity.UserStatusSuspended:
session.Desc("suspended_at")
session.Desc("user.suspended_at")
default:
session.Desc("created_at")
session.Desc("user.created_at")
}
if len(query) > 0 {
if email, e := mail.ParseAddress(query); e == nil {
session.And(builder.Eq{"e_mail": email.Address})
} else {
var (
idSearch = false
id = ""
)
if strings.Contains(query, "user:") {
idSearch = true
id = strings.TrimSpace(strings.TrimPrefix(query, "user:"))
for _, r := range id {
if !unicode.IsDigit(r) {
idSearch = false
break
}
}
}
if idSearch {
session.And(builder.Eq{
"id": id,
})
} else {
session.And(builder.Or(
builder.Like{"username", query},
builder.Like{"display_name", query},
))
}
}
if len(usernameOrDisplayName) > 0 {
session.And(builder.Or(
builder.Like{"user.username", usernameOrDisplayName},
builder.Like{"user.display_name", usernameOrDisplayName},
))
}
if isStaff {
session.Join("INNER", "user_role_rel", "user.id = user_role_rel.user_id AND user_role_rel.role_id > 1")
}
total, err = pager.Help(page, pageSize, &users, user, session)

View File

@ -29,6 +29,7 @@ type AnswerAPIRouter struct {
notificationController *controller.NotificationController
dashboardController *controller.DashboardController
uploadController *controller.UploadController
roleController *controller_backyard.RoleController
}
func NewAnswerAPIRouter(
@ -54,6 +55,7 @@ func NewAnswerAPIRouter(
notificationController *controller.NotificationController,
dashboardController *controller.DashboardController,
uploadController *controller.UploadController,
roleController *controller_backyard.RoleController,
) *AnswerAPIRouter {
return &AnswerAPIRouter{
langController: langController,
@ -78,6 +80,7 @@ func NewAnswerAPIRouter(
siteinfoController: siteinfoController,
dashboardController: dashboardController,
uploadController: uploadController,
roleController: roleController,
}
}
@ -215,6 +218,7 @@ func (a *AnswerAPIRouter) RegisterAnswerCmsAPIRouter(r *gin.RouterGroup) {
// user
r.GET("/users/page", a.backyardUserController.GetUserPage)
r.PUT("/user/status", a.backyardUserController.UpdateUserStatus)
r.PUT("/user/role", a.backyardUserController.UpdateUserRole)
// reason
r.GET("/reasons", a.reasonController.Reasons)
@ -239,6 +243,9 @@ func (a *AnswerAPIRouter) RegisterAnswerCmsAPIRouter(r *gin.RouterGroup) {
r.GET("/setting/smtp", a.siteInfoController.GetSMTPConfig)
r.PUT("/setting/smtp", a.siteInfoController.UpdateSMTPConfig)
//dashboard
// dashboard
r.GET("/dashboard", a.dashboardController.DashboardInfo)
// roles
r.GET("/roles", a.roleController.GetRoleList)
}

View File

@ -30,6 +30,8 @@ type GetUserPageReq struct {
Query string `validate:"omitempty,gt=0,lte=100" form:"query"`
// user status
Status string `validate:"omitempty,oneof=suspended deleted inactive" form:"status"`
// staff, if staff is true means query admin or moderator
Staff bool `validate:"omitempty" form:"staff"`
}
func (r *GetUserPageReq) IsSuspended() bool { return r.Status == UserSuspended }
@ -58,6 +60,10 @@ type GetUserPageResp struct {
DisplayName string `json:"display_name"`
// avatar
Avatar string `json:"avatar"`
// role id
RoleID int `json:"role_id"`
// role name
RoleName string `json:"role_name"`
}
// GetUserInfoReq get user request
@ -68,3 +74,13 @@ type GetUserInfoReq struct {
// GetUserInfoResp get user response
type GetUserInfoResp struct {
}
// UpdateUserRoleReq update user role request
type UpdateUserRoleReq struct {
// user id
UserID string `validate:"required" json:"user_id"`
// role id
RoleID int `validate:"required" json:"role_id"`
// login user id
LoginUserID string `json:"-"`
}

View File

@ -0,0 +1,8 @@
package schema
// GetRoleResp get role response
type GetRoleResp struct {
ID int `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
}

View File

@ -0,0 +1,37 @@
package permission
const (
AdminAccess = "admin.access"
QuestionAdd = "question.add"
QuestionEdit = "question.edit"
QuestionEditWithoutReview = "question.edit_without_review"
QuestionDelete = "question.delete"
QuestionClose = "question.close"
QuestionOpen = "question.open"
QuestionVoteUp = "question.vote_up"
QuestionVoteDown = "question.vote_down"
AnswerAdd = "answer.add"
AnswerEdit = "answer.edit"
AnswerEditWithoutReview = "answer.edit_without_review"
AnswerDelete = "answer.delete"
AnswerAccept = "answer.accept"
AnswerVoteUp = "answer.vote_up"
AnswerVoteDown = "answer.vote_down"
CommentAdd = "comment.add"
CommentEdit = "comment.edit"
CommentDelete = "comment.delete"
CommentVoteUp = "comment.vote_up"
CommentVoteDown = "comment.vote_down"
ReportAdd = "report.add"
TagAdd = "tag.add"
TagEdit = "tag.edit"
TagEditSlugName = "tag.edit_slug_name"
TagEditWithoutReview = "tag.edit_without_review"
TagDelete = "tag.delete"
TagSynonym = "tag.synonym"
LinkUrlLimit = "link.url_limit"
VoteDetail = "vote.detail"
AnswerAudit = "answer.audit"
QuestionAudit = "question.audit"
TagAudit = "tag.audit"
)

View File

@ -22,9 +22,10 @@ import (
"github.com/answerdev/answer/internal/service/report_backyard"
"github.com/answerdev/answer/internal/service/report_handle_backyard"
"github.com/answerdev/answer/internal/service/revision_common"
"github.com/answerdev/answer/internal/service/role"
"github.com/answerdev/answer/internal/service/search_parser"
"github.com/answerdev/answer/internal/service/siteinfo"
"github.com/answerdev/answer/internal/service/siteinfo_common"
"github.com/answerdev/answer/internal/service/search_parser"
"github.com/answerdev/answer/internal/service/tag"
tagcommon "github.com/answerdev/answer/internal/service/tag_common"
"github.com/answerdev/answer/internal/service/uploader"
@ -72,4 +73,7 @@ var ProviderSetService = wire.NewSet(
notification.NewNotificationService,
activity.NewAnswerActivityService,
dashboard.NewDashboardService,
role.NewRoleService,
role.NewUserRoleRelService,
role.NewRolePowerRelService,
)

View File

@ -0,0 +1,47 @@
package role
import (
"context"
"github.com/answerdev/answer/internal/entity"
)
// PowerRepo power repository
type PowerRepo interface {
GetPowerList(ctx context.Context, power *entity.Power) (powers []*entity.Power, err error)
}
//// PowerService user service
//type PowerService struct {
// powerRepo PowerRepo
// rolePowerRelService *RolePowerRelService
//}
//
//// NewPowerService new power service
//func NewPowerService(powerRepo PowerRepo, rolePowerRelService *RolePowerRelService) *PowerService {
// return &PowerService{
// powerRepo: powerRepo,
// }
//}
//
//// GetRolePowerList get role power list
//func (ps *PowerService) GetRolePowerList(ctx context.Context, roleID string) (powers []string, err error) {
// power := &entity.Power{}
// powerList, err := ps.powerRepo.GetPowerList(ctx, power)
// if err != nil {
// return
// }
//}
//
//// GetPowerList get list all
//func (ps *PowerService) GetPowerList(ctx context.Context, req *schema.GetPowerListReq) (resp *[]schema.GetPowerResp, err error) {
// power := &entity.Power{}
// powers, err := ps.powerRepo.GetPowerList(ctx, power)
// if err != nil {
// return
// }
//
// resp = &[]schema.GetPowerResp{}
// _ = copier.Copy(resp, powers)
// return
//}

View File

@ -0,0 +1,27 @@
package role
import (
"context"
)
// RolePowerRelRepo rolePowerRel repository
type RolePowerRelRepo interface {
GetRolePowerTypeList(ctx context.Context, roleID int) (powers []string, err error)
}
// RolePowerRelService user service
type RolePowerRelService struct {
rolePowerRelRepo RolePowerRelRepo
}
// NewRolePowerRelService new role power rel service
func NewRolePowerRelService(rolePowerRelRepo RolePowerRelRepo) *RolePowerRelService {
return &RolePowerRelService{
rolePowerRelRepo: rolePowerRelRepo,
}
}
// GetRolePowerList get role power list
func (rs *RolePowerRelService) GetRolePowerList(ctx context.Context, roleID int) (powers []string, err error) {
return rs.rolePowerRelRepo.GetRolePowerTypeList(ctx, roleID)
}

View File

@ -0,0 +1,81 @@
package role
import (
"context"
"github.com/answerdev/answer/internal/base/handler"
"github.com/answerdev/answer/internal/base/translator"
"github.com/answerdev/answer/internal/entity"
"github.com/answerdev/answer/internal/schema"
"github.com/jinzhu/copier"
)
const (
// Since there is currently no need to edit roles to add roles and other operations,
// the current role information is translated directly.
// Later on, when the relevant ability is available, it can be adjusted by the user himself.
roleUserName = "User"
roleAdminName = "Admin"
roleModeratorName = "Moderator"
trRoleNameUser = "role.name.user"
trRoleNameAdmin = "role.name.admin"
trRoleNameModerator = "role.name.moderator"
trRoleDescriptionUser = "role.description.user"
trRoleDescriptionAdmin = "role.description.admin"
trRoleDescriptionModerator = "role.description.moderator"
)
// RoleRepo role repository
type RoleRepo interface {
GetRoleAllList(ctx context.Context) (roles []*entity.Role, err error)
GetRoleAllMapping(ctx context.Context) (roleMapping map[int]*entity.Role, err error)
}
// RoleService user service
type RoleService struct {
roleRepo RoleRepo
}
func NewRoleService(roleRepo RoleRepo) *RoleService {
return &RoleService{
roleRepo: roleRepo,
}
}
// GetRoleList get role list all
func (rs *RoleService) GetRoleList(ctx context.Context) (resp []*schema.GetRoleResp, err error) {
roles, err := rs.roleRepo.GetRoleAllList(ctx)
if err != nil {
return
}
for _, role := range roles {
rs.translateRole(ctx, role)
}
resp = []*schema.GetRoleResp{}
_ = copier.Copy(&resp, roles)
return
}
func (rs *RoleService) GetRoleMapping(ctx context.Context) (roleMapping map[int]*entity.Role, err error) {
return rs.roleRepo.GetRoleAllMapping(ctx)
}
func (rs *RoleService) translateRole(ctx context.Context, role *entity.Role) {
switch role.Name {
case roleUserName:
role.Name = translator.GlobalTrans.Tr(handler.GetLangByCtx(ctx), trRoleNameUser)
role.Description = translator.GlobalTrans.Tr(handler.GetLangByCtx(ctx), trRoleDescriptionUser)
case roleAdminName:
role.Name = translator.GlobalTrans.Tr(handler.GetLangByCtx(ctx), trRoleNameAdmin)
role.Description = translator.GlobalTrans.Tr(handler.GetLangByCtx(ctx), trRoleDescriptionAdmin)
case roleModeratorName:
role.Name = translator.GlobalTrans.Tr(handler.GetLangByCtx(ctx), trRoleNameModerator)
role.Description = translator.GlobalTrans.Tr(handler.GetLangByCtx(ctx), trRoleDescriptionModerator)
}
return
}

View File

@ -0,0 +1,81 @@
package role
import (
"context"
"github.com/answerdev/answer/internal/entity"
)
// UserRoleRelRepo userRoleRel repository
type UserRoleRelRepo interface {
SaveUserRoleRel(ctx context.Context, userID string, roleID int) (err error)
GetUserRoleRelList(ctx context.Context, userIDs []string) (userRoleRelList []*entity.UserRoleRel, err error)
}
// UserRoleRelService user service
type UserRoleRelService struct {
userRoleRelRepo UserRoleRelRepo
roleService *RoleService
}
// NewUserRoleRelService new user role rel service
func NewUserRoleRelService(userRoleRelRepo UserRoleRelRepo, roleService *RoleService) *UserRoleRelService {
return &UserRoleRelService{
userRoleRelRepo: userRoleRelRepo,
roleService: roleService,
}
}
// SaveUserRole save user role
func (us *UserRoleRelService) SaveUserRole(ctx context.Context, userID string, roleID int) (err error) {
return us.userRoleRelRepo.SaveUserRoleRel(ctx, userID, roleID)
}
// GetUserRoleMapping get user role mapping
func (us *UserRoleRelService) GetUserRoleMapping(ctx context.Context, userIDs []string) (
userRoleMapping map[string]*entity.Role, err error) {
userRoleMapping = make(map[string]*entity.Role, 0)
roleMapping, err := us.roleService.GetRoleMapping(ctx)
if err != nil {
return userRoleMapping, err
}
if len(roleMapping) == 0 {
return userRoleMapping, nil
}
relMapping, err := us.GetUserRoleRelMapping(ctx, userIDs)
if err != nil {
return userRoleMapping, err
}
// default role is user
defaultRole := roleMapping[1]
for _, userID := range userIDs {
roleID, ok := relMapping[userID]
if !ok {
userRoleMapping[userID] = defaultRole
continue
}
userRoleMapping[userID] = roleMapping[roleID]
if userRoleMapping[userID] == nil {
userRoleMapping[userID] = defaultRole
}
}
return userRoleMapping, nil
}
// GetUserRoleRelMapping get user role rel mapping
func (us *UserRoleRelService) GetUserRoleRelMapping(ctx context.Context, userIDs []string) (
userRoleRelMapping map[string]int, err error) {
userRoleRelMapping = make(map[string]int, 0)
relList, err := us.userRoleRelRepo.GetUserRoleRelList(ctx, userIDs)
if err != nil {
return userRoleRelMapping, err
}
for _, rel := range relList {
userRoleRelMapping[rel.UserID] = rel.RoleID
}
return userRoleRelMapping, nil
}

View File

@ -3,31 +3,43 @@ package user_backyard
import (
"context"
"fmt"
"net/mail"
"strings"
"time"
"unicode"
"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/role"
"github.com/jinzhu/copier"
"github.com/segmentfault/pacman/errors"
"github.com/segmentfault/pacman/log"
)
// UserBackyardRepo user repository
type UserBackyardRepo interface {
UpdateUserStatus(ctx context.Context, userID string, userStatus, mailStatus int, email string) (err error)
GetUserInfo(ctx context.Context, userID string) (user *entity.User, exist bool, err error)
GetUserPage(ctx context.Context, page, pageSize int, user *entity.User, query string) (users []*entity.User, total int64, err error)
GetUserPage(ctx context.Context, page, pageSize int, user *entity.User,
usernameOrDisplayName string, isStaff bool) (users []*entity.User, total int64, err error)
}
// UserBackyardService user service
type UserBackyardService struct {
userRepo UserBackyardRepo
userRepo UserBackyardRepo
userRoleRelService *role.UserRoleRelService
}
func NewUserBackyardService(userRepo UserBackyardRepo) *UserBackyardService {
// NewUserBackyardService new user backyard service
func NewUserBackyardService(
userRepo UserBackyardRepo,
userRoleRelService *role.UserRoleRelService,
) *UserBackyardService {
return &UserBackyardService{
userRepo: userRepo,
userRepo: userRepo,
userRoleRelService: userRoleRelService,
}
}
@ -62,6 +74,16 @@ func (us *UserBackyardService) UpdateUserStatus(ctx context.Context, req *schema
return us.userRepo.UpdateUserStatus(ctx, userInfo.ID, userInfo.Status, userInfo.MailStatus, userInfo.EMail)
}
// UpdateUserRole update user role
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 us.userRoleRelService.SaveUserRole(ctx, req.UserID, req.RoleID)
}
// GetUserInfo get user one
func (us *UserBackyardService) GetUserInfo(ctx context.Context, userID string) (resp *schema.GetUserInfoResp, err error) {
user, exist, err := us.userRepo.GetUserInfo(ctx, userID)
@ -91,7 +113,29 @@ func (us *UserBackyardService) GetUserPage(ctx context.Context, req *schema.GetU
user.Status = entity.UserStatusDeleted
}
users, total, err := us.userRepo.GetUserPage(ctx, req.Page, req.PageSize, user, req.Query)
if len(req.Query) > 0 {
if email, e := mail.ParseAddress(req.Query); e == nil {
user.EMail = email.Address
req.Query = ""
} else if strings.HasPrefix(req.Query, "user:") {
id := strings.TrimSpace(strings.TrimPrefix(req.Query, "user:"))
idSearch := true
for _, r := range id {
if !unicode.IsDigit(r) {
idSearch = false
break
}
}
if idSearch {
user.ID = id
req.Query = ""
} else {
req.Query = id
}
}
}
users, total, err := us.userRepo.GetUserPage(ctx, req.Page, req.PageSize, user, req.Query, req.Staff)
if err != nil {
return
}
@ -121,5 +165,28 @@ func (us *UserBackyardService) GetUserPage(ctx context.Context, req *schema.GetU
}
resp = append(resp, t)
}
us.setUserRoleInfo(ctx, resp)
return pager.NewPageModel(total, resp), nil
}
func (us *UserBackyardService) setUserRoleInfo(ctx context.Context, resp []*schema.GetUserPageResp) {
var userIDs []string
for _, u := range resp {
userIDs = append(userIDs, u.UserID)
}
userRoleMapping, err := us.userRoleRelService.GetUserRoleMapping(ctx, userIDs)
if err != nil {
log.Error(err)
return
}
for _, u := range resp {
r := userRoleMapping[u.UserID]
if r == nil {
continue
}
u.RoleID = r.ID
u.RoleName = r.Name
}
}

View File

@ -5,6 +5,7 @@ import (
"github.com/answerdev/answer/internal/entity"
"github.com/answerdev/answer/internal/schema"
"github.com/answerdev/answer/internal/service/role"
)
type UserRepo interface {
@ -27,7 +28,8 @@ type UserRepo interface {
// UserCommon user service
type UserCommon struct {
userRepo UserRepo
userRepo UserRepo
roleService *role.RoleService
}
func NewUserCommon(userRepo UserRepo) *UserCommon {