mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-07 03:29:19 +02:00
348 lines
14 KiB
PHP
348 lines
14 KiB
PHP
<?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));
|
|
}
|
|
?>
|
|
<?php require_once __DIR__ . '/inc/head.php'; ?>
|
|
|
|
<main>
|
|
<h2>Importer des TFE depuis un fichier CSV</h2>
|
|
|
|
<?php if (!empty($errors)): ?>
|
|
<div class="alert-error">
|
|
<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 class="alert-success">
|
|
<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 class="info-message">
|
|
<pre><?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 require_once __DIR__ . "/inc/footer.php"; ?>
|