package service import ( "context" "errors" "strings" "gorm.io/gorm" "ws_usernode/internal/model" "ws_usernode/internal/pkg" "ws_usernode/internal/system" ) // 用户服务错误。 var ( ErrUserNotFound = errors.New("service: 用户不存在") ErrUserExists = errors.New("service: 用户名已存在") ) // UserService 外部用户生命周期服务。 // M0 提供查询与创建骨架;建号(useradd)、禁用/延期等系统操作 M1 接入 system.Manager。 type UserService struct { db *gorm.DB sys system.Manager } // NewUserService 创建用户服务。 func NewUserService(db *gorm.DB, sys system.Manager) *UserService { return &UserService{db: db, sys: sys} } // GetByUsername 按用户名查询外部用户(含或不含 ext_ 前缀均可)。 func (s *UserService) GetByUsername(ctx context.Context, username string) (*model.User, error) { if !strings.HasPrefix(username, "ext_") { username = "ext_" + username } var u model.User if err := s.db.WithContext(ctx).First(&u, "username = ?", username).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, ErrUserNotFound } return nil, err } return &u, nil } // Create 创建外部用户记录并调用系统层建号。M0 阶段系统层为 dry-run。 // username 为不含前缀的申请名,内部加 ext_ 前缀。 func (s *UserService) Create(ctx context.Context, username, email, supervisor, purpose string, ttlSeconds int64) (*model.User, error) { if err := pkg.ValidateUserName(username); err != nil { return nil, err } if err := pkg.ValidateEmail(email); err != nil { return nil, err } full := "ext_" + username var count int64 if err := s.db.WithContext(ctx).Model(&model.User{}).Where("username = ?", full).Count(&count).Error; err != nil { return nil, err } if count > 0 { return nil, ErrUserExists } u := &model.User{ Username: full, Email: email, Supervisor: supervisor, Purpose: purpose, Status: model.UserStatusActive, Shell: "/bin/sh", } if err := s.db.WithContext(ctx).Create(u).Error; err != nil { return nil, err } // 系统账号创建(dry-run / 真实),失败时回滚 DB 记录 if err := s.sys.CreateUser(ctx, system.Account{Username: full}); err != nil { _ = s.db.WithContext(ctx).Delete(u).Error return nil, err } return u, nil }