Browse Source

mis a jour gestion d'utilisateur

31052025_01
b.razafimandimbihery 6 months ago
parent
commit
d41936441c
  1. 34
      lib/Components/appDrawer.dart
  2. 94
      lib/Models/menu.dart
  3. 231
      lib/Services/app_database.dart
  4. 215
      lib/Views/RoleListPage.dart
  5. 177
      lib/Views/RolePermissionPage.dart
  6. 64
      lib/Views/gestionRole.dart
  7. 2
      lib/Views/loginPage.dart
  8. 93
      lib/controller/userController.dart
  9. 5
      lib/main.dart

34
lib/Components/appDrawer.dart

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:youmazgestion/Views/RoleListPage.dart';
import 'package:youmazgestion/Views/historique.dart';
import 'package:youmazgestion/Views/addProduct.dart';
import 'package:youmazgestion/Views/bilanMois.dart';
@ -50,8 +51,21 @@ class CustomDrawer extends StatelessWidget {
leading: const Icon(Icons.home),
iconColor: Colors.lightBlueAccent,
title: const Text("Accueil"),
onTap: () {
onTap: () async {
bool hasPermission = await userController.hasPermission('view', '/accueil');
if (hasPermission) {
Get.to(const AccueilPage());
} else {
Get.snackbar(
"Accès refusé",
"Vous n'avez pas les droits pour accéder à cette page",
backgroundColor: Colors.red,
colorText: Colors.white,
icon: const Icon(Icons.error),
duration: const Duration(seconds: 3),
snackPosition: SnackPosition.TOP,
);
}
},
),
ListTile(
@ -59,7 +73,7 @@ class CustomDrawer extends StatelessWidget {
iconColor: Colors.green,
title: const Text("Ajouter un utilisateur"),
onTap: () async {
bool hasPermission = await userController.hasAnyPermission(['create']);
bool hasPermission = await userController.hasPermission('create', '/ajouter-utilisateur');
if (hasPermission) {
Get.to(const RegistrationPage());
} else {
@ -80,7 +94,7 @@ class CustomDrawer extends StatelessWidget {
iconColor: const Color.fromARGB(255, 4, 54, 95),
title: const Text("Modifier/Supprimer un utilisateur"),
onTap: () async {
bool hasPermission = await userController.hasAnyPermission(['update', 'delete']);
bool hasPermission = await userController.hasPermission('update', '/modifier-utilisateur');
if (hasPermission) {
Get.to(const ListUserPage());
} else {
@ -101,7 +115,7 @@ class CustomDrawer extends StatelessWidget {
iconColor: Colors.indigoAccent,
title: const Text("Ajouter un produit"),
onTap: () async {
bool hasPermission = await userController.hasAnyPermission(['create']);
bool hasPermission = await userController.hasPermission('create', '/ajouter-produit');
if (hasPermission) {
Get.to(const AddProductPage());
} else {
@ -122,7 +136,7 @@ class CustomDrawer extends StatelessWidget {
iconColor: Colors.redAccent,
title: const Text("Modifier/Supprimer un produit"),
onTap: () async {
bool hasPermission = await userController.hasAnyPermission(['update', 'delete']);
bool hasPermission = await userController.hasPermission('update', '/modifier-produit');
if (hasPermission) {
Get.to(GestionProduit());
} else {
@ -142,7 +156,7 @@ class CustomDrawer extends StatelessWidget {
leading: const Icon(Icons.bar_chart),
title: const Text("Bilan"),
onTap: () async {
bool hasPermission = await userController.hasAnyPermission(['read']);
bool hasPermission = await userController.hasPermission('read', '/bilan');
if (hasPermission) {
Get.to(const BilanMois());
} else {
@ -162,10 +176,12 @@ class CustomDrawer extends StatelessWidget {
leading: const Icon(Icons.warning_amber),
title: const Text("Gérer les rôles"),
onTap: () async {
bool hasPermission = await userController.hasAnyPermission(['update', 'delete','create']);
bool hasPermission = await userController.hasPermission('admin', '/gerer-roles');
if (hasPermission) {
Get.to(const HandleUserRole());
Get.to(const RoleListPage());
print("permission accepted");
} else {
print("permission not accepted for" +userController.username);
Get.snackbar(
"Accès refusé ",
"Vous n'avez pas les droits pour gérer les rôles",
@ -183,7 +199,7 @@ class CustomDrawer extends StatelessWidget {
iconColor: Colors.blueAccent,
title: const Text("Gestion de stock"),
onTap: () async {
bool hasPermission = await userController.hasAnyPermission(['update']);
bool hasPermission = await userController.hasPermission('update', '/gestion-stock');
if (hasPermission) {
Get.to(const GestionStockPage());
} else {

94
lib/Models/menu.dart

@ -0,0 +1,94 @@
// Models/menu.dart
class Menu {
final int? id;
final String title;
final String icon;
final String route;
final int orderIndex;
final bool isActive;
final int? parentId;
Menu({
this.id,
required this.title,
required this.icon,
required this.route,
this.orderIndex = 0,
this.isActive = true,
this.parentId,
});
Map<String, dynamic> toMap() {
return {
'id': id,
'title': title,
'icon': icon,
'route': route,
'order_index': orderIndex,
'is_active': isActive ? 1 : 0,
'parent_id': parentId,
};
}
factory Menu.fromMap(Map<String, dynamic> map) {
return Menu(
id: map['id']?.toInt(),
title: map['title'] ?? '',
icon: map['icon'] ?? '',
route: map['route'] ?? '',
orderIndex: map['order_index']?.toInt() ?? 0,
isActive: (map['is_active'] ?? 1) == 1,
parentId: map['parent_id']?.toInt(),
);
}
Menu copyWith({
int? id,
String? title,
String? icon,
String? route,
int? orderIndex,
bool? isActive,
int? parentId,
}) {
return Menu(
id: id ?? this.id,
title: title ?? this.title,
icon: icon ?? this.icon,
route: route ?? this.route,
orderIndex: orderIndex ?? this.orderIndex,
isActive: isActive ?? this.isActive,
parentId: parentId ?? this.parentId,
);
}
@override
String toString() {
return 'Menu(id: $id, title: $title, icon: $icon, route: $route, orderIndex: $orderIndex, isActive: $isActive, parentId: $parentId)';
}
@override
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is Menu &&
other.id == id &&
other.title == title &&
other.icon == icon &&
other.route == route &&
other.orderIndex == orderIndex &&
other.isActive == isActive &&
other.parentId == parentId;
}
@override
int get hashCode {
return id.hashCode ^
title.hashCode ^
icon.hashCode ^
route.hashCode ^
orderIndex.hashCode ^
isActive.hashCode ^
parentId.hashCode;
}
}

231
lib/Services/app_database.dart

@ -26,6 +26,7 @@ class AppDatabase {
_database = await _initDB('app_database.db');
await _createDB(_database, 1);
await insertDefaultPermissions();
await insertDefaultMenus();
await insertDefaultRoles();
await insertDefaultSuperAdmin();
}
@ -36,13 +37,11 @@ class AppDatabase {
bool dbExists = await File(path).exists();
if (!dbExists) {
// Optionnel : copier depuis assets si vous avez une DB pré-remplie
try {
ByteData data = await rootBundle.load('assets/database/$filePath');
List<int> bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
await File(path).writeAsBytes(bytes);
} catch (e) {
// Si pas de fichier dans assets, on continue avec une DB vide
print('Pas de fichier DB dans assets, création d\'une nouvelle DB');
}
}
@ -54,7 +53,6 @@ class AppDatabase {
final tables = await db.rawQuery("SELECT name FROM sqlite_master WHERE type='table'");
final tableNames = tables.map((row) => row['name'] as String).toList();
// Table des rôles
if (!tableNames.contains('roles')) {
await db.execute('''
CREATE TABLE roles (
@ -65,7 +63,6 @@ class AppDatabase {
print("Table 'roles' créée.");
}
// Table des permissions
if (!tableNames.contains('permissions')) {
await db.execute('''
CREATE TABLE permissions (
@ -76,7 +73,17 @@ class AppDatabase {
print("Table 'permissions' créée.");
}
// Table de liaison role_permissions
if (!tableNames.contains('menu')) {
await db.execute('''
CREATE TABLE menu (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
route TEXT NOT NULL UNIQUE
)
''');
print("Table 'menu' créée.");
}
if (!tableNames.contains('role_permissions')) {
await db.execute('''
CREATE TABLE role_permissions (
@ -90,7 +97,19 @@ class AppDatabase {
print("Table 'role_permissions' créée.");
}
// Table des utilisateurs
if (!tableNames.contains('menu_permissions')) {
await db.execute('''
CREATE TABLE menu_permissions (
menu_id INTEGER,
permission_id INTEGER,
PRIMARY KEY (menu_id, permission_id),
FOREIGN KEY (menu_id) REFERENCES menu(id) ON DELETE CASCADE,
FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE
)
''');
print("Table 'menu_permissions' créée.");
}
if (!tableNames.contains('users')) {
await db.execute('''
CREATE TABLE users (
@ -106,9 +125,22 @@ class AppDatabase {
''');
print("Table 'users' créée.");
}
if (!tableNames.contains('role_menu_permissions')) {
await db.execute('''
CREATE TABLE role_menu_permissions (
role_id INTEGER,
menu_id INTEGER,
permission_id INTEGER,
PRIMARY KEY (role_id, menu_id, permission_id),
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
FOREIGN KEY (menu_id) REFERENCES menu(id) ON DELETE CASCADE,
FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE
)
''');
print("Table 'role_menu_permissions' créée.");
}
// ========== INSERTION DES DONNÉES PAR DÉFAUT ==========
}
Future<void> insertDefaultPermissions() async {
final db = await database;
@ -123,67 +155,118 @@ class AppDatabase {
}
}
Future<void> insertDefaultMenus() async {
final db = await database;
final existingMenus = await db.query('menu');
if (existingMenus.isEmpty) {
await db.insert('menu', {'name': 'Accueil', 'route': '/accueil'});
await db.insert('menu', {'name': 'Ajouter un utilisateur', 'route': '/ajouter-utilisateur'});
await db.insert('menu', {'name': 'Modifier/Supprimer un utilisateur', 'route': '/modifier-utilisateur'});
await db.insert('menu', {'name': 'Ajouter un produit', 'route': '/ajouter-produit'});
await db.insert('menu', {'name': 'Modifier/Supprimer un produit', 'route': '/modifier-produit'});
await db.insert('menu', {'name': 'Bilan', 'route': '/bilan'});
await db.insert('menu', {'name': 'Gérer les rôles', 'route': '/gerer-roles'});
await db.insert('menu', {'name': 'Gestion de stock', 'route': '/gestion-stock'});
await db.insert('menu', {'name': 'Historique', 'route': '/historique'});
await db.insert('menu', {'name': 'Déconnexion', 'route': '/deconnexion'});
print("Menus par défaut insérés");
}
}
Future<void> insertDefaultRoles() async {
final db = await database;
final existingRoles = await db.query('roles');
if (existingRoles.isEmpty) {
// Créer le rôle Super Admin
int superAdminRoleId = await db.insert('roles', {'designation': 'Super Admin'});
// Créer d'autres rôles de base
int adminRoleId = await db.insert('roles', {'designation': 'Admin'});
int userRoleId = await db.insert('roles', {'designation': 'User'});
// Assigner toutes les permissions au Super Admin
final permissions = await db.query('permissions');
final menus = await db.query('menu');
// Assigner toutes les permissions à tous les menus pour le Super Admin
for (var menu in menus) {
for (var permission in permissions) {
await db.insert('role_permissions', {
await db.insert('role_menu_permissions', {
'role_id': superAdminRoleId,
'menu_id': menu['id'],
'permission_id': permission['id'],
});
}
}
// Assigner quelques permissions à l'Admin
// Assigner quelques permissions à l'Admin et à l'User
final viewPermission = await db.query('permissions', where: 'name = ?', whereArgs: ['view']);
final createPermission = await db.query('permissions', where: 'name = ?', whereArgs: ['create']);
final updatePermission = await db.query('permissions', where: 'name = ?', whereArgs: ['update']);
if (viewPermission.isNotEmpty) {
await db.insert('role_permissions', {
await db.insert('role_menu_permissions', {
'role_id': adminRoleId,
'menu_id': 1, // Assurez-vous que l'ID du menu est correct
'permission_id': viewPermission.first['id'],
});
await db.insert('role_menu_permissions', {
'role_id': userRoleId,
'menu_id': 1, // Assurez-vous que l'ID du menu est correct
'permission_id': viewPermission.first['id'],
});
}
if (createPermission.isNotEmpty) {
await db.insert('role_permissions', {
await db.insert('role_menu_permissions', {
'role_id': adminRoleId,
'menu_id': 1, // Assurez-vous que l'ID du menu est correct
'permission_id': createPermission.first['id'],
});
}
if (updatePermission.isNotEmpty) {
await db.insert('role_permissions', {
await db.insert('role_menu_permissions', {
'role_id': adminRoleId,
'menu_id': 1, // Assurez-vous que l'ID du menu est correct
'permission_id': updatePermission.first['id'],
});
}
// Assigner seulement la permission view à User
if (viewPermission.isNotEmpty) {
await db.insert('role_permissions', {
'role_id': userRoleId,
'permission_id': viewPermission.first['id'],
print("Rôles par défaut créés et permissions assignées");
} else {
// Si les rôles existent déjà, vérifier et ajouter les permissions manquantes pour le Super Admin
final superAdminRole = await db.query('roles', where: 'designation = ?', whereArgs: ['Super Admin']);
if (superAdminRole.isNotEmpty) {
final superAdminRoleId = superAdminRole.first['id'] as int;
final permissions = await db.query('permissions');
final menus = await db.query('menu');
// Vérifier et ajouter les permissions manquantes pour le Super Admin
for (var menu in menus) {
for (var permission in permissions) {
final existingPermission = await db.query(
'role_menu_permissions',
where: 'role_id = ? AND menu_id = ? AND permission_id = ?',
whereArgs: [superAdminRoleId, menu['id'], permission['id']],
);
if (existingPermission.isEmpty) {
await db.insert('role_menu_permissions', {
'role_id': superAdminRoleId,
'menu_id': menu['id'],
'permission_id': permission['id'],
});
}
}
}
print("Rôles par défaut créés et permissions assignées");
print("Permissions manquantes ajoutées pour le Super Admin");
}
}
}
Future<void> insertDefaultSuperAdmin() async {
final db = await database;
// Vérifier si un super admin existe déjà
final existingSuperAdmin = await db.rawQuery('''
SELECT u.* FROM users u
INNER JOIN roles r ON u.role_id = r.id
@ -191,7 +274,6 @@ class AppDatabase {
''');
if (existingSuperAdmin.isEmpty) {
// Récupérer l'ID du rôle Super Admin
final superAdminRole = await db.query('roles',
where: 'designation = ?',
whereArgs: ['Super Admin']
@ -200,12 +282,11 @@ class AppDatabase {
if (superAdminRole.isNotEmpty) {
final superAdminRoleId = superAdminRole.first['id'] as int;
// Créer l'utilisateur Super Admin
await db.insert('users', {
'name': 'Super',
'lastname': 'Admin',
'email': 'superadmin@youmazgestion.com',
'password': 'admin123', // CHANGEZ CE MOT DE PASSE !
'password': 'admin123',
'username': 'superadmin',
'role_id': superAdminRoleId,
});
@ -220,8 +301,6 @@ class AppDatabase {
}
}
// ========== GESTION DES UTILISATEURS ==========
Future<int> createUser(Users user) async {
final db = await database;
return await db.insert('users', user.toMap());
@ -301,8 +380,6 @@ class AppDatabase {
return result.map((json) => Users.fromMap(json)).toList();
}
// ========== GESTION DES RÔLES ==========
Future<int> createRole(Role role) async {
final db = await database;
return await db.insert('roles', role.toMap());
@ -333,8 +410,6 @@ class AppDatabase {
);
}
// ========== GESTION DES PERMISSIONS ==========
Future<List<Permission>> getAllPermissions() async {
final db = await database;
final result = await db.query('permissions', orderBy: 'name ASC');
@ -386,7 +461,22 @@ class AppDatabase {
);
}
// ========== MÉTHODES UTILITAIRES POUR LA SÉCURITÉ ==========
Future<void> assignMenuPermission(int menuId, int permissionId) async {
final db = await database;
await db.insert('menu_permissions', {
'menu_id': menuId,
'permission_id': permissionId,
}, conflictAlgorithm: ConflictAlgorithm.ignore);
}
Future<void> removeMenuPermission(int menuId, int permissionId) async {
final db = await database;
await db.delete(
'menu_permissions',
where: 'menu_id = ? AND permission_id = ?',
whereArgs: [menuId, permissionId],
);
}
Future<bool> isSuperAdmin(String username) async {
final db = await database;
@ -403,13 +493,11 @@ class AppDatabase {
Future<void> changePassword(String username, String oldPassword, String newPassword) async {
final db = await database;
// Vérifier l'ancien mot de passe
final isValidOldPassword = await verifyUser(username, oldPassword);
if (!isValidOldPassword) {
throw Exception('Ancien mot de passe incorrect');
}
// Changer le mot de passe
await db.update(
'users',
{'password': newPassword},
@ -418,54 +506,48 @@ class AppDatabase {
);
}
// ========== UTILITAIRES ==========
Future<void> close() async {
if (_database.isOpen) {
await _database.close();
}
}
Future<bool> hasPermission(String username, String permissionName) async {
Future<bool> hasPermission(String username, String permissionName, String menuRoute) async {
final db = await database;
final result = await db.rawQuery('''
SELECT COUNT(*) as count
FROM permissions p
JOIN role_permissions rp ON p.id = rp.permission_id
JOIN roles r ON rp.role_id = r.id
JOIN role_menu_permissions rmp ON p.id = rmp.permission_id
JOIN roles r ON rmp.role_id = r.id
JOIN users u ON u.role_id = r.id
WHERE u.username = ? AND p.name = ?
''', [username, permissionName]);
JOIN menu m ON m.route = ?
WHERE u.username = ? AND p.name = ? AND rmp.menu_id = m.id
''', [menuRoute, username, permissionName]);
return (result.first['count'] as int) > 0;
}
// ========== MÉTHODE DE DEBUG ==========
Future<void> close() async {
if (_database.isOpen) {
await _database.close();
}
}
Future<void> printDatabaseInfo() async {
final db = await database;
print("=== INFORMATIONS DE LA BASE DE DONNÉES ===");
// Compter les utilisateurs
final userCount = await getUserCount();
print("Nombre d'utilisateurs: $userCount");
// Lister tous les utilisateurs
final users = await getAllUsers();
print("Utilisateurs:");
for (var user in users) {
print(" - ${user.username} (${user.name} ) - Email: ${user.email}");
}
// Lister tous les rôles
final roles = await getRoles();
print("Rôles:");
for (var role in roles) {
print(" - ${role.designation} (ID: ${role.id})");
}
// Lister toutes les permissions
final permissions = await getAllPermissions();
print("Permissions:");
for (var permission in permissions) {
@ -474,4 +556,47 @@ class AppDatabase {
print("=========================================");
}
Future<List<Permission>> getPermissionsForRoleAndMenu(int roleId, int menuId) async {
final db = await database;
final result = await db.rawQuery('''
SELECT p.id, p.name
FROM permissions p
JOIN role_menu_permissions rmp ON p.id = rmp.permission_id
WHERE rmp.role_id = ? AND rmp.menu_id = ?
ORDER BY p.name ASC
''', [roleId, menuId]);
return result.map((map) => Permission.fromMap(map)).toList();
}
// Ajoutez cette méthode temporaire pour supprimer la DB corrompue
Future<void> deleteDatabaseFile() async {
final documentsDirectory = await getApplicationDocumentsDirectory();
final path = join(documentsDirectory.path, 'app_database.db');
final file = File(path);
if (await file.exists()) {
await file.delete();
print("Base de données supprimée");
}
}
Future<void> assignRoleMenuPermission(int roleId, int menuId, int permissionId) async {
final db = await database;
await db.insert('role_menu_permissions', {
'role_id': roleId,
'menu_id': menuId,
'permission_id': permissionId,
}, conflictAlgorithm: ConflictAlgorithm.ignore);
}
Future<void> removeRoleMenuPermission(int roleId, int menuId, int permissionId) async {
final db = await database;
await db.delete(
'role_menu_permissions',
where: 'role_id = ? AND menu_id = ? AND permission_id = ?',
whereArgs: [roleId, menuId, permissionId],
);
}
}

215
lib/Views/RoleListPage.dart

@ -0,0 +1,215 @@
import 'package:flutter/material.dart';
import 'package:youmazgestion/Components/app_bar.dart';
import 'package:youmazgestion/Models/Permission.dart';
import 'package:youmazgestion/Services/app_database.dart';
import 'package:youmazgestion/Models/role.dart';
import 'package:youmazgestion/Views/RolePermissionPage.dart';
class RoleListPage extends StatefulWidget {
const RoleListPage({super.key});
@override
State<RoleListPage> createState() => _RoleListPageState();
}
class _RoleListPageState extends State<RoleListPage> {
final db = AppDatabase.instance;
final TextEditingController _roleController = TextEditingController();
List<Role> roles = [];
@override
void initState() {
super.initState();
_loadRoles();
}
Future<void> _loadRoles() async {
final roleList = await db.getRoles();
setState(() {
roles = roleList;
});
}
Future<void> _addRole() async {
String designation = _roleController.text.trim();
if (designation.isEmpty) return;
await db.createRole(Role(designation: designation));
_roleController.clear();
await _loadRoles();
}
Future<void> _deleteRole(int roleId) async {
await db.deleteRole(roleId);
await _loadRoles();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const CustomAppBar(title: "Gestion des rôles"),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
// Section d'ajout de rôle
Card(
elevation: 4,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Text(
'Ajouter un nouveau rôle',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 10),
Row(
children: [
Expanded(
child: TextField(
controller: _roleController,
decoration: InputDecoration(
labelText: 'Nom du rôle',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 12, vertical: 12),
),
),
),
const SizedBox(width: 10),
ElevatedButton(
onPressed: _addRole,
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
// padding: const EdgeInsets.symmetric(
// horizontal: 20, vertical: 15),
),
),
child: const Text('Ajouter'),
)
],
),
],
),
),
),
const SizedBox(height: 20),
// Liste des rôles existants
Expanded(
child: Card(
elevation: 4,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Liste des rôles',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 10),
Expanded(
child: roles.isEmpty
? const Center(
child: Text('Aucun rôle créé'),
)
: ListView.builder(
itemCount: roles.length,
itemBuilder: (context, index) {
final role = roles[index];
return Card(
margin: const EdgeInsets.only(bottom: 8),
elevation: 2,
child: ListTile(
title: Text(role.designation),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(Icons.edit,
color: Colors.blue),
onPressed: () {
_navigateToRolePermissions(
context, role);
},
),
IconButton(
icon: const Icon(Icons.delete,
color: Colors.red),
onPressed: () {
_showDeleteDialog(role);
},
),
],
),
onTap: () {
_navigateToRolePermissions(
context, role);
},
),
);
},
),
),
],
),
),
),
),
],
),
),
);
}
void _navigateToRolePermissions(BuildContext context, Role role) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => RolePermissionsPage(role: role),
),
);
}
void _showDeleteDialog(Role role) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Confirmer la suppression'),
content: Text(
'Êtes-vous sûr de vouloir supprimer le rôle "${role.designation}" ?'),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: const Text('Annuler'),
),
TextButton(
onPressed: () async {
Navigator.of(context).pop();
await _deleteRole(role.id!);
},
child: const Text('Supprimer', style: TextStyle(color: Colors.red)),
),
],
);
},
);
}
}

177
lib/Views/RolePermissionPage.dart

@ -0,0 +1,177 @@
import 'package:flutter/material.dart';
import 'package:youmazgestion/Components/app_bar.dart';
import 'package:youmazgestion/Models/Permission.dart';
import 'package:youmazgestion/Services/app_database.dart';
import 'package:youmazgestion/Models/role.dart';
class RolePermissionsPage extends StatefulWidget {
final Role role;
const RolePermissionsPage({super.key, required this.role});
@override
State<RolePermissionsPage> createState() => _RolePermissionsPageState();
}
class _RolePermissionsPageState extends State<RolePermissionsPage> {
final db = AppDatabase.instance;
List<Permission> permissions = [];
List<Map<String, dynamic>> menus = [];
Map<int, Map<String, bool>> menuPermissionsMap = {};
@override
void initState() {
super.initState();
_initData();
}
Future<void> _initData() async {
final perms = await db.getAllPermissions();
final menuList = await db.database.then((db) => db.query('menu'));
Map<int, Map<String, bool>> tempMenuPermissionsMap = {};
for (var menu in menuList) {
final menuId = menu['id'] as int;
final menuPerms = await db.getPermissionsForRoleAndMenu(
widget.role.id!, menuId);
tempMenuPermissionsMap[menuId] = {
for (var perm in perms)
perm.name: menuPerms.any((mp) => mp.name == perm.name)
};
}
setState(() {
permissions = perms;
menus = menuList;
menuPermissionsMap = tempMenuPermissionsMap;
});
}
Future<void> _onPermissionToggle(
int menuId, String permission, bool enabled) async {
final perm = permissions.firstWhere((p) => p.name == permission);
if (enabled) {
await db.assignRoleMenuPermission(
widget.role.id!, menuId, perm.id!);
} else {
await db.removeRoleMenuPermission(
widget.role.id!, menuId, perm.id!);
}
setState(() {
menuPermissionsMap[menuId]![permission] = enabled;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(
title: "Permissions - ${widget.role.designation}",
// showBackButton: true,
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Gestion des permissions pour le rôle: ${widget.role.designation}',
style: Theme.of(context).textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 10),
const Text(
'Sélectionnez les permissions pour chaque menu:',
style: TextStyle(fontSize: 14, color: Colors.grey),
),
const SizedBox(height: 20),
if (permissions.isNotEmpty && menus.isNotEmpty)
Expanded(
child: ListView.builder(
itemCount: menus.length,
itemBuilder: (context, index) {
final menu = menus[index];
final menuId = menu['id'] as int;
final menuName = menu['name'] as String;
return Card(
margin: const EdgeInsets.only(bottom: 15),
elevation: 3,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
menuName,
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 16),
),
const SizedBox(height: 8),
Wrap(
spacing: 10,
runSpacing: 10,
children: permissions.map((perm) {
final isChecked = menuPermissionsMap[menuId]?[perm.name] ?? false;
return FilterChip(
label: perm.name,
selected: isChecked,
onSelected: (bool value) {
_onPermissionToggle(menuId, perm.name, value);
},
);
}).toList(),
),
],
),
),
);
},
),
)
else
const Expanded(
child: Center(
child: CircularProgressIndicator(),
),
),
],
),
),
);
}
}
class FilterChip extends StatelessWidget {
final String label;
final bool selected;
final ValueChanged<bool> onSelected;
const FilterChip({
super.key,
required this.label,
required this.selected,
required this.onSelected,
});
@override
Widget build(BuildContext context) {
return ChoiceChip(
label: Text(label),
selected: selected,
onSelected: onSelected,
selectedColor: Colors.blue,
labelStyle: TextStyle(
color: selected ? Colors.white : Colors.black,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
);
}
}

64
lib/Views/gestionRole.dart

@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:youmazgestion/Components/app_bar.dart';
import 'package:youmazgestion/Models/Permission.dart';
import 'package:youmazgestion/Services/app_database.dart';
import 'package:youmazgestion/Models/role.dart';
@ -13,9 +14,10 @@ class HandleUserRole extends StatefulWidget {
class _HandleUserRoleState extends State<HandleUserRole> {
final db = AppDatabase.instance;
List<Map<String, dynamic>> roles = [];
List<dynamic> permissions = [];
Map<int, Map<String, bool>> rolePermissionsMap = {};
List<Role> roles = [];
List<Permission> permissions = [];
List<Map<String, dynamic>> menus = [];
Map<int, Map<int, Map<String, bool>>> roleMenuPermissionsMap = {};
final TextEditingController _roleController = TextEditingController();
@ -26,25 +28,32 @@ class _HandleUserRoleState extends State<HandleUserRole> {
}
Future<void> _initData() async {
final roleList = await db.database.then((db) => db.query('roles'));
final roleList = await db.getRoles();
final perms = await db.getAllPermissions();
final menuList = await db.database.then((db) => db.query('menu'));
Map<int, Map<String, bool>> tempRolePermissionsMap = {};
Map<int, Map<int, Map<String, bool>>> tempRoleMenuPermissionsMap = {};
for (var role in roleList) {
final roleId = role['id'] as int;
final rolePerms = await db.getPermissionsForRole(roleId);
final roleId = role.id!;
tempRoleMenuPermissionsMap[roleId] = {};
tempRolePermissionsMap[roleId] = {
for (var menu in menuList) {
final menuId = menu['id'] as int;
final menuPerms = await db.getPermissionsForRoleAndMenu(roleId, menuId);
tempRoleMenuPermissionsMap[roleId]![menuId] = {
for (var perm in perms)
perm.name: rolePerms.any((rp) => rp.name == perm.name)
perm.name: menuPerms.any((mp) => mp.name == perm.name)
};
}
}
setState(() {
roles = roleList;
permissions = perms;
rolePermissionsMap = tempRolePermissionsMap;
menus = menuList;
roleMenuPermissionsMap = tempRoleMenuPermissionsMap;
});
}
@ -57,17 +66,17 @@ class _HandleUserRoleState extends State<HandleUserRole> {
await _initData();
}
Future<void> _onPermissionToggle(int roleId, String permission, bool enabled) async {
Future<void> _onPermissionToggle(int roleId, int menuId, String permission, bool enabled) async {
final perm = permissions.firstWhere((p) => p.name == permission);
if (enabled) {
await db.assignPermission(roleId, perm.id!);
await db.assignRoleMenuPermission(roleId, menuId, perm.id!);
} else {
await db.removePermission(roleId, perm.id!);
await db.removeRoleMenuPermission(roleId, menuId, perm.id!);
}
setState(() {
rolePermissionsMap[roleId]![permission] = enabled;
roleMenuPermissionsMap[roleId]![menuId]![permission] = enabled;
});
}
@ -117,7 +126,7 @@ class _HandleUserRoleState extends State<HandleUserRole> {
),
const SizedBox(height: 20),
// Tableau des rôles et permissions
if (roles.isNotEmpty && permissions.isNotEmpty)
if (roles.isNotEmpty && permissions.isNotEmpty && menus.isNotEmpty)
Expanded(
child: Card(
elevation: 6,
@ -132,7 +141,16 @@ class _HandleUserRoleState extends State<HandleUserRole> {
constraints: BoxConstraints(
minWidth: MediaQuery.of(context).size.width - 32,
),
child: DataTable(
child: Column(
children: menus.map((menu) {
final menuId = menu['id'] as int;
return Column(
children: [
Text(
menu['name'],
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
),
DataTable(
columnSpacing: 20,
columns: [
const DataColumn(
@ -149,17 +167,17 @@ class _HandleUserRoleState extends State<HandleUserRole> {
)).toList(),
],
rows: roles.map((role) {
final roleId = role['id'] as int;
final roleId = role.id!;
return DataRow(
cells: [
DataCell(Text(role['designation'] ?? '')),
DataCell(Text(role.designation)),
...permissions.map((perm) {
final isChecked = rolePermissionsMap[roleId]?[perm.name] ?? false;
final isChecked = roleMenuPermissionsMap[roleId]?[menuId]?[perm.name] ?? false;
return DataCell(
Checkbox(
value: isChecked,
onChanged: (bool? value) {
_onPermissionToggle(roleId, perm.name, value ?? false);
_onPermissionToggle(roleId, menuId, perm.name, value ?? false);
},
),
);
@ -168,6 +186,10 @@ class _HandleUserRoleState extends State<HandleUserRole> {
);
}).toList(),
),
],
);
}).toList(),
),
),
),
),
@ -176,7 +198,7 @@ class _HandleUserRoleState extends State<HandleUserRole> {
else
const Expanded(
child: Center(
child: Text('Aucun rôle ou permission trouvé'),
child: Text('Aucun rôle, permission ou menu trouvé'),
),
),
],

2
lib/Views/loginPage.dart

@ -129,7 +129,7 @@ class _LoginPageState extends State<LoginPage> {
print('ID: ${userCredentials['id']}');
// Sauvegarder dans le contrôleur
userController.setUser(user);
// userController.setUser(user);
// Sauvegarder dans SharedPreferences
await saveUser(

93
lib/controller/userController.dart

@ -1,4 +1,5 @@
import 'package:get/get.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:youmazgestion/Models/users.dart';
import 'package:youmazgestion/Services/app_database.dart';
@ -17,9 +18,33 @@ class UserController extends GetxController {
String get lastname => _lastname.value;
String get password => _password.value;
@override
void onInit() {
super.onInit();
loadUserData(); // Charger les données au démarrage
}
// Charger les données depuis SharedPreferences
Future<void> loadUserData() async {
try {
final prefs = await SharedPreferences.getInstance();
_username.value = prefs.getString('username') ?? '';
_email.value = prefs.getString('email') ?? '';
_role.value = prefs.getString('role') ?? '';
_name.value = prefs.getString('name') ?? '';
_lastname.value = prefs.getString('lastname') ?? '';
print("Données chargées - Username: ${_username.value}");
print("Role: ${_role.value}");
} catch (e) {
print('Erreur lors du chargement des données utilisateur: $e');
}
}
void setUser(Users user) {
_username.value = user.username;
print(_username.value);
print("username " + _username.value);
_email.value = user.email;
print(_email.value);
_role.value = user.role;
@ -30,19 +55,73 @@ class UserController extends GetxController {
print(_lastname.value);
_password.value = user.password;
print(_password.value);
// Sauvegarder dans SharedPreferences
saveUserData();
}
// Sauvegarder les données dans SharedPreferences
Future<void> saveUserData() async {
try {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('username', _username.value);
await prefs.setString('email', _email.value);
await prefs.setString('role', _role.value);
await prefs.setString('name', _name.value);
await prefs.setString('lastname', _lastname.value);
print("Données sauvegardées avec succès");
} catch (e) {
print('Erreur lors de la sauvegarde des données utilisateur: $e');
}
}
// Méthode pour vider les données utilisateur
Future<void> clearUserData() async {
try {
final prefs = await SharedPreferences.getInstance();
await prefs.remove('username');
await prefs.remove('email');
await prefs.remove('role');
await prefs.remove('name');
await prefs.remove('lastname');
// Vider les variables observables
_username.value = '';
_email.value = '';
_role.value = '';
_name.value = '';
_lastname.value = '';
_password.value = '';
print("Données utilisateur effacées");
} catch (e) {
print('Erreur lors de l\'effacement des données utilisateur: $e');
}
}
Future<bool> hasPermission(String permission, String route) async {
try {
if (_username.value.isEmpty) {
print('Username vide, rechargement des données...');
await loadUserData();
}
Future<bool> hasPermission(String permissionName) async {
// Utilisez votre instance de AppDatabase pour vérifier la permission
return await AppDatabase.instance.hasPermission(username, permissionName);
return await AppDatabase.instance.hasPermission(username, permission, route);
} catch (e) {
print('Erreur vérification permission: $e');
return false; // Sécurité : refuser l'accès en cas d'erreur
}
Future<bool> hasAnyPermission(List<String> permissionNames) async {
}
Future<bool> hasAnyPermission(List<String> permissionNames, String menuRoute) async {
for (String permissionName in permissionNames) {
if (await hasPermission(permissionName)) {
if (await hasPermission(permissionName, menuRoute)) {
return true;
}
}
return false;
}
}

5
lib/main.dart

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:youmazgestion/Services/app_database.dart';
import 'package:youmazgestion/controller/userController.dart';
import 'Services/productDatabase.dart';
import 'my_app.dart';
import 'package:logging/logging.dart';
@ -10,12 +11,14 @@ void main() async {
try {
// Initialiser les bases de données une seule fois
// await AppDatabase.instance.deleteDatabaseFile();
await ProductDatabase.instance.initDatabase();
await AppDatabase.instance.initDatabase();
// Afficher les informations de la base (pour debug)
await AppDatabase.instance.printDatabaseInfo();
Get.put(UserController()); // Ajoute ce code AVANT tout accès au UserController
setupLogger();
runApp(const GetMaterialApp(

Loading…
Cancel
Save