rbac
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
package rbac
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"portal-mini-go/internal/model/admin"
|
||||
"portal-mini-go/internal/pkg/auth"
|
||||
"portal-mini-go/internal/pkg/errors"
|
||||
adminrepo "portal-mini-go/internal/repository/admin"
|
||||
)
|
||||
|
||||
// AdminService 管理员账号业务:CRUD、角色分配、密码重置。
|
||||
type AdminService struct {
|
||||
repo UserRepository
|
||||
invalidator CacheInvalidator
|
||||
}
|
||||
|
||||
func NewAdminService(repo UserRepository, invalidator CacheInvalidator) *AdminService {
|
||||
return &AdminService{repo: repo, invalidator: invalidator}
|
||||
}
|
||||
|
||||
// CreateReq 新建管理员请求。
|
||||
type CreateAdminReq struct {
|
||||
Username string `json:"username" binding:"required"`
|
||||
Nickname string `json:"nickname"`
|
||||
Password string `json:"password" binding:"required"`
|
||||
Status int8 `json:"status"`
|
||||
}
|
||||
|
||||
// Create 新建管理员,用户名唯一,密码以 bcrypt 存储。
|
||||
func (s *AdminService) Create(ctx context.Context, req CreateAdminReq) (*admin.User, error) {
|
||||
if req.Status == 0 {
|
||||
req.Status = admin.UserStatusEnabled
|
||||
}
|
||||
if req.Status != admin.UserStatusEnabled && req.Status != admin.UserStatusDisabled {
|
||||
return nil, errors.New(40000, "非法的管理员状态")
|
||||
}
|
||||
if _, err := s.repo.GetByUsername(ctx, req.Username); err == nil {
|
||||
return nil, errors.New(40900, "用户名已存在")
|
||||
} else if !errors.Is(err, errors.ErrNotFound) {
|
||||
return nil, err
|
||||
}
|
||||
hash, err := auth.HashPassword(req.Password)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(50000, "hash password", err)
|
||||
}
|
||||
u := &admin.User{
|
||||
Username: req.Username,
|
||||
Nickname: req.Nickname,
|
||||
PasswordHash: hash,
|
||||
Status: req.Status,
|
||||
}
|
||||
if err := s.repo.Create(ctx, u); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// AdminListReq 管理员列表过滤条件。
|
||||
type AdminListReq struct {
|
||||
Keyword string
|
||||
Status int8
|
||||
Page int
|
||||
Size int
|
||||
}
|
||||
|
||||
// List 分页查询管理员。
|
||||
func (s *AdminService) List(ctx context.Context, req AdminListReq) ([]admin.User, int64, error) {
|
||||
page, size := req.Page, req.Size
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
if size <= 0 {
|
||||
size = 20
|
||||
}
|
||||
return s.repo.List(ctx, adminrepo.UserListFilter{
|
||||
Keyword: req.Keyword,
|
||||
Status: req.Status,
|
||||
Page: page,
|
||||
Size: size,
|
||||
})
|
||||
}
|
||||
|
||||
// GetByID 按 ID 查询管理员。
|
||||
func (s *AdminService) GetByID(ctx context.Context, id uint64) (*admin.User, error) {
|
||||
return s.repo.GetByID(ctx, id)
|
||||
}
|
||||
|
||||
// UpdateAdminReq 编辑管理员请求;指针区分“未提供”与“置空”。
|
||||
type UpdateAdminReq struct {
|
||||
Nickname *string `json:"nickname"`
|
||||
Status *int8 `json:"status"`
|
||||
}
|
||||
|
||||
// Update 局部更新管理员昵称与状态。
|
||||
func (s *AdminService) Update(ctx context.Context, id uint64, req UpdateAdminReq) (*admin.User, error) {
|
||||
cols := map[string]interface{}{}
|
||||
if req.Nickname != nil {
|
||||
cols["nickname"] = *req.Nickname
|
||||
}
|
||||
if req.Status != nil {
|
||||
if *req.Status != admin.UserStatusEnabled && *req.Status != admin.UserStatusDisabled {
|
||||
return nil, errors.New(40000, "非法的管理员状态")
|
||||
}
|
||||
cols["status"] = *req.Status
|
||||
}
|
||||
if len(cols) == 0 {
|
||||
return s.repo.GetByID(ctx, id)
|
||||
}
|
||||
if err := s.repo.Update(ctx, id, cols); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
s.invalidator.Invalidate(ctx, id)
|
||||
return s.repo.GetByID(ctx, id)
|
||||
}
|
||||
|
||||
// Delete 删除管理员(同时清理其角色关联,并失效缓存)。
|
||||
func (s *AdminService) Delete(ctx context.Context, id uint64) error {
|
||||
if err := s.repo.Delete(ctx, id); err != nil {
|
||||
return err
|
||||
}
|
||||
s.invalidator.Invalidate(ctx, id)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetRoles 为管理员分配角色(全量替换)。
|
||||
func (s *AdminService) SetRoles(ctx context.Context, id uint64, roleIDs []uint64) error {
|
||||
if err := s.repo.SetRoles(ctx, id, roleIDs); err != nil {
|
||||
return err
|
||||
}
|
||||
s.invalidator.Invalidate(ctx, id)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResetPassword 重置管理员密码。
|
||||
func (s *AdminService) ResetPassword(ctx context.Context, id uint64, newPassword string) error {
|
||||
hash, err := auth.HashPassword(newPassword)
|
||||
if err != nil {
|
||||
return errors.Wrap(50000, "hash password", err)
|
||||
}
|
||||
if err := s.repo.Update(ctx, id, map[string]interface{}{"password_hash": hash}); err != nil {
|
||||
return err
|
||||
}
|
||||
s.invalidator.Invalidate(ctx, id)
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user