Admin Page work - Still blank/broken

This commit is contained in:
Eric Gullickson
2025-11-06 16:29:11 -06:00
parent 858cf31d38
commit 5630979adf
38 changed files with 7373 additions and 924 deletions

View File

@@ -11,13 +11,25 @@ import { logger } from '../../../core/logging/logger';
import {
CreateAdminInput,
AdminAuth0SubInput,
AuditLogsQueryInput
AuditLogsQueryInput,
BulkCreateAdminInput,
BulkRevokeAdminInput,
BulkReinstateAdminInput
} from './admin.validation';
import {
createAdminSchema,
adminAuth0SubSchema,
auditLogsQuerySchema
auditLogsQuerySchema,
bulkCreateAdminSchema,
bulkRevokeAdminSchema,
bulkReinstateAdminSchema
} from './admin.validation';
import {
BulkCreateAdminResponse,
BulkRevokeAdminResponse,
BulkReinstateAdminResponse,
AdminUser
} from '../domain/admin.types';
export class AdminController {
private adminService: AdminService;
@@ -398,6 +410,260 @@ export class AdminController {
}
}
/**
* POST /api/admin/admins/bulk - Create multiple admin users
*/
async bulkCreateAdmins(
request: FastifyRequest<{ Body: BulkCreateAdminInput }>,
reply: FastifyReply
) {
try {
const actorId = request.userContext?.userId;
if (!actorId) {
return reply.code(401).send({
error: 'Unauthorized',
message: 'User context missing'
});
}
// Validate request body
const validation = bulkCreateAdminSchema.safeParse(request.body);
if (!validation.success) {
return reply.code(400).send({
error: 'Bad Request',
message: 'Invalid request body',
details: validation.error.errors
});
}
const { admins } = validation.data;
const created: AdminUser[] = [];
const failed: Array<{ email: string; error: string }> = [];
// Process each admin creation sequentially to maintain data consistency
for (const adminInput of admins) {
try {
const { email, role = 'admin' } = adminInput;
// Generate auth0Sub for the new admin
// In production, this should be the actual Auth0 user ID
const auth0Sub = `auth0|${email.replace('@', '_at_')}`;
const admin = await this.adminService.createAdmin(
email,
role,
auth0Sub,
actorId
);
created.push(admin);
} catch (error: any) {
logger.error('Error creating admin in bulk operation', {
error: error.message,
email: adminInput.email,
actorId
});
failed.push({
email: adminInput.email,
error: error.message || 'Failed to create admin'
});
}
}
const response: BulkCreateAdminResponse = {
created,
failed
};
// Return 207 Multi-Status if there were any failures, 201 if all succeeded
const statusCode = failed.length > 0 ? 207 : 201;
return reply.code(statusCode).send(response);
} catch (error: any) {
logger.error('Error in bulk create admins', {
error: error.message,
actorId: request.userContext?.userId
});
return reply.code(500).send({
error: 'Internal server error',
message: 'Failed to process bulk admin creation'
});
}
}
/**
* PATCH /api/admin/admins/bulk-revoke - Revoke multiple admin users
*/
async bulkRevokeAdmins(
request: FastifyRequest<{ Body: BulkRevokeAdminInput }>,
reply: FastifyReply
) {
try {
const actorId = request.userContext?.userId;
if (!actorId) {
return reply.code(401).send({
error: 'Unauthorized',
message: 'User context missing'
});
}
// Validate request body
const validation = bulkRevokeAdminSchema.safeParse(request.body);
if (!validation.success) {
return reply.code(400).send({
error: 'Bad Request',
message: 'Invalid request body',
details: validation.error.errors
});
}
const { auth0Subs } = validation.data;
const revoked: AdminUser[] = [];
const failed: Array<{ auth0Sub: string; error: string }> = [];
// Process each revocation sequentially to maintain data consistency
for (const auth0Sub of auth0Subs) {
try {
// Check if admin exists
const targetAdmin = await this.adminService.getAdminByAuth0Sub(auth0Sub);
if (!targetAdmin) {
failed.push({
auth0Sub,
error: 'Admin user not found'
});
continue;
}
// Attempt to revoke the admin
const admin = await this.adminService.revokeAdmin(auth0Sub, actorId);
revoked.push(admin);
} catch (error: any) {
logger.error('Error revoking admin in bulk operation', {
error: error.message,
auth0Sub,
actorId
});
// Special handling for "last admin" constraint
failed.push({
auth0Sub,
error: error.message || 'Failed to revoke admin'
});
}
}
const response: BulkRevokeAdminResponse = {
revoked,
failed
};
// Return 207 Multi-Status if there were any failures, 200 if all succeeded
const statusCode = failed.length > 0 ? 207 : 200;
return reply.code(statusCode).send(response);
} catch (error: any) {
logger.error('Error in bulk revoke admins', {
error: error.message,
actorId: request.userContext?.userId
});
return reply.code(500).send({
error: 'Internal server error',
message: 'Failed to process bulk admin revocation'
});
}
}
/**
* PATCH /api/admin/admins/bulk-reinstate - Reinstate multiple revoked admin users
*/
async bulkReinstateAdmins(
request: FastifyRequest<{ Body: BulkReinstateAdminInput }>,
reply: FastifyReply
) {
try {
const actorId = request.userContext?.userId;
if (!actorId) {
return reply.code(401).send({
error: 'Unauthorized',
message: 'User context missing'
});
}
// Validate request body
const validation = bulkReinstateAdminSchema.safeParse(request.body);
if (!validation.success) {
return reply.code(400).send({
error: 'Bad Request',
message: 'Invalid request body',
details: validation.error.errors
});
}
const { auth0Subs } = validation.data;
const reinstated: AdminUser[] = [];
const failed: Array<{ auth0Sub: string; error: string }> = [];
// Process each reinstatement sequentially to maintain data consistency
for (const auth0Sub of auth0Subs) {
try {
// Check if admin exists
const targetAdmin = await this.adminService.getAdminByAuth0Sub(auth0Sub);
if (!targetAdmin) {
failed.push({
auth0Sub,
error: 'Admin user not found'
});
continue;
}
// Attempt to reinstate the admin
const admin = await this.adminService.reinstateAdmin(auth0Sub, actorId);
reinstated.push(admin);
} catch (error: any) {
logger.error('Error reinstating admin in bulk operation', {
error: error.message,
auth0Sub,
actorId
});
failed.push({
auth0Sub,
error: error.message || 'Failed to reinstate admin'
});
}
}
const response: BulkReinstateAdminResponse = {
reinstated,
failed
};
// Return 207 Multi-Status if there were any failures, 200 if all succeeded
const statusCode = failed.length > 0 ? 207 : 200;
return reply.code(statusCode).send(response);
} catch (error: any) {
logger.error('Error in bulk reinstate admins', {
error: error.message,
actorId: request.userContext?.userId
});
return reply.code(500).send({
error: 'Internal server error',
message: 'Failed to process bulk admin reinstatement'
});
}
}
private resolveUserEmail(request: FastifyRequest): string | undefined {
console.log('[DEBUG] resolveUserEmail - request.userContext:', JSON.stringify(request.userContext, null, 2));
console.log('[DEBUG] resolveUserEmail - request.user:', JSON.stringify((request as any).user, null, 2));