/** * @ai-summary Admin feature business logic * @ai-context Handles admin user management with audit logging */ import { AdminRepository } from '../data/admin.repository'; import { AdminUser, AdminAuditLog } from './admin.types'; import { logger } from '../../../core/logging/logger'; import { auditLogService } from '../../audit-log'; export class AdminService { constructor(private repository: AdminRepository) {} async getAdminByAuth0Sub(auth0Sub: string): Promise { try { return await this.repository.getAdminByAuth0Sub(auth0Sub); } catch (error) { logger.error('Error getting admin by auth0_sub', { error }); throw error; } } async getAdminByEmail(email: string): Promise { try { return await this.repository.getAdminByEmail(email); } catch (error) { logger.error('Error getting admin by email', { error }); throw error; } } async getAllAdmins(): Promise { try { return await this.repository.getAllAdmins(); } catch (error) { logger.error('Error getting all admins', { error }); throw error; } } async getActiveAdmins(): Promise { try { return await this.repository.getActiveAdmins(); } catch (error) { logger.error('Error getting active admins', { error }); throw error; } } async createAdmin(email: string, role: string, auth0Sub: string, createdBy: string): Promise { try { // Check if admin already exists const normalizedEmail = email.trim().toLowerCase(); const existing = await this.repository.getAdminByEmail(normalizedEmail); if (existing) { throw new Error(`Admin user with email ${normalizedEmail} already exists`); } // Create new admin const admin = await this.repository.createAdmin(auth0Sub, normalizedEmail, role, createdBy); // Log audit action (legacy) await this.repository.logAuditAction(createdBy, 'CREATE', admin.auth0Sub, 'admin_user', admin.email, { email, role }); // Log to unified audit log await auditLogService.info( 'admin', createdBy, `Admin user created: ${admin.email}`, 'admin_user', admin.auth0Sub, { email: admin.email, role } ).catch(err => logger.error('Failed to log admin create audit event', { error: err })); logger.info('Admin user created', { email, role }); return admin; } catch (error) { logger.error('Error creating admin', { error, email }); throw error; } } async revokeAdmin(auth0Sub: string, revokedBy: string): Promise { try { // Check that at least one active admin will remain const activeAdmins = await this.repository.getActiveAdmins(); if (activeAdmins.length <= 1) { throw new Error('Cannot revoke the last active admin'); } // Revoke the admin const admin = await this.repository.revokeAdmin(auth0Sub); // Log audit action (legacy) await this.repository.logAuditAction(revokedBy, 'REVOKE', auth0Sub, 'admin_user', admin.email); // Log to unified audit log await auditLogService.info( 'admin', revokedBy, `Admin user revoked: ${admin.email}`, 'admin_user', auth0Sub, { email: admin.email } ).catch(err => logger.error('Failed to log admin revoke audit event', { error: err })); logger.info('Admin user revoked', { auth0Sub, email: admin.email }); return admin; } catch (error) { logger.error('Error revoking admin', { error, auth0Sub }); throw error; } } async reinstateAdmin(auth0Sub: string, reinstatedBy: string): Promise { try { // Reinstate the admin const admin = await this.repository.reinstateAdmin(auth0Sub); // Log audit action (legacy) await this.repository.logAuditAction(reinstatedBy, 'REINSTATE', auth0Sub, 'admin_user', admin.email); // Log to unified audit log await auditLogService.info( 'admin', reinstatedBy, `Admin user reinstated: ${admin.email}`, 'admin_user', auth0Sub, { email: admin.email } ).catch(err => logger.error('Failed to log admin reinstate audit event', { error: err })); logger.info('Admin user reinstated', { auth0Sub, email: admin.email }); return admin; } catch (error) { logger.error('Error reinstating admin', { error, auth0Sub }); throw error; } } async getAuditLogs(limit: number = 100, offset: number = 0): Promise<{ logs: AdminAuditLog[]; total: number }> { try { return await this.repository.getAuditLogs(limit, offset); } catch (error) { logger.error('Error fetching audit logs', { error }); throw error; } } async linkAdminAuth0Sub(email: string, auth0Sub: string): Promise { try { return await this.repository.updateAuth0SubByEmail(email.trim().toLowerCase(), auth0Sub); } catch (error) { logger.error('Error linking admin auth0_sub to email', { error, email, auth0Sub }); throw error; } } }