chore: initial commit
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/db.php';
|
||||
|
||||
try {
|
||||
match ($_SERVER['REQUEST_METHOD']) {
|
||||
'GET' => handle_get(),
|
||||
'POST' => handle_post(),
|
||||
'PUT' => handle_put(),
|
||||
'DELETE' => handle_delete(),
|
||||
default => error_out('Method not allowed', 405),
|
||||
};
|
||||
} catch (PDOException $e) {
|
||||
error_out('Database error: ' . $e->getMessage(), 500);
|
||||
}
|
||||
|
||||
// ─── GET /api/schedule.php ────────────────────────────────────────────────────
|
||||
|
||||
function handle_get(): never
|
||||
{
|
||||
$rows = db()->query(
|
||||
'SELECT sr.id, sr.mode, sr.offset_value, sr.offset_unit,
|
||||
sr.specific_datetime, sr.created_at,
|
||||
t.id AS template_id, t.name AS template_name
|
||||
FROM scheduled_rules sr
|
||||
JOIN sms_templates t ON t.id = sr.template_id
|
||||
ORDER BY sr.created_at DESC'
|
||||
)->fetchAll();
|
||||
|
||||
json_out(['rules' => $rows]);
|
||||
}
|
||||
|
||||
// ─── POST /api/schedule.php ───────────────────────────────────────────────────
|
||||
// Body: {
|
||||
// "template_id": 1,
|
||||
// "mode": "relative", -- or "specific"
|
||||
// "offset_value": 30, -- required for relative
|
||||
// "offset_unit": "minutes", -- required for relative (minutes|hours|days)
|
||||
// "specific_datetime": "..." -- required for specific (ISO 8601 or MySQL datetime)
|
||||
// }
|
||||
|
||||
function handle_post(): never
|
||||
{
|
||||
$body = json_body();
|
||||
$templateId = (int) ($body['template_id'] ?? 0);
|
||||
$mode = (string) ($body['mode'] ?? '');
|
||||
|
||||
if ($templateId <= 0) {
|
||||
error_out('template_id is required');
|
||||
}
|
||||
if (!in_array($mode, ['relative', 'specific'], true)) {
|
||||
error_out('mode must be "relative" or "specific"');
|
||||
}
|
||||
|
||||
$offsetValue = null;
|
||||
$offsetUnit = null;
|
||||
$specificDt = null;
|
||||
|
||||
if ($mode === 'relative') {
|
||||
$offsetValue = (int) ($body['offset_value'] ?? 0);
|
||||
$offsetUnit = (string) ($body['offset_unit'] ?? '');
|
||||
|
||||
if ($offsetValue <= 0) {
|
||||
error_out('offset_value must be a positive integer');
|
||||
}
|
||||
if (!in_array($offsetUnit, ['minutes', 'hours', 'days'], true)) {
|
||||
error_out('offset_unit must be "minutes", "hours", or "days"');
|
||||
}
|
||||
} else {
|
||||
$specificDt = (string) ($body['specific_datetime'] ?? '');
|
||||
if ($specificDt === '') {
|
||||
error_out('specific_datetime is required when mode is "specific"');
|
||||
}
|
||||
if (strtotime($specificDt) === false) {
|
||||
error_out('specific_datetime is not a valid date/time');
|
||||
}
|
||||
}
|
||||
|
||||
// Verify template exists
|
||||
$check = db()->prepare('SELECT id FROM sms_templates WHERE id = :id');
|
||||
$check->execute([':id' => $templateId]);
|
||||
if (!$check->fetch()) {
|
||||
error_out('Template not found', 404);
|
||||
}
|
||||
|
||||
$stmt = db()->prepare(
|
||||
'INSERT INTO scheduled_rules (template_id, mode, offset_value, offset_unit, specific_datetime)
|
||||
VALUES (:template_id, :mode, :offset_value, :offset_unit, :specific_datetime)'
|
||||
);
|
||||
$stmt->execute([
|
||||
':template_id' => $templateId,
|
||||
':mode' => $mode,
|
||||
':offset_value' => $offsetValue,
|
||||
':offset_unit' => $offsetUnit,
|
||||
':specific_datetime' => $specificDt,
|
||||
]);
|
||||
|
||||
json_out(['id' => (int) db()->lastInsertId()], 201);
|
||||
}
|
||||
|
||||
// ─── PUT /api/schedule.php?id=N ─────────────────────────────────────────────
|
||||
// Body: same fields as POST
|
||||
|
||||
function handle_put(): never
|
||||
{
|
||||
$id = (int) ($_GET['id'] ?? 0);
|
||||
if ($id <= 0) {
|
||||
error_out('Missing or invalid id');
|
||||
}
|
||||
|
||||
$body = json_body();
|
||||
$templateId = (int) ($body['template_id'] ?? 0);
|
||||
$mode = (string) ($body['mode'] ?? '');
|
||||
|
||||
if ($templateId <= 0) {
|
||||
error_out('template_id is required');
|
||||
}
|
||||
if (!in_array($mode, ['relative', 'specific'], true)) {
|
||||
error_out('mode must be "relative" or "specific"');
|
||||
}
|
||||
|
||||
$offsetValue = null;
|
||||
$offsetUnit = null;
|
||||
$specificDt = null;
|
||||
|
||||
if ($mode === 'relative') {
|
||||
$offsetValue = (int) ($body['offset_value'] ?? 0);
|
||||
$offsetUnit = (string) ($body['offset_unit'] ?? '');
|
||||
if ($offsetValue <= 0) {
|
||||
error_out('offset_value must be a positive integer');
|
||||
}
|
||||
if (!in_array($offsetUnit, ['minutes', 'hours', 'days'], true)) {
|
||||
error_out('offset_unit must be "minutes", "hours", or "days"');
|
||||
}
|
||||
} else {
|
||||
$specificDt = (string) ($body['specific_datetime'] ?? '');
|
||||
if ($specificDt === '') {
|
||||
error_out('specific_datetime is required when mode is "specific"');
|
||||
}
|
||||
if (strtotime($specificDt) === false) {
|
||||
error_out('specific_datetime is not a valid date/time');
|
||||
}
|
||||
}
|
||||
|
||||
$db = db();
|
||||
$check = $db->prepare('SELECT id FROM sms_templates WHERE id = :id');
|
||||
$check->execute([':id' => $templateId]);
|
||||
if (!$check->fetch()) {
|
||||
error_out('Template not found', 404);
|
||||
}
|
||||
|
||||
$stmt = $db->prepare(
|
||||
'UPDATE scheduled_rules
|
||||
SET template_id = :template_id, mode = :mode,
|
||||
offset_value = :offset_value, offset_unit = :offset_unit,
|
||||
specific_datetime = :specific_datetime
|
||||
WHERE id = :id'
|
||||
);
|
||||
$stmt->execute([
|
||||
':template_id' => $templateId,
|
||||
':mode' => $mode,
|
||||
':offset_value' => $offsetValue,
|
||||
':offset_unit' => $offsetUnit,
|
||||
':specific_datetime' => $specificDt,
|
||||
':id' => $id,
|
||||
]);
|
||||
|
||||
if ($stmt->rowCount() === 0) {
|
||||
error_out('Rule not found', 404);
|
||||
}
|
||||
|
||||
// Detach previous send_jobs so the updated rule fires fresh on the next
|
||||
// scheduler tick (delivery_log history is preserved via the send_jobs FK).
|
||||
$db->prepare('UPDATE send_jobs SET scheduled_rule_id = NULL WHERE scheduled_rule_id = :id')
|
||||
->execute([':id' => $id]);
|
||||
|
||||
json_out(['updated' => true]);
|
||||
}
|
||||
|
||||
// ─── DELETE /api/schedule.php?id=N ───────────────────────────────────────────
|
||||
|
||||
function handle_delete(): never
|
||||
{
|
||||
$id = (int) ($_GET['id'] ?? 0);
|
||||
if ($id <= 0) {
|
||||
error_out('Missing or invalid id');
|
||||
}
|
||||
|
||||
$stmt = db()->prepare('DELETE FROM scheduled_rules WHERE id = :id');
|
||||
$stmt->execute([':id' => $id]);
|
||||
|
||||
if ($stmt->rowCount() === 0) {
|
||||
error_out('Rule not found', 404);
|
||||
}
|
||||
|
||||
json_out(['deleted' => true]);
|
||||
}
|
||||
Reference in New Issue
Block a user