diff --git a/app/api/users/[userId]/route.ts b/app/api/users/[userId]/route.ts index 25de7413..fc7b3415 100644 --- a/app/api/users/[userId]/route.ts +++ b/app/api/users/[userId]/route.ts @@ -5,7 +5,14 @@ import { NextResponse } from "next/server"; // Helper function to get Leantime user ID by email async function getLeantimeUserId(email: string): Promise { try { - // Get user directly by email + // Validate email format + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(email)) { + console.error('Invalid email format'); + return null; + } + + // Get user by email using the proper method const userResponse = await fetch('https://agilite.slm-lab.net/api/jsonrpc', { method: 'POST', headers: { @@ -23,22 +30,29 @@ async function getLeantimeUserId(email: string): Promise { }); const userData = await userResponse.json(); - console.log('Leantime get user response:', userData); + + // Only log minimal information for debugging + console.log('Leantime user lookup response status:', userResponse.status); if (!userResponse.ok || !userData.result) { - console.error('Failed to get Leantime user:', userData); + console.error('Failed to get Leantime user'); + return null; + } + + // The result should be the user object or false + if (userData.result === false) { return null; } return userData.result.id; } catch (error) { - console.error('Error getting Leantime user:', error); + console.error('Error getting Leantime user'); return null; } } // Helper function to delete user from Leantime -async function deleteLeantimeUser(email: string): Promise<{ success: boolean; error?: string }> { +async function deleteLeantimeUser(email: string, requestingUserId: string): Promise<{ success: boolean; error?: string }> { try { // First get the Leantime user ID const leantimeUserId = await getLeantimeUserId(email); @@ -49,6 +63,15 @@ async function deleteLeantimeUser(email: string): Promise<{ success: boolean; er }; } + // Check if the requesting user has permission to delete this user + // This is a placeholder - implement proper permission check based on your requirements + if (!await hasDeletePermission(requestingUserId, leantimeUserId)) { + return { + success: false, + error: 'Unauthorized to delete this user' + }; + } + const response = await fetch('https://agilite.slm-lab.net/api/jsonrpc', { method: 'POST', headers: { @@ -66,19 +89,20 @@ async function deleteLeantimeUser(email: string): Promise<{ success: boolean; er }); const data = await response.json(); - console.log('Leantime delete response:', data); + + // Only log minimal information + console.log('Leantime delete response status:', response.status); if (!response.ok || !data.result) { - console.error('Leantime user deletion failed:', data); return { success: false, - error: data.error?.message || 'Failed to delete user in Leantime' + error: 'Failed to delete user in Leantime' }; } return { success: true }; } catch (error) { - console.error('Error deleting Leantime user:', error); + console.error('Error deleting Leantime user'); return { success: false, error: 'Error deleting user in Leantime' @@ -86,6 +110,16 @@ async function deleteLeantimeUser(email: string): Promise<{ success: boolean; er } } +// Placeholder for permission check - implement based on your requirements +async function hasDeletePermission(requestingUserId: string, targetUserId: number): Promise { + // Implement proper permission check logic here + // For example: + // 1. Check if requesting user is admin + // 2. Check if requesting user is trying to delete themselves + // 3. Check if requesting user has the right role/permissions + return true; +} + export async function DELETE( req: Request, { params }: { params: { userId: string } } @@ -115,7 +149,7 @@ export async function DELETE( const tokenData = await tokenResponse.json(); if (!tokenResponse.ok || !tokenData.access_token) { - console.error("Failed to get admin token:", tokenData); + console.error("Failed to get admin token"); return NextResponse.json({ error: "Erreur d'authentification" }, { status: 401 }); } @@ -130,7 +164,7 @@ export async function DELETE( ); if (!userResponse.ok) { - console.error("Failed to get user details:", await userResponse.text()); + console.error("Failed to get user details"); return NextResponse.json( { error: "Erreur lors de la récupération des détails de l'utilisateur" }, { status: userResponse.status } @@ -151,19 +185,18 @@ export async function DELETE( ); if (!deleteResponse.ok) { - const errorData = await deleteResponse.json(); - console.error("Keycloak delete error:", errorData); + console.error("Keycloak delete error"); return NextResponse.json( - { error: "Erreur lors de la suppression de l'utilisateur", details: errorData }, + { error: "Erreur lors de la suppression de l'utilisateur" }, { status: deleteResponse.status } ); } // Delete user from Leantime - const leantimeResult = await deleteLeantimeUser(params.userId); + const leantimeResult = await deleteLeantimeUser(userDetails.email, session.user.id); if (!leantimeResult.success) { - console.error("Leantime user deletion failed:", leantimeResult.error); + console.error("Leantime user deletion failed"); // We don't return an error here since Keycloak user was deleted successfully // We just log the error and continue } @@ -171,9 +204,9 @@ export async function DELETE( return NextResponse.json({ success: true }); } catch (error) { - console.error("Error deleting user:", error); + console.error("Error deleting user"); return NextResponse.json( - { error: "Erreur serveur", details: error }, + { error: "Erreur serveur" }, { status: 500 } ); }