[FEAT] Fix some bug and css issues.

This commit is contained in:
NADAL Jean-Baptiste
2026-09-15 11:46:02 +02:00
parent a38fc0bfa9
commit 71d3b71362
26 changed files with 829 additions and 418 deletions
+2 -1
View File
@@ -417,8 +417,9 @@ if (preg_match('#^admin/scores/(\d+)$#', $path, $matches) && $method === 'DELETE
$part = $_POST['part'] ?? '1';
$watermark = isset($_POST['watermark']) && $_POST['watermark'] === 'true';
$watermarkPosition = $_POST['watermarkPosition'] ?? 'left';
$combined = $_POST['combined'] ?? '';
$result = $scanner->uploadPdf($scoreId, $file, $piece, $instrument, $version, $key, $clef, $variant, $part, $watermark, $watermarkPosition);
$result = $scanner->uploadPdf($scoreId, $file, $piece, $instrument, $version, $key, $clef, $variant, $part, $watermark, $watermarkPosition, $combined);
if ($result['success']) {
echo json_encode(['success' => true, 'path' => $result['path']]);
+13 -14
View File
@@ -594,7 +594,7 @@ class ScoreScanner {
rmdir($dir);
}
public function uploadPdf(string $scoreId, array $file, string $piece, string $instrument, string $version, string $key = '', string $clef = '', string $variant = '', string $part = '1', bool $watermark = false, string $watermarkPosition = 'left'): array {
public function uploadPdf(string $scoreId, array $file, string $piece, string $instrument, string $version, string $key = '', string $clef = '', string $variant = '', string $part = '1', bool $watermark = false, string $watermarkPosition = 'left', ?string $combined = null): array {
// Security: every input used to build a path or a filename is validated
if (!$this->isValidSegment($scoreId, '/^\d{1,6}$/')) {
return ['success' => false, 'error' => 'Invalid score id'];
@@ -680,20 +680,19 @@ class ScoreScanner {
$instName = $instrumentNames[$instrument] ?? $instrument;
// Build filename: instrument_variant_key_clef_part.pdf
$filenameParts = [$instName];
if (!empty($variant)) {
$filenameParts[] = $variant;
if (in_array($instrument, ['sup', 'par'], true) && $combined !== null && trim($combined) !== '') {
// Combined/superposed parts keep their real instrument names (e.g. "contrebasse-1+clarinette-1")
$combined = strtolower(trim($combined));
if (!$this->isValidSegment($combined, '/^[a-z0-9_+.-]+$/')) {
return ['success' => false, 'error' => 'Invalid combined instruments'];
}
$filename = $combined . '.pdf';
} else {
// NAMING.md: fields separated by '-', compound names/suffixes by '_'
$nameParts = array_values(array_filter([$instName, $key, $variant, $clef], fn($v) => $v !== ''));
$nameParts[] = $part;
$filename = implode('-', $nameParts) . '.pdf';
}
if (!empty($key)) {
$filenameParts[] = $key;
}
if (!empty($clef)) {
$filenameParts[] = $clef;
}
$filenameParts[] = $part;
$filename = implode('_', $filenameParts) . '.pdf';
$targetPath = $targetDir . '/' . $filename;
+18 -7
View File
@@ -330,7 +330,7 @@ class APITest {
// Get files to verify it was uploaded (recursive tree)
$files = $this->request('GET', "admin/scores/$scoreId/files");
$found = $this->findTreeFile($files['body']['files'] ?? [], 'direction_1.pdf');
$found = $this->findTreeFile($files['body']['files'] ?? [], 'direction-1.pdf');
if ($found) {
require_once __DIR__ . '/vendor/autoload.php';
$check = new \setasign\Fpdi\Fpdi();
@@ -357,7 +357,7 @@ class APITest {
// Clean up all uploaded files (recursive) then the dedicated score
$files = $this->request('GET', "admin/scores/$scoreId/files");
$this->deleteTreeMatching($files['body']['files'] ?? [], $scoreId, 'direction_');
$this->deleteTreeMatching($files['body']['files'] ?? [], $scoreId, 'direction-');
$this->request('DELETE', "admin/scores/$scoreId");
}
@@ -682,6 +682,17 @@ class APITest {
$noFile = $this->request('POST', "admin/scores/$scoreId/upload", ['unexpected' => 'body']);
$this->test('Upload without file part returns 413', $noFile['code'] === 413);
// Combined/superposed parts are named after the combined instruments
$supUp = $this->multipartRequest("admin/scores/$scoreId/upload", [
['name' => 'file', 'file' => $tmpPdf],
['name' => 'piece', 'data' => '1'],
['name' => 'instrument', 'data' => 'sup'],
['name' => 'version', 'data' => '1'],
['name' => 'combined', 'data' => 'contrebasse-1+clarinette-1'],
]);
$this->test('Upload sup combined returns 200', $supUp['code'] === 200);
$this->test('Upload sup combined filename', str_contains($supUp['body']['path'] ?? '', 'contrebasse-1+clarinette-1.pdf'));
// Instruments (list + filter)
$instr = $this->request('GET', "scores/$scoreId/instruments");
$this->test('Instruments returns 200', $instr['code'] === 200);
@@ -693,7 +704,7 @@ class APITest {
$this->test('Pieces returns 200', $pieces['code'] === 200);
// Download success + failures
$path = "$scoreId/1/dir/1/direction_1.pdf";
$path = "$scoreId/1/dir/1/direction-1.pdf";
$ok = $this->request('GET', "download/$path");
$this->test('Download with token returns 200', $ok['code'] === 200);
$noToken = $this->request('GET', "download/$path", null, false);
@@ -742,7 +753,7 @@ class APITest {
}
// Delete uploaded file, then the score
$del = $this->request('DELETE', "admin/scores/$scoreId/files", null, true, ['path' => '1/dir/1/direction_1.pdf']);
$del = $this->request('DELETE', "admin/scores/$scoreId/files", null, true, ['path' => '1/dir/1/direction-1.pdf']);
$this->test('Delete file returns 200', $del['code'] === 200);
$delScore = $this->request('DELETE', "admin/scores/$scoreId");
$this->test('Delete score returns 200', $delScore['code'] === 200);
@@ -950,9 +961,9 @@ class APITest {
@chmod($base . '100/1/flu/1', 0555);
$this->test('Unit: upload copy failure', $scanner->uploadPdf('100', $file, '1', 'flu', '1')['success'] === false);
@chmod($base . '100/1/flu/1', 0755);
@mkdir($base . '100/1/dir/1/direction_1.pdf', 0777, true);
@mkdir($base . '100/1/dir/1/direction-1.pdf', 0777, true);
$this->test('Unit: uploadPdf rename failure', $scanner->uploadPdf('100', $wmFile, '1', 'dir', '1', '', '', '', '1', true, 'left')['success'] === false);
@rmdir($base . '100/1/dir/1/direction_1.pdf');
@rmdir($base . '100/1/dir/1/direction-1.pdf');
$this->test('Unit: getScoreFiles unknown', $scanner->getScoreFiles('999')['success'] === false);
$this->test('Unit: getScoreFiles ok', $scanner->getScoreFiles('100')['success'] === true);
@@ -970,7 +981,7 @@ class APITest {
@mkdir($base . '100/1/cla/1/subdir', 0777, true);
$this->test('Unit: deleteFile directory', $scanner->deleteScoreFile('100', '1/cla/1/subdir')['success'] === false);
@chmod($base . '100/1/flu/1', 0555);
$this->test('Unit: deleteFile unlink failure', $scanner->deleteScoreFile('100', '1/flu/1/flute_ut_clesol_1.pdf')['success'] === false);
$this->test('Unit: deleteFile unlink failure', $scanner->deleteScoreFile('100', '1/flu/1/flute-ut-clesol-1.pdf')['success'] === false);
@chmod($base . '100/1/flu/1', 0755);
// deleteScore + deleteDirectory