mirror of https://gitee.com/answerdev/answer.git
feat(user): add role and role power
This commit is contained in:
parent
661d8a7f8f
commit
6a9408657c
|
@ -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)
|
||||
|
|
119
docs/docs.go
119
docs/docs.go
|
@ -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": [
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -8,4 +8,5 @@ var ProviderSetController = wire.NewSet(
|
|||
NewUserBackyardController,
|
||||
NewThemeController,
|
||||
NewSiteInfoController,
|
||||
NewRoleController,
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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]
|
||||
|
|
|
@ -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"
|
||||
}
|
|
@ -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"
|
||||
}
|
|
@ -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"
|
||||
}
|
|
@ -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"
|
||||
}
|
|
@ -28,6 +28,10 @@ var tables = []interface{}{
|
|||
&entity.Uniqid{},
|
||||
&entity.User{},
|
||||
&entity.Version{},
|
||||
&entity.Role{},
|
||||
&entity.RolePowerRel{},
|
||||
&entity.Power{},
|
||||
&entity.UserRoleRel{},
|
||||
}
|
||||
|
||||
// InitDB init db
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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:"-"`
|
||||
}
|
||||
|
|
|
@ -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"`
|
||||
}
|
|
@ -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"
|
||||
)
|
|
@ -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,
|
||||
)
|
||||
|
|
|
@ -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
|
||||
//}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue