Livraison d ela gestion des opérations v0.4.0
This commit is contained in:
276
api/docs/EXPORT-SYSTEM.md
Normal file
276
api/docs/EXPORT-SYSTEM.md
Normal file
@@ -0,0 +1,276 @@
|
||||
# Système d'Export/Import d'Opérations - Geosector API
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
Le système d'export/import permet de sauvegarder et restaurer des opérations complètes avec toutes leurs données associées (passages, utilisateurs, secteurs, relations).
|
||||
|
||||
## Architecture
|
||||
|
||||
### Routes API
|
||||
|
||||
#### Exports
|
||||
|
||||
- `GET /api/operations/{id}/export/excel` - Export Excel (consultation)
|
||||
- `GET /api/operations/{id}/export/json` - Export JSON (sauvegarde)
|
||||
- `GET /api/operations/{id}/export/full` - Export combiné (Excel + JSON)
|
||||
|
||||
#### Gestion des sauvegardes
|
||||
|
||||
- `GET /api/operations/{id}/backups` - Liste des sauvegardes
|
||||
- `GET /api/operations/{id}/backups/{backup_id}` - Télécharger une sauvegarde
|
||||
- `DELETE /api/operations/{id}/backups/{backup_id}` - Supprimer une sauvegarde
|
||||
|
||||
### Structure des fichiers
|
||||
|
||||
```
|
||||
uploads/entites/{entite_id}/operations/{operation_id}/documents/exports/
|
||||
├── excel/
|
||||
│ └── geosector-export-{operation_id}-{timestamp}.xlsx
|
||||
└── json/
|
||||
└── geosector-backup-{operation_id}-{type}-{timestamp}.json
|
||||
```
|
||||
|
||||
## Export Excel
|
||||
|
||||
### Contenu
|
||||
|
||||
Le fichier Excel contient 4 feuilles :
|
||||
|
||||
#### 1. Feuille "Passages"
|
||||
|
||||
- **Colonnes** : ID_Passage, Date, Heure, Prénom, Nom, Tournée, Type, N°, Rue, Ville, Habitat, Donateur, Email, Tél, Montant, Règlement, Remarque, FK_User, FK_Sector, FK_Operation
|
||||
- **Données déchiffrées** : Noms, emails, téléphones
|
||||
- **Formatage** : Dates françaises (dd/mm/yyyy), types traduits
|
||||
|
||||
#### 2. Feuille "Utilisateurs"
|
||||
|
||||
- **Colonnes** : ID_User, Nom, Prénom, Email, Téléphone, Mobile, Rôle, Date_création, Actif, FK_Entite
|
||||
- **Données déchiffrées** : Informations personnelles
|
||||
|
||||
#### 3. Feuille "Secteurs"
|
||||
|
||||
- **Colonnes** : ID_Sector, Libellé, Couleur, Date_création, Actif, FK_Operation
|
||||
|
||||
#### 4. Feuille "Secteurs-Utilisateurs"
|
||||
|
||||
- **Colonnes** : ID_Relation, FK_Sector, Nom_Secteur, FK_User, Nom_Utilisateur, Date_assignation, FK_Operation
|
||||
|
||||
### Paramètres optionnels
|
||||
|
||||
- `?user_id={id}` - Filtrer les passages par utilisateur
|
||||
|
||||
### Exemple d'utilisation
|
||||
|
||||
```bash
|
||||
# Export complet
|
||||
GET /api/operations/2644/export/excel
|
||||
|
||||
# Export filtré par utilisateur
|
||||
GET /api/operations/2644/export/excel?user_id=123
|
||||
```
|
||||
|
||||
## Export JSON
|
||||
|
||||
### Structure du fichier JSON
|
||||
|
||||
```json
|
||||
{
|
||||
"export_metadata": {
|
||||
"version": "1.0",
|
||||
"export_date": "2025-06-21T16:19:23Z",
|
||||
"source_entite_id": 5,
|
||||
"export_type": "full_operation"
|
||||
},
|
||||
"operation": {
|
||||
"id": 2644,
|
||||
"libelle": "OPE 2024-25",
|
||||
"date_deb": "2024-09-01",
|
||||
"date_fin": "2025-05-30",
|
||||
"fk_entite": 5,
|
||||
"chk_distinct_sectors": 1,
|
||||
"created_at": "2024-08-15T10:00:00Z"
|
||||
},
|
||||
"users": [...],
|
||||
"sectors": [...],
|
||||
"passages": [...],
|
||||
"user_sectors": [...]
|
||||
}
|
||||
```
|
||||
|
||||
### Types d'export JSON
|
||||
|
||||
- **manual** : Export à la demande (par défaut)
|
||||
- **auto** : Sauvegarde automatique (avant modifications importantes)
|
||||
|
||||
### Paramètres
|
||||
|
||||
- `?type=manual|auto` - Type d'export
|
||||
|
||||
## Sécurité
|
||||
|
||||
### Contrôles d'accès
|
||||
|
||||
- ✅ Authentification obligatoire
|
||||
- ✅ Vérification d'appartenance à l'entité
|
||||
- ✅ Isolation des données par entité
|
||||
- ✅ Logs détaillés de toutes les opérations
|
||||
|
||||
### Données sensibles
|
||||
|
||||
- ✅ Chiffrement/déchiffrement automatique
|
||||
- ✅ Données personnelles protégées
|
||||
- ✅ Pas d'exposition des clés de chiffrement
|
||||
|
||||
## Stockage et organisation
|
||||
|
||||
### Enregistrement en base
|
||||
|
||||
Tous les fichiers sont enregistrés dans la table `medias` :
|
||||
|
||||
```sql
|
||||
support = 'operation'
|
||||
support_id = {operation_id}
|
||||
file_type = 'xlsx' | 'json'
|
||||
description = 'Export Excel opération - {libelle}'
|
||||
```
|
||||
|
||||
### Métadonnées des fichiers
|
||||
|
||||
- **ID** : Identifiant unique en base
|
||||
- **Filename** : Nom du fichier généré
|
||||
- **Path** : Chemin relatif depuis la racine
|
||||
- **Size** : Taille en octets
|
||||
- **Type** : excel | json
|
||||
|
||||
## Exemples de réponses API
|
||||
|
||||
### Export Excel réussi
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"message": "Export Excel généré avec succès",
|
||||
"file": {
|
||||
"id": 123,
|
||||
"filename": "geosector-export-2644-20250621-161923.xlsx",
|
||||
"path": "uploads/entites/5/operations/2644/documents/exports/excel/geosector-export-2644-20250621-161923.xlsx",
|
||||
"size": 45678,
|
||||
"type": "excel"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Export complet réussi
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"message": "Export complet généré avec succès",
|
||||
"files": {
|
||||
"excel": {
|
||||
"id": 123,
|
||||
"filename": "geosector-export-2644-20250621-161923.xlsx",
|
||||
"path": "uploads/entites/5/operations/2644/documents/exports/excel/geosector-export-2644-20250621-161923.xlsx",
|
||||
"size": 45678,
|
||||
"type": "excel"
|
||||
},
|
||||
"json": {
|
||||
"id": 124,
|
||||
"filename": "geosector-backup-2644-manual-20250621-161923.json",
|
||||
"path": "uploads/entites/5/operations/2644/documents/exports/json/geosector-backup-2644-manual-20250621-161923.json",
|
||||
"size": 12345,
|
||||
"type": "json"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Liste des sauvegardes
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"backups": [
|
||||
{
|
||||
"id": 124,
|
||||
"fichier": "geosector-backup-2644-manual-20250621-161923.json",
|
||||
"file_type": "json",
|
||||
"file_size": 12345,
|
||||
"description": "Sauvegarde JSON opération - manual - OPE 2024-25",
|
||||
"created_at": "2025-06-21 16:19:23",
|
||||
"fk_user_creat": 1
|
||||
},
|
||||
{
|
||||
"id": 123,
|
||||
"fichier": "geosector-export-2644-20250621-161923.xlsx",
|
||||
"file_type": "xlsx",
|
||||
"file_size": 45678,
|
||||
"description": "Export Excel opération - OPE 2024-25",
|
||||
"created_at": "2025-06-21 16:19:23",
|
||||
"fk_user_creat": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Installation et dépendances
|
||||
|
||||
### PhpSpreadsheet
|
||||
|
||||
```bash
|
||||
composer require phpoffice/phpspreadsheet
|
||||
```
|
||||
|
||||
### Permissions de dossiers
|
||||
|
||||
```bash
|
||||
chmod 755 uploads/
|
||||
chmod 755 uploads/entites/
|
||||
```
|
||||
|
||||
## Gestion des erreurs
|
||||
|
||||
### Erreurs courantes
|
||||
|
||||
- **401** : Non authentifié
|
||||
- **403** : Pas d'accès à l'entité
|
||||
- **404** : Opération non trouvée
|
||||
- **500** : Erreur de génération
|
||||
|
||||
### Logs
|
||||
|
||||
Tous les événements sont loggés via `LogService` :
|
||||
|
||||
- Exports réussis (level: info)
|
||||
- Erreurs de génération (level: error)
|
||||
- Tentatives d'accès non autorisées (level: warning)
|
||||
|
||||
## Maintenance
|
||||
|
||||
### Nettoyage automatique (à implémenter)
|
||||
|
||||
- Sauvegardes auto > 30 jours
|
||||
- Fichiers temporaires > 24h
|
||||
- Vérification cohérence base/fichiers
|
||||
|
||||
### Monitoring
|
||||
|
||||
- Espace disque utilisé
|
||||
- Nombre de fichiers par entité
|
||||
- Fréquence des exports
|
||||
|
||||
## Évolutions futures
|
||||
|
||||
### Import/Restauration
|
||||
|
||||
- Validation des fichiers JSON
|
||||
- Import transactionnel
|
||||
- Gestion des conflits d'IDs
|
||||
- Mapping entités source/cible
|
||||
|
||||
### Optimisations
|
||||
|
||||
- Compression des fichiers
|
||||
- Export asynchrone pour gros volumes
|
||||
- Cache des exports fréquents
|
||||
- API de streaming pour téléchargements
|
||||
376
api/docs/FILE-SYSTEM-API.md
Normal file
376
api/docs/FILE-SYSTEM-API.md
Normal file
@@ -0,0 +1,376 @@
|
||||
# API de Gestion des Fichiers - Geosector
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
L'API de gestion des fichiers permet aux administrateurs de naviguer, rechercher et gérer les fichiers stockés dans l'application Geosector avec des contrôles d'accès basés sur les rôles.
|
||||
|
||||
## Contrôles d'accès
|
||||
|
||||
### Rôle 2 (Admin d'entité)
|
||||
|
||||
- Accès limité aux fichiers de son entité uniquement
|
||||
- Chemin racine : `/uploads/entites/{son_entite_id}/`
|
||||
- Peut naviguer dans tous les sous-dossiers de son entité
|
||||
|
||||
### Rôle > 2 (Super admin)
|
||||
|
||||
- Accès complet à tous les fichiers
|
||||
- Chemin racine : `/uploads/` (accès total)
|
||||
- Peut naviguer dans toutes les entités et dossiers système
|
||||
|
||||
## Routes disponibles
|
||||
|
||||
### Navigation et listing
|
||||
|
||||
#### `GET /api/files/browse`
|
||||
|
||||
Navigation dans l'arborescence avec recherche et pagination.
|
||||
|
||||
**Paramètres de requête :**
|
||||
|
||||
- `path` (string) : Chemin à explorer (ex: `entites/5/operations`)
|
||||
- `page` (int) : Page (défaut: 1)
|
||||
- `per_page` (int) : Éléments par page (défaut: 50, max: 100)
|
||||
- `search` (string) : Recherche dans nom, nom original, description
|
||||
- `type` (string) : Filtrage par extension (pdf, jpg, xlsx, etc.)
|
||||
- `category` (string) : Filtrage par catégorie métier
|
||||
- `sort` (string) : Tri (name, date, size, type) - défaut: date
|
||||
- `order` (string) : Ordre (asc, desc) - défaut: desc
|
||||
|
||||
**Exemple :**
|
||||
|
||||
```bash
|
||||
GET /api/files/browse?path=entites/5/operations&search=2024&type=xlsx&page=1
|
||||
```
|
||||
|
||||
**Réponse :**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"current_path": "entites/5/operations",
|
||||
"parent_path": "entites/5",
|
||||
"pagination": {
|
||||
"current_page": 1,
|
||||
"per_page": 50,
|
||||
"total_items": 127,
|
||||
"total_pages": 3,
|
||||
"has_next": true,
|
||||
"has_prev": false
|
||||
},
|
||||
"filters": {
|
||||
"search": "2024",
|
||||
"type": "xlsx",
|
||||
"category": null,
|
||||
"sort": "date",
|
||||
"order": "desc"
|
||||
},
|
||||
"files": [
|
||||
{
|
||||
"id": 123,
|
||||
"fichier": "planning_2024_op2644.xlsx",
|
||||
"original_name": "Planning Opération 2024.xlsx",
|
||||
"file_type": "xlsx",
|
||||
"file_category": "planning",
|
||||
"description": "Planning détaillé opération 2024",
|
||||
"file_size": 1024000,
|
||||
"file_path": "entites/5/operations/2644/documents/planning_2024_op2644.xlsx",
|
||||
"created_at": "2025-06-22 08:30:00",
|
||||
"creator_name": "Jean Dupont"
|
||||
}
|
||||
],
|
||||
"summary": {
|
||||
"total_files": 45,
|
||||
"total_size": 25600000,
|
||||
"by_category": {
|
||||
"planning": 12,
|
||||
"export": 20,
|
||||
"backup": 13
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `GET /api/files/list/{support}/{id}`
|
||||
|
||||
Liste des fichiers par support (entite, user, operation, passage).
|
||||
|
||||
**Paramètres :**
|
||||
|
||||
- `support` : Type de support (entite, user, operation, passage)
|
||||
- `id` : ID de l'élément
|
||||
- Mêmes paramètres de requête que `/browse`
|
||||
|
||||
**Exemple :**
|
||||
|
||||
```bash
|
||||
GET /api/files/list/operation/2644?category=export&page=1
|
||||
```
|
||||
|
||||
### Recherche
|
||||
|
||||
#### `GET /api/files/search`
|
||||
|
||||
Recherche globale dans tous les fichiers accessibles.
|
||||
|
||||
**Paramètres de requête :**
|
||||
|
||||
- `q` (string, requis) : Terme de recherche
|
||||
- `page`, `per_page`, `type`, `category`, `sort`, `order` : Mêmes que browse
|
||||
|
||||
**Exemple :**
|
||||
|
||||
```bash
|
||||
GET /api/files/search?q=planning&type=xlsx&category=planning
|
||||
```
|
||||
|
||||
### Actions sur fichiers
|
||||
|
||||
#### `GET /api/files/download/{id}`
|
||||
|
||||
Téléchargement sécurisé d'un fichier.
|
||||
|
||||
**Réponse :** Fichier en téléchargement direct avec headers appropriés.
|
||||
|
||||
#### `DELETE /api/files/{id}`
|
||||
|
||||
Suppression sécurisée d'un fichier (physique + base de données).
|
||||
|
||||
**Réponse :**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"message": "Fichier supprimé avec succès"
|
||||
}
|
||||
```
|
||||
|
||||
#### `GET /api/files/info/{id}`
|
||||
|
||||
Informations détaillées d'un fichier.
|
||||
|
||||
**Réponse :**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"file": {
|
||||
"id": 123,
|
||||
"fichier": "planning_2024.xlsx",
|
||||
"original_name": "Planning Opération 2024.xlsx",
|
||||
"file_type": "xlsx",
|
||||
"file_category": "planning",
|
||||
"file_size": 1024000,
|
||||
"mime_type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
"description": "Planning détaillé",
|
||||
"support": "operation",
|
||||
"support_id": 2644,
|
||||
"fk_entite": 5,
|
||||
"created_at": "2025-06-22 08:30:00",
|
||||
"updated_at": "2025-06-22 08:30:00",
|
||||
"creator_name": "Jean Dupont",
|
||||
"modifier_name": null,
|
||||
"file_exists": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Statistiques
|
||||
|
||||
#### `GET /api/files/stats`
|
||||
|
||||
Statistiques d'utilisation des fichiers.
|
||||
|
||||
**Pour admin d'entité (rôle 2) :**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"entite_id": 5,
|
||||
"storage": {
|
||||
"total_files": 245,
|
||||
"total_size": 157286400,
|
||||
"by_support": {
|
||||
"entite": { "count": 12, "size": 45000000 },
|
||||
"operation": { "count": 180, "size": 98000000 },
|
||||
"user": { "count": 45, "size": 12000000 },
|
||||
"passage": { "count": 8, "size": 2286400 }
|
||||
},
|
||||
"by_category": {
|
||||
"document": 25,
|
||||
"export": 120,
|
||||
"avatar": 45,
|
||||
"photo": 55
|
||||
},
|
||||
"by_type": {
|
||||
"xlsx": 85,
|
||||
"jpg": 120,
|
||||
"pdf": 40
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Pour super admin (rôle > 2) :**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"global_stats": {
|
||||
"total_files": 2450,
|
||||
"total_size": 1572864000,
|
||||
"entites_count": 25,
|
||||
"by_entite": [
|
||||
{ "entite_id": 5, "files": 245, "size": 157286400 },
|
||||
{ "entite_id": 12, "files": 180, "size": 98000000 }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Métadonnées
|
||||
|
||||
#### `GET /api/files/metadata`
|
||||
|
||||
Informations sur les catégories, extensions et limites autorisées.
|
||||
|
||||
**Réponse :**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"categories": {
|
||||
"entite": ["logo", "document", "reglement", "statut"],
|
||||
"user": ["avatar", "photo"],
|
||||
"operation": ["planning", "liste", "export", "backup"],
|
||||
"passage": ["recu", "photo", "justificatif", "carte"]
|
||||
},
|
||||
"extensions": ["pdf", "jpg", "jpeg", "png", "gif", "webp", "xlsx", "xls", "json", "csv"],
|
||||
"mime_types": {
|
||||
"pdf": "application/pdf",
|
||||
"jpg": "image/jpeg",
|
||||
"xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||
},
|
||||
"max_file_sizes": {
|
||||
"entite": 20971520, // 20 MB
|
||||
"user": 5242880, // 5 MB
|
||||
"operation": 20971520, // 20 MB
|
||||
"passage": 10485760 // 10 MB
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Catégories de fichiers
|
||||
|
||||
### Distinction Extension vs Catégorie
|
||||
|
||||
- **Extension** (`file_type`) : Type technique (pdf, jpg, xlsx, png, etc.)
|
||||
- **Catégorie** (`file_category`) : Type métier (logo, carte, photo, document, planning, etc.)
|
||||
|
||||
### Catégories par support
|
||||
|
||||
#### Entité
|
||||
|
||||
- `logo` : Logo de l'entité
|
||||
- `document` : Documents généraux
|
||||
- `reglement` : Règlements internes
|
||||
- `statut` : Statuts de l'entité
|
||||
|
||||
#### Utilisateur
|
||||
|
||||
- `avatar` : Photo de profil
|
||||
- `photo` : Photos diverses
|
||||
|
||||
#### Opération
|
||||
|
||||
- `planning` : Plannings d'opération
|
||||
- `liste` : Listes diverses
|
||||
- `export` : Exports de données
|
||||
- `backup` : Sauvegardes automatiques
|
||||
|
||||
#### Passage
|
||||
|
||||
- `recu` : Reçus de passage
|
||||
- `photo` : Photos de passage
|
||||
- `justificatif` : Justificatifs divers
|
||||
- `carte` : Cartes et plans
|
||||
|
||||
## Sécurité
|
||||
|
||||
### Validation des chemins
|
||||
|
||||
- Empêche les traversées de répertoire (`../`)
|
||||
- Validation stricte selon le rôle utilisateur
|
||||
- Contrôle d'accès au niveau fichier
|
||||
|
||||
### Logs
|
||||
|
||||
- Tous les téléchargements sont loggés
|
||||
- Toutes les suppressions sont tracées
|
||||
- Erreurs d'accès enregistrées
|
||||
|
||||
### Contrôles d'intégrité
|
||||
|
||||
- Vérification de l'existence physique des fichiers
|
||||
- Validation des permissions avant chaque action
|
||||
- Contrôle de cohérence base/fichiers
|
||||
|
||||
## Exemples d'utilisation
|
||||
|
||||
### Navigation dans les opérations d'une entité
|
||||
|
||||
```bash
|
||||
GET /api/files/browse?path=entites/5/operations&sort=name&order=asc
|
||||
```
|
||||
|
||||
### Recherche de tous les exports Excel
|
||||
|
||||
```bash
|
||||
GET /api/files/search?q=export&type=xlsx&category=export
|
||||
```
|
||||
|
||||
### Statistiques de stockage
|
||||
|
||||
```bash
|
||||
GET /api/files/stats
|
||||
```
|
||||
|
||||
### Téléchargement d'un fichier
|
||||
|
||||
```bash
|
||||
GET /api/files/download/123
|
||||
```
|
||||
|
||||
### Suppression d'un fichier
|
||||
|
||||
```bash
|
||||
DELETE /api/files/123
|
||||
```
|
||||
|
||||
## Codes d'erreur
|
||||
|
||||
- **401** : Non authentifié
|
||||
- **403** : Accès refusé (rôle insuffisant ou fichier d'une autre entité)
|
||||
- **404** : Fichier ou chemin non trouvé
|
||||
- **400** : Paramètres invalides (terme de recherche manquant, etc.)
|
||||
- **500** : Erreur serveur
|
||||
|
||||
## Migration base de données
|
||||
|
||||
Pour utiliser le système, exécuter la migration :
|
||||
|
||||
```sql
|
||||
-- Ajout de la colonne file_category
|
||||
ALTER TABLE `medias`
|
||||
ADD COLUMN `file_category` varchar(50) DEFAULT NULL COMMENT 'Catégorie du fichier (logo, carte, photo, document, etc.)' AFTER `file_type`;
|
||||
|
||||
-- Index pour optimiser les requêtes
|
||||
ALTER TABLE `medias`
|
||||
ADD INDEX `idx_file_category` (`file_category`);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Version** : 1.0
|
||||
**Date** : Juin 2025
|
||||
**Auteur** : API Geosector Team
|
||||
339
api/docs/README-UPLOAD.md
Normal file
339
api/docs/README-UPLOAD.md
Normal file
@@ -0,0 +1,339 @@
|
||||
# Système de Gestion des Fichiers - API Geosector
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
Ce document décrit l'organisation et la gestion des fichiers uploadés dans l'API Geosector. Le système permet de stocker et organiser différents types de fichiers par entité, utilisateur, opération et passage.
|
||||
|
||||
## Structure des Dossiers
|
||||
|
||||
```
|
||||
uploads/
|
||||
├── entites/
|
||||
│ ├── {entite_id}/
|
||||
│ │ ├── documents/ # PDF, Excel généraux de l'entité
|
||||
│ │ ├── images/ # Images de l'entité
|
||||
│ │ ├── users/ # Dossier pour les fichiers des utilisateurs
|
||||
│ │ │ └── {user_id}/ # Images par utilisateur (avatars, etc.)
|
||||
│ │ └── operations/ # Dossier pour les opérations
|
||||
│ │ └── {operation_id}/
|
||||
│ │ ├── documents/ # Fichiers Excel de l'opération
|
||||
│ │ └── passages/ # Fichiers des passages de cette opération
|
||||
│ │ └── {passage_id}/ # PDF et images par passage
|
||||
│ └── temp/ # Fichiers temporaires avant validation
|
||||
```
|
||||
|
||||
### Exemples de chemins
|
||||
|
||||
- Document d'entité : `uploads/entites/5/documents/reglement_2024.pdf`
|
||||
- Avatar utilisateur : `uploads/entites/5/users/123/avatar.jpg`
|
||||
- Excel d'opération : `uploads/entites/5/operations/2644/documents/planning.xlsx`
|
||||
- Photo de passage : `uploads/entites/5/operations/2644/passages/789/photo_1.jpg`
|
||||
|
||||
## Structure de la Table `medias`
|
||||
|
||||
### Table existante enrichie
|
||||
|
||||
```sql
|
||||
-- Structure complète de la table medias
|
||||
CREATE TABLE `medias` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`support` varchar(45) NOT NULL DEFAULT '' COMMENT 'Type de support (entite, user, operation, passage)',
|
||||
`support_id` int(10) unsigned NOT NULL DEFAULT 0 COMMENT 'ID de l\'élément associé',
|
||||
`fichier` varchar(250) NOT NULL DEFAULT '' COMMENT 'Nom du fichier stocké',
|
||||
`file_type` varchar(50) DEFAULT NULL COMMENT 'Extension du fichier (pdf, jpg, xlsx, etc.)',
|
||||
`file_size` int(10) unsigned DEFAULT NULL COMMENT 'Taille du fichier en octets',
|
||||
`mime_type` varchar(100) DEFAULT NULL COMMENT 'Type MIME du fichier',
|
||||
`original_name` varchar(255) DEFAULT NULL COMMENT 'Nom original du fichier uploadé',
|
||||
`fk_entite` int(10) unsigned DEFAULT NULL COMMENT 'ID de l\'entité propriétaire',
|
||||
`fk_operation` int(10) unsigned DEFAULT NULL COMMENT 'ID de l\'opération (pour passages)',
|
||||
`file_path` varchar(500) DEFAULT NULL COMMENT 'Chemin complet du fichier',
|
||||
`original_width` int(10) unsigned DEFAULT NULL COMMENT 'Largeur originale de l\'image',
|
||||
`original_height` int(10) unsigned DEFAULT NULL COMMENT 'Hauteur originale de l\'image',
|
||||
`processed_width` int(10) unsigned DEFAULT NULL COMMENT 'Largeur après traitement',
|
||||
`processed_height` int(10) unsigned DEFAULT NULL COMMENT 'Hauteur après traitement',
|
||||
`is_processed` tinyint(1) unsigned DEFAULT 0 COMMENT 'Image redimensionnée (1) ou originale (0)',
|
||||
`description` varchar(100) NOT NULL DEFAULT '' COMMENT 'Description du fichier',
|
||||
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`fk_user_creat` int(10) unsigned NOT NULL DEFAULT 0,
|
||||
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp(),
|
||||
`fk_user_modif` int(10) unsigned NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `id_UNIQUE` (`id`),
|
||||
KEY `idx_entite` (`fk_entite`),
|
||||
KEY `idx_operation` (`fk_operation`),
|
||||
KEY `idx_support_type` (`support`, `support_id`),
|
||||
KEY `idx_file_type` (`file_type`),
|
||||
CONSTRAINT `fk_medias_entite` FOREIGN KEY (`fk_entite`) REFERENCES `entites` (`id`) ON UPDATE CASCADE ON DELETE CASCADE,
|
||||
CONSTRAINT `fk_medias_operation` FOREIGN KEY (`fk_operation`) REFERENCES `operations` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
```
|
||||
|
||||
### Migration SQL pour table existante
|
||||
|
||||
```sql
|
||||
-- Ajout des nouvelles colonnes à la table existante
|
||||
ALTER TABLE `medias`
|
||||
ADD COLUMN `file_type` varchar(50) DEFAULT NULL COMMENT 'Extension du fichier (pdf, jpg, xlsx, etc.)' AFTER `fichier`,
|
||||
ADD COLUMN `file_size` int(10) unsigned DEFAULT NULL COMMENT 'Taille du fichier en octets' AFTER `file_type`,
|
||||
ADD COLUMN `mime_type` varchar(100) DEFAULT NULL COMMENT 'Type MIME du fichier' AFTER `file_size`,
|
||||
ADD COLUMN `original_name` varchar(255) DEFAULT NULL COMMENT 'Nom original du fichier uploadé' AFTER `mime_type`,
|
||||
ADD COLUMN `fk_entite` int(10) unsigned DEFAULT NULL COMMENT 'ID de l\'entité propriétaire' AFTER `support_id`,
|
||||
ADD COLUMN `fk_operation` int(10) unsigned DEFAULT NULL COMMENT 'ID de l\'opération (pour passages)' AFTER `fk_entite`,
|
||||
ADD COLUMN `file_path` varchar(500) DEFAULT NULL COMMENT 'Chemin complet du fichier' AFTER `original_name`,
|
||||
ADD COLUMN `original_width` int(10) unsigned DEFAULT NULL COMMENT 'Largeur originale de l\'image' AFTER `file_path`,
|
||||
ADD COLUMN `original_height` int(10) unsigned DEFAULT NULL COMMENT 'Hauteur originale de l\'image' AFTER `original_width`,
|
||||
ADD COLUMN `processed_width` int(10) unsigned DEFAULT NULL COMMENT 'Largeur après traitement' AFTER `original_height`,
|
||||
ADD COLUMN `processed_height` int(10) unsigned DEFAULT NULL COMMENT 'Hauteur après traitement' AFTER `processed_width`,
|
||||
ADD COLUMN `is_processed` tinyint(1) unsigned DEFAULT 0 COMMENT 'Image redimensionnée (1) ou originale (0)' AFTER `processed_height`;
|
||||
|
||||
-- Ajout des index pour optimiser les requêtes
|
||||
ALTER TABLE `medias`
|
||||
ADD INDEX `idx_entite` (`fk_entite`),
|
||||
ADD INDEX `idx_operation` (`fk_operation`),
|
||||
ADD INDEX `idx_support_type` (`support`, `support_id`),
|
||||
ADD INDEX `idx_file_type` (`file_type`);
|
||||
|
||||
-- Ajout des contraintes de clés étrangères
|
||||
ALTER TABLE `medias`
|
||||
ADD CONSTRAINT `fk_medias_entite` FOREIGN KEY (`fk_entite`) REFERENCES `entites` (`id`) ON UPDATE CASCADE ON DELETE CASCADE,
|
||||
ADD CONSTRAINT `fk_medias_operation` FOREIGN KEY (`fk_operation`) REFERENCES `operations` (`id`) ON UPDATE CASCADE ON DELETE CASCADE;
|
||||
```
|
||||
|
||||
## Types de Support
|
||||
|
||||
### 1. Entité (`support = 'entite'`)
|
||||
|
||||
- **Fichiers autorisés** : PDF, Excel, Images (JPG, PNG)
|
||||
- **Taille max** : 20 MB
|
||||
- **Usage** : Documents généraux de l'entité (règlements, statuts, etc.)
|
||||
- **Chemin** : `uploads/entites/{entite_id}/documents/`
|
||||
|
||||
### 2. Utilisateur (`support = 'user'`)
|
||||
|
||||
- **Fichiers autorisés** : Images uniquement (JPG, PNG, GIF, WebP)
|
||||
- **Taille max** : 5 MB
|
||||
- **Usage** : Avatars, photos de profil
|
||||
- **Chemin** : `uploads/entites/{entite_id}/users/{user_id}/`
|
||||
- **Traitement** : Redimensionnement automatique
|
||||
|
||||
### 3. Opération (`support = 'operation'`)
|
||||
|
||||
- **Fichiers autorisés** : Excel uniquement (XLS, XLSX)
|
||||
- **Taille max** : 20 MB
|
||||
- **Usage** : Plannings, listes, données d'opération
|
||||
- **Chemin** : `uploads/entites/{entite_id}/operations/{operation_id}/documents/`
|
||||
|
||||
### 4. Passage (`support = 'passage'`)
|
||||
|
||||
- **Fichiers autorisés** : PDF et Images (JPG, PNG, PDF)
|
||||
- **Taille max** : 10 MB par fichier
|
||||
- **Usage** : Reçus, photos de passage, justificatifs
|
||||
- **Chemin** : `uploads/entites/{entite_id}/operations/{operation_id}/passages/{passage_id}/`
|
||||
- **Traitement** : Redimensionnement automatique pour les images
|
||||
|
||||
## Traitement Automatique des Images
|
||||
|
||||
### Règles de redimensionnement
|
||||
|
||||
- **Dimension maximale** : 250px (hauteur ou largeur, selon la plus grande)
|
||||
- **Résolution** : 72 DPI (optimisé web)
|
||||
- **Préservation du ratio** : Redimensionnement proportionnel
|
||||
- **Formats supportés** : JPG, PNG, GIF, WebP
|
||||
- **Qualité JPEG** : 85% (bon compromis qualité/poids)
|
||||
|
||||
### Exemples de transformation
|
||||
|
||||
```
|
||||
Image originale 1000x800px → Image traitée 250x200px
|
||||
Image originale 600x1200px → Image traitée 125x250px
|
||||
Image originale 200x150px → Pas de redimensionnement (déjà < 250px)
|
||||
```
|
||||
|
||||
### Workflow de traitement
|
||||
|
||||
1. **Upload** → Validation du type MIME
|
||||
2. **Analyse** → Détection des dimensions originales
|
||||
3. **Traitement** → Redimensionnement si nécessaire
|
||||
4. **Optimisation** → Compression et résolution web
|
||||
5. **Sauvegarde** → Image optimisée + métadonnées
|
||||
6. **Nettoyage** → Suppression du fichier temporaire
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Routes de gestion des fichiers
|
||||
|
||||
```php
|
||||
// Upload de fichiers
|
||||
POST /api/medias/upload
|
||||
Content-Type: multipart/form-data
|
||||
Body: {
|
||||
"file": [fichier],
|
||||
"support": "entite|user|operation|passage",
|
||||
"support_id": 123,
|
||||
"description": "Description du fichier"
|
||||
}
|
||||
|
||||
// Récupération d'un fichier
|
||||
GET /api/medias/{id}
|
||||
|
||||
// Liste des fichiers par support
|
||||
GET /api/medias/list/{support}/{support_id}
|
||||
|
||||
// Suppression d'un fichier
|
||||
DELETE /api/medias/{id}
|
||||
```
|
||||
|
||||
### Exemples de requêtes
|
||||
|
||||
#### Upload d'un avatar utilisateur
|
||||
|
||||
```bash
|
||||
curl -X POST "https://api.geosector.fr/medias/upload" \
|
||||
-H "Authorization: Bearer {token}" \
|
||||
-F "file=@avatar.jpg" \
|
||||
-F "support=user" \
|
||||
-F "support_id=123" \
|
||||
-F "description=Avatar utilisateur"
|
||||
```
|
||||
|
||||
#### Upload d'une photo de passage
|
||||
|
||||
```bash
|
||||
curl -X POST "https://api.geosector.fr/medias/upload" \
|
||||
-H "Authorization: Bearer {token}" \
|
||||
-F "file=@photo_passage.jpg" \
|
||||
-F "support=passage" \
|
||||
-F "support_id=789" \
|
||||
-F "description=Photo du passage"
|
||||
```
|
||||
|
||||
## Sécurité et Contrôles
|
||||
|
||||
### Validation des fichiers
|
||||
|
||||
- **Types MIME** : Vérification stricte du type de fichier
|
||||
- **Extensions** : Validation de l'extension par rapport au contenu
|
||||
- **Taille** : Limite selon le type de support
|
||||
- **Contenu** : Scan antivirus recommandé en production
|
||||
|
||||
### Contrôles d'accès
|
||||
|
||||
- **Authentification** : Token JWT requis
|
||||
- **Autorisation** : Utilisateur ne peut accéder qu'aux fichiers de son entité
|
||||
- **Vérification** : Contrôle que l'utilisateur appartient à l'entité du fichier
|
||||
- **Logs** : Traçabilité complète des uploads et accès
|
||||
|
||||
### Nommage des fichiers
|
||||
|
||||
```php
|
||||
// Format : {timestamp}_{random}_{sanitized_name}.{extension}
|
||||
// Exemple : 1640995200_a1b2c3_document_reglement.pdf
|
||||
```
|
||||
|
||||
## Gestion des Erreurs
|
||||
|
||||
### Codes d'erreur HTTP
|
||||
|
||||
- **400** : Fichier invalide ou paramètres manquants
|
||||
- **401** : Non authentifié
|
||||
- **403** : Accès refusé à cette entité
|
||||
- **413** : Fichier trop volumineux
|
||||
- **415** : Type de fichier non supporté
|
||||
- **500** : Erreur serveur lors du traitement
|
||||
|
||||
### Messages d'erreur
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "error",
|
||||
"message": "Type de fichier non autorisé pour ce support",
|
||||
"code": "INVALID_FILE_TYPE",
|
||||
"allowed_types": ["jpg", "png", "gif", "webp"]
|
||||
}
|
||||
```
|
||||
|
||||
## Maintenance et Nettoyage
|
||||
|
||||
### Nettoyage automatique
|
||||
|
||||
- **Fichiers temporaires** : Suppression après 24h
|
||||
- **Fichiers orphelins** : Détection et suppression des fichiers sans référence en base
|
||||
- **Anciennes opérations** : Suppression en cascade lors de la suppression d'une opération
|
||||
|
||||
### Commandes de maintenance
|
||||
|
||||
```bash
|
||||
# Nettoyage des fichiers temporaires
|
||||
php scripts/cleanup_temp_files.php
|
||||
|
||||
# Détection des fichiers orphelins
|
||||
php scripts/find_orphan_files.php
|
||||
|
||||
# Statistiques d'utilisation
|
||||
php scripts/storage_stats.php
|
||||
```
|
||||
|
||||
## Performances et Optimisation
|
||||
|
||||
### Optimisations
|
||||
|
||||
- **CDN** : Recommandé pour la distribution des fichiers
|
||||
- **Cache** : Headers de cache appropriés pour les fichiers statiques
|
||||
- **Compression** : Gzip pour les réponses API
|
||||
- **Index** : Index optimisés sur la table medias
|
||||
|
||||
### Monitoring
|
||||
|
||||
- **Espace disque** : Surveillance de l'utilisation
|
||||
- **Performance** : Temps de traitement des images
|
||||
- **Erreurs** : Logs des échecs d'upload et de traitement
|
||||
|
||||
## Exemples d'Utilisation
|
||||
|
||||
### Cas d'usage typiques
|
||||
|
||||
1. **Upload d'avatar utilisateur**
|
||||
|
||||
- Fichier JPG de 2MB
|
||||
- Redimensionnement automatique à 250x250px
|
||||
- Stockage dans `uploads/entites/5/users/123/`
|
||||
|
||||
2. **Document d'opération**
|
||||
|
||||
- Fichier Excel de planning
|
||||
- Stockage dans `uploads/entites/5/operations/2644/documents/`
|
||||
- Pas de traitement (fichier conservé tel quel)
|
||||
|
||||
3. **Photo de passage**
|
||||
- Photo JPG de 8MB prise sur mobile
|
||||
- Redimensionnement automatique à 250px max
|
||||
- Stockage dans `uploads/entites/5/operations/2644/passages/789/`
|
||||
|
||||
### Intégration frontend
|
||||
|
||||
```javascript
|
||||
// Upload avec progress
|
||||
const uploadFile = async (file, support, supportId, description) => {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append('support', support);
|
||||
formData.append('support_id', supportId);
|
||||
formData.append('description', description);
|
||||
|
||||
const response = await fetch('/api/medias/upload', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
body: formData,
|
||||
});
|
||||
|
||||
return response.json();
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Version** : 1.0
|
||||
**Date** : Juin 2025
|
||||
**Auteur** : API Geosector Team
|
||||
@@ -237,17 +237,37 @@ CREATE TABLE `entites` (
|
||||
|
||||
CREATE TABLE `medias` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`support` varchar(45) NOT NULL DEFAULT '',
|
||||
`support_id` int(10) unsigned NOT NULL DEFAULT 0,
|
||||
`fichier` varchar(250) NOT NULL DEFAULT '',
|
||||
`description` varchar(100) NOT NULL DEFAULT '',
|
||||
`support` varchar(45) NOT NULL DEFAULT '' COMMENT 'Type de support (entite, user, operation, passage)',
|
||||
`support_id` int(10) unsigned NOT NULL DEFAULT 0 COMMENT 'ID de élément associé',
|
||||
`fichier` varchar(250) NOT NULL DEFAULT '' COMMENT 'Nom du fichier stocké',
|
||||
`file_type` varchar(50) DEFAULT NULL COMMENT 'Extension du fichier (pdf, jpg, xlsx, etc.)',
|
||||
`file_category` varchar(50) DEFAULT NULL COMMENT 'export, logo, carte, etc.',
|
||||
`file_size` int(10) unsigned DEFAULT NULL COMMENT 'Taille du fichier en octets',
|
||||
`mime_type` varchar(100) DEFAULT NULL COMMENT 'Type MIME du fichier',
|
||||
`original_name` varchar(255) DEFAULT NULL COMMENT 'Nom original du fichier uploadé',
|
||||
`fk_entite` int(10) unsigned DEFAULT NULL COMMENT 'ID de entité propriétaire',
|
||||
`fk_operation` int(10) unsigned DEFAULT NULL COMMENT 'ID de opération (pour passages)',
|
||||
`file_path` varchar(500) DEFAULT NULL COMMENT 'Chemin complet du fichier',
|
||||
`original_width` int(10) unsigned DEFAULT NULL COMMENT 'Largeur originale de image',
|
||||
`original_height` int(10) unsigned DEFAULT NULL COMMENT 'Hauteur originale de image',
|
||||
`processed_width` int(10) unsigned DEFAULT NULL COMMENT 'Largeur après traitement',
|
||||
`processed_height` int(10) unsigned DEFAULT NULL COMMENT 'Hauteur après traitement',
|
||||
`is_processed` tinyint(1) unsigned DEFAULT 0 COMMENT 'Image redimensionnée (1) ou originale (0)',
|
||||
`description` varchar(100) NOT NULL DEFAULT '' COMMENT 'Description du fichier',
|
||||
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`fk_user_creat` int(10) unsigned NOT NULL DEFAULT 0,
|
||||
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp(),
|
||||
`fk_user_modif` int(10) unsigned NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `id_UNIQUE` (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=176 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||
UNIQUE KEY `id_UNIQUE` (`id`),
|
||||
KEY `idx_entite` (`fk_entite`),
|
||||
KEY `idx_operation` (`fk_operation`),
|
||||
KEY `idx_support_type` (`support`, `support_id`),
|
||||
KEY `idx_file_type` (`file_type`),
|
||||
KEY `idx_file_category` (`file_category`),
|
||||
CONSTRAINT `fk_medias_entite` FOREIGN KEY (`fk_entite`) REFERENCES `entites` (`id`) ON UPDATE CASCADE ON DELETE CASCADE,
|
||||
CONSTRAINT `fk_medias_operation` FOREIGN KEY (`fk_operation`) REFERENCES `operations` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE `ope_pass` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
@@ -375,22 +395,6 @@ CREATE TABLE `ope_users_sectors` (
|
||||
CONSTRAINT `ope_users_sectors_ibfk_3` FOREIGN KEY (`fk_sector`) REFERENCES `ope_sectors` (`id`) ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=48082 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||
|
||||
CREATE TABLE `ope_users_suivis` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`fk_operation` int(10) unsigned NOT NULL DEFAULT 0,
|
||||
`fk_user` int(10) unsigned NOT NULL DEFAULT 0,
|
||||
`date_suivi` timestamp NOT NULL DEFAULT current_timestamp() COMMENT 'Date du suivi',
|
||||
`gps_lat` varchar(20) NOT NULL DEFAULT '',
|
||||
`gps_lng` varchar(20) NOT NULL DEFAULT '',
|
||||
`vitesse` varchar(20) NOT NULL DEFAULT '',
|
||||
`created_at` timestamp NOT NULL DEFAULT current_timestamp() COMMENT 'Date de création',
|
||||
`fk_user_creat` int(10) unsigned NOT NULL DEFAULT 0,
|
||||
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp() COMMENT 'Date de modification',
|
||||
`fk_user_modif` int(10) unsigned NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `id_UNIQUE` (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci `PAGE_COMPRESSED`='ON';
|
||||
|
||||
CREATE TABLE `operations` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`fk_entite` int(10) unsigned NOT NULL DEFAULT 1,
|
||||
|
||||
Reference in New Issue
Block a user