194 lines
5.6 KiB
Go
194 lines
5.6 KiB
Go
package logic
|
||
|
||
import (
|
||
"context"
|
||
"strconv"
|
||
"strings"
|
||
|
||
"github.com/gogf/gf/v2/errors/gerror"
|
||
"github.com/gogf/gf/v2/frame/g"
|
||
"github.com/gogf/gf/v2/os/gtime"
|
||
"golang.org/x/crypto/bcrypt"
|
||
|
||
v1 "tool-api/api/admin/v1"
|
||
"tool-api/internal/consts"
|
||
)
|
||
|
||
// ============================================================================
|
||
// 管理员账号管理(T17)
|
||
// ============================================================================
|
||
|
||
// AdminList 管理员列表
|
||
func AdminList(ctx context.Context) (*v1.AdminListRes, error) {
|
||
records, err := g.Model(consts.TableAdminUsers).OrderAsc("id").All()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
list := make([]v1.AdminItem, 0, len(records))
|
||
for _, r := range records {
|
||
list = append(list, v1.AdminItem{
|
||
Id: r["id"].Int64(),
|
||
Account: r["account"].String(),
|
||
NickName: r["nick_name"].String(),
|
||
RoleName: r["role_name"].String(),
|
||
RoleValue: r["role_value"].String(),
|
||
Status: r["status"].Int(),
|
||
CreatedAt: r["created_at"].String(),
|
||
})
|
||
}
|
||
return &v1.AdminListRes{List: list}, nil
|
||
}
|
||
|
||
// lastSuperGuard 保护「最后一个启用中的超级管理员」:
|
||
// 若该管理员当前是启用中的超管,而改动后会失去「启用中的超管」身份(降角色或停用),
|
||
// 且库中仅剩这一个,则拒绝——避免把自己锁在门外。
|
||
func lastSuperGuard(ctx context.Context, id int64, newRole string, newStatus int) error {
|
||
rec, err := g.Model(consts.TableAdminUsers).Where("id", id).One()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if rec.IsEmpty() {
|
||
return nil
|
||
}
|
||
isEnabledSuper := rec["role_value"].String() == consts.AdminRoleSuper &&
|
||
rec["status"].Int() == consts.AdminStatusEnabled
|
||
if !isEnabledSuper {
|
||
return nil
|
||
}
|
||
stillSuper := newRole == consts.AdminRoleSuper && newStatus == consts.AdminStatusEnabled
|
||
if stillSuper {
|
||
return nil
|
||
}
|
||
count, err := g.Model(consts.TableAdminUsers).
|
||
Where("role_value", consts.AdminRoleSuper).
|
||
Where("status", consts.AdminStatusEnabled).
|
||
Count()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if count <= 1 {
|
||
return gerror.New("至少保留一个启用中的超级管理员")
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// AdminSave 新增/修改管理员。编辑不清空密码(除非显式传入新密码)。
|
||
func AdminSave(ctx context.Context, req *v1.AdminSaveReq) (*v1.AdminSaveRes, error) {
|
||
if req.Id > 0 {
|
||
rec, err := g.Model(consts.TableAdminUsers).Where("id", req.Id).One()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if rec.IsEmpty() {
|
||
return nil, gerror.New("管理员不存在")
|
||
}
|
||
if err = lastSuperGuard(ctx, req.Id, req.RoleValue, rec["status"].Int()); err != nil {
|
||
return nil, err
|
||
}
|
||
data := g.Map{
|
||
"nick_name": req.NickName,
|
||
"role_name": roleNameOf(req.RoleValue),
|
||
"role_value": req.RoleValue,
|
||
}
|
||
pwdChanged := strings.TrimSpace(req.Password) != ""
|
||
if pwdChanged {
|
||
hash, herr := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
|
||
if herr != nil {
|
||
return nil, herr
|
||
}
|
||
data["password"] = string(hash)
|
||
}
|
||
if _, err = g.Model(consts.TableAdminUsers).Where("id", req.Id).Data(data).Update(); err != nil {
|
||
return nil, err
|
||
}
|
||
WriteAudit(ctx, AuditEntry{
|
||
Action: "admin.update",
|
||
TargetType: "admin",
|
||
TargetId: strconv.FormatInt(req.Id, 10),
|
||
Before: g.Map{
|
||
"nick_name": rec["nick_name"].String(),
|
||
"role_value": rec["role_value"].String(),
|
||
},
|
||
After: g.Map{
|
||
"nick_name": req.NickName,
|
||
"role_value": req.RoleValue,
|
||
"pwd_changed": pwdChanged,
|
||
},
|
||
Result: consts.AuditResultSuccess,
|
||
})
|
||
return &v1.AdminSaveRes{}, nil
|
||
}
|
||
|
||
account := strings.TrimSpace(req.Account)
|
||
if account == "" {
|
||
return nil, gerror.New("请填写登录账号")
|
||
}
|
||
if strings.TrimSpace(req.Password) == "" {
|
||
return nil, gerror.New("请填写登录密码")
|
||
}
|
||
count, err := g.Model(consts.TableAdminUsers).Where("account", account).Count()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if count > 0 {
|
||
return nil, gerror.New("账号已存在")
|
||
}
|
||
hash, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
newId, err := g.Model(consts.TableAdminUsers).Data(g.Map{
|
||
"account": account,
|
||
"password": string(hash),
|
||
"nick_name": req.NickName,
|
||
"role_name": roleNameOf(req.RoleValue),
|
||
"role_value": req.RoleValue,
|
||
"status": consts.AdminStatusEnabled,
|
||
"created_at": gtime.Now(),
|
||
}).InsertAndGetId()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
WriteAudit(ctx, AuditEntry{
|
||
Action: "admin.create",
|
||
TargetType: "admin",
|
||
TargetId: strconv.FormatInt(newId, 10),
|
||
After: g.Map{
|
||
"account": account,
|
||
"nick_name": req.NickName,
|
||
"role_value": req.RoleValue,
|
||
},
|
||
Result: consts.AuditResultSuccess,
|
||
})
|
||
return &v1.AdminSaveRes{}, nil
|
||
}
|
||
|
||
// AdminStatus 启停管理员
|
||
func AdminStatus(ctx context.Context, id int64, status int) (*v1.AdminStatusRes, error) {
|
||
if status != consts.AdminStatusEnabled && status != consts.AdminStatusDisabled {
|
||
return nil, gerror.New("状态非法")
|
||
}
|
||
rec, err := g.Model(consts.TableAdminUsers).Where("id", id).One()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if rec.IsEmpty() {
|
||
return nil, gerror.New("管理员不存在")
|
||
}
|
||
if err = lastSuperGuard(ctx, id, rec["role_value"].String(), status); err != nil {
|
||
return nil, err
|
||
}
|
||
if _, err = g.Model(consts.TableAdminUsers).Where("id", id).Data(g.Map{"status": status}).Update(); err != nil {
|
||
return nil, err
|
||
}
|
||
WriteAudit(ctx, AuditEntry{
|
||
Action: "admin.status",
|
||
TargetType: "admin",
|
||
TargetId: strconv.FormatInt(id, 10),
|
||
Before: g.Map{"status": rec["status"].Int()},
|
||
After: g.Map{"status": status},
|
||
Result: consts.AuditResultSuccess,
|
||
})
|
||
return &v1.AdminStatusRes{}, nil
|
||
}
|