179 lines
6.3 KiB
TypeScript
179 lines
6.3 KiB
TypeScript
export default defineEventHandler(async (event) => {
|
|
console.log('[api/members/[id]/keycloak-groups.put] =========================');
|
|
console.log('[api/members/[id]/keycloak-groups.put] PUT /api/members/:id/keycloak-groups - Update member Keycloak groups');
|
|
|
|
try {
|
|
// Validate session and require admin privileges
|
|
const sessionManager = createSessionManager();
|
|
const cookieHeader = getCookie(event, 'monacousa-session') ? getHeader(event, 'cookie') : undefined;
|
|
const session = sessionManager.getSession(cookieHeader);
|
|
|
|
if (!session?.user) {
|
|
throw createError({
|
|
statusCode: 401,
|
|
statusMessage: 'Authentication required'
|
|
});
|
|
}
|
|
|
|
// Require admin privileges for group management
|
|
if (session.user.tier !== 'admin') {
|
|
throw createError({
|
|
statusCode: 403,
|
|
statusMessage: 'Admin privileges required'
|
|
});
|
|
}
|
|
|
|
console.log('[api/members/[id]/keycloak-groups.put] Authorized admin user:', session.user.email);
|
|
|
|
// Get member ID from route parameter
|
|
const memberId = getRouterParam(event, 'id');
|
|
if (!memberId) {
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: 'Member ID is required'
|
|
});
|
|
}
|
|
|
|
// Parse request body
|
|
const body = await readBody(event);
|
|
const { newGroup } = body;
|
|
|
|
console.log('[api/members/[id]/keycloak-groups.put] Processing member ID:', memberId, 'new group:', newGroup);
|
|
|
|
// Validate new group
|
|
if (!['user', 'board', 'admin'].includes(newGroup)) {
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: 'Invalid group. Must be one of: user, board, admin'
|
|
});
|
|
}
|
|
|
|
// 1. Get member data
|
|
const { getMemberById, updateMember } = await import('~/server/utils/nocodb');
|
|
const member = await getMemberById(memberId);
|
|
|
|
if (!member) {
|
|
throw createError({
|
|
statusCode: 404,
|
|
statusMessage: 'Member not found'
|
|
});
|
|
}
|
|
|
|
// 2. Check if member has portal account
|
|
if (!member.keycloak_id) {
|
|
console.log('[api/members/[id]/keycloak-groups.put] Member has no portal account');
|
|
throw createError({
|
|
statusCode: 404,
|
|
statusMessage: 'Member has no portal account'
|
|
});
|
|
}
|
|
|
|
console.log('[api/members/[id]/keycloak-groups.put] Found member with Keycloak ID:', member.keycloak_id);
|
|
|
|
// 3. Get current group status
|
|
const { createKeycloakAdminClient } = await import('~/server/utils/keycloak-admin');
|
|
const keycloakAdmin = createKeycloakAdminClient();
|
|
|
|
console.log('[api/members/[id]/keycloak-groups.put] Getting current groups...');
|
|
const currentGroups = await keycloakAdmin.getUserGroups(member.keycloak_id);
|
|
const currentPrimaryGroups = currentGroups.filter(g => ['user', 'board', 'admin'].includes(g.name || ''));
|
|
const currentPrimaryGroup = currentPrimaryGroups.length > 0 ? currentPrimaryGroups[0].name : 'user';
|
|
|
|
console.log('[api/members/[id]/keycloak-groups.put] Current primary group:', currentPrimaryGroup);
|
|
|
|
// 4. Check if change is needed
|
|
if (currentPrimaryGroup === newGroup) {
|
|
console.log('[api/members/[id]/keycloak-groups.put] User already in target group, syncing database...');
|
|
|
|
// Still sync database to ensure consistency
|
|
await updateMember(memberId, { portal_group: newGroup });
|
|
|
|
return {
|
|
success: true,
|
|
message: `User was already in ${newGroup} group. Database synced.`,
|
|
data: {
|
|
member_id: memberId,
|
|
keycloak_id: member.keycloak_id,
|
|
old_group: currentPrimaryGroup,
|
|
new_group: newGroup,
|
|
changed: false
|
|
}
|
|
};
|
|
}
|
|
|
|
// 5. Change user's primary group in Keycloak
|
|
console.log('[api/members/[id]/keycloak-groups.put] Changing user primary group in Keycloak...');
|
|
await keycloakAdmin.changeUserPrimaryGroup(member.keycloak_id, newGroup);
|
|
|
|
// 6. Update database portal_group field
|
|
console.log('[api/members/[id]/keycloak-groups.put] Updating database portal_group field...');
|
|
await updateMember(memberId, { portal_group: newGroup });
|
|
|
|
// 7. Verify the change
|
|
console.log('[api/members/[id]/keycloak-groups.put] Verifying group change...');
|
|
const updatedGroups = await keycloakAdmin.getUserGroups(member.keycloak_id);
|
|
const newPrimaryGroups = updatedGroups.filter(g => ['user', 'board', 'admin'].includes(g.name || ''));
|
|
const verifiedNewGroup = newPrimaryGroups.length > 0 ? newPrimaryGroups[0].name : 'user';
|
|
|
|
const changeSuccessful = verifiedNewGroup === newGroup;
|
|
|
|
if (changeSuccessful) {
|
|
console.log('[api/members/[id]/keycloak-groups.put] ✅ Group change successful and verified');
|
|
} else {
|
|
console.error('[api/members/[id]/keycloak-groups.put] ❌ Group change verification failed');
|
|
}
|
|
|
|
return {
|
|
success: changeSuccessful,
|
|
message: changeSuccessful
|
|
? `Successfully changed user from ${currentPrimaryGroup} to ${newGroup} group`
|
|
: `Group change attempted but verification failed. Current group: ${verifiedNewGroup}`,
|
|
data: {
|
|
member_id: memberId,
|
|
keycloak_id: member.keycloak_id,
|
|
old_group: currentPrimaryGroup,
|
|
new_group: newGroup,
|
|
verified_group: verifiedNewGroup,
|
|
changed: changeSuccessful,
|
|
database_updated: true
|
|
}
|
|
};
|
|
|
|
} catch (error: any) {
|
|
console.error('[api/members/[id]/keycloak-groups.put] ❌ Failed to update member groups:', error);
|
|
|
|
// If it's already an HTTP error, re-throw it
|
|
if (error.statusCode) {
|
|
throw error;
|
|
}
|
|
|
|
// Handle specific Keycloak errors
|
|
if (error.message?.includes('Failed to get user groups')) {
|
|
throw createError({
|
|
statusCode: 500,
|
|
statusMessage: 'Failed to retrieve user groups from Keycloak. Check service account permissions.'
|
|
});
|
|
}
|
|
|
|
if (error.message?.includes('Invalid group name')) {
|
|
throw createError({
|
|
statusCode: 400,
|
|
statusMessage: error.message
|
|
});
|
|
}
|
|
|
|
if (error.message?.includes('Group not found')) {
|
|
throw createError({
|
|
statusCode: 500,
|
|
statusMessage: `Keycloak group not found. Ensure the groups 'user', 'board', and 'admin' exist in Keycloak.`
|
|
});
|
|
}
|
|
|
|
// Otherwise, wrap it in a generic error
|
|
throw createError({
|
|
statusCode: 500,
|
|
statusMessage: error.message || 'Failed to update member Keycloak groups'
|
|
});
|
|
}
|
|
});
|