refactor: migrate authentication to NextAuth and clean up related services

This commit is contained in:
Julien Froidefond
2025-10-12 15:45:09 +02:00
parent 117ac243f5
commit 7d12a66c12
25 changed files with 558 additions and 353 deletions

View File

@@ -1,18 +1,19 @@
import { redirect } from "next/navigation";
import { AuthService, userService, TeamsService } from "@/services";
import { auth } from "@/auth";
import { userService, TeamsService } from "@/services";
import { AccountForm } from "@/components/account/account-form";
export default async function AccountPage() {
try {
// Vérifier si l'utilisateur est connecté
const userUuid = await AuthService.getUserUuidFromCookie();
const session = await auth();
if (!userUuid) {
if (!session?.user) {
redirect("/login");
}
// Récupérer le profil utilisateur
const userProfile = await userService.getUserByUuid(userUuid);
const userProfile = await userService.getUserByUuid(session.user.id);
if (!userProfile) {
redirect("/login");

View File

@@ -0,0 +1,3 @@
import { handlers } from "@/auth";
export const { GET, POST } = handlers;

View File

@@ -1,54 +0,0 @@
import { NextRequest, NextResponse } from "next/server";
import { AuthService, UserService } from "@/services";
export async function POST(request: NextRequest) {
try {
const { email, password } = await request.json();
// Validation des données
if (!email || !password) {
return NextResponse.json(
{ error: "Email et mot de passe requis" },
{ status: 400 }
);
}
// Vérifier les identifiants
const userService = new UserService();
const user = await userService.verifyCredentials(email, password);
if (!user) {
return NextResponse.json(
{ error: "Email ou mot de passe incorrect" },
{ status: 401 }
);
}
// Créer la réponse avec le cookie de session
const response = NextResponse.json(
{
message: "Connexion réussie",
user: {
id: user.uuid_id,
firstName: user.first_name,
lastName: user.last_name,
email: user.email,
teamId: user.team_id,
},
},
{ status: 200 }
);
// Créer la session et définir le cookie
await AuthService.createSession(user.uuid_id, response);
return response;
} catch (error) {
console.error("Login error:", error);
return NextResponse.json(
{ error: "Erreur interne du serveur" },
{ status: 500 }
);
}
}

View File

@@ -1,25 +0,0 @@
import { NextResponse } from "next/server";
import { AuthService } from "@/services";
export async function POST() {
try {
// Créer la réponse
const response = NextResponse.json(
{ message: "Déconnexion réussie" },
{ status: 200 }
);
// Supprimer la session et le cookie
AuthService.removeSession(response);
return response;
} catch (error) {
console.error("Logout error:", error);
return NextResponse.json(
{ error: "Erreur interne du serveur" },
{ status: 500 }
);
}
}

View File

@@ -1,46 +0,0 @@
import { NextRequest, NextResponse } from "next/server";
import { AuthService, userService } from "@/services";
export async function PUT(request: NextRequest) {
try {
// Vérifier si l'utilisateur est connecté
const userUuid = await AuthService.getUserUuidFromCookie();
if (!userUuid) {
return NextResponse.json({ error: "Non authentifié" }, { status: 401 });
}
// Récupérer les données de mise à jour
const { firstName, lastName, teamId } = await request.json();
// Validation des données
if (!firstName || !lastName || !teamId) {
return NextResponse.json(
{ error: "Tous les champs sont requis" },
{ status: 400 }
);
}
// Mettre à jour l'utilisateur
await userService.updateUserByUuid(userUuid, {
firstName,
lastName,
teamId,
});
return NextResponse.json({
message: "Profil mis à jour avec succès",
user: {
firstName,
lastName,
teamId,
},
});
} catch (error: any) {
console.error("Profile update error:", error);
return NextResponse.json(
{ error: error.message || "Erreur lors de la mise à jour du profil" },
{ status: 500 }
);
}
}

View File

@@ -1,6 +1,5 @@
import { NextRequest, NextResponse } from "next/server";
import { AuthService, userService } from "@/services";
import { userService } from "@/services";
import bcrypt from "bcryptjs";
export async function POST(request: NextRequest) {
@@ -45,8 +44,9 @@ export async function POST(request: NextRequest) {
);
}
// Créer la réponse avec le cookie de session
const response = NextResponse.json(
// Retourner les informations de l'utilisateur créé
// Le client devra appeler signIn() pour créer la session
return NextResponse.json(
{
message: "Compte créé avec succès",
user: {
@@ -59,11 +59,6 @@ export async function POST(request: NextRequest) {
},
{ status: 201 }
);
// Créer la session et définir le cookie
await AuthService.createSession(newUser.uuid_id, response);
return response;
} catch (error) {
console.error("Register error:", error);
return NextResponse.json(

View File

@@ -1,11 +1,24 @@
import { NextRequest, NextResponse } from "next/server";
import { AuthService } from "@/services/auth-service";
import { auth } from "@/auth";
import { evaluationService } from "@/services/evaluation-service";
export async function PUT(request: NextRequest) {
try {
// Récupérer l'utilisateur depuis le cookie (maintenant un UUID)
const { userProfile } = await AuthService.requireAuthenticatedUser();
// Récupérer l'utilisateur depuis la session NextAuth
const session = await auth();
if (!session?.user) {
return NextResponse.json(
{ error: "Non authentifié" },
{ status: 401 }
);
}
const userProfile = {
firstName: session.user.firstName,
lastName: session.user.lastName,
teamId: session.user.teamId,
};
const body = await request.json();
const { category, skillId, level, canMentor, wantsToLearn, action } = body;

View File

@@ -1,13 +1,20 @@
import { NextRequest, NextResponse } from "next/server";
import { TeamReviewService } from "@/services/team-review-service";
import { AuthService } from "@/services/auth-service";
import { auth } from "@/auth";
export async function GET(request: NextRequest) {
try {
// Vérifier l'authentification
const { userProfile } = await AuthService.requireAuthenticatedUser();
const session = await auth();
if (!session?.user) {
return NextResponse.json(
{ error: "Non authentifié" },
{ status: 401 }
);
}
const teamId = userProfile.teamId;
const teamId = session.user.teamId;
const data = await TeamReviewService.getTeamReviewData(teamId);
return NextResponse.json(data);

View File

@@ -1,5 +1,5 @@
import { redirect } from "next/navigation";
import { AuthService } from "@/services";
import { auth } from "@/auth";
import { SkillsService, TeamsService } from "@/services";
import { evaluationService } from "@/services/evaluation-service";
import { EvaluationClientWrapper } from "@/components/evaluation";
@@ -7,12 +7,14 @@ import { SkillEvaluation } from "@/components/skill-evaluation";
export default async function EvaluationPage() {
// Charger les données côté serveur
const userUuid = await AuthService.getUserUuidFromCookie();
const session = await auth();
if (!userUuid) {
if (!session?.user) {
redirect("/login");
}
const userUuid = session.user.id;
const [userEvaluation, skillCategories, teams] = await Promise.all([
evaluationService.getServerUserEvaluation(userUuid!),
SkillsService.getSkillCategories(),

View File

@@ -7,7 +7,9 @@ import { ThemeProvider } from "@/components/layout/theme-provider";
import { Toaster } from "@/components/ui/sonner";
import { UserProvider } from "@/hooks/use-user-context";
import { NavigationWrapper } from "@/components/layout/navigation-wrapper";
import { AuthService, TeamsService } from "@/services";
import { SessionProvider } from "@/components/auth/session-provider";
import { auth } from "@/auth";
import { TeamsService } from "@/services";
export const metadata: Metadata = {
title: "PeakSkills - Auto-évaluation de compétences",
@@ -20,32 +22,33 @@ export default async function RootLayout({
}: {
children: React.ReactNode;
}) {
// Récupérer les infos utilisateur côté serveur
// Récupérer les infos utilisateur depuis la session NextAuth
let userInfo = null;
try {
const { userUuid, userProfile } =
await AuthService.requireAuthenticatedUser();
const session = await auth();
// Récupérer le nom de l'équipe
let teamName = "Équipe non définie";
if (userProfile.teamId) {
try {
const team = await TeamsService.getTeamById(userProfile.teamId);
if (team) {
teamName = team.name;
if (session?.user) {
// Récupérer le nom de l'équipe
let teamName = "Équipe non définie";
if (session.user.teamId) {
try {
const team = await TeamsService.getTeamById(session.user.teamId);
if (team) {
teamName = team.name;
}
} catch (error) {
console.error("Failed to fetch team name:", error);
}
} catch (error) {
console.error("Failed to fetch team name:", error);
}
}
userInfo = {
firstName: userProfile.firstName,
lastName: userProfile.lastName,
teamName,
teamId: userProfile.teamId,
uuid: userUuid,
};
userInfo = {
firstName: session.user.firstName,
lastName: session.user.lastName,
teamName,
teamId: session.user.teamId,
uuid: session.user.id,
};
}
} catch (error) {
// Utilisateur non authentifié, userInfo reste null
console.log("User not authenticated:", error);
@@ -56,18 +59,20 @@ export default async function RootLayout({
<body
className={`${GeistSans.variable} ${GeistMono.variable} antialiased`}
>
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
<UserProvider initialUserInfo={userInfo}>
<NavigationWrapper />
<main className="min-h-screen">{children}</main>
<Toaster />
</UserProvider>
</ThemeProvider>
<SessionProvider>
<ThemeProvider
attribute="class"
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
<UserProvider initialUserInfo={userInfo}>
<NavigationWrapper />
<main className="min-h-screen">{children}</main>
<Toaster />
</UserProvider>
</ThemeProvider>
</SessionProvider>
</body>
</html>
);

View File

@@ -1,5 +1,5 @@
import { TeamsService, userService } from "@/services";
import { AuthService } from "@/services";
import { auth } from "@/auth";
import { LoginLayout, AuthWrapper, LoginLoading } from "@/components/login";
export default async function LoginPage() {
@@ -8,13 +8,13 @@ export default async function LoginPage() {
const teams = await TeamsService.getTeams();
// Vérifier si l'utilisateur est déjà connecté
const userUuid = await AuthService.getUserUuidFromCookie();
const session = await auth();
let userProfile = null;
if (userUuid) {
if (session?.user) {
// Si l'utilisateur est connecté, récupérer son profil côté serveur
userProfile = await userService.getUserByUuid(userUuid);
userProfile = await userService.getUserByUuid(session.user.id);
}
// Si l'utilisateur n'est pas connecté, afficher le formulaire d'auth

View File

@@ -1,5 +1,5 @@
import { redirect } from "next/navigation";
import { AuthService } from "@/services";
import { auth } from "@/auth";
import { evaluationService, SkillsService, TeamsService } from "@/services";
import { generateRadarData } from "@/lib/evaluation-utils";
import {
@@ -14,12 +14,14 @@ import {
export default async function HomePage() {
// Charger les données côté serveur
const userUuid = await AuthService.getUserUuidFromCookie();
const session = await auth();
if (!userUuid) {
if (!session?.user) {
redirect("/login");
}
const userUuid = session.user.id;
const [userEvaluation, skillCategories, teams] = await Promise.all([
evaluationService.getServerUserEvaluation(userUuid!),
SkillsService.getSkillCategories(),

View File

@@ -1,5 +1,5 @@
import { TeamReviewService } from "@/services/team-review-service";
import { AuthService } from "@/services/auth-service";
import { auth } from "@/auth";
import { redirect } from "next/navigation";
import { TeamOverview } from "@/components/team-review/team-overview";
import { SkillMatrix } from "@/components/team-review/skill-matrix";
@@ -13,10 +13,14 @@ export const dynamic = "force-dynamic";
async function TeamReviewPage() {
try {
const { userProfile } = await AuthService.requireAuthenticatedUser();
const session = await auth();
if (!session?.user) {
redirect("/login");
}
const teamData = await TeamReviewService.getTeamReviewData(
userProfile.teamId
session.user.teamId
);
return (