- Ajout système complet de gestion des secteurs avec contours géographiques - Import des contours départementaux depuis GeoJSON - API REST pour la gestion des secteurs (/api/sectors) - Service de géolocalisation pour déterminer les secteurs - Migration base de données avec tables x_departements_contours et sectors_adresses - Interface Flutter pour visualisation et gestion des secteurs - Ajout thème sombre dans l'application - Corrections diverses et optimisations 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
790 lines
28 KiB
PHP
Executable File
790 lines
28 KiB
PHP
Executable File
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Controllers;
|
|
|
|
require_once __DIR__ . '/../Services/LogService.php';
|
|
require_once __DIR__ . '/../Services/ApiService.php';
|
|
|
|
use PDO;
|
|
use PDOException;
|
|
use Database;
|
|
use AppConfig;
|
|
use Request;
|
|
use Response;
|
|
use Session;
|
|
use LogService;
|
|
use ApiService;
|
|
|
|
class UserController {
|
|
private PDO $db;
|
|
private AppConfig $appConfig;
|
|
|
|
public function __construct() {
|
|
$this->db = Database::getInstance();
|
|
$this->appConfig = AppConfig::getInstance();
|
|
}
|
|
|
|
public function getUsers(): void {
|
|
Session::requireAuth();
|
|
|
|
// Vérification des droits d'accès (rôle administrateur)
|
|
// Récupérer le rôle de l'utilisateur depuis la base de données
|
|
$userId = Session::getUserId();
|
|
$stmt = $this->db->prepare('SELECT fk_role FROM users WHERE id = ?');
|
|
$stmt->execute([$userId]);
|
|
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
$userRole = $result ? $result['fk_role'] : null;
|
|
|
|
if ($userRole != '1' && $userRole != '2') { // Supposons que 1 et 2 sont des rôles admin
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Accès non autorisé'
|
|
], 403);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
$stmt = $this->db->prepare('
|
|
SELECT
|
|
u.id,
|
|
u.encrypted_email,
|
|
u.encrypted_name,
|
|
u.first_name,
|
|
u.fk_role as role,
|
|
u.fk_entite,
|
|
u.chk_active,
|
|
u.created_at,
|
|
u.updated_at,
|
|
e.encrypted_name as entite_name
|
|
FROM users u
|
|
LEFT JOIN entites e ON u.fk_entite = e.id
|
|
ORDER BY u.created_at DESC
|
|
');
|
|
$stmt->execute();
|
|
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
// Déchiffrement des données sensibles pour chaque utilisateur
|
|
foreach ($users as &$user) {
|
|
$user['email'] = ApiService::decryptSearchableData($user['encrypted_email']);
|
|
$user['name'] = ApiService::decryptData($user['encrypted_name']);
|
|
|
|
if (!empty($user['entite_name'])) {
|
|
$user['entite_name'] = ApiService::decryptData($user['entite_name']);
|
|
}
|
|
|
|
// Suppression des champs chiffrés
|
|
unset($user['encrypted_email']);
|
|
unset($user['encrypted_name']);
|
|
}
|
|
|
|
Response::json([
|
|
'status' => 'success',
|
|
'users' => $users
|
|
]);
|
|
} catch (PDOException $e) {
|
|
LogService::log('Erreur lors de la récupération des utilisateurs GeoSector', [
|
|
'level' => 'error',
|
|
'error' => $e->getMessage()
|
|
]);
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Erreur serveur'
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
public function getUserById(string $id): void {
|
|
Session::requireAuth();
|
|
|
|
// Vérification des droits d'accès (rôle administrateur ou utilisateur lui-même)
|
|
$currentUserId = Session::getUserId();
|
|
|
|
// Récupérer le rôle de l'utilisateur depuis la base de données
|
|
$stmt = $this->db->prepare('SELECT fk_role FROM users WHERE id = ?');
|
|
$stmt->execute([$currentUserId]);
|
|
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
$userRole = $result ? $result['fk_role'] : null;
|
|
|
|
if ($userRole != '1' && $userRole != '2' && $currentUserId != $id) {
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Accès non autorisé'
|
|
], 403);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
$stmt = $this->db->prepare('
|
|
SELECT
|
|
u.id,
|
|
u.encrypted_email,
|
|
u.encrypted_name,
|
|
u.first_name,
|
|
u.sect_name,
|
|
u.encrypted_phone,
|
|
u.encrypted_mobile,
|
|
u.fk_role as role,
|
|
u.fk_entite,
|
|
u.chk_alert_email,
|
|
u.chk_suivi,
|
|
u.date_naissance,
|
|
u.date_embauche,
|
|
u.chk_active,
|
|
u.created_at,
|
|
u.updated_at,
|
|
e.encrypted_name as entite_name,
|
|
e.adresse1,
|
|
e.adresse2,
|
|
e.cp,
|
|
e.ville,
|
|
e.fk_region
|
|
FROM users u
|
|
LEFT JOIN entites e ON u.fk_entite = e.id
|
|
WHERE u.id = ?
|
|
');
|
|
$stmt->execute([$id]);
|
|
$user = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$user) {
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Utilisateur non trouvé'
|
|
], 404);
|
|
return;
|
|
}
|
|
|
|
// Déchiffrement des données sensibles
|
|
$user['email'] = ApiService::decryptSearchableData($user['encrypted_email']);
|
|
$user['name'] = ApiService::decryptData($user['encrypted_name']);
|
|
$user['phone'] = ApiService::decryptData($user['encrypted_phone'] ?? '');
|
|
$user['mobile'] = ApiService::decryptData($user['encrypted_mobile'] ?? '');
|
|
|
|
if (!empty($user['entite_name'])) {
|
|
$user['entite_name'] = ApiService::decryptData($user['entite_name']);
|
|
}
|
|
|
|
// Suppression des champs chiffrés
|
|
unset($user['encrypted_email']);
|
|
unset($user['encrypted_name']);
|
|
unset($user['encrypted_phone']);
|
|
unset($user['encrypted_mobile']);
|
|
|
|
Response::json([
|
|
'status' => 'success',
|
|
'user' => $user
|
|
]);
|
|
} catch (PDOException $e) {
|
|
LogService::log('Erreur lors de la récupération de l\'utilisateur GeoSector', [
|
|
'level' => 'error',
|
|
'error' => $e->getMessage(),
|
|
'userId' => $id
|
|
]);
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Erreur serveur'
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
public function createUser(): void {
|
|
Session::requireAuth();
|
|
|
|
// Vérification des droits d'accès (rôle administrateur)
|
|
$currentUserId = Session::getUserId();
|
|
|
|
// Récupérer le rôle de l'utilisateur depuis la base de données
|
|
$stmt = $this->db->prepare('SELECT fk_role FROM users WHERE id = ?');
|
|
$stmt->execute([$currentUserId]);
|
|
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
$userRole = $result ? $result['fk_role'] : null;
|
|
|
|
if ($userRole != '1' && $userRole != '2') {
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Accès non autorisé'
|
|
], 403);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
$data = Request::getJson();
|
|
$currentUserId = Session::getUserId();
|
|
|
|
// Validation des données requises
|
|
if (!isset($data['email'], $data['name'])) {
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Email et nom requis'
|
|
], 400);
|
|
return;
|
|
}
|
|
|
|
$email = trim(strtolower($data['email']));
|
|
$name = trim($data['name']);
|
|
$firstName = isset($data['first_name']) ? trim($data['first_name']) : '';
|
|
$role = isset($data['role']) ? (int)$data['role'] : 1;
|
|
$entiteId = isset($data['fk_entite']) ? (int)$data['fk_entite'] : 1;
|
|
|
|
// Vérification des longueurs d'entrée
|
|
if (strlen($email) > 75 || strlen($name) > 50) {
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Email ou nom trop long'
|
|
], 400);
|
|
return;
|
|
}
|
|
|
|
// Validation de l'email
|
|
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Format d\'email invalide'
|
|
], 400);
|
|
return;
|
|
}
|
|
|
|
// Chiffrement des données sensibles
|
|
$encryptedEmail = ApiService::encryptSearchableData($email);
|
|
$encryptedName = ApiService::encryptData($name);
|
|
|
|
// Vérification de l'existence de l'email
|
|
$checkStmt = $this->db->prepare('SELECT id FROM users WHERE encrypted_email = ?');
|
|
$checkStmt->execute([$encryptedEmail]);
|
|
if ($checkStmt->fetch()) {
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Cet email est déjà utilisé'
|
|
], 409);
|
|
return;
|
|
}
|
|
|
|
// Génération du mot de passe
|
|
$password = ApiService::generateSecurePassword();
|
|
$passwordHash = password_hash($password, PASSWORD_DEFAULT);
|
|
|
|
// Préparation des champs optionnels
|
|
$phone = isset($data['phone']) ? ApiService::encryptData(trim($data['phone'])) : null;
|
|
$mobile = isset($data['mobile']) ? ApiService::encryptData(trim($data['mobile'])) : null;
|
|
$sectName = isset($data['sect_name']) ? trim($data['sect_name']) : '';
|
|
$alertEmail = isset($data['chk_alert_email']) ? (int)$data['chk_alert_email'] : 1;
|
|
$suivi = isset($data['chk_suivi']) ? (int)$data['chk_suivi'] : 0;
|
|
$dateNaissance = isset($data['date_naissance']) ? $data['date_naissance'] : null;
|
|
$dateEmbauche = isset($data['date_embauche']) ? $data['date_embauche'] : null;
|
|
|
|
// Insertion en base de données
|
|
$stmt = $this->db->prepare('
|
|
INSERT INTO users (
|
|
encrypted_email, user_pass_hash, encrypted_name, first_name,
|
|
sect_name, encrypted_phone, encrypted_mobile, fk_role,
|
|
fk_entite, chk_alert_email, chk_suivi,
|
|
date_naissance, date_embauche,
|
|
created_at, fk_user_creat, chk_active
|
|
) VALUES (
|
|
?, ?, ?, ?,
|
|
?, ?, ?, ?,
|
|
?, ?, ?,
|
|
?, ?,
|
|
NOW(), ?, 1
|
|
)
|
|
');
|
|
$stmt->execute([
|
|
$encryptedEmail,
|
|
$passwordHash,
|
|
$encryptedName,
|
|
$firstName,
|
|
$sectName,
|
|
$phone,
|
|
$mobile,
|
|
$role,
|
|
$entiteId,
|
|
$alertEmail,
|
|
$suivi,
|
|
$dateNaissance,
|
|
$dateEmbauche,
|
|
$currentUserId
|
|
]);
|
|
$userId = $this->db->lastInsertId();
|
|
|
|
// Envoi de l'email avec les identifiants
|
|
ApiService::sendEmail($email, $name, 'welcome', ['password' => $password]);
|
|
|
|
LogService::log('Utilisateur GeoSector créé', [
|
|
'level' => 'info',
|
|
'createdBy' => $currentUserId,
|
|
'newUserId' => $userId,
|
|
'email' => $email
|
|
]);
|
|
|
|
Response::json([
|
|
'status' => 'success',
|
|
'message' => 'Utilisateur créé avec succès',
|
|
'id' => $userId
|
|
], 201);
|
|
} catch (PDOException $e) {
|
|
LogService::log('Erreur lors de la création d\'un utilisateur GeoSector', [
|
|
'level' => 'error',
|
|
'error' => $e->getMessage(),
|
|
'code' => $e->getCode()
|
|
]);
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Erreur serveur'
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
public function updateUser(string $id): void {
|
|
Session::requireAuth();
|
|
|
|
// Vérification des droits d'accès (rôle administrateur ou utilisateur lui-même)
|
|
$currentUserId = Session::getUserId();
|
|
|
|
// Récupérer le rôle de l'utilisateur depuis la base de données
|
|
$stmt = $this->db->prepare('SELECT fk_role FROM users WHERE id = ?');
|
|
$stmt->execute([$currentUserId]);
|
|
$result = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
$userRole = $result ? $result['fk_role'] : null;
|
|
|
|
if ($userRole != '1' && $userRole != '2' && $currentUserId != $id) {
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Accès non autorisé'
|
|
], 403);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
$data = Request::getJson();
|
|
|
|
// Vérification qu'il y a des données à mettre à jour
|
|
if (empty($data)) {
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Aucune donnée à mettre à jour'
|
|
], 400);
|
|
return;
|
|
}
|
|
|
|
// Construction de la requête UPDATE dynamique
|
|
$updateFields = [];
|
|
$params = ['id' => $id];
|
|
|
|
// Traitement des champs à chiffrer
|
|
if (isset($data['email'])) {
|
|
// Vérification que l'email n'est pas déjà utilisé par un autre utilisateur
|
|
$email = trim(strtolower($data['email']));
|
|
$encryptedEmail = ApiService::encryptSearchableData($email);
|
|
|
|
$checkStmt = $this->db->prepare('SELECT id FROM users WHERE encrypted_email = ? AND id != ?');
|
|
$checkStmt->execute([$encryptedEmail, $id]);
|
|
if ($checkStmt->fetch()) {
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Cet email est déjà utilisé par un autre utilisateur'
|
|
], 409);
|
|
return;
|
|
}
|
|
|
|
$updateFields[] = "encrypted_email = :encrypted_email";
|
|
$params['encrypted_email'] = $encryptedEmail;
|
|
}
|
|
|
|
if (isset($data['name'])) {
|
|
$updateFields[] = "encrypted_name = :encrypted_name";
|
|
$params['encrypted_name'] = ApiService::encryptData(trim($data['name']));
|
|
}
|
|
|
|
if (isset($data['phone'])) {
|
|
$updateFields[] = "encrypted_phone = :encrypted_phone";
|
|
$params['encrypted_phone'] = ApiService::encryptData(trim($data['phone']));
|
|
}
|
|
|
|
if (isset($data['mobile'])) {
|
|
$updateFields[] = "encrypted_mobile = :encrypted_mobile";
|
|
$params['encrypted_mobile'] = ApiService::encryptData(trim($data['mobile']));
|
|
}
|
|
|
|
// Traitement des champs non chiffrés
|
|
$nonEncryptedFields = [
|
|
'first_name',
|
|
'sect_name',
|
|
'fk_role',
|
|
'fk_entite',
|
|
'chk_alert_email',
|
|
'chk_suivi',
|
|
'date_naissance',
|
|
'date_embauche',
|
|
'chk_active'
|
|
];
|
|
|
|
foreach ($nonEncryptedFields as $field) {
|
|
if (isset($data[$field])) {
|
|
$updateFields[] = "$field = :$field";
|
|
$params[$field] = is_string($data[$field]) ? trim($data[$field]) : $data[$field];
|
|
}
|
|
}
|
|
|
|
// Mise à jour du mot de passe si fourni
|
|
if (isset($data['password']) && !empty($data['password'])) {
|
|
if (strlen($data['password']) < 8) {
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Le mot de passe doit contenir au moins 8 caractères'
|
|
], 400);
|
|
return;
|
|
}
|
|
$updateFields[] = "user_pass_hash = :password";
|
|
$params['password'] = password_hash($data['password'], PASSWORD_DEFAULT);
|
|
}
|
|
|
|
// Ajout des champs de mise à jour
|
|
$updateFields[] = "updated_at = NOW()";
|
|
$updateFields[] = "fk_user_modif = :modifier_id";
|
|
$params['modifier_id'] = $currentUserId;
|
|
|
|
if (!empty($updateFields)) {
|
|
$sql = 'UPDATE users SET ' . implode(', ', $updateFields) . ' WHERE id = :id';
|
|
$stmt = $this->db->prepare($sql);
|
|
$stmt->execute($params);
|
|
|
|
if ($stmt->rowCount() === 0) {
|
|
Response::json([
|
|
'status' => 'warning',
|
|
'message' => 'Aucune modification effectuée'
|
|
]);
|
|
return;
|
|
}
|
|
|
|
LogService::log('Utilisateur GeoSector mis à jour', [
|
|
'level' => 'info',
|
|
'modifiedBy' => $currentUserId,
|
|
'userId' => $id,
|
|
'fields' => array_keys($data),
|
|
]);
|
|
|
|
Response::json([
|
|
'status' => 'success',
|
|
'message' => 'Utilisateur mis à jour avec succès'
|
|
]);
|
|
} else {
|
|
Response::json([
|
|
'status' => 'warning',
|
|
'message' => 'Aucune donnée valide à mettre à jour'
|
|
]);
|
|
}
|
|
} catch (PDOException $e) {
|
|
LogService::log('Erreur lors de la mise à jour d\'un utilisateur GeoSector', [
|
|
'level' => 'error',
|
|
'error' => $e->getMessage(),
|
|
'userId' => $id
|
|
]);
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Erreur serveur'
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
public function deleteUser(string $id): void {
|
|
Session::requireAuth();
|
|
|
|
$currentUserId = Session::getUserId();
|
|
|
|
// Récupérer les infos de l'utilisateur courant
|
|
$stmt = $this->db->prepare('SELECT fk_role, fk_entite FROM users WHERE id = ?');
|
|
$stmt->execute([$currentUserId]);
|
|
$currentUser = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$currentUser) {
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Utilisateur courant non trouvé'
|
|
], 403);
|
|
return;
|
|
}
|
|
|
|
$userRole = (int)$currentUser['fk_role'];
|
|
$userEntite = $currentUser['fk_entite'];
|
|
|
|
// Empêcher la suppression de son propre compte
|
|
if ($currentUserId == $id) {
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Vous ne pouvez pas supprimer votre propre compte'
|
|
], 400);
|
|
return;
|
|
}
|
|
|
|
// Récupérer l'utilisateur cible
|
|
$stmt2 = $this->db->prepare('SELECT fk_entite FROM users WHERE id = ?');
|
|
$stmt2->execute([$id]);
|
|
$userToDelete = $stmt2->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$userToDelete) {
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Utilisateur cible non trouvé'
|
|
], 404);
|
|
return;
|
|
}
|
|
|
|
// Contrôle des droits
|
|
if ($userRole === 1) {
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => "Vous n'avez pas le droit de supprimer un utilisateur"
|
|
], 403);
|
|
return;
|
|
} elseif ($userRole === 2) {
|
|
if ($userEntite != $userToDelete['fk_entite']) {
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => "Vous n'avez pas le droit de supprimer un utilisateur d'une autre amicale"
|
|
], 403);
|
|
return;
|
|
}
|
|
}
|
|
// fk_role > 2 : tout est permis (hors auto-suppression)
|
|
|
|
// ——— Gestion du transfert éventuel ———
|
|
$transferTo = isset($_GET['transfer_to']) ? trim($_GET['transfer_to']) : null;
|
|
|
|
if ($transferTo) {
|
|
try {
|
|
// Transférer TOUS les passages de l'utilisateur vers l'utilisateur désigné
|
|
$stmt3 = $this->db->prepare('
|
|
UPDATE ope_pass
|
|
SET fk_user = :new_user_id
|
|
WHERE fk_user = :delete_user_id
|
|
');
|
|
$stmt3->execute([
|
|
'new_user_id' => $transferTo,
|
|
'delete_user_id' => $id
|
|
]);
|
|
|
|
$transferredCount = $stmt3->rowCount();
|
|
|
|
LogService::log('Passages transférés avant suppression utilisateur', [
|
|
'level' => 'info',
|
|
'from_user' => $id,
|
|
'to_user' => $transferTo,
|
|
'passages_transferred' => $transferredCount
|
|
]);
|
|
} catch (PDOException $e) {
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Erreur lors du transfert des passages',
|
|
'error' => $e->getMessage()
|
|
], 500);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// —— Suppression réelle de l'utilisateur ——
|
|
try {
|
|
// Supprimer les enregistrements dépendants dans ope_users
|
|
$stmtOpeUsers = $this->db->prepare('DELETE FROM ope_users WHERE fk_user = ?');
|
|
$stmtOpeUsers->execute([$id]);
|
|
|
|
// Supprimer les enregistrements dépendants dans ope_users_sectors
|
|
$stmtOpeUsersSectors = $this->db->prepare('DELETE FROM ope_users_sectors WHERE fk_user = ?');
|
|
$stmtOpeUsersSectors->execute([$id]);
|
|
|
|
$stmt = $this->db->prepare('DELETE FROM users WHERE id = ?');
|
|
$stmt->execute([$id]);
|
|
|
|
if ($stmt->rowCount() === 0) {
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Utilisateur non trouvé ou déjà supprimé'
|
|
], 404);
|
|
return;
|
|
}
|
|
|
|
LogService::log('Utilisateur GeoSector supprimé', [
|
|
'level' => 'info',
|
|
'deletedBy' => $currentUserId,
|
|
'userId' => $id,
|
|
'passage_transfer' => $transferTo ? "Tous les passages transférés vers utilisateur $transferTo" : 'Aucun transfert'
|
|
]);
|
|
|
|
Response::json([
|
|
'status' => 'success',
|
|
'message' => 'Utilisateur supprimé avec succès'
|
|
]);
|
|
} catch (PDOException $e) {
|
|
LogService::log('Erreur lors de la suppression d\'un utilisateur GeoSector', [
|
|
'level' => 'error',
|
|
'error' => $e->getMessage(),
|
|
'userId' => $id
|
|
]);
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Erreur serveur'
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
public function resetPassword(string $id): void {
|
|
Session::requireAuth();
|
|
|
|
$currentUserId = Session::getUserId();
|
|
|
|
// Récupérer les infos de l'utilisateur courant
|
|
$stmt = $this->db->prepare('SELECT fk_role, fk_entite, chk_active FROM users WHERE id = ?');
|
|
$stmt->execute([$currentUserId]);
|
|
$currentUser = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$currentUser) {
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Utilisateur courant non trouvé'
|
|
], 403);
|
|
return;
|
|
}
|
|
|
|
// Vérifier que l'utilisateur courant est actif
|
|
if ($currentUser['chk_active'] != 1) {
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Votre compte n\'est pas actif'
|
|
], 403);
|
|
return;
|
|
}
|
|
|
|
$userRole = (int)$currentUser['fk_role'];
|
|
$userEntite = $currentUser['fk_entite'];
|
|
|
|
// Récupérer l'utilisateur cible
|
|
$stmt = $this->db->prepare('
|
|
SELECT id, encrypted_email, encrypted_name, fk_entite, chk_active
|
|
FROM users
|
|
WHERE id = ?
|
|
');
|
|
$stmt->execute([$id]);
|
|
$targetUser = $stmt->fetch(PDO::FETCH_ASSOC);
|
|
|
|
if (!$targetUser) {
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Utilisateur non trouvé'
|
|
], 404);
|
|
return;
|
|
}
|
|
|
|
// Vérifier que l'utilisateur est actif
|
|
if ($targetUser['chk_active'] != 1) {
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'L\'utilisateur n\'est pas actif'
|
|
], 400);
|
|
return;
|
|
}
|
|
|
|
// Contrôle des droits selon le rôle
|
|
if ($userRole === 1) {
|
|
// Role 1 : peut uniquement réinitialiser son propre mot de passe
|
|
if ($currentUserId != $id) {
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Vous ne pouvez réinitialiser que votre propre mot de passe'
|
|
], 403);
|
|
return;
|
|
}
|
|
} elseif ($userRole === 2) {
|
|
// Role 2 : peut réinitialiser les mots de passe de sa propre entité
|
|
if ($userEntite != $targetUser['fk_entite']) {
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Vous ne pouvez réinitialiser que les mots de passe des utilisateurs de votre entité'
|
|
], 403);
|
|
return;
|
|
}
|
|
}
|
|
// Role > 2 : peut tout faire
|
|
|
|
try {
|
|
// Déchiffrement des données
|
|
$email = ApiService::decryptSearchableData($targetUser['encrypted_email']);
|
|
$name = ApiService::decryptData($targetUser['encrypted_name']);
|
|
|
|
// Génération d'un nouveau mot de passe sécurisé
|
|
$newPassword = ApiService::generateSecurePassword();
|
|
$passwordHash = password_hash($newPassword, PASSWORD_DEFAULT);
|
|
|
|
// Mise à jour du mot de passe en base de données
|
|
$updateStmt = $this->db->prepare('
|
|
UPDATE users
|
|
SET user_pass_hash = :password,
|
|
updated_at = NOW(),
|
|
fk_user_modif = :modifier_id
|
|
WHERE id = :id
|
|
');
|
|
$updateStmt->execute([
|
|
'password' => $passwordHash,
|
|
'modifier_id' => $currentUserId,
|
|
'id' => $id
|
|
]);
|
|
|
|
// Envoi de l'email avec le nouveau mot de passe
|
|
ApiService::sendEmail($email, $name, 'password_reset', ['password' => $newPassword]);
|
|
|
|
LogService::log('Mot de passe réinitialisé', [
|
|
'level' => 'info',
|
|
'resetBy' => $currentUserId,
|
|
'userId' => $id,
|
|
'email' => $email
|
|
]);
|
|
|
|
Response::json([
|
|
'status' => 'success',
|
|
'message' => 'Mot de passe réinitialisé avec succès. Un email a été envoyé à l\'utilisateur.'
|
|
]);
|
|
|
|
} catch (PDOException $e) {
|
|
LogService::log('Erreur lors de la réinitialisation du mot de passe', [
|
|
'level' => 'error',
|
|
'error' => $e->getMessage(),
|
|
'userId' => $id
|
|
]);
|
|
Response::json([
|
|
'status' => 'error',
|
|
'message' => 'Erreur serveur'
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
// Méthodes auxiliaires
|
|
private function validateUpdateData(array $data): ?string {
|
|
// Validation de l'email
|
|
if (isset($data['email'])) {
|
|
if (!filter_var(trim($data['email']), FILTER_VALIDATE_EMAIL)) {
|
|
return 'Format d\'email invalide';
|
|
}
|
|
}
|
|
|
|
// Validation du nom
|
|
if (isset($data['name']) && strlen(trim($data['name'])) < 2) {
|
|
return 'Le nom doit contenir au moins 2 caractères';
|
|
}
|
|
|
|
// Validation du téléphone
|
|
if (isset($data['phone']) && !empty($data['phone'])) {
|
|
if (!preg_match('/^[0-9+\s()-]{6,20}$/', trim($data['phone']))) {
|
|
return 'Format de téléphone invalide';
|
|
}
|
|
}
|
|
|
|
// Validation du mobile
|
|
if (isset($data['mobile']) && !empty($data['mobile'])) {
|
|
if (!preg_match('/^[0-9+\s()-]{6,20}$/', trim($data['mobile']))) {
|
|
return 'Format de mobile invalide';
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|