package service import ( "context" "database/sql" "fmt" "time" "github.com/google/uuid" "github.com/ocdp/cluster-service/internal/domain/entity" "github.com/ocdp/cluster-service/internal/domain/repository" ) // UserManagementService 用户管理领域服务(仅 Admin 可用) type UserManagementService struct { userRepo repository.UserRepository workspaceRepo repository.WorkspaceRepository passwordHasher PasswordHasher } // NewUserManagementService 创建用户管理服务 func NewUserManagementService( userRepo repository.UserRepository, workspaceRepo repository.WorkspaceRepository, passwordHasher PasswordHasher, ) *UserManagementService { return &UserManagementService{ userRepo: userRepo, workspaceRepo: workspaceRepo, passwordHasher: passwordHasher, } } // CreateUser 创建用户(Admin 操作) func (s *UserManagementService) CreateUser(ctx context.Context, username, password, email, role string, workspaceID string) (*entity.User, error) { // 检查用户是否已存在 existing, _ := s.userRepo.GetByUsername(ctx, username) if existing != nil { return nil, entity.ErrUserExists } // 验证角色 if role != string(entity.RoleAdmin) && role != string(entity.RoleUser) { return nil, fmt.Errorf("invalid role: %s", role) } // 如果指定了 workspace,验证 workspace 存在 if workspaceID != "" { _, err := s.workspaceRepo.GetByID(ctx, workspaceID) if err != nil { if err == entity.ErrWorkspaceNotFound { return nil, entity.ErrWorkspaceNotFound } return nil, err } } // Admin 不能分配到 workspace if role == string(entity.RoleAdmin) && workspaceID != "" { workspaceID = "" } // 哈希密码 passwordHash, err := s.passwordHasher.Hash(password) if err != nil { return nil, err } // 生成占位邮箱 if email == "" { email = username + "@local.ocdp" } // 创建用户 user := entity.NewUser(username, passwordHash, email) user.ID = uuid.New().String() user.Role = entity.UserRole(role) user.WorkspaceID = workspaceID user.IsActive = true user.MustChangePassword = true // 首次登录必须修改密码 if err := user.Validate(); err != nil { return nil, err } if err := s.userRepo.Create(ctx, user); err != nil { return nil, err } return user, nil } // GetUser 获取用户 func (s *UserManagementService) GetUser(ctx context.Context, id string) (*entity.User, error) { return s.userRepo.GetByID(ctx, id) } // ListUsers 列出用户(可筛选 workspace) func (s *UserManagementService) ListUsers(ctx context.Context, workspaceID string) ([]*entity.User, error) { if workspaceID != "" { return s.userRepo.ListByWorkspace(ctx, workspaceID) } return s.userRepo.List(ctx) } // UpdateUser 更新用户信息 func (s *UserManagementService) UpdateUser(ctx context.Context, user *entity.User) error { return s.userRepo.Update(ctx, user) } // SetUserActive 启用/禁用用户 func (s *UserManagementService) SetUserActive(ctx context.Context, userID string, isActive bool) error { user, err := s.userRepo.GetByID(ctx, userID) if err != nil { return err } user.IsActive = isActive return s.userRepo.Update(ctx, user) } // ChangeUserWorkspace 分配用户到 workspace func (s *UserManagementService) ChangeUserWorkspace(ctx context.Context, userID, workspaceID string) error { user, err := s.userRepo.GetByID(ctx, userID) if err != nil { return err } // Admin 不能分配到 workspace if user.Role == entity.RoleAdmin { return fmt.Errorf("admin user cannot be assigned to workspace") } // 验证 workspace 存在 if workspaceID != "" { _, err := s.workspaceRepo.GetByID(ctx, workspaceID) if err != nil { if err == sql.ErrNoRows || err == entity.ErrWorkspaceNotFound { return entity.ErrWorkspaceNotFound } return err } } user.WorkspaceID = workspaceID return s.userRepo.Update(ctx, user) } // ResetPassword 重置用户密码(Admin 操作) func (s *UserManagementService) ResetPassword(ctx context.Context, userID, newPassword string) error { user, err := s.userRepo.GetByID(ctx, userID) if err != nil { return err } // 哈希新密码 passwordHash, err := s.passwordHasher.Hash(newPassword) if err != nil { return err } // 更新密码并设置必须修改密码标志 user.PasswordHash = passwordHash user.MustChangePassword = true user.RevokeAllTokens() // 强制登出所有会话 return s.userRepo.Update(ctx, user) } // DeleteUser 删除用户 func (s *UserManagementService) DeleteUser(ctx context.Context, id string) error { return s.userRepo.Delete(ctx, id) } // GetUserWithWorkspace 获取用户及其 workspace 信息 type UserWithWorkspace struct { User *entity.User Workspace *entity.Workspace } // GetUserWithWorkspace 获取用户及其 workspace 信息 func (s *UserManagementService) GetUserWithWorkspace(ctx context.Context, userID string) (*UserWithWorkspace, error) { user, err := s.userRepo.GetByID(ctx, userID) if err != nil { return nil, err } result := &UserWithWorkspace{ User: user, } if user.WorkspaceID != "" { workspace, _ := s.workspaceRepo.GetByID(ctx, user.WorkspaceID) result.Workspace = workspace } return result, nil } // ListUsersWithWorkspace 列出用户及其 workspace 信息 func (s *UserManagementService) ListUsersWithWorkspace(ctx context.Context) ([]*UserWithWorkspace, error) { users, err := s.userRepo.List(ctx) if err != nil { return nil, err } // 预加载所有 workspace workspaces, err := s.workspaceRepo.List(ctx) if err != nil { return nil, err } workspaceMap := make(map[string]*entity.Workspace) for _, w := range workspaces { workspaceMap[w.ID] = w } result := make([]*UserWithWorkspace, len(users)) for i, user := range users { result[i] = &UserWithWorkspace{ User: user, } if user.WorkspaceID != "" { result[i].Workspace = workspaceMap[user.WorkspaceID] } } return result, nil } // EnsureAdminExists 确保存在一个 Admin 用户 func (s *UserManagementService) EnsureAdminExists(ctx context.Context, defaultPassword string) error { users, err := s.userRepo.List(ctx) if err != nil { return err } // 检查是否已有 admin for _, u := range users { if u.Role == entity.RoleAdmin { return nil } } // 创建默认 admin 用户 _, err = s.CreateUser(ctx, "admin", defaultPassword, "", string(entity.RoleAdmin), "") return err } // CreateInitialUser 创建初始用户(首次启动时调用) func (s *UserManagementService) CreateInitialUser(ctx context.Context, username, password, role string) (*entity.User, error) { // 检查是否已有用户 users, err := s.userRepo.List(ctx) if err != nil { return nil, err } if len(users) > 0 { return nil, fmt.Errorf("initial user already exists") } // 验证角色 if role != string(entity.RoleAdmin) && role != string(entity.RoleUser) { return nil, fmt.Errorf("invalid role: %s", role) } // 哈希密码 passwordHash, err := s.passwordHasher.Hash(password) if err != nil { return nil, err } // 生成占位邮箱 email := username + "@local.ocdp" // 创建用户 user := entity.NewUser(username, passwordHash, email) user.ID = uuid.New().String() user.Role = entity.UserRole(role) // workspace_id 为 NULL(admin)或空(首个普通用户) user.IsActive = true user.MustChangePassword = false // 初始用户不需要强制修改密码 if err := user.Validate(); err != nil { return nil, err } // 设置创建时间和更新时间 now := time.Now() user.CreatedAt = now user.UpdatedAt = now if err := s.userRepo.Create(ctx, user); err != nil { return nil, err } return user, nil }