feat(auth): add profile and QR card identification endpoints

This commit is contained in:
SaidSoighiri94
2026-06-22 10:13:45 +02:00
parent 20490a05c5
commit b5a7577e8d
7 changed files with 106 additions and 5 deletions
@@ -0,0 +1,23 @@
import { Request, Response } from 'express';
import { AppError } from '../errors/app-error';
import { getProfil, identifierParCarte } from '../services/utilisateur.service';
export async function getMe(req: Request, res: Response): Promise<void> {
const user = req.user;
if (!user) {
throw new AppError(401, 'Authentification requise');
}
const profil = await getProfil(user.id);
res.json({ data: profil });
}
export async function identifier(req: Request, res: Response): Promise<void> {
const qr = req.params.qr;
if (typeof qr !== 'string') {
throw new AppError(400, 'QR code invalide');
}
const profil = await identifierParCarte(qr);
res.json({ data: profil });
}
@@ -0,0 +1,13 @@
import { Prisma } from '@prisma/client';
import { prisma } from '../db/prisma';
export type CarteAvecUtilisateur = Prisma.CarteEtudianteGetPayload<{
include: { utilisateur: { include: { role: true; campus: true } } };
}>;
export function findByQrCode(qrCode: string): Promise<CarteAvecUtilisateur | null> {
return prisma.carteEtudiante.findFirst({
where: { qrCode },
include: { utilisateur: { include: { role: true, campus: true } } },
});
}
@@ -3,9 +3,20 @@ import { prisma } from '../db/prisma';
export type UtilisateurAvecRole = Prisma.UtilisateurGetPayload<{ include: { role: true } }>;
export type UtilisateurProfil = Prisma.UtilisateurGetPayload<{
include: { role: true; campus: true };
}>;
export function findByEmail(email: string): Promise<UtilisateurAvecRole | null> {
return prisma.utilisateur.findUnique({
where: { email },
include: { role: true },
});
}
export function findById(id: number): Promise<UtilisateurProfil | null> {
return prisma.utilisateur.findUnique({
where: { id },
include: { role: true, campus: true },
});
}
+11
View File
@@ -0,0 +1,11 @@
import { Router } from 'express';
import { currentUser } from '../middlewares/current-user';
import { getMe, identifier } from '../controllers/auth.controller';
export const authRoutes: Router = Router();
// Identification par QR code : point d'entrée du parcours, donc public.
authRoutes.get('/carte/:qr', identifier);
// Profil de l'utilisateur déjà identifié : protégé.
authRoutes.get('/me', currentUser, getMe);
+7 -3
View File
@@ -1,10 +1,14 @@
import { Router } from 'express';
import { currentUser } from '../middlewares/current-user';
import { authRoutes } from './auth.routes';
import { materielRoutes } from './materiel.routes';
import { empruntRoutes } from './emprunt.routes';
export const apiRouter: Router = Router();
apiRouter.use(currentUser);
apiRouter.use('/materiels', materielRoutes);
apiRouter.use('/mes-emprunts', empruntRoutes);
// /auth gère lui-même ses routes publiques/protégées.
apiRouter.use('/auth', authRoutes);
// Le reste exige un utilisateur identifié.
apiRouter.use('/materiels', currentUser, materielRoutes);
apiRouter.use('/mes-emprunts', currentUser, empruntRoutes);
@@ -0,0 +1,31 @@
import { AppError } from '../errors/app-error';
import { findById, UtilisateurProfil } from '../repositories/utilisateur.repository';
import { findByQrCode } from '../repositories/carte-etudiante.repository';
export async function getProfil(utilisateurId: number): Promise<UtilisateurProfil> {
const profil = await findById(utilisateurId);
if (!profil) {
throw new AppError(404, 'Utilisateur introuvable');
}
return profil;
}
/* RG02 : identification de l'étudiant par le QR code de sa carte. La carte doit
exister, être active et non expirée, et le compte doit être actif. */
export async function identifierParCarte(qrCode: string): Promise<UtilisateurProfil> {
const carte = await findByQrCode(qrCode);
if (!carte || !carte.actif) {
throw new AppError(404, 'Carte non reconnue');
}
if (carte.dateExpiration.getTime() < Date.now()) {
throw new AppError(401, 'Carte expiree');
}
if (!carte.utilisateur.actif) {
throw new AppError(401, 'Compte inactif');
}
return carte.utilisateur;
}