$image['title'] ?? '', 'desc' => $image['desc'] ?? '', 'date' => $image['date'] ?? '', 'image' => $image['image'] ?? '', ]; } } $cache->setContent($data); $cache->save(); } // --------------------------------------------------------------------------- // Actions // --------------------------------------------------------------------------- if ($_SERVER['REQUEST_METHOD'] === 'POST') { $do = (string)($_POST['do'] ?? ''); $id = intv($_POST['id'] ?? 0); if ($id > 0) { // Soft delete: hidden from the public gallery but kept on record. if ($do === 'delete') { updateImage($id, 3); acp_gallery_rebuild_cache(); acp_log('gallery.hide', '#' . $id); acp_flash_success(t('acp.gal.hidden', ['id' => $id])); acp_redirect('gallery'); } // Accept, or recover a soft-deleted image. if ($do === 'accept') { updateImage($id, 2); acp_gallery_rebuild_cache(); acp_log('gallery.accept', '#' . $id); acp_flash_success(t('acp.gal.public', ['id' => $id])); acp_redirect('gallery'); } // Hard delete: drop it at imgur too, then remove the row. if ($do === 'remove') { $delhash = (string)($_POST['delhash'] ?? ''); $imgurClientID = (string)($config['gallery']['Client ID'] ?? ''); if ($delhash !== '' && $imgurClientID !== '' && function_exists('curl_init')) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'https://api.imgur.com/3/image/' . rawurlencode($delhash)); curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE'); curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Client-ID {$imgurClientID}"]); $result = curl_exec($ch); if ($result === false) { error_log('cURL error (imgur delete): ' . curl_error($ch)); } curl_close($ch); } db()->execute("DELETE FROM `znote_images` WHERE `id` = ? LIMIT 1;", [$id]); acp_gallery_rebuild_cache(); acp_log('gallery.remove', '#' . $id); acp_flash_success(t('acp.gal.removed', ['id' => $id])); acp_redirect('gallery'); } } acp_flash_error(t('acp.gal.unknown_action')); acp_redirect('gallery'); } /** * One moderation section: heading, count, and a card per image. * * @param array>|false $images * @param array $actions */ function acp_gallery_section($images, string $title, string $subtitle, array $actions, string $emptyText): void { $images = is_array($images) ? $images : []; ?>

'], h((string)($image['desc'] ?? ''))); ?>
'accept', 'label' => t('acp.gal.approve'), 'icon' => 'fa-check', 'class' => 'acp-btn--green'], ['do' => 'delete', 'label' => t('acp.gal.reject'), 'icon' => 'fa-times', 'class' => 'acp-btn--red'], ], t('acp.gal.pending_empty') ); acp_gallery_section( fetchImages(2), t('acp.gal.public_title'), t('acp.gal.public_sub'), [ ['do' => 'delete', 'label' => t('acp.gal.hide'), 'icon' => 'fa-eye-slash', 'class' => 'acp-btn--amber'], ], t('acp.gal.public_empty') ); acp_gallery_section( fetchImages(3), t('acp.gal.hidden_title'), t('acp.gal.hidden_sub'), [ ['do' => 'accept', 'label' => t('acp.gal.recover'), 'icon' => 'fa-undo', 'class' => 'acp-btn--green'], [ 'do' => 'remove', 'label' => t('acp.gal.delete_forever'), 'icon' => 'fa-trash', 'class' => 'acp-btn--red', 'confirm' => t('acp.gal.delete_confirm'), ], ], t('acp.gal.hidden_empty') );