jobs_delete.php 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. <?php
  2. // Soft-delete a job. ICG only. Sets jobs.deleted_at and logs a 'deleted'
  3. // event so the audit log captures who removed it and when.
  4. require_once __DIR__ . '/../lib/identity.php';
  5. require_once __DIR__ . '/../lib/jobs.php';
  6. [$actor, ] = resolve_request_actor();
  7. if ($actor !== 'ICG') {
  8. http_response_code(403);
  9. echo 'Only ICG can delete jobs';
  10. return;
  11. }
  12. $job_id = (int) ($_POST['job_id'] ?? 0);
  13. if ($job_id <= 0) {
  14. http_response_code(400);
  15. echo 'Bad job_id';
  16. return;
  17. }
  18. $pdo = db();
  19. $stmt = $pdo->prepare('SELECT * FROM jobs WHERE id = ?');
  20. $stmt->execute([$job_id]);
  21. $job = $stmt->fetch();
  22. if (!$job) {
  23. http_response_code(404);
  24. echo 'Job not found';
  25. return;
  26. }
  27. if (!empty($job['deleted_at'])) {
  28. // Already deleted — idempotent success.
  29. echo 'Success';
  30. return;
  31. }
  32. // BEGIN IMMEDIATE + retry, same pattern as apply_job_change.
  33. $attempts = 0;
  34. while (true) {
  35. $attempts++;
  36. try {
  37. $pdo->exec('BEGIN IMMEDIATE');
  38. break;
  39. } catch (PDOException $e) {
  40. if ($attempts >= 50 || !is_busy_error($e)) throw $e;
  41. usleep(100000);
  42. }
  43. }
  44. try {
  45. $upd = $pdo->prepare("UPDATE jobs SET deleted_at = datetime('now'), updated_at = datetime('now') WHERE id = ?");
  46. $upd->execute([$job_id]);
  47. $hist = $pdo->prepare(
  48. 'INSERT INTO job_history(job_id, field, old_value, new_value, actor) VALUES (?, ?, ?, ?, ?)'
  49. );
  50. $hist->execute([$job_id, 'deleted', null, $job['job'], $actor]);
  51. $pdo->exec('COMMIT');
  52. echo 'Success';
  53. } catch (Throwable $e) {
  54. $pdo->exec('ROLLBACK');
  55. throw $e;
  56. }