mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-06-25 16:19:19 +02:00
Add periodic cleanup of orphaned drafts: cleanup job, just command, deploy cron
This commit is contained in:
@@ -2307,6 +2307,59 @@ class Database
|
||||
return $newId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and optionally delete orphaned draft theses older than a threshold.
|
||||
*
|
||||
* Draft theses are created with status='draft' before file operations
|
||||
* (two-phase commit). If the file phase throws after COMMIT, the draft
|
||||
* remains orphaned indefinitely — no files are attached but the row blocks
|
||||
* the identifier number.
|
||||
*
|
||||
* @param int $olderThanHours Drafts older than this many hours are candidates.
|
||||
* @param bool $dryRun When true, only list candidates without deleting.
|
||||
* @return array{deleted: int, candidates: array} Deleted count + list of IDs found.
|
||||
*/
|
||||
public function cleanupOrphanedDrafts(int $olderThanHours = 24, bool $dryRun = true): array
|
||||
{
|
||||
$cutoff = date('Y-m-d H:i:s', strtotime("-{$olderThanHours} hours"));
|
||||
|
||||
// Draft theses with no files attached = orphaned submissions.
|
||||
$stmt = $this->pdo->prepare(
|
||||
"SELECT t.id, t.identifier, t.title, t.submitted_at
|
||||
FROM theses t
|
||||
WHERE t.status = 'draft'
|
||||
AND t.deleted_at IS NULL
|
||||
AND t.submitted_at < ?
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM thesis_files tf WHERE tf.thesis_id = t.id
|
||||
)
|
||||
ORDER BY t.submitted_at ASC"
|
||||
);
|
||||
$stmt->execute([$cutoff]);
|
||||
$candidates = $stmt->fetchAll();
|
||||
|
||||
if ($dryRun) {
|
||||
return ['deleted' => 0, 'candidates' => $candidates];
|
||||
}
|
||||
|
||||
$deleted = 0;
|
||||
require_once __DIR__ . '/Audit.php';
|
||||
$actor = Audit::actor();
|
||||
foreach ($candidates as $row) {
|
||||
$id = (int)$row['id'];
|
||||
$old = $this->fetchRow('theses', $id);
|
||||
// Hard-delete the orphan row and its junction records.
|
||||
// Cascade covers thesis_authors, thesis_tags, thesis_files (empty),
|
||||
// thesis_supervisors, thesis_languages, thesis_formats.
|
||||
$this->pdo->prepare('DELETE FROM theses WHERE id = ?')->execute([$id]);
|
||||
Audit::log($this, $actor, 'DELETE', 'theses', $id, $old, null);
|
||||
$deleted++;
|
||||
error_log("[cleanup-drafts] Deleted orphaned draft thesis {$id} ({$row['identifier']}) — submitted {$row['submitted_at']}");
|
||||
}
|
||||
|
||||
return ['deleted' => $deleted, 'candidates' => $candidates];
|
||||
}
|
||||
|
||||
/**
|
||||
* Soft-delete a single thesis (sets deleted_at).
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user