useMemory(false); $cache->setContent(db()->fetchAll(" SELECT `id`, `text`, `time`, `report_id`, `status` FROM `znote_changelog` ORDER BY `id` DESC; ") ?: []); $cache->save(); } // The public page writes 35 for entries created by hand; reports.php writes the // report status. Kept as-is so both keep meaning the same thing. const ACP_CHANGELOG_MANUAL_STATUS = 35; // --------------------------------------------------------------------------- // Mutations // --------------------------------------------------------------------------- if ($_SERVER['REQUEST_METHOD'] === 'POST') { $do = (string)($_POST['do'] ?? ''); $id = intv($_POST['id'] ?? 0); if ($do === 'delete' && $id > 0) { db()->execute("DELETE FROM `znote_changelog` WHERE `id` = ? LIMIT 1;", [$id]); acp_changelog_rebuild_cache(); acp_log('changelog.delete', '#' . $id); acp_flash_success(t('acp.chg.deleted')); acp_redirect('changelog'); } $text = trim((string)($_POST['text'] ?? '')); if ($text === '') { acp_flash_error(t('acp.chg.empty')); acp_redirect('changelog', $id > 0 ? ['action' => 'edit', 'id' => $id] : []); } // The column is varchar(255). Cutting is no longer safe now that the text can // carry BBCode - substr() would happily slice [b]word[/b] into [b]word[/ and // leave the tag dangling on the public page. Refuse instead and say why. if (strlen($text) > 254) { acp_flash_error(t('acp.chg.too_long', ['n' => strlen($text)])); acp_redirect('changelog', $id > 0 ? ['action' => 'edit', 'id' => $id] : []); } if ($do === 'update' && $id > 0) { db()->execute(" UPDATE `znote_changelog` SET `text` = ? WHERE `id` = ? LIMIT 1; ", [$text, $id]); acp_changelog_rebuild_cache(); acp_log('changelog.update', '#' . $id, ['text' => substr($text, 0, 60)]); acp_flash_success(t('acp.chg.updated')); acp_redirect('changelog'); } if ($do === 'create') { $when = intv($_POST['time'] ?? 0); if ($when <= 0) { $when = time(); } db()->execute(" INSERT INTO `znote_changelog` (`text`, `time`, `report_id`, `status`) VALUES (?, ?, 0, ?); ", [$text, $when, ACP_CHANGELOG_MANUAL_STATUS]); acp_changelog_rebuild_cache(); acp_log('changelog.create', '', ['text' => substr($text, 0, 60)]); acp_flash_success(t('acp.chg.published')); acp_redirect('changelog'); } acp_flash_error(t('acp.chg.unknown_action')); acp_redirect('changelog'); } // --------------------------------------------------------------------------- // View state // --------------------------------------------------------------------------- $entries = db()->fetchAll(" SELECT `id`, `text`, `time`, `report_id`, `status` FROM `znote_changelog` ORDER BY `id` DESC; "); $entries = is_array($entries) ? $entries : []; $editing = null; if (($_GET['action'] ?? '') === 'edit') { $editId = intv($_GET['id'] ?? 0); foreach ($entries as $entry) { if ((int)$entry['id'] === $editId) { $editing = $entry; break; } } if ($editing === null) { acp_flash_error(t('acp.chg.not_found')); acp_redirect('changelog'); } } $fromReports = 0; foreach ($entries as $entry) { if ((int)$entry['report_id'] > 0) { $fromReports++; } } ?>
= t('acp.chg.appears_top') ?>
= t('acp.chg.how_text1', [ 'link' => '' . t('acp.chg.reports_link') . '', ]) ?>
= t('acp.chg.how_text2') ?>
= t('acp.chg.newest_first') ?>
| # | = t('acp.chg.col_date') ?> | = t('acp.chg.col_entry') ?> | = t('acp.chg.col_source') ?> | = t('acp.chg.col_actions') ?> |
|---|---|---|---|---|
| = $id ?> | = h(getClock((int)$entry['time'], true, true)) ?> | = h((string)$entry['text']) ?> | 0): ?> = t('acp.chg.report_hash', ['id' => $reportId]) ?> = t('acp.chg.manual') ?> | = t('acp.chg.edit') ?> |