mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-06 11:09:18 +02:00
Extract ThesisCreateController; add Database publish methods
Consolidate action handlers into controller methods (todo/02-php-components.md).
src/ThesisCreateController.php (new, 435 lines)
Mirrors ThesisEditController for the add-thesis flow.
make() — factory; instantiates Database via new Database()
loadFormData() — returns all lookup tables needed by admin/add.php
(orientations, apPrograms, finalityTypes, languages,
formatTypes, licenseTypes)
submit(post, files) — full new-thesis creation pipeline:
1. validateAndSanitise() — trims/strips HTML, validates required fields,
year range, orientation/ap/finality IDs, language selection, max-10
keywords, URL format; throws named Exception on failure
2. findOrCreateAuthor() — reuses existing DB method
3. Transaction: createThesis + setThesisJury + setThesisLanguages +
setThesisFormats + setThesisTags; rolls back on any failure
4. File uploads outside transaction: cover image (JPG/PNG only, stored in
storage/covers/), banner via handleBannerUpload(), thesis files
(PDF/JPG/PNG/MP4/ZIP/VTT, stored in storage/theses/YEAR/IDENT/,
file_type auto-detected: caption/annex/main/other)
autofocusFieldForError() — static; maps exception messages to field names
for WCAG 3.3.1 autofocus on re-render (same contract as
ThesisEditController::autofocusFieldForError)
admin/actions/formulaire.php 346 → 45 lines
Now: bootstrap + CSRF guard + ThesisCreateController::make()->submit() +
flash/redirect on error. All validation, DB logic, and file handling removed.
admin/add.php
Lookup-table block (new Database() + 6 individual DB calls) replaced with
ThesisCreateController::make()->loadFormData() + extract().
src/Database.php — two new methods added
setPublished(int , bool ): void
UPDATE theses SET is_published = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?
bulkSetPublished(int[] , bool ): void
Same but with an IN (...) clause for multiple IDs
admin/actions/publish.php 100 → 65 lines
Raw SQL (->prepare('UPDATE theses SET is_published = ?...')) replaced
with ->setPublished() / ->bulkSetPublished(). No raw PDO calls remain
in any action handler file.
This commit is contained in:
@@ -1,346 +1,45 @@
|
||||
<?php // formulaire.php
|
||||
<?php
|
||||
// Bootstrap application
|
||||
require_once __DIR__ . "/../../../config/bootstrap.php";
|
||||
require_once __DIR__ . '/../../../config/bootstrap.php';
|
||||
require_once __DIR__ . '/../../../src/AdminAuth.php';
|
||||
|
||||
// Configure error reporting
|
||||
ini_set('display_errors', 0);
|
||||
ini_set('log_errors', 1);
|
||||
ini_set('error_log', 'error.log');
|
||||
|
||||
// PHP-level auth guard (defence-in-depth behind nginx Basic Auth)
|
||||
AdminAuth::requireLogin();
|
||||
|
||||
// Verify CSRF token
|
||||
if (!isset($_POST['csrf_token']) || !isset($_SESSION['csrf_token']) ||
|
||||
!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
|
||||
error_log("CSRF token validation failed");
|
||||
die("Erreur de sécurité : token invalide. Veuillez recharger le formulaire.");
|
||||
if (!isset($_POST['csrf_token'], $_SESSION['csrf_token'])
|
||||
|| !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
|
||||
error_log('CSRF token validation failed in formulaire.php');
|
||||
die('Erreur de sécurité : token invalide. Veuillez recharger le formulaire.');
|
||||
}
|
||||
|
||||
// Log the content of the $_FILES array
|
||||
error_log("FILES array: " . print_r($_FILES, true));
|
||||
error_log('FILES array: ' . print_r($_FILES, true));
|
||||
|
||||
require_once __DIR__ . '/../../../src/Database.php';
|
||||
|
||||
// Helper function to sanitize string input
|
||||
function sanitize_string($input) {
|
||||
// Trim and strip raw HTML tags only — htmlspecialchars belongs at render time, not storage time.
|
||||
// PDO parameterised queries handle SQL injection; the templates call htmlspecialchars() on output.
|
||||
return strip_tags(trim($input));
|
||||
}
|
||||
|
||||
// Helper function to validate required field
|
||||
function validate_required($value, $fieldName) {
|
||||
if (empty($value)) {
|
||||
throw new Exception("Le champ '$fieldName' est requis.");
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
require_once APP_ROOT . '/src/ThesisCreateController.php';
|
||||
|
||||
try {
|
||||
// Initialize database connection
|
||||
$db = new Database();
|
||||
// Begin transaction - all or nothing
|
||||
$db->beginTransaction();
|
||||
$ctrl = ThesisCreateController::make();
|
||||
$thesisId = $ctrl->submit($_POST, $_FILES);
|
||||
|
||||
// ===== VALIDATE AND SANITIZE INPUT DATA =====
|
||||
|
||||
// Author information
|
||||
$auteurName = validate_required(sanitize_string($_POST["auteurice"] ?? ''), "Nom/Prénom/Pseudo");
|
||||
|
||||
$mail = $_POST["mail"] ?? '';
|
||||
if (!empty($mail)) {
|
||||
// Could be email or social media handle
|
||||
$mail = sanitize_string($mail);
|
||||
}
|
||||
|
||||
// Year validation
|
||||
$annee = filter_var($_POST["année"] ?? '', FILTER_VALIDATE_INT);
|
||||
if ($annee === false || $annee < 2000 || $annee > (int)date('Y') + 1) {
|
||||
throw new Exception("Année invalide. Veuillez entrer une année valide.");
|
||||
}
|
||||
|
||||
// Academic details
|
||||
$orientationId = filter_var($_POST["orientation"] ?? '', FILTER_VALIDATE_INT);
|
||||
if ($orientationId === false) {
|
||||
throw new Exception("Veuillez sélectionner une orientation.");
|
||||
}
|
||||
|
||||
$apProgramId = filter_var($_POST["ap"] ?? '', FILTER_VALIDATE_INT);
|
||||
if ($apProgramId === false) {
|
||||
throw new Exception("Veuillez sélectionner un Atelier Pratique.");
|
||||
}
|
||||
|
||||
$finalityId = filter_var($_POST["finality"] ?? '', FILTER_VALIDATE_INT);
|
||||
if ($finalityId === false) {
|
||||
throw new Exception("Veuillez sélectionner une finalité.");
|
||||
}
|
||||
|
||||
// Thesis content
|
||||
$titre = validate_required(sanitize_string($_POST["titre"] ?? ''), "Titre du mémoire");
|
||||
$subtitle = sanitize_string($_POST["subtitle"] ?? '');
|
||||
$synopsis = validate_required(sanitize_string($_POST["synopsis"] ?? ''), "Synopsis");
|
||||
$durationInfo = sanitize_string($_POST["duration_info"] ?? '');
|
||||
|
||||
// Jury members
|
||||
$juryMembers = [];
|
||||
if (!empty(trim($_POST['jury_president'] ?? ''))) {
|
||||
$juryMembers[] = ['name' => trim($_POST['jury_president']), 'role' => 'president', 'is_external' => 0];
|
||||
}
|
||||
if (!empty(trim($_POST['jury_promoteur'] ?? ''))) {
|
||||
$juryMembers[] = ['name' => trim($_POST['jury_promoteur']), 'role' => 'promoteur',
|
||||
'is_external' => isset($_POST['jury_promoteur_ext']) ? 1 : 0];
|
||||
}
|
||||
foreach ($_POST['jury_lecteurs'] ?? [] as $i => $name) {
|
||||
$name = trim($name);
|
||||
if ($name !== '') {
|
||||
$juryMembers[] = ['name' => $name, 'role' => 'lecteur',
|
||||
'is_external' => isset($_POST['jury_lecteurs_ext'][$i]) ? 1 : 0];
|
||||
}
|
||||
}
|
||||
|
||||
// Keywords (max 10)
|
||||
$tagRaw = sanitize_string($_POST["tag"] ?? '');
|
||||
$keywords = !empty($tagRaw) ? array_map('trim', explode(',', $tagRaw)) : [];
|
||||
if (count($keywords) > 10) {
|
||||
throw new Exception("Maximum 10 mots-clés autorisés.");
|
||||
}
|
||||
|
||||
// Languages (at least one required)
|
||||
$languageIds = $_POST["languages"] ?? [];
|
||||
if (empty($languageIds)) {
|
||||
throw new Exception("Veuillez sélectionner au moins une langue.");
|
||||
}
|
||||
$languageIds = array_map('intval', $languageIds);
|
||||
|
||||
// Formats (optional, multiple selection)
|
||||
$formatIds = isset($_POST["formats"]) ? array_map('intval', $_POST["formats"]) : [];
|
||||
|
||||
// License
|
||||
$licenseId = filter_var($_POST['license_id'] ?? '', FILTER_VALIDATE_INT) ?: null;
|
||||
|
||||
// External link
|
||||
$lien = $_POST["lien"] ?? '';
|
||||
if (!empty($lien)) {
|
||||
$lien = filter_var($lien, FILTER_VALIDATE_URL);
|
||||
if ($lien === false) {
|
||||
throw new Exception("Lien URL invalide.");
|
||||
}
|
||||
}
|
||||
|
||||
// File uploads
|
||||
$couverture = $_FILES["couverture"] ?? null;
|
||||
$bannerFile = $_FILES["banner"] ?? null;
|
||||
$files = $_FILES["files"] ?? null;
|
||||
|
||||
// ===== CREATE OR FIND AUTHOR =====
|
||||
$authorId = $db->findOrCreateAuthor($auteurName, $mail);
|
||||
error_log("Author ID: $authorId");
|
||||
|
||||
// ===== INSERT THESIS RECORD + LINK AUTHOR =====
|
||||
$thesisId = $db->createThesis([
|
||||
'year' => $annee,
|
||||
'orientation_id' => $orientationId,
|
||||
'ap_program_id' => $apProgramId,
|
||||
'finality_id' => $finalityId,
|
||||
'title' => $titre,
|
||||
'subtitle' => $subtitle,
|
||||
'synopsis' => $synopsis,
|
||||
'file_size_info' => $durationInfo,
|
||||
'baiu_link' => $lien,
|
||||
'license_id' => $licenseId,
|
||||
'author_id' => $authorId,
|
||||
]);
|
||||
$identifier = $db->getThesisIdentifier($thesisId);
|
||||
error_log("Thesis ID: $thesisId (identifier: $identifier)");
|
||||
|
||||
// ===== LINK JURY TO THESIS =====
|
||||
$db->setThesisJury($thesisId, $juryMembers);
|
||||
|
||||
// ===== LINK LANGUAGES TO THESIS =====
|
||||
$db->setThesisLanguages($thesisId, $languageIds);
|
||||
|
||||
// ===== LINK FORMATS TO THESIS =====
|
||||
$db->setThesisFormats($thesisId, $formatIds);
|
||||
|
||||
// ===== LINK TAGS TO THESIS =====
|
||||
$db->setThesisTags($thesisId, $keywords);
|
||||
|
||||
// ===== HANDLE FILE UPLOADS =====
|
||||
|
||||
// Create necessary directories — outside the webroot (security items #3 & #4).
|
||||
// Files are served through /media.php, never directly via a URL path.
|
||||
$uploadBaseDir = STORAGE_ROOT . "/theses/{$annee}/{$identifier}/";
|
||||
$coverDir = STORAGE_ROOT . "/covers/";
|
||||
$bannerDir = STORAGE_ROOT . "/banners/";
|
||||
|
||||
if (!file_exists($uploadBaseDir)) {
|
||||
mkdir($uploadBaseDir, 0755, true);
|
||||
}
|
||||
if (!file_exists($coverDir)) {
|
||||
mkdir($coverDir, 0755, true);
|
||||
}
|
||||
if (!file_exists($bannerDir)) {
|
||||
mkdir($bannerDir, 0755, true);
|
||||
}
|
||||
|
||||
// Define security constraints
|
||||
$allowedMimeTypes = ['image/jpeg', 'image/png', 'application/pdf', 'video/mp4', 'application/zip', 'text/vtt'];
|
||||
$allowedExtensions = ['jpg', 'jpeg', 'png', 'pdf', 'mp4', 'zip', 'vtt'];
|
||||
$maxFileSize = 50 * 1024 * 1024; // 50 MB
|
||||
|
||||
// Process cover image
|
||||
$coverPath = null;
|
||||
if ($couverture && isset($couverture["error"]) && $couverture["error"] === UPLOAD_ERR_OK) {
|
||||
$finfo = new finfo(FILEINFO_MIME_TYPE);
|
||||
$mimeType = $finfo->file($couverture["tmp_name"]);
|
||||
$fileExtension = strtolower(pathinfo($couverture["name"], PATHINFO_EXTENSION));
|
||||
|
||||
// Only allow image files for cover
|
||||
if (in_array($mimeType, ['image/jpeg', 'image/png']) &&
|
||||
in_array($fileExtension, ['jpg', 'jpeg', 'png'])) {
|
||||
|
||||
// Generate random filename
|
||||
$randomName = bin2hex(random_bytes(16));
|
||||
$safeFileName = $randomName . "." . $fileExtension;
|
||||
$targetFile = $coverDir . $safeFileName;
|
||||
|
||||
if (move_uploaded_file($couverture["tmp_name"], $targetFile)) {
|
||||
chmod($targetFile, 0644);
|
||||
// Path stored relative to STORAGE_ROOT; served via /media.php?path=...
|
||||
$coverPath = "covers/" . $safeFileName;
|
||||
|
||||
// Record cover in thesis_files (type = 'cover')
|
||||
$db->insertThesisFile(
|
||||
$thesisId,
|
||||
'cover',
|
||||
$coverPath,
|
||||
basename($couverture["name"]),
|
||||
$couverture["size"],
|
||||
$mimeType
|
||||
);
|
||||
error_log("Cover image uploaded: " . $safeFileName);
|
||||
}
|
||||
} else {
|
||||
error_log("Invalid cover image type: " . $mimeType);
|
||||
}
|
||||
}
|
||||
|
||||
// Process banner image
|
||||
$db->handleBannerUpload($thesisId, $bannerFile ?: null);
|
||||
|
||||
// Process thesis files
|
||||
if ($files && is_array($files["name"])) {
|
||||
for ($i = 0; $i < count($files["name"]); $i++) {
|
||||
// Skip if no file was uploaded for this slot
|
||||
if ($files["error"][$i] === UPLOAD_ERR_NO_FILE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($files["error"][$i] !== UPLOAD_ERR_OK) {
|
||||
error_log("File upload error code " . $files["error"][$i] . ": " . $files["name"][$i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Validate file
|
||||
$finfo = new finfo(FILEINFO_MIME_TYPE);
|
||||
$mimeType = $finfo->file($files["tmp_name"][$i]);
|
||||
$fileExtension = strtolower(pathinfo($files["name"][$i], PATHINFO_EXTENSION));
|
||||
|
||||
// finfo may return 'text/plain' for WebVTT on some systems; normalise by extension.
|
||||
if ($mimeType === 'text/plain' && $fileExtension === 'vtt') {
|
||||
$mimeType = 'text/vtt';
|
||||
}
|
||||
|
||||
if (!in_array($mimeType, $allowedMimeTypes) || !in_array($fileExtension, $allowedExtensions)) {
|
||||
error_log("Invalid file type: " . $files["name"][$i] . " (MIME: $mimeType)");
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($files["size"][$i] > $maxFileSize) {
|
||||
error_log("File too large: " . $files["name"][$i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Generate random filename
|
||||
$randomName = bin2hex(random_bytes(16));
|
||||
$safeFileName = $randomName . "." . $fileExtension;
|
||||
$targetFile = $uploadBaseDir . $safeFileName;
|
||||
|
||||
if (move_uploaded_file($files["tmp_name"][$i], $targetFile)) {
|
||||
chmod($targetFile, 0644);
|
||||
|
||||
// Determine file type
|
||||
$fileType = 'other';
|
||||
if ($fileExtension === 'vtt') {
|
||||
$fileType = 'caption'; // WebVTT caption sidecar
|
||||
} elseif (strpos(strtolower($files["name"][$i]), 'annex') !== false) {
|
||||
$fileType = 'annex';
|
||||
} elseif ($fileExtension === 'pdf') {
|
||||
$fileType = 'main';
|
||||
}
|
||||
|
||||
// Insert file record — path relative to STORAGE_ROOT
|
||||
$db->insertThesisFile(
|
||||
$thesisId,
|
||||
$fileType,
|
||||
"theses/{$annee}/{$identifier}/" . $safeFileName,
|
||||
basename($files["name"][$i]),
|
||||
$files["size"][$i],
|
||||
$mimeType
|
||||
);
|
||||
|
||||
error_log("File uploaded: " . $safeFileName);
|
||||
} else {
|
||||
error_log("Failed to move file: " . $files["name"][$i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== COMMIT TRANSACTION =====
|
||||
$db->commit();
|
||||
|
||||
error_log("Thesis submission completed successfully: $identifier");
|
||||
|
||||
// Clear CSRF token
|
||||
unset($_SESSION['csrf_token']);
|
||||
|
||||
// Redirect to thank you page
|
||||
header('Location: ../thanks.php?id=' . urlencode($thesisId));
|
||||
exit();
|
||||
|
||||
} catch (Exception $e) {
|
||||
// Rollback transaction on error
|
||||
if (isset($db)) {
|
||||
$db->rollback();
|
||||
}
|
||||
error_log('ThesisCreateController error: ' . $e->getMessage());
|
||||
|
||||
error_log("Form processing error: " . $e->getMessage());
|
||||
|
||||
// Save error message and form data to session
|
||||
App::flash('error', $e->getMessage());
|
||||
$_SESSION['form_data'] = $_POST;
|
||||
|
||||
// WCAG 3.3.1 — identify which field caused the error and request autofocus.
|
||||
// Mapping is based on the exception messages thrown above.
|
||||
$msg = $e->getMessage();
|
||||
$autofocusField = null;
|
||||
if (str_contains($msg, "Nom/Prénom/Pseudo")) $autofocusField = 'auteurice';
|
||||
elseif (str_contains($msg, "Titre du mémoire")) $autofocusField = 'titre';
|
||||
elseif (str_contains($msg, "Synopsis")) $autofocusField = 'synopsis';
|
||||
elseif (str_contains($msg, "Année invalide")) $autofocusField = 'année';
|
||||
elseif (str_contains($msg, "orientation")) $autofocusField = 'orientation';
|
||||
elseif (str_contains($msg, "Atelier Pratique")) $autofocusField = 'ap';
|
||||
elseif (str_contains($msg, "finalité")) $autofocusField = 'finality';
|
||||
elseif (str_contains($msg, "langue")) $autofocusField = 'languages';
|
||||
elseif (str_contains($msg, "mots-clés")) $autofocusField = 'tag';
|
||||
elseif (str_contains($msg, "Lien URL")) $autofocusField = 'lien';
|
||||
$autofocusField = ThesisCreateController::autofocusFieldForError($e->getMessage());
|
||||
if ($autofocusField !== null) {
|
||||
App::flashAutofocus($autofocusField);
|
||||
}
|
||||
|
||||
// Redirect back to form with preserved data
|
||||
header('Location: ../add.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
@@ -1,100 +1,65 @@
|
||||
<?php
|
||||
// Bootstrap application
|
||||
require_once __DIR__ . "/../../../config/bootstrap.php";
|
||||
require_once __DIR__ . '/../../../config/bootstrap.php';
|
||||
require_once __DIR__ . '/../../../src/AdminAuth.php';
|
||||
|
||||
/**
|
||||
* Handle publish/unpublish actions for theses
|
||||
*/
|
||||
// PHP-level auth guard (defence-in-depth behind nginx Basic Auth)
|
||||
AdminAuth::requireLogin();
|
||||
|
||||
require_once __DIR__ . '/../../../src/Database.php';
|
||||
|
||||
// Verify CSRF token
|
||||
if (!isset($_POST['csrf_token']) || !isset($_SESSION['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
|
||||
App::flash('error', "Erreur de sécurité : token invalide.");
|
||||
if (!isset($_POST['csrf_token'], $_SESSION['csrf_token'])
|
||||
|| !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
|
||||
App::flash('error', 'Erreur de sécurité : token invalide.');
|
||||
header('Location: ../index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$action = isset($_POST['action']) ? $_POST['action'] : '';
|
||||
$isBulk = isset($_POST['bulk']) && $_POST['bulk'] == '1';
|
||||
$action = $_POST['action'] ?? '';
|
||||
$isBulk = !empty($_POST['bulk']);
|
||||
|
||||
if (!in_array($action, ['publish', 'unpublish'])) {
|
||||
App::flash('error', "Action invalide.");
|
||||
if (!in_array($action, ['publish', 'unpublish'], true)) {
|
||||
App::flash('error', 'Action invalide.');
|
||||
header('Location: ../index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$published = ($action === 'publish');
|
||||
|
||||
try {
|
||||
$db = new Database();
|
||||
$pdo = $db->getPDO();
|
||||
|
||||
$isPublished = ($action === 'publish') ? 1 : 0;
|
||||
|
||||
if ($isBulk) {
|
||||
// Handle bulk action
|
||||
$thesisIds = isset($_POST['selected_theses']) ? $_POST['selected_theses'] : [];
|
||||
$ids = array_filter(array_map('intval', $_POST['selected_theses'] ?? []), fn($id) => $id > 0);
|
||||
|
||||
if (empty($thesisIds)) {
|
||||
App::flash('error', "Aucun TFE sélectionné.");
|
||||
if (empty($ids)) {
|
||||
App::flash('error', 'Aucun TFE sélectionné.');
|
||||
header('Location: ../index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Validate all IDs are integers
|
||||
$thesisIds = array_map('intval', $thesisIds);
|
||||
$thesisIds = array_filter($thesisIds, fn($id) => $id > 0);
|
||||
|
||||
if (empty($thesisIds)) {
|
||||
App::flash('error', "IDs invalides.");
|
||||
header('Location: ../index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Prepare placeholders for IN clause
|
||||
$placeholders = str_repeat('?,', count($thesisIds) - 1) . '?';
|
||||
$sql = "UPDATE theses SET is_published = ?, updated_at = CURRENT_TIMESTAMP WHERE id IN ($placeholders)";
|
||||
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$params = array_merge([$isPublished], $thesisIds);
|
||||
$stmt->execute($params);
|
||||
|
||||
$count = count($thesisIds);
|
||||
if ($action === 'publish') {
|
||||
App::flash('success', "$count TFE(s) publié(s) avec succès!");
|
||||
} else {
|
||||
App::flash('success', "$count TFE(s) retiré(s) de la publication.");
|
||||
}
|
||||
$db->bulkSetPublished($ids, $published);
|
||||
$count = count($ids);
|
||||
App::flash('success', $published
|
||||
? "$count TFE(s) publié(s) avec succès."
|
||||
: "$count TFE(s) retiré(s) de la publication.");
|
||||
|
||||
} else {
|
||||
// Handle single action
|
||||
$thesisId = isset($_POST['thesis_id']) ? intval($_POST['thesis_id']) : 0;
|
||||
$thesisId = filter_var($_POST['thesis_id'] ?? '', FILTER_VALIDATE_INT);
|
||||
|
||||
if ($thesisId <= 0) {
|
||||
App::flash('error', "ID invalide.");
|
||||
if (!$thesisId || $thesisId <= 0) {
|
||||
App::flash('error', 'ID invalide.');
|
||||
header('Location: ../index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("UPDATE theses SET is_published = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?");
|
||||
$stmt->execute([$isPublished, $thesisId]);
|
||||
|
||||
if ($action === 'publish') {
|
||||
App::flash('success', "TFE publié avec succès!");
|
||||
} else {
|
||||
App::flash('success', "TFE retiré de la publication.");
|
||||
}
|
||||
$db->setPublished($thesisId, $published);
|
||||
App::flash('success', $published ? 'TFE publié avec succès.' : 'TFE retiré de la publication.');
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log("Publish error: " . $e->getMessage());
|
||||
App::flash('error', "Erreur lors de la modification: " . $e->getMessage());
|
||||
error_log('publish.php error: ' . $e->getMessage());
|
||||
App::flash('error', 'Erreur lors de la modification : ' . $e->getMessage());
|
||||
}
|
||||
|
||||
// Regenerate CSRF token
|
||||
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
||||
|
||||
header('Location: ../index.php');
|
||||
exit;
|
||||
|
||||
@@ -9,19 +9,14 @@ if (empty($_SESSION["csrf_token"])) {
|
||||
|
||||
$pageTitle = "Ajouter un TFE";
|
||||
|
||||
require_once __DIR__ . '/../../src/Database.php';
|
||||
require_once __DIR__ . '/../../src/ThesisCreateController.php';
|
||||
|
||||
try {
|
||||
$db = new Database();
|
||||
$orientations = $db->getAllOrientations();
|
||||
$apPrograms = $db->getAllAPPrograms();
|
||||
$finalityTypes = $db->getAllFinalityTypes();
|
||||
$languages = $db->getAllLanguages();
|
||||
$formatTypes = $db->getAllFormatTypes();
|
||||
$licenseTypes = $db->getAllLicenseTypes();
|
||||
$ctrl = ThesisCreateController::make();
|
||||
extract($ctrl->loadFormData());
|
||||
} catch (Exception $e) {
|
||||
error_log("Failed to load form data: " . $e->getMessage());
|
||||
die("Erreur lors du chargement du formulaire.");
|
||||
error_log('Failed to load form data: ' . $e->getMessage());
|
||||
die('Erreur lors du chargement du formulaire.');
|
||||
}
|
||||
|
||||
$formData = $_SESSION['form_data'] ?? [];
|
||||
|
||||
Reference in New Issue
Block a user