Files
ohmj2/api/index.php
2026-02-18 14:04:34 +01:00

279 lines
8.2 KiB
PHP

<?php
// Increase upload limits for this script
ini_set('upload_max_filesize', '64M');
ini_set('post_max_size', '64M');
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Authorization, Content-Type');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(200);
exit;
}
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/');
// Get Authorization header
$token = null;
$headers = getallheaders();
if (isset($headers['Authorization'])) {
$authHeader = $headers['Authorization'];
if (preg_match('/Bearer\s+(.+)/i', $authHeader, $matches)) {
$token = $matches[1];
}
}
// Parse request
$method = $_SERVER['REQUEST_METHOD'];
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$path = trim($uri, '/');
// Remove 'api/' prefix if present
$path = preg_replace('#^api/#', '', $path);
// Debug: log the path
// file_put_contents('/tmp/api_debug.log', date('Y-m-d H:i:s') . " PATH: $path METHOD: $method\n", FILE_APPEND);
// GET /download/:path - Download PDF (BEFORE auth check)
if (preg_match('#^download/([^?]+)#', $path, $matches) && $method === 'GET') {
$filePath = urldecode($matches[1]);
// Check token from header or query parameter
$downloadToken = $_GET['token'] ?? $token;
$downloadToken = urldecode($downloadToken ?? '');
if ($downloadToken === null || $downloadToken === '') {
http_response_code(401);
echo json_encode(['error' => 'Authorization required']);
exit;
}
$user = $auth->verifyToken($downloadToken);
if ($user === null) {
http_response_code(401);
echo json_encode(['error' => 'Invalid token']);
exit;
}
$fullPath = '/home/jbnadal/sources/jb/ohmj/ohmj2/legacy/Scores/' . $filePath;
if (!file_exists($fullPath) || !is_file($fullPath)) {
http_response_code(404);
echo json_encode(['error' => 'File not found', 'path' => $fullPath]);
exit;
}
header('Content-Type: application/pdf');
header('Content-Length: ' . filesize($fullPath));
header('Content-Disposition: attachment; filename="' . basename($fullPath) . '"');
readfile($fullPath);
exit;
}
// Route matching
if (($path === 'login' || $path === 'api/login') && $method === 'POST') {
$input = json_decode(file_get_contents('php://input'), true);
$username = $input['username'] ?? '';
$password = $input['password'] ?? '';
$result = $auth->login($username, $password);
if ($result['success']) {
echo json_encode([
'success' => true,
'token' => $result['token'],
'user' => $result['user']
]);
} else {
http_response_code(401);
echo json_encode([
'success' => false,
'error' => $result['error']
]);
}
exit;
}
// Protected routes - require auth
if ($token === null) {
http_response_code(401);
echo json_encode(['error' => 'Authorization required']);
exit;
}
$user = $auth->verifyToken($token);
if ($user === null) {
http_response_code(401);
echo json_encode(['error' => 'Invalid token']);
exit;
}
// GET /scores - List all scores
if ($path === 'scores' && $method === 'GET') {
$scores = $scanner->listScores();
echo json_encode(['success' => true, 'scores' => $scores]);
exit;
}
// GET /scores/:id - Get score details
if (preg_match('#^scores/(\d+)$#', $path, $matches) && $method === 'GET') {
$scoreId = $matches[1];
$score = $scanner->getScore($scoreId);
if ($score === null) {
http_response_code(404);
echo json_encode(['error' => 'Score not found']);
exit;
}
echo json_encode(['success' => true, 'score' => $score]);
exit;
}
// GET /scores/:id/instruments - Get instruments for a score
// GET /scores/:id/instruments?piece=1 - Get instruments for a specific piece
if (preg_match('#^scores/(\d+)/instruments$#', $path, $matches) && $method === 'GET') {
$scoreId = $matches[1];
$pieceId = $_GET['piece'] ?? null;
$instruments = $scanner->getInstruments($scoreId, $pieceId);
echo json_encode(['success' => true, 'instruments' => $instruments]);
exit;
}
// GET /pieces/:scoreId - Get pieces for a score
if (preg_match('#^pieces/(\d+)$#', $path, $matches) && $method === 'GET') {
$scoreId = $matches[1];
$pieces = $scanner->getPieces($scoreId);
echo json_encode(['success' => true, 'pieces' => $pieces]);
exit;
}
// ADMIN ROUTES - require admin role
if ($user['role'] !== 'admin') {
http_response_code(403);
echo json_encode(['error' => 'Admin access required']);
exit;
}
// POST /admin/scores - Create new score
if ($path === 'admin/scores' && $method === 'POST') {
$input = json_decode(file_get_contents('php://input'), true);
$id = $input['id'] ?? null;
$name = $input['name'] ?? '';
$compositor = $input['compositor'] ?? '';
// Auto-generate ID if not provided
if (empty($id)) {
$scores = $scanner->listScores();
$maxId = 0;
foreach ($scores as $s) {
$num = intval($s['id']);
if ($num > $maxId) $maxId = $maxId;
}
// Find highest numeric ID
foreach ($scores as $s) {
$num = intval($s['id']);
if ($num > $maxId) $maxId = $num;
}
$id = strval($maxId + 1);
// Pad with zeros to 3 digits if needed
if (strlen($id) < 3) {
$id = str_pad($id, 3, '0', STR_PAD_LEFT);
}
}
if (empty($name)) {
http_response_code(400);
echo json_encode(['error' => 'ID and name required']);
exit;
}
$result = $scanner->createScore($id, $name, $compositor);
if ($result['success']) {
echo json_encode(['success' => true, 'score' => $result['score']]);
} else {
http_response_code(400);
echo json_encode(['error' => $result['error']]);
}
exit;
}
// PUT /admin/scores/:id - Update score
if (preg_match('#^admin/scores/(\d+)$#', $path, $matches) && $method === 'PUT') {
$scoreId = $matches[1];
$input = json_decode(file_get_contents('php://input'), true);
$name = $input['name'] ?? null;
$compositor = $input['compositor'] ?? null;
$result = $scanner->updateScore($scoreId, $name, $compositor);
if ($result['success']) {
echo json_encode(['success' => true]);
} else {
http_response_code(400);
echo json_encode(['error' => $result['error']]);
}
exit;
}
// DELETE /admin/scores/:id - Delete score
if (preg_match('#^admin/scores/(\d+)$#', $path, $matches) && $method === 'DELETE') {
$scoreId = $matches[1];
$result = $scanner->deleteScore($scoreId);
if ($result['success']) {
echo json_encode(['success' => true]);
} else {
http_response_code(400);
echo json_encode(['error' => $result['error']]);
}
exit;
}
// POST /admin/scores/:id/upload - Upload PDF
if (preg_match('#^admin/scores/(\d+)/upload$#', $path, $matches) && $method === 'POST') {
$scoreId = $matches[1];
if (!isset($_FILES['file'])) {
http_response_code(400);
echo json_encode(['error' => 'No file uploaded']);
exit;
}
$file = $_FILES['file'];
$piece = $_POST['piece'] ?? '1';
$instrument = $_POST['instrument'] ?? '';
$version = $_POST['version'] ?? '1';
$key = $_POST['key'] ?? '';
$clef = $_POST['clef'] ?? '';
$variant = $_POST['variant'] ?? '';
$part = $_POST['part'] ?? '1';
$result = $scanner->uploadPdf($scoreId, $file, $piece, $instrument, $version, $key, $clef, $variant, $part);
if ($result['success']) {
echo json_encode(['success' => true, 'path' => $result['path']]);
} else {
http_response_code(400);
echo json_encode(['error' => $result['error']]);
}
exit;
}
// 404 Not Found
http_response_code(404);
echo json_encode(['error' => 'Not found']);