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 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) { // Optionnel : copier depuis assets si vous avez une DB pré-remplie 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) { // 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'); } } 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(); // Table des rôles 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."); } // Table des permissions 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."); } // Table de liaison role_permissions 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."); } // Table des utilisateurs 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."); } } // ========== INSERTION DES DONNÉES PAR DÉFAUT ========== 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'}); print("Permissions par défaut insérées"); } } Future 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'); for (var permission in permissions) { await db.insert('role_permissions', { 'role_id': superAdminRoleId, 'permission_id': permission['id'], }); } // Assigner quelques permissions à l'Admin 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', { 'role_id': adminRoleId, 'permission_id': viewPermission.first['id'], }); } if (createPermission.isNotEmpty) { await db.insert('role_permissions', { 'role_id': adminRoleId, 'permission_id': createPermission.first['id'], }); } if (updatePermission.isNotEmpty) { await db.insert('role_permissions', { 'role_id': adminRoleId, '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"); } } Future 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 WHERE r.designation = 'Super Admin' '''); if (existingSuperAdmin.isEmpty) { // Récupérer l'ID du rôle Super Admin final superAdminRole = await db.query('roles', where: 'designation = ?', whereArgs: ['Super Admin'] ); 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 ! '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à"); } } // ========== GESTION DES UTILISATEURS ========== 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(); } // ========== GESTION DES RÔLES ========== 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], ); } // ========== GESTION DES PERMISSIONS ========== 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], ); } // ========== MÉTHODES UTILITAIRES POUR LA SÉCURITÉ ========== 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; // 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}, where: 'username = ?', whereArgs: [username], ); } // ========== UTILITAIRES ========== Future close() async { if (_database.isOpen) { await _database.close(); } } Future hasPermission(String username, String permissionName) 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 users u ON u.role_id = r.id WHERE u.username = ? AND p.name = ? ''', [username, permissionName]); return (result.first['count'] as int) > 0; } // ========== MÉTHODE DE DEBUG ========== Future 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) { print(" - ${permission.name} (ID: ${permission.id})"); } print("========================================="); } }