You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

477 lines
15 KiB

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<Database> get database async {
if (_database.isOpen) return _database;
_database = await _initDB('app_database.db');
return _database;
}
Future<void> initDatabase() async {
_database = await _initDB('app_database.db');
await _createDB(_database, 1);
await insertDefaultPermissions();
await insertDefaultRoles();
await insertDefaultSuperAdmin();
}
Future<Database> _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<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');
}
}
return await databaseFactoryFfi.openDatabase(path);
}
Future<void> _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<void> 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<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');
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<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
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<int> createUser(Users user) async {
final db = await database;
return await db.insert('users', user.toMap());
}
Future<int> deleteUser(int id) async {
final db = await database;
return await db.delete('users', where: 'id = ?', whereArgs: [id]);
}
Future<int> updateUser(Users user) async {
final db = await database;
return await db.update('users', user.toMap(), where: 'id = ?', whereArgs: [user.id]);
}
Future<int> getUserCount() async {
final db = await database;
List<Map<String, dynamic>> result = await db.rawQuery('SELECT COUNT(*) as count FROM users');
return result.first['count'] as int;
}
Future<bool> 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<Users> 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<Map<String, dynamic>?> 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<List<Users>> 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<int> createRole(Role role) async {
final db = await database;
return await db.insert('roles', role.toMap());
}
Future<List<Role>> 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<int> updateRole(Role role) async {
final db = await database;
return await db.update(
'roles',
role.toMap(),
where: 'id = ?',
whereArgs: [role.id],
);
}
Future<int> deleteRole(int? id) async {
final db = await database;
return await db.delete(
'roles',
where: 'id = ?',
whereArgs: [id],
);
}
// ========== GESTION DES PERMISSIONS ==========
Future<List<Permission>> getAllPermissions() async {
final db = await database;
final result = await db.query('permissions', orderBy: 'name ASC');
return result.map((e) => Permission.fromMap(e)).toList();
}
Future<List<Permission>> 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<List<Permission>> 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<void> 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<void> 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<bool> 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<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},
where: 'username = ?',
whereArgs: [username],
);
}
// ========== UTILITAIRES ==========
Future<void> close() async {
if (_database.isOpen) {
await _database.close();
}
}
Future<bool> 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<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) {
print(" - ${permission.name} (ID: ${permission.id})");
}
print("=========================================");
}
}