import 'dart:async'; import 'dart:io'; import 'package:flutter/services.dart'; import 'package:path/path.dart'; import 'package:path_provider/path_provider.dart'; import 'package:sqflite_common_ffi/sqflite_ffi.dart'; import '../Models/users.dart'; import '../Models/role.dart'; import '../Models/Permission.dart'; class AppDatabase { static final AppDatabase instance = AppDatabase._init(); late Database _database; AppDatabase._init() { sqfliteFfiInit(); } Future get database async { if (_database.isOpen) return _database; _database = await _initDB('app_database.db'); return _database; } Future initDatabase() async { _database = await _initDB('app_database.db'); await _createDB(_database, 1); await insertDefaultPermissions(); await insertDefaultMenus(); await insertDefaultRoles(); await insertDefaultSuperAdmin(); } Future _initDB(String filePath) async { final documentsDirectory = await getApplicationDocumentsDirectory(); final path = join(documentsDirectory.path, filePath); bool dbExists = await File(path).exists(); if (!dbExists) { try { ByteData data = await rootBundle.load('assets/database/$filePath'); List bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes); await File(path).writeAsBytes(bytes); } catch (e) { print('Pas de fichier DB dans assets, création d\'une nouvelle DB'); } } return await databaseFactoryFfi.openDatabase(path); } Future _createDB(Database db, int version) async { final tables = await db.rawQuery("SELECT name FROM sqlite_master WHERE type='table'"); final tableNames = tables.map((row) => row['name'] as String).toList(); if (!tableNames.contains('roles')) { await db.execute(''' CREATE TABLE roles ( id INTEGER PRIMARY KEY AUTOINCREMENT, designation TEXT NOT NULL UNIQUE ) '''); print("Table 'roles' créée."); } if (!tableNames.contains('permissions')) { await db.execute(''' CREATE TABLE permissions ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL UNIQUE ) '''); print("Table 'permissions' créée."); } 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 ( role_id INTEGER, permission_id INTEGER, PRIMARY KEY (role_id, permission_id), FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE, FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE ) '''); print("Table 'role_permissions' créée."); } 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 ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, lastname TEXT NOT NULL, email TEXT NOT NULL UNIQUE, password TEXT NOT NULL, username TEXT NOT NULL UNIQUE, role_id INTEGER NOT NULL, FOREIGN KEY (role_id) REFERENCES roles(id) ) '''); 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."); } } Future insertDefaultPermissions() async { final db = await database; final existing = await db.query('permissions'); if (existing.isEmpty) { await db.insert('permissions', {'name': 'view'}); await db.insert('permissions', {'name': 'create'}); await db.insert('permissions', {'name': 'update'}); await db.insert('permissions', {'name': 'delete'}); await db.insert('permissions', {'name': 'admin'}); await db.insert('permissions', {'name': 'manage'}); // Nouvelle permission await db.insert('permissions', {'name': 'read'}); // Nouvelle permission print("Permissions par défaut insérées"); } else { // Vérifier et ajouter les nouvelles permissions si elles n'existent pas final newPermissions = ['manage', 'read']; for (var permission in newPermissions) { final existingPermission = await db.query('permissions', where: 'name = ?', whereArgs: [permission]); if (existingPermission.isEmpty) { await db.insert('permissions', {'name': permission}); print("Permission ajoutée: $permission"); } } } } Future insertDefaultMenus() async { final db = await database; final existingMenus = await db.query('menu'); if (existingMenus.isEmpty) { // Menus existants 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'}); // Nouveaux menus ajoutés await db.insert('menu', {'name': 'Nouvelle commande', 'route': '/nouvelle-commande'}); await db.insert('menu', {'name': 'Gérer les commandes', 'route': '/gerer-commandes'}); print("Menus par défaut insérés"); } else { // Si des menus existent déjà, vérifier et ajouter les nouveaux menus manquants await _addMissingMenus(db); } } Future _addMissingMenus(Database db) async { final menusToAdd = [ {'name': 'Nouvelle commande', 'route': '/nouvelle-commande'}, {'name': 'Gérer les commandes', 'route': '/gerer-commandes'}, ]; for (var menu in menusToAdd) { final existing = await db.query( 'menu', where: 'route = ?', whereArgs: [menu['route']], ); if (existing.isEmpty) { await db.insert('menu', menu); print("Menu ajouté: ${menu['name']}"); } } } Future insertDefaultRoles() async { final db = await database; final existingRoles = await db.query('roles'); if (existingRoles.isEmpty) { int superAdminRoleId = await db.insert('roles', {'designation': 'Super Admin'}); int adminRoleId = await db.insert('roles', {'designation': 'Admin'}); int userRoleId = await db.insert('roles', {'designation': 'User'}); 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_menu_permissions', { 'role_id': superAdminRoleId, 'menu_id': menu['id'], 'permission_id': permission['id'], }, conflictAlgorithm: ConflictAlgorithm.ignore ); } } // Assigner quelques permissions à l'Admin et à l'User pour les nouveaux menus await _assignBasicPermissionsToRoles(db, adminRoleId, userRoleId); 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 await _updateExistingRolePermissions(db); } } // Nouvelle méthode pour assigner les permissions de base aux nouveaux menus Future _assignBasicPermissionsToRoles(Database db, int adminRoleId, int userRoleId) async { 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']); final managePermission = await db.query('permissions', where: 'name = ?', whereArgs: ['manage']); // Récupérer les IDs des nouveaux menus final nouvelleCommandeMenu = await db.query('menu', where: 'route = ?', whereArgs: ['/nouvelle-commande']); final gererCommandesMenu = await db.query('menu', where: 'route = ?', whereArgs: ['/gerer-commandes']); if (nouvelleCommandeMenu.isNotEmpty && createPermission.isNotEmpty) { // Admin peut créer de nouvelles commandes await db.insert('role_menu_permissions', { 'role_id': adminRoleId, 'menu_id': nouvelleCommandeMenu.first['id'], 'permission_id': createPermission.first['id'], }, conflictAlgorithm: ConflictAlgorithm.ignore ); // User peut aussi créer de nouvelles commandes await db.insert('role_menu_permissions', { 'role_id': userRoleId, 'menu_id': nouvelleCommandeMenu.first['id'], 'permission_id': createPermission.first['id'], }, conflictAlgorithm: ConflictAlgorithm.ignore ); } if (gererCommandesMenu.isNotEmpty && managePermission.isNotEmpty) { // Admin peut gérer les commandes await db.insert('role_menu_permissions', { 'role_id': adminRoleId, 'menu_id': gererCommandesMenu.first['id'], 'permission_id': managePermission.first['id'], }, conflictAlgorithm: ConflictAlgorithm.ignore ); } if (gererCommandesMenu.isNotEmpty && viewPermission.isNotEmpty) { // User peut voir les commandes await db.insert('role_menu_permissions', { 'role_id': userRoleId, 'menu_id': gererCommandesMenu.first['id'], 'permission_id': viewPermission.first['id'], } , conflictAlgorithm: ConflictAlgorithm.ignore ); } } Future _updateExistingRolePermissions(Database db) async { 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 sur tous les menus 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'], }, conflictAlgorithm: ConflictAlgorithm.ignore ); } } } // Assigner les permissions de base aux autres rôles pour les nouveaux menus final adminRole = await db.query('roles', where: 'designation = ?', whereArgs: ['Admin']); final userRole = await db.query('roles', where: 'designation = ?', whereArgs: ['User']); if (adminRole.isNotEmpty && userRole.isNotEmpty) { await _assignBasicPermissionsToRoles(db, adminRole.first['id'] as int, userRole.first['id'] as int); } print("Permissions mises à jour pour tous les rôles"); } } Future insertDefaultSuperAdmin() async { final db = await database; final existingSuperAdmin = await db.rawQuery(''' SELECT u.* FROM users u INNER JOIN roles r ON u.role_id = r.id WHERE r.designation = 'Super Admin' '''); if (existingSuperAdmin.isEmpty) { final superAdminRole = await db.query('roles', where: 'designation = ?', whereArgs: ['Super Admin'] ); if (superAdminRole.isNotEmpty) { final superAdminRoleId = superAdminRole.first['id'] as int; await db.insert('users', { 'name': 'Super', 'lastname': 'Admin', 'email': 'superadmin@youmazgestion.com', 'password': 'admin123', 'username': 'superadmin', 'role_id': superAdminRoleId, }); print("Super Admin créé avec succès !"); print("Username: superadmin"); print("Password: admin123"); print("ATTENTION: Changez ce mot de passe après la première connexion !"); } } else { print("Super Admin existe déjà"); } } Future createUser(Users user) async { final db = await database; return await db.insert('users', user.toMap()); } Future deleteUser(int id) async { final db = await database; return await db.delete('users', where: 'id = ?', whereArgs: [id]); } Future updateUser(Users user) async { final db = await database; return await db.update('users', user.toMap(), where: 'id = ?', whereArgs: [user.id]); } Future getUserCount() async { final db = await database; List> result = await db.rawQuery('SELECT COUNT(*) as count FROM users'); return result.first['count'] as int; } Future verifyUser(String username, String password) async { final db = await database; final result = await db.rawQuery(''' SELECT users.id FROM users WHERE users.username = ? AND users.password = ? ''', [username, password]); return result.isNotEmpty; } Future getUser(String username) async { final db = await database; final result = await db.rawQuery(''' SELECT users.*, roles.designation as role_name FROM users INNER JOIN roles ON users.role_id = roles.id WHERE users.username = ? ''', [username]); if (result.isNotEmpty) { return Users.fromMap(result.first); } else { throw Exception('User not found'); } } Future?> getUserCredentials(String username, String password) async { final db = await database; final result = await db.rawQuery(''' SELECT users.username, users.id, roles.designation as role_name, roles.id as role_id FROM users INNER JOIN roles ON users.role_id = roles.id WHERE username = ? AND password = ? ''', [username, password]); if (result.isNotEmpty) { return { 'id': result.first['id'], 'username': result.first['username'] as String, 'role': result.first['role_name'] as String, 'role_id': result.first['role_id'], }; } else { return null; } } Future> getAllUsers() async { final db = await database; final result = await db.rawQuery(''' SELECT users.*, roles.designation as role_name FROM users INNER JOIN roles ON users.role_id = roles.id ORDER BY users.id ASC '''); return result.map((json) => Users.fromMap(json)).toList(); } Future createRole(Role role) async { final db = await database; return await db.insert('roles', role.toMap()); } Future> getRoles() async { final db = await database; final maps = await db.query('roles', orderBy: 'designation ASC'); return List.generate(maps.length, (i) => Role.fromMap(maps[i])); } Future updateRole(Role role) async { final db = await database; return await db.update( 'roles', role.toMap(), where: 'id = ?', whereArgs: [role.id], ); } Future deleteRole(int? id) async { final db = await database; return await db.delete( 'roles', where: 'id = ?', whereArgs: [id], ); } Future> getAllPermissions() async { final db = await database; final result = await db.query('permissions', orderBy: 'name ASC'); return result.map((e) => Permission.fromMap(e)).toList(); } Future> getPermissionsForRole(int roleId) async { final db = await database; final result = await db.rawQuery(''' SELECT p.id, p.name FROM permissions p JOIN role_permissions rp ON p.id = rp.permission_id WHERE rp.role_id = ? ORDER BY p.name ASC ''', [roleId]); return result.map((map) => Permission.fromMap(map)).toList(); } Future> getPermissionsForUser(String username) async { final db = await database; final result = await db.rawQuery(''' SELECT DISTINCT p.id, p.name FROM permissions p JOIN role_permissions rp ON p.id = rp.permission_id JOIN roles r ON rp.role_id = r.id JOIN users u ON u.role_id = r.id WHERE u.username = ? ORDER BY p.name ASC ''', [username]); return result.map((map) => Permission.fromMap(map)).toList(); } Future assignPermission(int roleId, int permissionId) async { final db = await database; await db.insert('role_permissions', { 'role_id': roleId, 'permission_id': permissionId, }, conflictAlgorithm: ConflictAlgorithm.ignore); } Future removePermission(int roleId, int permissionId) async { final db = await database; await db.delete( 'role_permissions', where: 'role_id = ? AND permission_id = ?', whereArgs: [roleId, permissionId], ); } Future 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 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 isSuperAdmin(String username) async { final db = await database; final result = await db.rawQuery(''' SELECT COUNT(*) as count FROM users u INNER JOIN roles r ON u.role_id = r.id WHERE u.username = ? AND r.designation = 'Super Admin' ''', [username]); return (result.first['count'] as int) > 0; } Future changePassword(String username, String oldPassword, String newPassword) async { final db = await database; final isValidOldPassword = await verifyUser(username, oldPassword); if (!isValidOldPassword) { throw Exception('Ancien mot de passe incorrect'); } await db.update( 'users', {'password': newPassword}, where: 'username = ?', whereArgs: [username], ); } Future 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_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 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; } Future close() async { if (_database.isOpen) { await _database.close(); } } Future printDatabaseInfo() async { final db = await database; print("=== INFORMATIONS DE LA BASE DE DONNÉES ==="); final userCount = await getUserCount(); print("Nombre d'utilisateurs: $userCount"); final users = await getAllUsers(); print("Utilisateurs:"); for (var user in users) { print(" - ${user.username} (${user.name} ) - Email: ${user.email}"); } final roles = await getRoles(); print("Rôles:"); for (var role in roles) { print(" - ${role.designation} (ID: ${role.id})"); } final permissions = await getAllPermissions(); print("Permissions:"); for (var permission in permissions) { print(" - ${permission.name} (ID: ${permission.id})"); } print("========================================="); } Future> 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 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 utilisateur supprimée"); } } Future 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 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], ); } }