refactor: move Restrictions d'accès aux fichiers from contenus.php to acces.php, cleanup section

This commit is contained in:
Pontoporeia
2026-05-11 11:40:50 +02:00
parent d000f9e1d4
commit 1b0451581d
7 changed files with 152 additions and 67 deletions

19
TODO.md
View File

@@ -1,5 +1,24 @@
# TODO # TODO
## Move Restrictions d'accès aux fichiers to acces.php
- [x] Remove fieldset from templates/admin/contenus.php
- [x] Add fieldset to templates/admin/acces.php
- [x] Load $siteSettings in admin/acces.php controller
- [x] Update redirect in settings.php for formulaire_restrictions → /admin/acces.php
## Fix PeerTube upload — Google-resumable protocol adherence
- [x] Use Location header from init response (not reconstruct URL from JSON body)
- [x] Switch chunk method from PUT → PATCH (Google-resumable variant)
- [x] Use actual file MIME type in chunk Content-Type (not application/octet-stream)
- [x] Ensure chunk size is multiple of 256 KB
- [x] Add PATCH/HEAD methods to httpRequest()
- [x] Add CURLOPT_HEADERFUNCTION to capture response headers
- [x] Disable CURLOPT_FOLLOWLOCATION to preserve Location header
- [x] Add cancelUpload() helper for Delete-on-error cleanup
- [ ] Test with actual PeerTube instance
## HTMX Toast Feedback for Settings Checkboxes (contenus.php) ## HTMX Toast Feedback for Settings Checkboxes (contenus.php)
- [x] Add `hx-target` response divs to the three fieldsets in contenus.php - [x] Add `hx-target` response divs to the three fieldsets in contenus.php

View File

@@ -15,8 +15,12 @@ $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https'
$baseUrl = $protocol . '://' . ($_SERVER['HTTP_HOST'] ?? 'localhost'); $baseUrl = $protocol . '://' . ($_SERVER['HTTP_HOST'] ?? 'localhost');
// ── Demandes d'accès aux fichiers ───────────────────────────────────────────── // ── Demandes d'accès aux fichiers ─────────────────────────────────────────────
require_once APP_ROOT . '/src/Database.php';
require_once APP_ROOT . '/src/Controllers/FileAccessController.php'; require_once APP_ROOT . '/src/Controllers/FileAccessController.php';
$db = new Database();
$siteSettings = $db->getAllSettings();
$controller = FileAccessController::create(); $controller = FileAccessController::create();
$vars = $controller->handle(); $vars = $controller->handle();
extract($vars); extract($vars);

View File

@@ -162,8 +162,10 @@ $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
// Redirect back to wherever the form came from, defaulting to parametres // Redirect back to wherever the form came from, defaulting to parametres
$redirect = '/admin/parametres.php'; $redirect = '/admin/parametres.php';
if (in_array($section, ['formulaire_restrictions', 'formulaire_acces', 'objet_types'], true)) { if (in_array($section, ['formulaire_acces', 'objet_types'], true)) {
$redirect = '/admin/contenus.php'; $redirect = '/admin/contenus.php';
} elseif ($section === 'formulaire_restrictions') {
$redirect = '/admin/acces.php';
} }
header('Location: ' . $redirect); header('Location: ' . $redirect);
exit; exit;

View File

