package setup import ( "context" "errors" "fmt" "github.com/panelhosting/panel/internal/auth" "github.com/panelhosting/panel/internal/bootstrap" "github.com/panelhosting/panel/internal/config" "github.com/panelhosting/panel/internal/models" "github.com/panelhosting/panel/internal/repository" ) var ErrSetupCompleted = errors.New("setup already completed") type Service struct { users *repository.UserRepository servers *repository.ServerRepository cfg *config.Config } func NewService(users *repository.UserRepository, servers *repository.ServerRepository, cfg *config.Config) *Service { return &Service{users: users, servers: servers, cfg: cfg} } func (s *Service) Status(ctx context.Context) (bool, error) { count, err := s.users.Count(ctx) if err != nil { return false, err } return count == 0, nil } type RegisterInput struct { Email string `json:"email"` Username string `json:"username"` Password string `json:"password"` } func (s *Service) RegisterFirstAdmin(ctx context.Context, in RegisterInput) (*models.User, error) { required, err := s.Status(ctx) if err != nil { return nil, err } if !required { return nil, ErrSetupCompleted } if err := auth.ValidateEmail(in.Email); err != nil { return nil, err } if err := auth.ValidateUsername(in.Username); err != nil { return nil, err } hash, err := auth.HashPassword(in.Password) if err != nil { return nil, err } user, err := s.users.Create(ctx, in.Email, in.Username, hash, models.RoleSuperAdmin, models.UserStatusActive) if err != nil { return nil, fmt.Errorf("register admin: %w", err) } if err := bootstrap.EnsureDefaultServer(ctx, s.servers, s.cfg); err != nil { return nil, fmt.Errorf("bootstrap server: %w", err) } if err := bootstrap.GrantServerAccess(ctx, s.servers, user.ID); err != nil { return nil, fmt.Errorf("grant server access: %w", err) } return user, nil }