feat: 优化web
This commit is contained in:
@@ -0,0 +1,240 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"giter.top/smart/internal/iam/entity"
|
||||
"giter.top/smart/internal/iam/repository"
|
||||
"giter.top/smart/pkg/utils/id"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
// UserService 用户
|
||||
type UserService interface {
|
||||
Create(ctx context.Context, tenantID string, req *CreateUserRequest) (*entity.User, error)
|
||||
Update(ctx context.Context, tenantID string, uid string, req *UpdateUserRequest) (*entity.User, error)
|
||||
Delete(ctx context.Context, tenantID string, ids []string) error
|
||||
Get(ctx context.Context, tenantID string, uid string) (*entity.User, error)
|
||||
List(ctx context.Context, tenantID string, q *UserListQuery) (*UserListResponse, error)
|
||||
DataScopeForUser(ctx context.Context, userID string) (int16, error)
|
||||
}
|
||||
|
||||
type CreateUserRequest struct {
|
||||
UserName string `json:"user_name" binding:"required,max=64"`
|
||||
Password string `json:"password" binding:"required,min=6,max=64"`
|
||||
RealName string `json:"real_name" binding:"max=64"`
|
||||
Phone string `json:"phone"`
|
||||
Email string `json:"email"`
|
||||
DeptID *string `json:"dept_id"`
|
||||
DeptIDs []string `json:"dept_ids"`
|
||||
RoleIDs []string `json:"role_ids"`
|
||||
}
|
||||
|
||||
type UpdateUserRequest struct {
|
||||
RealName *string `json:"real_name"`
|
||||
Phone *string `json:"phone"`
|
||||
Email *string `json:"email"`
|
||||
DeptID *string `json:"dept_id"`
|
||||
DeptIDs []string `json:"dept_ids"`
|
||||
RoleIDs []string `json:"role_ids"`
|
||||
Status *int16 `json:"status"`
|
||||
Password *string `json:"password"`
|
||||
}
|
||||
|
||||
type UserListQuery struct {
|
||||
DeptID *string
|
||||
RoleID *string
|
||||
Keyword string
|
||||
Status *int16
|
||||
Page int
|
||||
PageSize int
|
||||
}
|
||||
|
||||
type UserListResponse struct {
|
||||
Items []entity.User `json:"items"`
|
||||
Total int64 `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
TotalPages int `json:"total_pages"`
|
||||
}
|
||||
|
||||
type userService struct {
|
||||
users repository.UserRepository
|
||||
roles repository.RoleRepository
|
||||
}
|
||||
|
||||
func NewUserService(users repository.UserRepository, roles repository.RoleRepository) UserService {
|
||||
return &userService{users: users, roles: roles}
|
||||
}
|
||||
|
||||
func (s *userService) Create(ctx context.Context, tenantID string, req *CreateUserRequest) (*entity.User, error) {
|
||||
ok, err := s.users.ExistsUserName(ctx, tenantID, req.UserName, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ok {
|
||||
return nil, fmt.Errorf("账号已存在")
|
||||
}
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u := &entity.User{
|
||||
ID: id.New(),
|
||||
TenantID: tenantID,
|
||||
UserName: req.UserName,
|
||||
RealName: req.RealName,
|
||||
Phone: req.Phone,
|
||||
Email: req.Email,
|
||||
PasswordHash: string(hash),
|
||||
Status: 1,
|
||||
}
|
||||
if req.DeptID != nil {
|
||||
u.DeptID = req.DeptID
|
||||
}
|
||||
if err := s.users.Create(ctx, u); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
depts := req.DeptIDs
|
||||
primary := ""
|
||||
if req.DeptID != nil {
|
||||
primary = *req.DeptID
|
||||
}
|
||||
if len(depts) == 0 && primary != "" {
|
||||
depts = []string{primary}
|
||||
}
|
||||
if len(depts) > 0 {
|
||||
if primary == "" {
|
||||
primary = depts[0]
|
||||
}
|
||||
u.DeptID = &primary
|
||||
_ = s.users.Update(ctx, u)
|
||||
if err := s.users.ReplaceUserDepts(ctx, u.ID, primary, depts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if len(req.RoleIDs) > 0 {
|
||||
if err := s.users.ReplaceUserRoles(ctx, u.ID, req.RoleIDs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return u, nil
|
||||
}
|
||||
|
||||
func (s *userService) Update(ctx context.Context, tenantID string, uid string, req *UpdateUserRequest) (*entity.User, error) {
|
||||
u, err := s.users.GetByID(ctx, uid)
|
||||
if err != nil {
|
||||
if errors.Is(err, repository.ErrNotFound) {
|
||||
return nil, fmt.Errorf("用户不存在")
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if u.TenantID != tenantID {
|
||||
return nil, fmt.Errorf("用户不属于当前租户")
|
||||
}
|
||||
if req.RealName != nil {
|
||||
u.RealName = *req.RealName
|
||||
}
|
||||
if req.Phone != nil {
|
||||
u.Phone = *req.Phone
|
||||
}
|
||||
if req.Email != nil {
|
||||
u.Email = *req.Email
|
||||
}
|
||||
if req.Status != nil {
|
||||
u.Status = *req.Status
|
||||
}
|
||||
if req.Password != nil && *req.Password != "" {
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(*req.Password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u.PasswordHash = string(hash)
|
||||
}
|
||||
if err := s.users.Update(ctx, u); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if req.DeptIDs != nil || req.DeptID != nil {
|
||||
depts := req.DeptIDs
|
||||
primary := ""
|
||||
if req.DeptID != nil {
|
||||
primary = *req.DeptID
|
||||
u.DeptID = req.DeptID
|
||||
_ = s.users.Update(ctx, u)
|
||||
}
|
||||
if len(depts) == 0 && primary != "" {
|
||||
depts = []string{primary}
|
||||
}
|
||||
if primary == "" && len(depts) > 0 {
|
||||
primary = depts[0]
|
||||
}
|
||||
if err := s.users.ReplaceUserDepts(ctx, u.ID, primary, depts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if req.RoleIDs != nil {
|
||||
if err := s.users.ReplaceUserRoles(ctx, u.ID, req.RoleIDs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return u, nil
|
||||
}
|
||||
|
||||
func (s *userService) Delete(ctx context.Context, tenantID string, ids []string) error {
|
||||
for _, uid := range ids {
|
||||
u, err := s.users.GetByID(ctx, uid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if u.TenantID != tenantID {
|
||||
return fmt.Errorf("用户 %s 不属于当前租户", uid)
|
||||
}
|
||||
if err := s.users.Delete(ctx, uid); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *userService) Get(ctx context.Context, tenantID string, uid string) (*entity.User, error) {
|
||||
u, err := s.users.GetByID(ctx, uid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if u.TenantID != tenantID {
|
||||
return nil, fmt.Errorf("用户不属于当前租户")
|
||||
}
|
||||
return u, nil
|
||||
}
|
||||
|
||||
func (s *userService) List(ctx context.Context, tenantID string, q *UserListQuery) (*UserListResponse, error) {
|
||||
if q.Page <= 0 {
|
||||
q.Page = 1
|
||||
}
|
||||
if q.PageSize <= 0 {
|
||||
q.PageSize = 10
|
||||
}
|
||||
rows, total, err := s.users.List(ctx, tenantID, q.DeptID, q.RoleID, q.Keyword, q.Status, q.Page, q.PageSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tp := int(total) / q.PageSize
|
||||
if int(total)%q.PageSize != 0 {
|
||||
tp++
|
||||
}
|
||||
return &UserListResponse{Items: rows, Total: total, Page: q.Page, PageSize: q.PageSize, TotalPages: tp}, nil
|
||||
}
|
||||
|
||||
func (s *userService) DataScopeForUser(ctx context.Context, userID string) (int16, error) {
|
||||
roles, err := s.roles.ListRolesByUser(ctx, userID)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
scopes := make([]int16, 0, len(roles))
|
||||
for _, r := range roles {
|
||||
scopes = append(scopes, r.DataScope)
|
||||
}
|
||||
return MergeDataScope(scopes), nil
|
||||
}
|
||||
Reference in New Issue
Block a user