mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-06 19:19:19 +02:00
Fix admin CSS not loading and quirks mode issues
Fixed multiple issues in admin panel: 1. CSS path: modern-normalize.css → modern-normalize.min.css (File is actually named .min.css) 2. Icon path: assets/icon.svg → /assets/admin_favicon.svg (Was relative, now absolute; correct filename) 3. Navigation: /admin/list.php → /admin/ (list.php was renamed to index.php) 4. Short PHP tags: <? → <?php (Better compatibility, some servers don't enable short_open_tag) 5. Quirks mode warning was due to CSS not loading, not DOCTYPE (DOCTYPE was already present) Files modified: - public/admin/inc/head.php (main fixes) - public/admin/index.php (short tags) - public/admin/add.php (short tags) - public/admin/import.php (short tags) Need to redeploy for production: just deploy
This commit is contained in:
355
public/admin/import.php
Normal file
355
public/admin/import.php
Normal file
@@ -0,0 +1,355 @@
|
||||
<?php
|
||||
// Bootstrap application
|
||||
require_once __DIR__ . "/../../config/bootstrap.php";
|
||||
|
||||
// CSV Import page for Post-ERG thesis database
|
||||
// This page allows importing thesis data from CSV files
|
||||
|
||||
session_start();
|
||||
|
||||
// Generate CSRF token
|
||||
if (empty($_SESSION['csrf_token'])) {
|
||||
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/../../lib/Database.php';
|
||||
|
||||
$pageTitle = "Import";
|
||||
|
||||
$message = '';
|
||||
$errors = [];
|
||||
$importedCount = 0;
|
||||
$skippedCount = 0;
|
||||
$importResults = [];
|
||||
|
||||
// Handle CSV upload and import
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['csv_file'])) {
|
||||
// Verify CSRF token
|
||||
if (!isset($_POST['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
|
||||
$errors[] = "Erreur de sécurité : token invalide.";
|
||||
} else {
|
||||
try {
|
||||
$db = new Database();
|
||||
$pdo = $db->getPDO();
|
||||
|
||||
// Check file upload
|
||||
if ($_FILES['csv_file']['error'] !== UPLOAD_ERR_OK) {
|
||||
throw new Exception("Erreur lors du téléversement du fichier.");
|
||||
}
|
||||
|
||||
// Read CSV file
|
||||
$csvFile = $_FILES['csv_file']['tmp_name'];
|
||||
$handle = fopen($csvFile, 'r');
|
||||
|
||||
if (!$handle) {
|
||||
throw new Exception("Impossible d'ouvrir le fichier CSV.");
|
||||
}
|
||||
|
||||
// Skip first two rows (empty and headers)
|
||||
fgetcsv($handle); // Empty row
|
||||
$headers = fgetcsv($handle); // Header row
|
||||
fgetcsv($handle); // Description row
|
||||
$headers = fgetcsv($handle); // Actual column names
|
||||
|
||||
// Map CSV columns
|
||||
$columnMap = [
|
||||
0 => 'identifier', // Identifiant
|
||||
1 => 'title', // Titre
|
||||
2 => 'subtitle', // Sous-titre
|
||||
3 => 'authors', // Auteur·ice(s)
|
||||
4 => 'contact', // Contact
|
||||
5 => 'supervisors', // Promoteur·ice(s)
|
||||
6 => 'formats', // Format
|
||||
7 => 'year', // Année
|
||||
8 => 'ap', // AP
|
||||
9 => 'orientation', // Orientation
|
||||
10 => 'finality', // Finalité
|
||||
11 => 'keywords', // Mots-clés
|
||||
12 => 'synopsis', // Synopsis
|
||||
13 => 'context', // Contexte
|
||||
14 => 'remarks', // Remarques
|
||||
15 => 'language', // Langue
|
||||
16 => 'access', // Autorisation
|
||||
17 => 'license', // License
|
||||
18 => 'size_info', // taille
|
||||
19 => 'jury_points', // Points sur 20
|
||||
20 => 'baiu_link', // lien BAIU
|
||||
];
|
||||
|
||||
// Orientation abbreviation mapping
|
||||
$orientationMap = [
|
||||
'SC' => 'Sculpture',
|
||||
'VI' => 'Vidéographie',
|
||||
'CA' => 'Cinéma d\'animation',
|
||||
'IP' => 'Installation-Performance',
|
||||
'PE' => 'Peinture',
|
||||
'PH' => 'Photographie',
|
||||
'DE' => 'Dessin',
|
||||
'AN' => 'Arts Numériques',
|
||||
'GR' => 'Graphisme',
|
||||
'TY' => 'Typographie',
|
||||
'DN' => 'Design Numérique',
|
||||
'IL' => 'Illustration',
|
||||
'BD' => 'Bande-Dessinée',
|
||||
'SE' => 'Sérigraphie',
|
||||
'GV' => 'Gravure',
|
||||
];
|
||||
|
||||
// Process each row
|
||||
$lineNumber = 5; // Start after headers
|
||||
while (($row = fgetcsv($handle)) !== false) {
|
||||
$lineNumber++;
|
||||
|
||||
// Skip empty rows
|
||||
if (empty($row[0]) && empty($row[1])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$db->beginTransaction();
|
||||
|
||||
// Extract data
|
||||
$identifier = trim($row[0] ?? '');
|
||||
$title = trim($row[1] ?? '');
|
||||
$subtitle = trim($row[2] ?? '');
|
||||
$authorsRaw = trim($row[3] ?? '');
|
||||
$contact = trim($row[4] ?? '');
|
||||
$supervisorsRaw = trim($row[5] ?? '');
|
||||
$formatsRaw = trim($row[6] ?? '');
|
||||
$year = intval($row[7] ?? 0);
|
||||
$apCode = trim($row[8] ?? '');
|
||||
$orientationCode = trim($row[9] ?? '');
|
||||
$finalityName = trim($row[10] ?? '');
|
||||
$keywordsRaw = trim($row[11] ?? '');
|
||||
$synopsis = trim($row[12] ?? '');
|
||||
$context = trim($row[13] ?? '');
|
||||
$remarks = trim($row[14] ?? '');
|
||||
$languageRaw = trim($row[15] ?? '');
|
||||
$access = trim($row[16] ?? '');
|
||||
$license = trim($row[17] ?? '');
|
||||
$sizeInfo = trim($row[18] ?? '');
|
||||
$juryPoints = !empty($row[19]) ? floatval($row[19]) : null;
|
||||
$baiuLink = trim($row[20] ?? '');
|
||||
|
||||
// Validate required fields
|
||||
if (empty($title) || empty($year)) {
|
||||
throw new Exception("Ligne $lineNumber: Titre et année requis.");
|
||||
}
|
||||
|
||||
// Map orientation
|
||||
$orientationName = isset($orientationMap[$orientationCode]) ? $orientationMap[$orientationCode] : null;
|
||||
$orientationId = null;
|
||||
if ($orientationName) {
|
||||
$orientationId = $db->getOrientationId($orientationName);
|
||||
}
|
||||
|
||||
// Map AP program
|
||||
$apProgramId = null;
|
||||
if (!empty($apCode)) {
|
||||
$stmt = $pdo->prepare("SELECT id FROM ap_programs WHERE code = ?");
|
||||
$stmt->execute([$apCode]);
|
||||
$result = $stmt->fetch();
|
||||
if ($result) {
|
||||
$apProgramId = $result['id'];
|
||||
}
|
||||
}
|
||||
|
||||
// Map finality
|
||||
$finalityId = null;
|
||||
if (!empty($finalityName)) {
|
||||
$finalityId = $db->getFinalityId($finalityName);
|
||||
}
|
||||
|
||||
// Insert thesis
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO theses (
|
||||
identifier, title, subtitle, year,
|
||||
orientation_id, ap_program_id, finality_id,
|
||||
synopsis, context_note, remarks,
|
||||
file_size_info, jury_points, baiu_link,
|
||||
submitted_at
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
|
||||
");
|
||||
|
||||
$stmt->execute([
|
||||
!empty($identifier) ? $identifier : null,
|
||||
$title,
|
||||
!empty($subtitle) ? $subtitle : null,
|
||||
$year,
|
||||
$orientationId,
|
||||
$apProgramId,
|
||||
$finalityId,
|
||||
!empty($synopsis) ? $synopsis : null,
|
||||
!empty($context) ? $context : null,
|
||||
!empty($remarks) ? $remarks : null,
|
||||
!empty($sizeInfo) ? $sizeInfo : null,
|
||||
$juryPoints,
|
||||
!empty($baiuLink) ? $baiuLink : null
|
||||
]);
|
||||
|
||||
$thesisId = $pdo->lastInsertId();
|
||||
|
||||
// Add authors
|
||||
if (!empty($authorsRaw)) {
|
||||
$authors = array_map('trim', explode(',', $authorsRaw));
|
||||
foreach ($authors as $index => $authorName) {
|
||||
if (!empty($authorName)) {
|
||||
$authorId = $db->findOrCreateAuthor($authorName, $index === 0 ? $contact : null);
|
||||
$stmt = $pdo->prepare("INSERT INTO thesis_authors (thesis_id, author_id, author_order) VALUES (?, ?, ?)");
|
||||
$stmt->execute([$thesisId, $authorId, $index + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add supervisors
|
||||
if (!empty($supervisorsRaw)) {
|
||||
$supervisors = array_map('trim', explode(',', $supervisorsRaw));
|
||||
foreach ($supervisors as $index => $supervisorName) {
|
||||
if (!empty($supervisorName)) {
|
||||
$supervisorId = $db->findOrCreateSupervisor($supervisorName);
|
||||
$stmt = $pdo->prepare("INSERT INTO thesis_supervisors (thesis_id, supervisor_id, supervisor_order) VALUES (?, ?, ?)");
|
||||
$stmt->execute([$thesisId, $supervisorId, $index + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add keywords
|
||||
if (!empty($keywordsRaw)) {
|
||||
$keywords = array_map('trim', explode(',', $keywordsRaw));
|
||||
$keywords = array_slice($keywords, 0, 10); // Max 10
|
||||
foreach ($keywords as $keyword) {
|
||||
if (!empty($keyword)) {
|
||||
$keywordId = $db->findOrCreateKeyword($keyword);
|
||||
if ($keywordId) {
|
||||
$stmt = $pdo->prepare("INSERT INTO thesis_keywords (thesis_id, keyword_id) VALUES (?, ?)");
|
||||
$stmt->execute([$thesisId, $keywordId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add language
|
||||
if (!empty($languageRaw)) {
|
||||
$languageId = $db->getLanguageId(ucfirst(strtolower($languageRaw)));
|
||||
if ($languageId) {
|
||||
$stmt = $pdo->prepare("INSERT INTO thesis_languages (thesis_id, language_id) VALUES (?, ?)");
|
||||
$stmt->execute([$thesisId, $languageId]);
|
||||
}
|
||||
}
|
||||
|
||||
// Add formats
|
||||
if (!empty($formatsRaw)) {
|
||||
$formats = array_map('trim', explode(',', $formatsRaw));
|
||||
foreach ($formats as $formatName) {
|
||||
if (!empty($formatName)) {
|
||||
$formatId = $db->getFormatId(ucfirst(strtolower($formatName)));
|
||||
if ($formatId) {
|
||||
$stmt = $pdo->prepare("INSERT INTO thesis_formats (thesis_id, format_id) VALUES (?, ?)");
|
||||
$stmt->execute([$thesisId, $formatId]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$db->commit();
|
||||
$importedCount++;
|
||||
$importResults[] = "✓ Ligne $lineNumber: \"$title\" importé (ID: $thesisId)";
|
||||
} catch (Exception $e) {
|
||||
$db->rollback();
|
||||
$skippedCount++;
|
||||
$importResults[] = "✗ Ligne $lineNumber: " . $e->getMessage();
|
||||
error_log("Import error on line $lineNumber: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
fclose($handle);
|
||||
|
||||
$message = "Import terminé : $importedCount TFE importés, $skippedCount ignorés.";
|
||||
} catch (Exception $e) {
|
||||
$errors[] = $e->getMessage();
|
||||
error_log("CSV import error: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// Regenerate CSRF token
|
||||
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
||||
}
|
||||
?>
|
||||
// <title>Import CSV - Post-ERG</title>
|
||||
// <header>
|
||||
// <h1>Import CSV - Post-ERG</h1>
|
||||
// <nav>
|
||||
// <a href="index.php">← Nouveau TFE</a> |
|
||||
// <a href="list.php">📋 Liste des TFE</a>
|
||||
// </nav>
|
||||
// </header>
|
||||
|
||||
<main>
|
||||
<h2>Importer des TFE depuis un fichier CSV</h2>
|
||||
|
||||
<?php if (!empty($errors)): ?>
|
||||
<div style="background: #fee; border: 2px solid #c00; padding: 1rem; margin-bottom: 1rem; border-radius: 4px; color: #c00;">
|
||||
<strong>⚠️ Erreurs:</strong>
|
||||
<ul>
|
||||
<?php foreach ($errors as $error): ?>
|
||||
<li><?php echo htmlspecialchars($error); ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($message): ?>
|
||||
<div style="background: #efe; border: 2px solid #0a0; padding: 1rem; margin-bottom: 1rem; border-radius: 4px; color: #0a0;">
|
||||
<strong>✓ <?php echo htmlspecialchars($message); ?></strong>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form action="import.php" method="post" enctype="multipart/form-data">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo htmlspecialchars($_SESSION['csrf_token']); ?>">
|
||||
|
||||
<fieldset>
|
||||
<legend>Sélectionner un fichier CSV</legend>
|
||||
|
||||
<p><strong>Format attendu:</strong></p>
|
||||
<ul>
|
||||
<li>Colonnes: Identifiant, Titre, Sous-titre, Auteur·ice(s), Contact, Promoteur·ice(s), Format, Année, AP, Orientation, Finalité, Mots-clés, Synopsis, Contexte, Remarques, Langue, Autorisation, License, taille, Points sur 20, lien BAIU</li>
|
||||
<li>Les deux premières lignes seront ignorées (entête)</li>
|
||||
<li>Séparateur: virgule</li>
|
||||
<li>Encodage: UTF-8</li>
|
||||
</ul>
|
||||
|
||||
<label for="csv_file">Fichier CSV:</label>
|
||||
<input type="file" id="csv_file" name="csv_file" accept=".csv" required>
|
||||
|
||||
<button type="submit">Importer</button>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<?php if (!empty($importResults)): ?>
|
||||
<h3>Résultats de l'import</h3>
|
||||
<div style="background: #f5f5f5; padding: 1rem; border-radius: 4px; max-height: 400px; overflow-y: auto;">
|
||||
<pre style="margin: 0; font-size: 0.9em;"><?php
|
||||
foreach ($importResults as $result) {
|
||||
echo htmlspecialchars($result) . "\n";
|
||||
}
|
||||
?></pre>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<hr>
|
||||
|
||||
<h3>Notes importantes</h3>
|
||||
<ul>
|
||||
<li><strong>Codes orientation:</strong> SC (Sculpture), VI (Vidéographie), CA (Cinéma d'animation), IP (Installation-Performance), etc.</li>
|
||||
<li><strong>Codes AP:</strong> DPM, LIENS, APS (comme dans la base)</li>
|
||||
<li><strong>Auteurs multiples:</strong> Séparer par des virgules</li>
|
||||
<li><strong>Mots-clés:</strong> Maximum 10, séparés par des virgules</li>
|
||||
<li><strong>Formats:</strong> Séparer par des virgules</li>
|
||||
<li>Les lignes avec erreurs seront ignorées et loggées</li>
|
||||
</ul>
|
||||
|
||||
<h3>Exemple de fichier CSV</h3>
|
||||
<p>Voir: <code>../db/Database_TFE_test.csv</code></p>
|
||||
</main>
|
||||
|
||||
<?php include "inc/footer.php" ?>
|
||||
Reference in New Issue
Block a user