Initial commit: unionflow-mobile-apps
Application Flutter complète (sans build artifacts). Signed-off-by: lions dev Team
This commit is contained in:
66
lib/features/admin/data/models/admin_user_model.dart
Normal file
66
lib/features/admin/data/models/admin_user_model.dart
Normal file
@@ -0,0 +1,66 @@
|
||||
/// Modèle pour un utilisateur admin (Keycloak) - aligné sur l'API /api/admin/users
|
||||
library admin_user_model;
|
||||
|
||||
class AdminUserModel {
|
||||
final String id;
|
||||
final String? username;
|
||||
final String? email;
|
||||
final String? prenom;
|
||||
final String? nom;
|
||||
final bool? enabled;
|
||||
final List<String>? realmRoles;
|
||||
|
||||
AdminUserModel({
|
||||
required this.id,
|
||||
this.username,
|
||||
this.email,
|
||||
this.prenom,
|
||||
this.nom,
|
||||
this.enabled,
|
||||
this.realmRoles,
|
||||
});
|
||||
|
||||
String get displayName {
|
||||
if (prenom != null && nom != null) return '$prenom $nom';
|
||||
if (prenom != null) return prenom!;
|
||||
if (nom != null) return nom!;
|
||||
return username ?? email ?? id;
|
||||
}
|
||||
|
||||
factory AdminUserModel.fromJson(Map<String, dynamic> json) {
|
||||
final roles = json['realmRoles'] as List<dynamic>?;
|
||||
return AdminUserModel(
|
||||
id: json['id'] as String? ?? '',
|
||||
username: json['username'] as String?,
|
||||
email: json['email'] as String?,
|
||||
prenom: json['prenom'] as String?,
|
||||
nom: json['nom'] as String?,
|
||||
enabled: json['enabled'] as bool?,
|
||||
realmRoles: roles?.map((e) => e is Map ? (e['name'] as String?) ?? e.toString() : e.toString()).toList(),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'id': id,
|
||||
'username': username,
|
||||
'email': email,
|
||||
'prenom': prenom,
|
||||
'nom': nom,
|
||||
'enabled': enabled,
|
||||
'realmRoles': realmRoles,
|
||||
};
|
||||
}
|
||||
|
||||
class AdminRoleModel {
|
||||
final String id;
|
||||
final String name;
|
||||
final String? description;
|
||||
|
||||
AdminRoleModel({required this.id, required this.name, this.description});
|
||||
|
||||
factory AdminRoleModel.fromJson(Map<String, dynamic> json) => AdminRoleModel(
|
||||
id: json['id'] as String? ?? '',
|
||||
name: json['name'] as String? ?? '',
|
||||
description: json['description'] as String?,
|
||||
);
|
||||
}
|
||||
105
lib/features/admin/data/repositories/admin_user_repository.dart
Normal file
105
lib/features/admin/data/repositories/admin_user_repository.dart
Normal file
@@ -0,0 +1,105 @@
|
||||
/// Repository pour la gestion des utilisateurs admin (API /api/admin/users)
|
||||
library admin_user_repository;
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:unionflow_mobile_apps/core/network/api_client.dart';
|
||||
import '../models/admin_user_model.dart';
|
||||
|
||||
abstract class AdminUserRepository {
|
||||
Future<AdminUserSearchResult> search({int page = 0, int size = 20, String? search});
|
||||
Future<AdminUserModel?> getById(String id);
|
||||
Future<List<AdminRoleModel>> getRealmRoles();
|
||||
Future<List<AdminRoleModel>> getUserRoles(String userId);
|
||||
Future<void> setUserRoles(String userId, List<String> roleNames);
|
||||
/// Associe un utilisateur (email) à une organisation (réservé SUPER_ADMIN).
|
||||
Future<void> associerOrganisation({required String email, required String organisationId});
|
||||
}
|
||||
|
||||
class AdminUserSearchResult {
|
||||
final List<AdminUserModel> users;
|
||||
final int totalCount;
|
||||
final int currentPage;
|
||||
final int pageSize;
|
||||
final int totalPages;
|
||||
|
||||
AdminUserSearchResult({
|
||||
required this.users,
|
||||
required this.totalCount,
|
||||
required this.currentPage,
|
||||
required this.pageSize,
|
||||
required this.totalPages,
|
||||
});
|
||||
}
|
||||
|
||||
@LazySingleton(as: AdminUserRepository)
|
||||
class AdminUserRepositoryImpl implements AdminUserRepository {
|
||||
final ApiClient _apiClient;
|
||||
static const String _base = '/api/admin/users';
|
||||
|
||||
AdminUserRepositoryImpl(this._apiClient);
|
||||
|
||||
@override
|
||||
Future<AdminUserSearchResult> search({int page = 0, int size = 20, String? search}) async {
|
||||
final query = <String, dynamic>{'page': page, 'size': size};
|
||||
if (search != null && search.isNotEmpty) query['search'] = search;
|
||||
final response = await _apiClient.get(_base, queryParameters: query);
|
||||
if (response.statusCode != 200) throw Exception('Erreur ${response.statusCode}');
|
||||
final data = response.data as Map<String, dynamic>;
|
||||
final list = data['users'] as List<dynamic>? ?? [];
|
||||
return AdminUserSearchResult(
|
||||
users: list.map((e) => AdminUserModel.fromJson(e as Map<String, dynamic>)).toList(),
|
||||
totalCount: (data['totalCount'] as num?)?.toInt() ?? 0,
|
||||
currentPage: (data['currentPage'] as num?)?.toInt() ?? 0,
|
||||
pageSize: (data['pageSize'] as num?)?.toInt() ?? size,
|
||||
totalPages: (data['totalPages'] as num?)?.toInt() ?? 0,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<AdminUserModel?> getById(String id) async {
|
||||
final response = await _apiClient.get('$_base/$id');
|
||||
if (response.statusCode == 200) {
|
||||
return AdminUserModel.fromJson(response.data as Map<String, dynamic>);
|
||||
}
|
||||
if (response.statusCode == 404) return null;
|
||||
throw Exception('Erreur ${response.statusCode}');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<AdminRoleModel>> getRealmRoles() async {
|
||||
final response = await _apiClient.get('$_base/roles');
|
||||
if (response.statusCode != 200) return [];
|
||||
final list = response.data as List<dynamic>? ?? [];
|
||||
return list.map((e) => AdminRoleModel.fromJson(e as Map<String, dynamic>)).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<AdminRoleModel>> getUserRoles(String userId) async {
|
||||
final response = await _apiClient.get('$_base/$userId/roles');
|
||||
if (response.statusCode != 200) return [];
|
||||
final list = response.data as List<dynamic>? ?? [];
|
||||
return list.map((e) => AdminRoleModel.fromJson(e as Map<String, dynamic>)).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setUserRoles(String userId, List<String> roleNames) async {
|
||||
final response = await _apiClient.put('$_base/$userId/roles', data: roleNames);
|
||||
if (response.statusCode != 200) throw Exception('Erreur ${response.statusCode}');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> associerOrganisation({required String email, required String organisationId}) async {
|
||||
const path = '/api/admin/associer-organisation';
|
||||
final response = await _apiClient.post(
|
||||
path,
|
||||
data: {'email': email, 'organisationId': organisationId},
|
||||
);
|
||||
if (response.statusCode != 200) {
|
||||
final msg = response.data is Map && response.data['message'] != null
|
||||
? response.data['message'] as String
|
||||
: 'Erreur ${response.statusCode}';
|
||||
throw Exception(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user