41f07b6ad8
Browser-based feed selection layered on top of config/feeds.php: - manage.php (password + CSRF gated, session based): add subreddits (name / r/name / URL) and YouTube channels (@handle / UC id / URL, handle resolved to channel_id once, youtube.com only); enable/disable toggles; remove manual feeds; config feeds are hidden, not deleted. - New feeds are validated with one immediate fetch (bypassing the per-refresh host cap): HTTP 404 rejects the entry, 429 keeps it for a later refresh. YouTube labels adopt the real channel title. - feeds table gains origin (config|manual) and enabled columns, with a guarded ALTER migration for existing databases. - Only enabled feeds are refreshed and served: getItems/countItems filter by feed_url in enabled feeds, so deselected feeds' cached stories are hidden, not deleted; re-adding a URL re-enables it. - Dashboard header gets a Manage link; manage page styled with the existing design tokens; README documents the feature.
72 lines
2.0 KiB
PHP
72 lines
2.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* Manual feed configuration: sign in, then add/remove/toggle subreddits and
|
|
* YouTube channels. POST actions redirect (PRG); results surface as flash.
|
|
*/
|
|
|
|
/** @var array<string, mixed> $app */
|
|
$app = require __DIR__ . '/src/bootstrap.php';
|
|
|
|
$config = $app['config'];
|
|
$manager = $app['manager'];
|
|
$service = $app['service'];
|
|
|
|
$auth = new App\ManageAuth($config);
|
|
|
|
$redirect = static function (): never {
|
|
header('Location: manage.php', true, 303);
|
|
exit;
|
|
};
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
$token = is_string($_POST['csrf'] ?? null) ? $_POST['csrf'] : '';
|
|
$action = is_string($_POST['action'] ?? null) ? $_POST['action'] : '';
|
|
$input = is_string($_POST['input'] ?? null) ? trim($_POST['input']) : '';
|
|
$url = is_string($_POST['url'] ?? null) ? trim($_POST['url']) : '';
|
|
$enabled = is_string($_POST['enabled'] ?? null) && $_POST['enabled'] === '1';
|
|
|
|
if (!$auth->enabled() || !$auth->checkCsrf($token)) {
|
|
$auth->flash('err', 'Session expired — please try again.');
|
|
$redirect();
|
|
}
|
|
|
|
if ($action === 'logout') {
|
|
$auth->logout();
|
|
$auth->flash('ok', 'Signed out.');
|
|
$redirect();
|
|
}
|
|
|
|
if ($action === 'login') {
|
|
if (!$auth->login($input)) {
|
|
$auth->flash('err', 'Wrong password.');
|
|
}
|
|
$redirect();
|
|
}
|
|
|
|
$result = $auth->authed() ? match ($action) {
|
|
'add_reddit' => $manager->addReddit($input),
|
|
'add_youtube' => $manager->addYouTube($input),
|
|
'toggle' => $manager->setEnabled($url, $enabled),
|
|
'remove' => $manager->remove($url),
|
|
default => null,
|
|
} : null;
|
|
|
|
if ($result === null) {
|
|
$auth->flash('err', 'Please sign in first.');
|
|
} else {
|
|
$auth->flash($result['ok'] ? 'ok' : 'err', $result['message']);
|
|
}
|
|
|
|
$redirect();
|
|
}
|
|
|
|
echo App\View::render('manage', [
|
|
'config' => $config,
|
|
'auth' => $auth,
|
|
'feeds' => $auth->authed() ? $service->feedsStatus() : [],
|
|
'flash' => $auth->takeFlash(),
|
|
]);
|