[FEAT] Full function and deployed version

This commit is contained in:
NADAL Jean-Baptiste
2026-02-19 15:15:58 +01:00
parent e7c4768589
commit cf0db69f2d
24 changed files with 6949 additions and 69 deletions

View File

@@ -1 +1,2 @@
JWT_SECRET=ohmj_test_secret_key_change_in_production_12345
JWT_SECRET=6jh/MWqVplwXQKsiwlKahE19TSavfR1dNCawsQFixus=
SCORES_PATH=/data/scores/

View File

@@ -70,7 +70,8 @@ GET /scores
{
"id": "102",
"name": "A Legend from Yao",
"compositor": "Yeh Shu-Han"
"compositor": "Yeh Shu-Han",
"ressource": "https://youtube.com/watch?v=xxx"
},
{
"id": "390",
@@ -100,6 +101,7 @@ GET /scores/390
"id": "102",
"name": "A Legend from Yao",
"compositor": "Yeh Shu-Han",
"ressource": "https://youtube.com/watch?v=xxx",
"instruments": [
{
"id": "cla",
@@ -307,10 +309,16 @@ Content-Type: application/json
```json
{
"name": "Nouveau nom",
"compositor": "Nouveau compositeur"
"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.)
---
### DELETE /admin/scores/:id

View File

@@ -1,4 +1,22 @@
<?php
// Load .env file if it exists
if (file_exists(__DIR__ . '/.env')) {
$lines = file(__DIR__ . '/.env', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($lines as $line) {
if (strpos($line, '#') === 0) continue;
if (strpos($line, '=') !== false) {
list($key, $value) = explode('=', $line, 2);
$key = trim($key);
$value = trim($value);
if (!getenv($key)) {
putenv("$key=$value");
$_ENV[$key] = $value;
$_SERVER[$key] = $value;
}
}
}
}
// Increase upload limits for this script
ini_set('upload_max_filesize', '64M');
ini_set('post_max_size', '64M');
@@ -12,11 +30,16 @@ header('Referrer-Policy: strict-origin-when-cross-origin');
header('Strict-Transport-Security: max-age=31536000; includeSubDomains');
// CORS - Restrict to allowed origins
$allowedOrigins = ['http://localhost:5173', 'http://localhost:3000', 'https://ohmj2.free.fr', 'https://partitions.ohmj.fr'];
$allowedOrigins = ['http://localhost:5173', 'http://localhost:3000', 'http://localhost:4173', 'https://ohmj2.free.fr', 'https://partitions.c.nadal-fr.com', 'https://ohmj-api.c.nadal-fr.com'];
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
// Always send CORS headers for preflight requests
if (in_array($origin, $allowedOrigins)) {
header("Access-Control-Allow-Origin: $origin");
header('Access-Control-Allow-Credentials: true');
} else {
// For preflight without matching origin, still allow (for debugging)
header("Access-Control-Allow-Origin: *");
}
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Authorization, Content-Type');
@@ -70,7 +93,11 @@ require_once __DIR__ . '/lib/Auth.php';
require_once __DIR__ . '/lib/ScoreScanner.php';
$auth = new Auth();
$scanner = new ScoreScanner('/home/jbnadal/sources/jb/ohmj/ohmj2/legacy/Scores/');
$scoresPath = getenv('SCORES_PATH');
if ($scoresPath === false || $scoresPath === '') {
$scoresPath = __DIR__ . '/../legacy/Scores/';
}
$scanner = new ScoreScanner($scoresPath);
// Get Authorization header
$token = null;
@@ -124,7 +151,7 @@ if (preg_match('#^download/([^?]+)#', $path, $matches) && $method === 'GET') {
exit;
}
$basePath = '/home/jbnadal/sources/jb/ohmj/ohmj2/legacy/Scores/';
$basePath = getenv('SCORES_PATH') ?: __DIR__ . '/../legacy/Scores/';
$fullPath = $basePath . $filePath;
// Security: Verify resolved path is within allowed directory
@@ -198,6 +225,11 @@ if ($user === null) {
// GET /scores - List all scores
if ($path === 'scores' && $method === 'GET') {
$scores = $scanner->listScores();
if (isset($scores['error'])) {
http_response_code(500);
echo json_encode(['success' => false, 'error' => $scores['error']]);
exit;
}
echo json_encode(['success' => true, 'scores' => $scores]);
exit;
}
@@ -297,8 +329,9 @@ if (preg_match('#^admin/scores/(\d+)$#', $path, $matches) && $method === 'PUT')
$name = $input['name'] ?? null;
$compositor = $input['compositor'] ?? null;
$ressource = $input['ressource'] ?? '';
$result = $scanner->updateScore($scoreId, $name, $compositor);
$result = $scanner->updateScore($scoreId, $name, $compositor, $ressource);
if ($result['success']) {
echo json_encode(['success' => true]);
@@ -332,13 +365,47 @@ if (preg_match('#^admin/scores/(\d+)$#', $path, $matches) && $method === 'DELETE
if (preg_match('#^admin/scores/(\d+)/upload$#', $path, $matches) && $method === 'POST') {
$scoreId = $matches[1];
// Check for upload errors
if (!isset($_FILES['file'])) {
// Check if post_max_size was exceeded
if (empty($_POST) && $_SERVER['CONTENT_LENGTH'] > 0) {
$maxSize = ini_get('post_max_size');
http_response_code(413);
echo json_encode(['error' => "File too large. Maximum size is $maxSize"]);
exit;
}
http_response_code(400);
echo json_encode(['error' => 'No file uploaded']);
exit;
}
$file = $_FILES['file'];
// Check for PHP upload errors
if ($file['error'] !== UPLOAD_ERR_OK) {
$errorMsg = 'Upload failed';
switch ($file['error']) {
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
$maxSize = ini_get('upload_max_filesize');
$errorMsg = "File too large. Maximum size is $maxSize";
http_response_code(413);
break;
case UPLOAD_ERR_PARTIAL:
$errorMsg = 'File was only partially uploaded';
http_response_code(400);
break;
case UPLOAD_ERR_NO_FILE:
$errorMsg = 'No file was uploaded';
http_response_code(400);
break;
default:
http_response_code(400);
}
echo json_encode(['error' => $errorMsg]);
exit;
}
$piece = $_POST['piece'] ?? '1';
$instrument = $_POST['instrument'] ?? '';
$version = $_POST['version'] ?? '1';

View File

@@ -7,6 +7,10 @@ class ScoreScanner {
}
public function getAllScores() {
if (!is_dir($this->scoresPath)) {
return ['error' => 'Scores directory not found: ' . $this->scoresPath];
}
$scores = [];
$directories = scandir($this->scoresPath);

View File

@@ -17,6 +17,25 @@ if (file_exists($envFile)) {
}
}
// CORS headers - MUST be sent before any other output
$allowedOrigins = ['http://localhost:5173', 'http://localhost:3000', 'http://localhost:4173', 'https://ohmj2.free.fr', 'https://partitions.c.nadal-fr.com', 'https://ohmj-api.c.nadal-fr.com'];
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
if (in_array($origin, $allowedOrigins)) {
header("Access-Control-Allow-Origin: $origin");
header('Access-Control-Allow-Credentials: true');
} else {
header("Access-Control-Allow-Origin: *");
}
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Authorization, Content-Type');
// Handle OPTIONS preflight immediately
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit;
}
// Router script for PHP built-in server
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);