Files
geo/api/scripts/migrate_uploads_structure.php
Pierre 6d41a1274f feat: Release v3.1.6 - Amélioration complète des flux de passages
- Optimisation des listes de passages (user/admin)
- Amélioration du flux de création avec validation temps réel
- Amélioration du flux de consultation avec export multi-formats
- Amélioration du flux de modification avec suivi des changements
- Ajout de la génération PDF pour les reçus
- Migration de la structure des uploads
- Implémentation de la file d'attente d'emails
- Ajout des permissions de suppression de passages
- Corrections de bugs et optimisations performances

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-21 17:57:27 +02:00

298 lines
9.6 KiB
PHP

#!/usr/bin/env php
<?php
/**
* Script de migration de l'arborescence des uploads
* Réorganise les fichiers existants vers la nouvelle structure simplifiée
*
* Ancienne structure : uploads/entites/{id}/* et uploads/{id}/*
* Nouvelle structure : uploads/{id}/*
*
* Usage: php scripts/migrate_uploads_structure.php [--dry-run]
*/
declare(strict_types=1);
// Chemin de base des uploads
const BASE_PATH = '/var/www/geosector/api/uploads';
const LOG_FILE = '/var/www/geosector/api/logs/migration_uploads_' . date('Ymd_His') . '.log';
// Mode dry-run (simulation sans modification)
$dryRun = in_array('--dry-run', $argv);
// Fonction pour logger
function logMessage(string $message, string $level = 'INFO'): void {
$timestamp = date('Y-m-d H:i:s');
$log = "[$timestamp] [$level] $message" . PHP_EOL;
echo $log;
if (!$GLOBALS['dryRun']) {
file_put_contents(LOG_FILE, $log, FILE_APPEND);
}
}
// Fonction pour déplacer un fichier ou dossier
function moveItem(string $source, string $destination): bool {
global $dryRun;
if (!file_exists($source)) {
logMessage("Source n'existe pas: $source", 'WARNING');
return false;
}
// Créer le dossier de destination si nécessaire
$destDir = dirname($destination);
if (!is_dir($destDir)) {
logMessage("Création du dossier: $destDir");
if (!$dryRun) {
mkdir($destDir, 0775, true);
chown($destDir, 'nginx');
chgrp($destDir, 'nobody');
}
}
// Déplacer l'élément
logMessage("Déplacement: $source -> $destination");
if (!$dryRun) {
if (is_dir($source)) {
// Pour un dossier, utiliser rename
return rename($source, $destination);
} else {
// Pour un fichier
return rename($source, $destination);
}
}
return true;
}
// Fonction pour copier récursivement un dossier
function copyDirectory(string $source, string $dest): bool {
global $dryRun;
if (!is_dir($source)) {
return false;
}
if (!$dryRun) {
if (!is_dir($dest)) {
mkdir($dest, 0775, true);
chown($dest, 'nginx');
chgrp($dest, 'nobody');
}
}
$dir = opendir($source);
while (($file = readdir($dir)) !== false) {
if ($file === '.' || $file === '..') {
continue;
}
$srcPath = "$source/$file";
$destPath = "$dest/$file";
if (is_dir($srcPath)) {
copyDirectory($srcPath, $destPath);
} else {
logMessage("Copie: $srcPath -> $destPath");
if (!$dryRun) {
copy($srcPath, $destPath);
chmod($destPath, 0664);
chown($destPath, 'nginx');
chgrp($destPath, 'nobody');
}
}
}
closedir($dir);
return true;
}
// Fonction principale de migration
function migrateUploads(): void {
global $dryRun;
logMessage("=== Début de la migration des uploads ===");
logMessage($dryRun ? "MODE DRY-RUN (simulation)" : "MODE RÉEL (modifications effectives)");
// 1. Migrer uploads/entites/* vers uploads/*
$entitesPath = BASE_PATH . '/entites';
if (is_dir($entitesPath)) {
logMessage("Traitement du dossier entites/");
$entites = scandir($entitesPath);
foreach ($entites as $entiteId) {
if ($entiteId === '.' || $entiteId === '..') continue;
$oldPath = "$entitesPath/$entiteId";
$newPath = BASE_PATH . "/$entiteId";
if (!is_dir($oldPath)) continue;
logMessage("Migration entité $entiteId");
// Si le dossier destination existe déjà, fusionner
if (is_dir($newPath)) {
logMessage("Le dossier $entiteId existe déjà à la racine, fusion nécessaire", 'INFO');
// Migrer les sous-dossiers
$subDirs = scandir($oldPath);
foreach ($subDirs as $subDir) {
if ($subDir === '.' || $subDir === '..') continue;
$oldSubPath = "$oldPath/$subDir";
$newSubPath = "$newPath/$subDir";
if ($subDir === 'operations') {
// Traiter spécialement le dossier operations
migrateOperations($oldSubPath, $newSubPath);
} else {
// Pour logo et recus, déplacer directement
if (!is_dir($newSubPath)) {
moveItem($oldSubPath, $newSubPath);
} else {
logMessage("Le dossier $newSubPath existe déjà, fusion du contenu");
copyDirectory($oldSubPath, $newSubPath);
if (!$dryRun) {
// Supprimer l'ancien après copie
exec("rm -rf " . escapeshellarg($oldSubPath));
}
}
}
}
} else {
// Déplacer simplement le dossier entier
moveItem($oldPath, $newPath);
}
}
// Supprimer le dossier entites vide
if (!$dryRun) {
if (count(scandir($entitesPath)) === 2) { // Seulement . et ..
rmdir($entitesPath);
logMessage("Suppression du dossier entites/ vide");
}
}
}
// 2. Nettoyer la structure des dossiers operations
logMessage("Nettoyage de la structure des dossiers operations");
cleanupOperationsStructure();
logMessage("=== Migration terminée ===");
if (!$dryRun) {
logMessage("Logs sauvegardés dans: " . LOG_FILE);
}
}
// Fonction pour migrer le dossier operations avec simplification
function migrateOperations(string $oldPath, string $newPath): void {
global $dryRun;
if (!is_dir($oldPath)) return;
logMessage("Migration du dossier operations: $oldPath");
if (!$dryRun && !is_dir($newPath)) {
mkdir($newPath, 0775, true);
chown($newPath, 'nginx');
chgrp($newPath, 'nobody');
}
$operations = scandir($oldPath);
foreach ($operations as $opId) {
if ($opId === '.' || $opId === '..') continue;
$oldOpPath = "$oldPath/$opId";
$newOpPath = "$newPath/$opId";
// Simplifier la structure: déplacer les xlsx directement dans operations/{id}/
if (is_dir("$oldOpPath/documents/exports/excel")) {
$excelPath = "$oldOpPath/documents/exports/excel";
$files = scandir($excelPath);
foreach ($files as $file) {
if ($file === '.' || $file === '..' || !str_ends_with($file, '.xlsx')) continue;
$oldFilePath = "$excelPath/$file";
$newFilePath = "$newOpPath/$file";
logMessage("Déplacement Excel: $oldFilePath -> $newFilePath");
if (!$dryRun) {
if (!is_dir($newOpPath)) {
mkdir($newOpPath, 0775, true);
chown($newOpPath, 'nginx');
chgrp($newOpPath, 'nobody');
}
rename($oldFilePath, $newFilePath);
chmod($newFilePath, 0664);
chown($newFilePath, 'nginx');
chgrp($newFilePath, 'nobody');
}
}
}
}
}
// Fonction pour nettoyer la structure après migration
function cleanupOperationsStructure(): void {
global $dryRun;
$uploadsDir = BASE_PATH;
$entites = scandir($uploadsDir);
foreach ($entites as $entiteId) {
if ($entiteId === '.' || $entiteId === '..' || $entiteId === 'entites') continue;
$operationsPath = "$uploadsDir/$entiteId/operations";
if (!is_dir($operationsPath)) continue;
$operations = scandir($operationsPath);
foreach ($operations as $opId) {
if ($opId === '.' || $opId === '..') continue;
$opPath = "$operationsPath/$opId";
// Supprimer l'ancienne structure documents/exports/excel si elle est vide
$oldStructure = "$opPath/documents";
if (is_dir($oldStructure)) {
logMessage("Suppression de l'ancienne structure: $oldStructure");
if (!$dryRun) {
exec("rm -rf " . escapeshellarg($oldStructure));
}
}
}
}
}
// Vérifier les permissions
if (!is_dir(BASE_PATH)) {
die("ERREUR: Le dossier " . BASE_PATH . " n'existe pas\n");
}
if (!is_writable(BASE_PATH) && !$dryRun) {
die("ERREUR: Le dossier " . BASE_PATH . " n'est pas accessible en écriture\n");
}
// Lancer la migration
try {
migrateUploads();
if ($dryRun) {
echo "\n";
echo "========================================\n";
echo "SIMULATION TERMINÉE\n";
echo "Pour exécuter réellement la migration:\n";
echo "php " . $argv[0] . "\n";
echo "========================================\n";
} else {
echo "\n";
echo "========================================\n";
echo "MIGRATION TERMINÉE AVEC SUCCÈS\n";
echo "Vérifiez les logs: " . LOG_FILE . "\n";
echo "========================================\n";
}
} catch (Exception $e) {
logMessage("ERREUR FATALE: " . $e->getMessage(), 'ERROR');
exit(1);
}