# OHMJ API Documentation API REST pour la gestion des partitions de l'Harmonie de Montpellier-Jacou. ## Installation Prérequis : **PHP 8.5** avec les extensions `gd`, `zlib`, `curl`. ```bash cd api php composer.phar install # vendor/ est déjà présent dans le dépôt cp .env.example .env # puis définir JWT_SECRET ``` Dépendances (`composer.json`) : | Package | Rôle | |---|---| | `setasign/fpdi` | import de pages PDF (watermark) | | `setasign/fpdf` | génération PDF de base | | `tecnickcom/tcpdf` | boîte à outils PDF | ## Base URL ``` http://localhost:8000 ``` ## Authentification L'API utilise JWT (JSON Web Token) pour l'authentification. ### Login ```http POST /login Content-Type: application/json ``` **Corps de la requête :** ```json { "username": "admin", "password": "password" } ``` **Réponse :** ```json { "success": true, "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "user": { "username": "admin", "role": "admin" } } ``` **Rôles disponibles :** - `admin` - Accès complet - `user` - Accès lecture seule ### Utilisation du token Inclure le token dans l'en-tête `Authorization` : ```http Authorization: Bearer ``` --- ## Endpoints ### GET /scores Liste toutes les partitions. ```http GET /scores ``` **Réponse :** ```json { "success": true, "scores": [ { "id": "102", "name": "A Legend from Yao", "compositor": "Yeh Shu-Han", "ressource": "https://youtube.com/watch?v=xxx" }, { "id": "390", "name": "La part d Euterpe", "compositor": "Michael CUVILLON" } ] } ``` --- ### GET /scores/:id Détails d'une partition. Pour les partitions multi-morceaux (ex: 390), retourne tous les instruments de toutes les pièces. ```http GET /scores/102 GET /scores/390 ``` **Réponse (score simple) :** ```json { "success": true, "score": { "id": "102", "name": "A Legend from Yao", "compositor": "Yeh Shu-Han", "ressource": "https://youtube.com/watch?v=xxx", "instruments": [ { "id": "cla", "title": "Clarinette", "piece": "1", "parts": [ { "id": "1", "files": [ { "name": "clarinette-sib-1", "filename": "clarinette-sib-1.pdf", "path": "102/1/cla/1/clarinette-sib-1.pdf", "part": "1", "key": "sib", "clef": null, "variant": null } ] } ] } ] } } ``` **Réponse (partition multi-morceaux comme 390) :** ```json { "success": true, "score": { "id": "390", "name": "La part d Euterpe", "compositor": "Michael CUVILLON", "instruments": [ { "id": "cla", "title": "Clarinette", "piece": "1", "parts": [...] }, { "id": "sax", "title": "Sax Alto", "piece": "2", "parts": [...] } ] } } ``` --- ### GET /scores/:id/instruments Liste les instruments d'une partition. Pour les partitions multi-morceaux (ex: 390), peut filtrer par pièce. ```http GET /scores/102/instruments GET /scores/390/instruments?piece=1 ``` **Paramètre optionnel :** - `piece` - Numéro de la pièce (pour partitions multi-morceaux) **Réponse :** ```json { "success": true, "instruments": [ { "id": "cla", "title": "Clarinette", "piece": "1", "parts": [ { "id": "1", "files": [ { "name": "clarinette-sib-1", "filename": "clarinette-sib-1.pdf", "path": "102/1/cla/1/clarinette-sib-1.pdf", "part": "1", "key": "sib", "clef": null, "variant": null } ] } ] } ] } ``` **Champs des fichiers :** - `name` - Nom du fichier sans extension - `filename` - Nom du fichier avec extension - `path` - Chemin relatif pour download - `part` - Numéro de partie (ex: "1", "2_3") - `key` - Tonalité (ex: "sib", "mib", "fa") - `clef` - Clé (ex: "clesol", "clefa") - `variant` - Variante (ex: "solo", "default") --- ### GET /pieces/:scoreId Liste les pièces d'une partition. ```http GET /pieces/102 ``` **Réponse :** ```json { "success": true, "pieces": [ { "id": 1, "name": "Pièce 1" } ] } ``` --- ### GET /download/:path Télécharge un fichier PDF. ```http GET /download/102/1/cla/1/clarinette-sib-1.pdf ``` **Réponse :** Fichier PDF (Content-Type: application/pdf) **Structure des chemins :** ``` NUM/PIECE/INSTRUMENT/VERSION/PARTIE.pdf ``` **Instruments disponibles :** | Code | Instrument | |------|------------| | dir | Direction | | pic | Piccolo | | flu | Flûte | | cla | Clarinette | | clb | Clarinette basse | | sax | Saxophone alto | | sab | Saxophone baryton | | sat | Saxophone ténor | | coa | Cor anglais | | cba | Contrebasse | | cor | Cor | | trp | Trompette | | trb | Trombone | | tub | Tuba | | htb | Hautbois | | bas | Basson | | per | Percussion | | crn | Cornet | | eup | Euphonium | | har | Harpe | | pia | Piano | | sup | Parties combinées ("supérieur") | | par | Parties combinées | --- ## Routes Admin ### POST /admin/scores Créer une nouvelle partition. ```http POST /admin/scores Authorization: Bearer Content-Type: application/json ``` **Corps de la requête :** ```json { "id": "200", "name": "Nouvelle partition", "compositor": "Compositeur" } ``` --- ### PUT /admin/scores/:id Mettre à jour une partition. ```http PUT /admin/scores/102 Authorization: Bearer Content-Type: application/json ``` **Corps de la requête :** ```json { "name": "Nouveau nom", "compositor": "Nouveau compositeur", "ressource": "https://youtube.com/watch?v=xxx" } ``` **Paramètres optionnels :** - `name` - Nom du morceau - `compositor` - Nom du compositeur - `ressource` - Lien externe (YouTube, site éditeur, etc.) > **Bug connu :** `ressource` n'est actuellement **pas persisté** par cette route > (`ScoreScanner::updateScore()` n'accepte pas le paramètre et la reconstruction de > `score.ini` ne réécrit pas `ressource`). À corriger côté backend. --- ### DELETE /admin/scores/:id Supprimer une partition. ```http DELETE /admin/scores/102 Authorization: Bearer ``` --- ### GET /admin/scores/:id/files Récupérer l'arborescence des fichiers d'une partition. ```http GET /admin/scores/001/files Authorization: Bearer ``` **Réponse :** ```json { "success": true, "files": [ { "name": "1", "path": "1", "type": "folder", "children": [ { "name": "cla", "path": "1/cla", "type": "folder", "children": [ { "name": "1", "path": "1/cla/1", "type": "folder", "children": [ { "name": "clarinette_sib_1.pdf", "path": "1/cla/1/clarinette_sib_1.pdf", "type": "file" } ] } ] } ] } ] } ``` --- ### DELETE /admin/scores/:id/files Supprimer un fichier spécifique. ```http DELETE /admin/scores/001/files?path=1/cla/1/clarinette_sib_1.pdf Authorization: Bearer ``` **Paramètres :** - `path` - Chemin relatif du fichier (requis) --- ### POST /admin/scores/:id/upload Uploader un fichier PDF pour une partition. ```http POST /admin/scores/001/upload Authorization: Bearer Content-Type: multipart/form-data ``` **Corps de la requête :** ``` file: piece: 1 instrument: cla version: 1 key: sib (optionnel) clef: clesol (optionnel) variant: solo (optionnel) part: 1 (optionnel, défaut: 1) watermark: true (optionnel) # ajoute le numéro de partition sur le PDF watermarkPosition: left|right (optionnel, défaut: left) ``` --- ## Codes d'erreur | Code | Description | |------|-------------| | 200 | Succès | | 400 | Requête invalide (champ manquant, payload incorrect) | | 401 | Non authentifié | | 403 | Accès interdit (rôle insuffisant) | | 404 | Ressource non trouvée | | 413 | Fichier trop volumineux | | 429 | Trop de requêtes (rate limiting) | | 500 | Erreur serveur | --- ## Lancer les tests ```bash cd api php tests.php ``` Les tests vérifient : - **Auth** : Login, mauvais mots de passe, token manquant/invalide - **Scores** : CRUD, gestion d'erreurs pour ressources inexistantes - **Create Score with Pieces** : Création avec plusieurs parties, vérification score.ini - **Files** : Get files tree, suppression de fichiers --- ## Lancer le serveur ```bash cd api php -c php-upload.ini -S localhost:8000 router.php ``` > `-c php-upload.ini` est requis pour autoriser l'upload de PDF (64M max). > `ini_set()` ne peut pas modifier `upload_max_filesize`/`post_max_size` à l'exécution. > L'API répond sur `http://localhost:8000` (sans préfixe `/api`). --- ## Structure des fichiers ``` legacy/Scores/ ├── 102/ │ ├── 1/ │ │ ├── cla/ │ │ │ ├── 1/ │ │ │ │ ├── clarinette-sib-1.pdf │ │ │ │ ├── clarinette-sib-2.pdf │ │ │ │ └── clarinette-mib-1.pdf │ │ │ └── 2/ │ │ │ └── clarinette-sib-1.pdf │ │ ├── flu/ │ │ └── sax/ │ └── 2/ └── score.ini ```