/// Modèles de données utilisateur avec contexte et permissions /// Support des relations multi-organisations et permissions contextuelles library user_models; import 'package:equatable/equatable.dart'; import 'user_role.dart'; import 'permission_matrix.dart'; /// Modèle utilisateur principal avec contexte multi-organisations /// /// Supporte les utilisateurs ayant des rôles différents dans plusieurs organisations /// avec des permissions contextuelles et des préférences personnalisées class User extends Equatable { /// Identifiant unique de l'utilisateur final String id; /// Informations personnelles final String email; final String firstName; final String lastName; final String? avatar; final String? phone; /// Rôle principal de l'utilisateur (le plus élevé) final UserRole primaryRole; /// Contextes organisationnels (rôles dans différentes organisations) final List organizationContexts; /// Permissions supplémentaires accordées spécifiquement final List additionalPermissions; /// Permissions révoquées spécifiquement final List revokedPermissions; /// Préférences utilisateur final UserPreferences preferences; /// Métadonnées final DateTime createdAt; final DateTime lastLoginAt; final bool isActive; final bool isVerified; /// Constructeur du modèle utilisateur const User({ required this.id, required this.email, required this.firstName, required this.lastName, required this.primaryRole, this.avatar, this.phone, this.organizationContexts = const [], this.additionalPermissions = const [], this.revokedPermissions = const [], this.preferences = const UserPreferences(), required this.createdAt, required this.lastLoginAt, this.isActive = true, this.isVerified = false, }); /// Nom complet de l'utilisateur String get fullName => '$firstName $lastName'; /// Initiales de l'utilisateur String get initials => '${firstName[0]}${lastName[0]}'.toUpperCase(); /// Vérifie si l'utilisateur a une permission dans le contexte actuel bool hasPermission(String permission, {String? organizationId}) { // Vérification des permissions révoquées if (revokedPermissions.contains(permission)) return false; // Vérification des permissions additionnelles if (additionalPermissions.contains(permission)) return true; // Vérification du rôle principal if (primaryRole.hasPermission(permission)) return true; // Vérification dans le contexte organisationnel spécifique if (organizationId != null) { final context = getOrganizationContext(organizationId); if (context?.role.hasPermission(permission) == true) return true; } // Vérification dans tous les contextes organisationnels return organizationContexts.any((context) => context.role.hasPermission(permission)); } /// Obtient le contexte organisationnel pour une organisation UserOrganizationContext? getOrganizationContext(String organizationId) { try { return organizationContexts.firstWhere( (context) => context.organizationId == organizationId, ); } catch (e) { return null; } } /// Obtient le rôle dans une organisation spécifique UserRole getRoleInOrganization(String organizationId) { final context = getOrganizationContext(organizationId); return context?.role ?? primaryRole; } /// Vérifie si l'utilisateur est membre d'une organisation bool isMemberOfOrganization(String organizationId) { return organizationContexts.any( (context) => context.organizationId == organizationId, ); } /// Obtient toutes les permissions effectives de l'utilisateur List getEffectivePermissions({String? organizationId}) { final permissions = {}; // Permissions du rôle principal permissions.addAll(primaryRole.getEffectivePermissions()); // Permissions des contextes organisationnels if (organizationId != null) { final context = getOrganizationContext(organizationId); if (context != null) { permissions.addAll(context.role.getEffectivePermissions()); } } else { for (final context in organizationContexts) { permissions.addAll(context.role.getEffectivePermissions()); } } // Permissions additionnelles permissions.addAll(additionalPermissions); // Retirer les permissions révoquées permissions.removeAll(revokedPermissions); return permissions.toList()..sort(); } /// Crée une copie de l'utilisateur avec des modifications User copyWith({ String? email, String? firstName, String? lastName, String? avatar, String? phone, UserRole? primaryRole, List? organizationContexts, List? additionalPermissions, List? revokedPermissions, UserPreferences? preferences, DateTime? lastLoginAt, bool? isActive, bool? isVerified, }) { return User( id: id, email: email ?? this.email, firstName: firstName ?? this.firstName, lastName: lastName ?? this.lastName, avatar: avatar ?? this.avatar, phone: phone ?? this.phone, primaryRole: primaryRole ?? this.primaryRole, organizationContexts: organizationContexts ?? this.organizationContexts, additionalPermissions: additionalPermissions ?? this.additionalPermissions, revokedPermissions: revokedPermissions ?? this.revokedPermissions, preferences: preferences ?? this.preferences, createdAt: createdAt, lastLoginAt: lastLoginAt ?? this.lastLoginAt, isActive: isActive ?? this.isActive, isVerified: isVerified ?? this.isVerified, ); } /// Conversion vers Map pour sérialisation Map toJson() { return { 'id': id, 'email': email, 'firstName': firstName, 'lastName': lastName, 'avatar': avatar, 'phone': phone, 'primaryRole': primaryRole.name, 'organizationContexts': organizationContexts.map((c) => c.toJson()).toList(), 'additionalPermissions': additionalPermissions, 'revokedPermissions': revokedPermissions, 'preferences': preferences.toJson(), 'createdAt': createdAt.toIso8601String(), 'lastLoginAt': lastLoginAt.toIso8601String(), 'isActive': isActive, 'isVerified': isVerified, }; } /// Création depuis Map pour désérialisation factory User.fromJson(Map json) { return User( id: json['id'], email: json['email'], firstName: json['firstName'], lastName: json['lastName'], avatar: json['avatar'], phone: json['phone'], primaryRole: UserRole.fromString(json['primaryRole']) ?? UserRole.visitor, organizationContexts: (json['organizationContexts'] as List?) ?.map((c) => UserOrganizationContext.fromJson(c)) .toList() ?? [], additionalPermissions: List.from(json['additionalPermissions'] ?? []), revokedPermissions: List.from(json['revokedPermissions'] ?? []), preferences: UserPreferences.fromJson(json['preferences'] ?? {}), createdAt: DateTime.parse(json['createdAt']), lastLoginAt: DateTime.parse(json['lastLoginAt']), isActive: json['isActive'] ?? true, isVerified: json['isVerified'] ?? false, ); } @override List get props => [ id, email, firstName, lastName, avatar, phone, primaryRole, organizationContexts, additionalPermissions, revokedPermissions, preferences, createdAt, lastLoginAt, isActive, isVerified, ]; } /// Contexte organisationnel d'un utilisateur /// /// Définit le rôle et les permissions spécifiques dans une organisation class UserOrganizationContext extends Equatable { /// Identifiant de l'organisation final String organizationId; /// Nom de l'organisation final String organizationName; /// Rôle de l'utilisateur dans cette organisation final UserRole role; /// Permissions spécifiques dans cette organisation final List specificPermissions; /// Date d'adhésion à l'organisation final DateTime joinedAt; /// Statut dans l'organisation final bool isActive; /// Constructeur du contexte organisationnel const UserOrganizationContext({ required this.organizationId, required this.organizationName, required this.role, this.specificPermissions = const [], required this.joinedAt, this.isActive = true, }); /// Conversion vers Map Map toJson() { return { 'organizationId': organizationId, 'organizationName': organizationName, 'role': role.name, 'specificPermissions': specificPermissions, 'joinedAt': joinedAt.toIso8601String(), 'isActive': isActive, }; } /// Création depuis Map factory UserOrganizationContext.fromJson(Map json) { return UserOrganizationContext( organizationId: json['organizationId'], organizationName: json['organizationName'], role: UserRole.fromString(json['role']) ?? UserRole.visitor, specificPermissions: List.from(json['specificPermissions'] ?? []), joinedAt: DateTime.parse(json['joinedAt']), isActive: json['isActive'] ?? true, ); } @override List get props => [ organizationId, organizationName, role, specificPermissions, joinedAt, isActive, ]; } /// Préférences utilisateur personnalisables class UserPreferences extends Equatable { /// Langue préférée final String language; /// Thème préféré final String theme; /// Notifications activées final bool notificationsEnabled; /// Notifications par email final bool emailNotifications; /// Notifications push final bool pushNotifications; /// Layout du dashboard préféré final String dashboardLayout; /// Timezone final String timezone; /// Constructeur des préférences const UserPreferences({ this.language = 'fr', this.theme = 'system', this.notificationsEnabled = true, this.emailNotifications = true, this.pushNotifications = true, this.dashboardLayout = 'default', this.timezone = 'Europe/Paris', }); /// Conversion vers Map Map toJson() { return { 'language': language, 'theme': theme, 'notificationsEnabled': notificationsEnabled, 'emailNotifications': emailNotifications, 'pushNotifications': pushNotifications, 'dashboardLayout': dashboardLayout, 'timezone': timezone, }; } /// Création depuis Map factory UserPreferences.fromJson(Map json) { return UserPreferences( language: json['language'] ?? 'fr', theme: json['theme'] ?? 'system', notificationsEnabled: json['notificationsEnabled'] ?? true, emailNotifications: json['emailNotifications'] ?? true, pushNotifications: json['pushNotifications'] ?? true, dashboardLayout: json['dashboardLayout'] ?? 'default', timezone: json['timezone'] ?? 'Europe/Paris', ); } @override List get props => [ language, theme, notificationsEnabled, emailNotifications, pushNotifications, dashboardLayout, timezone, ]; }