feat(backend): API admin configuration avec test SMTP (#6)
Implémentation de l'API REST pour la gestion de la configuration système par les administrateurs. Nouveaux fichiers : - modules/config/config.controller.ts : Controller REST - modules/config/dto/update-config.dto.ts : DTO mise à jour - modules/config/dto/test-smtp.dto.ts : DTO test SMTP Endpoints créés : ✅ GET /api/v1/configuration/setup/status → Vérifier si la configuration initiale est terminée ✅ POST /api/v1/configuration/setup/complete → Marquer la configuration comme terminée ✅ POST /api/v1/configuration/test-smtp → Tester la connexion SMTP + envoi email de test ✅ PATCH /api/v1/configuration/bulk → Mise à jour multiple des configurations ✅ GET /api/v1/configuration → Récupérer toutes les configurations (admin) ✅ GET /api/v1/configuration/:category → Récupérer par catégorie (email/app/security) Fonctionnalités : - Validation des données avec class-validator - Test SMTP avec Nodemailer - Envoi d'email de test HTML - Gestion d'erreurs complète - Rechargement automatique du cache - Traçabilité des modifications Sécurité : - Guards commentés (à activer avec JWT) - Validation des catégories - Mots de passe masqués dans les réponses Dépendances ajoutées : - nodemailer ^6.9.16 - @types/nodemailer ^6.4.16 Tests effectués : ✅ GET /setup/status → {setupCompleted: false} ✅ GET /email → 8 configurations email ✅ Build Docker réussi ✅ Toutes les routes mappées correctement Ref: #6
This commit is contained in:
@@ -0,0 +1,232 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Patch,
|
||||
Post,
|
||||
Body,
|
||||
Param,
|
||||
UseGuards,
|
||||
Request,
|
||||
HttpStatus,
|
||||
HttpException,
|
||||
} from '@nestjs/common';
|
||||
import { AppConfigService } from './config.service';
|
||||
import { UpdateConfigDto } from './dto/update-config.dto';
|
||||
import { TestSmtpDto } from './dto/test-smtp.dto';
|
||||
|
||||
@Controller('configuration')
|
||||
export class ConfigController {
|
||||
constructor(private readonly configService: AppConfigService) {}
|
||||
|
||||
/**
|
||||
* Vérifier si la configuration initiale est terminée
|
||||
* GET /api/v1/configuration/setup/status
|
||||
*/
|
||||
@Get('setup/status')
|
||||
async getSetupStatus() {
|
||||
try {
|
||||
const isCompleted = this.configService.isSetupCompleted();
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
setupCompleted: isCompleted,
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
{
|
||||
success: false,
|
||||
message: 'Erreur lors de la vérification du statut de configuration',
|
||||
error: error.message,
|
||||
},
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marquer la configuration initiale comme terminée
|
||||
* POST /api/v1/configuration/setup/complete
|
||||
*/
|
||||
@Post('setup/complete')
|
||||
// @UseGuards(JwtAuthGuard, RolesGuard)
|
||||
// @Roles('super_admin')
|
||||
async completeSetup(@Request() req: any) {
|
||||
try {
|
||||
// TODO: Récupérer l'ID utilisateur depuis le JWT
|
||||
const userId = req.user?.id || 'system';
|
||||
|
||||
await this.configService.markSetupCompleted(userId);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: 'Configuration initiale terminée avec succès',
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
{
|
||||
success: false,
|
||||
message: 'Erreur lors de la finalisation de la configuration',
|
||||
error: error.message,
|
||||
},
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test de la connexion SMTP
|
||||
* POST /api/v1/configuration/test-smtp
|
||||
*/
|
||||
@Post('test-smtp')
|
||||
// @UseGuards(JwtAuthGuard, RolesGuard)
|
||||
// @Roles('super_admin')
|
||||
async testSmtp(@Body() testSmtpDto: TestSmtpDto) {
|
||||
try {
|
||||
const result = await this.configService.testSmtpConnection(testSmtpDto.testEmail);
|
||||
|
||||
if (result.success) {
|
||||
return {
|
||||
success: true,
|
||||
message: 'Connexion SMTP réussie. Email de test envoyé.',
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
success: false,
|
||||
message: 'Échec du test SMTP',
|
||||
error: result.error,
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
{
|
||||
success: false,
|
||||
message: 'Erreur lors du test SMTP',
|
||||
error: error.message,
|
||||
},
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mise à jour multiple des configurations
|
||||
* PATCH /api/v1/configuration/bulk
|
||||
*/
|
||||
@Patch('bulk')
|
||||
// @UseGuards(JwtAuthGuard, RolesGuard)
|
||||
// @Roles('super_admin')
|
||||
async updateBulk(@Body() updateConfigDto: UpdateConfigDto, @Request() req: any) {
|
||||
try {
|
||||
// TODO: Récupérer l'ID utilisateur depuis le JWT
|
||||
const userId = req.user?.id || null;
|
||||
|
||||
let updated = 0;
|
||||
const errors: string[] = [];
|
||||
|
||||
// Parcourir toutes les clés du DTO
|
||||
for (const [key, value] of Object.entries(updateConfigDto)) {
|
||||
if (value !== undefined) {
|
||||
try {
|
||||
await this.configService.set(key, value, userId);
|
||||
updated++;
|
||||
} catch (error) {
|
||||
errors.push(`${key}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Recharger le cache après les modifications
|
||||
await this.configService.loadCache();
|
||||
|
||||
if (errors.length > 0) {
|
||||
return {
|
||||
success: false,
|
||||
message: 'Certaines configurations n\'ont pas pu être mises à jour',
|
||||
updated,
|
||||
errors,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: 'Configuration mise à jour avec succès',
|
||||
updated,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
{
|
||||
success: false,
|
||||
message: 'Erreur lors de la mise à jour des configurations',
|
||||
error: error.message,
|
||||
},
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupérer toutes les configurations (pour l'admin)
|
||||
* GET /api/v1/configuration
|
||||
*/
|
||||
@Get()
|
||||
// @UseGuards(JwtAuthGuard, RolesGuard)
|
||||
// @Roles('super_admin')
|
||||
async getAll() {
|
||||
try {
|
||||
const configs = await this.configService.getAll();
|
||||
return {
|
||||
success: true,
|
||||
data: configs,
|
||||
};
|
||||
} catch (error) {
|
||||
throw new HttpException(
|
||||
{
|
||||
success: false,
|
||||
message: 'Erreur lors de la récupération des configurations',
|
||||
error: error.message,
|
||||
},
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupérer les configurations par catégorie
|
||||
* GET /api/v1/configuration/:category
|
||||
*/
|
||||
@Get(':category')
|
||||
// @UseGuards(JwtAuthGuard, RolesGuard)
|
||||
// @Roles('super_admin')
|
||||
async getByCategory(@Param('category') category: string) {
|
||||
try {
|
||||
if (!['email', 'app', 'security'].includes(category)) {
|
||||
throw new HttpException(
|
||||
{
|
||||
success: false,
|
||||
message: 'Catégorie invalide. Valeurs acceptées: email, app, security',
|
||||
},
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
}
|
||||
|
||||
const configs = await this.configService.getByCategory(category);
|
||||
return {
|
||||
success: true,
|
||||
data: configs,
|
||||
};
|
||||
} catch (error) {
|
||||
if (error instanceof HttpException) {
|
||||
throw error;
|
||||
}
|
||||
throw new HttpException(
|
||||
{
|
||||
success: false,
|
||||
message: 'Erreur lors de la récupération des configurations',
|
||||
error: error.message,
|
||||
},
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user