chore: refactor admin system for UUID identity (refs #213)
Migrate admin controller, routes, validation, and users controller from auth0Sub identifiers to UUID. Admin CRUD now uses admin UUID id, user management routes use user_profiles UUID. Clean up debug logging. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -6,11 +6,12 @@
|
||||
import { FastifyRequest, FastifyReply } from 'fastify';
|
||||
import { AdminService } from '../domain/admin.service';
|
||||
import { AdminRepository } from '../data/admin.repository';
|
||||
import { UserProfileRepository } from '../../user-profile/data/user-profile.repository';
|
||||
import { pool } from '../../../core/config/database';
|
||||
import { logger } from '../../../core/logging/logger';
|
||||
import {
|
||||
CreateAdminInput,
|
||||
AdminAuth0SubInput,
|
||||
AdminIdInput,
|
||||
AuditLogsQueryInput,
|
||||
BulkCreateAdminInput,
|
||||
BulkRevokeAdminInput,
|
||||
@@ -18,7 +19,7 @@ import {
|
||||
} from './admin.validation';
|
||||
import {
|
||||
createAdminSchema,
|
||||
adminAuth0SubSchema,
|
||||
adminIdSchema,
|
||||
auditLogsQuerySchema,
|
||||
bulkCreateAdminSchema,
|
||||
bulkRevokeAdminSchema,
|
||||
@@ -33,10 +34,12 @@ import {
|
||||
|
||||
export class AdminController {
|
||||
private adminService: AdminService;
|
||||
private userProfileRepository: UserProfileRepository;
|
||||
|
||||
constructor() {
|
||||
const repository = new AdminRepository(pool);
|
||||
this.adminService = new AdminService(repository);
|
||||
this.userProfileRepository = new UserProfileRepository(pool);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,49 +50,18 @@ export class AdminController {
|
||||
const userId = request.userContext?.userId;
|
||||
const userEmail = this.resolveUserEmail(request);
|
||||
|
||||
console.log('[DEBUG] Admin verify - userId:', userId);
|
||||
console.log('[DEBUG] Admin verify - userEmail:', userEmail);
|
||||
|
||||
if (userEmail && request.userContext) {
|
||||
request.userContext.email = userEmail.toLowerCase();
|
||||
}
|
||||
|
||||
if (!userId && !userEmail) {
|
||||
console.log('[DEBUG] Admin verify - No userId or userEmail, returning 401');
|
||||
if (!userId) {
|
||||
return reply.code(401).send({
|
||||
error: 'Unauthorized',
|
||||
message: 'User context missing'
|
||||
});
|
||||
}
|
||||
|
||||
let adminRecord = userId
|
||||
? await this.adminService.getAdminByAuth0Sub(userId)
|
||||
: null;
|
||||
|
||||
console.log('[DEBUG] Admin verify - adminRecord by auth0Sub:', adminRecord ? 'FOUND' : 'NOT FOUND');
|
||||
|
||||
// Fallback: attempt to resolve admin by email for legacy records
|
||||
if (!adminRecord && userEmail) {
|
||||
const emailMatch = await this.adminService.getAdminByEmail(userEmail.toLowerCase());
|
||||
|
||||
console.log('[DEBUG] Admin verify - emailMatch:', emailMatch ? 'FOUND' : 'NOT FOUND');
|
||||
if (emailMatch) {
|
||||
console.log('[DEBUG] Admin verify - emailMatch.auth0Sub:', emailMatch.auth0Sub);
|
||||
console.log('[DEBUG] Admin verify - emailMatch.revokedAt:', emailMatch.revokedAt);
|
||||
}
|
||||
|
||||
if (emailMatch && !emailMatch.revokedAt) {
|
||||
// If the stored auth0Sub differs, link it to the authenticated user
|
||||
if (userId && emailMatch.auth0Sub !== userId) {
|
||||
console.log('[DEBUG] Admin verify - Calling linkAdminAuth0Sub to update auth0Sub');
|
||||
adminRecord = await this.adminService.linkAdminAuth0Sub(userEmail, userId);
|
||||
console.log('[DEBUG] Admin verify - adminRecord after link:', adminRecord ? 'SUCCESS' : 'FAILED');
|
||||
} else {
|
||||
console.log('[DEBUG] Admin verify - Using emailMatch as adminRecord');
|
||||
adminRecord = emailMatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
const adminRecord = await this.adminService.getAdminByUserProfileId(userId);
|
||||
|
||||
if (adminRecord && !adminRecord.revokedAt) {
|
||||
if (request.userContext) {
|
||||
@@ -97,12 +69,11 @@ export class AdminController {
|
||||
request.userContext.adminRecord = adminRecord;
|
||||
}
|
||||
|
||||
console.log('[DEBUG] Admin verify - Returning isAdmin: true');
|
||||
// User is an active admin
|
||||
return reply.code(200).send({
|
||||
isAdmin: true,
|
||||
adminRecord: {
|
||||
auth0Sub: adminRecord.auth0Sub,
|
||||
id: adminRecord.id,
|
||||
userProfileId: adminRecord.userProfileId,
|
||||
email: adminRecord.email,
|
||||
role: adminRecord.role
|
||||
}
|
||||
@@ -114,14 +85,11 @@ export class AdminController {
|
||||
request.userContext.adminRecord = undefined;
|
||||
}
|
||||
|
||||
console.log('[DEBUG] Admin verify - Returning isAdmin: false');
|
||||
// User is not an admin
|
||||
return reply.code(200).send({
|
||||
isAdmin: false,
|
||||
adminRecord: null
|
||||
});
|
||||
} catch (error) {
|
||||
console.log('[DEBUG] Admin verify - Error caught:', error instanceof Error ? error.message : 'Unknown error');
|
||||
logger.error('Error verifying admin access', {
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
userId: request.userContext?.userId?.substring(0, 8) + '...'
|
||||
@@ -139,9 +107,9 @@ export class AdminController {
|
||||
*/
|
||||
async listAdmins(request: FastifyRequest, reply: FastifyReply) {
|
||||
try {
|
||||
const actorId = request.userContext?.userId;
|
||||
const actorUserProfileId = request.userContext?.userId;
|
||||
|
||||
if (!actorId) {
|
||||
if (!actorUserProfileId) {
|
||||
return reply.code(401).send({
|
||||
error: 'Unauthorized',
|
||||
message: 'User context missing'
|
||||
@@ -150,11 +118,6 @@ export class AdminController {
|
||||
|
||||
const admins = await this.adminService.getAllAdmins();
|
||||
|
||||
// Log VIEW action
|
||||
await this.adminService.getAdminByAuth0Sub(actorId);
|
||||
// Note: Not logging VIEW as it would create excessive audit entries
|
||||
// VIEW logging can be enabled if needed for compliance
|
||||
|
||||
return reply.code(200).send({
|
||||
total: admins.length,
|
||||
admins
|
||||
@@ -162,7 +125,7 @@ export class AdminController {
|
||||
} catch (error: any) {
|
||||
logger.error('Error listing admins', {
|
||||
error: error.message,
|
||||
actorId: request.userContext?.userId
|
||||
actorUserProfileId: request.userContext?.userId
|
||||
});
|
||||
return reply.code(500).send({
|
||||
error: 'Internal server error',
|
||||
@@ -179,15 +142,24 @@ export class AdminController {
|
||||
reply: FastifyReply
|
||||
) {
|
||||
try {
|
||||
const actorId = request.userContext?.userId;
|
||||
const actorUserProfileId = request.userContext?.userId;
|
||||
|
||||
if (!actorId) {
|
||||
if (!actorUserProfileId) {
|
||||
return reply.code(401).send({
|
||||
error: 'Unauthorized',
|
||||
message: 'User context missing'
|
||||
});
|
||||
}
|
||||
|
||||
// Get actor's admin record to get admin ID
|
||||
const actorAdmin = await this.adminService.getAdminByUserProfileId(actorUserProfileId);
|
||||
if (!actorAdmin) {
|
||||
return reply.code(403).send({
|
||||
error: 'Forbidden',
|
||||
message: 'Actor is not an admin'
|
||||
});
|
||||
}
|
||||
|
||||
// Validate request body
|
||||
const validation = createAdminSchema.safeParse(request.body);
|
||||
if (!validation.success) {
|
||||
@@ -200,23 +172,27 @@ export class AdminController {
|
||||
|
||||
const { email, role } = validation.data;
|
||||
|
||||
// Generate auth0Sub for the new admin
|
||||
// In production, this should be the actual Auth0 user ID
|
||||
// For now, we'll use email-based identifier
|
||||
const auth0Sub = `auth0|${email.replace('@', '_at_')}`;
|
||||
// Look up user profile by email to get UUID
|
||||
const userProfile = await this.userProfileRepository.getByEmail(email);
|
||||
if (!userProfile) {
|
||||
return reply.code(404).send({
|
||||
error: 'Not Found',
|
||||
message: `No user profile found with email ${email}. User must sign up first.`
|
||||
});
|
||||
}
|
||||
|
||||
const admin = await this.adminService.createAdmin(
|
||||
email,
|
||||
role,
|
||||
auth0Sub,
|
||||
actorId
|
||||
userProfile.id,
|
||||
actorAdmin.id
|
||||
);
|
||||
|
||||
return reply.code(201).send(admin);
|
||||
} catch (error: any) {
|
||||
logger.error('Error creating admin', {
|
||||
error: error.message,
|
||||
actorId: request.userContext?.userId
|
||||
actorUserProfileId: request.userContext?.userId
|
||||
});
|
||||
|
||||
if (error.message.includes('already exists')) {
|
||||
@@ -234,36 +210,45 @@ export class AdminController {
|
||||
}
|
||||
|
||||
/**
|
||||
* PATCH /api/admin/admins/:auth0Sub/revoke - Revoke admin access
|
||||
* PATCH /api/admin/admins/:id/revoke - Revoke admin access
|
||||
*/
|
||||
async revokeAdmin(
|
||||
request: FastifyRequest<{ Params: AdminAuth0SubInput }>,
|
||||
request: FastifyRequest<{ Params: AdminIdInput }>,
|
||||
reply: FastifyReply
|
||||
) {
|
||||
try {
|
||||
const actorId = request.userContext?.userId;
|
||||
const actorUserProfileId = request.userContext?.userId;
|
||||
|
||||
if (!actorId) {
|
||||
if (!actorUserProfileId) {
|
||||
return reply.code(401).send({
|
||||
error: 'Unauthorized',
|
||||
message: 'User context missing'
|
||||
});
|
||||
}
|
||||
|
||||
// Get actor's admin record
|
||||
const actorAdmin = await this.adminService.getAdminByUserProfileId(actorUserProfileId);
|
||||
if (!actorAdmin) {
|
||||
return reply.code(403).send({
|
||||
error: 'Forbidden',
|
||||
message: 'Actor is not an admin'
|
||||
});
|
||||
}
|
||||
|
||||
// Validate params
|
||||
const validation = adminAuth0SubSchema.safeParse(request.params);
|
||||
const validation = adminIdSchema.safeParse(request.params);
|
||||
if (!validation.success) {
|
||||
return reply.code(400).send({
|
||||
error: 'Bad Request',
|
||||
message: 'Invalid auth0Sub parameter',
|
||||
message: 'Invalid admin ID parameter',
|
||||
details: validation.error.errors
|
||||
});
|
||||
}
|
||||
|
||||
const { auth0Sub } = validation.data;
|
||||
const { id } = validation.data;
|
||||
|
||||
// Check if admin exists
|
||||
const targetAdmin = await this.adminService.getAdminByAuth0Sub(auth0Sub);
|
||||
const targetAdmin = await this.adminService.getAdminById(id);
|
||||
if (!targetAdmin) {
|
||||
return reply.code(404).send({
|
||||
error: 'Not Found',
|
||||
@@ -272,14 +257,14 @@ export class AdminController {
|
||||
}
|
||||
|
||||
// Revoke the admin (service handles last admin check)
|
||||
const admin = await this.adminService.revokeAdmin(auth0Sub, actorId);
|
||||
const admin = await this.adminService.revokeAdmin(id, actorAdmin.id);
|
||||
|
||||
return reply.code(200).send(admin);
|
||||
} catch (error: any) {
|
||||
logger.error('Error revoking admin', {
|
||||
error: error.message,
|
||||
actorId: request.userContext?.userId,
|
||||
targetAuth0Sub: request.params.auth0Sub
|
||||
actorUserProfileId: request.userContext?.userId,
|
||||
targetAdminId: (request.params as any).id
|
||||
});
|
||||
|
||||
if (error.message.includes('Cannot revoke the last active admin')) {
|
||||
@@ -304,36 +289,45 @@ export class AdminController {
|
||||
}
|
||||
|
||||
/**
|
||||
* PATCH /api/admin/admins/:auth0Sub/reinstate - Restore revoked admin
|
||||
* PATCH /api/admin/admins/:id/reinstate - Restore revoked admin
|
||||
*/
|
||||
async reinstateAdmin(
|
||||
request: FastifyRequest<{ Params: AdminAuth0SubInput }>,
|
||||
request: FastifyRequest<{ Params: AdminIdInput }>,
|
||||
reply: FastifyReply
|
||||
) {
|
||||
try {
|
||||
const actorId = request.userContext?.userId;
|
||||
const actorUserProfileId = request.userContext?.userId;
|
||||
|
||||
if (!actorId) {
|
||||
if (!actorUserProfileId) {
|
||||
return reply.code(401).send({
|
||||
error: 'Unauthorized',
|
||||
message: 'User context missing'
|
||||
});
|
||||
}
|
||||
|
||||
// Get actor's admin record
|
||||
const actorAdmin = await this.adminService.getAdminByUserProfileId(actorUserProfileId);
|
||||
if (!actorAdmin) {
|
||||
return reply.code(403).send({
|
||||
error: 'Forbidden',
|
||||
message: 'Actor is not an admin'
|
||||
});
|
||||
}
|
||||
|
||||
// Validate params
|
||||
const validation = adminAuth0SubSchema.safeParse(request.params);
|
||||
const validation = adminIdSchema.safeParse(request.params);
|
||||
if (!validation.success) {
|
||||
return reply.code(400).send({
|
||||
error: 'Bad Request',
|
||||
message: 'Invalid auth0Sub parameter',
|
||||
message: 'Invalid admin ID parameter',
|
||||
details: validation.error.errors
|
||||
});
|
||||
}
|
||||
|
||||
const { auth0Sub } = validation.data;
|
||||
const { id } = validation.data;
|
||||
|
||||
// Check if admin exists
|
||||
const targetAdmin = await this.adminService.getAdminByAuth0Sub(auth0Sub);
|
||||
const targetAdmin = await this.adminService.getAdminById(id);
|
||||
if (!targetAdmin) {
|
||||
return reply.code(404).send({
|
||||
error: 'Not Found',
|
||||
@@ -342,14 +336,14 @@ export class AdminController {
|
||||
}
|
||||
|
||||
// Reinstate the admin
|
||||
const admin = await this.adminService.reinstateAdmin(auth0Sub, actorId);
|
||||
const admin = await this.adminService.reinstateAdmin(id, actorAdmin.id);
|
||||
|
||||
return reply.code(200).send(admin);
|
||||
} catch (error: any) {
|
||||
logger.error('Error reinstating admin', {
|
||||
error: error.message,
|
||||
actorId: request.userContext?.userId,
|
||||
targetAuth0Sub: request.params.auth0Sub
|
||||
actorUserProfileId: request.userContext?.userId,
|
||||
targetAdminId: (request.params as any).id
|
||||
});
|
||||
|
||||
if (error.message.includes('not found')) {
|
||||
@@ -418,15 +412,24 @@ export class AdminController {
|
||||
reply: FastifyReply
|
||||
) {
|
||||
try {
|
||||
const actorId = request.userContext?.userId;
|
||||
const actorUserProfileId = request.userContext?.userId;
|
||||
|
||||
if (!actorId) {
|
||||
if (!actorUserProfileId) {
|
||||
return reply.code(401).send({
|
||||
error: 'Unauthorized',
|
||||
message: 'User context missing'
|
||||
});
|
||||
}
|
||||
|
||||
// Get actor's admin record
|
||||
const actorAdmin = await this.adminService.getAdminByUserProfileId(actorUserProfileId);
|
||||
if (!actorAdmin) {
|
||||
return reply.code(403).send({
|
||||
error: 'Forbidden',
|
||||
message: 'Actor is not an admin'
|
||||
});
|
||||
}
|
||||
|
||||
// Validate request body
|
||||
const validation = bulkCreateAdminSchema.safeParse(request.body);
|
||||
if (!validation.success) {
|
||||
@@ -447,15 +450,21 @@ export class AdminController {
|
||||
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_')}`;
|
||||
// Look up user profile by email to get UUID
|
||||
const userProfile = await this.userProfileRepository.getByEmail(email);
|
||||
if (!userProfile) {
|
||||
failed.push({
|
||||
email,
|
||||
error: `No user profile found with email ${email}. User must sign up first.`
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
const admin = await this.adminService.createAdmin(
|
||||
email,
|
||||
role,
|
||||
auth0Sub,
|
||||
actorId
|
||||
userProfile.id,
|
||||
actorAdmin.id
|
||||
);
|
||||
|
||||
created.push(admin);
|
||||
@@ -463,7 +472,7 @@ export class AdminController {
|
||||
logger.error('Error creating admin in bulk operation', {
|
||||
error: error.message,
|
||||
email: adminInput.email,
|
||||
actorId
|
||||
actorAdminId: actorAdmin.id
|
||||
});
|
||||
|
||||
failed.push({
|
||||
@@ -485,7 +494,7 @@ export class AdminController {
|
||||
} catch (error: any) {
|
||||
logger.error('Error in bulk create admins', {
|
||||
error: error.message,
|
||||
actorId: request.userContext?.userId
|
||||
actorUserProfileId: request.userContext?.userId
|
||||
});
|
||||
|
||||
return reply.code(500).send({
|
||||
@@ -503,15 +512,24 @@ export class AdminController {
|
||||
reply: FastifyReply
|
||||
) {
|
||||
try {
|
||||
const actorId = request.userContext?.userId;
|
||||
const actorUserProfileId = request.userContext?.userId;
|
||||
|
||||
if (!actorId) {
|
||||
if (!actorUserProfileId) {
|
||||
return reply.code(401).send({
|
||||
error: 'Unauthorized',
|
||||
message: 'User context missing'
|
||||
});
|
||||
}
|
||||
|
||||
// Get actor's admin record
|
||||
const actorAdmin = await this.adminService.getAdminByUserProfileId(actorUserProfileId);
|
||||
if (!actorAdmin) {
|
||||
return reply.code(403).send({
|
||||
error: 'Forbidden',
|
||||
message: 'Actor is not an admin'
|
||||
});
|
||||
}
|
||||
|
||||
// Validate request body
|
||||
const validation = bulkRevokeAdminSchema.safeParse(request.body);
|
||||
if (!validation.success) {
|
||||
@@ -522,37 +540,36 @@ export class AdminController {
|
||||
});
|
||||
}
|
||||
|
||||
const { auth0Subs } = validation.data;
|
||||
const { ids } = validation.data;
|
||||
|
||||
const revoked: AdminUser[] = [];
|
||||
const failed: Array<{ auth0Sub: string; error: string }> = [];
|
||||
const failed: Array<{ id: string; error: string }> = [];
|
||||
|
||||
// Process each revocation sequentially to maintain data consistency
|
||||
for (const auth0Sub of auth0Subs) {
|
||||
for (const id of ids) {
|
||||
try {
|
||||
// Check if admin exists
|
||||
const targetAdmin = await this.adminService.getAdminByAuth0Sub(auth0Sub);
|
||||
const targetAdmin = await this.adminService.getAdminById(id);
|
||||
if (!targetAdmin) {
|
||||
failed.push({
|
||||
auth0Sub,
|
||||
id,
|
||||
error: 'Admin user not found'
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
// Attempt to revoke the admin
|
||||
const admin = await this.adminService.revokeAdmin(auth0Sub, actorId);
|
||||
const admin = await this.adminService.revokeAdmin(id, actorAdmin.id);
|
||||
revoked.push(admin);
|
||||
} catch (error: any) {
|
||||
logger.error('Error revoking admin in bulk operation', {
|
||||
error: error.message,
|
||||
auth0Sub,
|
||||
actorId
|
||||
adminId: id,
|
||||
actorAdminId: actorAdmin.id
|
||||
});
|
||||
|
||||
// Special handling for "last admin" constraint
|
||||
failed.push({
|
||||
auth0Sub,
|
||||
id,
|
||||
error: error.message || 'Failed to revoke admin'
|
||||
});
|
||||
}
|
||||
@@ -570,7 +587,7 @@ export class AdminController {
|
||||
} catch (error: any) {
|
||||
logger.error('Error in bulk revoke admins', {
|
||||
error: error.message,
|
||||
actorId: request.userContext?.userId
|
||||
actorUserProfileId: request.userContext?.userId
|
||||
});
|
||||
|
||||
return reply.code(500).send({
|
||||
@@ -588,15 +605,24 @@ export class AdminController {
|
||||
reply: FastifyReply
|
||||
) {
|
||||
try {
|
||||
const actorId = request.userContext?.userId;
|
||||
const actorUserProfileId = request.userContext?.userId;
|
||||
|
||||
if (!actorId) {
|
||||
if (!actorUserProfileId) {
|
||||
return reply.code(401).send({
|
||||
error: 'Unauthorized',
|
||||
message: 'User context missing'
|
||||
});
|
||||
}
|
||||
|
||||
// Get actor's admin record
|
||||
const actorAdmin = await this.adminService.getAdminByUserProfileId(actorUserProfileId);
|
||||
if (!actorAdmin) {
|
||||
return reply.code(403).send({
|
||||
error: 'Forbidden',
|
||||
message: 'Actor is not an admin'
|
||||
});
|
||||
}
|
||||
|
||||
// Validate request body
|
||||
const validation = bulkReinstateAdminSchema.safeParse(request.body);
|
||||
if (!validation.success) {
|
||||
@@ -607,36 +633,36 @@ export class AdminController {
|
||||
});
|
||||
}
|
||||
|
||||
const { auth0Subs } = validation.data;
|
||||
const { ids } = validation.data;
|
||||
|
||||
const reinstated: AdminUser[] = [];
|
||||
const failed: Array<{ auth0Sub: string; error: string }> = [];
|
||||
const failed: Array<{ id: string; error: string }> = [];
|
||||
|
||||
// Process each reinstatement sequentially to maintain data consistency
|
||||
for (const auth0Sub of auth0Subs) {
|
||||
for (const id of ids) {
|
||||
try {
|
||||
// Check if admin exists
|
||||
const targetAdmin = await this.adminService.getAdminByAuth0Sub(auth0Sub);
|
||||
const targetAdmin = await this.adminService.getAdminById(id);
|
||||
if (!targetAdmin) {
|
||||
failed.push({
|
||||
auth0Sub,
|
||||
id,
|
||||
error: 'Admin user not found'
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
// Attempt to reinstate the admin
|
||||
const admin = await this.adminService.reinstateAdmin(auth0Sub, actorId);
|
||||
const admin = await this.adminService.reinstateAdmin(id, actorAdmin.id);
|
||||
reinstated.push(admin);
|
||||
} catch (error: any) {
|
||||
logger.error('Error reinstating admin in bulk operation', {
|
||||
error: error.message,
|
||||
auth0Sub,
|
||||
actorId
|
||||
adminId: id,
|
||||
actorAdminId: actorAdmin.id
|
||||
});
|
||||
|
||||
failed.push({
|
||||
auth0Sub,
|
||||
id,
|
||||
error: error.message || 'Failed to reinstate admin'
|
||||
});
|
||||
}
|
||||
@@ -654,7 +680,7 @@ export class AdminController {
|
||||
} catch (error: any) {
|
||||
logger.error('Error in bulk reinstate admins', {
|
||||
error: error.message,
|
||||
actorId: request.userContext?.userId
|
||||
actorUserProfileId: request.userContext?.userId
|
||||
});
|
||||
|
||||
return reply.code(500).send({
|
||||
@@ -665,9 +691,6 @@ export class AdminController {
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
const candidates: Array<string | undefined> = [
|
||||
request.userContext?.email,
|
||||
(request as any).user?.email,
|
||||
@@ -676,15 +699,11 @@ export class AdminController {
|
||||
(request as any).user?.preferred_username,
|
||||
];
|
||||
|
||||
console.log('[DEBUG] resolveUserEmail - candidates:', candidates);
|
||||
|
||||
for (const value of candidates) {
|
||||
if (typeof value === 'string' && value.includes('@')) {
|
||||
console.log('[DEBUG] resolveUserEmail - found email:', value);
|
||||
return value.trim();
|
||||
}
|
||||
}
|
||||
console.log('[DEBUG] resolveUserEmail - no email found');
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user