diff options
Diffstat (limited to 'p')
| -rw-r--r-- | p/api/greader.php | 6 | ||||
| -rw-r--r-- | p/api/query.php | 175 | ||||
| -rw-r--r-- | p/scripts/main.js | 15 | ||||
| -rw-r--r-- | p/themes/base-theme/frss.css | 4 | ||||
| -rw-r--r-- | p/themes/base-theme/frss.rtl.css | 4 |
5 files changed, 195 insertions, 9 deletions
diff --git a/p/api/greader.php b/p/api/greader.php index f8390e3ef..615f83567 100644 --- a/p/api/greader.php +++ b/p/api/greader.php @@ -572,7 +572,7 @@ final class GReaderAPI { continue; } - $feed = FreshRSS_CategoryDAO::findFeed($categories, $entry->feedId()); + $feed = FreshRSS_Category::findFeed($categories, $entry->feedId()); if ($feed === null) { continue; } @@ -694,7 +694,7 @@ final class GReaderAPI { } $entryDAO = FreshRSS_Factory::createEntryDao(); - $entries = $entryDAO->listWhere($type, $include_target, $state, $order === 'o' ? 'ASC' : 'DESC', $count, $continuation, $searches); + $entries = $entryDAO->listWhere($type, $include_target, $state, $order === 'o' ? 'ASC' : 'DESC', $count, 0, $continuation, $searches); $entries = iterator_to_array($entries); //TODO: Improve $items = self::entriesToArray($entries); @@ -746,7 +746,7 @@ final class GReaderAPI { } $entryDAO = FreshRSS_Factory::createEntryDao(); - $ids = $entryDAO->listIdsWhere($type, $id, $state, $order === 'o' ? 'ASC' : 'DESC', $count, $continuation, $searches); + $ids = $entryDAO->listIdsWhere($type, $id, $state, $order === 'o' ? 'ASC' : 'DESC', $count, 0, $continuation, $searches); if ($ids === null) { self::internalServerError(); } diff --git a/p/api/query.php b/p/api/query.php new file mode 100644 index 000000000..0ba14453f --- /dev/null +++ b/p/api/query.php @@ -0,0 +1,175 @@ +<?php +declare(strict_types=1); +require(__DIR__ . '/../../constants.php'); +require(LIB_PATH . '/lib_rss.php'); //Includes class autoloader + +Minz_Request::init(); + +$token = Minz_Request::paramString('t'); +if (!ctype_alnum($token)) { + header('HTTP/1.1 422 Unprocessable Entity'); + header('Content-Type: text/plain; charset=UTF-8'); + die('Invalid token `t`!' . $token); +} + +$format = Minz_Request::paramString('f'); +if (!in_array($format, ['atom', 'html', 'opml', 'rss'], true)) { + header('HTTP/1.1 422 Unprocessable Entity'); + header('Content-Type: text/plain; charset=UTF-8'); + die('Invalid format `f`!'); +} + +$user = Minz_Request::paramString('user'); +if (!FreshRSS_user_Controller::checkUsername($user)) { + header('HTTP/1.1 422 Unprocessable Entity'); + header('Content-Type: text/plain; charset=UTF-8'); + die('Invalid user!'); +} + +Minz_Session::init('FreshRSS', true); + +FreshRSS_Context::initSystem(); +if (!FreshRSS_Context::hasSystemConf() || !FreshRSS_Context::systemConf()->api_enabled) { + header('HTTP/1.1 503 Service Unavailable'); + header('Content-Type: text/plain; charset=UTF-8'); + die('Service Unavailable!'); +} + +FreshRSS_Context::initUser($user); +if (!FreshRSS_Context::hasUserConf()) { + usleep(rand(100, 10000)); //Primitive mitigation of scanning for users + header('HTTP/1.1 404 Not Found'); + header('Content-Type: text/plain; charset=UTF-8'); + die('User not found!'); +} else { + usleep(rand(20, 200)); +} + +if (!file_exists(DATA_PATH . '/no-cache.txt')) { + require(LIB_PATH . '/http-conditional.php'); + // TODO: Consider taking advantage of $feedMode, only for monotonous queries {all, categories, feeds} and not dynamic ones {read/unread, favourites, user labels} + if (httpConditional(FreshRSS_UserDAO::mtime($user) ?: time(), 0, 0, false, PHP_COMPRESSION, false)) { + exit(); //No need to send anything + } +} + +Minz_Translate::init(FreshRSS_Context::userConf()->language); +Minz_ExtensionManager::init(); +Minz_ExtensionManager::enableByList(FreshRSS_Context::userConf()->extensions_enabled, 'user'); + +$query = null; +$userSearch = null; +foreach (FreshRSS_Context::userConf()->queries as $raw_query) { + if (!empty($raw_query['token']) && $raw_query['token'] === $token) { + switch ($format) { + case 'atom': + case 'html': + case 'rss': + if (empty($raw_query['shareRss'])) { + continue 2; + } + break; + case 'opml': + if (empty($raw_query['shareOpml'])) { + continue 2; + } + break; + default: + continue 2; + } + $query = new FreshRSS_UserQuery($raw_query, FreshRSS_Context::categories(), FreshRSS_Context::labels()); + Minz_Request::_param('get', $query->getGet()); + if (Minz_Request::paramString('order') === '') { + Minz_Request::_param('order', $query->getOrder()); + } + Minz_Request::_param('state', $query->getState()); + + $search = $query->getSearch()->getRawInput(); + // Note: we disallow references to user queries in public user search to avoid sniffing internal user queries + $userSearch = new FreshRSS_BooleanSearch(Minz_Request::paramString('search'), 0, 'AND', false); + if ($userSearch->getRawInput() !== '') { + if ($search === '') { + $search = $userSearch->getRawInput(); + } else { + $search .= ' (' . $userSearch->getRawInput() . ')'; + } + } + Minz_Request::_param('search', $search); + break; + } +} +if ($query === null || $userSearch === null) { + usleep(rand(100, 10000)); + header('HTTP/1.1 404 Not Found'); + header('Content-Type: text/plain; charset=UTF-8'); + die('User query not found!'); +} + +$view = new FreshRSS_View(); + +try { + FreshRSS_Context::updateUsingRequest(false); + Minz_Request::_param('search', $userSearch->getRawInput()); // Restore user search + $view->entries = FreshRSS_index_Controller::listEntriesByContext(); +} catch (Minz_Exception $e) { + Minz_Error::error(400, 'Bad user query!'); + die(); +} + +$get = FreshRSS_Context::currentGet(true); +$type = (string)$get[0]; +$id = (int)$get[1]; + +switch ($type) { + case 'c': // Category + $cat = FreshRSS_Context::categories()[$id] ?? null; + if ($cat === null) { + Minz_Error::error(404, "Category {$id} not found!"); + die(); + } + $view->categories = [ $cat->id() => $cat ]; + break; + case 'f': // Feed + $feed = FreshRSS_Category::findFeed(FreshRSS_Context::categories(), $id); + if ($feed === null) { + Minz_Error::error(404, "Feed {$id} not found!"); + die(); + } + $view->feeds = [ $feed->id() => $feed ]; + $view->categories = []; + break; + default: + $view->categories = FreshRSS_Context::categories(); + break; +} + +$view->disable_aside = true; +$view->excludeMutedFeeds = true; +$view->internal_rendering = true; +$view->userQuery = $query; +$view->html_url = $query->sharedUrlHtml(); +$view->rss_url = $query->sharedUrlRss(); +$view->rss_title = $query->getName(); +if ($query->getName() != '') { + FreshRSS_View::_title($query->getName()); +} +FreshRSS_Context::systemConf()->allow_anonymous = true; + +if (in_array($format, ['rss', 'atom'], true)) { + header('Content-Type: application/rss+xml; charset=utf-8'); + $view->_layout(null); + $view->_path('index/rss.phtml'); +} elseif ($format === 'opml') { + if (!$query->safeForOpml()) { + Minz_Error::error(404, 'OPML not allowed for this user query!'); + die(); + } + header('Content-Type: application/xml; charset=utf-8'); + $view->_layout(null); + $view->_path('index/opml.phtml'); +} else { + $view->_layout('layout'); + $view->_path('index/html.phtml'); +} + +$view->build(); diff --git a/p/scripts/main.js b/p/scripts/main.js index ca52bac56..d07568617 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -439,7 +439,7 @@ function toggleContent(new_active, old_active, skipping) { const nav_menu = document.querySelector('.nav_menu'); let nav_menu_height = 0; - if (getComputedStyle(nav_menu).position === 'fixed' || getComputedStyle(nav_menu).position === 'sticky') { + if (nav_menu && (getComputedStyle(nav_menu).position === 'fixed' || getComputedStyle(nav_menu).position === 'sticky')) { nav_menu_height = nav_menu.offsetHeight; } @@ -1941,11 +1941,14 @@ function init_main_afterDOM() { if (stream) { init_load_more(stream); init_posts(); - init_nav_entries(); - init_notifs_html5(); - toggle_bigMarkAsRead_button(); - setTimeout(faviconNbUnread, 1000); - setInterval(refreshUnreads, 120000); + if (document.getElementById('new-article')) { + // Only relevant for interactive views + init_nav_entries(); + init_notifs_html5(); + toggle_bigMarkAsRead_button(); + setTimeout(faviconNbUnread, 1000); + setInterval(refreshUnreads, 120000); + } } if (window.console) { diff --git a/p/themes/base-theme/frss.css b/p/themes/base-theme/frss.css index ebbd7a627..ab2ac57ab 100644 --- a/p/themes/base-theme/frss.css +++ b/p/themes/base-theme/frss.css @@ -110,6 +110,10 @@ h2 { line-height: 1.5; } +.api > h2 { + text-align: center; +} + h2 .icon, legend .icon { height: 0.8em; diff --git a/p/themes/base-theme/frss.rtl.css b/p/themes/base-theme/frss.rtl.css index 45b967b63..239c8ca8b 100644 --- a/p/themes/base-theme/frss.rtl.css +++ b/p/themes/base-theme/frss.rtl.css @@ -110,6 +110,10 @@ h2 { line-height: 1.5; } +.api > h2 { + text-align: center; +} + h2 .icon, legend .icon { height: 0.8em; |
