/** * This action is called before every other action in that class. It is * the common boiler plate for every action. It is triggered by the * underlying framework. */ public function firstAction() { if (!FreshRSS_Auth::hasAccess()) { Minz_Error::error(403); } require_once LIB_PATH . '/lib_opml.php'; $this->catDAO = new FreshRSS_CategoryDAO(); $this->entryDAO = FreshRSS_Factory::createEntryDao(); $this->feedDAO = FreshRSS_Factory::createFeedDao(); }
public function loadCompleteContent($pathEntries) { // Gestion du contenu // On cherche à récupérer les articles en entier... même si le flux ne le propose pas if ($pathEntries) { $entryDAO = FreshRSS_Factory::createEntryDao(); $entry = $entryDAO->searchByGuid($this->feed, $this->guid); if ($entry) { // l'article existe déjà en BDD, en se contente de recharger ce contenu $this->content = $entry->content(); } else { try { // l'article n'est pas en BDD, on va le chercher sur le site $this->content = get_content_by_parsing(htmlspecialchars_decode($this->link(), ENT_QUOTES), $pathEntries); } catch (Exception $e) { // rien à faire, on garde l'ancien contenu(requête a échoué) } } } }
/** * This action handles the archive configuration page. * * It displays the archive configuration page. * If this action is reached through a POST request, it stores all new * configuration values then sends a notification to the user. * * The options available on that page are: * - duration to retain old article (default: 3) * - number of article to retain per feed (default: 0) * - refresh frequency (default: -2) * * @todo explain why the default value is -2 but this value does not * exist in the drop-down list */ public function archivingAction() { if (Minz_Request::isPost()) { FreshRSS_Context::$user_conf->old_entries = Minz_Request::param('old_entries', 3); FreshRSS_Context::$user_conf->keep_history_default = Minz_Request::param('keep_history_default', 0); FreshRSS_Context::$user_conf->ttl_default = Minz_Request::param('ttl_default', -2); FreshRSS_Context::$user_conf->save(); invalidateHttpCache(); Minz_Request::good(_t('feedback.conf.updated'), array('c' => 'configure', 'a' => 'archiving')); } Minz_View::prependTitle(_t('conf.archiving.title') . ' · '); $entryDAO = FreshRSS_Factory::createEntryDao(); $this->view->nb_total = $entryDAO->count(); $this->view->size_user = $entryDAO->size(); if (FreshRSS_Auth::hasAccess('admin')) { $this->view->size_total = $entryDAO->size(true); } }
function markAllAsRead($streamId, $olderThanId) { logMe("markAllAsRead({$streamId}, {$olderThanId})\n"); $entryDAO = FreshRSS_Factory::createEntryDao(); if (strpos($streamId, 'feed/') === 0) { $f_id = basename($streamId); $entryDAO->markReadFeed($f_id, $olderThanId); } elseif (strpos($streamId, 'user/-/label/') === 0) { $c_name = basename($streamId); $categoryDAO = new FreshRSS_CategoryDAO(); $cat = $categoryDAO->searchByName($c_name); $entryDAO->markReadCat($cat === null ? -1 : $cat->id(), $olderThanId); } elseif ($streamId === 'user/-/state/com.google/reading-list') { $entryDAO->markReadEntries($olderThanId, false, -1); } echo 'OK'; exit; }
/** * This action actualizes entries from one or several feeds. * * Parameters are: * - id (default: false): Feed ID * - url (default: false): Feed URL * - force (default: false) * If id and url are not specified, all the feeds are actualized. But if force is * false, process stops at 10 feeds to avoid time execution problem. */ public function actualizeAction($simplePiePush = null) { @set_time_limit(300); $feedDAO = FreshRSS_Factory::createFeedDao(); $entryDAO = FreshRSS_Factory::createEntryDao(); Minz_Session::_param('actualize_feeds', false); $id = Minz_Request::param('id'); $url = Minz_Request::param('url'); $force = Minz_Request::param('force'); // Create a list of feeds to actualize. // If id is set and valid, corresponding feed is added to the list but // alone in order to automatize further process. $feeds = array(); if ($id || $url) { $feed = $id ? $feedDAO->searchById($id) : $feedDAO->searchByUrl($url); if ($feed) { $feeds[] = $feed; } } else { $feeds = $feedDAO->listFeedsOrderUpdate(FreshRSS_Context::$user_conf->ttl_default); } // Calculate date of oldest entries we accept in DB. $nb_month_old = max(FreshRSS_Context::$user_conf->old_entries, 1); $date_min = time() - 3600 * 24 * 30 * $nb_month_old; // PubSubHubbub support $pubsubhubbubEnabledGeneral = FreshRSS_Context::$system_conf->pubsubhubbub_enabled; $pshbMinAge = time() - 3600 * 24; //TODO: Make a configuration. $updated_feeds = 0; $is_read = FreshRSS_Context::$user_conf->mark_when['reception'] ? 1 : 0; foreach ($feeds as $feed) { $url = $feed->url(); //For detection of HTTP 301 $pubSubHubbubEnabled = $pubsubhubbubEnabledGeneral && $feed->pubSubHubbubEnabled(); if (!$simplePiePush && !$id && $pubSubHubbubEnabled && $feed->lastUpdate() > $pshbMinAge) { //$text = 'Skip pull of feed using PubSubHubbub: ' . $url; //Minz_Log::debug($text); //file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND); continue; //When PubSubHubbub is used, do not pull refresh so often } if (!$feed->lock()) { Minz_Log::notice('Feed already being actualized: ' . $feed->url()); continue; } try { if ($simplePiePush) { $feed->loadEntries($simplePiePush); //Used by PubSubHubbub } else { $feed->load(false); } } catch (FreshRSS_Feed_Exception $e) { Minz_Log::warning($e->getMessage()); $feedDAO->updateLastUpdate($feed->id(), true); $feed->unlock(); continue; } $feed_history = $feed->keepHistory(); if ($feed_history == -2) { // TODO: -2 must be a constant! // -2 means we take the default value from configuration $feed_history = FreshRSS_Context::$user_conf->keep_history_default; } // We want chronological order and SimplePie uses reverse order. $entries = array_reverse($feed->entries()); if (count($entries) > 0) { $newGuids = array(); foreach ($entries as $entry) { $newGuids[] = $entry->guid(); } // For this feed, check existing GUIDs already in database. $existingHashForGuids = $entryDAO->listHashForFeedGuids($feed->id(), $newGuids); unset($newGuids); $oldGuids = array(); // Add entries in database if possible. foreach ($entries as $entry) { $entry_date = $entry->date(true); if (isset($existingHashForGuids[$entry->guid()])) { $existingHash = $existingHashForGuids[$entry->guid()]; if (strcasecmp($existingHash, $entry->hash()) === 0 || $existingHash === '00000000000000000000000000000000') { //This entry already exists and is unchanged. TODO: Remove the test with the zero'ed hash in FreshRSS v1.3 $oldGuids[] = $entry->guid(); } else { //This entry already exists but has been updated Minz_Log::debug('Entry with GUID `' . $entry->guid() . '` updated in feed ' . $feed->id() . ', old hash ' . $existingHash . ', new hash ' . $entry->hash()); //TODO: Make an updated/is_read policy by feed, in addition to the global one. $entry->_isRead(FreshRSS_Context::$user_conf->mark_updated_article_unread ? false : null); //Change is_read according to policy. if (!$entryDAO->hasTransaction()) { $entryDAO->beginTransaction(); } $entryDAO->updateEntry($entry->toArray()); } } elseif ($feed_history == 0 && $entry_date < $date_min) { // This entry should not be added considering configuration and date. $oldGuids[] = $entry->guid(); } else { if ($entry_date < $date_min) { $id = min(time(), $entry_date) . uSecString(); $entry->_isRead(true); //Old article that was not in database. Probably an error, so mark as read } else { $id = uTimeString(); $entry->_isRead($is_read); } $entry->_id($id); $entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry); if ($entry === null) { // An extension has returned a null value, there is nothing to insert. continue; } if ($pubSubHubbubEnabled && !$simplePiePush) { //We use push, but have discovered an article by pull! $text = 'An article was discovered by pull although we use PubSubHubbub!: Feed ' . $url . ' GUID ' . $entry->guid(); file_put_contents(USERS_PATH . '/_/log_pshb.txt', date('c') . "\t" . $text . "\n", FILE_APPEND); Minz_Log::warning($text); $pubSubHubbubEnabled = false; $feed->pubSubHubbubError(true); } if (!$entryDAO->hasTransaction()) { $entryDAO->beginTransaction(); } $entryDAO->addEntry($entry->toArray()); } } $entryDAO->updateLastSeen($feed->id(), $oldGuids); } if ($feed_history >= 0 && rand(0, 30) === 1) { // TODO: move this function in web cron when available (see entry::purge) // Remove old entries once in 30. if (!$entryDAO->hasTransaction()) { $entryDAO->beginTransaction(); } $nb = $feedDAO->cleanOldEntries($feed->id(), $date_min, max($feed_history, count($entries) + 10)); if ($nb > 0) { Minz_Log::debug($nb . ' old entries cleaned in feed [' . $feed->url() . ']'); } } $feedDAO->updateLastUpdate($feed->id(), 0, $entryDAO->hasTransaction()); if ($entryDAO->hasTransaction()) { $entryDAO->commit(); } if ($feed->hubUrl() && $feed->selfUrl()) { //selfUrl has priority for PubSubHubbub if ($feed->selfUrl() !== $url) { //https://code.google.com/p/pubsubhubbub/wiki/MovingFeedsOrChangingHubs $selfUrl = checkUrl($feed->selfUrl()); if ($selfUrl) { Minz_Log::debug('PubSubHubbub unsubscribe ' . $feed->url()); if (!$feed->pubSubHubbubSubscribe(false)) { //Unsubscribe Minz_Log::warning('Error while PubSubHubbub unsubscribing from ' . $feed->url()); } $feed->_url($selfUrl, false); Minz_Log::notice('Feed ' . $url . ' canonical address moved to ' . $feed->url()); $feedDAO->updateFeed($feed->id(), array('url' => $feed->url())); } } } elseif ($feed->url() !== $url) { // HTTP 301 Moved Permanently Minz_Log::notice('Feed ' . $url . ' moved permanently to ' . $feed->url()); $feedDAO->updateFeed($feed->id(), array('url' => $feed->url())); } $feed->faviconPrepare(); if ($pubsubhubbubEnabledGeneral && $feed->pubSubHubbubPrepare()) { Minz_Log::notice('PubSubHubbub subscribe ' . $feed->url()); if (!$feed->pubSubHubbubSubscribe(true)) { //Subscribe Minz_Log::warning('Error while PubSubHubbub subscribing to ' . $feed->url()); } } $feed->unlock(); $updated_feeds++; unset($feed); // No more than 10 feeds unless $force is true to avoid overloading // the server. if ($updated_feeds >= 10 && !$force) { break; } } if (Minz_Request::param('ajax')) { // Most of the time, ajax request is for only one feed. But since // there are several parallel requests, we should return that there // are several updated feeds. $notif = array('type' => 'good', 'content' => _t('feedback.sub.feed.actualizeds')); Minz_Session::_param('notification', $notif); // No layout in ajax request. $this->view->_useLayout(false); } else { // Redirect to the main page with correct notification. if ($updated_feeds === 1) { $feed = reset($feeds); Minz_Request::good(_t('feedback.sub.feed.actualized', $feed->name()), array('params' => array('get' => 'f_' . $feed->id()))); } elseif ($updated_feeds > 1) { Minz_Request::good(_t('feedback.sub.feed.n_actualized', $updated_feeds), array()); } else { Minz_Request::good(_t('feedback.sub.feed.no_refresh'), array()); } } return $updated_feeds; }
/** * This method returns a list of entries based on the Context object. */ private function listEntriesByContext() { $entryDAO = FreshRSS_Factory::createEntryDao(); $get = FreshRSS_Context::currentGet(true); if (count($get) > 1) { $type = $get[0]; $id = $get[1]; } else { $type = $get; $id = ''; } return $entryDAO->listWhere($type, $id, FreshRSS_Context::$state, FreshRSS_Context::$order, FreshRSS_Context::$number + 1, FreshRSS_Context::$first_id, FreshRSS_Context::$search); }
/** * This action displays the user management page. */ public function manageAction() { if (!FreshRSS_Auth::hasAccess('admin')) { Minz_Error::error(403); } Minz_View::prependTitle(_t('admin.user.title') . ' · '); // Get the correct current user. $username = Minz_Request::param('u', Minz_Session::param('currentUser')); if (!FreshRSS_UserDAO::exist($username)) { $username = Minz_Session::param('currentUser'); } $this->view->current_user = $username; // Get information about the current user. $entryDAO = FreshRSS_Factory::createEntryDao($this->view->current_user); $this->view->nb_articles = $entryDAO->count(); $this->view->size_user = $entryDAO->size(); }
/** * This action optimizes database to reduce its size. * * This action shouldbe reached by a POST request. * * @todo move this action in configure controller. * @todo call this action through web-cron when available */ public function optimizeAction() { $url_redirect = array('c' => 'configure', 'a' => 'archiving'); if (!Minz_Request::isPost()) { Minz_Request::forward($url_redirect, true); } @set_time_limit(300); $entryDAO = FreshRSS_Factory::createEntryDao(); $entryDAO->optimizeTable(); $feedDAO = FreshRSS_Factory::createFeedDao(); $feedDAO->updateCachedValues(); invalidateHttpCache(); Minz_Request::good(_t('feedback.admin.optimization_complete'), $url_redirect); }
public function getCounters() { $categoryDAO = new FreshRSS_CategoryDAO(); $counters = array(); $total_unreads = 0; // Get feed unread counters $categories = $categoryDAO->listCategories(true, true); foreach ($categories as $cat) { foreach ($cat->feeds() as $feed) { $counters[] = array('id' => $feed->id(), 'counter' => $feed->nbNotRead()); } $total_unreads += $cat->nbNotRead(); } // Get global unread counter $counters[] = array('id' => 'global-unread', 'counter' => $total_unreads); // Get favorite unread counter $entryDAO = FreshRSS_Factory::createEntryDao(); $fav_counters = $entryDAO->countUnreadReadFavorites(); $counters[] = array('id' => -1, 'counter' => $fav_counters['unread']); $this->good($counters); }
/** * This action actualizes entries from one or several feeds. * * Parameters are: * - id (default: false) * - force (default: false) * If id is not specified, all the feeds are actualized. But if force is * false, process stops at 10 feeds to avoid time execution problem. */ public function actualizeAction() { @set_time_limit(300); $feedDAO = FreshRSS_Factory::createFeedDao(); $entryDAO = FreshRSS_Factory::createEntryDao(); Minz_Session::_param('actualize_feeds', false); $id = Minz_Request::param('id'); $force = Minz_Request::param('force'); // Create a list of feeds to actualize. // If id is set and valid, corresponding feed is added to the list but // alone in order to automatize further process. $feeds = array(); if ($id) { $feed = $feedDAO->searchById($id); if ($feed) { $feeds[] = $feed; } } else { $feeds = $feedDAO->listFeedsOrderUpdate(FreshRSS_Context::$user_conf->ttl_default); } // Calculate date of oldest entries we accept in DB. $nb_month_old = max(FreshRSS_Context::$user_conf->old_entries, 1); $date_min = time() - 3600 * 24 * 30 * $nb_month_old; $updated_feeds = 0; $is_read = FreshRSS_Context::$user_conf->mark_when['reception'] ? 1 : 0; foreach ($feeds as $feed) { if (!$feed->lock()) { Minz_Log::notice('Feed already being actualized: ' . $feed->url()); continue; } try { // Load entries $feed->load(false); } catch (FreshRSS_Feed_Exception $e) { Minz_Log::notice($e->getMessage()); $feedDAO->updateLastUpdate($feed->id(), 1); $feed->unlock(); continue; } $url = $feed->url(); $feed_history = $feed->keepHistory(); if ($feed_history == -2) { // TODO: -2 must be a constant! // -2 means we take the default value from configuration $feed_history = FreshRSS_Context::$user_conf->keep_history_default; } // We want chronological order and SimplePie uses reverse order. $entries = array_reverse($feed->entries()); if (count($entries) > 0) { // For this feed, check last n entry GUIDs already in database. $existing_guids = array_fill_keys($entryDAO->listLastGuidsByFeed($feed->id(), count($entries) + 10), 1); $use_declared_date = empty($existing_guids); // Add entries in database if possible. $prepared_statement = $entryDAO->addEntryPrepare(); $feedDAO->beginTransaction(); foreach ($entries as $entry) { $entry_date = $entry->date(true); if (isset($existing_guids[$entry->guid()]) || $feed_history == 0 && $entry_date < $date_min) { // This entry already exists in DB or should not be added // considering configuration and date. continue; } $id = uTimeString(); if ($use_declared_date || $entry_date < $date_min) { // Use declared date at first import. $id = min(time(), $entry_date) . uSecString(); } $entry->_id($id); $entry->_isRead($is_read); $entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry); if (is_null($entry)) { // An extension has returned a null value, there is nothing to insert. continue; } $values = $entry->toArray(); $entryDAO->addEntry($values, $prepared_statement); } } if ($feed_history >= 0 && rand(0, 30) === 1) { // TODO: move this function in web cron when available (see entry::purge) // Remove old entries once in 30. if (!$feedDAO->hasTransaction()) { $feedDAO->beginTransaction(); } $nb = $feedDAO->cleanOldEntries($feed->id(), $date_min, max($feed_history, count($entries) + 10)); if ($nb > 0) { Minz_Log::debug($nb . ' old entries cleaned in feed [' . $feed->url() . ']'); } } $feedDAO->updateLastUpdate($feed->id(), 0, $feedDAO->hasTransaction()); if ($feedDAO->hasTransaction()) { $feedDAO->commit(); } if ($feed->url() !== $url) { // HTTP 301 Moved Permanently Minz_Log::notice('Feed ' . $url . ' moved permanently to ' . $feed->url()); $feedDAO->updateFeed($feed->id(), array('url' => $feed->url())); } $feed->faviconPrepare(); $feed->unlock(); $updated_feeds++; unset($feed); // No more than 10 feeds unless $force is true to avoid overloading // the server. if ($updated_feeds >= 10 && !$force) { break; } } if (Minz_Request::param('ajax')) { // Most of the time, ajax request is for only one feed. But since // there are several parallel requests, we should return that there // are several updated feeds. $notif = array('type' => 'good', 'content' => _t('feedback.sub.feed.actualizeds')); Minz_Session::_param('notification', $notif); // No layout in ajax request. $this->view->_useLayout(false); return; } // Redirect to the main page with correct notification. if ($updated_feeds === 1) { $feed = reset($feeds); Minz_Request::good(_t('feedback.sub.feed.actualized', $feed->name()), array('params' => array('get' => 'f_' . $feed->id()))); } elseif ($updated_feeds > 1) { Minz_Request::good(_t('feedback.sub.feed.n_actualized', $updated_feeds), array()); } else { Minz_Request::good(_t('feedback.sub.feed.no_refresh'), array()); } }