361 lines
11 KiB
Dart
361 lines
11 KiB
Dart
/// 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<UserOrganizationContext> organizationContexts;
|
|
|
|
/// Permissions supplémentaires accordées spécifiquement
|
|
final List<String> additionalPermissions;
|
|
|
|
/// Permissions révoquées spécifiquement
|
|
final List<String> 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<String> getEffectivePermissions({String? organizationId}) {
|
|
final permissions = <String>{};
|
|
|
|
// 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<UserOrganizationContext>? organizationContexts,
|
|
List<String>? additionalPermissions,
|
|
List<String>? 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<String, dynamic> 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<String, dynamic> 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<String>.from(json['additionalPermissions'] ?? []),
|
|
revokedPermissions: List<String>.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<Object?> 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<String> 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<String, dynamic> toJson() {
|
|
return {
|
|
'organizationId': organizationId,
|
|
'organizationName': organizationName,
|
|
'role': role.name,
|
|
'specificPermissions': specificPermissions,
|
|
'joinedAt': joinedAt.toIso8601String(),
|
|
'isActive': isActive,
|
|
};
|
|
}
|
|
|
|
/// Création depuis Map
|
|
factory UserOrganizationContext.fromJson(Map<String, dynamic> json) {
|
|
return UserOrganizationContext(
|
|
organizationId: json['organizationId'],
|
|
organizationName: json['organizationName'],
|
|
role: UserRole.fromString(json['role']) ?? UserRole.visitor,
|
|
specificPermissions: List<String>.from(json['specificPermissions'] ?? []),
|
|
joinedAt: DateTime.parse(json['joinedAt']),
|
|
isActive: json['isActive'] ?? true,
|
|
);
|
|
}
|
|
|
|
@override
|
|
List<Object?> 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<String, dynamic> toJson() {
|
|
return {
|
|
'language': language,
|
|
'theme': theme,
|
|
'notificationsEnabled': notificationsEnabled,
|
|
'emailNotifications': emailNotifications,
|
|
'pushNotifications': pushNotifications,
|
|
'dashboardLayout': dashboardLayout,
|
|
'timezone': timezone,
|
|
};
|
|
}
|
|
|
|
/// Création depuis Map
|
|
factory UserPreferences.fromJson(Map<String, dynamic> 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<Object?> get props => [
|
|
language, theme, notificationsEnabled, emailNotifications,
|
|
pushNotifications, dashboardLayout, timezone,
|
|
];
|
|
}
|