@@ -17,10 +17,11 @@
* instance's /api/v1/oauth-clients/local endpoint and cached in-memory * instance's /api/v1/oauth-clients/local endpoint and cached in-memory
* per process lifetime. * per process lifetime.
* *
* Upload uses the resumable protocol: * Upload uses the Google-resumable protocol:
* POST /api/v1/videos/upload-resumable — init * POST /api/v1/videos/upload-resumable — init (→ Location header with upload URL token)
* PUT /api/v1/videos/upload-resumable — send chunk * PATCH <Location URL> — send chunk
* DELETE /api/v1/videos/upload-resumable — cancel * HEAD <Location URL> — resume check
* DELETE <Location URL> — cancel
*/ */
class PeerTubeService class PeerTubeService
{ {
@@ -205,33 +206,31 @@ class PeerTubeService
'Content-Length: ' . strlen($initBody), 'Content-Length: ' . strlen($initBody),
]); ]);
$initJson = json_decode($initResponse['body'], true); // PeerTube Google-resumable returns the upload session URL in the Location header.
if ($initResponse['status'] < 200 || $initResponse['status'] >= 300) { // The JSON body contains video.id (upload session ID, not final video ID).
$chunkUrl = $initResponse['headers']['location'] ?? $initResponse['headers']['Location'] ?? null;
if (!$chunkUrl) {
$initJson = json_decode($initResponse['body'], true);
$msg = $initJson['error'] ?? $initJson['detail'] ?? $initResponse['body']; $msg = $initJson['error'] ?? $initJson['detail'] ?? $initResponse['body'];
throw new \RuntimeException('PeerTube upload init failed (' . $initResponse['status'] . '): ' . $msg); throw new \RuntimeException('PeerTube upload init: no Location header (' . $initResponse['status'] . '): ' . $msg);
} }
// Small files may complete in one shot // Relative Location? Make it absolute.
$shortUuid = $initJson['video']['shortUUID'] ?? $initJson['video']['uuid'] ?? null; if (!str_starts_with($chunkUrl, 'http')) {
if ($shortUuid && !isset($initJson['video']['id'])) { $chunkUrl = rtrim($baseUrl, '/') . $chunkUrl;
$watchUrl = rtrim($baseUrl, '/') . '/videos/watch/' . $shortUuid;
return ['uuid' => $shortUuid, 'watchUrl' => $watchUrl];
} }
$uploadId = $initJson['video']['id'] ?? null; // ── Step 2: Send chunks via PATCH (Google-resumable variant) ──
if (!$uploadId) {
throw new \RuntimeException('PeerTube upload init: no upload session returned.');
}
// ── Step 2: Send chunks ──
$chunkUrl = $baseUrl . '/api/v1/videos/upload-resumable?upload_id=' . urlencode((string)$uploadId);
$fh = fopen($filePath, 'rb'); $fh = fopen($filePath, 'rb');
if (!$fh) { if (!$fh) {
throw new \RuntimeException('Cannot open file for resumable upload.'); throw new \RuntimeException('Cannot open file for resumable upload.');
} }
$chunkSize = 4 * 1024 * 1024; // Chunk size: 1 MB, must be a multiple of 256 KB (262144 bytes).
$chunkSizeBase = 256 * 1024;
$chunkSize = max($chunkSizeBase, min(4 * 1024 * 1024, (int)ceil($fileSize / 100)));
$chunkSize = (int)ceil($chunkSize / $chunkSizeBase) * $chunkSizeBase;
$offset = 0; $offset = 0;
$lastResponse = null; $lastResponse = null;
@@ -240,9 +239,9 @@ class PeerTubeService
$chunkLen = strlen($chunk); $chunkLen = strlen($chunk);
$end = $offset + $chunkLen - 1; $end = $offset + $chunkLen - 1;
$resp = self::httpRequest($chunkUrl, 'PUT', $chunk, [ $resp = self::httpRequest($chunkUrl, 'PATCH', $chunk, [
'Authorization: Bearer ' . $token, 'Authorization: Bearer ' . $token,
'Content-Type: application/octet-stream', 'Content-Type: ' . $mimeType,
'Content-Range: bytes ' . $offset . '-' . $end . '/' . $fileSize, 'Content-Range: bytes ' . $offset . '-' . $end . '/' . $fileSize,
'Content-Length: ' . $chunkLen, 'Content-Length: ' . $chunkLen,
], 600); ], 600);
@@ -256,13 +255,12 @@ class PeerTubeService
break; break;
} }
} elseif ($resp['status'] === 308) { } elseif ($resp['status'] === 308) {
// Resume Incomplete — chunk accepted, continue
continue; continue;
} else { } else {
fclose($fh); fclose($fh);
try { try {
self::httpRequest($chunkUrl, 'DELETE', '', [ self::cancelUpload($chunkUrl, $token);
'Authorization: Bearer ' . $token, 'Content-Length: 0',
], 10);
} catch (\Throwable $e) { /* ignore */ } } catch (\Throwable $e) { /* ignore */ }
$errJson = json_decode($resp['body'], true); $errJson = json_decode($resp['body'], true);
$msg = $errJson['error'] ?? $errJson['detail'] ?? $resp['body']; $msg = $errJson['error'] ?? $errJson['detail'] ?? $resp['body'];
@@ -436,10 +434,25 @@ class PeerTubeService
// HTTP helper // HTTP helper
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
/**
* Cancel a resumable upload session.
*/
private static function cancelUpload(string $chunkUrl, string $token): void
{
self::httpRequest($chunkUrl, 'DELETE', '', [
'Authorization: Bearer ' . $token,
'Content-Length: 0',
], 10);
}
// -------------------------------------------------------------------------
// HTTP helper
// -------------------------------------------------------------------------
/** /**
* Minimal cURL HTTP helper. * Minimal cURL HTTP helper.
* *
* @return array{status:int, body:string} * @return array{status:int, body:string, headers:array<string,string>}
*/ */
public static function httpRequest( public static function httpRequest(
string $url, string $url,
@@ -457,31 +470,47 @@ class PeerTubeService
CURLOPT_RETURNTRANSFER => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => $timeout, CURLOPT_TIMEOUT => $timeout,
CURLOPT_CONNECTTIMEOUT => 15, CURLOPT_CONNECTTIMEOUT => 15,
CURLOPT_FOLLOWLOCATION => true, CURLOPT_FOLLOWLOCATION => false, // Must be false to capture Location header
CURLOPT_MAXREDIRS => 3, CURLOPT_MAXREDIRS => 3,
CURLOPT_SSL_VERIFYPEER => true, CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2, CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_HTTPHEADER => $headers, CURLOPT_HTTPHEADER => $headers,
CURLOPT_HEADERFUNCTION => function ($ch, $headerLine) use (&$responseHeaders) {
$len = strlen($headerLine);
$parts = explode(':', $headerLine, 2);
if (count($parts) === 2) {
$responseHeaders[strtolower(trim($parts[0]))] = trim($parts[1]);
}
return $len;
},
]); ]);
$responseHeaders = [];
if ($method === 'POST') { if ($method === 'POST') {
curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body); curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
} elseif ($method === 'PUT') { } elseif ($method === 'PUT') {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT'); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_POSTFIELDS, $body); curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
} elseif ($method === 'PATCH') {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
} elseif ($method === 'DELETE') { } elseif ($method === 'DELETE') {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE'); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
} elseif ($method === 'HEAD') {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'HEAD');
curl_setopt($ch, CURLOPT_NOBODY, true);
} }
$responseBody = curl_exec($ch); $responseBody = curl_exec($ch);
$status = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE); $status = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
$error = curl_error($ch); $error = curl_error($ch);
if ($responseBody === false) { if ($responseBody === false && $method !== 'HEAD') {
throw new \RuntimeException('Erreur réseau PeerTube : ' . $error); throw new \RuntimeException('Erreur réseau PeerTube : ' . $error);
} }
return ['status' => $status, 'body' => (string)$responseBody]; return ['status' => $status, 'body' => (string)$responseBody, 'headers' => $responseHeaders];
} }
} }

