Client Portal) - the notices on the * portal's home page, to every client or one, between their start and end. */ defined('FROM_POST_HANDLER') || die("Direct file access is not allowed"); /** The announcement form, checked - [$fields, $error]. Raw values; the handlers escape them. */ function portalAnnouncementFromPost() { global $mysqli; $title = trim(mb_substr((string) ($_POST['title'] ?? ''), 0, 200)); $body = trim(mb_substr((string) ($_POST['body'] ?? ''), 0, 5000)); $tone = isset(PORTAL_ANNOUNCEMENT_TONES[$_POST['tone'] ?? '']) ? $_POST['tone'] : 'info'; $client_id = intval($_POST['client_id'] ?? 0); if ($client_id && !mysqli_num_rows(mysqli_query($mysqli, "SELECT client_id FROM clients WHERE client_id = $client_id"))) { $client_id = 0; } $when = function ($value) { $value = trim((string) $value); if ($value === '') { return null; } $time = strtotime($value); return $time ? date('Y-m-d H:i:s', $time) : false; }; $starts = $when($_POST['starts_at'] ?? ''); $ends = $when($_POST['ends_at'] ?? ''); $fields = compact('title', 'body', 'tone', 'client_id', 'starts', 'ends'); if ($title === '') { return [$fields, 'An announcement needs a title']; } if ($starts === false || $ends === false) { return [$fields, 'That date is not one']; } if ($starts && $ends && strtotime($ends) <= strtotime($starts)) { return [$fields, 'It has to end after it starts']; } return [$fields, '']; } /** The SET list for an announcement's fields. */ function portalAnnouncementSetSql(array $f) { global $mysqli; $body = mysqli_real_escape_string($mysqli, $f['body']); return "announcement_title = '" . escapeSql($f['title']) . "', announcement_body = '$body', announcement_tone = '" . escapeSql($f['tone']) . "', announcement_client_id = " . intval($f['client_id']) . ", announcement_starts_at = " . ($f['starts'] ? "'" . escapeSql($f['starts']) . "'" : 'NULL') . ", announcement_ends_at = " . ($f['ends'] ? "'" . escapeSql($f['ends']) . "'" : 'NULL'); } if (isset($_POST['add_portal_announcement'])) { validateCSRFToken(); [$fields, $error] = portalAnnouncementFromPost(); if ($error !== '') { flashAlert($error, 'error'); redirect(); } mysqli_query($mysqli, "INSERT INTO portal_announcements SET " . portalAnnouncementSetSql($fields) . ", announcement_created_by = $session_user_id"); $announcement_id = mysqli_insert_id($mysqli); $title = escapeSql($fields['title']); logAudit("Announcement", "Create", "$session_name posted the client portal announcement $title", intval($fields['client_id']), $announcement_id); flashAlert("Announcement " . escapeHtml($fields['title']) . " posted"); redirect(); } if (isset($_POST['edit_portal_announcement'])) { validateCSRFToken(); $announcement_id = intval($_POST['announcement_id'] ?? 0); [$fields, $error] = portalAnnouncementFromPost(); if ($error !== '') { flashAlert($error, 'error'); redirect(); } mysqli_query($mysqli, "UPDATE portal_announcements SET " . portalAnnouncementSetSql($fields) . " WHERE announcement_id = $announcement_id"); $title = escapeSql($fields['title']); logAudit("Announcement", "Edit", "$session_name edited the client portal announcement $title", intval($fields['client_id']), $announcement_id); flashAlert("Announcement " . escapeHtml($fields['title']) . " saved"); redirect(); } if (isset($_GET['archive_portal_announcement']) || isset($_GET['restore_portal_announcement'])) { validateCSRFToken(); $archive = isset($_GET['archive_portal_announcement']); $announcement_id = intval($archive ? $_GET['archive_portal_announcement'] : $_GET['restore_portal_announcement']); $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT announcement_title, announcement_client_id FROM portal_announcements WHERE announcement_id = $announcement_id")); if (!$row) { redirect(); } mysqli_query($mysqli, "UPDATE portal_announcements SET announcement_archived_at = " . ($archive ? 'NOW()' : 'NULL') . " WHERE announcement_id = $announcement_id"); $title = escapeSql($row['announcement_title']); logAudit("Announcement", $archive ? "Archive" : "Restore", "$session_name " . ($archive ? 'archived' : 'restored') . " the client portal announcement $title", intval($row['announcement_client_id']), $announcement_id); flashAlert("Announcement " . escapeHtml($row['announcement_title']) . " " . ($archive ? 'archived - the portal no longer shows it' : 'restored'), $archive ? 'error' : 'success'); redirect(); } if (isset($_GET['delete_portal_announcement'])) { validateCSRFToken(); $announcement_id = intval($_GET['delete_portal_announcement']); $row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT announcement_title, announcement_client_id FROM portal_announcements WHERE announcement_id = $announcement_id")); if (!$row) { redirect(); } mysqli_query($mysqli, "DELETE FROM portal_announcements WHERE announcement_id = $announcement_id"); $title = escapeSql($row['announcement_title']); logAudit("Announcement", "Delete", "$session_name deleted the client portal announcement $title", intval($row['announcement_client_id']), $announcement_id); flashAlert("Announcement " . escapeHtml($row['announcement_title']) . " deleted", 'error'); redirect(); }