Fix #4 v2: decouple contact_interne from contact_visible in ThesisCreateController

validateAndSanitise() no longer cross-contaminates:
- contact_interne overwrote mail, which then copied to contact_visible
- Fixed: contactInterne from contact_interne (admin) or confirmation_email (student)
- Fixed: contactVisible from contact_visible (admin) or mail (student)
- Fixed: submit() uses contactInterne as author email, not mail
This commit is contained in:
Pontoporeia
2026-06-09 19:35:33 +02:00
parent 1490c99268
commit 317547ac93
4 changed files with 51 additions and 12 deletions

File diff suppressed because one or more lines are too long

View File

@@ -4,6 +4,7 @@
- [x] Fix #2: Renommer "Note contextuelle" → "Note contextuelle relative à soutenance"
- [x] Fix #3: Impossible de mettre une majuscule au nom d'étudiant·e — la recherche par nom en SQLite est case-sensitive (BINARY), contournait le UPDATE et tombait dans le fallback email sans updater le nom. Ajout COLLATE NOCASE + UPDATE dans le chemin email.
- [x] Fix #4: Décorréler contact interne et contact visible (ajouter colonne contact_visible sur theses)
- [x] Fix #4 (v2): Découplage complet dans ThesisCreateController — validateAndSanitise ne croise plus contact_interne ↔ mail/contact_visible, submit utilise contactInterne (et non mail) comme email de l'auteurice
- [x] Fix #5: "Contact public : non" partout, non modifiable, sans impact
- [x] Fix #6: Investiguer "libre → interne" impossible — aucune restriction trouvée dans le code admin
- [x] Hotfix: contact_visible manquant dans le SQL de updateThesis (l'edit matchait createThesis à la place)

View File

@@ -125,11 +125,13 @@ class ThesisCreateController
}
// ── 2. Build author entries (alphabetically sorted) ───────────────────
// The first author's email is contact_interne (private, for confirmation emails).
// contact_visible is stored on the thesis row, decoupled from the author email.
$authorEntries = [];
foreach ($data['authorNames'] as $i => $name) {
$authorEntries[] = [
'name' => $name,
'email' => $i === 0 ? ($data['mail'] ?: null) : null,
'email' => $i === 0 ? ($data['contactInterne'] ?: null) : null,
'show_contact' => $i === 0 ? $data['showContact'] : false,
];
}
@@ -305,19 +307,22 @@ class ThesisCreateController
throw new Exception("Le champ 'Auteur·ice(s)' est requis.");
}
// contact_interne (backoffice) takes precedence over mail (tfe-info fieldset)
// contact_interne: private email (backoffice field in admin mode,
// confirmation_email field in student mode). Stored as the first
// author's email — NOT as contact_visible.
$contactInterne = trim($post['contact_interne'] ?? '');
$mail = !empty($post['mail']) ? $this->sanitiseString($post['mail']) : '';
if ($contactInterne !== '') {
$mail = $contactInterne;
if ($contactInterne === '' && !$adminMode) {
$contactInterne = trim($post['confirmation_email'] ?? '');
}
// contact_visible: what appears publicly on the TFE page
// In admin mode: from contact_visible field. In student mode: from mail field.
// contact_visible: public-facing contact shown on the TFE page.
// Admin mode: from the dedicated contact_visible field.
// Student mode: from the mail field (labeled "Contact visible" in fieldset-tfe-info).
// These two concepts (contact_interne and contact_visible) are fully decoupled.
$contactVisible = trim($post['contact_visible'] ?? '');
if ($contactVisible === '' && $mail !== '') {
$contactVisible = $mail;
if ($contactVisible === '') {
$contactVisible = trim($post['mail'] ?? '');
}
// showContact for backwards compat
// showContact: whether to show the contact publicly
if (array_key_exists('contact_public', $post)) {
$showContact = !empty($post['contact_public']);
} else {
@@ -533,7 +538,7 @@ class ThesisCreateController
return compact(
'authorNames',
'mail',
'contactInterne',
'contactVisible',
'showContact',
'annee',

View File

@@ -18,3 +18,36 @@
#2 /home/padlock/repos/xamxam/app/public/admin/actions/edit.php(36): ThesisEditController->save()
#3 /home/padlock/repos/xamxam/app/router.php(46): include('...')
#4 {main}","extra":{"thesis_id":143}}
{"timestamp":"2026-06-09T17:35:12+00:00","ip":"unknown","user_agent":"","context":"test_context","exception":"Exception","message":"test message","trace":"#0 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestCase.php(1667): ErrorHandlerTest->testLogWithContext()
#1 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestCase.php(519): PHPUnit\\Framework\\TestCase->runTest()
#2 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestRunner/TestRunner.php(87): PHPUnit\\Framework\\TestCase->runBare()
#3 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestCase.php(365): PHPUnit\\Framework\\TestRunner->run()
#4 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestSuite.php(369): PHPUnit\\Framework\\TestCase->run()
#5 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestSuite.php(369): PHPUnit\\Framework\\TestSuite->run()
#6 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/TextUI/TestRunner.php(64): PHPUnit\\Framework\\TestSuite->run()
#7 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/TextUI/Application.php(211): PHPUnit\\TextUI\\TestRunner->run()
#8 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/phpunit(104): PHPUnit\\TextUI\\Application->run()
#9 /home/padlock/repos/xamxam/vendor/bin/phpunit(122): include('...')
#10 {main}","extra":{"thesis_id":42,"slug":"20250101-TEST1234"}}
{"timestamp":"2026-06-09T17:35:12+00:00","ip":"unknown","user_agent":"","context":"test_null","exception":"PDOException","message":"test","trace":"#0 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestCase.php(1667): ErrorHandlerTest->testLogWithNullValues()
#1 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestCase.php(519): PHPUnit\\Framework\\TestCase->runTest()
#2 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestRunner/TestRunner.php(87): PHPUnit\\Framework\\TestCase->runBare()
#3 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestCase.php(365): PHPUnit\\Framework\\TestRunner->run()
#4 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestSuite.php(369): PHPUnit\\Framework\\TestCase->run()
#5 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestSuite.php(369): PHPUnit\\Framework\\TestSuite->run()
#6 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/TextUI/TestRunner.php(64): PHPUnit\\Framework\\TestSuite->run()
#7 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/TextUI/Application.php(211): PHPUnit\\TextUI\\TestRunner->run()
#8 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/phpunit(104): PHPUnit\\TextUI\\Application->run()
#9 /home/padlock/repos/xamxam/vendor/bin/phpunit(122): include('...')
#10 {main}","extra":{"id":null,"name":"foo"}}
{"timestamp":"2026-06-09T17:35:12+00:00","ip":"unknown","user_agent":"","context":"test_empty","exception":"RuntimeException","message":"bare","trace":"#0 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestCase.php(1667): ErrorHandlerTest->testLogWithEmptyExtra()
#1 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestCase.php(519): PHPUnit\\Framework\\TestCase->runTest()
#2 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestRunner/TestRunner.php(87): PHPUnit\\Framework\\TestCase->runBare()
#3 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestCase.php(365): PHPUnit\\Framework\\TestRunner->run()
#4 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestSuite.php(369): PHPUnit\\Framework\\TestCase->run()
#5 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestSuite.php(369): PHPUnit\\Framework\\TestSuite->run()
#6 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/TextUI/TestRunner.php(64): PHPUnit\\Framework\\TestSuite->run()
#7 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/TextUI/Application.php(211): PHPUnit\\TextUI\\TestRunner->run()
#8 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/phpunit(104): PHPUnit\\TextUI\\Application->run()
#9 /home/padlock/repos/xamxam/vendor/bin/phpunit(122): include('...')
#10 {main}"}