first commit
This commit is contained in:
203
unionflow-mobile-apps/lib/core/auth/bloc/auth_bloc.dart
Normal file
203
unionflow-mobile-apps/lib/core/auth/bloc/auth_bloc.dart
Normal file
@@ -0,0 +1,203 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import '../models/auth_state.dart';
|
||||
import '../services/auth_service.dart';
|
||||
import '../services/auth_api_service.dart';
|
||||
import 'auth_event.dart';
|
||||
|
||||
/// BLoC pour gérer l'authentification
|
||||
@singleton
|
||||
class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
final AuthService _authService;
|
||||
late StreamSubscription<AuthState> _authStateSubscription;
|
||||
|
||||
AuthBloc(this._authService) : super(const AuthState.unknown()) {
|
||||
// Écouter les changements d'état du service
|
||||
_authStateSubscription = _authService.authStateStream.listen(
|
||||
(authState) => add(AuthStateChanged(authState)),
|
||||
);
|
||||
|
||||
// Gestionnaires d'événements
|
||||
on<AuthInitializeRequested>(_onInitializeRequested);
|
||||
on<AuthLoginRequested>(_onLoginRequested);
|
||||
on<AuthLogoutRequested>(_onLogoutRequested);
|
||||
on<AuthTokenRefreshRequested>(_onTokenRefreshRequested);
|
||||
on<AuthSessionExpired>(_onSessionExpired);
|
||||
on<AuthStatusCheckRequested>(_onStatusCheckRequested);
|
||||
on<AuthErrorCleared>(_onErrorCleared);
|
||||
on<AuthStateChanged>(_onStateChanged);
|
||||
}
|
||||
|
||||
/// Initialisation de l'authentification
|
||||
Future<void> _onInitializeRequested(
|
||||
AuthInitializeRequested event,
|
||||
Emitter<AuthState> emit,
|
||||
) async {
|
||||
emit(const AuthState.checking());
|
||||
|
||||
try {
|
||||
await _authService.initialize();
|
||||
} catch (e) {
|
||||
emit(AuthState.error('Erreur d\'initialisation: $e'));
|
||||
}
|
||||
}
|
||||
|
||||
/// Gestion de la connexion
|
||||
Future<void> _onLoginRequested(
|
||||
AuthLoginRequested event,
|
||||
Emitter<AuthState> emit,
|
||||
) async {
|
||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||
|
||||
try {
|
||||
await _authService.login(event.loginRequest);
|
||||
// L'état sera mis à jour par le stream du service
|
||||
} on AuthApiException catch (e) {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: e.message,
|
||||
));
|
||||
} catch (e) {
|
||||
emit(state.copyWith(
|
||||
isLoading: false,
|
||||
errorMessage: 'Erreur de connexion: $e',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// Gestion de la déconnexion
|
||||
Future<void> _onLogoutRequested(
|
||||
AuthLogoutRequested event,
|
||||
Emitter<AuthState> emit,
|
||||
) async {
|
||||
emit(state.copyWith(isLoading: true));
|
||||
|
||||
try {
|
||||
await _authService.logout();
|
||||
// L'état sera mis à jour par le stream du service
|
||||
} catch (e) {
|
||||
// Même en cas d'erreur, on considère que la déconnexion locale a réussi
|
||||
emit(const AuthState.unauthenticated());
|
||||
}
|
||||
}
|
||||
|
||||
/// Gestion du rafraîchissement de token
|
||||
Future<void> _onTokenRefreshRequested(
|
||||
AuthTokenRefreshRequested event,
|
||||
Emitter<AuthState> emit,
|
||||
) async {
|
||||
// Le rafraîchissement est géré automatiquement par le service
|
||||
// Cet événement peut être utilisé pour forcer un rafraîchissement manuel
|
||||
try {
|
||||
// Le service gère déjà le rafraîchissement automatique
|
||||
// On peut ajouter ici une logique spécifique si nécessaire
|
||||
} catch (e) {
|
||||
emit(AuthState.error('Erreur lors du rafraîchissement: $e'));
|
||||
}
|
||||
}
|
||||
|
||||
/// Gestion de l'expiration de session
|
||||
Future<void> _onSessionExpired(
|
||||
AuthSessionExpired event,
|
||||
Emitter<AuthState> emit,
|
||||
) async {
|
||||
emit(const AuthState.expired());
|
||||
|
||||
// Optionnel: essayer un rafraîchissement automatique
|
||||
try {
|
||||
await _authService.logout();
|
||||
} catch (e) {
|
||||
// Ignorer les erreurs de déconnexion lors de l'expiration
|
||||
}
|
||||
}
|
||||
|
||||
/// Vérification du statut d'authentification
|
||||
Future<void> _onStatusCheckRequested(
|
||||
AuthStatusCheckRequested event,
|
||||
Emitter<AuthState> emit,
|
||||
) async {
|
||||
// Utiliser l'état actuel du service
|
||||
final currentServiceState = _authService.currentState;
|
||||
if (currentServiceState != state) {
|
||||
emit(currentServiceState);
|
||||
}
|
||||
}
|
||||
|
||||
/// Nettoyage des erreurs
|
||||
void _onErrorCleared(
|
||||
AuthErrorCleared event,
|
||||
Emitter<AuthState> emit,
|
||||
) {
|
||||
if (state.errorMessage != null) {
|
||||
emit(state.copyWith(errorMessage: null));
|
||||
}
|
||||
}
|
||||
|
||||
/// Mise à jour depuis le service d'authentification
|
||||
void _onStateChanged(
|
||||
AuthStateChanged event,
|
||||
Emitter<AuthState> emit,
|
||||
) {
|
||||
final newState = event.authState as AuthState;
|
||||
|
||||
// Émettre le nouvel état seulement s'il a changé
|
||||
if (newState != state) {
|
||||
emit(newState);
|
||||
}
|
||||
}
|
||||
|
||||
/// Vérifie si l'utilisateur est connecté
|
||||
bool get isAuthenticated => state.isAuthenticated;
|
||||
|
||||
/// Récupère l'utilisateur actuel
|
||||
get currentUser => state.user;
|
||||
|
||||
/// Vérifie si l'utilisateur a un rôle spécifique
|
||||
bool hasRole(String role) {
|
||||
return _authService.hasRole(role);
|
||||
}
|
||||
|
||||
/// Vérifie si l'utilisateur a un des rôles spécifiés
|
||||
bool hasAnyRole(List<String> roles) {
|
||||
return _authService.hasAnyRole(roles);
|
||||
}
|
||||
|
||||
/// Vérifie si la session expire bientôt
|
||||
bool get isSessionExpiringSoon => state.isExpiringSoon;
|
||||
|
||||
/// Récupère le message d'erreur formaté
|
||||
String? get errorMessage {
|
||||
final error = state.errorMessage;
|
||||
if (error == null) return null;
|
||||
|
||||
// Formatage des messages d'erreur pour l'utilisateur
|
||||
if (error.contains('network') || error.contains('connexion')) {
|
||||
return 'Problème de connexion. Vérifiez votre réseau.';
|
||||
}
|
||||
|
||||
if (error.contains('401') || error.contains('Identifiants')) {
|
||||
return 'Email ou mot de passe incorrect.';
|
||||
}
|
||||
|
||||
if (error.contains('403')) {
|
||||
return 'Accès non autorisé.';
|
||||
}
|
||||
|
||||
if (error.contains('timeout')) {
|
||||
return 'Délai d\'attente dépassé. Réessayez.';
|
||||
}
|
||||
|
||||
if (error.contains('server') || error.contains('500')) {
|
||||
return 'Erreur serveur temporaire. Réessayez plus tard.';
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_authStateSubscription.cancel();
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
60
unionflow-mobile-apps/lib/core/auth/bloc/auth_event.dart
Normal file
60
unionflow-mobile-apps/lib/core/auth/bloc/auth_event.dart
Normal file
@@ -0,0 +1,60 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import '../models/login_request.dart';
|
||||
|
||||
/// Événements d'authentification
|
||||
abstract class AuthEvent extends Equatable {
|
||||
const AuthEvent();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
/// Initialiser l'authentification
|
||||
class AuthInitializeRequested extends AuthEvent {
|
||||
const AuthInitializeRequested();
|
||||
}
|
||||
|
||||
/// Demande de connexion
|
||||
class AuthLoginRequested extends AuthEvent {
|
||||
final LoginRequest loginRequest;
|
||||
|
||||
const AuthLoginRequested(this.loginRequest);
|
||||
|
||||
@override
|
||||
List<Object> get props => [loginRequest];
|
||||
}
|
||||
|
||||
/// Demande de déconnexion
|
||||
class AuthLogoutRequested extends AuthEvent {
|
||||
const AuthLogoutRequested();
|
||||
}
|
||||
|
||||
/// Demande de rafraîchissement de token
|
||||
class AuthTokenRefreshRequested extends AuthEvent {
|
||||
const AuthTokenRefreshRequested();
|
||||
}
|
||||
|
||||
/// Session expirée
|
||||
class AuthSessionExpired extends AuthEvent {
|
||||
const AuthSessionExpired();
|
||||
}
|
||||
|
||||
/// Vérification de l'état d'authentification
|
||||
class AuthStatusCheckRequested extends AuthEvent {
|
||||
const AuthStatusCheckRequested();
|
||||
}
|
||||
|
||||
/// Réinitialisation de l'erreur
|
||||
class AuthErrorCleared extends AuthEvent {
|
||||
const AuthErrorCleared();
|
||||
}
|
||||
|
||||
/// Changement d'état depuis le service
|
||||
class AuthStateChanged extends AuthEvent {
|
||||
final dynamic authState;
|
||||
|
||||
const AuthStateChanged(this.authState);
|
||||
|
||||
@override
|
||||
List<Object?> get props => [authState];
|
||||
}
|
||||
74
unionflow-mobile-apps/lib/core/auth/bloc/temp_auth_bloc.dart
Normal file
74
unionflow-mobile-apps/lib/core/auth/bloc/temp_auth_bloc.dart
Normal file
@@ -0,0 +1,74 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../models/auth_state.dart';
|
||||
import '../services/temp_auth_service.dart';
|
||||
import 'auth_event.dart';
|
||||
|
||||
/// BLoC temporaire pour test sans injection de dépendances
|
||||
class TempAuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
final TempAuthService _authService;
|
||||
late StreamSubscription<AuthState> _authStateSubscription;
|
||||
|
||||
TempAuthBloc(this._authService) : super(const AuthState.unknown()) {
|
||||
_authStateSubscription = _authService.authStateStream.listen(
|
||||
(authState) => add(AuthStateChanged(authState)),
|
||||
);
|
||||
|
||||
on<AuthInitializeRequested>(_onInitializeRequested);
|
||||
on<AuthLoginRequested>(_onLoginRequested);
|
||||
on<AuthLogoutRequested>(_onLogoutRequested);
|
||||
on<AuthErrorCleared>(_onErrorCleared);
|
||||
on<AuthStateChanged>(_onStateChanged);
|
||||
}
|
||||
|
||||
Future<void> _onInitializeRequested(
|
||||
AuthInitializeRequested event,
|
||||
Emitter<AuthState> emit,
|
||||
) async {
|
||||
await _authService.initialize();
|
||||
}
|
||||
|
||||
Future<void> _onLoginRequested(
|
||||
AuthLoginRequested event,
|
||||
Emitter<AuthState> emit,
|
||||
) async {
|
||||
try {
|
||||
await _authService.login(event.loginRequest);
|
||||
} catch (e) {
|
||||
emit(AuthState.error(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onLogoutRequested(
|
||||
AuthLogoutRequested event,
|
||||
Emitter<AuthState> emit,
|
||||
) async {
|
||||
await _authService.logout();
|
||||
}
|
||||
|
||||
void _onErrorCleared(
|
||||
AuthErrorCleared event,
|
||||
Emitter<AuthState> emit,
|
||||
) {
|
||||
if (state.errorMessage != null) {
|
||||
emit(state.copyWith(errorMessage: null));
|
||||
}
|
||||
}
|
||||
|
||||
void _onStateChanged(
|
||||
AuthStateChanged event,
|
||||
Emitter<AuthState> emit,
|
||||
) {
|
||||
final newState = event.authState as AuthState;
|
||||
if (newState != state) {
|
||||
emit(newState);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_authStateSubscription.cancel();
|
||||
_authService.dispose();
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user