refactoring

This commit is contained in:
DahoudG
2024-11-02 15:27:26 +00:00
parent 8e625c1080
commit 9cf96b7acf
44 changed files with 2281 additions and 354 deletions

View File

@@ -5,136 +5,181 @@ import 'package:http/http.dart' as http;
import '../../core/errors/exceptions.dart';
/// Classe pour gérer les opérations API pour les utilisateurs.
/// Chaque action est loguée pour faciliter la traçabilité et le débogage.
/// Toutes les actions sont loguées pour faciliter la traçabilité et le débogage.
class UserRemoteDataSource {
// Client HTTP injecté pour réaliser les appels réseau
final http.Client client;
/// Constructeur avec injection du client HTTP
UserRemoteDataSource(this.client);
/// Authentifie un utilisateur avec l'email et le mot de passe en clair.
/// Authentifie un utilisateur avec l'email et le mot de passe.
/// Si l'authentification réussit, retourne un objet `UserModel`.
/// Les erreurs sont gérées et toutes les actions sont loguées.
Future<UserModel> authenticateUser(String email, String password) async {
print("Tentative d'authentification pour l'email : $email");
print("[LOG] Tentative d'authentification pour l'email : $email");
try {
// Requête POST avec l'email et le mot de passe en clair
// Préparation des données d'authentification à envoyer
final Map<String, dynamic> body = {
'email': email,
'motDePasse': password,
};
print("[DEBUG] Données envoyées pour authentification : $body");
// Envoi de la requête HTTP POST pour authentifier l'utilisateur
final response = await client.post(
Uri.parse('${Urls.baseUrl}/users/authenticate'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({
'email': email,
'motDePasse': password, // Le mot de passe est envoyé en clair pour le moment
}),
body: jsonEncode(body),
);
print("Réponse du serveur pour l'authentification : ${response.statusCode} - ${response.body}");
// Log de la réponse reçue du serveur
print("[LOG] Réponse du serveur : ${response.statusCode} - ${response.body}");
if (response.statusCode == 200) {
// Si l'authentification réussit, retourne l'utilisateur
return UserModel.fromJson(jsonDecode(response.body));
final userData = jsonDecode(response.body);
if (userData['userId'] != null && userData['userId'].isNotEmpty) {
print("[LOG] Utilisateur authentifié avec succès. ID: ${userData['userId']}");
return UserModel.fromJson(userData);
} else {
print("[ERROR] L'ID utilisateur est manquant dans la réponse.");
throw Exception("ID utilisateur manquant.");
}
} else if (response.statusCode == 401) {
// Gestion des erreurs d'authentification
throw UnauthorizedException();
print("[ERROR] Authentification échouée : Mot de passe incorrect.");
throw UnauthorizedException("Mot de passe incorrect.");
} else {
throw ServerException();
print("[ERROR] Erreur du serveur. Code : ${response.statusCode}");
throw ServerExceptionWithMessage("Erreur inattendue : ${response.body}");
}
} catch (e) {
print("Erreur d'authentification : $e");
print("[ERROR] Erreur lors de l'authentification : $e");
throw Exception("Erreur lors de l'authentification : $e");
}
}
/// Récupère un utilisateur par son identifiant et logue les étapes.
/// Récupère un utilisateur par son identifiant.
/// Les erreurs et les succès sont logués pour un suivi complet.
Future<UserModel> getUser(String id) async {
print("Tentative de récupération de l'utilisateur avec l'ID : $id");
print("[LOG] Tentative de récupération de l'utilisateur avec l'ID : $id");
try {
// Envoi de la requête GET pour obtenir l'utilisateur par son ID
final response = await client.get(Uri.parse('${Urls.baseUrl}/users/$id'));
print("Réponse du serveur pour getUser : ${response.statusCode} - ${response.body}");
print("[LOG] Réponse du serveur pour getUser : ${response.statusCode} - ${response.body}");
if (response.statusCode == 200) {
// Utilisateur trouvé, retour de l'objet UserModel
return UserModel.fromJson(json.decode(response.body));
} else if (response.statusCode == 404) {
print("Utilisateur non trouvé.");
}
// Gestion du cas où l'utilisateur n'est pas trouvé
else if (response.statusCode == 404) {
print("[ERROR] Utilisateur non trouvé.");
throw UserNotFoundException();
} else {
}
// Gestion des autres erreurs serveur
else {
print("[ERROR] Erreur du serveur lors de la récupération de l'utilisateur.");
throw ServerException();
}
} catch (e) {
print("Erreur lors de la récupération de l'utilisateur : $e");
print("[ERROR] Erreur lors de la récupération de l'utilisateur : $e");
throw Exception("Erreur lors de la récupération de l'utilisateur : $e");
}
}
/// Crée un nouvel utilisateur et logue les détails de la requête.
/// Crée un nouvel utilisateur dans le backend.
/// Toutes les actions, succès ou erreurs sont logués pour un suivi précis.
Future<UserModel> createUser(UserModel user) async {
print("Création d'un nouvel utilisateur : ${user.toJson()}");
print("[LOG] Création d'un nouvel utilisateur : ${user.toJson()}");
try {
// Envoi de la requête POST pour créer un nouvel utilisateur
final response = await client.post(
Uri.parse('${Urls.baseUrl}/users'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode(user.toJson()),
body: jsonEncode(user.toJson()), // Conversion du modèle utilisateur en JSON
);
print("Réponse du serveur pour createUser : ${response.statusCode} - ${response.body}");
print("[LOG] Réponse du serveur pour createUser : ${response.statusCode} - ${response.body}");
if (response.statusCode == 201) {
// Utilisateur créé avec succès
return UserModel.fromJson(json.decode(response.body));
} else if (response.statusCode == 409) {
// Gestion des conflits (utilisateur déjà existant)
}
// Gestion des conflits (ex: utilisateur déjà existant)
else if (response.statusCode == 409) {
print("[ERROR] Conflit lors de la création de l'utilisateur : Utilisateur déjà existant.");
throw ConflictException();
} else {
}
// Gestion des autres erreurs serveur
else {
print("[ERROR] Erreur du serveur lors de la création de l'utilisateur.");
throw ServerException();
}
} catch (e) {
print("Erreur lors de la création de l'utilisateur : $e");
print("[ERROR] Erreur lors de la création de l'utilisateur : $e");
throw Exception("Erreur lors de la création de l'utilisateur : $e");
}
}
/// Met à jour un utilisateur existant et logue les étapes.
/// Met à jour un utilisateur existant.
/// Chaque étape est loguée pour faciliter le débogage.
Future<UserModel> updateUser(UserModel user) async {
print("Mise à jour de l'utilisateur : ${user.toJson()}");
print("[LOG] Mise à jour de l'utilisateur : ${user.toJson()}");
try {
// Envoi de la requête PUT pour mettre à jour un utilisateur
final response = await client.put(
Uri.parse('${Urls.baseUrl}/users/${user.userId}'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode(user.toJson()),
body: jsonEncode(user.toJson()), // Conversion du modèle utilisateur en JSON
);
print("Réponse du serveur pour updateUser : ${response.statusCode} - ${response.body}");
print("[LOG] Réponse du serveur pour updateUser : ${response.statusCode} - ${response.body}");
if (response.statusCode == 200) {
// Mise à jour réussie
return UserModel.fromJson(json.decode(response.body));
} else if (response.statusCode == 404) {
// Gestion des cas où l'utilisateur n'est pas trouvé
}
// Gestion du cas où l'utilisateur n'est pas trouvé
else if (response.statusCode == 404) {
print("[ERROR] Utilisateur non trouvé.");
throw UserNotFoundException();
} else {
}
// Gestion des autres erreurs serveur
else {
print("[ERROR] Erreur du serveur lors de la mise à jour de l'utilisateur.");
throw ServerException();
}
} catch (e) {
print("Erreur lors de la mise à jour de l'utilisateur : $e");
print("[ERROR] Erreur lors de la mise à jour de l'utilisateur : $e");
throw Exception("Erreur lors de la mise à jour de l'utilisateur : $e");
}
}
/// Supprime un utilisateur et logue chaque étape.
/// Supprime un utilisateur par son identifiant.
/// Les erreurs et succès sont logués pour garantir un suivi complet.
Future<void> deleteUser(String id) async {
print("Tentative de suppression de l'utilisateur avec l'ID : $id");
print("[LOG] Tentative de suppression de l'utilisateur avec l'ID : $id");
try {
// Envoi de la requête DELETE pour supprimer un utilisateur
final response = await client.delete(Uri.parse('${Urls.baseUrl}/users/$id'));
print("Réponse du serveur pour deleteUser : ${response.statusCode} - ${response.body}");
print("[LOG] Réponse du serveur pour deleteUser : ${response.statusCode} - ${response.body}");
if (response.statusCode != 204) {
print("Erreur lors de la suppression de l'utilisateur.");
// Vérification du succès de la suppression
if (response.statusCode == 204) {
print("[LOG] Utilisateur supprimé avec succès.");
}
// Gestion des autres erreurs serveur
else {
print("[ERROR] Erreur du serveur lors de la suppression de l'utilisateur.");
throw ServerException();
} else {
print("Utilisateur supprimé avec succès.");
}
} catch (e) {
print("Erreur lors de la suppression de l'utilisateur : $e");
print("[ERROR] Erreur lors de la suppression de l'utilisateur : $e");
throw Exception("Erreur lors de la suppression de l'utilisateur : $e");
}
}

View File

@@ -0,0 +1,23 @@
class SocialPost {
final String userName;
final String userImage;
final String postText;
final String postImage;
final int likes;
final int comments;
final int shares;
final List<String> badges; // Gamification badges
final List<String> tags; // Ajout de tags pour personnalisation des posts
SocialPost({
required this.userName,
required this.userImage,
required this.postText,
required this.postImage,
required this.likes,
required this.comments,
required this.shares,
required this.badges,
this.tags = const [],
});
}

View File

@@ -20,7 +20,7 @@ class UserModel extends User {
/// Factory pour créer un `UserModel` à partir d'un JSON reçu depuis l'API.
factory UserModel.fromJson(Map<String, dynamic> json) {
return UserModel(
userId: json['id'] ?? '',
userId: json['userId'] ?? '',
nom: json['nom'] ?? 'Inconnu',
prenoms: json['prenoms'] ?? 'Inconnu',
email: json['email'] ?? 'inconnu@example.com',

View File

@@ -0,0 +1,159 @@
import 'package:flutter/material.dart';
import 'package:logger/logger.dart';
import '../../domain/entities/friend.dart';
import '../../data/repositories/friends_repository_impl.dart';
/// [FriendsProvider] est un `ChangeNotifier` qui gère la logique de gestion des amis.
/// Il utilise [FriendsRepositoryImpl] pour interagir avec l'API et assure la gestion des états,
/// comme le chargement, la pagination et les erreurs éventuelles.
class FriendsProvider with ChangeNotifier {
final FriendsRepositoryImpl friendsRepository;
final Logger _logger = Logger(); // Logger pour suivre toutes les actions.
// Liste privée des amis récupérée depuis l'API
List<Friend> _friendsList = [];
bool _isLoading = false; // Indique si une opération de chargement est en cours
bool _hasMore = true; // Indique s'il reste des amis à charger
int _currentPage = 0;
final int _friendsPerPage = 10; // Nombre d'amis par page pour la pagination
/// Constructeur de [FriendsProvider] qui requiert une instance de [FriendsRepositoryImpl].
FriendsProvider({required this.friendsRepository});
// Getters pour accéder aux états depuis l'interface utilisateur
bool get isLoading => _isLoading;
bool get hasMore => _hasMore;
List<Friend> get friendsList => _friendsList;
/// Récupère la liste paginée des amis pour un utilisateur donné.
///
/// [userId] : L'identifiant unique de l'utilisateur.
/// [loadMore] : Indique s'il s'agit d'une demande de chargement supplémentaire pour la pagination.
///
/// En cas d'erreur, logue l'exception et gère l'état `isLoading`.
Future<void> fetchFriends(String userId, {bool loadMore = false}) async {
if (_isLoading) {
_logger.w('[LOG] Chargement déjà en cours, annulation de la nouvelle demande.');
return;
}
_isLoading = true;
notifyListeners();
_logger.i('[LOG] Début du chargement des amis.');
if (!loadMore) {
// Réinitialisation de la liste et de la pagination si ce n'est pas un chargement supplémentaire
_friendsList = [];
_currentPage = 0;
_hasMore = true;
_logger.i('[LOG] Réinitialisation de la pagination et de la liste des amis.');
}
try {
_logger.i('[LOG] Chargement de la page $_currentPage des amis pour l\'utilisateur $userId.');
final newFriends = await friendsRepository.fetchFriends(userId, _currentPage, _friendsPerPage);
if (newFriends.isEmpty) {
_hasMore = false;
_logger.i('[LOG] Fin de liste atteinte, plus d\'amis à charger.');
} else {
_friendsList.addAll(newFriends);
_currentPage++;
_logger.i('[LOG] Amis ajoutés à la liste. Page actuelle : $_currentPage');
}
} catch (e) {
_logger.e('[ERROR] Erreur lors de la récupération des amis : $e');
} finally {
_isLoading = false;
_logger.i('[LOG] Fin du chargement des amis.');
notifyListeners();
}
}
/// Supprime un ami dans l'API et met à jour la liste localement.
///
/// [friendId] : Identifiant unique de l'ami à supprimer.
///
/// Loggue chaque étape pour assurer un suivi précis de l'opération.
Future<void> removeFriend(String friendId) async {
try {
_logger.i('[LOG] Tentative de suppression de l\'ami avec l\'ID : $friendId');
await friendsRepository.removeFriend(friendId);
_friendsList.removeWhere((friend) => friend.friendId == friendId);
_logger.i('[LOG] Ami supprimé localement avec succès : $friendId');
} catch (e) {
_logger.e('[ERROR] Erreur lors de la suppression de l\'ami : $e');
} finally {
notifyListeners();
}
}
/// Récupère les détails d'un ami via l'API.
///
/// [userId] : L'identifiant de l'utilisateur connecté.
/// [friendId] : Identifiant unique de l'ami.
///
/// Retourne un `Future<Friend?>` contenant les détails ou `null` en cas d'erreur.
Future<Friend?> fetchFriendDetails(String userId, String friendId) async {
try {
_logger.i('[LOG] Tentative de récupération des détails de l\'ami avec l\'ID : $friendId');
final friendDetails = await friendsRepository.getFriendDetails(friendId, userId);
if (friendDetails != null) {
_logger.i('[LOG] Détails de l\'ami récupérés avec succès : ${friendDetails.friendId}');
} else {
_logger.w('[LOG] Détails de l\'ami introuvables pour l\'ID : $friendId');
}
return friendDetails;
} catch (e) {
_logger.e('[ERROR] Exception lors de la récupération des détails de l\'ami : $e');
return null;
}
}
/// Convertit un statut sous forme de chaîne en [FriendStatus].
///
/// [status] : Le statut sous forme de chaîne.
///
/// Retourne un [FriendStatus] correspondant, ou `FriendStatus.unknown` si non reconnu.
FriendStatus _convertToFriendStatus(String status) {
switch (status.toLowerCase()) {
case 'pending':
return FriendStatus.pending;
case 'accepted':
return FriendStatus.accepted;
case 'blocked':
return FriendStatus.blocked;
default:
return FriendStatus.unknown;
}
}
/// Met à jour le statut d'un ami (par exemple : accepter, bloquer).
///
/// [friendId] : Identifiant unique de l'ami.
/// [status] : Nouveau statut pour l'ami sous forme de chaîne de caractères.
///
/// Loggue l'action, convertit le statut en `FriendStatus`, et met à jour la liste localement.
Future<void> updateFriendStatus(String friendId, String status) async {
try {
_logger.i('[LOG] Tentative de mise à jour du statut de l\'ami avec l\'ID : $friendId');
// Conversion du `String` en `FriendStatus` pour l'update locale
final friendStatus = _convertToFriendStatus(status);
await friendsRepository.updateFriendStatus(friendId, status);
// Mise à jour locale de la liste pour afficher le changement de statut
final friendIndex = _friendsList.indexWhere((friend) => friend.friendId == friendId);
if (friendIndex != -1) {
_friendsList[friendIndex] = _friendsList[friendIndex].copyWith(status: friendStatus);
_logger.i('[LOG] Statut de l\'ami mis à jour localement pour l\'ID : $friendId');
}
} catch (e) {
_logger.e('[ERROR] Erreur lors de la mise à jour du statut de l\'ami : $e');
} finally {
notifyListeners();
}
}
}

View File

@@ -1,18 +1,53 @@
import 'package:flutter/material.dart';
/// [UserProvider] est un `ChangeNotifier` qui gère les informations de l'utilisateur.
/// Toutes les modifications et actions sont loguées pour assurer une traçabilité complète dans le terminal.
class UserProvider with ChangeNotifier {
String _userId = '';
String _userName = '';
String _userLastName = '';
/// Getter pour l'ID de l'utilisateur
String get userId => _userId;
/// Getter pour le nom de l'utilisateur
String get userName => _userName;
/// Getter pour le prénom de l'utilisateur
String get userLastName => _userLastName;
/// Méthode pour définir les informations de l'utilisateur.
/// Logue les informations fournies et notifie les listeners des changements.
///
/// [id] : L'ID de l'utilisateur.
/// [name] : Le nom de l'utilisateur.
/// [lastName] : Le prénom de l'utilisateur.
void setUser(String id, String name, String lastName) {
debugPrint("[LOG] Tentative de définition des informations de l'utilisateur : ID = $id, Nom = $name, Prénom = $lastName");
_userId = id;
_userName = name;
_userLastName = lastName;
debugPrint("[LOG] Informations utilisateur définies : ID = $_userId, Nom = $_userName, Prénom = $_userLastName");
// Notifie les widgets écoutant ce provider qu'une modification a eu lieu
notifyListeners();
}
/// Méthode pour réinitialiser les informations de l'utilisateur.
/// Les valeurs sont loguées avant et après la réinitialisation.
void resetUser() {
debugPrint("[LOG] Réinitialisation des informations de l'utilisateur.");
debugPrint("[LOG] Valeurs avant réinitialisation : ID = $_userId, Nom = $_userName, Prénom = $_userLastName");
_userId = '';
_userName = '';
_userLastName = '';
debugPrint("[LOG] Informations utilisateur réinitialisées : ID = $_userId, Nom = $_userName, Prénom = $_userLastName");
// Notifie les widgets écoutant ce provider que l'utilisateur a été réinitialisé
notifyListeners();
}
}

View File

@@ -0,0 +1,48 @@
import 'package:afterwork/domain/entities/friend.dart';
/// Interface [FriendsRepository] définissant les méthodes pour gérer les amis.
/// Cette interface permet de séparer la logique métier des appels API et de la gestion des données.
/// Elle est implémentée par [FriendsRepositoryImpl], qui contient les détails d'implémentation.
abstract class FriendsRepository {
/// Récupère la liste paginée des amis pour un utilisateur donné via l'API.
///
/// [userId] : Identifiant unique de l'utilisateur pour lequel récupérer la liste d'amis.
/// [currentPage] : Indique la page actuelle pour la pagination.
/// [friendsPerPage] : Nombre d'amis à récupérer par page.
///
/// Retourne une liste d'objets [Friend] correspondant aux amis de l'utilisateur.
/// En cas d'échec, une liste vide peut être retournée par l'implémentation.
Future<List<Friend>> fetchFriends(String userId, int currentPage, int friendsPerPage);
/// Envoie une demande pour ajouter un nouvel ami via l'API.
///
/// [friend] : Objet [Friend] représentant l'ami à ajouter.
///
/// Retourne un `Future<void>`. En cas d'erreur, l'implémentation peut lancer une exception.
Future<void> addFriend(Friend friend);
/// Supprime un ami existant via l'API.
///
/// [friendId] : Identifiant unique de l'ami à supprimer.
///
/// Retourne un `Future<void>`. En cas d'erreur, l'implémentation peut lancer une exception.
Future<void> removeFriend(String friendId);
/// Récupère les détails d'un ami en utilisant son identifiant `friendId`.
///
/// [userId] : Identifiant unique de l'utilisateur connecté (facultatif selon le contexte).
/// [friendId] : Identifiant unique de l'ami pour lequel récupérer les détails.
///
/// Retourne un `Future<Friend?>` contenant les informations de l'ami si trouvées,
/// ou `null` si aucun ami correspondant n'est trouvé ou en cas d'échec.
Future<Friend?> getFriendDetails(String friendId, String userId);
/// Met à jour le statut d'un ami dans le système (par exemple, accepter, bloquer).
///
/// [friendId] : Identifiant unique de l'ami.
/// [status] : Nouveau statut de l'ami sous forme de chaîne de caractères.
///
/// Retourne un `Future<void>`. En cas d'erreur, l'implémentation peut lancer une exception.
Future<void> updateFriendStatus(String friendId, String status);
}

View File

@@ -0,0 +1,175 @@
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:http/http.dart' as http;
import 'package:logger/logger.dart';
import '../../core/constants/urls.dart';
import '../../domain/entities/friend.dart';
import 'friends_repository.dart';
/// Implémentation de [FriendsRepository] pour gérer les appels API relatifs aux amis.
/// Chaque action est loguée pour une traçabilité complète et une gestion des erreurs avancée.
class FriendsRepositoryImpl implements FriendsRepository {
final http.Client client;
final Logger _logger = Logger(); // Logger pour suivre toutes les actions.
FriendsRepositoryImpl({required this.client});
/// Récupère la liste paginée des amis pour un utilisateur donné via l'API.
///
/// [userId] : Identifiant unique de l'utilisateur.
/// [page] : Page actuelle pour la pagination.
/// [size] : Nombre d'amis par page.
///
/// Retourne une liste d'objets [Friend] ou une liste vide en cas d'erreur.
@override
Future<List<Friend>> fetchFriends(String userId, int page, int size) async {
try {
_logger.i("[LOG] Chargement des amis pour l'utilisateur : $userId, page : $page, taille : $size");
final uri = Uri.parse('${Urls.baseUrl}/friends/list/$userId?page=$page&size=$size');
_logger.d('[LOG] URL appelée : $uri');
final response = await client.get(uri);
if (response.statusCode == 200) {
_logger.i("[LOG] Liste des amis récupérée avec succès.");
final List<dynamic> friendsJson = json.decode(response.body);
_logger.i("[LOG] Nombre d'amis récupérés : ${friendsJson.length}");
return friendsJson.map((json) => Friend.fromJson(json as Map<String, dynamic>)).toList();
} else {
_logger.e("[ERROR] Échec de la récupération des amis. Code HTTP : ${response.statusCode}");
return [];
}
} catch (e) {
_logger.e("[ERROR] Exception lors de la récupération des amis : $e");
return [];
}
}
/// Envoie une demande pour ajouter un nouvel ami via l'API.
///
/// [friend] : Objet [Friend] représentant l'ami à ajouter.
///
/// Loggue chaque étape et lève une exception en cas d'erreur.
@override
Future<void> addFriend(Friend friend) async {
try {
_logger.i("[LOG] Tentative d'ajout de l'ami : ${friend.firstName} ${friend.lastName}");
final uri = Uri.parse('${Urls.baseUrl}/friends/send');
final response = await client.post(
uri,
headers: {'Content-Type': 'application/json'},
body: json.encode(friend.toJson()),
);
if (response.statusCode == 200) {
_logger.i("[LOG] Ami ajouté avec succès : ${friend.friendId}");
} else {
_logger.e("[ERROR] Échec lors de l'ajout de l'ami. Code HTTP : ${response.statusCode}");
throw Exception("Erreur lors de l'ajout de l'ami");
}
} catch (e) {
_logger.e("[ERROR] Exception lors de l'ajout de l'ami : $e");
rethrow;
}
}
/// Supprime un ami existant via l'API.
///
/// [friendId] : Identifiant unique de l'ami à supprimer.
///
/// Loggue l'action et lève une exception en cas d'erreur.
@override
Future<void> removeFriend(String friendId) async {
try {
_logger.i("[LOG] Tentative de suppression de l'ami avec l'ID : $friendId");
final uri = Uri.parse('${Urls.baseUrl}/friends/$friendId');
final response = await client.delete(uri);
if (response.statusCode == 200) {
_logger.i("[LOG] Ami supprimé avec succès : $friendId");
} else {
_logger.e("[ERROR] Échec lors de la suppression de l'ami. Code HTTP : ${response.statusCode}");
throw Exception("Erreur lors de la suppression de l'ami");
}
} catch (e) {
_logger.e("[ERROR] Exception lors de la suppression de l'ami : $e");
rethrow;
}
}
/// Récupère les détails d'un ami en utilisant son identifiant `friendId`.
///
/// [friendId] : Identifiant unique de l'ami.
/// [userId] : Identifiant unique de l'utilisateur connecté.
///
/// Retourne un `Future<Friend?>` avec les informations de l'ami ou `null` en cas d'échec.
@override
Future<Friend?> getFriendDetails(String friendId, String userId) async {
try {
_logger.i("[LOG] Récupération des détails de l'ami avec ID : $friendId pour l'utilisateur : $userId");
final uri = Uri.parse('${Urls.baseUrl}/friends/details');
_logger.d("[LOG] URL pour les détails de l'ami : $uri");
final headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
};
final body = jsonEncode({
'friendId': friendId,
'userId': userId,
});
final response = await client.post(uri, headers: headers, body: body);
_logger.d("[LOG] Réponse de l'API : ${response.body}");
if (response.statusCode == 200) {
final friendJson = json.decode(response.body);
_logger.i("[LOG] Détails de l'ami récupérés : $friendJson");
return Friend.fromJson(friendJson);
} else {
_logger.e("[ERROR] Échec de la récupération des détails. Code HTTP : ${response.statusCode}");
return null;
}
} catch (e) {
_logger.e("[ERROR] Exception lors de la récupération des détails de l'ami : $e");
return null;
}
}
/// Met à jour le statut d'un ami (par exemple, "accepté", "bloqué").
///
/// [friendId] : Identifiant unique de l'ami.
/// [status] : Nouveau statut sous forme de chaîne de caractères.
///
/// Loggue chaque étape et lève une exception en cas d'échec.
@override
Future<void> updateFriendStatus(String friendId, String status) async {
try {
_logger.i("[LOG] Mise à jour du statut de l'ami avec l'ID : $friendId, nouveau statut : $status");
final uri = Uri.parse('${Urls.baseUrl}/friends/$friendId/status');
final response = await client.patch(
uri,
headers: {'Content-Type': 'application/json'},
body: jsonEncode({'status': status}),
);
if (response.statusCode == 200) {
_logger.i("[LOG] Statut de l'ami mis à jour avec succès : $friendId");
} else {
_logger.e("[ERROR] Erreur lors de la mise à jour du statut. Code HTTP : ${response.statusCode}");
throw Exception("Erreur lors de la mise à jour du statut");
}
} catch (e) {
_logger.e("[ERROR] Exception lors de la mise à jour du statut de l'ami : $e");
rethrow;
}
}
}

View File

@@ -3,80 +3,96 @@ import 'package:shared_preferences/shared_preferences.dart';
/// Classe pour gérer les préférences utilisateur à l'aide de SharedPreferences.
/// Permet de stocker et récupérer des informations de manière non sécurisée,
/// contrairement au stockage sécurisé qui est utilisé pour des données sensibles.
/// Chaque action est loguée pour assurer la traçabilité complète dans le terminal.
class PreferencesHelper {
// Initialisation de SharedPreferences en tant que Future
final Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
/// Sauvegarde une chaîne de caractères (String) dans les préférences.
/// Les actions sont loguées et les erreurs capturées pour garantir une sauvegarde correcte.
Future<void> setString(String key, String value) async {
print("Sauvegarde dans les préférences : clé = $key, valeur = $value");
print("[LOG] Sauvegarde dans les préférences : clé = $key, valeur = $value");
final prefs = await _prefs;
await prefs.setString(key, value);
print("Sauvegarde réussie pour la clé : $key");
final success = await prefs.setString(key, value);
if (success) {
print("[LOG] Sauvegarde réussie pour la clé : $key");
} else {
print("[ERROR] Échec de la sauvegarde pour la clé : $key");
}
}
/// Récupère une chaîne de caractères depuis les préférences.
/// Retourne la valeur ou null si aucune donnée n'est trouvée.
Future<String?> getString(String key) async {
print("Récupération depuis les préférences pour la clé : $key");
print("[LOG] Récupération depuis les préférences pour la clé : $key");
final prefs = await _prefs;
final value = prefs.getString(key);
print("Valeur récupérée pour la clé $key : $value");
print("[LOG] Valeur récupérée pour la clé $key : $value");
return value;
}
/// Supprime une entrée dans les préférences.
/// Logue chaque étape de la suppression.
Future<void> remove(String key) async {
print("Suppression dans les préférences pour la clé : $key");
print("[LOG] Suppression dans les préférences pour la clé : $key");
final prefs = await _prefs;
await prefs.remove(key);
print("Suppression réussie pour la clé : $key");
final success = await prefs.remove(key);
if (success) {
print("[LOG] Suppression réussie pour la clé : $key");
} else {
print("[ERROR] Échec de la suppression pour la clé : $key");
}
}
/// Sauvegarde l'identifiant utilisateur dans les préférences.
/// Logue l'action et assure la robustesse de l'opération.
Future<void> saveUserId(String userId) async {
print("Sauvegarde de l'userId dans les préférences : $userId");
print("[LOG] Sauvegarde de l'userId dans les préférences : $userId");
await setString('user_id', userId);
print("Sauvegarde réussie de l'userId.");
}
/// Récupère l'identifiant utilisateur depuis les préférences.
/// Retourne l'ID ou null en cas d'échec.
Future<String?> getUserId() async {
print("Récupération de l'userId depuis les préférences.");
print("[LOG] Récupération de l'userId depuis les préférences.");
return await getString('user_id');
}
/// Sauvegarde le nom d'utilisateur dans les préférences.
/// Logue l'opération pour assurer un suivi complet.
Future<void> saveUserName(String userName) async {
print("Sauvegarde du userName dans les préférences : $userName");
print("[LOG] Sauvegarde du userName dans les préférences : $userName");
await setString('user_name', userName);
print("Sauvegarde réussie du userName.");
}
/// Récupère le nom d'utilisateur depuis les préférences.
/// Retourne le nom ou null en cas d'échec.
Future<String?> getUserName() async {
print("Récupération du userName depuis les préférences.");
print("[LOG] Récupération du userName depuis les préférences.");
return await getString('user_name');
}
/// Sauvegarde le prénom de l'utilisateur dans les préférences.
/// Logue l'opération pour assurer un suivi complet.
Future<void> saveUserLastName(String userLastName) async {
print("Sauvegarde du userLastName dans les préférences : $userLastName");
print("[LOG] Sauvegarde du userLastName dans les préférences : $userLastName");
await setString('user_last_name', userLastName);
print("Sauvegarde réussie du userLastName.");
}
/// Récupère le prénom de l'utilisateur depuis les préférences.
/// Retourne le prénom ou null en cas d'échec.
Future<String?> getUserLastName() async {
print("Récupération du userLastName depuis les préférences.");
print("[LOG] Récupération du userLastName depuis les préférences.");
return await getString('user_last_name');
}
/// Supprime toutes les informations utilisateur dans les préférences.
/// Logue chaque étape de la suppression.
Future<void> clearUserInfo() async {
print("Suppression des informations utilisateur (userId, userName, userLastName) des préférences.");
print("[LOG] Suppression des informations utilisateur (userId, userName, userLastName) des préférences.");
await remove('user_id');
await remove('user_name');
await remove('user_last_name');
print("Suppression réussie des informations utilisateur.");
print("[LOG] Suppression réussie des informations utilisateur.");
}
}

View File

@@ -1,78 +1,137 @@
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:logger/logger.dart';
/// Classe pour gérer le stockage sécurisé dans l'application.
/// Utilise FlutterSecureStorage pour stocker, lire et supprimer des données sensibles.
/// Classe SecureStorage pour gérer les opérations de stockage sécurisé.
/// Toutes les actions sont loguées pour permettre une traçabilité complète dans le terminal.
class SecureStorage {
// Instance de FlutterSecureStorage pour gérer le stockage sécurisé
// Instance de FlutterSecureStorage pour le stockage sécurisé.
final FlutterSecureStorage _storage = const FlutterSecureStorage();
// Logger pour suivre et enregistrer les actions dans le terminal.
final Logger _logger = Logger();
/// Écrit une valeur dans le stockage sécurisé avec la clé spécifiée.
/// Les actions sont loguées et les erreurs sont capturées pour assurer la robustesse.
Future<void> write(String key, String value) async {
print("Écriture dans le stockage sécurisé : clé = $key, valeur = $value");
await _storage.write(key: key, value: value);
print("Écriture réussie pour la clé : $key");
try {
_logger.i("[LOG] Tentative d'écriture dans le stockage sécurisé : clé = $key, valeur = $value");
await _storage.write(key: key, value: value);
_logger.i("[LOG] Écriture réussie pour la clé : $key");
} catch (e) {
_logger.e("[ERROR] Échec d'écriture pour la clé $key : $e");
rethrow;
}
}
/// Lit une valeur depuis le stockage sécurisé en fonction de la clé spécifiée.
/// Retourne la valeur ou null en cas d'erreur. Chaque action est loguée.
Future<String?> read(String key) async {
print("Lecture dans le stockage sécurisé pour la clé : $key");
final value = await _storage.read(key: key);
print("Valeur lue pour la clé $key : $value");
return value;
try {
_logger.i("[LOG] Lecture de la clé : $key");
final value = await _storage.read(key: key);
_logger.i("[LOG] Valeur lue pour la clé $key : $value");
return value;
} catch (e) {
_logger.e("[ERROR] Échec de lecture pour la clé $key : $e");
return null;
}
}
/// Supprime une entrée dans le stockage sécurisé pour la clé spécifiée.
/// Logue chaque étape de l'opération de suppression.
Future<void> delete(String key) async {
print("Suppression dans le stockage sécurisé pour la clé : $key");
await _storage.delete(key: key);
print("Suppression réussie pour la clé : $key");
try {
_logger.i("[LOG] Suppression de la clé : $key");
await _storage.delete(key: key);
_logger.i("[LOG] Suppression réussie pour la clé : $key");
} catch (e) {
_logger.e("[ERROR] Échec de suppression pour la clé $key : $e");
rethrow;
}
}
/// Sauvegarde l'identifiant utilisateur dans le stockage sécurisé.
/// Logue l'action et assure la robustesse de l'opération.
Future<void> saveUserId(String userId) async {
print("Sauvegarde de l'userId dans le stockage sécurisé : $userId");
await write('user_id', userId);
print("Sauvegarde réussie de l'userId.");
if (userId.isNotEmpty) {
_logger.i("[LOG] Tentative de sauvegarde de l'userId : $userId");
await write('user_id', userId);
final savedId = await getUserId(); // Récupération immédiate pour vérifier l'enregistrement
if (savedId != null && savedId == userId) {
_logger.i("[LOG] L'userId a été sauvegardé avec succès et vérifié : $savedId");
} else {
_logger.e("[ERROR] L'userId n'a pas été correctement sauvegardé.");
}
} else {
_logger.e("[ERROR] L'userId est vide, échec de sauvegarde.");
}
}
/// Récupère l'identifiant utilisateur depuis le stockage sécurisé.
/// Retourne l'ID ou null en cas d'échec.
Future<String?> getUserId() async {
print("Récupération de l'userId depuis le stockage sécurisé.");
_logger.i("[LOG] Récupération de l'userId.");
return await read('user_id');
}
/// Sauvegarde le nom d'utilisateur dans le stockage sécurisé.
Future<void> saveUserName(String userName) async {
print("Sauvegarde du userName dans le stockage sécurisé : $userName");
await write('user_name', userName);
print("Sauvegarde réussie du userName.");
/// Retourne un booléen pour indiquer le succès ou l'échec.
Future<bool> saveUserName(String userName) async {
_logger.i("[LOG] Tentative de sauvegarde du userName : $userName");
return await _safeWrite('user_name', userName);
}
/// Récupère le nom d'utilisateur depuis le stockage sécurisé.
/// Retourne le nom ou null en cas d'échec.
Future<String?> getUserName() async {
print("Récupération du userName depuis le stockage sécurisé.");
return await read('user_name');
_logger.i("[LOG] Tentative de récupération du userName depuis le stockage sécurisé.");
return await _safeRead('user_name');
}
/// Sauvegarde le prénom de l'utilisateur dans le stockage sécurisé.
Future<void> saveUserLastName(String userLastName) async {
print("Sauvegarde du userLastName dans le stockage sécurisé : $userLastName");
await write('user_last_name', userLastName);
print("Sauvegarde réussie du userLastName.");
/// Retourne un booléen pour indiquer le succès ou l'échec.
Future<bool> saveUserLastName(String userLastName) async {
_logger.i("[LOG] Tentative de sauvegarde du userLastName : $userLastName");
return await _safeWrite('user_last_name', userLastName);
}
/// Récupère le prénom de l'utilisateur depuis le stockage sécurisé.
/// Retourne le prénom ou null en cas d'échec.
Future<String?> getUserLastName() async {
print("Récupération du userLastName depuis le stockage sécurisé.");
return await read('user_last_name');
_logger.i("[LOG] Tentative de récupération du userLastName depuis le stockage sécurisé.");
return await _safeRead('user_last_name');
}
/// Supprime toutes les informations utilisateur du stockage sécurisé.
/// Logue chaque étape de la suppression.
Future<void> deleteUserInfo() async {
print("Suppression des informations utilisateur (userId, userName, userLastName).");
_logger.i("[LOG] Tentative de suppression de toutes les informations utilisateur.");
await delete('user_id');
await delete('user_name');
await delete('user_last_name');
print("Suppression réussie des informations utilisateur.");
_logger.i("[LOG] Suppression réussie des informations utilisateur.");
}
/// Méthode privée pour encapsuler l'écriture sécurisée avec gestion d'erreur.
/// Retourne un booléen indiquant le succès ou l'échec de l'opération.
Future<bool> _safeWrite(String key, String value) async {
try {
await write(key, value);
return true; // Indique que l'écriture a réussi.
} catch (e) {
_logger.e("[ERROR] Erreur lors de l'écriture sécurisée : $e");
return false; // Indique un échec.
}
}
/// Méthode privée pour encapsuler la lecture sécurisée avec gestion d'erreur.
/// Retourne la valeur ou null si la lecture échoue.
Future<String?> _safeRead(String key) async {
try {
return await read(key);
} catch (e) {
_logger.e("[ERROR] Erreur lors de la lecture sécurisée : $e");
return null; // Retourne null en cas d'erreur.
}
}
}