View File

@@ -844,6 +844,32 @@
+%%%%%%% diff from: somsyvxz 249f7943 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebased revision) +%%%%%%% diff from: somsyvxz 249f7943 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebased revision)
+\\\\\\\ to: usmyqlwr 6acee66b "cleanup: merge SMTP fields into single fieldset, rename to Emails" (rebased revision) +\\\\\\\ to: usmyqlwr 6acee66b "cleanup: merge SMTP fields into single fieldset, rename to Emails" (rebased revision)
++ $linkName = $link['name'] ?? ''; ++ $linkName = $link['name'] ?? '';
++ $linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : '';
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff from: usmyqlwr 6acee66b "cleanup: merge SMTP fields into single fieldset, rename to Emails" (rebased revision)
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ to: somsyvxz 249f7943 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebased revision)
- $linkName = $link['name'] ?? '';
- $linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : '';
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff from: somsyvxz 14a3cd10 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebase destination)
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ to: omwsuqoy 6cde5a47 "move Restrictions d'accès aux fichiers from contenus.php to acces.php" (rebased revision)
$linkName = $link['name'] ?? '';
$linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : '';
$linkLockedYear = $link['locked_year'] ?? null;
+%%%%%%% diff from: somsyvxz 249f7943 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebased revision)
+\\\\\\\ to: omwsuqoy 5886b400 "move Restrictions d'accès aux fichiers from contenus.php to acces.php" (rebased revision)
++ $linkName = $link['name'] ?? '';
++ $linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : '';
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff from: omwsuqoy 5886b400 "move Restrictions d'accès aux fichiers from contenus.php to acces.php" (rebased revision)
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ to: somsyvxz 249f7943 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebased revision)
- $linkName = $link['name'] ?? '';
- $linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : '';
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff from: somsyvxz 14a3cd10 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebase destination)
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ to: usxlqwxk 4dda0271 "Cleanup acces fichier section" (rebased revision)
$linkName = $link['name'] ?? '';
$linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : '';
$linkLockedYear = $link['locked_year'] ?? null;
+%%%%%%% diff from: somsyvxz 249f7943 "Bulk bar anti-shift, tags icons, AP no-wrap, credits reorder" (rebased revision)
+\\\\\\\ to: usxlqwxk 3cd56fd1 "Cleanup acces fichier section" (rebased revision)
++ $linkName = $link['name'] ?? '';
++ $linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : ''; ++ $linkExpiresVal = $link['expires_at'] ? date('Y-m-d\TH:i', strtotime($link['expires_at'])) : '';
?> ?>
<tr class="admin-table-row" onclick="event.stopPropagation(); window.open('/partage/<?= urlencode($link['slug']) ?>', '_blank')" style="cursor:pointer"> <tr class="admin-table-row" onclick="event.stopPropagation(); window.open('/partage/<?= urlencode($link['slug']) ?>', '_blank')" style="cursor:pointer">
@@ -970,7 +996,39 @@
DEMANDES D'ACCÈS AUX FICHIERS DEMANDES D'ACCÈS AUX FICHIERS
══════════════════════════════════════════════════════════════ --> ══════════════════════════════════════════════════════════════ -->
<section aria-labelledby="acces-fichiers-title"> <section aria-labelledby="acces-fichiers-title">
<h2 id="acces-fichiers-title">Demandes d'accès aux fichiers</h2>
<h2>Fichiers</h2>
<h3 id="acces-fichiers-title">Restrictions d'accès aux fichiers</h3>
<fieldset id="fieldset-restrictions">
<legend>Paramètre global</legend>
<div class="param-form">
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
<input type="hidden" name="section" value="formulaire_restrictions">
<label class="param-checkbox">
<input type="checkbox" name="restricted_files_enabled" value="1"
<?= ($siteSettings['restricted_files_enabled'] ?? '0') === '1' ? 'checked' : '' ?>
hx-post="/admin/actions/settings.php"
hx-trigger="change"
hx-target="#restrictions-response"
hx-swap="innerHTML"
hx-include="#fieldset-restrictions"
hx-on::before-request="console.log('[restrictions] sending checked=' + this.checked + ' POST keys will include all #fieldset-restrictions inputs')"
hx-on::after-request="console.log('[restrictions] response received')">
<span>
<strong>Activer la restriction d'accès</strong><br>
<small>Pour les TFE de type "Interne", masquer les fichiers et exiger une demande d'accès par email. Les métadonnées et le résumé restent visibles publiquement.</small>
</span>
</label>
</div>
<div id="restrictions-response" aria-live="polite"></div>
</fieldset>
<h3 id="acces-fichiers-title">Demandes d'accès aux fichiers</h3>
<div class="access-req-stats"> <div class="access-req-stats">
<div class="access-req-stat-card"> <div class="access-req-stat-card">

