mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-06-25 16:19:19 +02:00
Combine phpstan, cs-check, cs-fix into lint-php recipe; fix lint issues + test failures + duplicate detection bug
This commit is contained in:
@@ -62,7 +62,7 @@ class MediaController
|
||||
exit;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
ErrorHandler::log('media_visibility', $e, ['path' => $path]);
|
||||
ErrorHandler::log('media_visibility', $e, ['path' => $requestedPath]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -164,19 +164,19 @@ class ThesisCreateController
|
||||
error_log("[ThesisCreate] Step 1 OK — thesis_id=$thesisId ($identifier) | authors=" . count($authorEntries));
|
||||
|
||||
$this->db->setThesisAuthors($thesisId, $authorEntries);
|
||||
error_log("[ThesisCreate] Step 2 OK — authors=" . json_encode($data['authorNames']));
|
||||
error_log('[ThesisCreate] Step 2 OK — authors=' . json_encode($data['authorNames']));
|
||||
|
||||
$this->db->setThesisJury($thesisId, $data['juryMembers']);
|
||||
error_log("[ThesisCreate] Step 3 OK — jury=" . count($data['juryMembers']));
|
||||
error_log('[ThesisCreate] Step 3 OK — jury=' . count($data['juryMembers']));
|
||||
|
||||
$this->db->setThesisLanguages($thesisId, $data['languageIds']);
|
||||
error_log("[ThesisCreate] Step 4 OK — languages=" . json_encode($data['languageIds']));
|
||||
error_log('[ThesisCreate] Step 4 OK — languages=' . json_encode($data['languageIds']));
|
||||
|
||||
$this->db->setThesisFormats($thesisId, $data['formatIds']);
|
||||
error_log("[ThesisCreate] Step 5 OK — formats=" . json_encode($data['formatIds']));
|
||||
error_log('[ThesisCreate] Step 5 OK — formats=' . json_encode($data['formatIds']));
|
||||
|
||||
$this->db->setThesisTags($thesisId, $data['keywords']);
|
||||
error_log("[ThesisCreate] Step 6 OK — tags=" . json_encode($data['keywords']));
|
||||
error_log('[ThesisCreate] Step 6 OK — tags=' . json_encode($data['keywords']));
|
||||
|
||||
$this->db->commit();
|
||||
error_log("[ThesisCreate] COMMIT OK — thesis_id=$thesisId");
|
||||
@@ -230,7 +230,7 @@ class ThesisCreateController
|
||||
*/
|
||||
public static function autofocusFieldForError(string $message): ?string
|
||||
{
|
||||
if (str_contains($message, "Auteur·ice")) {
|
||||
if (str_contains($message, 'Auteur·ice')) {
|
||||
return 'auteurice';
|
||||
}
|
||||
if (str_contains($message, 'Titre du TFE')) {
|
||||
@@ -420,13 +420,13 @@ class ThesisCreateController
|
||||
|
||||
// Keywords (max 10, min 3) — lowercased, spaces collapsed, deduplicated
|
||||
$keywords = [];
|
||||
$normalizeTag = fn(string $t): string => strtolower(trim(preg_replace('/\s+/', ' ', $t)));
|
||||
$normalizeTag = fn (string $t): string => strtolower(trim(preg_replace('/\s+/', ' ', $t)));
|
||||
if (isset($post['tag']) && is_array($post['tag'])) {
|
||||
$keywords = array_values(array_unique(array_map(
|
||||
$normalizeTag,
|
||||
array_map(fn($t) => (string)$t, $post['tag'])
|
||||
array_map(fn ($t) => (string)$t, $post['tag'])
|
||||
)));
|
||||
$keywords = array_filter($keywords, fn($t) => $t !== '');
|
||||
$keywords = array_filter($keywords, fn ($t) => $t !== '');
|
||||
$keywords = array_slice($keywords, 0, 10);
|
||||
} else {
|
||||
$tagRaw = $this->sanitiseString($post['tag'] ?? '');
|
||||
@@ -435,7 +435,7 @@ class ThesisCreateController
|
||||
}
|
||||
}
|
||||
$keywords = array_values(array_unique($keywords));
|
||||
$keywords = array_filter($keywords, fn($t) => $t !== '');
|
||||
$keywords = array_filter($keywords, fn ($t) => $t !== '');
|
||||
$keywords = array_slice($keywords, 0, 10);
|
||||
if (count($keywords) > 10) {
|
||||
throw new Exception('Maximum 10 mots-clés autorisés.');
|
||||
@@ -630,7 +630,7 @@ class ThesisCreateController
|
||||
null,
|
||||
null
|
||||
);
|
||||
error_log("ThesisCreateController: PeerTube upload OK → " . $result['watchUrl']);
|
||||
error_log('ThesisCreateController: PeerTube upload OK → ' . $result['watchUrl']);
|
||||
} catch (\Throwable $e) {
|
||||
error_log('ThesisCreateController: PeerTube upload failed — ' . $e->getMessage());
|
||||
// Non-fatal: thesis already saved; admin can re-upload manually.
|
||||
|
||||
@@ -278,12 +278,12 @@ class ThesisEditController
|
||||
error_log('[ThesisEdit] Step 5 OK — formats=' . json_encode($formatIds));
|
||||
|
||||
// ── 6. Tags ───────────────────────────────────────────────────────
|
||||
$normalizeTag = fn(string $t): string => strtolower(trim(preg_replace('/\s+/', ' ', $t)));
|
||||
$normalizeTag = fn (string $t): string => strtolower(trim(preg_replace('/\s+/', ' ', $t)));
|
||||
$keywords = [];
|
||||
if (isset($post['tag']) && is_array($post['tag'])) {
|
||||
$keywords = array_values(array_unique(array_map(
|
||||
$normalizeTag,
|
||||
array_map(fn($t) => (string)$t, $post['tag'])
|
||||
array_map(fn ($t) => (string)$t, $post['tag'])
|
||||
)));
|
||||
} else {
|
||||
$keywordsRaw = trim($post['tag'] ?? '');
|
||||
@@ -292,7 +292,7 @@ class ThesisEditController
|
||||
}
|
||||
}
|
||||
$keywords = array_values(array_unique($keywords));
|
||||
$keywords = array_filter($keywords, fn($t) => $t !== '');
|
||||
$keywords = array_filter($keywords, fn ($t) => $t !== '');
|
||||
$keywords = array_slice($keywords, 0, 10);
|
||||
if (count($keywords) < 1) {
|
||||
throw new Exception('Veuillez indiquer au moins 1 mot-clé.');
|
||||
@@ -587,67 +587,6 @@ class ThesisEditController
|
||||
return $members;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload PeerTube video/audio files from FilePond queue.
|
||||
*
|
||||
* Files arrive via PHP's nested $_FILES structure from
|
||||
* <input name="queue_file[peertube_video][]">.
|
||||
*
|
||||
* @param int $thesisId Thesis to attach the results to.
|
||||
* @param string $title Title to use on PeerTube.
|
||||
* @param array|null $uploads Flat $_FILES-style array from extractFilesSubArray().
|
||||
* @param string $fileType 'video' or 'audio'.
|
||||
*/
|
||||
private function handlePeerTubeQueueFiles(int $thesisId, string $title, ?array $uploads, string $fileType, ?string $progressToken = null): void
|
||||
{
|
||||
if (!$uploads || !is_array($uploads['name'] ?? null)) {
|
||||
return;
|
||||
}
|
||||
|
||||
require_once APP_ROOT . '/src/PeerTubeService.php';
|
||||
if (!PeerTubeService::isEnabled($this->db)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$label = $fileType === 'video' ? 'Vidéo' : 'Audio';
|
||||
$count = count($uploads['name']);
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
if (($uploads['error'][$i] ?? UPLOAD_ERR_NO_FILE) !== UPLOAD_ERR_OK) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$fileName = $uploads['name'][$i];
|
||||
if ($progressToken) {
|
||||
PeerTubeService::writeProgress($progressToken, 'peertube', 25 + (int)(($i / max($count, 1)) * 74), $label . ' : ' . $fileName);
|
||||
}
|
||||
|
||||
try {
|
||||
$result = PeerTubeService::upload(
|
||||
$this->db,
|
||||
$uploads['tmp_name'][$i],
|
||||
$fileName,
|
||||
$title,
|
||||
''
|
||||
);
|
||||
|
||||
$storedPath = 'peertube_ids:' . $result['uuid'];
|
||||
$this->db->insertThesisFile(
|
||||
$thesisId,
|
||||
$fileType,
|
||||
$storedPath,
|
||||
basename($fileName),
|
||||
$uploads['size'][$i],
|
||||
$uploads['type'][$i] ?? 'application/octet-stream',
|
||||
null,
|
||||
null
|
||||
);
|
||||
error_log("ThesisEditController: PeerTube upload OK → " . $result['watchUrl']);
|
||||
} catch (\Throwable $e) {
|
||||
error_log('ThesisEditController: PeerTube upload failed — ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or update a website URL thesis_file row.
|
||||
*
|
||||
|
||||
@@ -129,7 +129,8 @@ trait ThesisFileHandler
|
||||
$relPath = $folderPath . $targetName;
|
||||
|
||||
$this->db->insertThesisFile(
|
||||
$thesisId, 'cover',
|
||||
$thesisId,
|
||||
'cover',
|
||||
$relPath,
|
||||
basename($upload['name']),
|
||||
$upload['size'],
|
||||
@@ -184,7 +185,8 @@ trait ThesisFileHandler
|
||||
$relPath = $folderPath . $targetName;
|
||||
|
||||
$this->db->insertThesisFile(
|
||||
$thesisId, 'note_intention',
|
||||
$thesisId,
|
||||
'note_intention',
|
||||
$relPath,
|
||||
basename($upload['name']),
|
||||
$upload['size'],
|
||||
@@ -278,7 +280,7 @@ trait ThesisFileHandler
|
||||
}
|
||||
|
||||
// Sort by hierarchy rank
|
||||
usort($files, fn($a, $b) => $a['hierarchy'] - $b['hierarchy']);
|
||||
usort($files, fn ($a, $b) => $a['hierarchy'] - $b['hierarchy']);
|
||||
|
||||
// Assign contiguous TFE_XX numbers
|
||||
$videoCount = 0;
|
||||
@@ -527,7 +529,8 @@ trait ThesisFileHandler
|
||||
$relPath = $folderPath . $targetName;
|
||||
|
||||
$this->db->insertThesisFile(
|
||||
$thesisId, 'annex',
|
||||
$thesisId,
|
||||
'annex',
|
||||
$relPath,
|
||||
basename($uploads['name'][$i]),
|
||||
$uploads['size'][$i],
|
||||
@@ -600,7 +603,7 @@ trait ThesisFileHandler
|
||||
$limitMb = round($sizeLimit / 1024 / 1024);
|
||||
$sizeMb = round($uploads['size'][$i] / 1024 / 1024);
|
||||
$this->fileWarnings[] = "Annexe « {$uploads['name'][$i]} » ignorée : trop volumineuse ($sizeMb MB, max $limitMb MB).";
|
||||
error_log("ThesisFileHandler: annexe too large {$uploads['name'][$i]} (" . $sizeMb . " MB), skipping");
|
||||
error_log("ThesisFileHandler: annexe too large {$uploads['name'][$i]} (" . $sizeMb . ' MB), skipping');
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -620,7 +623,8 @@ trait ThesisFileHandler
|
||||
$fileType = ($ext === 'vtt' || $mimeType === 'text/vtt') ? 'caption' : 'annex';
|
||||
|
||||
$this->db->insertThesisFile(
|
||||
$thesisId, $fileType,
|
||||
$thesisId,
|
||||
$fileType,
|
||||
$relPath,
|
||||
basename($uploads['name'][$i]),
|
||||
$uploads['size'][$i],
|
||||
@@ -653,7 +657,8 @@ trait ThesisFileHandler
|
||||
$relPath = $folderPath . $targetName;
|
||||
|
||||
$this->db->insertThesisFile(
|
||||
$thesisId, $f['fileType'],
|
||||
$thesisId,
|
||||
$f['fileType'],
|
||||
$relPath,
|
||||
basename($f['origName']),
|
||||
$f['size'],
|
||||
@@ -730,7 +735,7 @@ trait ThesisFileHandler
|
||||
*/
|
||||
protected function generateAuthorSlug(string $authorNames): string
|
||||
{
|
||||
$names = array_values(array_filter(array_map('trim', explode(',', $authorNames)), fn($n) => $n !== ''));
|
||||
$names = array_values(array_filter(array_map('trim', explode(',', $authorNames)), fn ($n) => $n !== ''));
|
||||
sort($names, SORT_NATURAL);
|
||||
$joined = implode('-', $names);
|
||||
|
||||
@@ -936,7 +941,8 @@ trait ThesisFileHandler
|
||||
$relPath = $folderPath . $targetName;
|
||||
|
||||
$this->db->insertThesisFile(
|
||||
$thesisId, $fileType,
|
||||
$thesisId,
|
||||
$fileType,
|
||||
$relPath,
|
||||
$originalName,
|
||||
$size,
|
||||
@@ -1008,12 +1014,14 @@ trait ThesisFileHandler
|
||||
$uuid = $parts[2] ?? '';
|
||||
$storedPath = 'peertube_ids:' . $uuid;
|
||||
$this->db->insertThesisFile(
|
||||
$thesisId, $fileType,
|
||||
$thesisId,
|
||||
$fileType,
|
||||
$storedPath,
|
||||
$uuid . ' (PeerTube)',
|
||||
0,
|
||||
$fileType === 'video' ? 'video/mp4' : 'audio/mpeg',
|
||||
null, null
|
||||
null,
|
||||
null
|
||||
);
|
||||
error_log("ThesisFileHandler: PeerTube file associated → $uuid");
|
||||
continue;
|
||||
@@ -1091,12 +1099,14 @@ trait ThesisFileHandler
|
||||
$relPath = $folderPath . $targetName;
|
||||
|
||||
$this->db->insertThesisFile(
|
||||
$thesisId, 'annex',
|
||||
$thesisId,
|
||||
'annex',
|
||||
$relPath,
|
||||
basename($f['origName']),
|
||||
$f['size'],
|
||||
$f['mimeType'],
|
||||
null, null
|
||||
null,
|
||||
null
|
||||
);
|
||||
error_log("ThesisFileHandler: annexe (filepond) → $targetName");
|
||||
$num++;
|
||||
@@ -1112,7 +1122,7 @@ trait ThesisFileHandler
|
||||
$f['hierarchy'] = $this->tfeHierarchyRank($f['mimeType'], $f['ext']);
|
||||
$filesWithRank[] = $f;
|
||||
}
|
||||
usort($filesWithRank, fn($a, $b) => $a['hierarchy'] - $b['hierarchy']);
|
||||
usort($filesWithRank, fn ($a, $b) => $a['hierarchy'] - $b['hierarchy']);
|
||||
|
||||
$num = $startNum;
|
||||
$vttIdx = 0;
|
||||
@@ -1170,7 +1180,8 @@ trait ThesisFileHandler
|
||||
$relPath = $folderPath . $targetName;
|
||||
|
||||
$this->db->insertThesisFile(
|
||||
$thesisId, $f['fileType'],
|
||||
$thesisId,
|
||||
$f['fileType'],
|
||||
$relPath,
|
||||
basename($f['origName']),
|
||||
$f['size'],
|
||||
@@ -1250,7 +1261,7 @@ trait ThesisFileHandler
|
||||
@copy($abs, $trashPath);
|
||||
@unlink($abs);
|
||||
}
|
||||
error_log("ThesisFileHandler: file \$fileId moved to trash → \$trashName");
|
||||
error_log("ThesisFileHandler: file {$fileId} moved to trash → {$trashName}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* validate-file-fragment.php
|
||||
*
|
||||
|
||||
@@ -43,13 +43,13 @@ class Database
|
||||
{
|
||||
// Add 'name' column to share_links if missing
|
||||
try {
|
||||
$this->pdo->exec("ALTER TABLE share_links ADD COLUMN name TEXT");
|
||||
$this->pdo->exec('ALTER TABLE share_links ADD COLUMN name TEXT');
|
||||
} catch (\PDOException $e) {
|
||||
// Column already exists — ignore
|
||||
}
|
||||
// Add 'locked_year' column to share_links if missing
|
||||
try {
|
||||
$this->pdo->exec("ALTER TABLE share_links ADD COLUMN locked_year INTEGER");
|
||||
$this->pdo->exec('ALTER TABLE share_links ADD COLUMN locked_year INTEGER');
|
||||
} catch (\PDOException $e) {
|
||||
// Column already exists — ignore
|
||||
}
|
||||
@@ -765,7 +765,7 @@ class Database
|
||||
*/
|
||||
public function getAllLanguages(): array
|
||||
{
|
||||
$stmt = $this->pdo->query("SELECT id, UPPER(SUBSTR(name,1,1)) || SUBSTR(name,2) as name, created_at FROM languages WHERE deleted_at IS NULL ORDER BY name");
|
||||
$stmt = $this->pdo->query('SELECT id, UPPER(SUBSTR(name,1,1)) || SUBSTR(name,2) as name, created_at FROM languages WHERE deleted_at IS NULL ORDER BY name');
|
||||
return $stmt->fetchAll();
|
||||
}
|
||||
|
||||
@@ -798,7 +798,9 @@ class Database
|
||||
$dedup = [];
|
||||
foreach ($langs as $l) {
|
||||
$g = $l['grp'];
|
||||
if (isset($seen[$g])) continue;
|
||||
if (isset($seen[$g])) {
|
||||
continue;
|
||||
}
|
||||
$seen[$g] = true;
|
||||
$dedup[] = [
|
||||
'id' => $l['id'],
|
||||
@@ -1100,6 +1102,7 @@ class Database
|
||||
JOIN thesis_authors ta2 ON ta2.thesis_id = t.id
|
||||
JOIN authors a2 ON a2.id = ta2.author_id
|
||||
WHERE t.year = ?
|
||||
AND t.deleted_at IS NULL
|
||||
AND LOWER(TRIM(a.name)) IN ({$ph})
|
||||
GROUP BY t.id"
|
||||
);
|
||||
@@ -2110,7 +2113,12 @@ class Database
|
||||
public function updateThesis(int $thesisId, array $data): void
|
||||
{
|
||||
require_once __DIR__ . '/Audit.php';
|
||||
Audit::log($this, Audit::actor(), 'UPDATE', 'theses', $thesisId,
|
||||
Audit::log(
|
||||
$this,
|
||||
Audit::actor(),
|
||||
'UPDATE',
|
||||
'theses',
|
||||
$thesisId,
|
||||
$this->fetchRow('theses', $thesisId)
|
||||
);
|
||||
|
||||
@@ -2225,8 +2233,8 @@ class Database
|
||||
!empty($data['subtitle']) ? $data['subtitle'] : null,
|
||||
(int)$data['year'],
|
||||
$orientation ? (int)$orientation : null,
|
||||
$ap ? (int)$ap : null,
|
||||
$finality ? (int)$finality : null,
|
||||
$ap ? (int)$ap : null,
|
||||
$finality ? (int)$finality : null,
|
||||
$data['synopsis'],
|
||||
!empty($data['context_note']) ? $data['context_note'] : null,
|
||||
!empty($data['baiu_link']) ? $data['baiu_link'] : null,
|
||||
@@ -2316,7 +2324,12 @@ class Database
|
||||
public function restoreThesis(int $thesisId): void
|
||||
{
|
||||
require_once __DIR__ . '/Audit.php';
|
||||
Audit::log($this, Audit::actor(), 'UPDATE', 'theses', $thesisId,
|
||||
Audit::log(
|
||||
$this,
|
||||
Audit::actor(),
|
||||
'UPDATE',
|
||||
'theses',
|
||||
$thesisId,
|
||||
$this->fetchRow('theses', $thesisId)
|
||||
);
|
||||
$this->pdo->prepare('UPDATE theses SET deleted_at = NULL WHERE id = ?')->execute([$thesisId]);
|
||||
|
||||
@@ -50,7 +50,7 @@ class EmailObfuscator
|
||||
{
|
||||
return preg_replace_callback(
|
||||
'/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/',
|
||||
fn(array $m) => self::encode($m[0]),
|
||||
fn (array $m) => self::encode($m[0]),
|
||||
$text
|
||||
);
|
||||
}
|
||||
@@ -63,7 +63,7 @@ class EmailObfuscator
|
||||
{
|
||||
return preg_replace_callback(
|
||||
'/mailto:([A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,})/i',
|
||||
fn(array $m) => 'mailto:' . self::encode($m[1]),
|
||||
fn (array $m) => 'mailto:' . self::encode($m[1]),
|
||||
$text
|
||||
);
|
||||
}
|
||||
|
||||
@@ -52,8 +52,8 @@ class PeerTubeService
|
||||
|
||||
return [
|
||||
'instance_url' => $row['instance_url'] ?? '',
|
||||
'username' => $smtp['username'] ?? '',
|
||||
'password' => $smtp['password'] ?? '',
|
||||
'username' => $smtp['username'],
|
||||
'password' => $smtp['password'],
|
||||
'channel_name' => $row['channel_name'] ?? '',
|
||||
'privacy' => (int)($row['privacy'] ?? 1),
|
||||
'peertube_video_label' => $row['peertube_video_label'] ?? '',
|
||||
|
||||
@@ -147,7 +147,7 @@ class ShareLink
|
||||
'SELECT * FROM share_links WHERE is_archived = 0 ORDER BY created_at DESC'
|
||||
);
|
||||
$rows = $stmt->fetchAll();
|
||||
return array_map(fn($row) => $this->decorateWithPassword($row), $rows);
|
||||
return array_map(fn ($row) => $this->decorateWithPassword($row), $rows);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user