feat: 适配管理端系统 API 与管理员保护 (#67)
This commit is contained in:
@@ -1,13 +1,14 @@
|
||||
package apis
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.ilapage.cn/OPC/chorus/admin/common/global"
|
||||
"net/http"
|
||||
|
||||
"git.ilapage.cn/OPC/chorus/admin/app/admin/models"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
"github.com/go-admin-team/go-admin-core/sdk"
|
||||
"git.ilapage.cn/OPC/chorus/admin/app/admin/models"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-admin-team/go-admin-core/sdk/api"
|
||||
@@ -168,6 +169,11 @@ func (e SysRole) Update(c *gin.Context) {
|
||||
err = s.Update(&req, cb)
|
||||
if err != nil {
|
||||
e.Logger.Error(err)
|
||||
if errors.Is(err, service.ErrBuiltInRoleProtected) {
|
||||
e.Error(http.StatusConflict, err, err.Error())
|
||||
} else {
|
||||
e.Error(http.StatusInternalServerError, errors.New("角色更新失败"), "角色更新失败")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -207,7 +213,11 @@ func (e SysRole) Delete(c *gin.Context) {
|
||||
err = s.Remove(&req, cb)
|
||||
if err != nil {
|
||||
e.Logger.Error(err)
|
||||
e.Error(500, err, "")
|
||||
if errors.Is(err, service.ErrBuiltInRoleProtected) {
|
||||
e.Error(http.StatusConflict, err, err.Error())
|
||||
} else {
|
||||
e.Error(http.StatusInternalServerError, errors.New("角色删除失败"), "角色删除失败")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -240,7 +250,12 @@ func (e SysRole) Update2Status(c *gin.Context) {
|
||||
req.SetUpdateBy(user.GetUserId(c))
|
||||
err = s.UpdateStatus(&req)
|
||||
if err != nil {
|
||||
e.Error(500, err, fmt.Sprintf("更新角色状态失败,失败原因:%s ", err.Error()))
|
||||
if errors.Is(err, service.ErrBuiltInRoleProtected) {
|
||||
e.Error(http.StatusConflict, err, err.Error())
|
||||
} else {
|
||||
e.Logger.Error(err)
|
||||
e.Error(http.StatusInternalServerError, errors.New("角色状态更新失败"), "角色状态更新失败")
|
||||
}
|
||||
return
|
||||
}
|
||||
e.OK(req.GetId(), fmt.Sprintf("更新角色 %v 状态成功!", req.GetId()))
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package apis
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
"errors"
|
||||
"git.ilapage.cn/OPC/chorus/admin/app/admin/models"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"net/http"
|
||||
|
||||
@@ -190,9 +191,14 @@ func (e SysUser) Delete(c *gin.Context) {
|
||||
// 数据权限检查
|
||||
p := actions.GetPermissionFromContext(c)
|
||||
|
||||
err = s.Remove(&req, p)
|
||||
err = s.Remove(&req, p, user.GetUserId(c))
|
||||
if err != nil {
|
||||
e.Logger.Error(err)
|
||||
if errors.Is(err, service.ErrCurrentAdminProtected) || errors.Is(err, service.ErrLastAdminProtected) {
|
||||
e.Error(http.StatusConflict, err, err.Error())
|
||||
} else {
|
||||
e.Error(http.StatusInternalServerError, errors.New("管理员删除失败"), "管理员删除失败")
|
||||
}
|
||||
return
|
||||
}
|
||||
e.OK(req.GetId(), "删除成功")
|
||||
@@ -275,9 +281,14 @@ func (e SysUser) UpdateStatus(c *gin.Context) {
|
||||
//数据权限检查
|
||||
p := actions.GetPermissionFromContext(c)
|
||||
|
||||
err = s.UpdateStatus(&req, p)
|
||||
err = s.UpdateStatus(&req, p, user.GetUserId(c))
|
||||
if err != nil {
|
||||
e.Logger.Error(err)
|
||||
if errors.Is(err, service.ErrCurrentAdminProtected) || errors.Is(err, service.ErrLastAdminProtected) {
|
||||
e.Error(http.StatusConflict, err, err.Error())
|
||||
} else {
|
||||
e.Error(http.StatusInternalServerError, errors.New("管理员状态更新失败"), "管理员状态更新失败")
|
||||
}
|
||||
return
|
||||
}
|
||||
e.OK(req.GetId(), "更新成功")
|
||||
@@ -385,8 +396,7 @@ func (e SysUser) GetProfile(c *gin.Context) {
|
||||
|
||||
sysUser := models.SysUser{}
|
||||
roles := make([]models.SysRole, 0)
|
||||
posts := make([]models.SysPost, 0)
|
||||
err = s.GetProfile(&req, &sysUser, &roles, &posts)
|
||||
err = s.GetProfile(&req, &sysUser, &roles)
|
||||
if err != nil {
|
||||
e.Logger.Errorf("get user profile error, %s", err.Error())
|
||||
e.Error(500, err, "获取用户信息失败")
|
||||
@@ -395,7 +405,6 @@ func (e SysUser) GetProfile(c *gin.Context) {
|
||||
e.OK(gin.H{
|
||||
"user": sysUser,
|
||||
"roles": roles,
|
||||
"posts": posts,
|
||||
}, "查询成功")
|
||||
}
|
||||
|
||||
@@ -452,7 +461,6 @@ func (e SysUser) GetInfo(c *gin.Context) {
|
||||
}
|
||||
mp["userName"] = sysUser.Username
|
||||
mp["userId"] = sysUser.UserId
|
||||
mp["deptId"] = sysUser.DeptId
|
||||
mp["name"] = sysUser.NickName
|
||||
mp["code"] = 200
|
||||
e.OK(mp, "")
|
||||
|
||||
@@ -11,20 +11,20 @@ type SysUser struct {
|
||||
Username string `json:"username" gorm:"size:64;comment:用户名"`
|
||||
Password string `json:"-" gorm:"size:128;comment:密码"`
|
||||
NickName string `json:"nickName" gorm:"size:128;comment:昵称"`
|
||||
Phone string `json:"phone" gorm:"size:11;comment:手机号"`
|
||||
Phone string `json:"-" gorm:"size:11;comment:手机号"`
|
||||
RoleId int `json:"roleId" gorm:"size:20;comment:角色ID"`
|
||||
Salt string `json:"-" gorm:"size:255;comment:加盐"`
|
||||
Avatar string `json:"avatar" gorm:"size:255;comment:头像"`
|
||||
Sex string `json:"sex" gorm:"size:255;comment:性别"`
|
||||
Email string `json:"email" gorm:"size:128;comment:邮箱"`
|
||||
DeptId int `json:"deptId" gorm:"size:20;comment:部门"`
|
||||
PostId int `json:"postId" gorm:"size:20;comment:岗位"`
|
||||
Sex string `json:"-" gorm:"size:255;comment:性别"`
|
||||
Email string `json:"-" gorm:"size:128;comment:邮箱"`
|
||||
DeptId int `json:"-" gorm:"size:20;comment:部门"`
|
||||
PostId int `json:"-" gorm:"size:20;comment:岗位"`
|
||||
Remark string `json:"remark" gorm:"size:255;comment:备注"`
|
||||
Status string `json:"status" gorm:"size:4;comment:状态"`
|
||||
DeptIds []int `json:"deptIds" gorm:"-"`
|
||||
PostIds []int `json:"postIds" gorm:"-"`
|
||||
DeptIds []int `json:"-" gorm:"-"`
|
||||
PostIds []int `json:"-" gorm:"-"`
|
||||
RoleIds []int `json:"roleIds" gorm:"-"`
|
||||
Dept *SysDept `json:"dept"`
|
||||
Dept *SysDept `json:"-"`
|
||||
models.ControlBy
|
||||
models.ModelTime
|
||||
}
|
||||
|
||||
@@ -19,6 +19,5 @@ func registerSysApiRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddlew
|
||||
{
|
||||
r.GET("", api.GetPage)
|
||||
r.GET("/:id", api.Get)
|
||||
r.PUT("/:id", api.Update)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,5 @@ func registerSysLoginLogRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMi
|
||||
{
|
||||
r.GET("", api.GetPage)
|
||||
r.GET("/:id", api.Get)
|
||||
r.DELETE("", api.Delete)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,6 @@ func registerSysMenuRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddle
|
||||
{
|
||||
r.GET("", api.GetPage)
|
||||
r.GET("/:id", api.Get)
|
||||
r.POST("", api.Insert)
|
||||
r.PUT("/:id", api.Update)
|
||||
r.DELETE("", api.Delete)
|
||||
}
|
||||
|
||||
r1 := v1.Group("").Use(authMiddleware.MiddlewareFunc())
|
||||
|
||||
@@ -26,6 +26,5 @@ func registerSysRoleRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddle
|
||||
r1 := v1.Group("").Use(authMiddleware.MiddlewareFunc())
|
||||
{
|
||||
r1.PUT("/role-status", api.Update2Status)
|
||||
r1.PUT("/roledatascope", api.Update2DataScope)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,15 @@ func TestSystemRouterExposesLoginWithoutCaptcha(t *testing.T) {
|
||||
t.Fatalf("system route is not registered: %s", path)
|
||||
}
|
||||
}
|
||||
for _, path := range []string{
|
||||
"POST /api/v1/menu", "PUT /api/v1/menu/:id", "DELETE /api/v1/menu",
|
||||
"PUT /api/v1/sys-api/:id", "DELETE /api/v1/sys-login-log",
|
||||
"PUT /api/v1/roledatascope",
|
||||
} {
|
||||
if _, ok := routes[path]; ok {
|
||||
t.Fatalf("read-only system route must not be registered: %s", path)
|
||||
}
|
||||
}
|
||||
for _, path := range []string{"GET /api/v1/captcha", "GET /api/v1/getCaptcha"} {
|
||||
if _, ok := routes[path]; ok {
|
||||
t.Fatalf("captcha route must not be registered: %s", path)
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
|
||||
"git.ilapage.cn/OPC/chorus/admin/app/admin/models"
|
||||
)
|
||||
|
||||
func TestProtectAdminRemovalRejectsCurrentAndLastActiveAdmin(t *testing.T) {
|
||||
db, err := gorm.Open(sqlite.Open("file:"+t.Name()+"?mode=memory&cache=shared"), &gorm.Config{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := db.AutoMigrate(&models.SysUser{}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
admin := models.SysUser{UserId: 1, Username: "admin", Status: "2"}
|
||||
if err := db.Create(&admin).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := protectAdminRemoval(db, []models.SysUser{admin}, 1); !errors.Is(err, ErrCurrentAdminProtected) {
|
||||
t.Fatalf("current admin error = %v", err)
|
||||
}
|
||||
if err := protectAdminRemoval(db, []models.SysUser{admin}, 99); !errors.Is(err, ErrLastAdminProtected) {
|
||||
t.Fatalf("last active admin error = %v", err)
|
||||
}
|
||||
|
||||
second := models.SysUser{UserId: 2, Username: "operator", Status: "2"}
|
||||
if err := db.Create(&second).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := protectAdminRemoval(db, []models.SysUser{second}, 1); err != nil {
|
||||
t.Fatalf("removing one of two active admins: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestProtectBuiltInRole(t *testing.T) {
|
||||
role := models.SysRole{RoleId: 1, RoleName: "Chorus Operator", RoleKey: BuiltInOperatorRoleKey, Status: "2"}
|
||||
for name, test := range map[string]struct {
|
||||
roleName string
|
||||
roleKey string
|
||||
status string
|
||||
op string
|
||||
}{
|
||||
"rename display name": {"Other", BuiltInOperatorRoleKey, "2", "update"},
|
||||
"rename key": {role.RoleName, "other", "2", "update"},
|
||||
"disable": {role.RoleName, BuiltInOperatorRoleKey, "1", "status"},
|
||||
"delete": {"", "", "", "delete"},
|
||||
} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
if err := protectBuiltInRole(role, test.roleName, test.roleKey, test.status, test.op); !errors.Is(err, ErrBuiltInRoleProtected) {
|
||||
t.Fatalf("error = %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
if err := protectBuiltInRole(role, role.RoleName, role.RoleKey, "2", "update"); err != nil {
|
||||
t.Fatalf("menu-only update should remain allowed: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -12,13 +12,8 @@ type SysUserGetPageReq struct {
|
||||
UserId int `form:"userId" search:"type:exact;column:user_id;table:sys_user" comment:"用户ID"`
|
||||
Username string `form:"username" search:"type:contains;column:username;table:sys_user" comment:"用户名"`
|
||||
NickName string `form:"nickName" search:"type:contains;column:nick_name;table:sys_user" comment:"昵称"`
|
||||
Phone string `form:"phone" search:"type:contains;column:phone;table:sys_user" comment:"手机号"`
|
||||
RoleId string `form:"roleId" search:"type:exact;column:role_id;table:sys_user" comment:"角色ID"`
|
||||
Sex string `form:"sex" search:"type:exact;column:sex;table:sys_user" comment:"性别"`
|
||||
Email string `form:"email" search:"type:contains;column:email;table:sys_user" comment:"邮箱"`
|
||||
PostId string `form:"postId" search:"type:exact;column:post_id;table:sys_user" comment:"岗位"`
|
||||
Status string `form:"status" search:"type:exact;column:status;table:sys_user" comment:"状态"`
|
||||
DeptJoin `search:"type:left;on:dept_id:dept_id;table:sys_user;join:sys_dept"`
|
||||
SysUserOrder
|
||||
}
|
||||
|
||||
@@ -29,10 +24,6 @@ type SysUserOrder struct {
|
||||
CreatedAtOrder string `search:"type:order;column:created_at;table:sys_user" form:"createdAtOrder"`
|
||||
}
|
||||
|
||||
type DeptJoin struct {
|
||||
DeptId string `search:"type:contains;column:dept_path;table:sys_dept" form:"deptId"`
|
||||
}
|
||||
|
||||
func (m *SysUserGetPageReq) GetNeedSearch() interface{} {
|
||||
return *m
|
||||
}
|
||||
@@ -93,13 +84,7 @@ type SysUserInsertReq struct {
|
||||
Username string `json:"username" comment:"用户名" vd:"len($)>0"`
|
||||
Password string `json:"password" comment:"密码"`
|
||||
NickName string `json:"nickName" comment:"昵称" vd:"len($)>0"`
|
||||
Phone string `json:"phone" comment:"手机号" vd:"len($)>0"`
|
||||
RoleId int `json:"roleId" comment:"角色ID"`
|
||||
Avatar string `json:"avatar" comment:"头像"`
|
||||
Sex string `json:"sex" comment:"性别"`
|
||||
Email string `json:"email" comment:"邮箱" vd:"len($)>0,email"`
|
||||
DeptId int `json:"deptId" comment:"部门" vd:"$>0"`
|
||||
PostId int `json:"postId" comment:"岗位"`
|
||||
Remark string `json:"remark" comment:"备注"`
|
||||
Status string `json:"status" comment:"状态" vd:"len($)>0" default:"1"`
|
||||
common.ControlBy
|
||||
@@ -112,13 +97,7 @@ func (s *SysUserInsertReq) Generate(model *models.SysUser) {
|
||||
model.Username = s.Username
|
||||
model.Password = s.Password
|
||||
model.NickName = s.NickName
|
||||
model.Phone = s.Phone
|
||||
model.RoleId = s.RoleId
|
||||
model.Avatar = s.Avatar
|
||||
model.Sex = s.Sex
|
||||
model.Email = s.Email
|
||||
model.DeptId = s.DeptId
|
||||
model.PostId = s.PostId
|
||||
model.Remark = s.Remark
|
||||
model.Status = s.Status
|
||||
model.CreateBy = s.CreateBy
|
||||
@@ -132,15 +111,8 @@ type SysUserUpdateReq struct {
|
||||
UserId int `json:"userId" comment:"用户ID"` // 用户ID
|
||||
Username string `json:"username" comment:"用户名" vd:"len($)>0"`
|
||||
NickName string `json:"nickName" comment:"昵称" vd:"len($)>0"`
|
||||
Phone string `json:"phone" comment:"手机号" vd:"len($)>0"`
|
||||
RoleId int `json:"roleId" comment:"角色ID"`
|
||||
Avatar string `json:"avatar" comment:"头像"`
|
||||
Sex string `json:"sex" comment:"性别"`
|
||||
Email string `json:"email" comment:"邮箱" vd:"len($)>0,email"`
|
||||
DeptId int `json:"deptId" comment:"部门" vd:"$>0"`
|
||||
PostId int `json:"postId" comment:"岗位"`
|
||||
Remark string `json:"remark" comment:"备注"`
|
||||
Status string `json:"status" comment:"状态" default:"1"`
|
||||
common.ControlBy
|
||||
}
|
||||
|
||||
@@ -150,15 +122,8 @@ func (s *SysUserUpdateReq) Generate(model *models.SysUser) {
|
||||
}
|
||||
model.Username = s.Username
|
||||
model.NickName = s.NickName
|
||||
model.Phone = s.Phone
|
||||
model.RoleId = s.RoleId
|
||||
model.Avatar = s.Avatar
|
||||
model.Sex = s.Sex
|
||||
model.Email = s.Email
|
||||
model.DeptId = s.DeptId
|
||||
model.PostId = s.PostId
|
||||
model.Remark = s.Remark
|
||||
model.Status = s.Status
|
||||
}
|
||||
|
||||
func (s *SysUserUpdateReq) GetId() interface{} {
|
||||
|
||||
@@ -20,6 +20,29 @@ type SysRole struct {
|
||||
service.Service
|
||||
}
|
||||
|
||||
const BuiltInOperatorRoleKey = "chorus_operator"
|
||||
|
||||
var ErrBuiltInRoleProtected = errors.New("ADMIN_BUILT_IN_ROLE_PROTECTED: 内置角色不能改名、删除或停用")
|
||||
|
||||
func protectBuiltInRole(role models.SysRole, roleName, roleKey, status, operation string) error {
|
||||
if role.RoleKey != BuiltInOperatorRoleKey {
|
||||
return nil
|
||||
}
|
||||
switch operation {
|
||||
case "update":
|
||||
if roleName != role.RoleName || roleKey != role.RoleKey || status != "2" {
|
||||
return ErrBuiltInRoleProtected
|
||||
}
|
||||
case "delete":
|
||||
return ErrBuiltInRoleProtected
|
||||
case "status":
|
||||
if status != "2" {
|
||||
return ErrBuiltInRoleProtected
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetPage 获取SysRole列表
|
||||
func (e *SysRole) GetPage(c *dto.SysRoleGetPageReq, list *[]models.SysRole, count *int64) error {
|
||||
var err error
|
||||
@@ -143,7 +166,12 @@ func (e *SysRole) Update(c *dto.SysRoleUpdateReq, cb *casbin.SyncedEnforcer) err
|
||||
}
|
||||
var model = models.SysRole{}
|
||||
var mlist = make([]models.SysMenu, 0)
|
||||
tx.Preload("SysMenu").First(&model, c.GetId())
|
||||
if err = tx.Preload("SysMenu").First(&model, c.GetId()).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err = protectBuiltInRole(model, c.RoleName, c.RoleKey, c.Status, "update"); err != nil {
|
||||
return err
|
||||
}
|
||||
tx.Preload("SysApi").Where("menu_id in ?", c.MenuIds).Find(&mlist)
|
||||
err = tx.Model(&model).Association("SysMenu").Delete(model.SysMenu)
|
||||
if err != nil {
|
||||
@@ -206,8 +234,19 @@ func (e *SysRole) Remove(c *dto.SysRoleDeleteReq, cb *casbin.SyncedEnforcer) err
|
||||
}
|
||||
}()
|
||||
}
|
||||
var roles []models.SysRole
|
||||
if err = tx.Where("role_id IN ?", c.Ids).Find(&roles).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
for _, role := range roles {
|
||||
if err = protectBuiltInRole(role, "", "", "", "delete"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
var model = models.SysRole{}
|
||||
tx.Preload("SysMenu").Preload("SysDept").First(&model, c.GetId())
|
||||
if err = tx.Preload("SysMenu").Preload("SysDept").First(&model, c.GetId()).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
//删除 SysRole 时,同时删除角色所有 关联其它表 记录 (SysMenu 和 SysMenu)
|
||||
db := tx.Select(clause.Associations).Delete(&model)
|
||||
|
||||
@@ -295,7 +334,12 @@ func (e *SysRole) UpdateStatus(c *dto.UpdateStatusReq) error {
|
||||
}()
|
||||
}
|
||||
var model = models.SysRole{}
|
||||
tx.First(&model, c.GetId())
|
||||
if err = tx.First(&model, c.GetId()).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err = protectBuiltInRole(model, model.RoleName, model.RoleKey, c.Status, "status"); err != nil {
|
||||
return err
|
||||
}
|
||||
c.Generate(&model)
|
||||
// 更新关联的数据,使用 FullSaveAssociations 模式
|
||||
db := tx.Session(&gorm.Session{FullSaveAssociations: true}).Debug().Save(&model)
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/go-admin-team/go-admin-core/sdk/pkg"
|
||||
"github.com/go-admin-team/go-admin-core/sdk/service"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/clause"
|
||||
|
||||
"git.ilapage.cn/OPC/chorus/admin/common/actions"
|
||||
cDto "git.ilapage.cn/OPC/chorus/admin/common/dto"
|
||||
@@ -18,12 +19,17 @@ type SysUser struct {
|
||||
service.Service
|
||||
}
|
||||
|
||||
var (
|
||||
ErrCurrentAdminProtected = errors.New("ADMIN_CURRENT_ACCOUNT_PROTECTED: 不能停用或删除当前登录管理员")
|
||||
ErrLastAdminProtected = errors.New("ADMIN_LAST_ACTIVE_ACCOUNT_PROTECTED: 至少保留一个有效管理员")
|
||||
)
|
||||
|
||||
// GetPage 获取SysUser列表
|
||||
func (e *SysUser) GetPage(c *dto.SysUserGetPageReq, p *actions.DataPermission, list *[]models.SysUser, count *int64) error {
|
||||
var err error
|
||||
var data models.SysUser
|
||||
|
||||
err = e.Orm.Debug().Preload("Dept").
|
||||
err = e.Orm.Debug().
|
||||
Scopes(
|
||||
cDto.MakeCondition(c.GetNeedSearch()),
|
||||
cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
|
||||
@@ -136,26 +142,21 @@ func (e *SysUser) UpdateAvatar(c *dto.UpdateSysUserAvatarReq, p *actions.DataPer
|
||||
}
|
||||
|
||||
// UpdateStatus 更新用户状态
|
||||
func (e *SysUser) UpdateStatus(c *dto.UpdateSysUserStatusReq, p *actions.DataPermission) error {
|
||||
var err error
|
||||
var model models.SysUser
|
||||
db := e.Orm.Scopes(
|
||||
actions.Permission(model.TableName(), p),
|
||||
).First(&model, c.GetId())
|
||||
if err = db.Error; err != nil {
|
||||
e.Log.Errorf("Service UpdateSysUser error: %s", err)
|
||||
return err
|
||||
}
|
||||
if db.RowsAffected == 0 {
|
||||
return errors.New("无权更新该数据")
|
||||
|
||||
}
|
||||
err = e.Orm.Table(model.TableName()).Where("user_id =? ", c.UserId).Updates(c).Error
|
||||
if err != nil {
|
||||
e.Log.Errorf("Service UpdateSysUser error: %s", err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
func (e *SysUser) UpdateStatus(c *dto.UpdateSysUserStatusReq, p *actions.DataPermission, currentUserID int) error {
|
||||
return e.Orm.Transaction(func(tx *gorm.DB) error {
|
||||
var model models.SysUser
|
||||
if err := tx.Scopes(actions.Permission(model.TableName(), p)).First(&model, c.GetId()).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if c.Status != "2" {
|
||||
if err := protectAdminRemoval(tx, []models.SysUser{model}, currentUserID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return tx.Model(&model).Select("status", "update_by").Updates(map[string]interface{}{
|
||||
"status": c.Status, "update_by": c.UpdateBy,
|
||||
}).Error
|
||||
})
|
||||
}
|
||||
|
||||
// ResetPwd 重置用户密码
|
||||
@@ -182,20 +183,50 @@ func (e *SysUser) ResetPwd(c *dto.ResetSysUserPwdReq, p *actions.DataPermission)
|
||||
}
|
||||
|
||||
// Remove 删除SysUser
|
||||
func (e *SysUser) Remove(c *dto.SysUserById, p *actions.DataPermission) error {
|
||||
var err error
|
||||
var data models.SysUser
|
||||
func (e *SysUser) Remove(c *dto.SysUserById, p *actions.DataPermission, currentUserID int) error {
|
||||
return e.Orm.Transaction(func(tx *gorm.DB) error {
|
||||
var targets []models.SysUser
|
||||
if err := tx.Scopes(actions.Permission((&models.SysUser{}).TableName(), p)).
|
||||
Where("user_id IN ?", normalizedUserIDs(c)).Find(&targets).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if len(targets) == 0 {
|
||||
return errors.New("无权删除该数据")
|
||||
}
|
||||
if err := protectAdminRemoval(tx, targets, currentUserID); err != nil {
|
||||
return err
|
||||
}
|
||||
return tx.Delete(&models.SysUser{}, normalizedUserIDs(c)).Error
|
||||
})
|
||||
}
|
||||
|
||||
db := e.Orm.Model(&data).
|
||||
Scopes(
|
||||
actions.Permission(data.TableName(), p),
|
||||
).Delete(&data, c.GetId())
|
||||
if err = db.Error; err != nil {
|
||||
e.Log.Errorf("Error found in RemoveSysUser : %s", err)
|
||||
func normalizedUserIDs(c *dto.SysUserById) []int {
|
||||
ids := append([]int(nil), c.Ids...)
|
||||
if c.Id > 0 {
|
||||
ids = append(ids, c.Id)
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
func protectAdminRemoval(tx *gorm.DB, targets []models.SysUser, currentUserID int) error {
|
||||
activeTargets := 0
|
||||
for _, target := range targets {
|
||||
if target.UserId == currentUserID {
|
||||
return ErrCurrentAdminProtected
|
||||
}
|
||||
if target.Status == "2" {
|
||||
activeTargets++
|
||||
}
|
||||
}
|
||||
if activeTargets == 0 {
|
||||
return nil
|
||||
}
|
||||
var active []models.SysUser
|
||||
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where("status = ?", "2").Find(&active).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if db.RowsAffected == 0 {
|
||||
return errors.New("无权删除该数据")
|
||||
if len(active)-activeTargets < 1 {
|
||||
return ErrLastAdminProtected
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -248,8 +279,8 @@ func (e *SysUser) UpdatePwd(id int, oldPassword, newPassword string, p *actions.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *SysUser) GetProfile(c *dto.SysUserById, user *models.SysUser, roles *[]models.SysRole, posts *[]models.SysPost) error {
|
||||
err := e.Orm.Preload("Dept").First(user, c.GetId()).Error
|
||||
func (e *SysUser) GetProfile(c *dto.SysUserById, user *models.SysUser, roles *[]models.SysRole) error {
|
||||
err := e.Orm.First(user, c.GetId()).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -257,10 +288,5 @@ func (e *SysUser) GetProfile(c *dto.SysUserById, user *models.SysUser, roles *[]
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = e.Orm.Find(posts, user.PostIds).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user