Add SQLite indexes for contenus page language/tag queries + WIP: Peertube orphans, dialogs, contact decoupling, context note, finality types

This commit is contained in:
Pontoporeia
2026-06-21 13:33:55 +02:00
parent 0d5e9dac19
commit 03c9c3566f
38 changed files with 1432 additions and 333 deletions

View File

@@ -0,0 +1,126 @@
<?php
/**
* PeerTube video relink endpoint (admin).
*
* POST /admin/actions/peertube-relink.php
* Body: JSON { thesis_id: 123, uuid: "bmpQZTUPv4ou8ufiwajV63" }
*
* Links an existing PeerTube video to a thesis by inserting a thesis_files row
* with file_path = 'peertube_ids:{uuid}'. Only videos that are on the channel
* but NOT linked to any TFE can be relinked.
*/
require_once __DIR__ . '/../../../bootstrap.php';
require_once __DIR__ . '/../../../src/AdminAuth.php';
AdminAuth::requireLogin();
function peertubeRelinkError(int $code, string $message): never {
http_response_code($code);
header('Content-Type: application/json');
echo json_encode(['ok' => false, 'error' => $message]);
exit;
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
peertubeRelinkError(405, 'Méthode non autorisée.');
}
$csrfHeader = $_SERVER['HTTP_X_CSRF_TOKEN'] ?? '';
if (!isset($_SESSION['csrf_token'])
|| !hash_equals($_SESSION['csrf_token'], $csrfHeader)) {
peertubeRelinkError(403, 'Token CSRF invalide.');
}
$body = json_decode(file_get_contents('php://input'), true);
if (!is_array($body)) {
peertubeRelinkError(400, 'JSON invalide.');
}
$thesisId = filter_var($body['thesis_id'] ?? '', FILTER_VALIDATE_INT);
$uuid = trim($body['uuid'] ?? '');
if (!$thesisId || $uuid === '') {
peertubeRelinkError(400, 'Paramètres invalides (thesis_id + uuid requis).');
}
// Validate UUID format (shortUUID or full UUID)
if (!preg_match('/^[a-zA-Z0-9\-_]+$/', $uuid)) {
peertubeRelinkError(400, 'UUID invalide.');
}
require_once APP_ROOT . '/src/Database.php';
require_once APP_ROOT . '/src/PeerTubeService.php';
$db = new Database();
if (!PeerTubeService::isConfigured($db)) {
peertubeRelinkError(503, 'PeerTube non configuré.');
}
// Check thesis exists
$thesis = $db->getThesis($thesisId);
if (!$thesis) {
peertubeRelinkError(404, 'TFE introuvable.');
}
// Check this UUID is not already linked to this thesis
$pdo = $db->getConnection();
$stmt = $pdo->prepare(
"SELECT id FROM thesis_files
WHERE thesis_id = ? AND file_path = ?"
);
$stmt->execute([$thesisId, 'peertube_ids:' . $uuid]);
if ($stmt->fetch()) {
peertubeRelinkError(409, 'Cette vidéo est déjà liée à ce TFE.');
}
// Verify the video exists on the channel
$info = PeerTubeService::fetchVideoInfo($db, $uuid);
if ($info === null) {
peertubeRelinkError(404, 'Vidéo introuvable sur PeerTube.');
}
// Verify it's not already linked to another TFE
$stmt = $pdo->prepare(
"SELECT t.identifier FROM thesis_files tf
JOIN theses t ON t.id = tf.thesis_id
WHERE tf.file_path = ? AND t.deleted_at IS NULL"
);
$stmt->execute(['peertube_ids:' . $uuid]);
$existing = $stmt->fetch();
if ($existing) {
peertubeRelinkError(409,
'Cette vidéo est déjà liée au TFE ' . htmlspecialchars($existing['identifier'] ?? '?')
. '. Dé-liez-la d\'abord avant de la relier à un autre.'
);
}
// Determine file type from PeerTube info
$videoName = $info['name'] ?? $uuid;
$fileType = 'video'; // default
$catId = (int)($info['category']['id'] ?? 0);
if ($catId === 16) {
$fileType = 'audio';
}
$db->insertThesisFile(
$thesisId,
$fileType,
'peertube_ids:' . $uuid,
$videoName,
0, // size unknown (not on disk)
'video/mp4', // PeerTube streams HLS, mime is nominal
null,
null
);
$newId = $pdo->lastInsertId();
error_log("[peertube-relink] thesis_id=$thesisId uuid=$uuid file_type=$fileType new_id=$newId");
header('Content-Type: application/json');
echo json_encode([
'ok' => true,
'id' => (int)$newId,
'message' => 'Vidéo PeerTube reliée avec succès.',
]);
exit;