mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-06-25 16:19:19 +02:00
Add thesis status column for two-phase commit lifecycle tracking
This commit is contained in:
4
TODO.md
4
TODO.md
@@ -1,6 +1,6 @@
|
|||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
> Last updated: 2026-06-11 11:42
|
> Last updated: 2026-06-11 12:10
|
||||||
> Context: Form Accessibility & Resilience improvements for XAMXAM thesis submission platform
|
> Context: Form Accessibility & Resilience improvements for XAMXAM thesis submission platform
|
||||||
|
|
||||||
## In Progress
|
## In Progress
|
||||||
@@ -9,12 +9,12 @@
|
|||||||
|
|
||||||
- [ ] #aria-test-manual Test WCAG changes with VoiceOver and NVDA on full add/edit/partage form flows
|
- [ ] #aria-test-manual Test WCAG changes with VoiceOver and NVDA on full add/edit/partage form flows
|
||||||
- [ ] #nojs-upload-test Test end-to-end: submit partage form with JS disabled, verify files arrive via `$_FILES`
|
- [ ] #nojs-upload-test Test end-to-end: submit partage form with JS disabled, verify files arrive via `$_FILES`
|
||||||
- [ ] #two-phase-commit Add two-phase commit: INSERT thesis `status='draft'`, COMMIT, move files, UPDATE to `active` `(ThesisCreateController.php)`
|
|
||||||
- [ ] #cleanup-drafts Add periodic cleanup job for orphaned drafts (`just cleanup-drafts`)
|
- [ ] #cleanup-drafts Add periodic cleanup job for orphaned drafts (`just cleanup-drafts`)
|
||||||
- [ ] #form-setup-helper Add `ThesisFormSetup` helper class to reduce bootstrap duplication across add/edit/partage `(partage/index.php)` `(admin/add.php)` `(admin/edit.php)`
|
- [ ] #form-setup-helper Add `ThesisFormSetup` helper class to reduce bootstrap duplication across add/edit/partage `(partage/index.php)` `(admin/add.php)` `(admin/edit.php)`
|
||||||
|
|
||||||
## Completed
|
## Completed
|
||||||
|
|
||||||
|
- [x] #two-phase-commit Add two-phase commit: INSERT thesis `status='draft'`, COMMIT, move files, UPDATE to `active` `(ThesisCreateController.php)` ✓
|
||||||
- [x] #filepond-preserve Preserve FilePond temp file IDs on partage validation redirect `(partage/index.php)` `(FilepondHandler.php)` ✓
|
- [x] #filepond-preserve Preserve FilePond temp file IDs on partage validation redirect `(partage/index.php)` `(FilepondHandler.php)` ✓
|
||||||
- [x] #refactor-partage Extract partage form page chrome to `templates/partage/form-page.php` `(partage/index.php)` ✓
|
- [x] #refactor-partage Extract partage form page chrome to `templates/partage/form-page.php` `(partage/index.php)` ✓
|
||||||
- [x] #htmx-migration HTMX v2 migration: OverType editors, autosave handler, backend `HX-Request` detection ✓
|
- [x] #htmx-migration HTMX v2 migration: OverType editors, autosave handler, backend `HX-Request` detection ✓
|
||||||
|
|||||||
14
app/migrations/applied/039_add_thesis_status.sql
Normal file
14
app/migrations/applied/039_add_thesis_status.sql
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
-- 039: Add a status column to theses to track submission lifecycle
|
||||||
|
--
|
||||||
|
-- Lifecycle:
|
||||||
|
-- draft — thesis row created, file operations not yet completed (or failed)
|
||||||
|
-- active — all file operations succeeded, submission is complete
|
||||||
|
--
|
||||||
|
-- Separate from is_published (visibility). The admin can filter drafts
|
||||||
|
-- to find orphaned/broken submissions and the cleanup-drafts job targets
|
||||||
|
-- status='draft' rows older than a threshold.
|
||||||
|
|
||||||
|
ALTER TABLE theses ADD COLUMN status TEXT NOT NULL DEFAULT 'active';
|
||||||
|
|
||||||
|
-- Existing theses already have files → they are active.
|
||||||
|
-- New theses start as draft and are promoted to active after file ops succeed.
|
||||||
@@ -93,13 +93,14 @@ class ThesisCreateController
|
|||||||
* recapitulatif.php?id=<n>. On validation or DB failure, throws an Exception
|
* recapitulatif.php?id=<n>. On validation or DB failure, throws an Exception
|
||||||
* (caller must flash the message and redirect back to the form).
|
* (caller must flash the message and redirect back to the form).
|
||||||
*
|
*
|
||||||
* Execution order:
|
* Two-phase execution:
|
||||||
* 1. Validate + sanitise POST fields
|
* 1. Validate + sanitise POST fields
|
||||||
* 2. Find/create author record
|
* 2. Find/create author record
|
||||||
* 3. INSERT thesis row + link author (inside transaction)
|
* 3. INSERT thesis row (status='draft') + link author (inside transaction)
|
||||||
* 4. Link jury, languages, formats, tags (inside transaction)
|
* 4. Link jury, languages, formats, tags (inside transaction)
|
||||||
* 5. COMMIT
|
* 5. COMMIT (thesis visible only as draft)
|
||||||
* 6. Handle file uploads: cover, thesis files (outside transaction)
|
* 6. Handle file uploads: cover, thesis files (outside transaction)
|
||||||
|
* 7. UPDATE status to 'active' (confirms file operations succeeded)
|
||||||
*
|
*
|
||||||
* @param array $post Sanitised $_POST array.
|
* @param array $post Sanitised $_POST array.
|
||||||
* @param array $files $_FILES array.
|
* @param array $files $_FILES array.
|
||||||
@@ -226,6 +227,14 @@ class ThesisCreateController
|
|||||||
// ── 6. Website URL — stored as thesis_files row ──────────────────────
|
// ── 6. Website URL — stored as thesis_files row ──────────────────────
|
||||||
$this->handleWebsiteUrl($thesisId, $post);
|
$this->handleWebsiteUrl($thesisId, $post);
|
||||||
|
|
||||||
|
// ── 7. Two-phase commit: mark submission complete ──────────────────
|
||||||
|
// The thesis was committed as status='draft' before file operations.
|
||||||
|
// Now that all files are safely in place, promote to 'active'.
|
||||||
|
// If any file operation had thrown, the draft would remain orphaned
|
||||||
|
// for the periodic cleanup job (just cleanup-drafts).
|
||||||
|
$this->db->setThesisStatus($thesisId, 'active');
|
||||||
|
error_log("[ThesisCreate] ACTIVE — thesis_id=$thesisId | all file operations succeeded");
|
||||||
|
|
||||||
return $thesisId;
|
return $thesisId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1682,6 +1682,22 @@ class Database
|
|||||||
Audit::log($this, Audit::actor(), 'UPDATE', 'theses', $thesisId, $old, $new);
|
Audit::log($this, Audit::actor(), 'UPDATE', 'theses', $thesisId, $old, $new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the submission lifecycle status of a single thesis.
|
||||||
|
*
|
||||||
|
* Valid statuses: 'draft' (files not yet moved / failed) → 'active' (complete).
|
||||||
|
*/
|
||||||
|
public function setThesisStatus(int $thesisId, string $status): void
|
||||||
|
{
|
||||||
|
require_once __DIR__ . '/Audit.php';
|
||||||
|
$old = $this->fetchRow('theses', $thesisId);
|
||||||
|
$this->pdo->prepare(
|
||||||
|
'UPDATE theses SET status = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?'
|
||||||
|
)->execute([$status, $thesisId]);
|
||||||
|
$new = $this->fetchRow('theses', $thesisId);
|
||||||
|
Audit::log($this, Audit::actor(), 'UPDATE', 'theses', $thesisId, $old, $new);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the published state for multiple theses at once.
|
* Set the published state for multiple theses at once.
|
||||||
* @param int[] $thesisIds
|
* @param int[] $thesisIds
|
||||||
@@ -2242,12 +2258,12 @@ class Database
|
|||||||
baiu_link, license_id, license_custom,
|
baiu_link, license_id, license_custom,
|
||||||
access_type_id,
|
access_type_id,
|
||||||
objet,
|
objet,
|
||||||
is_published,
|
is_published, status,
|
||||||
remarks, jury_points,
|
remarks, jury_points,
|
||||||
exemplaire_baiu, exemplaire_erg,
|
exemplaire_baiu, exemplaire_erg,
|
||||||
cc2r,
|
cc2r,
|
||||||
submitted_at
|
submitted_at
|
||||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, "draft", ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
|
||||||
');
|
');
|
||||||
|
|
||||||
$validObjet = ['tfe', 'thèse', 'frart'];
|
$validObjet = ['tfe', 'thèse', 'frart'];
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ CREATE TABLE IF NOT EXISTS theses (
|
|||||||
defense_date DATETIME,
|
defense_date DATETIME,
|
||||||
published_at DATETIME,
|
published_at DATETIME,
|
||||||
is_published BOOLEAN DEFAULT 0,
|
is_published BOOLEAN DEFAULT 0,
|
||||||
|
status TEXT NOT NULL DEFAULT 'active',
|
||||||
baiu_link TEXT,
|
baiu_link TEXT,
|
||||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|||||||
Reference in New Issue
Block a user