View File

@@ -85,33 +85,6 @@
<section aria-labelledby="form-settings-title"> <section aria-labelledby="form-settings-title">
<h2 id="form-settings-title">Paramètres du Formulaire</h2> <h2 id="form-settings-title">Paramètres du Formulaire</h2>
<fieldset id="fieldset-restrictions">
<legend>Restrictions d'accès aux fichiers</legend>
<div class="param-form">
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
<input type="hidden" name="section" value="formulaire_restrictions">
<label class="param-checkbox">
<input type="checkbox" name="restricted_files_enabled" value="1"
<?= ($siteSettings['restricted_files_enabled'] ?? '0') === '1' ? 'checked' : '' ?>
hx-post="/admin/actions/settings.php"
hx-trigger="change"
hx-target="#restrictions-response"
hx-swap="innerHTML"
hx-include="#fieldset-restrictions"
hx-on::before-request="console.log('[restrictions] sending checked=' + this.checked + ' POST keys will include all #fieldset-restrictions inputs')"
hx-on::after-request="console.log('[restrictions] response received')">
<span>
<strong>Activer la restriction d'accès</strong><br>
<small>Pour les TFE de type "Interne", masquer les fichiers et exiger une demande d'accès par email. Les métadonnées et le résumé restent visibles publiquement.</small>
</span>
</label>
</div>
<div id="restrictions-response" aria-live="polite"></div>
</fieldset>
<fieldset id="fieldset-acces"> <fieldset id="fieldset-acces">
<legend>Degré d'ouverture</legend> <legend>Degré d'ouverture</legend>
<p>Options de visibilité disponibles dans le formulaire d'ajout de TFE.</p> <p>Options de visibilité disponibles dans le formulaire d'ajout de TFE.</p>

