feat: Ajout de la gestion des utilisateurs et optimisation du chargement des données
Cette mise à jour introduit la gestion complète des utilisateurs (création, mise à jour, suppression) via des Cloud Functions et optimise de manière significative le chargement des données dans toute l'application.
**Features :**
- **Gestion des utilisateurs (Backend & Frontend) :**
- Ajout des Cloud Functions `getUser`, `updateUser` et `deleteUser` pour gérer les utilisateurs de manière sécurisée, en respectant les permissions des rôles.
- L'authentification passe désormais par `onCall` pour plus de sécurité.
- **Optimisation du chargement des données :**
- Introduction de nouvelles Cloud Functions `getEquipmentsByIds` et `getContainersByIds` pour récupérer uniquement les documents nécessaires, réduisant ainsi la charge sur le client et Firestore.
- Les fournisseurs (`EquipmentProvider`, `ContainerProvider`) ont été refactorisés pour utiliser un chargement à la demande (`ensureLoaded`) et mettre en cache les données récupérées.
- Les écrans de détails et de préparation d'événements n'utilisent plus de `Stream` globaux, mais chargent les équipements et boites spécifiques via ces nouvelles fonctions, améliorant considérablement les performances.
**Refactorisation et Améliorations :**
- **Backend (Cloud Functions) :**
- Le service de vérification de disponibilité (`checkEquipmentAvailability`) est désormais une Cloud Function, déplaçant la logique métier côté serveur.
- La récupération des données (utilisateurs, événements, alertes) a été centralisée derrière des Cloud Functions, remplaçant les appels directs à Firestore depuis le client.
- Amélioration de la sérialisation des données (timestamps, références) dans les réponses des fonctions.
- **Frontend (Flutter) :**
- `LocalUserProvider` charge désormais les informations de l'utilisateur connecté via la fonction `getCurrentUser`, incluant son rôle et ses permissions en un seul appel.
- `AlertProvider` utilise des fonctions pour charger et manipuler les alertes, abandonnant le `Stream` Firestore.
- `EventAvailabilityService` utilise maintenant la Cloud Function `checkEquipmentAvailability` au lieu d'une logique client complexe.
- Correction de la gestion des références de rôles (`roles/ADMIN`) et des `DocumentReference` pour les utilisateurs dans l'ensemble de l'application.
- Le service d'export ICS (`IcsExportService`) a été simplifié, partant du principe que les données nécessaires (utilisateurs, options) sont déjà chargées dans l'application.
This commit is contained in:
@@ -84,16 +84,6 @@ class DataService {
|
||||
}
|
||||
}
|
||||
|
||||
/// Met à jour un utilisateur
|
||||
Future<void> updateUser(String userId, Map<String, dynamic> data) async {
|
||||
try {
|
||||
final requestData = {'userId': userId, ...data};
|
||||
await _apiService.call('updateUser', requestData);
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors de la mise à jour de l\'utilisateur: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Met à jour un événement
|
||||
Future<void> updateEvent(String eventId, Map<String, dynamic> data) async {
|
||||
try {
|
||||
@@ -271,6 +261,28 @@ class DataService {
|
||||
}
|
||||
}
|
||||
|
||||
/// Récupère plusieurs équipements par leurs IDs
|
||||
Future<List<Map<String, dynamic>>> getEquipmentsByIds(List<String> equipmentIds) async {
|
||||
try {
|
||||
if (equipmentIds.isEmpty) return [];
|
||||
|
||||
print('[DataService] Getting equipments by IDs: ${equipmentIds.length} items');
|
||||
final result = await _apiService.call('getEquipmentsByIds', {
|
||||
'equipmentIds': equipmentIds,
|
||||
});
|
||||
final equipments = result['equipments'] as List<dynamic>?;
|
||||
if (equipments == null) {
|
||||
print('[DataService] No equipments in result');
|
||||
return [];
|
||||
}
|
||||
print('[DataService] Found ${equipments.length} equipments by IDs');
|
||||
return equipments.map((e) => e as Map<String, dynamic>).toList();
|
||||
} catch (e) {
|
||||
print('[DataService] Error getting equipments by IDs: $e');
|
||||
throw Exception('Erreur lors de la récupération des équipements: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Récupère tous les conteneurs
|
||||
Future<List<Map<String, dynamic>>> getContainers() async {
|
||||
try {
|
||||
@@ -283,6 +295,28 @@ class DataService {
|
||||
}
|
||||
}
|
||||
|
||||
/// Récupère plusieurs conteneurs par leurs IDs
|
||||
Future<List<Map<String, dynamic>>> getContainersByIds(List<String> containerIds) async {
|
||||
try {
|
||||
if (containerIds.isEmpty) return [];
|
||||
|
||||
print('[DataService] Getting containers by IDs: ${containerIds.length} items');
|
||||
final result = await _apiService.call('getContainersByIds', {
|
||||
'containerIds': containerIds,
|
||||
});
|
||||
final containers = result['containers'] as List<dynamic>?;
|
||||
if (containers == null) {
|
||||
print('[DataService] No containers in result');
|
||||
return [];
|
||||
}
|
||||
print('[DataService] Found ${containers.length} containers by IDs');
|
||||
return containers.map((e) => e as Map<String, dynamic>).toList();
|
||||
} catch (e) {
|
||||
print('[DataService] Error getting containers by IDs: $e');
|
||||
throw Exception('Erreur lors de la récupération des conteneurs: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Récupère les maintenances (optionnellement filtrées par équipement)
|
||||
Future<List<Map<String, dynamic>>> getMaintenances({String? equipmentId}) async {
|
||||
try {
|
||||
@@ -298,29 +332,6 @@ class DataService {
|
||||
}
|
||||
}
|
||||
|
||||
/// Récupère les alertes
|
||||
Future<List<Map<String, dynamic>>> getAlerts() async {
|
||||
try {
|
||||
final result = await _apiService.call('getAlerts', {});
|
||||
final alerts = result['alerts'] as List<dynamic>?;
|
||||
if (alerts == null) return [];
|
||||
return alerts.map((e) => e as Map<String, dynamic>).toList();
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors de la récupération des alertes: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Récupère les utilisateurs (filtrés selon permissions)
|
||||
Future<List<Map<String, dynamic>>> getUsers() async {
|
||||
try {
|
||||
final result = await _apiService.call('getUsers', {});
|
||||
final users = result['users'] as List<dynamic>?;
|
||||
if (users == null) return [];
|
||||
return users.map((e) => e as Map<String, dynamic>).toList();
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors de la récupération des utilisateurs: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Récupère les containers contenant un équipement spécifique
|
||||
Future<List<Map<String, dynamic>>> getContainersByEquipment(String equipmentId) async {
|
||||
@@ -335,5 +346,138 @@ class DataService {
|
||||
throw Exception('Erreur lors de la récupération des containers pour l\'équipement: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// USER - Current User
|
||||
// ============================================================================
|
||||
|
||||
/// Récupère l'utilisateur actuellement authentifié avec son rôle
|
||||
Future<Map<String, dynamic>> getCurrentUser() async {
|
||||
try {
|
||||
print('[DataService] Calling getCurrentUser API...');
|
||||
final result = await _apiService.call('getCurrentUser', {});
|
||||
print('[DataService] Current user loaded successfully');
|
||||
return result['user'] as Map<String, dynamic>;
|
||||
} catch (e) {
|
||||
print('[DataService] Error getting current user: $e');
|
||||
throw Exception('Erreur lors de la récupération de l\'utilisateur actuel: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// ALERTS
|
||||
// ============================================================================
|
||||
|
||||
/// Récupère toutes les alertes
|
||||
Future<List<Map<String, dynamic>>> getAlerts() async {
|
||||
try {
|
||||
final result = await _apiService.call('getAlerts', {});
|
||||
final alerts = result['alerts'] as List<dynamic>?;
|
||||
if (alerts == null) return [];
|
||||
return alerts.map((e) => e as Map<String, dynamic>).toList();
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors de la récupération des alertes: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Marque une alerte comme lue
|
||||
Future<void> markAlertAsRead(String alertId) async {
|
||||
try {
|
||||
await _apiService.call('markAlertAsRead', {'alertId': alertId});
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors du marquage de l\'alerte comme lue: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Supprime une alerte
|
||||
Future<void> deleteAlert(String alertId) async {
|
||||
try {
|
||||
await _apiService.call('deleteAlert', {'alertId': alertId});
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors de la suppression de l\'alerte: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// EQUIPMENT AVAILABILITY
|
||||
// ============================================================================
|
||||
|
||||
/// Vérifie la disponibilité d'un équipement
|
||||
Future<Map<String, dynamic>> checkEquipmentAvailability({
|
||||
required String equipmentId,
|
||||
required DateTime startDate,
|
||||
required DateTime endDate,
|
||||
String? excludeEventId,
|
||||
}) async {
|
||||
try {
|
||||
final result = await _apiService.call('checkEquipmentAvailability', {
|
||||
'equipmentId': equipmentId,
|
||||
'startDate': startDate.toIso8601String(),
|
||||
'endDate': endDate.toIso8601String(),
|
||||
if (excludeEventId != null) 'excludeEventId': excludeEventId,
|
||||
});
|
||||
return result;
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors de la vérification de disponibilité: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// MAINTENANCES
|
||||
// ============================================================================
|
||||
|
||||
/// Supprime une maintenance
|
||||
Future<void> deleteMaintenance(String maintenanceId) async {
|
||||
try {
|
||||
await _apiService.call('deleteMaintenance', {'maintenanceId': maintenanceId});
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors de la suppression de la maintenance: $e');
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// USERS
|
||||
// ============================================================================
|
||||
|
||||
/// Récupère tous les utilisateurs (selon permissions)
|
||||
Future<List<Map<String, dynamic>>> getUsers() async {
|
||||
try {
|
||||
final result = await _apiService.call('getUsers', {});
|
||||
final users = result['users'] as List<dynamic>?;
|
||||
if (users == null) return [];
|
||||
return users.map((e) => e as Map<String, dynamic>).toList();
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors de la récupération des utilisateurs: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Récupère un utilisateur spécifique
|
||||
Future<Map<String, dynamic>> getUser(String userId) async {
|
||||
try {
|
||||
final result = await _apiService.call('getUser', {'userId': userId});
|
||||
return result['user'] as Map<String, dynamic>;
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors de la récupération de l\'utilisateur: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Supprime un utilisateur (Auth + Firestore)
|
||||
Future<void> deleteUser(String userId) async {
|
||||
try {
|
||||
await _apiService.call('deleteUser', {'userId': userId});
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors de la suppression de l\'utilisateur: $e');
|
||||
}
|
||||
}
|
||||
|
||||
/// Met à jour un utilisateur
|
||||
Future<void> updateUser(String userId, Map<String, dynamic> data) async {
|
||||
try {
|
||||
final requestData = {'userId': userId, ...data};
|
||||
await _apiService.call('updateUser', requestData);
|
||||
} catch (e) {
|
||||
throw Exception('Erreur lors de la mise à jour de l\'utilisateur: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user