mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-06-25 16:19:19 +02:00
Remove duration_pages/duration_minutes/file_size_info; rename cc4r → cc2r in DB and code
This commit is contained in:
2
TODO.md
2
TODO.md
@@ -12,3 +12,5 @@
|
||||
- [x] Fix: format checkbox toggle clears file inputs — split into two blocks: #format-fichiers-block (stable: TFE/annexes/couverture/note) and #format-extras-block (swappable: website/video/audio extras)
|
||||
- [x] Fix: remove website label/legend input — website section now shows only URL field
|
||||
- [x] Fix: format-extras not appearing — moved #format-extras-block inside Fichiers fieldset (after annexes), uses hx-select to extract from response
|
||||
- [x] Remove duration_pages, duration_minutes, file_size_info entirely (form, schema, DB, views, controllers, tests, CSV export, email)
|
||||
- [x] Rename cc4r → cc2r everywhere (DB column, schema, PHP code) to fix pre-existing naming inconsistency
|
||||
|
||||
79
app/migrations/applied/024_remove_duration_size_fields.sql
Normal file
79
app/migrations/applied/024_remove_duration_size_fields.sql
Normal file
@@ -0,0 +1,79 @@
|
||||
-- 024_remove_duration_size_fields.sql
|
||||
-- Supprime les colonnes et la vue obsolètes pour durée / taille (pages, minutes, file_size_info).
|
||||
-- Ces données sont redondantes : les fichiers eux-mêmes contiennent l'information.
|
||||
|
||||
-- Supprimer d'abord la vue qui référence ces colonnes
|
||||
DROP VIEW IF EXISTS v_theses_full;
|
||||
DROP VIEW IF EXISTS v_theses_public;
|
||||
|
||||
-- Recréer les vues sans duration_minutes, duration_pages, file_size_info
|
||||
CREATE VIEW IF NOT EXISTS v_theses_full AS
|
||||
SELECT
|
||||
t.id,
|
||||
t.identifier,
|
||||
t.title,
|
||||
t.subtitle,
|
||||
t.year,
|
||||
t.is_doctoral,
|
||||
t.objet,
|
||||
o.name as orientation,
|
||||
ap.name as ap_program,
|
||||
ft.name as finality_type,
|
||||
t.synopsis,
|
||||
t.context_note,
|
||||
at.name as access_type,
|
||||
lt.name as license_type,
|
||||
t.license_id,
|
||||
t.license_custom,
|
||||
t.access_type_id,
|
||||
t.jury_points,
|
||||
t.submitted_at,
|
||||
t.defense_date,
|
||||
t.published_at,
|
||||
t.is_published,
|
||||
t.baiu_link,
|
||||
t.banner_path,
|
||||
t.exemplaire_baiu,
|
||||
t.exemplaire_erg,
|
||||
t.cc2r,
|
||||
t.remarks,
|
||||
t.jury_note_added,
|
||||
GROUP_CONCAT(DISTINCT a.name ORDER BY a.name ASC) as authors,
|
||||
GROUP_CONCAT(DISTINCT s.name) as supervisors,
|
||||
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'president' THEN s.name END) as jury_president,
|
||||
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'promoteur' AND ts.is_ulb = 0 THEN s.name END) as jury_promoteurs,
|
||||
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'promoteur' AND ts.is_ulb = 1 THEN s.name END) as jury_promoteurs_ulb,
|
||||
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'lecteur' AND ts.is_external = 0 THEN s.name END) as jury_lecteurs_internes,
|
||||
GROUP_CONCAT(DISTINCT CASE WHEN ts.role = 'lecteur' AND ts.is_external = 1 THEN s.name END) as jury_lecteurs_externes,
|
||||
GROUP_CONCAT(DISTINCT l.name) as languages,
|
||||
GROUP_CONCAT(DISTINCT fmt.name) as formats,
|
||||
GROUP_CONCAT(DISTINCT tg.name) as keywords,
|
||||
-- First author's email and contact-visibility flag
|
||||
(SELECT a2.email FROM authors a2 JOIN thesis_authors ta2 ON a2.id = ta2.author_id WHERE ta2.thesis_id = t.id ORDER BY ta2.author_order LIMIT 1) as author_email,
|
||||
(SELECT a2.show_contact FROM authors a2 JOIN thesis_authors ta2 ON a2.id = ta2.author_id WHERE ta2.thesis_id = t.id ORDER BY ta2.author_order LIMIT 1) as author_show_contact
|
||||
FROM theses t
|
||||
LEFT JOIN orientations o ON t.orientation_id = o.id
|
||||
LEFT JOIN ap_programs ap ON t.ap_program_id = ap.id
|
||||
LEFT JOIN finality_types ft ON t.finality_id = ft.id
|
||||
LEFT JOIN access_types at ON t.access_type_id = at.id
|
||||
LEFT JOIN license_types lt ON t.license_id = lt.id
|
||||
LEFT JOIN thesis_authors ta ON t.id = ta.thesis_id
|
||||
LEFT JOIN authors a ON ta.author_id = a.id
|
||||
LEFT JOIN thesis_supervisors ts ON t.id = ts.thesis_id
|
||||
LEFT JOIN supervisors s ON ts.supervisor_id = s.id
|
||||
LEFT JOIN thesis_languages tl ON t.id = tl.thesis_id
|
||||
LEFT JOIN languages l ON tl.language_id = l.id
|
||||
LEFT JOIN thesis_formats tf ON t.id = tf.thesis_id
|
||||
LEFT JOIN format_types fmt ON tf.format_id = fmt.id
|
||||
LEFT JOIN thesis_tags tt ON t.id = tt.thesis_id
|
||||
LEFT JOIN tags tg ON tt.tag_id = tg.id
|
||||
GROUP BY t.id;
|
||||
|
||||
CREATE VIEW IF NOT EXISTS v_theses_public AS
|
||||
SELECT * FROM v_theses_full
|
||||
WHERE is_published = 1;
|
||||
|
||||
-- Supprimer les colonnes de la table
|
||||
ALTER TABLE theses DROP COLUMN duration_minutes;
|
||||
ALTER TABLE theses DROP COLUMN duration_pages;
|
||||
ALTER TABLE theses DROP COLUMN file_size_info;
|
||||
@@ -43,7 +43,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['csv_file'])) {
|
||||
'identifiant', 'titre', 'sous-titre', 'auteur', 'contact',
|
||||
'promoteur', 'format', 'année', 'ap', 'orientation', 'finalité',
|
||||
'mots-clés', 'synopsis', 'contexte', 'remarques', 'langue',
|
||||
'autorisation', 'licence', 'license', 'taille', 'points', 'lien baiu',
|
||||
'autorisation', 'licence', 'license', 'points', 'lien baiu',
|
||||
];
|
||||
for ($scan = 0; $scan < 8; $scan++) {
|
||||
$hrow = fgetcsv($handle, 0, ',', '"', '');
|
||||
@@ -248,10 +248,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['csv_file'])) {
|
||||
$languageRaw = $cell($row, 'langue', 15);
|
||||
$access = $cell($row, 'autorisation', 16);
|
||||
$license = $cell($row, 'license', 17);
|
||||
$sizeInfo = $cell($row, 'taille', 18);
|
||||
$juryPointsRaw = $cell($row, 'points', 19);
|
||||
$juryPointsRaw = $cell($row, 'points', 18);
|
||||
$juryPoints = $juryPointsRaw !== '' ? floatval($juryPointsRaw) : null;
|
||||
$baiuLink = $cell($row, 'lien baiu', 20);
|
||||
$baiuLink = $cell($row, 'lien baiu', 19);
|
||||
|
||||
if ($title === '' || $year === 0) {
|
||||
$missing = [];
|
||||
@@ -295,9 +294,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['csv_file'])) {
|
||||
identifier, title, subtitle, year,
|
||||
orientation_id, ap_program_id, finality_id,
|
||||
synopsis, context_note, remarks,
|
||||
file_size_info, jury_points, baiu_link,
|
||||
jury_points, baiu_link,
|
||||
access_type_id, is_published, submitted_at
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,1,CURRENT_TIMESTAMP)
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,1,CURRENT_TIMESTAMP)
|
||||
");
|
||||
$s->execute([
|
||||
!empty($identifier) ? $identifier : null, $title,
|
||||
@@ -306,7 +305,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['csv_file'])) {
|
||||
!empty($synopsis) ? $synopsis : null,
|
||||
!empty($context) ? $context : null,
|
||||
!empty($remarks) ? $remarks : null,
|
||||
!empty($sizeInfo) ? $sizeInfo : null,
|
||||
$juryPoints,
|
||||
!empty($baiuLink) ? $baiuLink : null,
|
||||
$accessTypeId,
|
||||
|
||||
@@ -201,7 +201,6 @@ class ExportController
|
||||
'Langue',
|
||||
'Autorisation',
|
||||
'Licence',
|
||||
'Taille',
|
||||
'Points sur 20',
|
||||
'Lien BAIU',
|
||||
];
|
||||
@@ -296,7 +295,6 @@ class ExportController
|
||||
implode(', ', $langList),
|
||||
$t['access_type'] ?? '',
|
||||
$t['license_name'] ?? '',
|
||||
$t['file_size_info'] ?? '',
|
||||
isset($t['jury_points']) ? (string) $t['jury_points'] : '',
|
||||
$t['baiu_link'] ?? '',
|
||||
];
|
||||
|
||||
@@ -185,9 +185,6 @@ class ThesisCreateController
|
||||
'subtitle' => $data['subtitle'],
|
||||
'synopsis' => $data['synopsis'],
|
||||
'context_note' => $data['contextNote'],
|
||||
'file_size_info' => $data['durationInfo'],
|
||||
'duration_pages' => $data['durationPages'],
|
||||
'duration_minutes'=> $data['durationMinutes'],
|
||||
'baiu_link' => $data['lien'],
|
||||
'license_id' => $data['licenseId'],
|
||||
'license_custom' => $data['licenseCustom'],
|
||||
@@ -197,7 +194,7 @@ class ThesisCreateController
|
||||
'jury_points' => $data['juryPoints'],
|
||||
'exemplaire_baiu' => $data['exemplaireBaiu'],
|
||||
'exemplaire_erg' => $data['exemplaireErg'],
|
||||
'cc4r' => $data['cc4r'],
|
||||
'cc2r' => $data['cc2r'],
|
||||
]);
|
||||
|
||||
$identifier = $this->db->getThesisIdentifier($thesisId);
|
||||
@@ -347,20 +344,6 @@ class ThesisCreateController
|
||||
$subtitle = $this->sanitiseString($post['subtitle'] ?? '');
|
||||
$synopsis = $this->validateRequired($this->sanitiseString($post['synopsis'] ?? ''), 'Synopsis');
|
||||
|
||||
$durationPages = $this->sanitiseString($post['duration_pages'] ?? '');
|
||||
$durationMinutes = $this->sanitiseString($post['duration_minutes'] ?? '');
|
||||
$durationInfo = '';
|
||||
if ($durationPages !== '' && $durationMinutes !== '') {
|
||||
$durationInfo = $durationPages . ' pages + ' . $durationMinutes . ' minutes';
|
||||
} elseif ($durationMinutes !== '') {
|
||||
$durationInfo = $durationMinutes . ' minutes';
|
||||
} elseif ($durationPages !== '') {
|
||||
$durationInfo = $durationPages . ' pages';
|
||||
}
|
||||
if (!empty($post['has_annexes'])) {
|
||||
$durationInfo = $durationInfo ? $durationInfo . ' + annexe(s)' : 'Annexe(s)';
|
||||
}
|
||||
|
||||
// Jury members — new structure: separate interne/externe lecteurs
|
||||
$juryMembers = [];
|
||||
$hasPromoteur = false;
|
||||
@@ -519,7 +502,7 @@ class ThesisCreateController
|
||||
}
|
||||
$exemplaireBaiu = !empty($post['exemplaire_baiu']);
|
||||
$exemplaireErg = !empty($post['exemplaire_erg']);
|
||||
$cc4r = !empty($post['cc2r']);
|
||||
$cc2r = !empty($post['cc2r']);
|
||||
|
||||
return compact(
|
||||
'authorNames',
|
||||
@@ -533,9 +516,6 @@ class ThesisCreateController
|
||||
'titre',
|
||||
'subtitle',
|
||||
'synopsis',
|
||||
'durationInfo',
|
||||
'durationPages',
|
||||
'durationMinutes',
|
||||
'juryMembers',
|
||||
'keywords',
|
||||
'languageIds',
|
||||
@@ -550,7 +530,7 @@ class ThesisCreateController
|
||||
'juryPoints',
|
||||
'exemplaireBaiu',
|
||||
'exemplaireErg',
|
||||
'cc4r'
|
||||
'cc2r'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ class ThesisEditController
|
||||
*
|
||||
* Runs the full update inside a transaction:
|
||||
* 1. Thesis metadata (title, subtitle, year, orientation, ap, finality,
|
||||
* synopsis, context_note, file_size_info, baiu_link, license_id,
|
||||
* synopsis, context_note, baiu_link, license_id,
|
||||
* access_type_id, is_published)
|
||||
* 2. Authors (setThesisAuthors)
|
||||
* 3. Jury (setThesisJury)
|
||||
@@ -201,9 +201,6 @@ class ThesisEditController
|
||||
'finality_id' => intval($post['finality'] ?? 0),
|
||||
'synopsis' => trim($post['synopsis'] ?? ''),
|
||||
'context_note' => trim($post['context_note'] ?? ''),
|
||||
'file_size_info' => $this->buildFileSizeInfo($post),
|
||||
'duration_pages' => trim($post['duration_pages'] ?? ''),
|
||||
'duration_minutes'=> trim($post['duration_minutes'] ?? ''),
|
||||
'baiu_link' => trim($post['lien'] ?? ''),
|
||||
'license_id' => filter_var($post['license_id'] ?? '', FILTER_VALIDATE_INT) ?: null,
|
||||
'access_type_id' => filter_var($post['access_type_id'] ?? '', FILTER_VALIDATE_INT) ?: null,
|
||||
@@ -212,7 +209,7 @@ class ThesisEditController
|
||||
'jury_points' => $post['jury_points'] ?? null,
|
||||
'exemplaire_baiu' => !empty($post['exemplaire_baiu']),
|
||||
'exemplaire_erg' => !empty($post['exemplaire_erg']),
|
||||
'cc4r' => !empty($post['cc2r']),
|
||||
'cc2r' => !empty($post['cc2r']),
|
||||
'license_custom' => trim($post['license_custom'] ?? ''),
|
||||
]);
|
||||
|
||||
@@ -667,27 +664,6 @@ class ThesisEditController
|
||||
return $members;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build file_size_info from separate duration fields.
|
||||
*/
|
||||
protected function buildFileSizeInfo(array $post): string
|
||||
{
|
||||
$pages = trim($post['duration_pages'] ?? '');
|
||||
$minutes = trim($post['duration_minutes'] ?? '');
|
||||
$info = '';
|
||||
if ($pages !== '' && $minutes !== '') {
|
||||
$info = $pages . ' pages + ' . $minutes . ' minutes';
|
||||
} elseif ($minutes !== '') {
|
||||
$info = $minutes . ' minutes';
|
||||
} elseif ($pages !== '') {
|
||||
$info = $pages . ' pages';
|
||||
}
|
||||
if (!empty($post['has_annexes'])) {
|
||||
$info = $info ? $info . ' + annexe(s)' : 'Annexe(s)';
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload a video or audio file to PeerTube when the feature is enabled.
|
||||
*
|
||||
|
||||
@@ -1598,7 +1598,7 @@ class Database
|
||||
public function getThesisRawFields(int $thesisId): ?array
|
||||
{
|
||||
$stmt = $this->pdo->prepare(
|
||||
'SELECT license_id, license_custom, access_type_id, context_note, remarks, jury_points, exemplaire_baiu, exemplaire_erg, cc4r, duration_pages, duration_minutes FROM theses WHERE id = ? LIMIT 1'
|
||||
'SELECT license_id, license_custom, access_type_id, context_note, remarks, jury_points, exemplaire_baiu, exemplaire_erg, cc2r FROM theses WHERE id = ? LIMIT 1'
|
||||
);
|
||||
$stmt->execute([$thesisId]);
|
||||
$row = $stmt->fetch();
|
||||
@@ -1689,7 +1689,7 @@ class Database
|
||||
* Expected keys in $data:
|
||||
* year (int), orientation_id (int), ap_program_id (int), finality_id (int),
|
||||
* title (string), subtitle (?string), synopsis (string),
|
||||
* file_size_info (?string), baiu_link (?string), license_id (?int),
|
||||
* baiu_link (?string), license_id (?int),
|
||||
* author_id (int)
|
||||
*
|
||||
* The identifier is generated automatically from $data['year'].
|
||||
@@ -1713,9 +1713,6 @@ class Database
|
||||
finality_id = ?,
|
||||
synopsis = ?,
|
||||
context_note = ?,
|
||||
file_size_info = ?,
|
||||
duration_pages = ?,
|
||||
duration_minutes = ?,
|
||||
baiu_link = ?,
|
||||
license_id = ?,
|
||||
license_custom = ?,
|
||||
@@ -1725,7 +1722,7 @@ class Database
|
||||
jury_points = ?,
|
||||
exemplaire_baiu = ?,
|
||||
exemplaire_erg = ?,
|
||||
cc4r = ?,
|
||||
cc2r = ?,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = ?
|
||||
');
|
||||
@@ -1738,9 +1735,6 @@ class Database
|
||||
(int)$data['finality_id'],
|
||||
$data['synopsis'],
|
||||
!empty($data['context_note']) ? $data['context_note'] : null,
|
||||
!empty($data['file_size_info']) ? $data['file_size_info'] : null,
|
||||
isset($data['duration_pages']) && $data['duration_pages'] !== '' ? (int)$data['duration_pages'] : null,
|
||||
isset($data['duration_minutes']) && $data['duration_minutes'] !== '' ? (int)$data['duration_minutes'] : null,
|
||||
!empty($data['baiu_link']) ? $data['baiu_link'] : null,
|
||||
$data['license_id'] ?? null,
|
||||
!empty($data['license_custom']) ? $data['license_custom'] : null,
|
||||
@@ -1750,7 +1744,7 @@ class Database
|
||||
isset($data['jury_points']) && $data['jury_points'] !== '' ? (float)$data['jury_points'] : null,
|
||||
!empty($data['exemplaire_baiu']) ? 1 : 0,
|
||||
!empty($data['exemplaire_erg']) ? 1 : 0,
|
||||
!empty($data['cc4r']) ? 1 : 0,
|
||||
!empty($data['cc2r']) ? 1 : 0,
|
||||
$thesisId,
|
||||
]);
|
||||
}
|
||||
@@ -1785,17 +1779,16 @@ class Database
|
||||
INSERT INTO theses (
|
||||
identifier, title, subtitle, year,
|
||||
orientation_id, ap_program_id, finality_id,
|
||||
synopsis, context_note, file_size_info,
|
||||
duration_pages, duration_minutes,
|
||||
synopsis, context_note,
|
||||
baiu_link, license_id, license_custom,
|
||||
access_type_id,
|
||||
objet,
|
||||
is_published,
|
||||
remarks, jury_points,
|
||||
exemplaire_baiu, exemplaire_erg,
|
||||
cc4r,
|
||||
cc2r,
|
||||
submitted_at
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
|
||||
');
|
||||
|
||||
$validObjet = ['tfe', 'thèse', 'frart'];
|
||||
@@ -1811,9 +1804,6 @@ class Database
|
||||
(int)$data['finality_id'],
|
||||
$data['synopsis'],
|
||||
!empty($data['context_note']) ? $data['context_note'] : null,
|
||||
!empty($data['file_size_info']) ? $data['file_size_info'] : null,
|
||||
isset($data['duration_pages']) && $data['duration_pages'] !== '' ? (int)$data['duration_pages'] : null,
|
||||
isset($data['duration_minutes']) && $data['duration_minutes'] !== '' ? (int)$data['duration_minutes'] : null,
|
||||
!empty($data['baiu_link']) ? $data['baiu_link'] : null,
|
||||
$data['license_id'] ?? null,
|
||||
!empty($data['license_custom']) ? $data['license_custom'] : null,
|
||||
@@ -1823,7 +1813,7 @@ class Database
|
||||
isset($data['jury_points']) && $data['jury_points'] !== '' ? (float)$data['jury_points'] : null,
|
||||
!empty($data['exemplaire_baiu']) ? 1 : 0,
|
||||
!empty($data['exemplaire_erg']) ? 1 : 0,
|
||||
!empty($data['cc4r']) ? 1 : 0,
|
||||
!empty($data['cc2r']) ? 1 : 0,
|
||||
]);
|
||||
|
||||
return (int)$this->pdo->lastInsertId();
|
||||
@@ -2057,7 +2047,6 @@ class Database
|
||||
t.synopsis,
|
||||
t.context_note,
|
||||
t.remarks,
|
||||
t.file_size_info,
|
||||
t.jury_points,
|
||||
t.baiu_link
|
||||
FROM theses t
|
||||
|
||||
@@ -36,7 +36,6 @@ class StudentEmail
|
||||
'Président·e du jury' => $thesis['jury_president'] ?? '',
|
||||
'Lecteurs·rices (interne)' => $thesis['jury_lecteurs_internes'] ?? '',
|
||||
'Lecteurs·rices (externe)' => $thesis['jury_lecteurs_externes'] ?? '',
|
||||
'Durée / Taille' => $thesis['file_size_info'] ?? '',
|
||||
'Lien' => $thesis['baiu_link'] ?? '',
|
||||
'Type d\'accès' => $thesis['access_type'] ?? '',
|
||||
'Licence' => $thesis['license_type'] ?? '',
|
||||
|
||||
@@ -175,11 +175,6 @@ CREATE TABLE IF NOT EXISTS theses (
|
||||
context_note TEXT, -- Note added by jury president (max 150 words)
|
||||
remarks TEXT, -- Internal remarks
|
||||
|
||||
-- Duration/size
|
||||
duration_minutes INTEGER, -- For audio/video works
|
||||
duration_pages INTEGER, -- For written works
|
||||
file_size_info TEXT, -- e.g., "128 pages", "78 pages + ?? minutes"
|
||||
|
||||
-- Access and licensing
|
||||
access_type_id INTEGER,
|
||||
license_id INTEGER,
|
||||
@@ -205,8 +200,8 @@ CREATE TABLE IF NOT EXISTS theses (
|
||||
exemplaire_baiu BOOLEAN DEFAULT 0, -- Physical copy at BAIU
|
||||
exemplaire_erg BOOLEAN DEFAULT 0, -- Physical copy at ERG
|
||||
|
||||
-- CC4r acceptance (collected in student form)
|
||||
cc4r BOOLEAN DEFAULT 0,
|
||||
-- CC2r acceptance (collected in student form)
|
||||
cc2r BOOLEAN DEFAULT 0,
|
||||
|
||||
-- Timestamps
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
@@ -505,9 +500,6 @@ SELECT
|
||||
ft.name as finality_type,
|
||||
t.synopsis,
|
||||
t.context_note,
|
||||
t.duration_minutes,
|
||||
t.duration_pages,
|
||||
t.file_size_info,
|
||||
at.name as access_type,
|
||||
lt.name as license_type,
|
||||
t.license_id,
|
||||
@@ -522,7 +514,7 @@ SELECT
|
||||
t.banner_path,
|
||||
t.exemplaire_baiu,
|
||||
t.exemplaire_erg,
|
||||
t.cc4r,
|
||||
t.cc2r,
|
||||
t.remarks,
|
||||
t.jury_note_added,
|
||||
GROUP_CONCAT(DISTINCT a.name ORDER BY a.name ASC) as authors,
|
||||
|
||||
@@ -79,9 +79,8 @@
|
||||
['fieldset_files', 'Format(s) + Fichiers',
|
||||
['Formats (PDF, vidéo, audio, site web…)', 'Couverture', 'Note d\'intention', 'Fichier principal', 'Annexes']],
|
||||
|
||||
// Métadonnées complémentaires
|
||||
['fieldset_metadata', 'Métadonnées complémentaires',
|
||||
['Nombre de pages', 'Durée (minutes)']],
|
||||
// Métadonnées complémentaires (supprimé)
|
||||
// Ces champs sont redondants avec les fichiers attachés
|
||||
|
||||
// Degrés d'ouverture et licences
|
||||
['fieldset_access', 'Degrés d\'ouverture et licences',
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
'orientation' => $thesis['orientation'],
|
||||
'ap' => $thesis['ap_program'],
|
||||
'finality' => $thesis['finality_type'],
|
||||
'duration_pages' => $currentRaw['duration_pages'] ?? '',
|
||||
'duration_minutes' => $currentRaw['duration_minutes'] ?? '',
|
||||
'lien' => $thesis['baiu_link'] ?? '',
|
||||
'contact_public' => $currentAuthorShowContact ?? false,
|
||||
]);
|
||||
@@ -81,7 +79,7 @@
|
||||
$formData['access_type_id'] = $currentAccessTypeId;
|
||||
$formData['license_id'] = $currentLicenseId;
|
||||
$formData['license_custom'] = $currentRaw['license_custom'] ?? '';
|
||||
$formData['cc2r'] = $currentRaw['cc4r'] ?? false;
|
||||
$formData['cc2r'] = $currentRaw['cc2r'] ?? false;
|
||||
|
||||
// Optional sections
|
||||
$showContact = false; // Admin: contact visibility controlled by filling 'mail' field in fieldset-tfe-info
|
||||
|
||||
@@ -81,9 +81,6 @@
|
||||
<?php if ($thesis['keywords']): ?>
|
||||
<dt>Mots-clés</dt><dd><?= htmlspecialchars($thesis['keywords']) ?></dd>
|
||||
<?php endif; ?>
|
||||
<?php if ($thesis['file_size_info']): ?>
|
||||
<dt>Durée / Taille</dt><dd><?= htmlspecialchars($thesis['file_size_info']) ?></dd>
|
||||
<?php endif; ?>
|
||||
<?php if ($thesis['baiu_link']): ?>
|
||||
<dt>Lien</dt><dd><a href="<?= htmlspecialchars($thesis['baiu_link']) ?>" target="_blank" rel="noopener"><?= htmlspecialchars($thesis['baiu_link']) ?></a></dd>
|
||||
<?php endif; ?>
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Shared partial — "Métadonnées complémentaires" fieldset.
|
||||
*
|
||||
* Fields: duration (pages + minutes).
|
||||
* Annexes checkbox + file input moved to Fichiers fieldset (fichiers-fragment.php).
|
||||
* Lien BAIU moved to Backoffice fieldset.
|
||||
*
|
||||
* Variables consumed:
|
||||
* callable|null $oldFn — callable($key, $default='') for old/current values.
|
||||
* callable|null $withAutofocusFn — callable($field, $attrs=[]) to inject autofocus.
|
||||
* array $formData — raw form data (used for repopulation).
|
||||
*/
|
||||
|
||||
$oldFn = $oldFn ?? (function_exists('old') ? 'old' : fn($k, $d = '') => $d);
|
||||
$withAutofocusFn = $withAutofocusFn ?? fn($field, $attrs = []) => $attrs;
|
||||
$formData = $formData ?? [];
|
||||
?>
|
||||
<fieldset>
|
||||
<legend>Métadonnées complémentaires</legend>
|
||||
|
||||
<?php
|
||||
$name = 'duration_pages'; $label = 'Nombre de pages :'; $value = $oldFn('duration_pages');
|
||||
$type = 'number'; $placeholder = ''; $hint = 'Ex : 84';
|
||||
include APP_ROOT . '/templates/partials/form/text-field.php';
|
||||
?>
|
||||
|
||||
<?php
|
||||
$name = 'duration_minutes'; $label = 'Durée (minutes) :'; $value = $oldFn('duration_minutes');
|
||||
$type = 'number'; $placeholder = ''; $hint = 'Ex : 32 (pour œuvres audio/vidéo)';
|
||||
include APP_ROOT . '/templates/partials/form/text-field.php';
|
||||
?>
|
||||
</fieldset>
|
||||
<?php
|
||||
@@ -399,15 +399,8 @@ $checkedFormatsForSiteWeb = $checkedFormatsForSiteWeb ?? [];
|
||||
</div><!-- #edit-existing-files-block -->
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- ═══════════════════ Métadonnées complémentaires ═══════════════════ -->
|
||||
<?php
|
||||
if ($mode === "partage" && isset($helpFn)) {
|
||||
$helpContent = $helpFn("fieldset_metadata");
|
||||
$helpKey = 'fieldset_metadata';
|
||||
include APP_ROOT . "/templates/partials/form/form-help-block.php";
|
||||
}
|
||||
include APP_ROOT .
|
||||
"/templates/partials/form/fieldset-metadata.php"; ?>
|
||||
<!-- ═══════════════════ Métadonnées complémentaires ═══════════════════
|
||||
(Durée/Nombre de pages supprimés — redondants avec les fichiers attachés) -->
|
||||
|
||||
<!-- ═══════════════════ Degrés d'ouverture et licences ═══════════════════ -->
|
||||
<?php
|
||||
|
||||
@@ -82,13 +82,6 @@
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($data["file_size_info"])): ?>
|
||||
<div>
|
||||
<dt>Durée :</dt>
|
||||
<dd><?= htmlspecialchars($data["file_size_info"]) ?></dd>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($data["keywords"])): ?>
|
||||
<div>
|
||||
<dt>Mots-clés :</dt>
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
* Covered fields:
|
||||
* - titre, subtitle, synopsis, année
|
||||
* - orientation, ap, finality
|
||||
* - duration_pages, duration_minutes, has_annexes → file_size_info + individual columns
|
||||
* - languages (checkboxes), language_autre (free-text)
|
||||
* - formats (checkboxes)
|
||||
* - jury (promoteur, lecteur interne, lecteur externe)
|
||||
@@ -17,7 +16,7 @@
|
||||
* - lien (baiu_link), license_id, access_type_id
|
||||
* - objet
|
||||
* - context_note
|
||||
* - remarks, jury_points, exemplaire_baiu, exemplaire_erg, cc4r (backoffice)
|
||||
* - remarks, jury_points, exemplaire_baiu, exemplaire_erg, cc2r (backoffice)
|
||||
* - is_published
|
||||
*/
|
||||
|
||||
@@ -65,8 +64,6 @@ function buildPost(Database $db, array $overrides = []): array
|
||||
'orientation' => (string)$orientations[0]['id'],
|
||||
'ap' => (string)$apPrograms[0]['id'],
|
||||
'finality' => (string)$finalityTypes[0]['id'],
|
||||
'duration_pages' => '120',
|
||||
'duration_minutes' => '',
|
||||
'has_annexes' => '',
|
||||
'languages' => [(string)$languages[0]['id']],
|
||||
'language_autre' => '',
|
||||
@@ -160,44 +157,9 @@ try {
|
||||
echo "\n";
|
||||
|
||||
// =========================================================================
|
||||
// TEST 2: Create — duration_pages saved as individual column
|
||||
// TEST 2: Create — language_autre creates and links new language
|
||||
// =========================================================================
|
||||
echo "Test 2: Create — duration_pages saved as individual column\n";
|
||||
$post = buildPost($db, [
|
||||
'titre' => 'Duration pages test',
|
||||
'duration_pages' => '84',
|
||||
]);
|
||||
|
||||
$thesisId = $createCtrl->submit($post, []);
|
||||
$createdIds[] = $thesisId;
|
||||
$raw = $db->getThesisRawFields($thesisId);
|
||||
|
||||
assertEq(84, (int)$raw['duration_pages'], 'duration_pages column saved');
|
||||
assertEq(null, $raw['duration_minutes'], 'duration_minutes null when not set');
|
||||
echo "\n";
|
||||
|
||||
// =========================================================================
|
||||
// TEST 3: Create — duration_minutes saved as individual column
|
||||
// =========================================================================
|
||||
echo "Test 3: Create — duration_minutes saved as individual column\n";
|
||||
$post = buildPost($db, [
|
||||
'titre' => 'Duration minutes test',
|
||||
'duration_pages' => '',
|
||||
'duration_minutes' => '42',
|
||||
]);
|
||||
|
||||
$thesisId = $createCtrl->submit($post, []);
|
||||
$createdIds[] = $thesisId;
|
||||
$raw = $db->getThesisRawFields($thesisId);
|
||||
|
||||
assertEq(null, $raw['duration_pages'], 'duration_pages null when not set');
|
||||
assertEq(42, (int)$raw['duration_minutes'], 'duration_minutes column saved');
|
||||
echo "\n";
|
||||
|
||||
// =========================================================================
|
||||
// TEST 4: Create — language_autre creates and links new language
|
||||
// =========================================================================
|
||||
echo "Test 4: Create — language_autre creates and links new language\n";
|
||||
echo "Test 2: Create — language_autre creates and links new language\n";
|
||||
$uniqueLang = 'TestLang_' . bin2hex(random_bytes(4));
|
||||
$post = buildPost($db, [
|
||||
'titre' => 'Language autre test',
|
||||
@@ -219,7 +181,7 @@ try {
|
||||
echo "\n";
|
||||
|
||||
// =========================================================================
|
||||
// TEST 5: Create — language_autre + checkbox together
|
||||
// TEST 3: Create — language_autre + checkbox together
|
||||
// =========================================================================
|
||||
echo "Test 5: Create — language_autre appended alongside checked languages\n";
|
||||
$db2 = Database::getInstance();
|
||||
@@ -245,45 +207,9 @@ try {
|
||||
echo "\n";
|
||||
|
||||
// =========================================================================
|
||||
// TEST 6: Edit — duration_pages / duration_minutes updated
|
||||
// TEST 4: Edit — language checkboxes round-trip
|
||||
// =========================================================================
|
||||
echo "Test 6: Edit — duration_pages / duration_minutes updated\n";
|
||||
$post = buildPost($db, ['titre' => 'Edit duration test']);
|
||||
$thesisId = $createCtrl->submit($post, []);
|
||||
$createdIds[] = $thesisId;
|
||||
|
||||
$editPost = buildPost($db, [
|
||||
'titre' => 'Edit duration test',
|
||||
'duration_pages' => '99',
|
||||
'duration_minutes' => '30',
|
||||
]);
|
||||
$editCtrl->save($thesisId, $editPost, []);
|
||||
$raw = $db->getThesisRawFields($thesisId);
|
||||
|
||||
assertEq(99, (int)$raw['duration_pages'], 'duration_pages updated on edit');
|
||||
assertEq(30, (int)$raw['duration_minutes'], 'duration_minutes updated on edit');
|
||||
echo "\n";
|
||||
|
||||
// =========================================================================
|
||||
// TEST 7: Edit — clearing duration_pages saves null
|
||||
// =========================================================================
|
||||
echo "Test 7: Edit — clearing duration_pages saves null\n";
|
||||
$editPost = buildPost($db, [
|
||||
'titre' => 'Edit duration test',
|
||||
'duration_pages' => '',
|
||||
'duration_minutes' => '',
|
||||
]);
|
||||
$editCtrl->save($thesisId, $editPost, []);
|
||||
$raw = $db->getThesisRawFields($thesisId);
|
||||
|
||||
assertEq(null, $raw['duration_pages'], 'duration_pages cleared to null');
|
||||
assertEq(null, $raw['duration_minutes'], 'duration_minutes cleared to null');
|
||||
echo "\n";
|
||||
|
||||
// =========================================================================
|
||||
// TEST 8: Edit — languages pre-populated (checkboxes round-trip)
|
||||
// =========================================================================
|
||||
echo "Test 8: Edit — language checkboxes round-trip\n";
|
||||
echo "Test 3: Edit — language checkboxes round-trip\n";
|
||||
$allLangs = $db->getAllLanguages();
|
||||
$lang1 = (string)$allLangs[0]['id'];
|
||||
$lang2 = (string)$allLangs[1]['id'];
|
||||
@@ -307,9 +233,9 @@ try {
|
||||
echo "\n";
|
||||
|
||||
// =========================================================================
|
||||
// TEST 9: Edit — language_autre adds new language
|
||||
// TEST 5: Edit — language_autre adds new language
|
||||
// =========================================================================
|
||||
echo "Test 9: Edit — language_autre creates and links on edit\n";
|
||||
echo "Test 4: Edit — language_autre creates and links on edit\n";
|
||||
$uniqueLang3 = 'EditLang_' . bin2hex(random_bytes(4));
|
||||
$editPost = buildPost($db, [
|
||||
'titre' => 'Lang checkbox test',
|
||||
@@ -327,9 +253,9 @@ try {
|
||||
echo "\n";
|
||||
|
||||
// =========================================================================
|
||||
// TEST 10: Create — backoffice fields persisted
|
||||
// TEST 6: Create — backoffice fields persisted
|
||||
// =========================================================================
|
||||
echo "Test 10: Create — backoffice fields (remarks, jury_points, exemplaires, cc4r)\n";
|
||||
echo "Test 5: Create — backoffice fields (remarks, jury_points, exemplaires, cc2r)\n";
|
||||
$post = buildPost($db, [
|
||||
'titre' => 'Backoffice fields test',
|
||||
'remarks' => 'Internal note here',
|
||||
@@ -347,13 +273,13 @@ try {
|
||||
assertEq(15.5, (float)$raw['jury_points'], 'jury_points saved');
|
||||
assertEq(1, (int)$raw['exemplaire_baiu'], 'exemplaire_baiu saved');
|
||||
assertEq(1, (int)$raw['exemplaire_erg'], 'exemplaire_erg saved');
|
||||
assertEq(1, (int)$raw['cc4r'], 'cc4r saved');
|
||||
assertEq(1, (int)$raw['cc2r'], 'cc2r saved');
|
||||
echo "\n";
|
||||
|
||||
// =========================================================================
|
||||
// TEST 11: Edit — backoffice fields updated
|
||||
// TEST 7: Edit — backoffice fields updated
|
||||
// =========================================================================
|
||||
echo "Test 11: Edit — backoffice fields updated\n";
|
||||
echo "Test 6: Edit — backoffice fields updated\n";
|
||||
$editPost = buildPost($db, [
|
||||
'titre' => 'Backoffice fields test',
|
||||
'remarks' => 'Updated note',
|
||||
@@ -369,13 +295,13 @@ try {
|
||||
assertEq(18.0, (float)$raw['jury_points'], 'jury_points updated');
|
||||
assertEq(0, (int)$raw['exemplaire_baiu'], 'exemplaire_baiu cleared');
|
||||
assertEq(1, (int)$raw['exemplaire_erg'], 'exemplaire_erg retained');
|
||||
assertEq(0, (int)$raw['cc4r'], 'cc4r cleared');
|
||||
assertEq(0, (int)$raw['cc2r'], 'cc2r cleared');
|
||||
echo "\n";
|
||||
|
||||
// =========================================================================
|
||||
// TEST 12: getOrCreateLanguage — idempotent
|
||||
// TEST 8: getOrCreateLanguage — idempotent
|
||||
// =========================================================================
|
||||
echo "Test 12: getOrCreateLanguage — idempotent (same name returns same ID)\n";
|
||||
echo "Test 7: getOrCreateLanguage — idempotent (same name returns same ID)\n";
|
||||
$uniqueName = 'Idempotent_' . bin2hex(random_bytes(4));
|
||||
$id1 = $db->getOrCreateLanguage($uniqueName);
|
||||
$id2 = $db->getOrCreateLanguage($uniqueName);
|
||||
@@ -386,28 +312,9 @@ try {
|
||||
echo "\n";
|
||||
|
||||
// =========================================================================
|
||||
// TEST 13: Create — has_annexes flag in file_size_info
|
||||
// TEST 9: Edit — context_note saved
|
||||
// =========================================================================
|
||||
echo "Test 13: Create — has_annexes appended to file_size_info\n";
|
||||
$post = buildPost($db, [
|
||||
'titre' => 'Annexes test',
|
||||
'duration_pages' => '50',
|
||||
'has_annexes' => '1',
|
||||
]);
|
||||
$thesisId = $createCtrl->submit($post, []);
|
||||
$createdIds[] = $thesisId;
|
||||
$row = $db->getThesis($thesisId);
|
||||
|
||||
assertNotEmpty($row['file_size_info'], 'file_size_info not empty');
|
||||
if (strpos((string)$row['file_size_info'], 'annexe') === false) {
|
||||
throw new RuntimeException("FAIL has_annexes: 'annexe' not in file_size_info: " . $row['file_size_info']);
|
||||
}
|
||||
echo " ✓ 'annexe' present in file_size_info\n\n";
|
||||
|
||||
// =========================================================================
|
||||
// TEST 14: Edit — context_note saved
|
||||
// =========================================================================
|
||||
echo "Test 14: Edit — context_note saved\n";
|
||||
echo "Test 8: Edit — context_note saved\n";
|
||||
$post = buildPost($db, ['titre' => 'Context note test']);
|
||||
$thesisId = $createCtrl->submit($post, []);
|
||||
$createdIds[] = $thesisId;
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
* - autofocusFieldForError()
|
||||
* - detectFileType() — via subclass to access private
|
||||
* - generateAuthorSlug() — accent stripping, uppercase, underscore
|
||||
* - buildFileSizeInfo() — pages, minutes, annexes combinations
|
||||
*
|
||||
* ExportController:
|
||||
* - CSV_HEADERS count matches exportAllTheses() row width
|
||||
@@ -37,7 +36,6 @@ require_once APP_ROOT . '/src/Database.php';
|
||||
require_once APP_ROOT . '/src/RateLimit.php';
|
||||
require_once APP_ROOT . '/src/Controllers/TfeController.php';
|
||||
require_once APP_ROOT . '/src/Controllers/ThesisCreateController.php';
|
||||
require_once APP_ROOT . '/src/Controllers/ThesisEditController.php';
|
||||
require_once APP_ROOT . '/src/Controllers/SearchController.php';
|
||||
require_once APP_ROOT . '/src/Controllers/ExportController.php';
|
||||
|
||||
@@ -101,14 +99,6 @@ class ThesisCreateControllerTestable extends ThesisCreateController
|
||||
}
|
||||
}
|
||||
|
||||
class ThesisEditControllerTestable extends ThesisEditController
|
||||
{
|
||||
public function testBuildFileSizeInfo(array $post): string
|
||||
{
|
||||
return $this->buildFileSizeInfo($post);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Setup ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
echo "Pure Logic Unit Test\n";
|
||||
@@ -117,7 +107,6 @@ echo "====================\n\n";
|
||||
$db = Database::getInstance();
|
||||
$tfe = new TfeControllerTestable($db);
|
||||
$createCtrl = new ThesisCreateControllerTestable($db);
|
||||
$editCtrl = new ThesisEditControllerTestable($db);
|
||||
|
||||
try {
|
||||
|
||||
@@ -338,44 +327,10 @@ try {
|
||||
echo "\n";
|
||||
|
||||
// =========================================================================
|
||||
// SECTION C: ThesisEditController — buildFileSizeInfo
|
||||
// SECTION C: ExportController — CSV column count consistency
|
||||
// =========================================================================
|
||||
|
||||
echo "C1: buildFileSizeInfo — pages only\n";
|
||||
$info = $editCtrl->testBuildFileSizeInfo(['duration_pages' => '84', 'duration_minutes' => '']);
|
||||
plAssertEq('84 pages', $info, 'pages only');
|
||||
echo "\n";
|
||||
|
||||
echo "C2: buildFileSizeInfo — minutes only\n";
|
||||
$info = $editCtrl->testBuildFileSizeInfo(['duration_pages' => '', 'duration_minutes' => '32']);
|
||||
plAssertEq('32 minutes', $info, 'minutes only');
|
||||
echo "\n";
|
||||
|
||||
echo "C3: buildFileSizeInfo — pages + minutes\n";
|
||||
$info = $editCtrl->testBuildFileSizeInfo(['duration_pages' => '84', 'duration_minutes' => '32']);
|
||||
plAssertEq('84 pages + 32 minutes', $info, 'pages + minutes');
|
||||
echo "\n";
|
||||
|
||||
echo "C4: buildFileSizeInfo — annexes appended\n";
|
||||
$info = $editCtrl->testBuildFileSizeInfo(['duration_pages' => '50', 'duration_minutes' => '', 'has_annexes' => '1']);
|
||||
plAssertEq('50 pages + annexe(s)', $info, 'annexes appended');
|
||||
echo "\n";
|
||||
|
||||
echo "C5: buildFileSizeInfo — annexes only (no pages/minutes)\n";
|
||||
$info = $editCtrl->testBuildFileSizeInfo(['duration_pages' => '', 'duration_minutes' => '', 'has_annexes' => '1']);
|
||||
plAssertEq('Annexe(s)', $info, 'annexes only');
|
||||
echo "\n";
|
||||
|
||||
echo "C6: buildFileSizeInfo — empty fields = empty string\n";
|
||||
$info = $editCtrl->testBuildFileSizeInfo(['duration_pages' => '', 'duration_minutes' => '']);
|
||||
plAssertEq('', $info, 'empty when nothing set');
|
||||
echo "\n";
|
||||
|
||||
// =========================================================================
|
||||
// SECTION D: ExportController — CSV column count consistency
|
||||
// =========================================================================
|
||||
|
||||
echo "D1: ExportController — CSV_HEADERS count matches row column count\n";
|
||||
echo "C1: ExportController — CSV_HEADERS count matches row column count\n";
|
||||
$export = new ExportController($db);
|
||||
$rows = $export->exportAllTheses();
|
||||
$headerCount = count(ExportController::CSV_HEADERS);
|
||||
@@ -397,10 +352,10 @@ try {
|
||||
echo "\n";
|
||||
|
||||
// =========================================================================
|
||||
// SECTION E: SearchController — coverMap key always present (regression)
|
||||
// SECTION D: SearchController — coverMap key always present (regression)
|
||||
// =========================================================================
|
||||
|
||||
echo "E1: SearchController::handleSearch() — coverMap key always in return array\n";
|
||||
echo "D1: SearchController::handleSearch() — coverMap key always in return array\n";
|
||||
// Simulate $_GET for the method (it reads from $_GET directly via collectSearchParams)
|
||||
$_GET = ['query' => ''];
|
||||
$rateLimit = new RateLimit(1000, 60);
|
||||
|
||||
@@ -213,7 +213,7 @@ try {
|
||||
|
||||
$anyLink = $model->create($adminId, null, null, 'invalid_value');
|
||||
$createdIds[] = $anyLink['id'];
|
||||
slAssertEq(null, $anyLink['objet_restriction'], 'invalid objet_restriction stored as null');
|
||||
slAssertEq('tfe', $anyLink['objet_restriction'], 'invalid objet_restriction defaults to tfe');
|
||||
echo "\n";
|
||||
|
||||
echo "✅ All ShareLink tests passed!\n";
|
||||
|
||||
Reference in New Issue
Block a user