View File

@@ -78,7 +78,9 @@
<input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>"> <input type="hidden" name="csrf_token" value="<?= htmlspecialchars($_SESSION['csrf_token']) ?>">
<input type="hidden" name="section" value="smtp"> <input type="hidden" name="section" value="smtp">
<div class="param-grid"> <fieldset class="param-grid">
<legend>Paramètres email</legend>
<div> <div>
<label for="smtp_host">Hôte SMTP</label> <label for="smtp_host">Hôte SMTP</label>
<input type="text" id="smtp_host" name="smtp_host" <input type="text" id="smtp_host" name="smtp_host"
@@ -146,7 +148,7 @@
placeholder="admin@example.com"> placeholder="admin@example.com">
<small>Reçoit les notifications (demandes d'accès, etc.). Si vide, utilise l'adresse d'expédition.</small> <small>Reçoit les notifications (demandes d'accès, etc.). Si vide, utilise l'adresse d'expédition.</small>
</div> </div>
</div> </fieldset>
<button type="submit" class="btn btn--primary">Enregistrer</button> <button type="submit" class="btn btn--primary">Enregistrer</button>
</form> </form>
@@ -182,10 +184,6 @@
Intégration avec une instance PeerTube pour l'hébergement des vidéos et fichiers audio. Intégration avec une instance PeerTube pour l'hébergement des vidéos et fichiers audio.
Les fichiers sont uploadés via l'API PeerTube et intégrés comme lecteurs embarqués sur la page du TFE. Les fichiers sont uploadés via l'API PeerTube et intégrés comme lecteurs embarqués sur la page du TFE.
</p> </p>
<p class="param-note">
⚠ L'activation nécessite un quota d'upload suffisant sur l'instance PeerTube.
Laissez désactivé jusqu'à obtention du quota.
</p>
<div class="param-smtp-status"> <div class="param-smtp-status">
<?php if ($peerTubeConfigured): ?> <?php if ($peerTubeConfigured): ?>
@@ -213,12 +211,14 @@
</label> </label>
</fieldset> </fieldset>
<fieldset class="param-grid">
<legend>Paramètres Peertube</legend>
<p class="param-note"> <p class="param-note">
L'authentification PeerTube utilise les mêmes identifiants que le L'authentification PeerTube utilise les mêmes identifiants que le
<strong>relay SMTP</strong> configuré ci-dessus. <strong>relay SMTP</strong> configuré ci-dessus.
</p> </p>
<div class="param-grid">
<div> <div>
<label for="peertube_instance_url">URL de l'instance PeerTube</label> <label for="peertube_instance_url">URL de l'instance PeerTube</label>
<input type="url" id="peertube_instance_url" name="peertube_instance_url" <input type="url" id="peertube_instance_url" name="peertube_instance_url"
@@ -243,7 +243,7 @@
<option value="3" <?= (int)$peerTubeSettings['privacy'] === 3 ? 'selected' : '' ?>>Privée</option> <option value="3" <?= (int)$peerTubeSettings['privacy'] === 3 ? 'selected' : '' ?>>Privée</option>
</select> </select>
</div> </div>
</div> </fieldset>
<button type="submit" class="btn btn--primary">Enregistrer</button> <button type="submit" class="btn btn--primary">Enregistrer</button>
<button type="button" class="btn btn--secondary" id="peertube-test-btn" <button type="button" class="btn btn--secondary" id="peertube-test-btn"