diff --git a/front/app/api/users/[id]/route.ts b/front/app/api/users/[id]/route.ts new file mode 100644 index 0000000..746c9fa --- /dev/null +++ b/front/app/api/users/[id]/route.ts @@ -0,0 +1,40 @@ +import { getServerSession } from "next-auth"; +import { authOptions } from "../../auth/[...nextauth]/route"; +import { NextResponse } from "next/server"; + +export async function DELETE( + req: Request, + { params }: { params: { id: string } } +) { + const session = await getServerSession(authOptions); + + if ( + !session?.user?.role?.includes("admin") && + !session?.user?.role?.includes("TEACHERS") + ) { + return NextResponse.json({ error: "Non autorisé" }, { status: 401 }); + } + + try { + const response = await fetch( + `${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users/${params.id}`, + { + method: "DELETE", + headers: { + Authorization: `Bearer ${session.accessToken}`, + }, + } + ); + + if (response.ok) { + return NextResponse.json({ success: true }); + } else { + return NextResponse.json( + { error: "Erreur suppression utilisateur" }, + { status: 400 } + ); + } + } catch (error) { + return NextResponse.json({ error: "Erreur serveur" }, { status: 500 }); + } +} diff --git a/front/app/api/users/route.ts b/front/app/api/users/route.ts new file mode 100644 index 0000000..ac9b27d --- /dev/null +++ b/front/app/api/users/route.ts @@ -0,0 +1,187 @@ +import { getServerSession } from "next-auth/next"; +import { authOptions } from "@/app/api/auth/[...nextauth]/route"; +import { NextResponse } from "next/server"; + +export async function GET() { + const session = await getServerSession(authOptions); + + if (!session) { + return NextResponse.json({ error: "Non autorisé" }, { status: 401 }); + } + + try { + // Récupérer la liste des utilisateurs + const usersResponse = await fetch( + `${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users`, + { + headers: { + Authorization: `Bearer ${session.accessToken}`, + }, + } + ); + + const users = await usersResponse.json(); + + // Récupérer les rôles pour chaque utilisateur + const usersWithRoles = await Promise.all( + users.map(async (user: any) => { + try { + const rolesResponse = await fetch( + `${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users/${user.id}/role-mappings/realm`, + { + headers: { + Authorization: `Bearer ${session.accessToken}`, + }, + } + ); + + const roles = await rolesResponse.json(); + + // Suppression de "default-roles-master" qui est un rôle technique + const filteredRoles = roles.filter( + (role: any) => role.name !== "default-roles-master" + ); + + return { + ...user, + roles: filteredRoles.map((role: any) => role.name), + }; + } catch (error) { + console.error( + `Erreur lors de la récupération des rôles pour l'utilisateur ${user.id}:`, + error + ); + return { + ...user, + roles: [], + }; + } + }) + ); + + return NextResponse.json(usersWithRoles); + } catch (error) { + console.error("Erreur lors de la récupération des utilisateurs:", error); + return NextResponse.json({ error: "Erreur serveur" }, { status: 500 }); + } +} + +export async function POST(req: Request) { + const session = await getServerSession(authOptions); + + if ( + !session?.user?.role?.includes("admin") && + !session?.user?.role?.includes("TEACHERS") + ) { + return NextResponse.json({ error: "Non autorisé" }, { status: 401 }); + } + + try { + const data = await req.json(); + + // Formater les données pour Keycloak + const keycloakUser = { + username: data.username, + enabled: true, + emailVerified: true, + firstName: data.firstName, + lastName: data.lastName, + email: data.email, + realmRoles: data.realmRoles ? [data.realmRoles] : [], + }; + + if (keycloakUser.realmRoles.length === 0) { + return NextResponse.json( + { error: "Veuillez sélectionner un rôle" }, + { status: 400 } + ); + } + + // Créer l'utilisateur + const createResponse = await fetch( + `${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users`, + { + method: "POST", + headers: { + Authorization: `Bearer ${session.accessToken}`, + "Content-Type": "application/json", + }, + body: JSON.stringify(keycloakUser), + } + ); + + if (!createResponse.ok) { + const errorData = await createResponse.json(); + console.log(errorData); + if (errorData.errorMessage?.includes("User exists with same username")) { + return NextResponse.json( + { error: "Un utilisateur existe déjà avec ce nom d'utilisateur" }, + { status: 400 } + ); + } else if ( + errorData.errorMessage?.includes("User exists with same email") + ) { + return NextResponse.json( + { error: "Un utilisateur existe déjà avec cet email" }, + { status: 400 } + ); + } + return NextResponse.json( + { error: "Erreur création utilisateur" }, + { status: 400 } + ); + } + + // Récupérer l'utilisateur créé + const userResponse = await fetch( + `${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users?username=${data.username}`, + { + headers: { + Authorization: `Bearer ${session.accessToken}`, + }, + } + ); + + const user = await userResponse.json(); + + console.log("Utilisateur créé:", user[0]); + + if (keycloakUser.realmRoles.length > 0) { + // Récupérer l'ID du rôle + const roleResponse = await fetch( + `${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/roles/${data.realmRoles}`, + { + headers: { + Authorization: `Bearer ${session.accessToken}`, + }, + } + ); + + const roleData = await roleResponse.json(); + + // Ajouter le rôle à l'utilisateur + await fetch( + `${process.env.KEYCLOAK_BASE_URL}/admin/realms/${process.env.KEYCLOAK_REALM}/users/${user[0].id}/role-mappings/realm`, + { + method: "POST", + headers: { + Authorization: `Bearer ${session.accessToken}`, + "Content-Type": "application/json", + }, + body: JSON.stringify([roleData]), + } + ); + + // Ajouter les realmRoles a l'utilisateur avant de le renvoyer + user[0].roles = [keycloakUser.realmRoles]; + } + + return NextResponse.json({ success: true, user: user[0] }); + } catch (error) { + console.error("Erreur complète:", error); + return NextResponse.json( + { error: "Erreur serveur", details: error }, + { status: 500 } + ); + } +} diff --git a/front/app/users/page.tsx b/front/app/users/page.tsx new file mode 100644 index 0000000..85fc73e --- /dev/null +++ b/front/app/users/page.tsx @@ -0,0 +1,22 @@ +import { getServerSession } from "next-auth/next"; +import { authOptions } from "@/app/api/auth/[...nextauth]/route"; +import { redirect } from "next/navigation"; +import { UsersTable } from "@/components/users/users-table"; + +export const metadata = { + title: "Enkun - Utilisateurs", +}; + +export default async function UsersPage() { + const session = await getServerSession(authOptions); + + if (!session) { + redirect("/signin"); + } + + return ( +