Compare commits
No commits in common. "95d1c3741b10232e0d346146062d307d3f8dd53e" and "cef197d1332f7c58e38f2f931c1839aeda00b7f3" have entirely different histories.
95d1c3741b
...
cef197d133
18
backend/src/admin/admin.controller.ts
Normal file
18
backend/src/admin/admin.controller.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { Controller, Post, Body, UseGuards, Req } from '@nestjs/common';
|
||||||
|
import { AdminService } from './admin.service';
|
||||||
|
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
|
||||||
|
|
||||||
|
@Controller('admin')
|
||||||
|
export class AdminController {
|
||||||
|
constructor(private readonly adminService: AdminService) {}
|
||||||
|
|
||||||
|
@Post('change-password')
|
||||||
|
@UseGuards(JwtAuthGuard)
|
||||||
|
async changePassword(
|
||||||
|
@Req() req,
|
||||||
|
@Body('oldPassword') oldPassword: string,
|
||||||
|
@Body('newPassword') newPassword: string,
|
||||||
|
) {
|
||||||
|
return this.adminService.changePassword(req.user.id, oldPassword, newPassword);
|
||||||
|
}
|
||||||
|
}
|
||||||
18
backend/src/admin/admin.module.ts
Normal file
18
backend/src/admin/admin.module.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { AdminController } from './admin.controller';
|
||||||
|
import { AdminService } from './admin.service';
|
||||||
|
import { PrismaModule } from '../prisma/prisma.module';
|
||||||
|
import { JwtModule } from '@nestjs/jwt';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [
|
||||||
|
PrismaModule,
|
||||||
|
JwtModule.register({
|
||||||
|
secret: process.env.JWT_SECRET,
|
||||||
|
signOptions: { expiresIn: '1d' },
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
controllers: [AdminController],
|
||||||
|
providers: [AdminService],
|
||||||
|
})
|
||||||
|
export class AdminModule {}
|
||||||
40
backend/src/admin/admin.service.ts
Normal file
40
backend/src/admin/admin.service.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
||||||
|
import { JwtService } from '@nestjs/jwt';
|
||||||
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
|
import * as bcrypt from 'bcrypt';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AdminService {
|
||||||
|
constructor(
|
||||||
|
private prisma: PrismaService,
|
||||||
|
private jwtService: JwtService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async changePassword(adminId: string, oldPassword: string, newPassword: string) {
|
||||||
|
// Récupérer l'administrateur
|
||||||
|
const admin = await this.prisma.admin.findUnique({
|
||||||
|
where: { id: adminId },
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!admin) {
|
||||||
|
throw new UnauthorizedException('Administrateur non trouvé');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vérifier l'ancien mot de passe
|
||||||
|
const isPasswordValid = await bcrypt.compare(oldPassword, admin.password);
|
||||||
|
if (!isPasswordValid) {
|
||||||
|
throw new UnauthorizedException('Ancien mot de passe incorrect');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hasher le nouveau mot de passe
|
||||||
|
const hashedPassword = await bcrypt.hash(newPassword, 10);
|
||||||
|
|
||||||
|
// Mettre à jour le mot de passe
|
||||||
|
await this.prisma.admin.update({
|
||||||
|
where: { id: adminId },
|
||||||
|
data: { password: hashedPassword },
|
||||||
|
});
|
||||||
|
|
||||||
|
return { message: 'Mot de passe modifié avec succès' };
|
||||||
|
}
|
||||||
|
}
|
||||||
72
backend/src/controllers/theme.controller.ts
Normal file
72
backend/src/controllers/theme.controller.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import { Request, Response } from 'express';
|
||||||
|
import { ThemeService, ThemeData } from '../services/theme.service';
|
||||||
|
|
||||||
|
export class ThemeController {
|
||||||
|
// Créer un nouveau thème
|
||||||
|
static async createTheme(req: Request, res: Response) {
|
||||||
|
try {
|
||||||
|
const themeData: ThemeData = req.body;
|
||||||
|
const theme = await ThemeService.createTheme(themeData);
|
||||||
|
res.status(201).json(theme);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ error: 'Erreur lors de la création du thème' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Récupérer tous les thèmes
|
||||||
|
static async getAllThemes(req: Request, res: Response) {
|
||||||
|
try {
|
||||||
|
const themes = await ThemeService.getAllThemes();
|
||||||
|
res.json(themes);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ error: 'Erreur lors de la récupération des thèmes' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Récupérer le thème actif
|
||||||
|
static async getActiveTheme(req: Request, res: Response) {
|
||||||
|
try {
|
||||||
|
const theme = await ThemeService.getActiveTheme();
|
||||||
|
if (!theme) {
|
||||||
|
return res.status(404).json({ error: 'Aucun thème actif trouvé' });
|
||||||
|
}
|
||||||
|
res.json(theme);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ error: 'Erreur lors de la récupération du thème actif' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Activer un thème
|
||||||
|
static async activateTheme(req: Request, res: Response) {
|
||||||
|
try {
|
||||||
|
const { themeId } = req.params;
|
||||||
|
const theme = await ThemeService.activateTheme(themeId);
|
||||||
|
res.json(theme);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ error: 'Erreur lors de l\'activation du thème' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mettre à jour un thème
|
||||||
|
static async updateTheme(req: Request, res: Response) {
|
||||||
|
try {
|
||||||
|
const { themeId } = req.params;
|
||||||
|
const themeData: Partial<ThemeData> = req.body;
|
||||||
|
const theme = await ThemeService.updateTheme(themeId, themeData);
|
||||||
|
res.json(theme);
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ error: 'Erreur lors de la mise à jour du thème' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supprimer un thème
|
||||||
|
static async deleteTheme(req: Request, res: Response) {
|
||||||
|
try {
|
||||||
|
const { themeId } = req.params;
|
||||||
|
await ThemeService.deleteTheme(themeId);
|
||||||
|
res.status(204).send();
|
||||||
|
} catch (error) {
|
||||||
|
res.status(500).json({ error: 'Erreur lors de la suppression du thème' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
95
backend/src/routes/auth.ts
Normal file
95
backend/src/routes/auth.ts
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
import { Router } from 'express';
|
||||||
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
import * as bcrypt from 'bcrypt';
|
||||||
|
import jwt from 'jsonwebtoken';
|
||||||
|
|
||||||
|
const router = Router();
|
||||||
|
const prisma = new PrismaClient();
|
||||||
|
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key';
|
||||||
|
|
||||||
|
// Route de connexion
|
||||||
|
router.post('/login', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { email, password } = req.body;
|
||||||
|
|
||||||
|
// Vérifier les identifiants
|
||||||
|
const admin = await prisma.admin.findUnique({
|
||||||
|
where: { email }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!admin) {
|
||||||
|
return res.status(401).json({ error: 'Identifiants invalides' });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vérifier le mot de passe
|
||||||
|
const validPassword = await bcrypt.compare(password, admin.password);
|
||||||
|
if (!validPassword) {
|
||||||
|
return res.status(401).json({ error: 'Identifiants invalides' });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vérifier si le mot de passe doit être changé
|
||||||
|
if (!admin.passwordChanged) {
|
||||||
|
return res.status(403).json({
|
||||||
|
error: 'Changement de mot de passe requis',
|
||||||
|
requiresPasswordChange: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Générer le token JWT
|
||||||
|
const token = jwt.sign(
|
||||||
|
{
|
||||||
|
id: admin.id,
|
||||||
|
email: admin.email,
|
||||||
|
role: 'admin'
|
||||||
|
},
|
||||||
|
JWT_SECRET,
|
||||||
|
{ expiresIn: '24h' }
|
||||||
|
);
|
||||||
|
|
||||||
|
res.json({ token });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erreur lors de la connexion:', error);
|
||||||
|
res.status(500).json({ error: 'Erreur serveur' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Route de changement de mot de passe
|
||||||
|
router.post('/change-password', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { email, currentPassword, newPassword } = req.body;
|
||||||
|
|
||||||
|
// Vérifier l'administrateur
|
||||||
|
const admin = await prisma.admin.findUnique({
|
||||||
|
where: { email }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!admin) {
|
||||||
|
return res.status(404).json({ error: 'Administrateur non trouvé' });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vérifier l'ancien mot de passe
|
||||||
|
const validPassword = await bcrypt.compare(currentPassword, admin.password);
|
||||||
|
if (!validPassword) {
|
||||||
|
return res.status(401).json({ error: 'Mot de passe actuel incorrect' });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hasher le nouveau mot de passe
|
||||||
|
const hashedPassword = await bcrypt.hash(newPassword, 10);
|
||||||
|
|
||||||
|
// Mettre à jour le mot de passe
|
||||||
|
await prisma.admin.update({
|
||||||
|
where: { id: admin.id },
|
||||||
|
data: {
|
||||||
|
password: hashedPassword,
|
||||||
|
passwordChanged: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
res.json({ message: 'Mot de passe changé avec succès' });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erreur lors du changement de mot de passe:', error);
|
||||||
|
res.status(500).json({ error: 'Erreur serveur' });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default router;
|
||||||
@ -1,11 +1,10 @@
|
|||||||
import { Body, Controller, Get, Post, Req, UnauthorizedException, BadRequestException, UseGuards } from '@nestjs/common';
|
import { Body, Controller, Get, Post, Req, UnauthorizedException, UseGuards } from '@nestjs/common';
|
||||||
import { LoginDto } from './dto/login.dto';
|
import { LoginDto } from './dto/login.dto';
|
||||||
import { AuthService } from './auth.service';
|
import { AuthService } from './auth.service';
|
||||||
import { Public } from 'src/common/decorators/public.decorator';
|
import { Public } from 'src/common/decorators/public.decorator';
|
||||||
import { RegisterDto } from './dto/register.dto';
|
import { RegisterDto } from './dto/register.dto';
|
||||||
import { RegisterParentDto } from './dto/register-parent.dto';
|
import { RegisterParentDto } from './dto/register-parent.dto';
|
||||||
import { RegisterParentCompletDto } from './dto/register-parent-complet.dto';
|
import { RegisterParentCompletDto } from './dto/register-parent-complet.dto';
|
||||||
import { ChangePasswordRequiredDto } from './dto/change-password.dto';
|
|
||||||
import { ApiBearerAuth, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
import { ApiBearerAuth, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||||
import { AuthGuard } from 'src/common/guards/auth.guard';
|
import { AuthGuard } from 'src/common/guards/auth.guard';
|
||||||
import type { Request } from 'express';
|
import type { Request } from 'express';
|
||||||
@ -88,7 +87,6 @@ export class AuthController {
|
|||||||
prenom: user.prenom ?? '',
|
prenom: user.prenom ?? '',
|
||||||
nom: user.nom ?? '',
|
nom: user.nom ?? '',
|
||||||
statut: user.statut,
|
statut: user.statut,
|
||||||
changement_mdp_obligatoire: user.changement_mdp_obligatoire,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,31 +96,5 @@ export class AuthController {
|
|||||||
logout(@User() currentUser: Users) {
|
logout(@User() currentUser: Users) {
|
||||||
return this.authService.logout(currentUser.id);
|
return this.authService.logout(currentUser.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post('change-password-required')
|
|
||||||
@UseGuards(AuthGuard)
|
|
||||||
@ApiBearerAuth('access-token')
|
|
||||||
@ApiOperation({
|
|
||||||
summary: 'Changement de mot de passe obligatoire',
|
|
||||||
description: 'Permet de changer le mot de passe lors de la première connexion (flag changement_mdp_obligatoire)'
|
|
||||||
})
|
|
||||||
@ApiResponse({ status: 200, description: 'Mot de passe changé avec succès' })
|
|
||||||
@ApiResponse({ status: 400, description: 'Mot de passe actuel incorrect ou confirmation non correspondante' })
|
|
||||||
@ApiResponse({ status: 403, description: 'Changement de mot de passe non requis pour cet utilisateur' })
|
|
||||||
async changePasswordRequired(
|
|
||||||
@User() currentUser: Users,
|
|
||||||
@Body() dto: ChangePasswordRequiredDto,
|
|
||||||
) {
|
|
||||||
// Vérifier que les mots de passe correspondent
|
|
||||||
if (dto.nouveau_mot_de_passe !== dto.confirmation_mot_de_passe) {
|
|
||||||
throw new BadRequestException('Les mots de passe ne correspondent pas');
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.authService.changePasswordRequired(
|
|
||||||
currentUser.id,
|
|
||||||
dto.mot_de_passe_actuel,
|
|
||||||
dto.nouveau_mot_de_passe,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -455,60 +455,6 @@ export class AuthService {
|
|||||||
return `/uploads/photos/${nomFichierUnique}`;
|
return `/uploads/photos/${nomFichierUnique}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Changement de mot de passe obligatoire (première connexion)
|
|
||||||
*/
|
|
||||||
async changePasswordRequired(
|
|
||||||
userId: string,
|
|
||||||
motDePasseActuel: string,
|
|
||||||
nouveauMotDePasse: string,
|
|
||||||
) {
|
|
||||||
const user = await this.usersRepo.findOne({ where: { id: userId } });
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
throw new UnauthorizedException('Utilisateur introuvable');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vérifier que le changement est bien obligatoire
|
|
||||||
if (!user.changement_mdp_obligatoire) {
|
|
||||||
throw new BadRequestException(
|
|
||||||
'Le changement de mot de passe n\'est pas requis pour cet utilisateur',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vérifier que l'utilisateur a un mot de passe
|
|
||||||
if (!user.password) {
|
|
||||||
throw new BadRequestException('Compte non activé');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vérifier le mot de passe actuel
|
|
||||||
const motDePasseValide = await bcrypt.compare(motDePasseActuel, user.password);
|
|
||||||
if (!motDePasseValide) {
|
|
||||||
throw new BadRequestException('Mot de passe actuel incorrect');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vérifier que le nouveau mot de passe est différent de l'ancien
|
|
||||||
const memeMotDePasse = await bcrypt.compare(nouveauMotDePasse, user.password);
|
|
||||||
if (memeMotDePasse) {
|
|
||||||
throw new BadRequestException(
|
|
||||||
'Le nouveau mot de passe doit être différent de l\'ancien',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hasher et sauvegarder le nouveau mot de passe
|
|
||||||
const sel = await bcrypt.genSalt(12);
|
|
||||||
user.password = await bcrypt.hash(nouveauMotDePasse, sel);
|
|
||||||
user.changement_mdp_obligatoire = false;
|
|
||||||
user.modifie_le = new Date();
|
|
||||||
|
|
||||||
await this.usersRepo.save(user);
|
|
||||||
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
message: 'Mot de passe changé avec succès',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async logout(userId: string) {
|
async logout(userId: string) {
|
||||||
return { success: true, message: 'Deconnexion'}
|
return { success: true, message: 'Deconnexion'}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,23 +0,0 @@
|
|||||||
import { ApiProperty } from '@nestjs/swagger';
|
|
||||||
import { IsString, MinLength, Matches } from 'class-validator';
|
|
||||||
|
|
||||||
export class ChangePasswordRequiredDto {
|
|
||||||
@ApiProperty({ description: 'Mot de passe actuel' })
|
|
||||||
@IsString()
|
|
||||||
mot_de_passe_actuel: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'Nouveau mot de passe (min 8 caractères, 1 majuscule, 1 chiffre)',
|
|
||||||
minLength: 8
|
|
||||||
})
|
|
||||||
@IsString()
|
|
||||||
@MinLength(8, { message: 'Le mot de passe doit contenir au moins 8 caractères' })
|
|
||||||
@Matches(/^(?=.*[A-Z])(?=.*\d)/, {
|
|
||||||
message: 'Le mot de passe doit contenir au moins une majuscule et un chiffre'
|
|
||||||
})
|
|
||||||
nouveau_mot_de_passe: string;
|
|
||||||
|
|
||||||
@ApiProperty({ description: 'Confirmation du nouveau mot de passe' })
|
|
||||||
@IsString()
|
|
||||||
confirmation_mot_de_passe: string;
|
|
||||||
}
|
|
||||||
@ -19,7 +19,4 @@ export class ProfileResponseDto {
|
|||||||
|
|
||||||
@ApiProperty({ enum: StatutUtilisateurType })
|
@ApiProperty({ enum: StatutUtilisateurType })
|
||||||
statut: StatutUtilisateurType;
|
statut: StatutUtilisateurType;
|
||||||
|
|
||||||
@ApiProperty({ description: 'Indique si le changement de mot de passe est obligatoire à la première connexion' })
|
|
||||||
changement_mdp_obligatoire: boolean;
|
|
||||||
}
|
}
|
||||||
|
|||||||
14
backend/src/routes/theme.routes.ts
Normal file
14
backend/src/routes/theme.routes.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { Router } from 'express';
|
||||||
|
import { ThemeController } from '../controllers/theme.controller';
|
||||||
|
|
||||||
|
const router = Router();
|
||||||
|
|
||||||
|
// Routes pour les thèmes
|
||||||
|
router.post('/', ThemeController.createTheme);
|
||||||
|
router.get('/', ThemeController.getAllThemes);
|
||||||
|
router.get('/active', ThemeController.getActiveTheme);
|
||||||
|
router.put('/:themeId/activate', ThemeController.activateTheme);
|
||||||
|
router.put('/:themeId', ThemeController.updateTheme);
|
||||||
|
router.delete('/:themeId', ThemeController.deleteTheme);
|
||||||
|
|
||||||
|
export default router;
|
||||||
39
backend/src/scripts/initAdmin.ts
Normal file
39
backend/src/scripts/initAdmin.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
import * as bcrypt from 'bcrypt';
|
||||||
|
|
||||||
|
const prisma = new PrismaClient();
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
try {
|
||||||
|
// Vérifier si l'administrateur existe déjà
|
||||||
|
const existingAdmin = await prisma.admin.findUnique({
|
||||||
|
where: { email: 'administrateur@ptitspas.fr' }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!existingAdmin) {
|
||||||
|
// Hasher le mot de passe
|
||||||
|
const hashedPassword = await bcrypt.hash('password', 10);
|
||||||
|
|
||||||
|
// Créer l'administrateur
|
||||||
|
await prisma.admin.create({
|
||||||
|
data: {
|
||||||
|
email: 'administrateur@ptitspas.fr',
|
||||||
|
password: hashedPassword,
|
||||||
|
firstName: 'Administrateur',
|
||||||
|
lastName: 'P\'titsPas',
|
||||||
|
passwordChanged: false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('✅ Administrateur créé avec succès');
|
||||||
|
} else {
|
||||||
|
console.log('ℹ️ L\'administrateur existe déjà');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Erreur lors de la création de l\'administrateur:', error);
|
||||||
|
} finally {
|
||||||
|
await prisma.$disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
77
backend/src/services/theme.service.ts
Normal file
77
backend/src/services/theme.service.ts
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
|
||||||
|
const prisma = new PrismaClient();
|
||||||
|
|
||||||
|
export interface ThemeData {
|
||||||
|
name: string;
|
||||||
|
primaryColor: string;
|
||||||
|
secondaryColor: string;
|
||||||
|
backgroundColor: string;
|
||||||
|
textColor: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ThemeService {
|
||||||
|
// Créer un nouveau thème
|
||||||
|
static async createTheme(data: ThemeData) {
|
||||||
|
return prisma.theme.create({
|
||||||
|
data: {
|
||||||
|
...data,
|
||||||
|
isActive: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Récupérer tous les thèmes
|
||||||
|
static async getAllThemes() {
|
||||||
|
return prisma.theme.findMany();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Récupérer le thème actif
|
||||||
|
static async getActiveTheme() {
|
||||||
|
const settings = await prisma.appSettings.findFirst({
|
||||||
|
include: {
|
||||||
|
currentTheme: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return settings?.currentTheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Activer un thème
|
||||||
|
static async activateTheme(themeId: string) {
|
||||||
|
// Désactiver tous les thèmes
|
||||||
|
await prisma.theme.updateMany({
|
||||||
|
where: { isActive: true },
|
||||||
|
data: { isActive: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
// Activer le thème sélectionné
|
||||||
|
const updatedTheme = await prisma.theme.update({
|
||||||
|
where: { id: themeId },
|
||||||
|
data: { isActive: true },
|
||||||
|
});
|
||||||
|
|
||||||
|
// Mettre à jour les paramètres de l'application
|
||||||
|
await prisma.appSettings.upsert({
|
||||||
|
where: { id: '1' },
|
||||||
|
update: { currentThemeId: themeId },
|
||||||
|
create: { id: '1', currentThemeId: themeId },
|
||||||
|
});
|
||||||
|
|
||||||
|
return updatedTheme;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mettre à jour un thème
|
||||||
|
static async updateTheme(themeId: string, data: Partial<ThemeData>) {
|
||||||
|
return prisma.theme.update({
|
||||||
|
where: { id: themeId },
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Supprimer un thème
|
||||||
|
static async deleteTheme(themeId: string) {
|
||||||
|
return prisma.theme.delete({
|
||||||
|
where: { id: themeId },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -342,28 +342,3 @@ ALTER TABLE utilisateurs
|
|||||||
INSERT INTO documents_legaux (type, version, fichier_nom, fichier_path, fichier_hash, actif, televerse_le, active_le) VALUES
|
INSERT INTO documents_legaux (type, version, fichier_nom, fichier_path, fichier_hash, actif, televerse_le, active_le) VALUES
|
||||||
('cgu', 1, 'cgu_v1_default.pdf', '/documents/legaux/cgu_v1_default.pdf', 'a3f8b2c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2', true, now(), now()),
|
('cgu', 1, 'cgu_v1_default.pdf', '/documents/legaux/cgu_v1_default.pdf', 'a3f8b2c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2', true, now(), now()),
|
||||||
('privacy', 1, 'privacy_v1_default.pdf', '/documents/legaux/privacy_v1_default.pdf', 'b4f9c3d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4', true, now(), now());
|
('privacy', 1, 'privacy_v1_default.pdf', '/documents/legaux/privacy_v1_default.pdf', 'b4f9c3d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4', true, now(), now());
|
||||||
|
|
||||||
-- ==========================================================
|
|
||||||
-- Seed : Super Administrateur par défaut
|
|
||||||
-- ==========================================================
|
|
||||||
-- Email: admin@ptits-pas.fr
|
|
||||||
-- Mot de passe: 4dm1n1strateur (hashé bcrypt)
|
|
||||||
-- IMPORTANT: Changer ce mot de passe en production !
|
|
||||||
-- ==========================================================
|
|
||||||
INSERT INTO utilisateurs (
|
|
||||||
email,
|
|
||||||
password,
|
|
||||||
prenom,
|
|
||||||
nom,
|
|
||||||
role,
|
|
||||||
statut,
|
|
||||||
changement_mdp_obligatoire
|
|
||||||
) VALUES (
|
|
||||||
'admin@ptits-pas.fr',
|
|
||||||
'$2b$12$plOZCW7lzLFkWgDPcE6p6u10EA4yErQt6Xcp5nyH3Sp/2.6EpNW.6',
|
|
||||||
'Super',
|
|
||||||
'Administrateur',
|
|
||||||
'super_admin',
|
|
||||||
'actif',
|
|
||||||
true
|
|
||||||
);
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user