feat(features): refontes adhesions/admin/auth/backup/contributions/dashboard/epargne/events
- adhesions : bloc complet avec events/states/model, dialogs paiement/rejet - admin : users bloc, user management list/detail pages - authentication : bloc + keycloak auth service + webview - backup : bloc complet, repository, models - contributions : bloc + widgets + export - dashboard : widgets connectés (activities, events, notifications, search) + charts + monitoring + shortcuts - epargne : repository, transactions, dialogs - events : bloc complet, pages (detail, connected, wrapper), models
This commit is contained in:
@@ -167,9 +167,56 @@ class KeycloakAuthService {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Logout : révoque la session SSO côté Keycloak via le back-channel
|
||||
/// (POST /logout silencieux, sans navigateur), puis purge le stockage local.
|
||||
///
|
||||
/// Conforme OIDC RP-Initiated Logout. Ne lève jamais d'exception : la purge
|
||||
/// locale est garantie même si Keycloak est injoignable. Le statut du
|
||||
/// back-channel est tracé dans les logs pour diagnostic.
|
||||
Future<void> logout() async {
|
||||
final refresh = await _storage.read(key: _refreshK);
|
||||
|
||||
if (refresh == null || refresh.isEmpty) {
|
||||
AppLogger.info('KeycloakAuthService: no refresh token, skipping backchannel logout');
|
||||
} else {
|
||||
try {
|
||||
final response = await _dio.post(
|
||||
KeycloakConfig.logoutEndpoint,
|
||||
data: {
|
||||
'client_id': KeycloakConfig.clientId,
|
||||
'refresh_token': refresh,
|
||||
},
|
||||
options: Options(
|
||||
contentType: Headers.formUrlEncodedContentType,
|
||||
// Accepte tout statut < 600 — on interprète nous-mêmes ci-dessous.
|
||||
validateStatus: (_) => true,
|
||||
),
|
||||
);
|
||||
final code = response.statusCode ?? 0;
|
||||
if (code == 200 || code == 204) {
|
||||
AppLogger.info('KeycloakAuthService: SSO session revoked at Keycloak (HTTP $code)');
|
||||
} else if (code == 400) {
|
||||
// Refresh token déjà invalide côté Keycloak → idempotent, OK.
|
||||
AppLogger.info('KeycloakAuthService: refresh token already invalid (HTTP 400) — session considered revoked');
|
||||
} else {
|
||||
AppLogger.error(
|
||||
'KeycloakAuthService: backchannel logout returned HTTP $code — '
|
||||
'SSO session may still be active. Body: ${response.data}',
|
||||
);
|
||||
}
|
||||
} catch (e, st) {
|
||||
AppLogger.error(
|
||||
'KeycloakAuthService: backchannel logout network error — local logout will still proceed',
|
||||
error: e,
|
||||
stackTrace: st,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Purge locale toujours effectuée — l'utilisateur "se sent" déconnecté
|
||||
// immédiatement même si le serveur n'a pas pu être notifié.
|
||||
await _storage.deleteAll();
|
||||
AppLogger.info('KeycloakAuthService: session cleared');
|
||||
AppLogger.info('KeycloakAuthService: local session cleared');
|
||||
}
|
||||
|
||||
Future<void> _saveTokens(Map<String, dynamic> data) async {
|
||||
|
||||
@@ -15,7 +15,7 @@ enum UserRole {
|
||||
level: 100,
|
||||
displayName: 'Super Administrateur',
|
||||
description: 'Accès complet système et multi-organisations',
|
||||
color: 0xFF6C5CE7, // Violet sophistiqué
|
||||
color: 0xFF7616E8, // Violet UnionFlow (super admin)
|
||||
permissions: _superAdminPermissions,
|
||||
),
|
||||
|
||||
@@ -25,7 +25,7 @@ enum UserRole {
|
||||
level: 80,
|
||||
displayName: 'Administrateur',
|
||||
description: 'Gestion complète de l\'organisation',
|
||||
color: 0xFF0984E3, // Bleu corporate
|
||||
color: 0xFF2563EB, // Bleu primaire UnionFlow
|
||||
permissions: _orgAdminPermissions,
|
||||
),
|
||||
|
||||
@@ -45,7 +45,7 @@ enum UserRole {
|
||||
level: 58,
|
||||
displayName: 'Consultant',
|
||||
description: 'Accès consultant et conseil',
|
||||
color: 0xFF6C5CE7, // Violet
|
||||
color: 0xFF5297FF, // Bleu intermédiaire (consultant)
|
||||
permissions: _consultantPermissions,
|
||||
),
|
||||
|
||||
@@ -55,7 +55,7 @@ enum UserRole {
|
||||
level: 52,
|
||||
displayName: 'Gestionnaire RH',
|
||||
description: 'Gestion des ressources humaines',
|
||||
color: 0xFF0984E3, // Bleu
|
||||
color: 0xFF1D4ED8, // Bleu foncé (RH)
|
||||
permissions: _hrManagerPermissions,
|
||||
),
|
||||
|
||||
@@ -65,7 +65,7 @@ enum UserRole {
|
||||
level: 40,
|
||||
displayName: 'Membre Actif',
|
||||
description: 'Participation active aux activités',
|
||||
color: 0xFF00B894, // Vert communauté
|
||||
color: 0xFF22C55E, // Vert succès (membre actif)
|
||||
permissions: _activeMemberPermissions,
|
||||
),
|
||||
|
||||
@@ -75,7 +75,7 @@ enum UserRole {
|
||||
level: 20,
|
||||
displayName: 'Membre',
|
||||
description: 'Accès aux informations de base',
|
||||
color: 0xFF00CEC9, // Teal simple
|
||||
color: 0xFF60A5FA, // Bleu clair (membre simple)
|
||||
permissions: _simpleMemberPermissions,
|
||||
),
|
||||
|
||||
@@ -85,7 +85,7 @@ enum UserRole {
|
||||
level: 0,
|
||||
displayName: 'Visiteur',
|
||||
description: 'Accès aux informations publiques',
|
||||
color: 0xFF6C5CE7, // Indigo accueillant
|
||||
color: 0xFF94A3B8, // Gris neutre (visiteur)
|
||||
permissions: _visitorPermissions,
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user