Fix: Hive sync et update entité via API REST
- Correction mapping JSON membres (fk_role, chk_active) - Ajout traitement amicale au login - Fix callback onSubmit pour sync Hive après update API
This commit is contained in:
210
app/PLAN2-APP.md
210
app/PLAN2-APP.md
@@ -29,9 +29,9 @@
|
||||
|
||||
## 🚀 SESSION DE TRAVAIL - PLANNING DÉTAILLÉ
|
||||
|
||||
### Phase 0: Préparation Git et environnement (15 min)
|
||||
### Phase 0: Préparation Git et environnement (15 min) ✅
|
||||
|
||||
#### Tâche 0.1: Création de la branche (5 min)
|
||||
#### Tâche 0.1: Création de la branche (5 min) ✅
|
||||
|
||||
```bash
|
||||
# Créer et basculer sur la nouvelle branche
|
||||
@@ -41,7 +41,7 @@ git checkout -b singletons
|
||||
git branch
|
||||
```
|
||||
|
||||
#### Tâche 0.2: Backup et documentation (10 min)
|
||||
#### Tâche 0.2: Backup et documentation (10 min) ✅
|
||||
|
||||
```bash
|
||||
# Créer un backup des fichiers critiques
|
||||
@@ -72,9 +72,9 @@ git commit -m "feat: création branche singletons - début refactorisation
|
||||
- Objectif: renommer Box users -> user"
|
||||
```
|
||||
|
||||
### Phase 1: Préparation et analyse (45 min)
|
||||
### Phase 1: Préparation et analyse (45 min) ✅
|
||||
|
||||
#### Tâche 1.1: Audit du code existant (20 min)
|
||||
#### Tâche 1.1: Audit du code existant (20 min) ✅
|
||||
|
||||
```bash
|
||||
# Rechercher toutes les utilisations des services
|
||||
@@ -94,7 +94,7 @@ grep -r "usersBoxName" app/lib --include="*.dart" > audit_usersbox.txt
|
||||
- [x] Analyser les Box Hive users/amicale
|
||||
- [x] Identifier toutes les occurrences de "usersBoxName"
|
||||
|
||||
#### Tâche 1.2: Modification app_keys.dart pour renommage Box (10 min)
|
||||
#### Tâche 1.2: Modification app_keys.dart pour renommage Box (10 min) ✅
|
||||
|
||||
**Fichier à modifier** : `app/lib/core/constants/app_keys.dart`
|
||||
**Actions** :
|
||||
@@ -103,7 +103,7 @@ grep -r "usersBoxName" app/lib --include="*.dart" > audit_usersbox.txt
|
||||
- [x] Ajouter une constante de migration si nécessaire
|
||||
- [x] Documenter le changement
|
||||
|
||||
**Code à modifier** :
|
||||
**Code modifié** :
|
||||
|
||||
```dart
|
||||
// Avant
|
||||
@@ -114,28 +114,83 @@ static const String userBoxName = 'user'; // Box pour l'utilisateur unique conne
|
||||
static const String usersBoxNameOld = 'users'; // Pour migration si nécessaire
|
||||
```
|
||||
|
||||
#### Tâche 1.3: Planification de la refactorisation (15 min)
|
||||
#### Tâche 1.3: Planification de la refactorisation (15 min) ✅
|
||||
|
||||
**Actions** :
|
||||
|
||||
- [ ] Créer une liste des repositories à modifier
|
||||
- [ ] Identifier les pages/widgets accédant aux données utilisateur
|
||||
- [ ] Planifier l'ordre de modification (dépendances)
|
||||
- [ ] Préparer la stratégie de tests
|
||||
- [ ] Définir l'architecture des nouveaux services
|
||||
- [ ] Planifier la migration de la Box users -> user
|
||||
- [x] Créer une liste des repositories à modifier
|
||||
- [x] Identifier les pages/widgets accédant aux données utilisateur
|
||||
- [x] Planifier l'ordre de modification (dépendances)
|
||||
- [x] Préparer la stratégie de tests
|
||||
- [x] Définir l'architecture des nouveaux services
|
||||
- [x] Planifier la migration de la Box users -> user
|
||||
|
||||
---
|
||||
|
||||
### Phase 2: Renommage et migration de la Hive Box (30 min)
|
||||
### Phase 2: Correction des modèles et préparation (60 min) ✅
|
||||
|
||||
#### Tâche 2.1: Mise à jour main.dart pour la nouvelle Box (15 min)
|
||||
#### Tâche 2.1: Correction MembreModel selon les vrais champs (30 min) ✅
|
||||
|
||||
**Fichier modifié** : `app/lib/core/data/models/membre_model.dart`
|
||||
**Actions** :
|
||||
|
||||
- [x] Corriger les champs selon les spécifications réelles :
|
||||
|
||||
- `final int id`
|
||||
- `int? fkEntite`
|
||||
- `final int role`
|
||||
- `int? fkTitre`
|
||||
- `String? name`
|
||||
- `String? firstName`
|
||||
- `String? username`
|
||||
- `String? sectName`
|
||||
- `final String email`
|
||||
- `String? phone`
|
||||
- `String? mobile`
|
||||
- `DateTime? dateNaissance`
|
||||
- `DateTime? dateEmbauche`
|
||||
- `final DateTime createdAt`
|
||||
- `bool isActive`
|
||||
|
||||
- [x] Adapter les annotations Hive @HiveField
|
||||
- [x] Corriger fromJson() et toJson()
|
||||
- [x] Mettre à jour copyWith()
|
||||
|
||||
#### Tâche 2.2: Correction ClientModel avec champs manquants (15 min) ✅
|
||||
|
||||
**Fichier modifié** : `app/lib/core/data/models/client_model.dart`
|
||||
**Actions** :
|
||||
|
||||
- [x] Ajouter les champs manqués : `chkStripe`, `createdAt`, `updatedAt`
|
||||
- [x] Mettre à jour les annotations Hive
|
||||
- [x] Corriger fromJson() et toJson()
|
||||
- [x] Mettre à jour copyWith()
|
||||
|
||||
#### Tâche 2.3: Correction des repositories selon les vrais modèles (15 min) ✅
|
||||
|
||||
**Fichiers modifiés** :
|
||||
|
||||
- `app/lib/core/repositories/membre_repository.dart`
|
||||
- `app/lib/core/repositories/client_repository.dart`
|
||||
**Actions** :
|
||||
|
||||
- [x] Adapter MembreRepository pour les vrais champs (`isActive` au lieu de `chkActive`, etc.)
|
||||
- [x] Corriger les méthodes create/update pour éviter les reconstructions manuelles
|
||||
- [x] Utiliser copyWith() correctement
|
||||
- [x] Simplifier la logique de création API
|
||||
- [x] Corriger ClientRepository de la même manière
|
||||
|
||||
---
|
||||
|
||||
### Phase 3: Renommage et migration de la Hive Box (30 min)
|
||||
|
||||
#### Tâche 3.1: Mise à jour main.dart pour la nouvelle Box (15 min)
|
||||
|
||||
**Fichier à modifier** : `app/lib/main.dart`
|
||||
**Actions** :
|
||||
|
||||
- [x] Remplacer `AppKeys.usersBoxName` par `AppKeys.userBoxName`
|
||||
- [x] Modifier l'ouverture de la Box dans `_openEssentialHiveBoxes()`
|
||||
- [ ] Remplacer `AppKeys.usersBoxName` par `AppKeys.userBoxName`
|
||||
- [ ] Modifier l'ouverture de la Box dans `_openEssentialHiveBoxes()`
|
||||
- [ ] Ajouter logique de migration depuis l'ancienne Box si nécessaire
|
||||
|
||||
**Code à modifier** :
|
||||
@@ -170,19 +225,18 @@ Future<void> _openEssentialHiveBoxes() async {
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('⚠️ Erreur migration box users: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Tâche 2.2: Mise à jour UserRepository pour la nouvelle Box (15 min)
|
||||
#### Tâche 3.2: Mise à jour UserRepository pour la nouvelle Box (15 min)
|
||||
|
||||
**Fichier à modifier** : `app/lib/core/repositories/user_repository.dart`
|
||||
|
||||
**Actions** :
|
||||
|
||||
- [x] Remplacer toutes les occurrences de `AppKeys.usersBoxName` par `AppKeys.userBoxName`
|
||||
- [x] Modifier les getters de Box
|
||||
- [x] Tester que la compilation passe
|
||||
- [ ] Remplacer toutes les occurrences de `AppKeys.usersBoxName` par `AppKeys.userBoxName`
|
||||
- [ ] Modifier les getters de Box
|
||||
- [ ] Tester que la compilation passe
|
||||
|
||||
**Code à modifier** :
|
||||
|
||||
@@ -196,16 +250,16 @@ Box<UserModel> get _userBox => Hive.box<UserModel>(AppKeys.userBoxName);
|
||||
|
||||
---
|
||||
|
||||
### Phase 3: Création du nouveau ApiService Singleton (45 min)
|
||||
### Phase 4: Création du nouveau ApiService Singleton (45 min)
|
||||
|
||||
#### Tâche 3.1: Backup du code existant (5 min)
|
||||
#### Tâche 4.1: Backup du code existant (5 min)
|
||||
|
||||
```bash
|
||||
# Sauvegarder l'ApiService actuel
|
||||
cp app/lib/core/services/api_service.dart app/lib/core/services/api_service_backup.dart
|
||||
```
|
||||
|
||||
#### Tâche 3.2: Refactorisation ApiService en Singleton (40 min)
|
||||
#### Tâche 4.2: Refactorisation ApiService en Singleton (40 min)
|
||||
|
||||
**Fichier à modifier** : `app/lib/core/services/api_service.dart`
|
||||
**Actions** :
|
||||
@@ -287,9 +341,9 @@ class ApiService {
|
||||
|
||||
---
|
||||
|
||||
### Phase 4: Création des Services Singleton Utilisateur/Amicale (90 min)
|
||||
### Phase 5: Création des Services Singleton Utilisateur/Amicale (90 min)
|
||||
|
||||
#### Tâche 4.1: Création CurrentUserService (45 min)
|
||||
#### Tâche 5.1: Création CurrentUserService (45 min)
|
||||
|
||||
**Fichier à créer** : `app/lib/core/services/current_user_service.dart`
|
||||
**Actions** :
|
||||
@@ -457,7 +511,7 @@ class CurrentUserService extends ChangeNotifier {
|
||||
}
|
||||
```
|
||||
|
||||
#### Tâche 4.2: Création CurrentAmicaleService (45 min)
|
||||
#### Tâche 5.2: Création CurrentAmicaleService (45 min)
|
||||
|
||||
**Fichier à créer** : `app/lib/core/services/current_amicale_service.dart`
|
||||
**Actions** :
|
||||
@@ -619,9 +673,9 @@ class CurrentAmicaleService extends ChangeNotifier {
|
||||
|
||||
---
|
||||
|
||||
### Phase 5: Modification du main.dart (20 min)
|
||||
### Phase 6: Modification du main.dart (20 min)
|
||||
|
||||
#### Tâche 5.1: Intégration dans main.dart (20 min)
|
||||
#### Tâche 6.1: Intégration dans main.dart (20 min)
|
||||
|
||||
**Fichier à modifier** : `app/lib/main.dart`
|
||||
**Actions** :
|
||||
@@ -668,9 +722,9 @@ import 'package:geosector_app/core/services/current_amicale_service.dart';
|
||||
|
||||
---
|
||||
|
||||
### Phase 6: Commit intermédiaire de sécurité (10 min)
|
||||
### Phase 7: Commit intermédiaire de sécurité (10 min)
|
||||
|
||||
#### Tâche 6.1: Commit des services créés (10 min)
|
||||
#### Tâche 7.1: Commit des services créés (10 min)
|
||||
|
||||
```bash
|
||||
# Ajouter tous les nouveaux fichiers
|
||||
@@ -704,9 +758,9 @@ Box Hive:
|
||||
|
||||
---
|
||||
|
||||
### Phase 7: Modification de l'App principale (20 min)
|
||||
### Phase 8: Modification de l'App principale (20 min)
|
||||
|
||||
#### Tâche 7.1: Refactorisation app.dart (20 min)
|
||||
#### Tâche 8.1: Refactorisation app.dart (20 min)
|
||||
|
||||
**Fichier à modifier** : `app/lib/app.dart`
|
||||
|
||||
@@ -734,9 +788,9 @@ final userRepository = UserRepository(apiService);
|
||||
|
||||
---
|
||||
|
||||
### Phase 8: Refactorisation des Repositories (90 min)
|
||||
### Phase 9: Refactorisation des Repositories (90 min)
|
||||
|
||||
#### Tâche 8.1: UserRepository - Refactorisation majeure (40 min)
|
||||
#### Tâche 9.1: UserRepository - Refactorisation majeure (40 min)
|
||||
|
||||
**Fichier** : `app/lib/core/repositories/user_repository.dart`
|
||||
|
||||
@@ -855,7 +909,7 @@ class UserRepository extends ChangeNotifier {
|
||||
}
|
||||
```
|
||||
|
||||
#### Tâche 8.2: AmicaleRepository (20 min)
|
||||
#### Tâche 9.2: AmicaleRepository (20 min)
|
||||
|
||||
**Fichier** : `app/lib/core/repositories/amicale_repository.dart`
|
||||
|
||||
@@ -866,7 +920,7 @@ class UserRepository extends ChangeNotifier {
|
||||
- [ ] Simplifier l'accès à l'amicale courante
|
||||
- [ ] Intégrer avec CurrentAmicaleService
|
||||
|
||||
#### Tâche 8.3: MembreRepository (15 min)
|
||||
#### Tâche 9.3: MembreRepository (15 min)
|
||||
|
||||
**Fichier** : `app/lib/core/repositories/membre_repository.dart`
|
||||
|
||||
@@ -876,7 +930,7 @@ class UserRepository extends ChangeNotifier {
|
||||
- [ ] Utiliser `ApiService.instance` dans les méthodes
|
||||
- [ ] Utiliser CurrentUserService pour les vérifications de permissions
|
||||
|
||||
#### Tâche 8.4: Autres repositories (15 min)
|
||||
#### Tâche 9.4: Autres repositories (15 min)
|
||||
|
||||
**Fichiers à traiter** :
|
||||
|
||||
@@ -893,9 +947,9 @@ class UserRepository extends ChangeNotifier {
|
||||
|
||||
---
|
||||
|
||||
### Phase 9: Modification des Pages principales (120 min)
|
||||
### Phase 10: Modification des Pages principales (120 min)
|
||||
|
||||
#### Tâche 9.1: Pages d'authentification (30 min)
|
||||
#### Tâche 10.1: Pages d'authentification (30 min)
|
||||
|
||||
**Fichiers** :
|
||||
|
||||
@@ -954,7 +1008,7 @@ class _LoginPageState extends State<LoginPage> {
|
||||
}
|
||||
```
|
||||
|
||||
#### Tâche 9.2: Dashboard pages (30 min)
|
||||
#### Tâche 10.2: Dashboard pages (30 min)
|
||||
|
||||
**Fichiers** :
|
||||
|
||||
@@ -1041,7 +1095,7 @@ class AdminDashboardPage extends StatelessWidget {
|
||||
}
|
||||
```
|
||||
|
||||
#### Tâche 9.3: Pages de gestion (30 min)
|
||||
#### Tâche 10.3: Pages de gestion (30 min)
|
||||
|
||||
**Fichiers** :
|
||||
|
||||
@@ -1055,7 +1109,7 @@ class AdminDashboardPage extends StatelessWidget {
|
||||
- [ ] Utiliser les services singleton
|
||||
- [ ] Simplifier l'accès aux données
|
||||
|
||||
#### Tâche 9.4: Pages formulaires (30 min)
|
||||
#### Tâche 10.4: Pages formulaires (30 min)
|
||||
|
||||
**Fichiers contenant des formulaires** :
|
||||
|
||||
@@ -1071,9 +1125,9 @@ class AdminDashboardPage extends StatelessWidget {
|
||||
|
||||
---
|
||||
|
||||
### Phase 10: Modification des Widgets (90 min)
|
||||
### Phase 11: Modification des Widgets (90 min)
|
||||
|
||||
#### Tâche 10.1: Création de widgets d'information (30 min)
|
||||
#### Tâche 11.1: Création de widgets d'information (30 min)
|
||||
|
||||
**Nouveaux widgets à créer** :
|
||||
|
||||
@@ -1209,7 +1263,7 @@ class AmicaleInfoWidget extends StatelessWidget {
|
||||
}
|
||||
```
|
||||
|
||||
#### Tâche 10.2: Widgets de tableaux (30 min)
|
||||
#### Tâche 11.2: Widgets de tableaux (30 min)
|
||||
|
||||
**Fichiers** :
|
||||
|
||||
@@ -1223,7 +1277,7 @@ class AmicaleInfoWidget extends StatelessWidget {
|
||||
- [ ] Utiliser CurrentUserService pour les vérifications de permissions
|
||||
- [ ] Simplifier la logique d'affichage conditionnel
|
||||
|
||||
#### Tâche 10.3: Widgets de formulaires (30 min)
|
||||
#### Tâche 11.3: Widgets de formulaires (30 min)
|
||||
|
||||
**Fichiers** :
|
||||
|
||||
@@ -1238,9 +1292,9 @@ class AmicaleInfoWidget extends StatelessWidget {
|
||||
|
||||
---
|
||||
|
||||
### Phase 11: Mise à jour du Router et Navigation (45 min)
|
||||
### Phase 12: Mise à jour du Router et Navigation (45 min)
|
||||
|
||||
#### Tâche 11.1: Configuration GoRouter (30 min)
|
||||
#### Tâche 12.1: Configuration GoRouter (30 min)
|
||||
|
||||
**Fichier** : `app/lib/core/routing/app_router.dart`
|
||||
|
||||
@@ -1275,7 +1329,7 @@ GoRoute(
|
||||
)
|
||||
```
|
||||
|
||||
#### Tâche 11.2: Création AuthGuard (15 min)
|
||||
#### Tâche 12.2: Création AuthGuard (15 min)
|
||||
|
||||
**Fichier à créer** : `app/lib/core/routing/auth_guard.dart`
|
||||
|
||||
@@ -1327,9 +1381,9 @@ class AuthGuard {
|
||||
|
||||
---
|
||||
|
||||
### Phase 12: Tests et validation (60 min)
|
||||
### Phase 13: Tests et validation (60 min)
|
||||
|
||||
#### Tâche 12.1: Tests de compilation (15 min)
|
||||
#### Tâche 13.1: Tests de compilation (15 min)
|
||||
|
||||
**Actions** :
|
||||
|
||||
@@ -1338,7 +1392,7 @@ class AuthGuard {
|
||||
- [ ] Corriger erreurs de compilation
|
||||
- [ ] Vérifier warnings
|
||||
|
||||
#### Tâche 12.2: Tests fonctionnels de base (30 min)
|
||||
#### Tâche 13.2: Tests fonctionnels de base (30 min)
|
||||
|
||||
**Scénarios à tester** :
|
||||
|
||||
@@ -1350,7 +1404,7 @@ class AuthGuard {
|
||||
- [ ] Persistence des données au redémarrage
|
||||
- [ ] Migration de la Box users -> user
|
||||
|
||||
#### Tâche 12.3: Tests des services singleton (15 min)
|
||||
#### Tâche 13.3: Tests des services singleton (15 min)
|
||||
|
||||
**Actions** :
|
||||
|
||||
@@ -1361,9 +1415,9 @@ class AuthGuard {
|
||||
|
||||
---
|
||||
|
||||
### Phase 13: Tests unitaires (45 min)
|
||||
### Phase 14: Tests unitaires (45 min)
|
||||
|
||||
#### Tâche 13.1: Tests ApiService (15 min)
|
||||
#### Tâche 14.1: Tests ApiService (15 min)
|
||||
|
||||
**Fichier** : `test/core/services/api_service_test.dart`
|
||||
|
||||
@@ -1374,7 +1428,7 @@ class AuthGuard {
|
||||
- [ ] Tester thread-safety
|
||||
- [ ] Mocker les appels réseau
|
||||
|
||||
#### Tâche 13.2: Tests CurrentUserService (15 min)
|
||||
#### Tâche 14.2: Tests CurrentUserService (15 min)
|
||||
|
||||
**Fichier** : `test/core/services/current_user_service_test.dart`
|
||||
|
||||
@@ -1385,7 +1439,7 @@ class AuthGuard {
|
||||
- [ ] Tester persistence Hive avec nouvelle Box
|
||||
- [ ] Tester les getters de rôles
|
||||
|
||||
#### Tâche 13.3: Tests CurrentAmicaleService (15 min)
|
||||
#### Tâche 14.3: Tests CurrentAmicaleService (15 min)
|
||||
|
||||
**Fichier** : `test/core/services/current_amicale_service_test.dart`
|
||||
|
||||
@@ -1398,9 +1452,9 @@ class AuthGuard {
|
||||
|
||||
---
|
||||
|
||||
### Phase 14: Optimisations et nettoyage (45 min)
|
||||
### Phase 15: Optimisations et nettoyage (45 min)
|
||||
|
||||
#### Tâche 14.1: Optimisation des performances (20 min)
|
||||
#### Tâche 15.1: Optimisation des performances (20 min)
|
||||
|
||||
**Actions** :
|
||||
|
||||
@@ -1409,7 +1463,7 @@ class AuthGuard {
|
||||
- [ ] Éliminer les rebuilds inutiles
|
||||
- [ ] Vérifier les memory leaks
|
||||
|
||||
#### Tâche 14.2: Nettoyage du code (25 min)
|
||||
#### Tâche 15.2: Nettoyage du code (25 min)
|
||||
|
||||
**Actions** :
|
||||
|
||||
@@ -1421,9 +1475,9 @@ class AuthGuard {
|
||||
|
||||
---
|
||||
|
||||
### Phase 15: Commit final et documentation (30 min)
|
||||
### Phase 16: Commit final et documentation (30 min)
|
||||
|
||||
#### Tâche 15.1: Commit final (15 min)
|
||||
#### Tâche 16.1: Commit final (15 min)
|
||||
|
||||
```bash
|
||||
# Ajouter tous les fichiers modifiés
|
||||
@@ -1447,8 +1501,15 @@ Hive Box:
|
||||
Repositories:
|
||||
✅ UserRepository simplifié (plus d'injection ApiService)
|
||||
✅ AmicaleRepository simplifié
|
||||
✅ MembreRepository corrigé selon vrais champs modèle
|
||||
✅ ClientRepository corrigé selon vrais champs modèle
|
||||
✅ Tous les repositories utilisent ApiService.instance
|
||||
|
||||
Models:
|
||||
✅ MembreModel corrigé avec les vrais champs
|
||||
✅ ClientModel complété avec champs manquants
|
||||
✅ Méthodes create/update simplifiées dans repositories
|
||||
|
||||
UI/UX:
|
||||
✅ Pages sans injections de dépendances
|
||||
✅ Widgets UserInfoWidget et AmicaleInfoWidget réactifs
|
||||
@@ -1468,6 +1529,7 @@ BREAKING CHANGES:
|
||||
- Box Hive users renommée en user
|
||||
- Constructeurs de pages/widgets simplifiés
|
||||
- Pattern d'accès aux données utilisateur/amicale changé
|
||||
- Champs de modèles corrigés selon spécifications
|
||||
|
||||
MIGRATION: Automatique au démarrage de l'app"
|
||||
|
||||
@@ -1475,7 +1537,7 @@ MIGRATION: Automatique au démarrage de l'app"
|
||||
git push origin singletons
|
||||
```
|
||||
|
||||
#### Tâche 15.2: Documentation finale (15 min)
|
||||
#### Tâche 16.2: Documentation finale (15 min)
|
||||
|
||||
**Actions** :
|
||||
|
||||
@@ -1523,15 +1585,29 @@ final hasGps = CurrentAmicaleService.instance.hasGpsCoordinates;
|
||||
final response = await ApiService.instance.get('/endpoint');
|
||||
```
|
||||
|
||||
## Corrections modèles
|
||||
|
||||
### MembreModel
|
||||
|
||||
- Corrigé selon les vrais champs : `isActive`, `role`, etc.
|
||||
- Plus de champs inventés
|
||||
|
||||
### ClientModel
|
||||
|
||||
- Ajout champs manquants : `chkStripe`, `createdAt`, `updatedAt`
|
||||
|
||||
## Migration
|
||||
|
||||
- Box `users` renommée en `user` (migration automatique)
|
||||
- Plus d'injection de dépendances dans les constructeurs
|
||||
- Widgets réactifs avec ListenableBuilder
|
||||
- Repositories simplifiés
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📁 Structure finale des fichiers modifiés/créés
|
||||
|
||||
### ✅ Fichiers déjà traités
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user