更新前后端代码
This commit is contained in:
@@ -0,0 +1,258 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
||||
"filestoragesystem/internal/config"
|
||||
"filestoragesystem/internal/model"
|
||||
"filestoragesystem/internal/repository"
|
||||
"filestoragesystem/internal/utils"
|
||||
"filestoragesystem/pkg/apperr"
|
||||
)
|
||||
|
||||
// UserService 用户管理服务(个人资料 + 管理员用户管理)
|
||||
type UserService struct {
|
||||
cfg *config.Config
|
||||
userRepo *repository.UserRepo
|
||||
roleRepo *repository.RoleRepo
|
||||
settingRepo *repository.SettingRepo
|
||||
opLogRepo *repository.OpLogRepo
|
||||
fileRepo *repository.FileRepo
|
||||
projectRepo *repository.ProjectRepo
|
||||
}
|
||||
|
||||
// GetProfile 获取个人资料
|
||||
func (s *UserService) GetProfile(userID uint) (*model.User, error) {
|
||||
u, err := s.userRepo.FindByID(userID)
|
||||
if err != nil {
|
||||
return nil, apperr.ErrNotFound
|
||||
}
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// UpdateProfile 更新个人资料(邮箱)
|
||||
func (s *UserService) UpdateProfile(userID uint, email string) error {
|
||||
email = strings.TrimSpace(strings.ToLower(email))
|
||||
if email != "" && !utils.IsEmail(email) {
|
||||
return fmt.Errorf("邮箱格式不正确")
|
||||
}
|
||||
if email != "" {
|
||||
if other, err := s.userRepo.FindByEmail(email); err == nil && other.ID != userID {
|
||||
return apperr.ErrUserExists
|
||||
}
|
||||
return s.userRepo.UpdateFields(userID, map[string]interface{}{"email": email})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ChangePassword 修改自己的密码
|
||||
func (s *UserService) ChangePassword(userID uint, oldPwd, newPwd string) error {
|
||||
if !utils.IsValidPassword(newPwd) {
|
||||
return fmt.Errorf("新密码至少8位且需包含字母和数字")
|
||||
}
|
||||
u, err := s.userRepo.FindByID(userID)
|
||||
if err != nil {
|
||||
return apperr.ErrNotFound
|
||||
}
|
||||
if !utils.CheckPassword(u.PasswordHash, oldPwd) {
|
||||
return fmt.Errorf("原密码错误")
|
||||
}
|
||||
hash, err := utils.HashPassword(newPwd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.userRepo.UpdateFields(userID, map[string]interface{}{"password_hash": hash})
|
||||
}
|
||||
|
||||
// ---- 管理员操作 ----
|
||||
|
||||
// AdminListUsers 用户列表
|
||||
func (s *UserService) AdminListUsers(keyword, roleID, status string, page, pageSize int) ([]model.User, int64, error) {
|
||||
return s.userRepo.List(keyword, roleID, status, page, pageSize)
|
||||
}
|
||||
|
||||
// AdminGetUser 用户详情
|
||||
func (s *UserService) AdminGetUser(id uint) (*model.User, error) {
|
||||
u, err := s.userRepo.FindByID(id)
|
||||
if err != nil {
|
||||
return nil, apperr.ErrNotFound
|
||||
}
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// AdminCreateUser 管理员创建用户
|
||||
func (s *UserService) AdminCreateUser(username, email, password string, roleID uint, storageLimit int64) (*model.User, error) {
|
||||
username = strings.TrimSpace(username)
|
||||
email = strings.TrimSpace(strings.ToLower(email))
|
||||
if len(username) < 3 {
|
||||
return nil, fmt.Errorf("用户名至少3个字符")
|
||||
}
|
||||
if !utils.IsEmail(email) {
|
||||
return nil, fmt.Errorf("邮箱格式不正确")
|
||||
}
|
||||
if !utils.IsValidPassword(password) {
|
||||
return nil, fmt.Errorf("密码至少8位且需包含字母和数字")
|
||||
}
|
||||
if _, err := s.userRepo.FindByUsername(username); err == nil {
|
||||
return nil, apperr.ErrUserExists
|
||||
}
|
||||
if _, err := s.userRepo.FindByEmail(email); err == nil {
|
||||
return nil, apperr.ErrUserExists
|
||||
}
|
||||
role, err := s.roleRepo.FindByID(roleID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("角色不存在")
|
||||
}
|
||||
if storageLimit <= 0 {
|
||||
storageLimit = 10737418240
|
||||
if v, err := s.settingRepo.GetValue("default_storage_limit"); err == nil {
|
||||
var n int64
|
||||
if _, e := fmt.Sscanf(v, "%d", &n); e == nil && n > 0 {
|
||||
storageLimit = n
|
||||
}
|
||||
}
|
||||
}
|
||||
hash, err := utils.HashPassword(password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u := &model.User{
|
||||
Username: username, Email: email, PasswordHash: hash,
|
||||
RoleID: role.ID, Status: 1, StorageLimit: storageLimit,
|
||||
}
|
||||
if err := s.userRepo.Create(u); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
utils.Info("user", "管理员创建用户: %s", username)
|
||||
return u, nil
|
||||
}
|
||||
|
||||
// AdminUpdateUser 编辑用户(邮箱/角色/配额)
|
||||
func (s *UserService) AdminUpdateUser(id uint, email string, roleID uint, storageLimit int64) (*model.User, error) {
|
||||
u, err := s.userRepo.FindByID(id)
|
||||
if err != nil {
|
||||
return nil, apperr.ErrNotFound
|
||||
}
|
||||
updates := map[string]interface{}{}
|
||||
if email = strings.TrimSpace(strings.ToLower(email)); email != "" {
|
||||
if !utils.IsEmail(email) {
|
||||
return nil, fmt.Errorf("邮箱格式不正确")
|
||||
}
|
||||
if other, err := s.userRepo.FindByEmail(email); err == nil && other.ID != id {
|
||||
return nil, apperr.ErrUserExists
|
||||
}
|
||||
updates["email"] = email
|
||||
}
|
||||
if roleID > 0 {
|
||||
role, err := s.roleRepo.FindByID(roleID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("角色不存在")
|
||||
}
|
||||
// 防止移除最后一个超管
|
||||
if u.Role != nil && u.Role.Code == "super_admin" && role.Code != "super_admin" {
|
||||
if n, _ := s.roleRepo.CountUsersByRole(u.RoleID); n <= 1 {
|
||||
return nil, fmt.Errorf("系统至少需要保留一个超级管理员")
|
||||
}
|
||||
}
|
||||
updates["role_id"] = role.ID
|
||||
}
|
||||
if storageLimit > 0 {
|
||||
updates["storage_limit"] = storageLimit
|
||||
}
|
||||
if len(updates) == 0 {
|
||||
return u, nil
|
||||
}
|
||||
if err := s.userRepo.UpdateFields(id, updates); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.userRepo.FindByID(id)
|
||||
}
|
||||
|
||||
// AdminSetUserStatus 启用/禁用用户
|
||||
func (s *UserService) AdminSetUserStatus(id uint, status int8) error {
|
||||
u, err := s.userRepo.FindByID(id)
|
||||
if err != nil {
|
||||
return apperr.ErrNotFound
|
||||
}
|
||||
if u.Role != nil && u.Role.Code == "super_admin" && status == 0 {
|
||||
if n, _ := s.roleRepo.CountUsersByRole(u.RoleID); n <= 1 {
|
||||
return fmt.Errorf("不能禁用最后一个超级管理员")
|
||||
}
|
||||
}
|
||||
return s.userRepo.UpdateFields(id, map[string]interface{}{"status": status})
|
||||
}
|
||||
|
||||
// AdminAssignRole 修改用户角色
|
||||
func (s *UserService) AdminAssignRole(id, roleID uint) error {
|
||||
role, err := s.roleRepo.FindByID(roleID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("角色不存在")
|
||||
}
|
||||
u, err := s.userRepo.FindByID(id)
|
||||
if err != nil {
|
||||
return apperr.ErrNotFound
|
||||
}
|
||||
if u.Role != nil && u.Role.Code == "super_admin" && role.Code != "super_admin" {
|
||||
if n, _ := s.roleRepo.CountUsersByRole(u.RoleID); n <= 1 {
|
||||
return fmt.Errorf("系统至少需要保留一个超级管理员")
|
||||
}
|
||||
}
|
||||
return s.userRepo.UpdateFields(id, map[string]interface{}{"role_id": role.ID})
|
||||
}
|
||||
|
||||
// AdminResetPassword 重置用户密码
|
||||
func (s *UserService) AdminResetPassword(id uint, newPassword string) error {
|
||||
if !utils.IsValidPassword(newPassword) {
|
||||
return fmt.Errorf("密码至少8位且需包含字母和数字")
|
||||
}
|
||||
hash, err := utils.HashPassword(newPassword)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.userRepo.UpdateFields(id, map[string]interface{}{"password_hash": hash})
|
||||
}
|
||||
|
||||
// AdminDeleteUser 删除用户及其全部数据
|
||||
func (s *UserService) AdminDeleteUser(id uint) error {
|
||||
u, err := s.userRepo.FindByID(id)
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return apperr.ErrNotFound
|
||||
}
|
||||
return err
|
||||
}
|
||||
if u.Role != nil && u.Role.Code == "super_admin" {
|
||||
if n, _ := s.roleRepo.CountUsersByRole(u.RoleID); n <= 1 {
|
||||
return fmt.Errorf("不能删除最后一个超级管理员")
|
||||
}
|
||||
}
|
||||
|
||||
// 删除物理文件
|
||||
files, _ := s.fileRepo.ListByUser(id)
|
||||
seen := make(map[string]bool)
|
||||
for _, f := range files {
|
||||
if f.StoredPath != "" && !seen[f.StoredPath] {
|
||||
seen[f.StoredPath] = true
|
||||
_ = os.Remove(filepath.Join(s.cfg.Storage.Root, f.StoredPath))
|
||||
}
|
||||
}
|
||||
|
||||
// 级联清理(文件/项目/密钥由外键无级联,手动删除)
|
||||
_ = s.fileRepo.DB.Exec("DELETE FROM files WHERE user_id = ?", id).Error
|
||||
_ = s.fileRepo.DB.Exec("DELETE FROM temp_links WHERE user_id = ?", id).Error
|
||||
_ = s.fileRepo.DB.Exec("DELETE FROM projects WHERE user_id = ?", id).Error
|
||||
_ = s.fileRepo.DB.Exec("DELETE FROM api_keys WHERE user_id = ?", id).Error
|
||||
_ = s.fileRepo.DB.Exec("DELETE FROM webhooks WHERE user_id = ?", id).Error
|
||||
_ = s.fileRepo.DB.Exec("DELETE FROM traffic_logs WHERE user_id = ?", id).Error
|
||||
|
||||
if err := s.userRepo.Delete(id); err != nil {
|
||||
return err
|
||||
}
|
||||
utils.Info("user", "管理员删除用户: %s", u.Username)
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user