mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-08-10 07:11:18 +02:00
chore: add explicit spacing to cleanup page article and h1
This commit is contained in:
@@ -0,0 +1,197 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Shared cleanup stats data-fetching logic.
|
||||||
|
*
|
||||||
|
* Used by both cleanup-stats.php (JSON endpoint) and
|
||||||
|
* cleanup-stats-fragment.php (HTML fragment).
|
||||||
|
*/
|
||||||
|
|
||||||
|
function dirSizeRecursive(string $dir): int
|
||||||
|
{
|
||||||
|
$size = 0;
|
||||||
|
if (!is_dir($dir)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
$items = @scandir($dir);
|
||||||
|
if ($items === false) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
foreach ($items as $item) {
|
||||||
|
if ($item === '.' || $item === '..') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$path = $dir . '/' . $item;
|
||||||
|
if (is_dir($path)) {
|
||||||
|
$size += dirSizeRecursive($path);
|
||||||
|
} else {
|
||||||
|
$size += filesize($path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $size;
|
||||||
|
}
|
||||||
|
|
||||||
|
function humanBytes(int $bytes): string
|
||||||
|
{
|
||||||
|
if ($bytes > 1073741824) {
|
||||||
|
return number_format($bytes / 1073741824, 1) . ' GB';
|
||||||
|
}
|
||||||
|
if ($bytes > 1048576) {
|
||||||
|
return number_format($bytes / 1048576, 1) . ' MB';
|
||||||
|
}
|
||||||
|
return number_format($bytes / 1024, 1) . ' KB';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCleanupStats(): array
|
||||||
|
{
|
||||||
|
$storageRoot = STORAGE_ROOT;
|
||||||
|
$filepondDir = $storageRoot . '/tmp/filepond';
|
||||||
|
$trashDir = $storageRoot . '/tmp/_trash';
|
||||||
|
$maxAgeFilepond = 7200; // 2h
|
||||||
|
$maxAgeTrash = 2592000; // 30d
|
||||||
|
|
||||||
|
$sessionSavePath = session_save_path();
|
||||||
|
if (!$sessionSavePath || $sessionSavePath === '') {
|
||||||
|
$sessionSavePath = sys_get_temp_dir();
|
||||||
|
}
|
||||||
|
|
||||||
|
$now = time();
|
||||||
|
|
||||||
|
// ── FilePond stats ───────────────────────────────────────────────────
|
||||||
|
$fpStaleCount = 0;
|
||||||
|
$fpStaleSize = 0;
|
||||||
|
$fpStaleFiles = [];
|
||||||
|
$fpActiveCount = 0;
|
||||||
|
$fpActiveSize = 0;
|
||||||
|
|
||||||
|
if (is_dir($filepondDir)) {
|
||||||
|
$items = @scandir($filepondDir);
|
||||||
|
if ($items !== false) {
|
||||||
|
foreach ($items as $item) {
|
||||||
|
if ($item === '.' || $item === '..' || $item === '.gitkeep') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$dirPath = $filepondDir . '/' . $item;
|
||||||
|
if (!is_dir($dirPath)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$size = dirSizeRecursive($dirPath);
|
||||||
|
$mtime = filemtime($dirPath);
|
||||||
|
$ageMinutes = (int)(($now - $mtime) / 60);
|
||||||
|
|
||||||
|
$stale = false;
|
||||||
|
|
||||||
|
// Session-based detection
|
||||||
|
$manifestPath = $dirPath . '/manifest.json';
|
||||||
|
if (file_exists($manifestPath)) {
|
||||||
|
$manifest = json_decode(file_get_contents($manifestPath), true);
|
||||||
|
if (is_array($manifest) && !empty($manifest['session_id'])) {
|
||||||
|
$sessionFile = $sessionSavePath . '/sess_' . $manifest['session_id'];
|
||||||
|
if (!file_exists($sessionFile)) {
|
||||||
|
$stale = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time-based fallback
|
||||||
|
if (!$stale && $ageMinutes > ($maxAgeFilepond / 60)) {
|
||||||
|
$stale = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($stale) {
|
||||||
|
$fpStaleCount++;
|
||||||
|
$fpStaleSize += $size;
|
||||||
|
$fpStaleFiles[] = [
|
||||||
|
'name' => $item,
|
||||||
|
'size' => $size,
|
||||||
|
'human' => humanBytes($size),
|
||||||
|
'age_minutes' => $ageMinutes,
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$fpActiveCount++;
|
||||||
|
$fpActiveSize += $size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Trash stats ──────────────────────────────────────────────────────
|
||||||
|
require_once __DIR__ . '/../../../src/Database.php';
|
||||||
|
$db = new Database();
|
||||||
|
$pdo = $db->getPDO();
|
||||||
|
|
||||||
|
$existingFileIds = [];
|
||||||
|
$stmt = $pdo->query('SELECT id FROM thesis_files');
|
||||||
|
while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||||
|
$existingFileIds[(int)$row['id']] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$trStaleCount = 0;
|
||||||
|
$trStaleSize = 0;
|
||||||
|
$trStaleFiles = [];
|
||||||
|
$trActiveCount = 0;
|
||||||
|
$trActiveSize = 0;
|
||||||
|
|
||||||
|
if (is_dir($trashDir)) {
|
||||||
|
$items = @scandir($trashDir);
|
||||||
|
if ($items !== false) {
|
||||||
|
foreach ($items as $item) {
|
||||||
|
if ($item === '.' || $item === '..') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$filePath = $trashDir . '/' . $item;
|
||||||
|
if (!is_file($filePath)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$size = filesize($filePath);
|
||||||
|
$mtime = filemtime($filePath);
|
||||||
|
$ageDays = (int)(($now - $mtime) / 86400);
|
||||||
|
|
||||||
|
$stale = false;
|
||||||
|
|
||||||
|
if (preg_match('/^(\d+)_/', $item, $m)) {
|
||||||
|
$dbId = (int)$m[1];
|
||||||
|
if (!isset($existingFileIds[$dbId])) {
|
||||||
|
$stale = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$stale && $ageDays > ($maxAgeTrash / 86400)) {
|
||||||
|
$stale = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($stale) {
|
||||||
|
$trStaleCount++;
|
||||||
|
$trStaleSize += $size;
|
||||||
|
$trStaleFiles[] = [
|
||||||
|
'name' => $item,
|
||||||
|
'size' => $size,
|
||||||
|
'human' => humanBytes($size),
|
||||||
|
'age_days' => $ageDays,
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$trActiveCount++;
|
||||||
|
$trActiveSize += $size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'filepond_stale_count' => $fpStaleCount,
|
||||||
|
'filepond_stale_size' => $fpStaleSize,
|
||||||
|
'filepond_stale_human' => humanBytes($fpStaleSize),
|
||||||
|
'filepond_stale_files' => $fpStaleFiles,
|
||||||
|
'filepond_active_count' => $fpActiveCount,
|
||||||
|
'filepond_active_size' => $fpActiveSize,
|
||||||
|
'filepond_active_human' => humanBytes($fpActiveSize),
|
||||||
|
'trash_stale_count' => $trStaleCount,
|
||||||
|
'trash_stale_size' => $trStaleSize,
|
||||||
|
'trash_stale_human' => humanBytes($trStaleSize),
|
||||||
|
'trash_stale_files' => $trStaleFiles,
|
||||||
|
'trash_active_count' => $trActiveCount,
|
||||||
|
'trash_active_size' => $trActiveSize,
|
||||||
|
'trash_active_human' => humanBytes($trActiveSize),
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Shared PeerTube orphan data-fetching logic.
|
||||||
|
*
|
||||||
|
* Used by both peertube-orphans.php (JSON endpoint) and
|
||||||
|
* peertube-orphans-fragment.php (HTML fragment).
|
||||||
|
*/
|
||||||
|
|
||||||
|
function getPeerTubeOrphansData(): array
|
||||||
|
{
|
||||||
|
require_once APP_ROOT . '/src/Database.php';
|
||||||
|
require_once APP_ROOT . '/src/PeerTubeService.php';
|
||||||
|
|
||||||
|
$db = new Database();
|
||||||
|
|
||||||
|
if (!PeerTubeService::isConfigured($db)) {
|
||||||
|
return [
|
||||||
|
'configured' => false,
|
||||||
|
'error' => 'PeerTube non configuré.',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Collect all Peertube UUIDs linked in the DB ──────────────────────
|
||||||
|
$pdo = $db->getPDO();
|
||||||
|
$dbUuids = [];
|
||||||
|
$linkedMap = []; // uuid → [thesis_id, thesis_title, thesis_identifier]
|
||||||
|
|
||||||
|
$stmt = $pdo->query(
|
||||||
|
"SELECT tf.file_path, tf.file_name, t.id AS thesis_id, t.title, t.identifier
|
||||||
|
FROM thesis_files tf
|
||||||
|
JOIN theses t ON t.id = tf.thesis_id
|
||||||
|
WHERE tf.file_path LIKE 'peertube_ids:%'
|
||||||
|
AND t.deleted_at IS NULL"
|
||||||
|
);
|
||||||
|
while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
|
||||||
|
$uuid = substr($row['file_path'], strlen('peertube_ids:'));
|
||||||
|
$dbUuids[$uuid] = true;
|
||||||
|
$linkedMap[$uuid][] = [
|
||||||
|
'thesis_id' => (int)$row['thesis_id'],
|
||||||
|
'title' => $row['title'],
|
||||||
|
'identifier' => $row['identifier'] ?? '',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── List all channel videos ──────────────────────────────────────────
|
||||||
|
try {
|
||||||
|
$channelVideos = PeerTubeService::listChannelVideos($db);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return [
|
||||||
|
'configured' => true,
|
||||||
|
'error' => 'Erreur lors du listage des vidéos : ' . $e->getMessage(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Find orphans: on channel but not in DB ───────────────────────────
|
||||||
|
$orphans = [];
|
||||||
|
$linked = [];
|
||||||
|
foreach ($channelVideos as $v) {
|
||||||
|
$uuid = $v['shortUUID'] ?: $v['uuid'];
|
||||||
|
if ($uuid === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isset($dbUuids[$uuid])) {
|
||||||
|
$linked[] = [
|
||||||
|
'uuid' => $uuid,
|
||||||
|
'name' => $v['name'],
|
||||||
|
'theses' => $linkedMap[$uuid] ?? [],
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$orphans[] = [
|
||||||
|
'uuid' => $uuid,
|
||||||
|
'name' => $v['name'],
|
||||||
|
'createdAt' => $v['createdAt'],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Find stale DB entries: in DB but not on channel ──────────────────
|
||||||
|
$stale = [];
|
||||||
|
foreach ($dbUuids as $uuid => $_) {
|
||||||
|
$found = false;
|
||||||
|
foreach ($channelVideos as $v) {
|
||||||
|
if (($v['shortUUID'] ?: $v['uuid']) === $uuid) {
|
||||||
|
$found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$found) {
|
||||||
|
$stale[] = [
|
||||||
|
'uuid' => $uuid,
|
||||||
|
'theses' => $linkedMap[$uuid] ?? [],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$totalOnChannel = count($channelVideos);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'configured' => true,
|
||||||
|
'channel_name' => PeerTubeService::getSettings($db)['channel_name'],
|
||||||
|
'total_on_channel' => $totalOnChannel,
|
||||||
|
'total_linked' => count($linked),
|
||||||
|
'orphan_count' => count($orphans),
|
||||||
|
'orphans' => $orphans,
|
||||||
|
'stale_count' => count($stale),
|
||||||
|
'stale_entries' => $stale,
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -10,11 +10,8 @@ require_once __DIR__ . '/../../../bootstrap.php';
|
|||||||
require_once __DIR__ . '/../../../src/AdminAuth.php';
|
require_once __DIR__ . '/../../../src/AdminAuth.php';
|
||||||
AdminAuth::requireLogin();
|
AdminAuth::requireLogin();
|
||||||
|
|
||||||
// Re-use the existing stats endpoint internally
|
require_once __DIR__ . '/_cleanup-stats-data.php';
|
||||||
ob_start();
|
$d = getCleanupStats();
|
||||||
require __DIR__ . '/cleanup-stats.php';
|
|
||||||
$json = ob_get_clean();
|
|
||||||
$d = json_decode($json, true);
|
|
||||||
|
|
||||||
$fpStale = $d['filepond_stale_count'] ?? 0;
|
$fpStale = $d['filepond_stale_count'] ?? 0;
|
||||||
$fpActive = $d['filepond_active_count'] ?? 0;
|
$fpActive = $d['filepond_active_count'] ?? 0;
|
||||||
@@ -41,13 +38,7 @@ if ($trStale > 0) {
|
|||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<?php if ($totalStale === 0 && $totalFiles === 0): ?>
|
<?php if ($totalStale === 0 && $totalFiles === 0): ?>
|
||||||
<fieldset>
|
<p style="margin:0;color:var(--accent-green)">✓ Aucun fichier temporaire.</p>
|
||||||
<legend>
|
|
||||||
<?= icon('paint-brush-household') ?>
|
|
||||||
Fichiers temporaires
|
|
||||||
</legend>
|
|
||||||
<p style="margin:0;color:var(--accent-green)">✓ Aucun fichier temporaire.</p>
|
|
||||||
</fieldset>
|
|
||||||
<?php return; endif; ?>
|
<?php return; endif; ?>
|
||||||
|
|
||||||
<!-- Bulk actions bar -->
|
<!-- Bulk actions bar -->
|
||||||
@@ -72,71 +63,61 @@ if ($trStale > 0) {
|
|||||||
</form>
|
</form>
|
||||||
|
|
||||||
<?php if ($fpStale > 0): ?>
|
<?php if ($fpStale > 0): ?>
|
||||||
<fieldset>
|
<h3 id="tmp-filepond-heading">Téléversements abandonnés <span class="n-meta"><?= htmlspecialchars($fpMeta) ?></span></h3>
|
||||||
<legend>
|
<table class="n-table" aria-labelledby="tmp-filepond-heading">
|
||||||
<?= icon('paint-brush-household') ?>
|
<thead><tr><th width="1%"><input type="checkbox" onchange="cleanupToggleAll(this, 'filepond')" title="Tout sélectionner"></th><th>Nom</th><th>Taille</th><th>Âge</th><th width="1%"></th></tr></thead>
|
||||||
Téléversements abandonnés <span class="n-meta"><?= htmlspecialchars($fpMeta) ?></span>
|
<tbody>
|
||||||
</legend>
|
<?php foreach ($d['filepond_stale_files'] as $f): ?>
|
||||||
<table class="n-table">
|
<tr>
|
||||||
<thead><tr><th width="1%"><input type="checkbox" onchange="cleanupToggleAll(this, 'filepond')" title="Tout sélectionner"></th><th>Nom</th><th>Taille</th><th>Âge</th><th width="1%"></th></tr></thead>
|
<td><input type="checkbox" name="filepond_dirs[]" value="<?= htmlspecialchars($f['name']) ?>" data-cleanup-group="filepond" onchange="cleanupUpdateBulk()"></td>
|
||||||
<tbody>
|
<td><strong><?= htmlspecialchars($f['name']) ?></strong></td>
|
||||||
<?php foreach ($d['filepond_stale_files'] as $f): ?>
|
<td style="white-space:nowrap"><?= htmlspecialchars($f['human']) ?></td>
|
||||||
<tr>
|
<td style="white-space:nowrap">~<?= (int)$f['age_minutes'] ?> min</td>
|
||||||
<td><input type="checkbox" name="filepond_dirs[]" value="<?= htmlspecialchars($f['name']) ?>" data-cleanup-group="filepond" onchange="cleanupUpdateBulk()"></td>
|
<td style="white-space:nowrap">
|
||||||
<td><strong><?= htmlspecialchars($f['name']) ?></strong></td>
|
<button type="button" class="btn btn--sm btn--danger" style="font-size:0.85em;padding:2px var(--space-xs)"
|
||||||
<td style="white-space:nowrap"><?= htmlspecialchars($f['human']) ?></td>
|
hx-post="/admin/actions/cleanup-tmp.php"
|
||||||
<td style="white-space:nowrap">~<?= (int)$f['age_minutes'] ?> min</td>
|
hx-confirm="Supprimer définitivement ce téléversement abandonné ?"
|
||||||
<td style="white-space:nowrap">
|
hx-vals='{"csrf_token":"<?= htmlspecialchars($_SESSION['csrf_token']) ?>","filepond_dir":"<?= htmlspecialchars($f['name']) ?>"}'
|
||||||
<button type="button" class="btn btn--sm btn--danger" style="font-size:0.85em;padding:2px var(--space-xs)"
|
hx-target="#tmp-cleanup-stats-wrapper"
|
||||||
hx-post="/admin/actions/cleanup-tmp.php"
|
hx-swap="innerHTML"
|
||||||
hx-confirm="Supprimer définitivement ce téléversement abandonné ?"
|
hx-indicator="#tmp-cleanup-stats-wrapper">
|
||||||
hx-vals='{"csrf_token":"<?= htmlspecialchars($_SESSION['csrf_token']) ?>","filepond_dir":"<?= htmlspecialchars($f['name']) ?>"}'
|
<?= icon('trash') ?>
|
||||||
hx-target="#tmp-cleanup-stats-wrapper"
|
Supprimer
|
||||||
hx-swap="innerHTML"
|
</button>
|
||||||
hx-indicator="#tmp-cleanup-stats-wrapper">
|
</td>
|
||||||
<?= icon('trash') ?>
|
</tr>
|
||||||
Supprimer
|
<?php endforeach; ?>
|
||||||
</button>
|
</tbody>
|
||||||
</td>
|
</table>
|
||||||
</tr>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</fieldset>
|
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if ($trStale > 0): ?>
|
<?php if ($trStale > 0): ?>
|
||||||
<fieldset>
|
<h3 id="tmp-trash-heading">Corbeille <span class="n-meta"><?= htmlspecialchars($trMeta) ?></span></h3>
|
||||||
<legend>
|
<table class="n-table" aria-labelledby="tmp-trash-heading">
|
||||||
<?= icon('trash') ?>
|
<thead><tr><th width="1%"><input type="checkbox" onchange="cleanupToggleAll(this, 'trash')" title="Tout sélectionner"></th><th>Nom</th><th>Taille</th><th>Âge</th><th width="1%"></th></tr></thead>
|
||||||
Corbeille <span class="n-meta"><?= htmlspecialchars($trMeta) ?></span>
|
<tbody>
|
||||||
</legend>
|
<?php foreach ($d['trash_stale_files'] as $f): ?>
|
||||||
<table class="n-table">
|
<tr>
|
||||||
<thead><tr><th width="1%"><input type="checkbox" onchange="cleanupToggleAll(this, 'trash')" title="Tout sélectionner"></th><th>Nom</th><th>Taille</th><th>Âge</th><th width="1%"></th></tr></thead>
|
<td><input type="checkbox" name="trash_files[]" value="<?= htmlspecialchars($f['name']) ?>" data-cleanup-group="trash" onchange="cleanupUpdateBulk()"></td>
|
||||||
<tbody>
|
<td><strong><?= htmlspecialchars($f['name']) ?></strong></td>
|
||||||
<?php foreach ($d['trash_stale_files'] as $f): ?>
|
<td style="white-space:nowrap"><?= htmlspecialchars($f['human']) ?></td>
|
||||||
<tr>
|
<td style="white-space:nowrap">~<?= (int)$f['age_days'] ?> j</td>
|
||||||
<td><input type="checkbox" name="trash_files[]" value="<?= htmlspecialchars($f['name']) ?>" data-cleanup-group="trash" onchange="cleanupUpdateBulk()"></td>
|
<td style="white-space:nowrap">
|
||||||
<td><strong><?= htmlspecialchars($f['name']) ?></strong></td>
|
<button type="button" class="btn btn--sm btn--danger" style="font-size:0.85em;padding:2px var(--space-xs)"
|
||||||
<td style="white-space:nowrap"><?= htmlspecialchars($f['human']) ?></td>
|
hx-post="/admin/actions/cleanup-tmp.php"
|
||||||
<td style="white-space:nowrap">~<?= (int)$f['age_days'] ?> j</td>
|
hx-confirm="Supprimer définitivement ce fichier de la corbeille ?"
|
||||||
<td style="white-space:nowrap">
|
hx-vals='{"csrf_token":"<?= htmlspecialchars($_SESSION['csrf_token']) ?>","trash_file":"<?= htmlspecialchars($f['name']) ?>"}'
|
||||||
<button type="button" class="btn btn--sm btn--danger" style="font-size:0.85em;padding:2px var(--space-xs)"
|
hx-target="#tmp-cleanup-stats-wrapper"
|
||||||
hx-post="/admin/actions/cleanup-tmp.php"
|
hx-swap="innerHTML"
|
||||||
hx-confirm="Supprimer définitivement ce fichier de la corbeille ?"
|
hx-indicator="#tmp-cleanup-stats-wrapper">
|
||||||
hx-vals='{"csrf_token":"<?= htmlspecialchars($_SESSION['csrf_token']) ?>","trash_file":"<?= htmlspecialchars($f['name']) ?>"}'
|
<?= icon('trash') ?>
|
||||||
hx-target="#tmp-cleanup-stats-wrapper"
|
Supprimer
|
||||||
hx-swap="innerHTML"
|
</button>
|
||||||
hx-indicator="#tmp-cleanup-stats-wrapper">
|
</td>
|
||||||
<?= icon('trash') ?>
|
</tr>
|
||||||
Supprimer
|
<?php endforeach; ?>
|
||||||
</button>
|
</tbody>
|
||||||
</td>
|
</table>
|
||||||
</tr>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</fieldset>
|
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if ($fpActive > 0 || $trActive > 0): ?>
|
<?php if ($fpActive > 0 || $trActive > 0): ?>
|
||||||
|
|||||||
@@ -15,194 +15,10 @@ AdminAuth::requireLogin();
|
|||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
|
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
|
||||||
http_response_code(405);
|
http_response_code(405);
|
||||||
exit;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$storageRoot = STORAGE_ROOT;
|
require_once __DIR__ . '/_cleanup-stats-data.php';
|
||||||
$filepondDir = $storageRoot . '/tmp/filepond';
|
|
||||||
$trashDir = $storageRoot . '/tmp/_trash';
|
|
||||||
$maxAgeFilepond = 7200; // 2h
|
|
||||||
$maxAgeTrash = 2592000; // 30d
|
|
||||||
|
|
||||||
$sessionSavePath = session_save_path();
|
|
||||||
if (!$sessionSavePath || $sessionSavePath === '') {
|
|
||||||
$sessionSavePath = sys_get_temp_dir();
|
|
||||||
}
|
|
||||||
|
|
||||||
$now = time();
|
|
||||||
|
|
||||||
// ── FilePond stats ───────────────────────────────────────────────────────
|
|
||||||
$fpStaleCount = 0;
|
|
||||||
$fpStaleSize = 0;
|
|
||||||
$fpStaleFiles = [];
|
|
||||||
$fpActiveCount = 0;
|
|
||||||
$fpActiveSize = 0;
|
|
||||||
|
|
||||||
if (is_dir($filepondDir)) {
|
|
||||||
$items = @scandir($filepondDir);
|
|
||||||
if ($items !== false) {
|
|
||||||
foreach ($items as $item) {
|
|
||||||
if ($item === '.' || $item === '..' || $item === '.gitkeep') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$dirPath = $filepondDir . '/' . $item;
|
|
||||||
if (!is_dir($dirPath)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$size = dirSizeRecursive($dirPath);
|
|
||||||
$mtime = filemtime($dirPath);
|
|
||||||
$ageMinutes = (int)(($now - $mtime) / 60);
|
|
||||||
|
|
||||||
$stale = false;
|
|
||||||
|
|
||||||
// Session-based detection
|
|
||||||
$manifestPath = $dirPath . '/manifest.json';
|
|
||||||
if (file_exists($manifestPath)) {
|
|
||||||
$manifest = json_decode(file_get_contents($manifestPath), true);
|
|
||||||
if (is_array($manifest) && !empty($manifest['session_id'])) {
|
|
||||||
$sessionFile = $sessionSavePath . '/sess_' . $manifest['session_id'];
|
|
||||||
if (!file_exists($sessionFile)) {
|
|
||||||
$stale = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Time-based fallback
|
|
||||||
if (!$stale && $ageMinutes > ($maxAgeFilepond / 60)) {
|
|
||||||
$stale = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($stale) {
|
|
||||||
$fpStaleCount++;
|
|
||||||
$fpStaleSize += $size;
|
|
||||||
$fpStaleFiles[] = [
|
|
||||||
'name' => $item,
|
|
||||||
'size' => $size,
|
|
||||||
'human' => humanBytes($size),
|
|
||||||
'age_minutes' => $ageMinutes,
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
$fpActiveCount++;
|
|
||||||
$fpActiveSize += $size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Trash stats ──────────────────────────────────────────────────────────
|
|
||||||
require_once __DIR__ . '/../../../src/Database.php';
|
|
||||||
$db = new Database();
|
|
||||||
$pdo = $db->getPDO();
|
|
||||||
|
|
||||||
$existingFileIds = [];
|
|
||||||
$stmt = $pdo->query('SELECT id FROM thesis_files');
|
|
||||||
while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
|
|
||||||
$existingFileIds[(int)$row['id']] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$trStaleCount = 0;
|
|
||||||
$trStaleSize = 0;
|
|
||||||
$trStaleFiles = [];
|
|
||||||
$trActiveCount = 0;
|
|
||||||
$trActiveSize = 0;
|
|
||||||
|
|
||||||
if (is_dir($trashDir)) {
|
|
||||||
$items = @scandir($trashDir);
|
|
||||||
if ($items !== false) {
|
|
||||||
foreach ($items as $item) {
|
|
||||||
if ($item === '.' || $item === '..') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$filePath = $trashDir . '/' . $item;
|
|
||||||
if (!is_file($filePath)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$size = filesize($filePath);
|
|
||||||
$mtime = filemtime($filePath);
|
|
||||||
$ageDays = (int)(($now - $mtime) / 86400);
|
|
||||||
|
|
||||||
$stale = false;
|
|
||||||
|
|
||||||
if (preg_match('/^(\d+)_/', $item, $m)) {
|
|
||||||
$dbId = (int)$m[1];
|
|
||||||
if (!isset($existingFileIds[$dbId])) {
|
|
||||||
$stale = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$stale && $ageDays > ($maxAgeTrash / 86400)) {
|
|
||||||
$stale = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($stale) {
|
|
||||||
$trStaleCount++;
|
|
||||||
$trStaleSize += $size;
|
|
||||||
$trStaleFiles[] = [
|
|
||||||
'name' => $item,
|
|
||||||
'size' => $size,
|
|
||||||
'human' => humanBytes($size),
|
|
||||||
'age_days' => $ageDays,
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
$trActiveCount++;
|
|
||||||
$trActiveSize += $size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
echo json_encode([
|
echo json_encode(getCleanupStats());
|
||||||
'filepond_stale_count' => $fpStaleCount,
|
|
||||||
'filepond_stale_size' => $fpStaleSize,
|
|
||||||
'filepond_stale_human' => humanBytes($fpStaleSize),
|
|
||||||
'filepond_stale_files' => $fpStaleFiles,
|
|
||||||
'filepond_active_count' => $fpActiveCount,
|
|
||||||
'filepond_active_size' => $fpActiveSize,
|
|
||||||
'filepond_active_human' => humanBytes($fpActiveSize),
|
|
||||||
'trash_stale_count' => $trStaleCount,
|
|
||||||
'trash_stale_size' => $trStaleSize,
|
|
||||||
'trash_stale_human' => humanBytes($trStaleSize),
|
|
||||||
'trash_stale_files' => $trStaleFiles,
|
|
||||||
'trash_active_count' => $trActiveCount,
|
|
||||||
'trash_active_size' => $trActiveSize,
|
|
||||||
'trash_active_human' => humanBytes($trActiveSize),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// ── Helpers ───────────────────────────────────────────────────────────────
|
|
||||||
function dirSizeRecursive(string $dir): int
|
|
||||||
{
|
|
||||||
$size = 0;
|
|
||||||
if (!is_dir($dir)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
$items = @scandir($dir);
|
|
||||||
if ($items === false) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
foreach ($items as $item) {
|
|
||||||
if ($item === '.' || $item === '..') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$path = $dir . '/' . $item;
|
|
||||||
if (is_dir($path)) {
|
|
||||||
$size += dirSizeRecursive($path);
|
|
||||||
} else {
|
|
||||||
$size += filesize($path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $size;
|
|
||||||
}
|
|
||||||
|
|
||||||
function humanBytes(int $bytes): string
|
|
||||||
{
|
|
||||||
if ($bytes > 1073741824) {
|
|
||||||
return number_format($bytes / 1073741824, 1) . ' GB';
|
|
||||||
}
|
|
||||||
if ($bytes > 1048576) {
|
|
||||||
return number_format($bytes / 1048576, 1) . ' MB';
|
|
||||||
}
|
|
||||||
return number_format($bytes / 1024, 1) . ' KB';
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -10,94 +10,69 @@ require_once __DIR__ . '/../../../bootstrap.php';
|
|||||||
require_once __DIR__ . '/../../../src/AdminAuth.php';
|
require_once __DIR__ . '/../../../src/AdminAuth.php';
|
||||||
AdminAuth::requireLogin();
|
AdminAuth::requireLogin();
|
||||||
|
|
||||||
// Re-use the existing JSON endpoint internally
|
require_once __DIR__ . '/_peertube-orphans-data.php';
|
||||||
ob_start();
|
$d = getPeerTubeOrphansData();
|
||||||
require __DIR__ . '/peertube-orphans.php';
|
|
||||||
$json = ob_get_clean();
|
|
||||||
$d = json_decode($json, true);
|
|
||||||
|
|
||||||
if (!($d['configured'] ?? false)): ?>
|
if (!($d['configured'] ?? false)): ?>
|
||||||
<fieldset>
|
<p style="margin:0;color:var(--color-warning)">⚠️ PeerTube non configuré.</p>
|
||||||
<legend>
|
|
||||||
<?= icon('video') ?>
|
|
||||||
Vidéos PeerTube orphelines
|
|
||||||
</legend>
|
|
||||||
<p style="margin:0;color:var(--color-warning)">⚠️ PeerTube non configuré.</p>
|
|
||||||
</fieldset>
|
|
||||||
<?php return; endif; ?>
|
<?php return; endif; ?>
|
||||||
|
|
||||||
<?php if (!empty($d['error'])): ?>
|
<?php if (!empty($d['error'])): ?>
|
||||||
<fieldset>
|
<p style="margin:0;color:var(--color-error)">✗ <?= htmlspecialchars($d['error']) ?></p>
|
||||||
<legend>
|
|
||||||
<?= icon('video') ?>
|
|
||||||
Vidéos PeerTube orphelines
|
|
||||||
</legend>
|
|
||||||
<p style="margin:0;color:var(--color-error)">✗ <?= htmlspecialchars($d['error']) ?></p>
|
|
||||||
</fieldset>
|
|
||||||
<?php return; endif; ?>
|
<?php return; endif; ?>
|
||||||
|
|
||||||
<fieldset>
|
|
||||||
<legend>
|
|
||||||
<?= icon('video') ?>
|
|
||||||
Vidéos PeerTube orphelines <span class="n-meta"><?= (int)($d['orphan_count'] ?? 0) ?> vidéos orphelines</span>
|
|
||||||
</legend>
|
|
||||||
<?php if (($d['orphan_count'] ?? 0) > 0): ?>
|
<?php if (($d['orphan_count'] ?? 0) > 0): ?>
|
||||||
<table class="n-table">
|
<h3 id="peertube-orphans-heading">Vidéos orphelines <span class="n-meta"><?= (int)$d['orphan_count'] ?> vidéos orphelines</span></h3>
|
||||||
<thead><tr><th>Nom</th><th>Date</th><th width="1%"></th></tr></thead>
|
<table class="n-table" aria-labelledby="peertube-orphans-heading">
|
||||||
<tbody>
|
<thead><tr><th>Nom</th><th>Date</th><th width="1%"></th></tr></thead>
|
||||||
<?php foreach ($d['orphans'] as $v): ?>
|
<tbody>
|
||||||
<tr>
|
<?php foreach ($d['orphans'] as $v): ?>
|
||||||
<td>
|
<tr>
|
||||||
<strong><?= htmlspecialchars($v['name']) ?></strong>
|
<td>
|
||||||
<span class="n-table__info" style="display:block"><?= htmlspecialchars($v['uuid']) ?></span>
|
<strong><?= htmlspecialchars($v['name']) ?></strong>
|
||||||
</td>
|
<span class="n-table__info" style="display:block"><?= htmlspecialchars($v['uuid']) ?></span>
|
||||||
<td style="white-space:nowrap"><?= htmlspecialchars(substr($v['createdAt'] ?? '', 0, 10)) ?></td>
|
</td>
|
||||||
<td style="white-space:nowrap">
|
<td style="white-space:nowrap"><?= htmlspecialchars(substr($v['createdAt'] ?? '', 0, 10)) ?></td>
|
||||||
<button type="button" class="btn btn--sm btn--danger" style="font-size:0.85em;padding:2px var(--space-xs)"
|
<td style="white-space:nowrap">
|
||||||
hx-post="/admin/actions/peertube-delete.php"
|
<button type="button" class="btn btn--sm btn--danger" style="font-size:0.85em;padding:2px var(--space-xs)"
|
||||||
hx-confirm="Supprimer définitivement cette vidéo de PeerTube ?"
|
hx-post="/admin/actions/peertube-delete.php"
|
||||||
hx-vals='{"csrf_token":"<?= htmlspecialchars($_SESSION['csrf_token']) ?>","uuid":"<?= htmlspecialchars($v['uuid']) ?>"}'
|
hx-confirm="Supprimer définitivement cette vidéo de PeerTube ?"
|
||||||
hx-target="#peertube-orphans-fragment"
|
hx-vals='{"csrf_token":"<?= htmlspecialchars($_SESSION['csrf_token']) ?>","uuid":"<?= htmlspecialchars($v['uuid']) ?>"}'
|
||||||
hx-swap="innerHTML"
|
hx-target="#peertube-orphans-fragment"
|
||||||
hx-trigger="click"
|
hx-swap="innerHTML"
|
||||||
hx-indicator="#peertube-orphans-fragment">
|
hx-trigger="click"
|
||||||
<?= icon('trash') ?>
|
hx-indicator="#peertube-orphans-fragment">
|
||||||
Supprimer
|
<?= icon('trash') ?>
|
||||||
</button>
|
Supprimer
|
||||||
</td>
|
</button>
|
||||||
</tr>
|
</td>
|
||||||
<?php endforeach; ?>
|
</tr>
|
||||||
</tbody>
|
<?php endforeach; ?>
|
||||||
</table>
|
</tbody>
|
||||||
|
</table>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<p style="margin:0;color:var(--accent-green)">✓ Aucune vidéo orpheline.</p>
|
<p style="margin:0;color:var(--accent-green)">✓ Aucune vidéo orpheline.</p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
<?php if (($d['stale_count'] ?? 0) > 0): ?>
|
<?php if (($d['stale_count'] ?? 0) > 0): ?>
|
||||||
<fieldset>
|
<h3 id="peertube-stale-heading" style="margin-top:var(--space-xl)">Références DB obsolètes <span class="n-meta"><?= $d['stale_count'] ?></span></h3>
|
||||||
<legend>
|
<p style="margin:0 0 var(--space-sm) 0;font-size:0.85em;color:var(--text-secondary)">Ces UUID sont référencés en base de données mais n'existent plus sur la chaîne PeerTube. Les TFE liés affichent des liens morts.</p>
|
||||||
<?= icon('warning-diamond') ?>
|
<table class="n-table" aria-labelledby="peertube-stale-heading">
|
||||||
Références DB obsolètes <span class="n-meta"><?= $d['stale_count'] ?></span>
|
<thead><tr><th>UUID</th><th>TFE(s)</th></tr></thead>
|
||||||
</legend>
|
<tbody>
|
||||||
<p style="margin:0 0 var(--space-sm) 0;font-size:0.85em;color:var(--text-secondary)">Ces UUID sont référencés en base de données mais n'existent plus sur la chaîne PeerTube. Les TFE liés affichent des liens morts.</p>
|
<?php foreach ($d['stale_entries'] as $s): ?>
|
||||||
<table class="n-table">
|
<tr>
|
||||||
<thead><tr><th>UUID</th><th>TFE(s)</th></tr></thead>
|
<td style="word-break:break-all;color:var(--text-secondary)"><?= htmlspecialchars($s['uuid']) ?></td>
|
||||||
<tbody>
|
<td>
|
||||||
<?php foreach ($d['stale_entries'] as $s): ?>
|
<?php if (!empty($s['theses'])): ?>
|
||||||
<tr>
|
<?= implode(', ', array_map(function($t) {
|
||||||
<td style="word-break:break-all;color:var(--text-secondary)"><?= htmlspecialchars($s['uuid']) ?></td>
|
$label = $t['identifier'] ?: '#' . $t['thesis_id'];
|
||||||
<td>
|
return '<a href="/admin/contenus-edit.php?id=' . (int)$t['thesis_id'] . '" target="_blank">' . htmlspecialchars($label) . '</a>';
|
||||||
<?php if (!empty($s['theses'])): ?>
|
}, $s['theses'])) ?>
|
||||||
<?= implode(', ', array_map(function($t) {
|
<?php endif; ?>
|
||||||
$label = $t['identifier'] ?: '#' . $t['thesis_id'];
|
</td>
|
||||||
return '<a href="/admin/contenus-edit.php?id=' . (int)$t['thesis_id'] . '" target="_blank">' . htmlspecialchars($label) . '</a>';
|
</tr>
|
||||||
}, $s['theses'])) ?>
|
<?php endforeach; ?>
|
||||||
<?php endif; ?>
|
</tbody>
|
||||||
</td>
|
</table>
|
||||||
</tr>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</fieldset>
|
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|||||||
@@ -14,108 +14,10 @@ AdminAuth::requireLogin();
|
|||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
|
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
|
||||||
http_response_code(405);
|
http_response_code(405);
|
||||||
exit;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
require_once APP_ROOT . '/src/Database.php';
|
require_once __DIR__ . '/_peertube-orphans-data.php';
|
||||||
require_once APP_ROOT . '/src/PeerTubeService.php';
|
|
||||||
|
|
||||||
$db = new Database();
|
|
||||||
|
|
||||||
if (!PeerTubeService::isConfigured($db)) {
|
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
|
||||||
echo json_encode([
|
|
||||||
'configured' => false,
|
|
||||||
'error' => 'PeerTube non configuré.',
|
|
||||||
]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Collect all Peertube UUIDs linked in the DB ──────────────────────────
|
|
||||||
$pdo = $db->getPDO();
|
|
||||||
$dbUuids = [];
|
|
||||||
$linkedMap = []; // uuid → [thesis_id, thesis_title, thesis_identifier]
|
|
||||||
|
|
||||||
$stmt = $pdo->query(
|
|
||||||
"SELECT tf.file_path, tf.file_name, t.id AS thesis_id, t.title, t.identifier
|
|
||||||
FROM thesis_files tf
|
|
||||||
JOIN theses t ON t.id = tf.thesis_id
|
|
||||||
WHERE tf.file_path LIKE 'peertube_ids:%'
|
|
||||||
AND t.deleted_at IS NULL"
|
|
||||||
);
|
|
||||||
while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
|
|
||||||
$uuid = substr($row['file_path'], strlen('peertube_ids:'));
|
|
||||||
$dbUuids[$uuid] = true;
|
|
||||||
$linkedMap[$uuid][] = [
|
|
||||||
'thesis_id' => (int)$row['thesis_id'],
|
|
||||||
'title' => $row['title'],
|
|
||||||
'identifier' => $row['identifier'] ?? '',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── List all channel videos ──────────────────────────────────────────────
|
|
||||||
try {
|
|
||||||
$channelVideos = PeerTubeService::listChannelVideos($db);
|
|
||||||
} catch (\Throwable $e) {
|
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
|
||||||
echo json_encode([
|
|
||||||
'configured' => true,
|
|
||||||
'error' => 'Erreur lors du listage des vidéos : ' . $e->getMessage(),
|
|
||||||
]);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Find orphans: on channel but not in DB ───────────────────────────────
|
|
||||||
$orphans = [];
|
|
||||||
$linked = [];
|
|
||||||
foreach ($channelVideos as $v) {
|
|
||||||
$uuid = $v['shortUUID'] ?: $v['uuid'];
|
|
||||||
if ($uuid === '') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (isset($dbUuids[$uuid])) {
|
|
||||||
$linked[] = [
|
|
||||||
'uuid' => $uuid,
|
|
||||||
'name' => $v['name'],
|
|
||||||
'theses' => $linkedMap[$uuid] ?? [],
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
$orphans[] = [
|
|
||||||
'uuid' => $uuid,
|
|
||||||
'name' => $v['name'],
|
|
||||||
'createdAt' => $v['createdAt'],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Find stale DB entries: in DB but not on channel ──────────────────────
|
|
||||||
$stale = [];
|
|
||||||
foreach ($dbUuids as $uuid => $_) {
|
|
||||||
$found = false;
|
|
||||||
foreach ($channelVideos as $v) {
|
|
||||||
if (($v['shortUUID'] ?: $v['uuid']) === $uuid) {
|
|
||||||
$found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!$found) {
|
|
||||||
$stale[] = [
|
|
||||||
'uuid' => $uuid,
|
|
||||||
'theses' => $linkedMap[$uuid] ?? [],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$totalOnChannel = count($channelVideos);
|
|
||||||
|
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
echo json_encode([
|
echo json_encode(getPeerTubeOrphansData());
|
||||||
'configured' => true,
|
|
||||||
'channel_name' => PeerTubeService::getSettings($db)['channel_name'],
|
|
||||||
'total_on_channel' => $totalOnChannel,
|
|
||||||
'total_linked' => count($linked),
|
|
||||||
'orphan_count' => count($orphans),
|
|
||||||
'orphans' => $orphans,
|
|
||||||
'stale_count' => count($stale),
|
|
||||||
'stale_entries' => $stale,
|
|
||||||
]);
|
|
||||||
|
|||||||
@@ -2235,6 +2235,9 @@ th.admin-ap-col {
|
|||||||
|
|
||||||
.admin-main--toc > article > section {
|
.admin-main--toc > article > section {
|
||||||
margin-bottom: var(--space-xl);
|
margin-bottom: var(--space-xl);
|
||||||
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.admin-main--toc > article > section > fieldset {
|
.admin-main--toc > article > section > fieldset {
|
||||||
|
|||||||
@@ -1,47 +1,29 @@
|
|||||||
<main id="main-content" class="admin-main--list">
|
<main id="main-content">
|
||||||
<div class="admin-list-toolbar admin-list-toolbar--list" style="margin-bottom:var(--space-m)">
|
<article style="padding-top:var(--space-m)">
|
||||||
<div class="admin-toolbar-top">
|
<h1 style="margin:0 0 var(--space-xl)">
|
||||||
<div class="admin-toolbar-title-row">
|
<a href="/admin/" class="admin-back-btn" title="Retour à la liste"><?= icon('arrow-left-circle') ?></a>
|
||||||
<h1>
|
Nettoyer les fichiers temporaires
|
||||||
<a href="/admin/" class="admin-back-btn" title="Retour à la liste"><?= icon('arrow-left-circle') ?></a>
|
</h1>
|
||||||
Nettoyer les fichiers temporaires
|
|
||||||
</h1>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<article>
|
<section aria-labelledby="cleanup-tmp-title">
|
||||||
<section aria-labelledby="tmp-files-title">
|
<h2 id="cleanup-tmp-title">Fichiers temporaires</h2>
|
||||||
<h2 id="tmp-files-title">Téléversements et corbeille</h2>
|
|
||||||
<div id="tmp-cleanup-stats-wrapper"
|
<div id="tmp-cleanup-stats-wrapper"
|
||||||
hx-get="/admin/actions/cleanup-stats-fragment.php"
|
hx-get="/admin/actions/cleanup-stats-fragment.php"
|
||||||
hx-trigger="load"
|
hx-trigger="load"
|
||||||
hx-swap="innerHTML"
|
hx-swap="innerHTML"
|
||||||
hx-indicator="#tmp-cleanup-stats-wrapper">
|
hx-indicator="#tmp-cleanup-stats-wrapper">
|
||||||
<fieldset>
|
<p class="admin-muted">Chargement…</p>
|
||||||
<legend>
|
|
||||||
<?= icon('paint-brush-household') ?>
|
|
||||||
Fichiers temporaires
|
|
||||||
</legend>
|
|
||||||
<p style="margin:0;color:var(--text-secondary)">Chargement…</p>
|
|
||||||
</fieldset>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section aria-labelledby="peertube-title">
|
<section aria-labelledby="cleanup-peertube-title">
|
||||||
<h2 id="peertube-title">Vidéos PeerTube</h2>
|
<h2 id="cleanup-peertube-title">Vidéos PeerTube</h2>
|
||||||
<div id="peertube-orphans-fragment"
|
<div id="peertube-orphans-fragment"
|
||||||
hx-get="/admin/actions/peertube-orphans-fragment.php"
|
hx-get="/admin/actions/peertube-orphans-fragment.php"
|
||||||
hx-trigger="load"
|
hx-trigger="load"
|
||||||
hx-swap="innerHTML"
|
hx-swap="innerHTML"
|
||||||
hx-indicator="#peertube-orphans-fragment">
|
hx-indicator="#peertube-orphans-fragment">
|
||||||
<fieldset>
|
<p class="admin-muted">Chargement…</p>
|
||||||
<legend>
|
|
||||||
<?= icon('video') ?>
|
|
||||||
Vidéos PeerTube
|
|
||||||
</legend>
|
|
||||||
<p style="margin:0;color:var(--text-secondary)">Chargement…</p>
|
|
||||||
</fieldset>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</article>
|
</article>
|
||||||
|
|||||||
@@ -28,11 +28,9 @@
|
|||||||
Corbeille (<?= $trashCount ?>)
|
Corbeille (<?= $trashCount ?>)
|
||||||
</a>
|
</a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<?php if ($tmpTotalCount > 0): ?>
|
|
||||||
<a href="/admin/cleanup.php" class="btn btn--sm btn--secondary">
|
<a href="/admin/cleanup.php" class="btn btn--sm btn--secondary">
|
||||||
<?= icon('trash') ?> Nettoyer (<?= $tmpTotalCount ?>)
|
<?= icon('trash') ?> Nettoyer<?= $tmpTotalCount > 0 ? " ($tmpTotalCount)" : '' ?>
|
||||||
</a>
|
</a>
|
||||||
<?php endif; ?>
|
|
||||||
<button type="button" class="btn btn--primary btn--sm" id="import-dialog-btn"
|
<button type="button" class="btn btn--primary btn--sm" id="import-dialog-btn"
|
||||||
onclick="document.getElementById('import-dialog').showModal(); window.XamxamInitFilePonds()">
|
onclick="document.getElementById('import-dialog').showModal(); window.XamxamInitFilePonds()">
|
||||||
<?= icon('tray-arrow-up') ?> Importer
|
<?= icon('tray-arrow-up') ?> Importer
|
||||||
|
|||||||
Reference in New Issue
Block a user