mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-06-25 16:19:19 +02:00
add file export system for admins
- ExportController: getAllThesisFiles(), buildExportManifest(), createExportZip() builds a ZIP archive with manifest.json + files/ mirror of storage/theses/ - Database: getAllThesisFilesForExport() queries all thesis_files + identifier - AdminLogger: logFilesExport() audit log entry - admin/actions/export-files.php: thin dispatcher, streams zip with headers - templates/admin/index.php: 'Exporter fichiers' button next to CSV export
This commit is contained in:
197
docs/export.md
Normal file
197
docs/export.md
Normal file
@@ -0,0 +1,197 @@
|
||||
# Export et sauvegarde des données XAMXAM
|
||||
|
||||
Ce document explique le fonctionnement du système d'export pour les
|
||||
administrateur·ices de la plateforme. Il couvre les trois types d'export
|
||||
disponibles depuis le panneau d'administration, la manière de les combiner
|
||||
pour une restauration complète, et les détails techniques utiles en cas de
|
||||
problème.
|
||||
|
||||
---
|
||||
|
||||
## Les trois exports disponibles
|
||||
|
||||
Depuis la page principale d'administration (`/admin/`), la barre d'outils
|
||||
propose trois boutons d'export :
|
||||
|
||||
| Bouton | Fichier produit | Contenu |
|
||||
|---|---|---|
|
||||
| **Exporter CSV** | `xamxam-export-AAAA-MM-JJ.csv` | Liste complète des TFE au format compatible avec l'import CSV |
|
||||
| **Exporter DB** | `xamxam-db-AAAA-MM-JJ.sqlite` | Copie brute du fichier de base de données SQLite |
|
||||
| **Exporter fichiers** | `xamxam-files-AAAA-MM-JJ.zip` | Archive ZIP contenant tous les fichiers attachés aux TFE + un manifeste JSON |
|
||||
|
||||
---
|
||||
|
||||
## Exporter les fichiers (ZIP)
|
||||
|
||||
### Ce que contient l'archive
|
||||
|
||||
```
|
||||
xamxam-files-2026-05-07.zip
|
||||
├── manifest.json ← métadonnées de chaque TFE et ses fichiers
|
||||
└── files/
|
||||
└── theses/
|
||||
├── 2025/
|
||||
│ ├── 2025_EMMA_RENARD/
|
||||
│ │ └── EMMA_RENARD_carte_loire_a_velo_france.pdf
|
||||
│ ├── 2025_LILA_DUBOIS_KARIM_NASSAR/
|
||||
│ │ ├── nixing_the_fix_report_final.pdf
|
||||
│ │ ├── bbb_sunflower_1080p_30fps_normal_mp4.zip
|
||||
│ │ └── carte_loire_a_velo_france.pdf
|
||||
│ └── …
|
||||
└── 2026/
|
||||
└── …
|
||||
```
|
||||
|
||||
### Le fichier `manifest.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"exported_at": "2026-05-07T15:30:00+02:00",
|
||||
"db_file": "xamxam.db",
|
||||
"total_theses": 140,
|
||||
"total_files": 312,
|
||||
"zip_added_count": 310,
|
||||
"zip_skipped_count": 2,
|
||||
"theses": {
|
||||
"2025-003": {
|
||||
"id": 42,
|
||||
"identifier": "2025-003",
|
||||
"title": "Titre du TFE",
|
||||
"year": 2025,
|
||||
"files": [
|
||||
{
|
||||
"type": "main",
|
||||
"path": "theses/2025/2025_AUTEUR/mon_fichier.pdf",
|
||||
"name": "mon_fichier.pdf",
|
||||
"size": 1234567,
|
||||
"mime": "application/pdf",
|
||||
"hash": null,
|
||||
"label": "Mémoire principal",
|
||||
"sort_order": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Le manifeste fait le **pont entre la base de données et les fichiers**. Chaque
|
||||
TFE est indexé par son identifiant (ex. `2025-003`), ce qui permet de
|
||||
retrouver ses fichiers même si l'ordre des IDs change après une restauration.
|
||||
|
||||
---
|
||||
|
||||
## Restaurer une sauvegarde complète
|
||||
|
||||
Une sauvegarde complète se compose de **trois fichiers** à exporter le même
|
||||
jour (DB + fichiers ZIP + CSV). Voici la procédure de restauration sur un
|
||||
serveur neuf ou après un incident.
|
||||
|
||||
### 1. Restaurer la base de données
|
||||
|
||||
```bash
|
||||
# Arrêter le serveur web
|
||||
sudo systemctl stop nginx
|
||||
|
||||
# Remplacer le fichier SQLite
|
||||
cp xamxam-db-AAAA-MM-JJ.sqlite /var/www/xamxam/storage/xamxam.db
|
||||
chown www-data:www-data /var/www/xamxam/storage/xamxam.db
|
||||
chmod 640 /var/www/xamxam/storage/xamxam.db
|
||||
```
|
||||
|
||||
### 2. Restaurer les fichiers
|
||||
|
||||
```bash
|
||||
# Décompresser l'archive dans le répertoire storage/
|
||||
# ATTENTION : le zip contient un dossier files/ à la racine.
|
||||
# On le décompresse dans /tmp puis on copie le contenu de files/theses/
|
||||
# dans storage/theses/ pour préserver la structure existante.
|
||||
|
||||
unzip xamxam-files-AAAA-MM-JJ.zip -d /tmp/xamxam-restore
|
||||
cp -r /tmp/xamxam-restore/files/theses/* /var/www/xamxam/storage/theses/
|
||||
chown -R www-data:www-data /var/www/xamxam/storage/theses/
|
||||
rm -rf /tmp/xamxam-restore
|
||||
```
|
||||
|
||||
> **Pourquoi ça fonctionne :** les chemins dans la table `thesis_files` sont
|
||||
> relatifs (ex. `theses/2025/2025_AUTEUR/fichier.pdf`). En restaurant les
|
||||
> fichiers au même emplacement sous `storage/`, les liens DB ↔ fichiers sont
|
||||
> automatiquement rétablis.
|
||||
|
||||
### 3. Redémarrer
|
||||
|
||||
```bash
|
||||
sudo systemctl start nginx
|
||||
```
|
||||
|
||||
### 4. Vérifier
|
||||
|
||||
Naviguer vers `/admin/` et vérifier que la liste des TFE s'affiche
|
||||
correctement et que les fichiers sont téléchargeables.
|
||||
|
||||
---
|
||||
|
||||
## Restauration partielle ou re-linkage
|
||||
|
||||
Si la base de données a été perdue mais que vous avez le ZIP des fichiers
|
||||
et le CSV d'export, vous pouvez reconstruire les liens grâce au
|
||||
`manifest.json` :
|
||||
|
||||
1. **Réimporter le CSV** via l'interface d'administration (bouton *Importer un
|
||||
CSV*). Les identifiants (colonne `Identifiant`) doivent correspondre à ceux
|
||||
du manifeste.
|
||||
|
||||
2. **Décompresser le ZIP** dans `storage/` comme décrit ci-dessus.
|
||||
|
||||
3. **Vérifier avec le manifeste** — les chemins dans `manifest.json`
|
||||
correspondent aux chemins dans `thesis_files.file_path`. Si les
|
||||
identifiants du CSV et ceux du manifeste coïncident, les fichiers seront
|
||||
correctement liés après l'import.
|
||||
|
||||
---
|
||||
|
||||
## Détails techniques
|
||||
|
||||
### Performance
|
||||
|
||||
L'export des fichiers utilise `ZipArchive` (extension PHP standard) et crée
|
||||
une archive temporaire dans `/tmp`. Pour un volume important de fichiers
|
||||
(plusieurs centaines), la création peut prendre quelques secondes. Un timeout
|
||||
d'exécution raisonnable (`max_execution_time ≥ 60s`) est recommandé.
|
||||
|
||||
### Sécurité
|
||||
|
||||
- Les exports sont **protégés par authentification administrateur**
|
||||
(`AdminAuth::requireLogin()`).
|
||||
- L'export DB et l'export fichiers sont journalisés dans le log d'audit
|
||||
(`admin_audit_log`) avec l'IP et l'User-Agent de l'administrateur.
|
||||
- Les fichiers temporaires sont supprimés après envoi (`unlink()` dans le
|
||||
bloc `finally` implicite de `export-files.php`).
|
||||
- Les fichiers dans le ZIP conservent leurs chemins relatifs d'origine — il
|
||||
n'y a pas de risque de *path traversal* car les chemins proviennent de la
|
||||
base de données et ne contiennent jamais `../`.
|
||||
|
||||
### Colonnes du CSV d'export
|
||||
|
||||
Le CSV utilise la même structure que l'import (21 colonnes). Il est
|
||||
directement ré-importable sans modification. Voir [`docs/import.md`](import.md)
|
||||
pour le détail des colonnes.
|
||||
|
||||
---
|
||||
|
||||
## Résumé des commandes utiles
|
||||
|
||||
```bash
|
||||
# Télécharger les trois exports (depuis le navigateur ou curl)
|
||||
curl -u admin:password -O https://xamxam.erg.be/admin/actions/export-db.php
|
||||
curl -u admin:password -O https://xamxam.erg.be/admin/actions/export-csv.php
|
||||
curl -u admin:password -O https://xamxam.erg.be/admin/actions/export-files.php
|
||||
|
||||
# Restauration complète
|
||||
sudo systemctl stop nginx
|
||||
cp xamxam-db-*.sqlite /var/www/xamxam/storage/xamxam.db
|
||||
unzip xamxam-files-*.zip -d /tmp/xamxam-restore
|
||||
cp -r /tmp/xamxam-restore/files/theses/* /var/www/xamxam/storage/theses/
|
||||
chown -R www-data:www-data /var/www/xamxam/storage/
|
||||
sudo systemctl start nginx
|
||||
```
|
||||
Reference in New Issue
Block a user