import { Injectable, Logger } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; import { randomBytes } from 'crypto'; import { ClientType } from '../common/enums/client-type.enum'; import { Role } from '../common/enums/role.enum'; import { PasswordService } from '../auth/services/password.service'; import { User, UserDocument } from '../users/schemas/user.schema'; import { UserMapper } from '../users/mappers/user.mapper'; import { UserResponseDto } from '../users/dto/user-response.dto'; import { AppException } from '../common/exceptions/app-exception'; export interface CreateSuperAdminInput { fullName: string; username: string; email: string; password: string; } @Injectable() export class CreateSuperAdminService { private readonly logger = new Logger(CreateSuperAdminService.name); constructor( @InjectModel(User.name) private readonly userModel: Model, private readonly passwordService: PasswordService, ) {} async create(input: CreateSuperAdminInput): Promise { if (input.password.length < 8) { throw new AppException('PASSWORD_TOO_SHORT'); } const username = input.username.toLowerCase().trim(); const email = input.email.toLowerCase().trim(); const existing = await this.userModel.findOne({ $or: [{ username }, { email }] }); if (existing) { throw new AppException('USERNAME_OR_EMAIL_EXISTS'); } const superAdminExists = await this.userModel.exists({ role: Role.SUPER_ADMIN }); if (superAdminExists) { this.logger.warn('A SUPER_ADMIN already exists; creating another.'); } const passwordHash = await this.passwordService.hash(input.password); const user = await this.userModel.create({ fullName: input.fullName.trim(), username, email, password: passwordHash, role: Role.SUPER_ADMIN, clientType: ClientType.INTERNAL, appName: 'inquiry-gateway', clientName: 'Internal', isActive: true, isBlocked: false, allowedInquiries: [], apiKey: `esg_${randomBytes(32).toString('hex')}`, passwordChangedAt: new Date(), }); return UserMapper.toResponseDto(user); } }