diff options
Diffstat (limited to 'app')
89 files changed, 660 insertions, 320 deletions
diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php index 28f0cb745..73e181b07 100755 --- a/app/Controllers/entryController.php +++ b/app/Controllers/entryController.php @@ -40,7 +40,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { $get = Minz_Request::param('get'); $next_get = Minz_Request::param('nextGet', $get); $id_max = Minz_Request::param('idMax', 0); - FreshRSS_Context::$search = new FreshRSS_Search(Minz_Request::param('search', '')); + FreshRSS_Context::$search = new FreshRSS_BooleanSearch(Minz_Request::param('search', '')); FreshRSS_Context::$state = Minz_Request::param('state', 0); if (FreshRSS_Context::isStateEnabled(FreshRSS_Entry::STATE_FAVORITE)) { diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index af732951f..ca85e7cb8 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -84,6 +84,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { 'description' => $feed->description(), 'lastUpdate' => time(), 'httpAuth' => $feed->httpAuth(), + 'attributes' => array(), ); $id = $feedDAO->addFeed($values); @@ -271,7 +272,6 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $updated_feeds = 0; $nb_new_articles = 0; - $is_read = FreshRSS_Context::$user_conf->mark_when['reception'] ? 1 : 0; foreach ($feeds as $feed) { $url = $feed->url(); //For detection of HTTP 301 @@ -284,10 +284,10 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } $mtime = 0; - $ttl = $feed->ttl(); - if ($ttl < FreshRSS_Feed::TTL_DEFAULT) { + if ($feed->mute()) { continue; //Feed refresh is disabled } + $ttl = $feed->ttl(); if ((!$simplePiePush) && (!$feed_id) && ($feed->lastUpdate() + 10 >= time() - ($ttl == FreshRSS_Feed::TTL_DEFAULT ? FreshRSS_Context::$user_conf->ttl_default : $ttl))) { //Too early to refresh from source, but check whether the feed was updated by another user @@ -353,8 +353,10 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } 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. - $needFeedCacheRefresh = FreshRSS_Context::$user_conf->mark_updated_article_unread; + $mark_updated_article_unread = $feed->attributes('mark_updated_article_unread') !== null ? ( + $feed->attributes('mark_updated_article_unread') + ) : FreshRSS_Context::$user_conf->mark_updated_article_unread; + $needFeedCacheRefresh = $mark_updated_article_unread; $entry->_isRead(FreshRSS_Context::$user_conf->mark_updated_article_unread ? false : null); //Change is_read according to policy. if (!$entryDAO->inTransaction()) { $entryDAO->beginTransaction(); @@ -365,15 +367,18 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // This entry should not be added considering configuration and date. $oldGuids[] = $entry->guid(); } else { + $read_upon_reception = $feed->attributes('read_upon_reception') !== null ? ( + $feed->attributes('read_upon_reception') + ) : FreshRSS_Context::$user_conf->mark_when['reception']; if ($isNewFeed) { $id = min(time(), $entry_date) . uSecString(); - $entry->_isRead($is_read); + $entry->_isRead($read_upon_reception); } elseif ($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->_isRead($read_upon_reception); } $entry->_id($id); diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index a76dd9a2b..0fb5ba651 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -390,6 +390,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $article_to_feed = array(); $nb_feeds = count($this->feedDAO->listFeeds()); + $newFeedGuids = array(); $limits = FreshRSS_Context::$system_conf->limits; // First, we check feeds of articles are in DB (and add them if needed). @@ -417,21 +418,25 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { if ($feed != null) { $article_to_feed[$item['id']] = $feed->id(); + if (!isset($newFeedGuids['f_' . $feed->id()])) { + $newFeedGuids['f_' . $feed->id()] = array(); + } + $newFeedGuids['f_' . $feed->id()][] = safe_ascii($item['id']); } } - $newGuids = array(); - foreach ($article_object['items'] as $item) { - $newGuids[] = safe_ascii($item['id']); + // For each feed, check existing GUIDs already in database. + $existingHashForGuids = array(); + foreach ($newFeedGuids as $feedId => $newGuids) { + $existingHashForGuids[$feedId] = $this->entryDAO->listHashForFeedGuids(substr($feedId, 2), $newGuids); } - // For this feed, check existing GUIDs already in database. - $existingHashForGuids = $this->entryDAO->listHashForFeedGuids($feed->id(), $newGuids); - $newGuids = array(); + unset($newFeedGuids); // Then, articles are imported. + $newGuids = array(); $this->entryDAO->beginTransaction(); foreach ($article_object['items'] as $item) { - if (!isset($article_to_feed[$item['id']])) { + if (empty($article_to_feed[$item['id']])) { // Related feed does not exist for this entry, do nothing. continue; } @@ -468,7 +473,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $values = $entry->toArray(); $ok = false; - if (isset($existingHashForGuids[$entry->guid()])) { + if (isset($existingHashForGuids['f_' . $feed_id][$entry->guid()])) { $ok = $this->entryDAO->updateEntry($values); } else { $ok = $this->entryDAO->addEntry($values); diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index e3dbd4664..8567b4657 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -182,7 +182,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { FreshRSS_Context::$state |= FreshRSS_Entry::STATE_READ; } - FreshRSS_Context::$search = new FreshRSS_Search(Minz_Request::param('search', '')); + FreshRSS_Context::$search = new FreshRSS_BooleanSearch(Minz_Request::param('search', '')); FreshRSS_Context::$order = Minz_Request::param( 'order', FreshRSS_Context::$user_conf->sort_order ); diff --git a/app/Controllers/subscriptionController.php b/app/Controllers/subscriptionController.php index 37efd3b57..701a588e0 100644 --- a/app/Controllers/subscriptionController.php +++ b/app/Controllers/subscriptionController.php @@ -15,7 +15,7 @@ class FreshRSS_subscription_Controller extends Minz_ActionController { } $catDAO = new FreshRSS_CategoryDAO(); - $feedDAO = new FreshRSS_FeedDAO(); + $feedDAO = FreshRSS_Factory::createFeedDao(); $catDAO->checkDefault(); $feedDAO->updateTTL(); @@ -74,9 +74,10 @@ class FreshRSS_subscription_Controller extends Minz_ActionController { return; } - $this->view->feed = $this->view->feeds[$id]; + $feed = $this->view->feeds[$id]; + $this->view->feed = $feed; - Minz_View::prependTitle(_t('sub.title.feed_management') . ' · ' . $this->view->feed->name() . ' · '); + Minz_View::prependTitle(_t('sub.title.feed_management') . ' · ' . $feed->name() . ' · '); if (Minz_Request::isPost()) { $user = trim(Minz_Request::param('http_user_feed' . $id, '')); @@ -95,6 +96,18 @@ class FreshRSS_subscription_Controller extends Minz_ActionController { $ttl = FreshRSS_Context::$user_conf->ttl_default; } + $feed->_attributes('mark_updated_article_unread', Minz_Request::paramTernary('mark_updated_article_unread')); + $feed->_attributes('read_upon_reception', Minz_Request::paramTernary('read_upon_reception')); + + if (FreshRSS_Auth::hasAccess('admin')) { + $feed->_attributes('ssl_verify', Minz_Request::paramTernary('ssl_verify')); + $timeout = intval(Minz_Request::param('timeout', 0)); + $feed->_attributes('timeout', $timeout > 0 ? $timeout : null); + } else { + $feed->_attributes('ssl_verify', null); + $feed->_attributes('timeout', null); + } + $values = array( 'name' => Minz_Request::param('name', ''), 'description' => sanitizeHTML(Minz_Request::param('description', '', true)), @@ -106,14 +119,15 @@ class FreshRSS_subscription_Controller extends Minz_ActionController { 'httpAuth' => $httpAuth, 'keep_history' => intval(Minz_Request::param('keep_history', FreshRSS_Feed::KEEP_HISTORY_DEFAULT)), 'ttl' => $ttl * ($mute ? -1 : 1), + 'attributes' => $feed->attributes() ); invalidateHttpCache(); $url_redirect = array('c' => 'subscription', 'params' => array('id' => $id)); if ($feedDAO->updateFeed($id, $values) !== false) { - $this->view->feed->_category($cat); - $this->view->feed->faviconPrepare(); + $feed->_category($cat); + $feed->faviconPrepare(); Minz_Request::good(_t('feedback.sub.feed.updated'), $url_redirect); } else { diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index 2dad6a3f0..47f0ecc62 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -44,8 +44,20 @@ class FreshRSS_user_Controller extends Minz_ActionController { return preg_match('/^' . self::USERNAME_PATTERN . '$/', $username) === 1; } + public static function deleteFeverKey($username) { + $userConfig = get_user_configuration($username); + if ($userConfig !== null && ctype_xdigit($userConfig->feverKey)) { + return @unlink(DATA_PATH . '/fever/.key-' . sha1(FreshRSS_Context::$system_conf->salt) . '-' . $userConfig->feverKey . '.txt'); + } + return false; + } + public static function updateUser($user, $passwordPlain, $apiPasswordPlain, $userConfigUpdated = array()) { $userConfig = get_user_configuration($user); + if ($userConfig === null) { + return false; + } + if ($passwordPlain != '') { $passwordHash = self::hashPassword($passwordPlain); $userConfig->passwordHash = $passwordHash; @@ -54,6 +66,16 @@ class FreshRSS_user_Controller extends Minz_ActionController { if ($apiPasswordPlain != '') { $apiPasswordHash = self::hashPassword($apiPasswordPlain); $userConfig->apiPasswordHash = $apiPasswordHash; + + @mkdir(DATA_PATH . '/fever/', 0770, true); + self::deleteFeverKey($user); + $userConfig->feverKey = strtolower(md5($user . ':' . $apiPasswordPlain)); + $ok = file_put_contents(DATA_PATH . '/fever/.key-' . sha1(FreshRSS_Context::$system_conf->salt) . '-' . $userConfig->feverKey . '.txt', $user) !== false; + + if (!$ok) { + Minz_Log::warning('Could not save API credentials for fever API', ADMIN_LOG); + return $ok; + } } if (is_array($userConfigUpdated)) { @@ -78,8 +100,8 @@ class FreshRSS_user_Controller extends Minz_ActionController { $username = Minz_Request::param('username'); $ok = self::updateUser($username, $passwordPlain, $apiPasswordPlain, array( - 'token' => Minz_Request::param('token', null), - )); + 'token' => Minz_Request::param('token', null), + )); if ($ok) { Minz_Request::good(_t('feedback.user.updated', $username), @@ -169,29 +191,15 @@ class FreshRSS_user_Controller extends Minz_ActionController { $ok &= !file_exists($configPath); } if ($ok) { - $passwordHash = ''; - if ($passwordPlain != '') { - $passwordHash = self::hashPassword($passwordPlain); - $ok &= ($passwordHash != ''); - } - - $apiPasswordHash = ''; - if ($apiPasswordPlain != '') { - $apiPasswordHash = self::hashPassword($apiPasswordPlain); - $ok &= ($apiPasswordHash != ''); - } - } - if ($ok) { if (!is_dir($homeDir)) { mkdir($homeDir); } - $userConfig['passwordHash'] = $passwordHash; - $userConfig['apiPasswordHash'] = $apiPasswordHash; $ok &= (file_put_contents($configPath, "<?php\n return " . var_export($userConfig, true) . ';') !== false); } if ($ok) { $userDAO = new FreshRSS_UserDAO(); $ok &= $userDAO->createUser($new_user_name, $userConfig['language'], $insertDefaultFeeds); + $ok &= self::updateUser($new_user_name, $passwordPlain, $apiPasswordPlain); } return $ok; } @@ -246,10 +254,9 @@ class FreshRSS_user_Controller extends Minz_ActionController { $ok &= (strcasecmp($username, $default_user) !== 0); //It is forbidden to delete the default user } $user_data = join_path(DATA_PATH, 'users', $username); + $ok &= is_dir($user_data); if ($ok) { - $ok &= is_dir($user_data); - } - if ($ok) { + self::deleteFeverKey($username); $userDAO = new FreshRSS_UserDAO(); $ok &= $userDAO->deleteUser($username); $ok &= recursive_unlink($user_data); diff --git a/app/Models/BooleanSearch.php b/app/Models/BooleanSearch.php new file mode 100644 index 000000000..6e016f7e9 --- /dev/null +++ b/app/Models/BooleanSearch.php @@ -0,0 +1,55 @@ +<?php + +/** + * Contains Boolean search from the search form. + */ +class FreshRSS_BooleanSearch { + + private $raw_input = ''; + private $searches = array(); + + public function __construct($input) { + $input = trim($input); + if ($input == '') { + return; + } + $this->raw_input = $input; + + $input = preg_replace('/:"(.*?)"/', ':"\1"', $input); + $splits = preg_split('/\b(OR)\b/i', $input, -1, PREG_SPLIT_DELIM_CAPTURE); + + $segment = ''; + $ns = count($splits); + for ($i = 0; $i < $ns; $i++) { + $segment = $segment . $splits[$i]; + if (trim($segment) == '' || strcasecmp($segment, 'OR') === 0) { + $segment = ''; + } else { + $quotes = substr_count($segment, '"') + substr_count($segment, '"'); + if ($quotes % 2 === 0) { + $segment = trim($segment); + if ($segment != '') { + $this->searches[] = new FreshRSS_Search($segment); + } + $segment = ''; + } + } + } + $segment = trim($segment); + if ($segment != '') { + $this->searches[] = new FreshRSS_Search($segment); + } + } + + public function searches() { + return $this->searches; + } + + public function __toString() { + return $this->getRawInput(); + } + + public function getRawInput() { + return $this->raw_input; + } +} diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php index 68db17db3..ef2c402a0 100644 --- a/app/Models/CategoryDAO.php +++ b/app/Models/CategoryDAO.php @@ -134,7 +134,11 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable if (isset($cat[0])) { return $cat[0]; } else { - return false; + if (FreshRSS_Context::$isCli) { + fwrite(STDERR, 'FreshRSS database error: Default category not found!' . "\n"); + } + Minz_Log::error('FreshRSS database error: Default category not found!'); + return null; } } public function checkDefault() { @@ -144,13 +148,27 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable $cat = new FreshRSS_Category(_t('gen.short.default_category')); $cat->_id(self::DEFAULTCATEGORYID); + $sql = 'INSERT INTO `' . $this->prefix . 'category`(id, name) VALUES(?, ?)'; + if (parent::$sharedDbType === 'pgsql') { + //Force call to nextval() + $sql .= " RETURNING nextval('" . $this->prefix . "category_id_seq');"; + } + $stm = $this->bd->prepare($sql); + $values = array( - 'id' => $cat->id(), - 'name' => $cat->name(), + $cat->id(), + $cat->name(), ); - $this->addCategory($values); + if ($stm && $stm->execute($values)) { + return $this->bd->lastInsertId('"' . $this->prefix . 'category_id_seq"'); + } else { + $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + Minz_Log::error('SQL error check default category: ' . json_encode($info)); + return false; + } } + return true; } public function count() { diff --git a/app/Models/DatabaseDAO.php b/app/Models/DatabaseDAO.php index f5469f2b7..b8e5577e4 100644 --- a/app/Models/DatabaseDAO.php +++ b/app/Models/DatabaseDAO.php @@ -50,7 +50,7 @@ class FreshRSS_DatabaseDAO extends Minz_ModelPdo { public function feedIsCorrect() { return $this->checkTable('feed', array( 'id', 'url', 'category', 'name', 'website', 'description', 'lastUpdate', - 'priority', 'pathEntries', 'httpAuth', 'error', 'keep_history', 'ttl', + 'priority', 'pathEntries', 'httpAuth', 'error', 'keep_history', 'ttl', 'attributes', 'cache_nbEntries', 'cache_nbUnreads' )); } diff --git a/app/Models/Entry.php b/app/Models/Entry.php index 0ad3781e5..c6b26a7cc 100644 --- a/app/Models/Entry.php +++ b/app/Models/Entry.php @@ -193,7 +193,8 @@ class FreshRSS_Entry extends Minz_Model { 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 + htmlspecialchars_decode($this->link(), ENT_QUOTES), $pathEntries, + $this->feed->attributes() ); } catch (Exception $e) { // rien à faire, on garde l'ancien contenu(requête a échoué) diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 8cdebedc5..a3bca3727 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -437,7 +437,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { * @param integer $priorityMin * @return integer affected rows */ - public function markReadEntries($idMax = 0, $onlyFavorites = false, $priorityMin = 0, $filter = null, $state = 0) { + public function markReadEntries($idMax = 0, $onlyFavorites = false, $priorityMin = 0, $filters = null, $state = 0) { FreshRSS_UserDAO::touch(); if ($idMax == 0) { $idMax = time() . '000000'; @@ -454,7 +454,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } $values = array($idMax); - list($searchValues, $search) = $this->sqlListEntriesWhere('e.', $filter, $state); + list($searchValues, $search) = $this->sqlListEntriesWhere('e.', $filters, $state); $stm = $this->bd->prepare($sql . $search); if (!($stm && $stm->execute(array_merge($values, $searchValues)))) { @@ -480,7 +480,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { * @param integer $idMax fail safe article ID * @return integer affected rows */ - public function markReadCat($id, $idMax = 0, $filter = null, $state = 0) { + public function markReadCat($id, $idMax = 0, $filters = null, $state = 0) { FreshRSS_UserDAO::touch(); if ($idMax == 0) { $idMax = time() . '000000'; @@ -492,7 +492,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { . 'WHERE f.category=? AND e.is_read=0 AND e.id <= ?'; $values = array($id, $idMax); - list($searchValues, $search) = $this->sqlListEntriesWhere('e.', $filter, $state); + list($searchValues, $search) = $this->sqlListEntriesWhere('e.', $filters, $state); $stm = $this->bd->prepare($sql . $search); if (!($stm && $stm->execute(array_merge($values, $searchValues)))) { @@ -518,7 +518,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { * @param integer $idMax fail safe article ID * @return integer affected rows */ - public function markReadFeed($id_feed, $idMax = 0, $filter = null, $state = 0) { + public function markReadFeed($id_feed, $idMax = 0, $filters = null, $state = 0) { FreshRSS_UserDAO::touch(); if ($idMax == 0) { $idMax = time() . '000000'; @@ -531,7 +531,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { . 'WHERE id_feed=? AND is_read=0 AND id <= ?'; $values = array($id_feed, $idMax); - list($searchValues, $search) = $this->sqlListEntriesWhere('', $filter, $state); + list($searchValues, $search) = $this->sqlListEntriesWhere('', $filters, $state); $stm = $this->bd->prepare($sql . $search); if (!($stm && $stm->execute(array_merge($values, $searchValues)))) { @@ -625,7 +625,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { return 'CONCAT(' . $s1 . ',' . $s2 . ')'; //MySQL } - protected function sqlListEntriesWhere($alias = '', $filter = null, $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $firstId = '', $date_min = 0) { + protected function sqlListEntriesWhere($alias = '', $filters = null, $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $firstId = '', $date_min = 0) { $search = ' '; $values = array(); if ($state & FreshRSS_Entry::STATE_NOT_READ) { @@ -650,10 +650,6 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { default: throw new FreshRSS_EntriesGetter_Exception('Bad order in Entry->listByType: [' . $order . ']!'); } - /*if ($firstId === '' && parent::$sharedDbType === 'mysql') { - //MySQL optimization. TODO: check if this is needed again, after the filtering for old articles has been removed in 0.9-dev - $firstId = $order === 'DESC' ? '9000000000'. '000000' : '0'; - }*/ if ($firstId !== '') { $search .= 'AND ' . $alias . 'id ' . ($order === 'DESC' ? '<=' : '>=') . ' ? '; $values[] = $firstId; @@ -662,91 +658,111 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $search .= 'AND ' . $alias . 'id >= ? '; $values[] = $date_min . '000000'; } - if ($filter) { - if ($filter->getMinDate()) { - $search .= 'AND ' . $alias . 'id >= ? '; - $values[] = "{$filter->getMinDate()}000000"; - } - if ($filter->getMaxDate()) { - $search .= 'AND ' . $alias . 'id <= ? '; - $values[] = "{$filter->getMaxDate()}000000"; - } - if ($filter->getMinPubdate()) { - $search .= 'AND ' . $alias . 'date >= ? '; - $values[] = $filter->getMinPubdate(); - } - if ($filter->getMaxPubdate()) { - $search .= 'AND ' . $alias . 'date <= ? '; - $values[] = $filter->getMaxPubdate(); - } + if ($filters && count($filters->searches()) > 0) { + $isOpen = false; + foreach ($filters->searches() as $filter) { + if ($filter == null) { + continue; + } + $sub_search = ''; + if ($filter->getMinDate()) { + $sub_search .= 'AND ' . $alias . 'id >= ? '; + $values[] = "{$filter->getMinDate()}000000"; + } + if ($filter->getMaxDate()) { + $sub_search .= 'AND ' . $alias . 'id <= ? '; + $values[] = "{$filter->getMaxDate()}000000"; + } + if ($filter->getMinPubdate()) { + $sub_search .= 'AND ' . $alias . 'date >= ? '; + $values[] = $filter->getMinPubdate(); + } + if ($filter->getMaxPubdate()) { + $sub_search .= 'AND ' . $alias . 'date <= ? '; + $values[] = $filter->getMaxPubdate(); + } - if ($filter->getAuthor()) { - foreach ($filter->getAuthor() as $author) { - $search .= 'AND ' . $alias . 'author LIKE ? '; - $values[] = "%{$author}%"; + if ($filter->getAuthor()) { + foreach ($filter->getAuthor() as $author) { + $sub_search .= 'AND ' . $alias . 'author LIKE ? '; + $values[] = "%{$author}%"; + } } - } - if ($filter->getIntitle()) { - foreach ($filter->getIntitle() as $title) { - $search .= 'AND ' . $alias . 'title LIKE ? '; - $values[] = "%{$title}%"; + if ($filter->getIntitle()) { + foreach ($filter->getIntitle() as $title) { + $sub_search .= 'AND ' . $alias . 'title LIKE ? '; + $values[] = "%{$title}%"; + } } - } - if ($filter->getTags()) { - foreach ($filter->getTags() as $tag) { - $search .= 'AND ' . $alias . 'tags LIKE ? '; - $values[] = "%{$tag}%"; + if ($filter->getTags()) { + foreach ($filter->getTags() as $tag) { + $sub_search .= 'AND ' . $alias . 'tags LIKE ? '; + $values[] = "%{$tag}%"; + } } - } - if ($filter->getInurl()) { - foreach ($filter->getInurl() as $url) { - $search .= 'AND CONCAT(' . $alias . 'link, ' . $alias . 'guid) LIKE ? '; - $values[] = "%{$url}%"; + if ($filter->getInurl()) { + foreach ($filter->getInurl() as $url) { + $sub_search .= 'AND CONCAT(' . $alias . 'link, ' . $alias . 'guid) LIKE ? '; + $values[] = "%{$url}%"; + } } - } - if ($filter->getNotAuthor()) { - foreach ($filter->getNotAuthor() as $author) { - $search .= 'AND (NOT ' . $alias . 'author LIKE ?) '; - $values[] = "%{$author}%"; + if ($filter->getNotAuthor()) { + foreach ($filter->getNotAuthor() as $author) { + $sub_search .= 'AND (NOT ' . $alias . 'author LIKE ?) '; + $values[] = "%{$author}%"; + } } - } - if ($filter->getNotIntitle()) { - foreach ($filter->getNotIntitle() as $title) { - $search .= 'AND (NOT ' . $alias . 'title LIKE ?) '; - $values[] = "%{$title}%"; + if ($filter->getNotIntitle()) { + foreach ($filter->getNotIntitle() as $title) { + $sub_search .= 'AND (NOT ' . $alias . 'title LIKE ?) '; + $values[] = "%{$title}%"; + } } - } - if ($filter->getNotTags()) { - foreach ($filter->getNotTags() as $tag) { - $search .= 'AND (NOT ' . $alias . 'tags LIKE ?) '; - $values[] = "%{$tag}%"; + if ($filter->getNotTags()) { + foreach ($filter->getNotTags() as $tag) { + $sub_search .= 'AND (NOT ' . $alias . 'tags LIKE ?) '; + $values[] = "%{$tag}%"; + } } - } - if ($filter->getNotInurl()) { - foreach ($filter->getNotInurl() as $url) { - $search .= 'AND (NOT CONCAT(' . $alias . 'link, ' . $alias . 'guid) LIKE ?) '; - $values[] = "%{$url}%"; + if ($filter->getNotInurl()) { + foreach ($filter->getNotInurl() as $url) { + $sub_search .= 'AND (NOT CONCAT(' . $alias . 'link, ' . $alias . 'guid) LIKE ?) '; + $values[] = "%{$url}%"; + } } - } - if ($filter->getSearch()) { - foreach ($filter->getSearch() as $search_value) { - $search .= 'AND ' . $this->sqlconcat($alias . 'title', $this->isCompressed() ? 'UNCOMPRESS(' . $alias . 'content_bin)' : '' . $alias . 'content') . ' LIKE ? '; - $values[] = "%{$search_value}%"; + if ($filter->getSearch()) { + foreach ($filter->getSearch() as $search_value) { + $sub_search .= 'AND ' . $this->sqlconcat($alias . 'title', $this->isCompressed() ? 'UNCOMPRESS(' . $alias . 'content_bin)' : '' . $alias . 'content') . ' LIKE ? '; + $values[] = "%{$search_value}%"; + } } - } - if ($filter->getNotSearch()) { - foreach ($filter->getNotSearch() as $search_value) { - $search .= 'AND (NOT ' . $this->sqlconcat($alias . 'title', $this->isCompressed() ? 'UNCOMPRESS(' . $alias . 'content_bin)' : '' . $alias . 'content') . ' LIKE ?) '; - $values[] = "%{$search_value}%"; + if ($filter->getNotSearch()) { + foreach ($filter->getNotSearch() as $search_value) { + $sub_search .= 'AND (NOT ' . $this->sqlconcat($alias . 'title', $this->isCompressed() ? 'UNCOMPRESS(' . $alias . 'content_bin)' : '' . $alias . 'content') . ' LIKE ?) '; + $values[] = "%{$search_value}%"; + } } + + if ($sub_search != '') { + if ($isOpen) { + $search .= 'OR '; + } else { + $search .= 'AND ('; + $isOpen = true; + } + $search .= '(' . substr($sub_search, 4) . ') '; + } + } + if ($isOpen) { + $search .= ') '; } } return array($values, $search); } - private function sqlListWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0) { + private function sqlListWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filters = null, $date_min = 0) { if (!$state) { $state = FreshRSS_Entry::STATE_ALL; } @@ -777,7 +793,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { throw new FreshRSS_EntriesGetter_Exception('Bad type in Entry->listByType: [' . $type . ']!'); } - list($searchValues, $search) = $this->sqlListEntriesWhere('e.', $filter, $state, $order, $firstId, $date_min); + list($searchValues, $search) = $this->sqlListEntriesWhere('e.', $filters, $state, $order, $firstId, $date_min); return array(array_merge($values, $searchValues), 'SELECT e.id FROM `' . $this->prefix . 'entry` e ' @@ -785,11 +801,11 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { . 'WHERE ' . $where . $search . 'ORDER BY e.id ' . $order - . ($limit > 0 ? ' LIMIT ' . $limit : '')); //TODO: See http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/ + . ($limit > 0 ? ' LIMIT ' . intval($limit) : '')); //TODO: See http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/ } - public function listWhereRaw($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0) { - list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min); + public function listWhereRaw($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filters = null, $date_min = 0) { + list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filters, $date_min); $sql = 'SELECT e0.id, e0.guid, e0.title, e0.author, ' . ($this->isCompressed() ? 'UNCOMPRESS(content_bin) AS content' : 'content') @@ -805,8 +821,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { return $stm; } - public function listWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0) { - $stm = $this->listWhereRaw($type, $id, $state, $order, $limit, $firstId, $filter, $date_min); + public function listWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filters = null, $date_min = 0) { + $stm = $this->listWhereRaw($type, $id, $state, $order, $limit, $firstId, $filters, $date_min); return self::daoToEntries($stm->fetchAll(PDO::FETCH_ASSOC)); } @@ -827,8 +843,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { return self::daoToEntries($stm->fetchAll(PDO::FETCH_ASSOC)); } - public function listIdsWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0) { //For API - list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min); + public function listIdsWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filters = null, $date_min = 0) { //For API + list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filters, $date_min); $stm = $this->bd->prepare($sql); $stm->execute($values); diff --git a/app/Models/EntryDAOSQLite.php b/app/Models/EntryDAOSQLite.php index 0f57dc1ba..cca970e36 100644 --- a/app/Models/EntryDAOSQLite.php +++ b/app/Models/EntryDAOSQLite.php @@ -7,7 +7,6 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { } protected function autoUpdateDb($errorInfo) { - Minz_Log::error('FreshRSS_EntryDAO::autoUpdateDb error: ' . print_r($errorInfo, true)); if ($tableInfo = $this->bd->query("SELECT sql FROM sqlite_master where name='entrytmp'")) { $showCreate = $tableInfo->fetchColumn(); if (stripos($showCreate, 'entrytmp') === false) { @@ -27,63 +26,28 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { public function commitNewEntries() { $sql = ' - CREATE TEMP TABLE `tmp` AS - SELECT - id, - guid, - title, - author, - content, - link, - date, - `lastSeen`, - hash, is_read, - is_favorite, - id_feed, - tags - FROM `' . $this->prefix . 'entrytmp` - ORDER BY date; - INSERT OR IGNORE INTO `' . $this->prefix . 'entry` - ( - id, - guid, - title, - author, - content, - link, - date, - `lastSeen`, - hash, - is_read, - is_favorite, - id_feed, - tags - ) - SELECT rowid + (SELECT MAX(id) - COUNT(*) FROM `tmp`) AS - id, - guid, - title, - author, - content, - link, - date, - `lastSeen`, - hash, - is_read, - is_favorite, - id_feed, - tags - FROM `tmp` - ORDER BY date; - DELETE FROM `' . $this->prefix . 'entrytmp` - WHERE id <= (SELECT MAX(id) - FROM `tmp`); - DROP TABLE `tmp`;'; +DROP TABLE IF EXISTS `tmp`; +CREATE TEMP TABLE `tmp` AS + SELECT id, guid, title, author, content, link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags + FROM `' . $this->prefix . 'entrytmp` + ORDER BY date; +INSERT OR IGNORE INTO `' . $this->prefix . 'entry` + (id, guid, title, author, content, link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags) + SELECT rowid + (SELECT MAX(id) - COUNT(*) FROM `tmp`) AS id, + guid, title, author, content, link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags + FROM `tmp` + ORDER BY date; +DELETE FROM `' . $this->prefix . 'entrytmp` WHERE id <= (SELECT MAX(id) FROM `tmp`); +DROP TABLE IF EXISTS `tmp`; +'; $hadTransaction = $this->bd->inTransaction(); if (!$hadTransaction) { $this->bd->beginTransaction(); } $result = $this->bd->exec($sql) !== false; + if (!$result) { + Minz_Log::error('SQL error commitNewEntries: ' . json_encode($this->bd->errorInfo())); + } if (!$hadTransaction) { $this->bd->commit(); } @@ -195,7 +159,7 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { * @param integer $priorityMin * @return integer affected rows */ - public function markReadEntries($idMax = 0, $onlyFavorites = false, $priorityMin = 0, $filter = null, $state = 0) { + public function markReadEntries($idMax = 0, $onlyFavorites = false, $priorityMin = 0, $filters = null, $state = 0) { if ($idMax == 0) { $idMax = time() . '000000'; Minz_Log::debug('Calling markReadEntries(0) is deprecated!'); @@ -209,7 +173,7 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { } $values = array($idMax); - list($searchValues, $search) = $this->sqlListEntriesWhere('', $filter, $state); + list($searchValues, $search) = $this->sqlListEntriesWhere('', $filters, $state); $stm = $this->bd->prepare($sql . $search); if (!($stm && $stm->execute(array_merge($values, $searchValues)))) { @@ -235,7 +199,7 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { * @param integer $idMax fail safe article ID * @return integer affected rows */ - public function markReadCat($id, $idMax = 0, $filter = null, $state = 0) { + public function markReadCat($id, $idMax = 0, $filters = null, $state = 0) { if ($idMax == 0) { $idMax = time() . '000000'; Minz_Log::debug('Calling markReadCat(0) is deprecated!'); @@ -247,7 +211,7 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { . 'id_feed IN (SELECT f.id FROM `' . $this->prefix . 'feed` f WHERE f.category=?)'; $values = array($idMax, $id); - list($searchValues, $search) = $this->sqlListEntriesWhere('', $filter, $state); + list($searchValues, $search) = $this->sqlListEntriesWhere('', $filters, $state); $stm = $this->bd->prepare($sql . $search); if (!($stm && $stm->execute(array_merge($values, $searchValues)))) { diff --git a/app/Models/Factory.php b/app/Models/Factory.php index dfccc883e..764987c46 100644 --- a/app/Models/Factory.php +++ b/app/Models/Factory.php @@ -3,7 +3,13 @@ class FreshRSS_Factory { public static function createFeedDao($username = null) { - return new FreshRSS_FeedDAO($username); + $conf = Minz_Configuration::get('system'); + switch ($conf->db['type']) { + case 'sqlite': + return new FreshRSS_FeedDAOSQLite($username); + default: + return new FreshRSS_FeedDAO($username); + } } public static function createEntryDao($username = null) { diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 196d94931..7eb079f15 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -26,6 +26,7 @@ class FreshRSS_Feed extends Minz_Model { private $error = false; private $keep_history = self::KEEP_HISTORY_DEFAULT; private $ttl = self::TTL_DEFAULT; + private $attributes = array(); private $mute = false; private $hash = null; private $lockPath = ''; @@ -114,6 +115,13 @@ class FreshRSS_Feed extends Minz_Model { public function ttl() { return $this->ttl; } + public function attributes($key = '') { + if ($key == '') { + return $this->attributes; + } else { + return isset($this->attributes[$key]) ? $this->attributes[$key] : null; + } + } public function mute() { return $this->mute; } @@ -234,6 +242,22 @@ class FreshRSS_Feed extends Minz_Model { $this->ttl = abs($value); $this->mute = $value < self::TTL_DEFAULT; } + + public function _attributes($key, $value) { + if ($key == '') { + if (is_string($value)) { + $value = json_decode($value, true); + } + if (is_array($value)) { + $this->attributes = $value; + } + } elseif ($value === null) { + unset($this->attributes[$key]); + } else { + $this->attributes[$key] = $value; + } + } + public function _nbNotRead($value) { $this->nbNotRead = intval($value); } @@ -253,7 +277,7 @@ class FreshRSS_Feed extends Minz_Model { if ($this->httpAuth != '') { $url = preg_replace('#((.+)://)(.+)#', '${1}' . $this->httpAuth . '@${3}', $url); } - $feed = customSimplePie(); + $feed = customSimplePie($this->attributes()); if (substr($url, -11) === '#force_feed') { $feed->force_feed(true); $url = substr($url, 0, -11); @@ -311,6 +335,8 @@ class FreshRSS_Feed extends Minz_Model { public function loadEntries($feed) { $entries = array(); + $guids = array(); + $hasUniqueGuids = true; foreach ($feed->get_items() as $item) { $title = html_only_entity_decode(strip_tags($item->get_title())); @@ -351,9 +377,13 @@ class FreshRSS_Feed extends Minz_Model { } } + $guid = $item->get_id(false, false); + $hasUniqueGuids &= empty($guids['_' . $guid]); + $guids['_' . $guid] = true; + $entry = new FreshRSS_Entry( $this->id(), - $item->get_id(false, false), + $guid, $title === null ? '' : $title, $author === null ? '' : html_only_entity_decode(strip_tags($author->name == null ? $author->email : $author->name)), $content === null ? '' : $content, @@ -368,14 +398,31 @@ class FreshRSS_Feed extends Minz_Model { unset($item); } + $hasBadGuids = $this->attributes('hasBadGuids'); + if ($hasBadGuids != !$hasUniqueGuids) { + $hasBadGuids = !$hasUniqueGuids; + if ($hasBadGuids) { + Minz_Log::warning('Feed has invalid GUIDs: ' . $this->url); + } else { + Minz_Log::warning('Feed has valid GUIDs again: ' . $this->url); + } + $feedDAO = FreshRSS_Factory::createFeedDao(); + $feedDAO->updateFeedAttribute($this, 'hasBadGuids', $hasBadGuids); + } + if (!$hasUniqueGuids) { + foreach ($entries as $entry) { + $entry->_guid(''); + } + } + $this->entries = $entries; } - function cacheModifiedTime() { + public function cacheModifiedTime() { return @filemtime(CACHE_PATH . '/' . md5($this->url) . '.spc'); } - function lock() { + public function lock() { $this->lockPath = TMP_PATH . '/' . $this->hash() . '.freshrss.lock'; if (file_exists($this->lockPath) && ((time() - @filemtime($this->lockPath)) > 3600)) { @unlink($this->lockPath); @@ -388,13 +435,13 @@ class FreshRSS_Feed extends Minz_Model { return true; } - function unlock() { + public function unlock() { @unlink($this->lockPath); } //<PubSubHubbub> - function pubSubHubbubEnabled() { + public function pubSubHubbubEnabled() { $url = $this->selfUrl ? $this->selfUrl : $this->url; $hubFilename = PSHB_PATH . '/feeds/' . base64url_encode($url) . '/!hub.json'; if ($hubFile = @file_get_contents($hubFilename)) { @@ -407,7 +454,7 @@ class FreshRSS_Feed extends Minz_Model { return false; } - function pubSubHubbubError($error = true) { + public function pubSubHubbubError($error = true) { $url = $this->selfUrl ? $this->selfUrl : $this->url; $hubFilename = PSHB_PATH . '/feeds/' . base64url_encode($url) . '/!hub.json'; $hubFile = @file_get_contents($hubFilename); @@ -420,7 +467,7 @@ class FreshRSS_Feed extends Minz_Model { return false; } - function pubSubHubbubPrepare() { + public function pubSubHubbubPrepare() { $key = ''; if (FreshRSS_Context::$system_conf->base_url && $this->hubUrl && $this->selfUrl && @is_dir(PSHB_PATH)) { $path = PSHB_PATH . '/feeds/' . base64url_encode($this->selfUrl); @@ -467,7 +514,7 @@ class FreshRSS_Feed extends Minz_Model { } //Parameter true to subscribe, false to unsubscribe. - function pubSubHubbubSubscribe($state) { + public function pubSubHubbubSubscribe($state) { $url = $this->selfUrl ? $this->selfUrl : $this->url; if (FreshRSS_Context::$system_conf->base_url && $url) { $hubFilename = PSHB_PATH . '/feeds/' . base64url_encode($url) . '/!hub.json'; diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index 0c25ab0ba..9d980c139 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -1,6 +1,33 @@ <?php class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { + + protected function addColumn($name) { + Minz_Log::warning('FreshRSS_FeedDAO::addColumn: ' . $name); + try { + if ($name === 'attributes') { //v1.11.0 + $stm = $this->bd->prepare('ALTER TABLE `' . $this->prefix . 'feed` ADD COLUMN attributes TEXT'); + return $stm && $stm->execute(); + } + } catch (Exception $e) { + Minz_Log::error('FreshRSS_FeedDAO::addColumn error: ' . $e->getMessage()); + } + return false; + } + + protected function autoUpdateDb($errorInfo) { + if (isset($errorInfo[0])) { + if ($errorInfo[0] === '42S22' || $errorInfo[0] === '42703') { //ER_BAD_FIELD_ERROR (Mysql), undefined_column (PostgreSQL) + foreach (array('attributes') as $column) { + if (stripos($errorInfo[2], $column) !== false) { + return $this->addColumn($column); + } + } + } + } + return false; + } + public function addFeed($valuesTmp) { $sql = ' INSERT INTO `' . $this->prefix . 'feed` @@ -15,10 +42,11 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { `httpAuth`, error, keep_history, - ttl + ttl, + attributes ) VALUES - (?, ?, ?, ?, ?, ?, 10, ?, 0, ?, ?)'; + (?, ?, ?, ?, ?, ?, 10, ?, 0, ?, ?, ?)'; $stm = $this->bd->prepare($sql); $valuesTmp['url'] = safe_ascii($valuesTmp['url']); @@ -34,12 +62,16 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { base64_encode($valuesTmp['httpAuth']), FreshRSS_Feed::KEEP_HISTORY_DEFAULT, FreshRSS_Feed::TTL_DEFAULT, + isset($valuesTmp['attributes']) ? json_encode($valuesTmp['attributes']) : '', ); if ($stm && $stm->execute($values)) { return $this->bd->lastInsertId('"' . $this->prefix . 'feed_id_seq"'); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); + if ($this->autoUpdateDb($info)) { + return $this->addFeed($valuesTmp); + } Minz_Log::error('SQL error addFeed: ' . $info[2]); return false; } @@ -60,7 +92,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { 'website' => $feed->website(), 'description' => $feed->description(), 'lastUpdate' => 0, - 'httpAuth' => $feed->httpAuth() + 'httpAuth' => $feed->httpAuth(), + 'attributes' => $feed->attributes(), ); $id = $this->addFeed($values); @@ -87,8 +120,10 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { foreach ($valuesTmp as $key => $v) { $set .= '`' . $key . '`=?, '; - if ($key == 'httpAuth') { + if ($key === 'httpAuth') { $valuesTmp[$key] = base64_encode($v); + } elseif ($key === 'attributes') { + $valuesTmp[$key] = json_encode($v); } } $set = substr($set, 0, -2); @@ -105,11 +140,25 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { return $stm->rowCount(); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); - Minz_Log::error('SQL error updateFeed: ' . $info[2]); + if ($this->autoUpdateDb($info)) { + return $this->updateFeed($id, $valuesTmp); + } + Minz_Log::error('SQL error updateFeed: ' . $info[2] . ' for feed ' . $id); return false; } } + public function updateFeedAttribute($feed, $key, $value) { + if ($feed instanceof FreshRSS_Feed) { + $feed->_attributes($key, $value); + return $this->updateFeed( + $feed->id(), + array('attributes' => $feed->attributes()) + ); + } + return false; + } + public function updateLastUpdate($id, $inError = false, $mtime = 0) { //See also updateCachedValue() $sql = 'UPDATE `' . $this->prefix . 'feed` ' . 'SET `lastUpdate`=?, error=? ' @@ -250,17 +299,25 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { /** * Use $defaultCacheDuration == -1 to return all feeds, without filtering them by TTL. */ - public function listFeedsOrderUpdate($defaultCacheDuration = 3600) { + public function listFeedsOrderUpdate($defaultCacheDuration = 3600, $limit = 0) { $this->updateTTL(); - $sql = 'SELECT id, url, name, website, `lastUpdate`, `pathEntries`, `httpAuth`, keep_history, ttl ' + $sql = 'SELECT id, url, name, website, `lastUpdate`, `pathEntries`, `httpAuth`, keep_history, ttl, attributes ' . 'FROM `' . $this->prefix . 'feed` ' . ($defaultCacheDuration < 0 ? '' : 'WHERE ttl >= ' . FreshRSS_Feed::TTL_DEFAULT . ' AND `lastUpdate` < (' . (time() + 60) . '-(CASE WHEN ttl=' . FreshRSS_Feed::TTL_DEFAULT . ' THEN ' . intval($defaultCacheDuration) . ' ELSE ttl END)) ') - . 'ORDER BY `lastUpdate`'; + . 'ORDER BY `lastUpdate` ' + . ($limit < 1 ? '' : 'LIMIT ' . intval($limit)); $stm = $this->bd->prepare($sql); - $stm->execute(); - - return self::daoToFeed($stm->fetchAll(PDO::FETCH_ASSOC)); + if ($stm && $stm->execute()) { + return self::daoToFeed($stm->fetchAll(PDO::FETCH_ASSOC)); + } else { + $info = $stm == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $stm->errorInfo(); + if ($this->autoUpdateDb($info)) { + return $this->listFeedsOrderUpdate($defaultCacheDuration); + } + Minz_Log::error('SQL error listFeedsOrderUpdate: ' . $info[2]); + return array(); + } } public function listByCategory($cat) { @@ -385,6 +442,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $myFeed->_error(isset($dao['error']) ? $dao['error'] : 0); $myFeed->_keepHistory(isset($dao['keep_history']) ? $dao['keep_history'] : FreshRSS_Feed::KEEP_HISTORY_DEFAULT); $myFeed->_ttl(isset($dao['ttl']) ? $dao['ttl'] : FreshRSS_Feed::TTL_DEFAULT); + $myFeed->_attributes('', isset($dao['attributes']) ? $dao['attributes'] : ''); $myFeed->_nbNotRead(isset($dao['cache_nbUnreads']) ? $dao['cache_nbUnreads'] : 0); $myFeed->_nbEntries(isset($dao['cache_nbEntries']) ? $dao['cache_nbEntries'] : 0); if (isset($dao['id'])) { diff --git a/app/Models/FeedDAOSQLite.php b/app/Models/FeedDAOSQLite.php new file mode 100644 index 000000000..3c203b378 --- /dev/null +++ b/app/Models/FeedDAOSQLite.php @@ -0,0 +1,17 @@ +<?php + +class FreshRSS_FeedDAOSQLite extends FreshRSS_FeedDAO { + + protected function autoUpdateDb($errorInfo) { + if ($tableInfo = $this->bd->query("PRAGMA table_info('feed')")) { + $columns = $tableInfo->fetchAll(PDO::FETCH_COLUMN, 1); + foreach (array('attributes') as $column) { + if (!in_array($column, $columns)) { + return $this->addColumn($column); + } + } + } + return false; + } + +} diff --git a/app/Models/UserQuery.php b/app/Models/UserQuery.php index 52747f538..ef94fdaf6 100644 --- a/app/Models/UserQuery.php +++ b/app/Models/UserQuery.php @@ -41,7 +41,7 @@ class FreshRSS_UserQuery { $query['search'] = ''; } // linked to deeply with the search object, need to use dependency injection - $this->search = new FreshRSS_Search($query['search']); + $this->search = new FreshRSS_BooleanSearch($query['search']); if (isset($query['state'])) { $this->state = $query['state']; } diff --git a/app/SQL/install.sql.mysql.php b/app/SQL/install.sql.mysql.php index b94a24298..747a0a6b3 100644 --- a/app/SQL/install.sql.mysql.php +++ b/app/SQL/install.sql.mysql.php @@ -24,6 +24,7 @@ CREATE TABLE IF NOT EXISTS `%1$sfeed` ( `error` boolean DEFAULT 0, `keep_history` MEDIUMINT NOT NULL DEFAULT -2, -- v0.7 `ttl` INT NOT NULL DEFAULT 0, -- v0.7.3 + `attributes` TEXT, -- v1.11.0 `cache_nbEntries` int DEFAULT 0, -- v0.7 `cache_nbUnreads` int DEFAULT 0, -- v0.7 PRIMARY KEY (`id`), diff --git a/app/SQL/install.sql.pgsql.php b/app/SQL/install.sql.pgsql.php index 23afdb783..b80fbf1e7 100644 --- a/app/SQL/install.sql.pgsql.php +++ b/app/SQL/install.sql.pgsql.php @@ -22,6 +22,7 @@ $SQL_CREATE_TABLES = array( "error" smallint DEFAULT 0, "keep_history" INT NOT NULL DEFAULT -2, "ttl" INT NOT NULL DEFAULT 0, + "attributes" TEXT, -- v1.11.0 "cache_nbEntries" INT DEFAULT 0, "cache_nbUnreads" INT DEFAULT 0, FOREIGN KEY ("category") REFERENCES "%1$scategory" ("id") ON DELETE SET NULL ON UPDATE CASCADE @@ -51,7 +52,7 @@ $SQL_CREATE_TABLES = array( 'CREATE INDEX %1$sis_read_index ON "%1$sentry" ("is_read");', 'CREATE INDEX %1$sentry_lastSeen_index ON "%1$sentry" ("lastSeen");', -'INSERT INTO "%1$scategory" (name) SELECT \'%2$s\' WHERE NOT EXISTS (SELECT id FROM "%1$scategory" WHERE id = 1);', +'INSERT INTO "%1$scategory" (id, name) SELECT 1, \'%2$s\' WHERE NOT EXISTS (SELECT id FROM "%1$scategory" WHERE id = 1) RETURNING nextval(\'%1$scategory_id_seq\');', ); global $SQL_CREATE_TABLE_ENTRYTMP; diff --git a/app/SQL/install.sql.sqlite.php b/app/SQL/install.sql.sqlite.php index d8e670bc8..cbfb719e5 100644 --- a/app/SQL/install.sql.sqlite.php +++ b/app/SQL/install.sql.sqlite.php @@ -21,6 +21,7 @@ $SQL_CREATE_TABLES = array( `error` boolean DEFAULT 0, `keep_history` MEDIUMINT NOT NULL DEFAULT -2, `ttl` INT NOT NULL DEFAULT 0, + `attributes` TEXT, -- v1.11.0 `cache_nbEntries` int DEFAULT 0, `cache_nbUnreads` int DEFAULT 0, FOREIGN KEY (`category`) REFERENCES `category`(`id`) ON DELETE SET NULL ON UPDATE CASCADE, diff --git a/app/actualize_script.php b/app/actualize_script.php index 6f48220a6..ba9660a14 100755 --- a/app/actualize_script.php +++ b/app/actualize_script.php @@ -1,3 +1,4 @@ +#!/usr/bin/php <?php require(__DIR__ . '/../cli/_cli.php'); diff --git a/app/i18n/cz/conf.php b/app/i18n/cz/conf.php index a7bcf6c08..e73ab168f 100644 --- a/app/i18n/cz/conf.php +++ b/app/i18n/cz/conf.php @@ -42,6 +42,7 @@ return array( 'query' => array( '_' => 'Uživatelské dotazy', 'deprecated' => 'Tento dotaz již není platný. Odkazovaná kategorie nebo kanál byly smazány.', + 'display' => 'Display user query results', // TODO 'filter' => 'Filtr aplikován:', 'get_all' => 'Zobrazit všechny články', 'get_category' => 'Zobrazit "%s" kategorii', @@ -52,6 +53,7 @@ return array( 'number' => 'Dotaz n°%d', 'order_asc' => 'Zobrazit nejdříve nejstarší články', 'order_desc' => 'Zobrazit nejdříve nejnovější články', + 'remove' => 'Remove user query', // TODO 'search' => 'Hledat "%s"', 'state_0' => 'Zobrazit všechny články', 'state_1' => 'Zobrazit přečtené články', diff --git a/app/i18n/cz/feedback.php b/app/i18n/cz/feedback.php index 22eaf77f7..ff9c87d12 100644 --- a/app/i18n/cz/feedback.php +++ b/app/i18n/cz/feedback.php @@ -31,11 +31,11 @@ return array( 'extensions' => array( 'already_enabled' => '%s je již zapnut', 'disable' => array( - 'ko' => '%s nelze vypnout. Pro více detailů <a href="%s">zkontrolujte logy FressRSS</a>.', + 'ko' => '%s nelze vypnout. Pro více detailů <a href="%s">zkontrolujte logy FreshRSS</a>.', 'ok' => '%s je nyní vypnut', ), 'enable' => array( - 'ko' => '%s nelze zapnout. Pro více detailů <a href="%s">zkontrolujte logy FressRSS</a>.', + 'ko' => '%s nelze zapnout. Pro více detailů <a href="%s">zkontrolujte logy FreshRSS</a>.', 'ok' => '%s je nyní zapnut', ), 'no_access' => 'Nemáte přístup k %s', @@ -72,7 +72,7 @@ return array( 'already_subscribed' => 'Již jste přihlášen k odběru <em>%s</em>', 'deleted' => 'Kanál byl smazán', 'error' => 'Kanál nelze aktualizovat', - 'internal_problem' => 'RSS kanál nelze přidat. Pro detaily <a href="%s">zkontrolujte logy FressRSS</a>.', + 'internal_problem' => 'RSS kanál nelze přidat. Pro detaily <a href="%s">zkontrolujte logy FreshRSS</a>.', // @todo 'invalid_url' => 'URL <em>%s</em> není platné', 'marked_read' => 'Kanály byly označeny jako přečtené', 'n_actualized' => '%d kanálů bylo aktualizováno', diff --git a/app/i18n/cz/gen.php b/app/i18n/cz/gen.php index 288be61ec..09a8307ff 100644 --- a/app/i18n/cz/gen.php +++ b/app/i18n/cz/gen.php @@ -170,6 +170,7 @@ return array( 'jdh' => 'Journal du hacker', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pocket' => 'Pocket', 'print' => 'Tisk', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', diff --git a/app/i18n/cz/sub.php b/app/i18n/cz/sub.php index ec77be317..5caf9acbe 100644 --- a/app/i18n/cz/sub.php +++ b/app/i18n/cz/sub.php @@ -44,8 +44,10 @@ return array( 'main_stream' => 'Zobrazit ve “Všechny kanály”', 'normal' => 'Show in its category', // TODO ), + 'ssl_verify' => 'Verify SSL security', //TODO 'stats' => 'Statistika', 'think_to_add' => 'Můžete přidat kanály.', + 'timeout' => 'Timeout in seconds', //TODO 'title' => 'Název', 'title_add' => 'Přidat RSS kanál', 'ttl' => 'Neobnovovat častěji než', diff --git a/app/i18n/de/admin.php b/app/i18n/de/admin.php index 45bf2de68..f03e6cdaf 100644 --- a/app/i18n/de/admin.php +++ b/app/i18n/de/admin.php @@ -175,15 +175,15 @@ return array( 'user' => array( 'articles_and_size' => '%s Artikel (%s)', 'create' => 'Neuen Benutzer erstellen', - 'delete_users' => 'Delete user', // TODO + 'delete_users' => 'Lösche Benutzer', 'language' => 'Sprache', 'number' => 'Es wurde bis jetzt %d Account erstellt', 'numbers' => 'Es wurden bis jetzt %d Accounts erstellt', 'password_form' => 'Passwort<br /><small>(für die Anmeldemethode per Webformular)</small>', 'password_format' => 'mindestens 7 Zeichen', - 'selected' => 'Selected user', // TODO + 'selected' => 'Ausgewählter Benutzer', 'title' => 'Benutzer verwalten', - 'update_users' => 'Update user', // TODO + 'update_users' => 'Aktualisiere Benutzer', 'user_list' => 'Liste der Benutzer', 'username' => 'Nutzername', 'users' => 'Benutzer', diff --git a/app/i18n/de/conf.php b/app/i18n/de/conf.php index 6b0d7c7f9..78f3b4510 100644 --- a/app/i18n/de/conf.php +++ b/app/i18n/de/conf.php @@ -37,11 +37,12 @@ return array( 'no_limit' => 'Keine Begrenzung', 'thin' => 'Klein', ), - 'show_nav_buttons' => 'Show the navigation buttons', //TODO + 'show_nav_buttons' => 'Zeige Navigations-Buttons', ), 'query' => array( '_' => 'Benutzerabfragen', 'deprecated' => 'Diese Abfrage ist nicht länger gültig. Die referenzierte Kategorie oder der Feed ist gelöscht worden.', + 'display' => 'Zeige Abfrage Ergebnisse', 'filter' => 'Angewendeter Filter:', 'get_all' => 'Alle Artikel anzeigen', 'get_category' => 'Kategorie "%s" anzeigen', @@ -52,6 +53,7 @@ return array( 'number' => 'Abfrage Nr. %d', 'order_asc' => 'Älteste Artikel zuerst anzeigen', 'order_desc' => 'Neueste Artikel zuerst anzeigen', + 'remove' => 'Lösche Abfrage', 'search' => 'Suche nach "%s"', 'state_0' => 'Alle Artikel anzeigen', 'state_1' => 'Gelesene Artikel anzeigen', @@ -94,7 +96,7 @@ return array( 'display_categories_unfolded' => 'Kategorien standardmäßig eingeklappt zeigen', 'hide_read_feeds' => 'Kategorien & Feeds ohne ungelesene Artikel verstecken (funktioniert nicht mit der Einstellung „Alle Artikel zeigen“)', 'img_with_lazyload' => 'Verwende die "träges Laden"-Methode zum Laden von Bildern', - 'sides_close_article' => 'Clicking outside of article text area closes the article', //TODO + 'sides_close_article' => 'Klick außerhalb des Artikel-Textes schließt den Artikel', 'jump_next' => 'springe zum nächsten ungelesenen Geschwisterelement (Feed oder Kategorie)', 'number_divided_when_reader' => 'Geteilt durch 2 in der Lese-Ansicht.', 'read' => array( @@ -126,7 +128,7 @@ return array( ), 'sharing' => array( '_' => 'Teilen', - 'add' => 'Add a sharing method', // TODO + 'add' => 'Füge eine Teilen-Dienst hinzu', 'blogotext' => 'Blogotext', 'diaspora' => 'Diaspora*', 'email' => 'E-Mail', @@ -134,7 +136,7 @@ return array( 'g+' => 'Google+', 'more_information' => 'Weitere Informationen', 'print' => 'Drucken', - 'remove' => 'Remove sharing method', // TODO + 'remove' => 'Entferne Teilen-Dienst', 'shaarli' => 'Shaarli', 'share_name' => 'Anzuzeigender Teilen-Name', 'share_url' => 'Zu verwendende Teilen-URL', @@ -151,7 +153,7 @@ return array( 'collapse_article' => 'Einklappen', 'first_article' => 'Zum ersten Artikel springen', 'focus_search' => 'Auf das Suchfeld zugreifen', - 'global_view' => 'Switch to global view', // TODO + 'global_view' => 'Wechsle zur globalen Ansicht', 'help' => 'Dokumentation anzeigen', 'javascript' => 'JavaScript muss aktiviert sein, um Tastaturkürzel benutzen zu können', 'last_article' => 'Zum letzten Artikel springen', @@ -161,17 +163,17 @@ return array( 'navigation' => 'Navigation', 'navigation_help' => 'Mit der "Umschalttaste" finden die Tastenkombination auf Feeds Anwendung.<br/>Mit der "Alt-Taste" finden die Tastenkombination auf Kategorien Anwendung.', 'next_article' => 'Zum nächsten Artikel springen', - 'normal_view' => 'Switch to normal view', // TODO + 'normal_view' => 'Wechsle zur normalen Ansicht', 'other_action' => 'Andere Aktionen', 'previous_article' => 'Zum vorherigen Artikel springen', - 'reading_view' => 'Switch to reading view', // TODO - 'rss_view' => 'Open RSS view in a new tab', // TODO + 'reading_view' => 'Wechsle zur Lese-Ansicht', + 'rss_view' => 'Öffne RSS Ansicht in neuem Tab', 'see_on_website' => 'Auf der Original-Webseite ansehen', 'shift_for_all_read' => '+ <code>Umschalttaste</code>, um alle Artikel als gelesen zu markieren.', 'title' => 'Tastenkombination', 'user_filter' => 'Auf Benutzerfilter zugreifen', 'user_filter_help' => 'Wenn es nur einen Benutzerfilter gibt, wird dieser verwendet. Ansonsten sind die Filter über ihre Nummer erreichbar.', - 'views' => 'Views', // TODO + 'views' => 'Ansichten', ), 'user' => array( 'articles_and_size' => '%s Artikel (%s)', diff --git a/app/i18n/de/feedback.php b/app/i18n/de/feedback.php index 0ac6efefc..2c46bbe56 100644 --- a/app/i18n/de/feedback.php +++ b/app/i18n/de/feedback.php @@ -31,11 +31,11 @@ return array( 'extensions' => array( 'already_enabled' => '%s ist bereits aktiviert', 'disable' => array( - 'ko' => '%s kann nicht deaktiviert werden. Für Details <a href="%s">prüfen Sie die FressRSS-Protokolle</a>.', + 'ko' => '%s kann nicht deaktiviert werden. Für Details <a href="%s">prüfen Sie die FreshRSS-Protokolle</a>.', 'ok' => '%s ist jetzt deaktiviert', ), 'enable' => array( - 'ko' => '%s kann nicht aktiviert werden. Für Details <a href="%s">prüfen Sie die FressRSS-Protokolle</a>.', + 'ko' => '%s kann nicht aktiviert werden. Für Details <a href="%s">prüfen Sie die FreshRSS-Protokolle</a>.', 'ok' => '%s ist jetzt aktiviert', ), 'no_access' => 'Sie haben keinen Zugang zu %s', @@ -72,7 +72,7 @@ return array( 'already_subscribed' => 'Sie haben <em>%s</em> bereits abonniert', 'deleted' => 'Der Feed ist gelöscht worden', 'error' => 'Der Feed kann nicht aktualisiert werden', - 'internal_problem' => 'Der RSS-Feed konnte nicht hinzugefügt werden. Für Details <a href="%s">prüfen Sie die FressRSS-Protokolle</a>.', + 'internal_problem' => 'Der RSS-Feed konnte nicht hinzugefügt werden. Für Details <a href="%s">prüfen Sie die FreshRSS-Protokolle</a>.', // @todo 'invalid_url' => 'Die URL <em>%s</em> ist ungültig', 'marked_read' => 'Die Feeds sind als gelesen markiert worden', 'n_actualized' => 'Die %d Feeds sind aktualisiert worden', @@ -102,8 +102,8 @@ return array( 'error' => 'Der Benutzer %s kann nicht gelöscht werden', ), 'updated' => array( - '_' => 'User %s has been updated', // TODO - 'error' => 'User %s has not been updated', // TODO + '_' => 'Benutzer %s wurde aktualisiert', + 'error' => 'Benutzer %s wurde nicht aktualisiert', ), ), 'profile' => array( diff --git a/app/i18n/de/gen.php b/app/i18n/de/gen.php index 8df0b1f07..7dbaac384 100644 --- a/app/i18n/de/gen.php +++ b/app/i18n/de/gen.php @@ -19,7 +19,7 @@ return array( 'see_website' => 'Webseite ansehen', 'submit' => 'Abschicken', 'truncate' => 'Alle Artikel löschen', - 'update' => 'Update', // TODO + 'update' => 'Aktualisieren', ), 'auth' => array( 'email' => 'E-Mail-Adresse', @@ -169,6 +169,7 @@ return array( 'jdh' => 'Journal du hacker', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pocket' => 'Pocket', 'print' => 'Drucken', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', diff --git a/app/i18n/de/sub.php b/app/i18n/de/sub.php index 6d41d0e5a..0ba818c69 100644 --- a/app/i18n/de/sub.php +++ b/app/i18n/de/sub.php @@ -2,13 +2,13 @@ return array( 'api' => array( - 'documentation' => 'Copy the following URL to use it within an external tool.',// TODO - 'title' => 'API',// TODO + 'documentation' => 'Kopieren Sie die folgende URL, um sie in einem externen Tool zu verwenden.', + 'title' => 'API', ), 'bookmarklet' => array( - 'documentation' => 'Drag this button to your bookmarks toolbar or right-click it and choose "Bookmark This Link". Then click "Subscribe" button in any page you want to subscribe to.',// TODO - 'label' => 'Subscribe',// TODO - 'title' => 'Bookmarklet',// TODO + 'documentation' => 'Ziehen Sie diese Schaltfläche auf Ihre Lesezeichen-Symbolleiste oder klicken Sie mit der rechten Maustaste darauf und wählen Sie "Als Lesezeichen hinzufügen". Klicken Sie dann auf einer beliebigen Seite, die Sie abonnieren möchten, auf die Schaltfläche "Abonnieren".', + 'label' => 'Abonnieren', + 'title' => 'Bookmarklet', ), 'category' => array( '_' => 'Kategorie', @@ -35,17 +35,19 @@ return array( 'informations' => 'Information', 'keep_history' => 'Minimale Anzahl an Artikeln, die behalten wird', 'moved_category_deleted' => 'Wenn Sie eine Kategorie entfernen, werden deren Feeds automatisch in die Kategorie <em>%s</em> eingefügt.', - 'mute' => 'mute', // TODO + 'mute' => 'Stumm schalten', 'no_selected' => 'Kein Feed ausgewählt.', 'number_entries' => '%d Artikel', 'priority' => array( - '_' => 'Visibility', // TODO - 'archived' => 'Do not show (archived)', // TODO + '_' => 'Sichtbarkeit', + 'archived' => 'Nicht anzeigen (archiviert)', 'main_stream' => 'In Haupt-Feeds zeigen', - 'normal' => 'Show in its category', // TODO + 'normal' => 'Zeige in eigener Kategorie', ), + 'ssl_verify' => 'Verify SSL security', //TODO 'stats' => 'Statistiken', 'think_to_add' => 'Sie können Feeds hinzufügen.', + 'timeout' => 'Timeout in seconds', //TODO 'title' => 'Titel', 'title_add' => 'Einen RSS-Feed hinzufügen', 'ttl' => 'Aktualisiere automatisch nicht öfter als', @@ -55,8 +57,8 @@ return array( 'pubsubhubbub' => 'Sofortbenachrichtigung mit PubSubHubbub', ), 'firefox' => array( - 'documentation' => 'Follow the steps described <a href="https://developer.mozilla.org/en-US/Firefox/Releases/2/Adding_feed_readers_to_Firefox#Adding_a_new_feed_reader_manually">here</a> to add FreshRSS to Firefox feed reader list.',// TODO - 'title' => 'Firefox feed reader',// TODO + 'documentation' => 'Folge den <a href="https://developer.mozilla.org/en-US/Firefox/Releases/2/Adding_feed_readers_to_Firefox#Adding_a_new_feed_reader_manually">hier</a> beschriebenen Schritten um FreshRSS zu Deiner Firefox RSS-Reader Liste hinzuzufügen.', + 'title' => 'Firefox RSS-Reader', ), 'import_export' => array( 'export' => 'Exportieren', @@ -73,11 +75,11 @@ return array( 'bookmark' => 'Abonnieren (FreshRSS-Lesezeichen)', 'import_export' => 'Importieren / Exportieren', 'subscription_management' => 'Abonnementverwaltung', - 'subscription_tools' => 'Subscription tools',// TODO + 'subscription_tools' => 'Abonnement-Tools', ), 'title' => array( '_' => 'Abonnementverwaltung', 'feed_management' => 'Verwaltung der RSS-Feeds', - 'subscription_tools' => 'Subscription tools',// TODO + 'subscription_tools' => 'Abonnement-Tools', ), ); diff --git a/app/i18n/en/conf.php b/app/i18n/en/conf.php index a1c3fc949..fd91ed8f6 100644 --- a/app/i18n/en/conf.php +++ b/app/i18n/en/conf.php @@ -42,6 +42,7 @@ return array( 'query' => array( '_' => 'User queries', 'deprecated' => 'This query is no longer valid. The referenced category or feed has been deleted.', + 'display' => 'Display user query results', 'filter' => 'Filter applied:', 'get_all' => 'Display all articles', 'get_category' => 'Display "%s" category', @@ -52,6 +53,7 @@ return array( 'number' => 'Query n°%d', 'order_asc' => 'Display oldest articles first', 'order_desc' => 'Display newest articles first', + 'remove' => 'Remove user query', 'search' => 'Search for "%s"', 'state_0' => 'Display all articles', 'state_1' => 'Display read articles', @@ -169,8 +171,8 @@ return array( 'see_on_website' => 'See on original website', 'shift_for_all_read' => '+ <code>shift</code> to mark all articles as read', 'title' => 'Shortcuts', - 'user_filter' => 'Access user filters', - 'user_filter_help' => 'If there is only one user filter, it is used. Otherwise, filters are accessible by their number.', + 'user_filter' => 'Access user queries', + 'user_filter_help' => 'If there is only one user query, it is used. Otherwise, queries are accessible by their number.', 'views' => 'Views', ), 'user' => array( diff --git a/app/i18n/en/feedback.php b/app/i18n/en/feedback.php index ad7f87fd9..a7fbda3a0 100644 --- a/app/i18n/en/feedback.php +++ b/app/i18n/en/feedback.php @@ -31,11 +31,11 @@ return array( 'extensions' => array( 'already_enabled' => '%s is already enabled', 'disable' => array( - 'ko' => '%s cannot be disabled. <a href="%s">Check FressRSS logs</a> for details.', + 'ko' => '%s cannot be disabled. <a href="%s">Check FreshRSS logs</a> for details.', 'ok' => '%s is now disabled', ), 'enable' => array( - 'ko' => '%s cannot be enabled. <a href="%s">Check FressRSS logs</a> for details.', + 'ko' => '%s cannot be enabled. <a href="%s">Check FreshRSS logs</a> for details.', 'ok' => '%s is now enabled', ), 'no_access' => 'You have no access on %s', @@ -72,7 +72,7 @@ return array( 'already_subscribed' => 'You have already subscribed to <em>%s</em>', 'deleted' => 'Feed has been deleted', 'error' => 'Feed cannot be updated', - 'internal_problem' => 'The RSS feed could not be added. <a href="%s">Check FressRSS logs</a> for details.', + 'internal_problem' => 'The newsfeed could not be added. <a href="%s">Check FreshRSS logs</a> for details. You can try force adding by appending <code>#force_feed</code> to the URL.', 'invalid_url' => 'URL <em>%s</em> is invalid', 'marked_read' => 'Feeds have been marked as read', 'n_actualized' => '%d feeds have been updated', diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index 82cd4da72..ceee25105 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -170,6 +170,7 @@ return array( 'Known' => 'Known based sites', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pocket' => 'Pocket', 'print' => 'Print', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', diff --git a/app/i18n/en/sub.php b/app/i18n/en/sub.php index b9bae7955..5ff41a4b3 100644 --- a/app/i18n/en/sub.php +++ b/app/i18n/en/sub.php @@ -44,8 +44,10 @@ return array( 'main_stream' => 'Show in main stream', 'normal' => 'Show in its category', ), + 'ssl_verify' => 'Verify SSL security', 'stats' => 'Statistics', 'think_to_add' => 'You may add some feeds.', + 'timeout' => 'Timeout in seconds', 'title' => 'Title', 'title_add' => 'Add a RSS feed', 'ttl' => 'Do not automatically refresh more often than', diff --git a/app/i18n/es/conf.php b/app/i18n/es/conf.php index 464bebc4f..0e198caf8 100755 --- a/app/i18n/es/conf.php +++ b/app/i18n/es/conf.php @@ -42,6 +42,7 @@ return array( 'query' => array( '_' => 'Consultas de usuario', 'deprecated' => 'Esta consulta ya no es válida. La categoría referenciada o fuente ha sido eliminada.', + 'display' => 'Display user query results', // TODO 'filter' => 'Filtro aplicado:', 'get_all' => 'Mostrar todos los artículos', 'get_category' => 'Mostrar la categoría "%s"', @@ -52,6 +53,7 @@ return array( 'number' => 'Consulta n° %d', 'order_asc' => 'Mostrar primero los artículos más antiguos', 'order_desc' => 'Mostrar primero los artículos más recientes', + 'remove' => 'Remove user query', // TODO 'search' => 'Buscar "%s"', 'state_0' => 'Mostrar todos los artículos', 'state_1' => 'Mostrar artículos leídos', diff --git a/app/i18n/es/feedback.php b/app/i18n/es/feedback.php index 7b23f1a8d..627c86afc 100755 --- a/app/i18n/es/feedback.php +++ b/app/i18n/es/feedback.php @@ -31,11 +31,11 @@ return array( 'extensions' => array( 'already_enabled' => '%s ya está activado', 'disable' => array( - 'ko' => '%s no se puede desactivar. <a href="%s">Revisa el registro de FressRSS</a> para más información.', + 'ko' => '%s no se puede desactivar. <a href="%s">Revisa el registro de FreshRSS</a> para más información.', 'ok' => '%s ha quedado desactivado', ), 'enable' => array( - 'ko' => '%s no se puede activar. <a href="%s">Revisa el registro de FressRSS</a> para más información.', + 'ko' => '%s no se puede activar. <a href="%s">Revisa el registro de FreshRSS</a> para más información.', 'ok' => '%s ha quedado activado', ), 'no_access' => 'No tienes acceso a %s', @@ -72,7 +72,7 @@ return array( 'already_subscribed' => 'Ya estás suscrito a <em>%s</em>', 'deleted' => 'Fuente eliminada', 'error' => 'No es posible actualizar la fuente', - 'internal_problem' => 'No ha sido posible agregar la fuente RSS. <a href="%s">Revisa el registro de FressRSS </a> para más información.', + 'internal_problem' => 'No ha sido posible agregar la fuente RSS. <a href="%s">Revisa el registro de FreshRSS </a> para más información.', // @todo 'invalid_url' => 'La URL <em>%s</em> es inválida', 'marked_read' => 'Fuentes marcadas como leídas', 'n_actualized' => 'Se han actualiado %d fuentes', diff --git a/app/i18n/es/gen.php b/app/i18n/es/gen.php index fe495a63f..a5957e12f 100755 --- a/app/i18n/es/gen.php +++ b/app/i18n/es/gen.php @@ -170,6 +170,7 @@ return array( 'jdh' => 'Journal du hacker', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pocket' => 'Pocket', 'print' => 'Print', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', diff --git a/app/i18n/es/sub.php b/app/i18n/es/sub.php index 091c1e3e3..3abc85578 100755 --- a/app/i18n/es/sub.php +++ b/app/i18n/es/sub.php @@ -39,8 +39,10 @@ return array( 'main_stream' => 'Mostrar en salida principal', 'normal' => 'Show in its category', // TODO ), + 'ssl_verify' => 'Verify SSL security', //TODO 'stats' => 'Estadísticas', 'think_to_add' => 'Puedes añadir fuentes.', + 'timeout' => 'Timeout in seconds', //TODO 'title' => 'Título', 'title_add' => 'Añadir fuente RSS', 'ttl' => 'No actualizar de forma automática con una frecuencia mayor a', diff --git a/app/i18n/fr/conf.php b/app/i18n/fr/conf.php index 402a97b1c..52b2f7e0d 100644 --- a/app/i18n/fr/conf.php +++ b/app/i18n/fr/conf.php @@ -42,6 +42,7 @@ return array( 'query' => array( '_' => 'Filtres utilisateurs', 'deprecated' => 'Ce filtre n’est plus valide. La catégorie ou le flux concerné a été supprimé.', + 'display' => 'Afficher les résultats du filtre', 'filter' => 'Filtres appliqués :', 'get_all' => 'Afficher tous les articles', 'get_category' => 'Afficher la catégorie "%s"', @@ -52,6 +53,7 @@ return array( 'number' => 'Filtre n°%d', 'order_asc' => 'Afficher les articles les plus anciens en premier', 'order_desc' => 'Afficher les articles les plus récents en premier', + 'remove' => 'Supprimer le filtre', 'search' => 'Recherche de "%s"', 'state_0' => 'Afficher tous les articles', 'state_1' => 'Afficher les articles lus', diff --git a/app/i18n/fr/feedback.php b/app/i18n/fr/feedback.php index 1abf1b518..2443ad30a 100644 --- a/app/i18n/fr/feedback.php +++ b/app/i18n/fr/feedback.php @@ -72,7 +72,7 @@ return array( 'already_subscribed' => 'Vous êtes déjà abonné à <em>%s</em>', 'deleted' => 'Le flux a été supprimé.', 'error' => 'Une erreur est survenue', - 'internal_problem' => 'Le flux ne peut pas être ajouté. <a href="%s">Consulter les logs de FreshRSS</a> pour plus de détails.', + 'internal_problem' => 'Le flux ne peut pas être ajouté. <a href="%s">Consulter les logs de FreshRSS</a> pour plus de détails. Vous pouvez essayer de forcer l’ajout par addition de <code>#force_feed</code> à l’URL.', 'invalid_url' => 'L’url <em>%s</em> est invalide.', 'marked_read' => 'Les flux ont été marqués comme lus.', 'n_actualized' => '%d flux ont été mis à jour.', diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php index beb578543..24c4b82fb 100644 --- a/app/i18n/fr/gen.php +++ b/app/i18n/fr/gen.php @@ -170,6 +170,7 @@ return array( 'jdh' => 'Journal du hacker', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pocket' => 'Pocket', 'print' => 'Imprimer', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', diff --git a/app/i18n/fr/sub.php b/app/i18n/fr/sub.php index 04be55aa5..c6af2fb90 100644 --- a/app/i18n/fr/sub.php +++ b/app/i18n/fr/sub.php @@ -44,8 +44,10 @@ return array( 'main_stream' => 'Afficher dans le flux principal', 'normal' => 'Afficher dans sa catégorie', ), + 'ssl_verify' => 'Vérification sécurité SSL', 'stats' => 'Statistiques', 'think_to_add' => 'Vous pouvez ajouter des flux.', + 'timeout' => 'Délai d’attente en secondes', 'title' => 'Titre', 'title_add' => 'Ajouter un flux RSS', 'ttl' => 'Ne pas automatiquement rafraîchir plus souvent que', diff --git a/app/i18n/he/conf.php b/app/i18n/he/conf.php index 3d0534fdc..a682461a6 100644 --- a/app/i18n/he/conf.php +++ b/app/i18n/he/conf.php @@ -42,6 +42,7 @@ return array( 'query' => array( '_' => 'שאילתות', 'deprecated' => 'שאילתה זו אינה בתוקף יותר, הפיד או הקטגוריה לייחוס נמחקו.', + 'display' => 'Display user query results', // TODO 'filter' => 'מסננים בשימוש:', 'get_all' => 'הצגת כל המאמרים', 'get_category' => 'הצגת קטגוריה "%s"', @@ -52,6 +53,7 @@ return array( 'number' => 'שאילתה מספר °%d', 'order_asc' => 'הצגת מאמרים ישנים בראש', 'order_desc' => 'הצגת מאמרים חדשים בראש', + 'remove' => 'Remove user query', // TODO 'search' => 'חיפוש "%s"', 'state_0' => 'הצגת כל המאמרים', 'state_1' => 'הצגת מאמרים שנקראו', diff --git a/app/i18n/he/feedback.php b/app/i18n/he/feedback.php index f773ff270..4b79b0d45 100644 --- a/app/i18n/he/feedback.php +++ b/app/i18n/he/feedback.php @@ -32,11 +32,11 @@ return array( 'extensions' => array( 'already_enabled' => '%s is already enabled', // @todo 'disable' => array( - 'ko' => '%s cannot be disabled. <a href="%s">Check FressRSS logs</a> for details.', // @todo + 'ko' => '%s cannot be disabled. <a href="%s">Check FreshRSS logs</a> for details.', // @todo 'ok' => '%s is now disabled', // @todo ), 'enable' => array( - 'ko' => '%s cannot be enabled. <a href="%s">Check FressRSS logs</a> for details.', // @todo + 'ko' => '%s cannot be enabled. <a href="%s">Check FreshRSS logs</a> for details.', // @todo 'ok' => '%s is now enabled', // @todo ), 'no_access' => 'You have no access on %s', // @todo @@ -73,7 +73,7 @@ return array( 'already_subscribed' => 'אתה כבר רשום ל <em>%s</em>', 'deleted' => 'ההזנה נמחקה', 'error' => 'Feed cannot be updated', // @todo - 'internal_problem' => 'אין אפשרות להוסיף את ההזנה. <a href="%s">בדקו את הלוגים</a> לפרטים.', + 'internal_problem' => 'אין אפשרות להוסיף את ההזנה. <a href="%s">בדקו את הלוגים</a> לפרטים.', // @todo 'invalid_url' => 'URL <em>%s</em> אינו תקין', 'marked_read' => 'הזנות סומנו כנקראו', 'n_actualized' => '%d הזנות עודכנו', diff --git a/app/i18n/he/gen.php b/app/i18n/he/gen.php index c4262ab66..401e13620 100644 --- a/app/i18n/he/gen.php +++ b/app/i18n/he/gen.php @@ -170,6 +170,7 @@ return array( 'Known' => 'Known based sites', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pocket' => 'Pocket', 'print' => 'הדפסה', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', diff --git a/app/i18n/he/sub.php b/app/i18n/he/sub.php index 849a1d5bd..a263cd728 100644 --- a/app/i18n/he/sub.php +++ b/app/i18n/he/sub.php @@ -44,8 +44,10 @@ return array( 'main_stream' => 'הצגה בזרם המרכזי', 'normal' => 'Show in its category', // TODO ), + 'ssl_verify' => 'Verify SSL security', //TODO 'stats' => 'סטטיסטיקות', 'think_to_add' => 'ניתן להוסיף הזנות חדשות.', + 'timeout' => 'Timeout in seconds', //TODO 'title' => 'כותרת', 'title_add' => 'הוספת הזנה', 'ttl' => 'אין לרענן אוטומטית יותר מ', diff --git a/app/i18n/it/conf.php b/app/i18n/it/conf.php index 5ab343c4d..65b979c51 100644 --- a/app/i18n/it/conf.php +++ b/app/i18n/it/conf.php @@ -42,6 +42,7 @@ return array( 'query' => array( '_' => 'Ricerche personali', 'deprecated' => 'Questa query non è più valida. La categoria o il feed di riferimento non stati cancellati.', + 'display' => 'Display user query results', // TODO 'filter' => 'Filtro applicato:', 'get_all' => 'Mostra tutti gli articoli', 'get_category' => 'Mostra la categoria "%s" ', @@ -52,6 +53,7 @@ return array( 'number' => 'Ricerca n°%d', 'order_asc' => 'Mostra prima gli articoli più vecchi', 'order_desc' => 'Mostra prima gli articoli più nuovi', + 'remove' => 'Remove user query', // TODO 'search' => 'Cerca per "%s"', 'state_0' => 'Mostra tutti gli articoli', 'state_1' => 'Mostra gli articoli letti', diff --git a/app/i18n/it/feedback.php b/app/i18n/it/feedback.php index d702eb448..934666aa5 100644 --- a/app/i18n/it/feedback.php +++ b/app/i18n/it/feedback.php @@ -72,7 +72,7 @@ return array( 'already_subscribed' => 'Hai già sottoscritto <em>%s</em>', 'deleted' => 'Feed cancellato', 'error' => 'Feed non aggiornato', - 'internal_problem' => 'RSS feed non aggiunto. <a href="%s">Verifica i logs</a> per dettagli.', + 'internal_problem' => 'RSS feed non aggiunto. <a href="%s">Verifica i logs</a> per dettagli.', // @todo 'invalid_url' => 'URL <em>%s</em> non valido', 'marked_read' => 'Feeds segnati come letti', 'n_actualized' => '%d feeds aggiornati', diff --git a/app/i18n/it/gen.php b/app/i18n/it/gen.php index d4f83735a..b2e007bce 100644 --- a/app/i18n/it/gen.php +++ b/app/i18n/it/gen.php @@ -170,6 +170,7 @@ return array( 'jdh' => 'Journal du hacker', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pocket' => 'Pocket', 'print' => 'Stampa', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', diff --git a/app/i18n/it/sub.php b/app/i18n/it/sub.php index 698e64481..22d58a27f 100644 --- a/app/i18n/it/sub.php +++ b/app/i18n/it/sub.php @@ -44,8 +44,10 @@ return array( 'main_stream' => 'Mostra in homepage', // TODO 'normal' => 'Show in its category', // TODO ), + 'ssl_verify' => 'Verify SSL security', //TODO 'stats' => 'Statistiche', 'think_to_add' => 'Aggiungi feed.', + 'timeout' => 'Timeout in seconds', //TODO 'title' => 'Titolo', 'title_add' => 'Aggiungi RSS feed', 'ttl' => 'Non aggiornare automaticamente piu di', diff --git a/app/i18n/kr/conf.php b/app/i18n/kr/conf.php index c9e91a804..558505973 100644 --- a/app/i18n/kr/conf.php +++ b/app/i18n/kr/conf.php @@ -42,6 +42,7 @@ return array( 'query' => array( '_' => '사용자 쿼리', 'deprecated' => '이 쿼리는 더 이상 유효하지 않습니다. 해당하는 카테고리나 피드가 삭제되었습니다.', + 'display' => 'Display user query results', // TODO 'filter' => '적용된 필터:', 'get_all' => '모든 글 표시', 'get_category' => '"%s" 카테고리 표시', @@ -52,6 +53,7 @@ return array( 'number' => '쿼리 #%d', 'order_asc' => '오래된 글 먼저 표시', 'order_desc' => '최근 글 먼저 표시', + 'remove' => 'Remove user query', // TODO 'search' => '"%s"의 검색 결과', 'state_0' => '모든 글 표시', 'state_1' => '읽은 글 표시', diff --git a/app/i18n/kr/feedback.php b/app/i18n/kr/feedback.php index bccf1aac0..f13675778 100644 --- a/app/i18n/kr/feedback.php +++ b/app/i18n/kr/feedback.php @@ -31,11 +31,11 @@ return array( 'extensions' => array( 'already_enabled' => '%s 확장 기능은 이미 활성화되어 있습니다', 'disable' => array( - 'ko' => '%s 확장 기능을 비활성화 할 수 없습니다. 자세한 내용은 <a href="%s">FressRSS 로그</a>를 참고하세요.', + 'ko' => '%s 확장 기능을 비활성화 할 수 없습니다. 자세한 내용은 <a href="%s">FreshRSS 로그</a>를 참고하세요.', 'ok' => '%s 확장 기능이 비활성화되었습니다', ), 'enable' => array( - 'ko' => '%s 확장 기능을 활성화 할 수 없습니다. 자세한 내용은 <a href="%s">FressRSS 로그</a>를 참고하세요.', + 'ko' => '%s 확장 기능을 활성화 할 수 없습니다. 자세한 내용은 <a href="%s">FreshRSS 로그</a>를 참고하세요.', 'ok' => '%s 확장 기능이 활성화되었습니다', ), 'no_access' => '%s 확장 기능에 접근 권한이 없습니다', @@ -72,7 +72,7 @@ return array( 'already_subscribed' => '이미 <em>%s</em> 피드를 구독 중입니다', 'deleted' => '피드가 삭제되었습니다', 'error' => '피드를 변경할 수 없습니다', - 'internal_problem' => 'RSS 피드를 추가할 수 없습니다. 자세한 내용은 <a href="%s">FressRSS 로그</a>를 참고하세요.', + 'internal_problem' => 'RSS 피드를 추가할 수 없습니다. 자세한 내용은 <a href="%s">FreshRSS 로그</a>를 참고하세요.', // @todo 'invalid_url' => 'URL (<em>%s</em>)이 유효하지 않습니다', 'marked_read' => '피드가 읽음으로 표시되었습니다', 'n_actualized' => '%d 개의 피드에서 새 글을 가져왔습니다', diff --git a/app/i18n/kr/gen.php b/app/i18n/kr/gen.php index 4fb6c92ff..b40ab14c4 100644 --- a/app/i18n/kr/gen.php +++ b/app/i18n/kr/gen.php @@ -170,6 +170,7 @@ return array( 'jdh' => 'Journal du hacker', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pocket' => 'Pocket', 'print' => '인쇄', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', diff --git a/app/i18n/kr/sub.php b/app/i18n/kr/sub.php index e11d4588f..464b64f70 100644 --- a/app/i18n/kr/sub.php +++ b/app/i18n/kr/sub.php @@ -44,8 +44,10 @@ return array( 'main_stream' => '메인 스트림에 표시하기', 'normal' => '피드가 속한 카테고리에만 표시하기', ), + 'ssl_verify' => 'Verify SSL security', //TODO 'stats' => '통계', 'think_to_add' => '피드를 추가할 수 있습니다.', + 'timeout' => 'Timeout in seconds', //TODO 'title' => '제목', 'title_add' => 'RSS 피드 추가', 'ttl' => '다음 시간이 지나기 전에 새로고침 금지', diff --git a/app/i18n/nl/admin.php b/app/i18n/nl/admin.php index cbdfd6978..a1d975305 100644 --- a/app/i18n/nl/admin.php +++ b/app/i18n/nl/admin.php @@ -175,7 +175,7 @@ return array( 'user' => array( 'articles_and_size' => '%s artikelen (%s)', 'create' => 'Creëer nieuwe gebruiker', - 'delete_users' => 'Delete user', // TODO + 'delete_users' => 'Verwijder gebruiker', 'language' => 'Taal', 'number' => 'Er is %d accounts gemaakt', 'numbers' => 'Er zijn %d accounts gemaakt', @@ -186,9 +186,9 @@ return array( 'help' => '0 betekent dat er geen accountlimiet is', 'number' => 'Max aantal accounts', ), - 'selected' => 'Selected user', // TODO + 'selected' => 'Geselecteerde gebruiker', 'title' => 'Beheer gebruikers', - 'update_users' => 'Update user', // TODO + 'update_users' => 'Gebruiker bijwerken', 'user_list' => 'Lijst van gebruikers ', 'username' => 'Gebruikersnaam', 'users' => 'Gebruikers', diff --git a/app/i18n/nl/conf.php b/app/i18n/nl/conf.php index 847c735d1..041b482b9 100644 --- a/app/i18n/nl/conf.php +++ b/app/i18n/nl/conf.php @@ -37,11 +37,12 @@ return array( 'no_limit' => 'Geen limiet', 'thin' => 'Smal', ), - 'show_nav_buttons' => 'Show the navigation buttons', //TODO + 'show_nav_buttons' => 'Toon navigatieknoppen', ), 'query' => array( - '_' => 'Gebruikers queries (informatie aanvragen)', + '_' => 'Gebruikersquery\'s (informatie aanvragen)', 'deprecated' => 'Deze query (informatie aanvraag) is niet langer geldig. De bedoelde categorie of feed is al verwijderd.', + 'display' => 'Queryresultaten weergeven', 'filter' => 'Filter toegepast:', 'get_all' => 'Toon alle artikelen', 'get_category' => 'Toon "%s" categorie', @@ -52,6 +53,7 @@ return array( 'number' => 'Query n°%d', 'order_asc' => 'Toon oudste artikelen eerst', 'order_desc' => 'Toon nieuwste artikelen eerst', + 'remove' => 'Gebruikersquery verwijderen', 'search' => 'Zoek naar "%s"', 'state_0' => 'Toon alle artikelen', 'state_1' => 'Toon gelezen artikelen', @@ -69,7 +71,7 @@ return array( 'state_13' => 'Toon gelezen artikelen', 'state_14' => 'Toon ongelezen artikelen', 'state_15' => 'Toon alle artikelen', - 'title' => 'Gebruikers queries', + 'title' => 'Gebruikersquery\'s', ), 'profile' => array( '_' => 'Profiel beheer', @@ -126,7 +128,7 @@ return array( ), 'sharing' => array( '_' => 'Delen', - 'add' => 'Add a sharing method', // TODO + 'add' => 'Deelmethode toevoegen', 'blogotext' => 'Blogotext', 'diaspora' => 'Diaspora*', 'email' => 'Email', @@ -134,7 +136,7 @@ return array( 'g+' => 'Google+', 'more_information' => 'Meer informatie', 'print' => 'Afdrukken', - 'remove' => 'Remove sharing method', // TODO + 'remove' => 'Deelmethode verwijderen', 'shaarli' => 'Shaarli', 'share_name' => 'Gedeelde naam om weer te geven', 'share_url' => 'Deel URL voor gebruik', @@ -146,12 +148,12 @@ return array( '_' => 'Shortcuts', 'article_action' => 'Artikel acties', 'auto_share' => 'Delen', - 'auto_share_help' => 'Als er slechts één deel methode i, dan wordt deze gebruikt. Anders zijn ze toegankelijk met hun nummer.', + 'auto_share_help' => 'Als er slechts één deelmethode is, dan wordt die gebruikt. Anders zijn ze toegankelijk met hun nummer.', 'close_dropdown' => 'Sluit menu', 'collapse_article' => 'Inklappen', 'first_article' => 'Spring naar eerste artikel', 'focus_search' => 'Toegang zoek venster', - 'global_view' => 'Switch to global view', // TODO + 'global_view' => 'Schakel naar globaal aanzicht', 'help' => 'Toon documentatie', 'javascript' => 'JavaScript moet geactiveerd zijn om verwijzingen te gebruiken', 'last_article' => 'Spring naar laatste artikel', @@ -161,17 +163,17 @@ return array( 'navigation' => 'Navigatie', 'navigation_help' => 'Met de "Shift" toets, kunt u navigatie verwijzingen voor feeds gebruiken.<br/>Met de "Alt" toets, kunt u navigatie verwijzingen voor categoriën gebruiken.', 'next_article' => 'Spring naar volgende artikel', - 'normal_view' => 'Switch to normal view', // TODO + 'normal_view' => 'Schakel naar gewoon aanzicht', 'other_action' => 'Andere acties', 'previous_article' => 'Spring naar vorige artikel', - 'reading_view' => 'Switch to reading view', // TODO - 'rss_view' => 'Open RSS view in a new tab', // TODO + 'reading_view' => 'Schakel naar leesaanzicht', + 'rss_view' => 'Open RSS-aanzicht in een nieuwe tab', 'see_on_website' => 'Bekijk op originale website', 'shift_for_all_read' => '+ <code>shift</code> om alle artikelen als gelezen te markeren', 'title' => 'Verwijzingen', 'user_filter' => 'Toegang gebruikers filters', - 'user_filter_help' => 'Als er slechts één gebruikers filter s, dan wordt deze gebruikt. Anders zijn ze toegankelijk met hun nummer.', - 'views' => 'Views', // TODO + 'user_filter_help' => 'Als er slechts één gebruikersfilter is, dan wordt die gebruikt. Anders zijn ze toegankelijk met hun nummer.', + 'views' => 'Aanzichten', ), 'user' => array( 'articles_and_size' => '%s artikelen (%s)', diff --git a/app/i18n/nl/feedback.php b/app/i18n/nl/feedback.php index 3fabc97b8..e73f2f7bd 100644 --- a/app/i18n/nl/feedback.php +++ b/app/i18n/nl/feedback.php @@ -31,11 +31,11 @@ return array( 'extensions' => array( 'already_enabled' => '%s is al ingeschakeld', 'disable' => array( - 'ko' => '%s kan niet worden uitgeschakeld. <a href="%s">Controleer FressRSS log bestanden</a> voor details.', + 'ko' => '%s kan niet worden uitgeschakeld. <a href="%s">Controleer FreshRSS log bestanden</a> voor details.', 'ok' => '%s is nu uitgeschakeld', ), 'enable' => array( - 'ko' => '%s kan niet worden ingeschakeld. <a href="%s">Controleer FressRSS log bestanden</a> voor details.', + 'ko' => '%s kan niet worden ingeschakeld. <a href="%s">Controleer FreshRSS log bestanden</a> voor details.', 'ok' => '%s is nn ingeschakeld', ), 'no_access' => 'U hebt geen toegang voor %s', @@ -72,7 +72,7 @@ return array( 'already_subscribed' => 'U bent al geabonneerd op <em>%s</em>', 'deleted' => 'Feed is verwijderd', 'error' => 'Feed kan niet worden vernieuwd', - 'internal_problem' => 'De RSS feed kon niet worden toegevoegd. <a href="%s">Controleer FressRSS log bestanden</a> voor details.', + 'internal_problem' => 'De feed kon niet worden toegevoegd. <a href="%s">Controleer de FreshRSS-logbestanden</a> voor details. Toevoegen forceren kan worden geprobeerd door <code>#force_feed</code> aan de URL toe te voegen.', 'invalid_url' => 'URL <em>%s</em> is ongeldig', 'marked_read' => 'Feeds zijn gemarkeerd als gelezen', 'n_actualized' => '%d feeds zijn vernieuwd', @@ -102,8 +102,8 @@ return array( 'error' => 'Gebruiker %s kan niet worden verwijderd', ), 'updated' => array( - '_' => 'User %s has been updated', // TODO - 'error' => 'User %s has not been updated', // TODO + '_' => 'Gebruiker %s is bijgewerkt', + 'error' => 'Gebruiker %s kan niet worden bijgewerkt', ), 'set_registration' => 'Het maximale aantal accounts is vernieuwd.', ), diff --git a/app/i18n/nl/gen.php b/app/i18n/nl/gen.php index ea3e720b4..683209cb9 100644 --- a/app/i18n/nl/gen.php +++ b/app/i18n/nl/gen.php @@ -19,7 +19,7 @@ return array( 'see_website' => 'Bekijk website', 'submit' => 'Opslaan', 'truncate' => 'Verwijder alle artikelen', - 'update' => 'Update', // TODO + 'update' => 'Updaten', ), 'auth' => array( 'email' => 'Email adres', @@ -170,6 +170,7 @@ return array( 'jdh' => 'Journal du hacker', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pocket' => 'Pocket', 'print' => 'Print', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', diff --git a/app/i18n/nl/sub.php b/app/i18n/nl/sub.php index 6b1ac268b..4ce254ef5 100644 --- a/app/i18n/nl/sub.php +++ b/app/i18n/nl/sub.php @@ -35,18 +35,20 @@ return array( 'informations' => 'Informatie', 'keep_history' => 'Minimum aantal artikelen om te houden', 'moved_category_deleted' => 'Als u een categorie verwijderd, worden de feeds automatisch geclassificeerd onder <em>%s</em>.', - 'mute' => 'mute', // TODO + 'mute' => 'demp', 'no_selected' => 'Geen feed geselecteerd.', 'number_entries' => '%d artikelen', 'priority' => array( - '_' => 'Visibility', // TODO - 'archived' => 'Do not show (archived)', // TODO + '_' => 'Zichtbaarheid', + 'archived' => 'Niet weergeven (gearchiveerd)', 'main_stream' => 'Zichtbaar in het overzicht', - 'normal' => 'Show in its category', // TODO + 'normal' => 'Toon in categorie', ), 'pubsubhubbub' => 'Directe notificaties met PubSubHubbub', + 'ssl_verify' => 'SSL-veiligheid controleren', 'stats' => 'Statistieken', 'think_to_add' => 'Voeg wat feeds toe.', + 'timeout' => 'Time-out in seconden', 'title' => 'Titel', 'title_add' => 'Voeg een RSS feed toe', 'ttl' => 'Vernieuw automatisch niet vaker dan', @@ -73,11 +75,11 @@ return array( 'bookmark' => 'Abonneer (FreshRSS bladwijzer)', 'import_export' => 'Importeer / exporteer', 'subscription_management' => 'Abonnementenbeheer', - 'subscription_tools' => 'Subscription tools',// TODO + 'subscription_tools' => 'Hulpmiddelen voor abonnementen', ), 'title' => array( '_' => 'Abonnementenbeheer', 'feed_management' => 'RSS-feedbeheer', - 'subscription_tools' => 'Subscription tools',// TODO + 'subscription_tools' => 'Hulpmiddelen voor abonnementen', ), ); diff --git a/app/i18n/pt-br/conf.php b/app/i18n/pt-br/conf.php index 864c80e61..61a12160c 100644 --- a/app/i18n/pt-br/conf.php +++ b/app/i18n/pt-br/conf.php @@ -42,6 +42,7 @@ return array( 'query' => array( '_' => 'Queries do usuário', 'deprecated' => 'Esta não é mais válida. A categoria ou feed relacionado foi deletado.', + 'display' => 'Display user query results', // TODO 'filter' => 'Filtro aplicado:', 'get_all' => 'Mostrar todos os artigos', 'get_category' => 'Visualizar "%s" categoria', @@ -52,6 +53,7 @@ return array( 'number' => 'Query n°%d', 'order_asc' => 'Exibir artigos mais antigos primeiro', 'order_desc' => 'Exibir artigos mais novos primeiro', + 'remove' => 'Remove user query', // TODO 'search' => 'Busca por "%s"', 'state_0' => 'Exibir todos os artigos', 'state_1' => 'Exibir artigos lidos', diff --git a/app/i18n/pt-br/feedback.php b/app/i18n/pt-br/feedback.php index 932bb72b1..2057cf985 100644 --- a/app/i18n/pt-br/feedback.php +++ b/app/i18n/pt-br/feedback.php @@ -31,11 +31,11 @@ return array( 'extensions' => array( 'already_enabled' => '%s já está habilitado', 'disable' => array( - 'ko' => '%s não pode ser desabilitado. <a href="%s">verifique os logs do FressRSS</a> para detalhes.', + 'ko' => '%s não pode ser desabilitado. <a href="%s">verifique os logs do FreshRSS</a> para detalhes.', 'ok' => '%s agora está desabilitado', ), 'enable' => array( - 'ko' => '%s não pode ser habilitado. <a href="%s">verifique os logs do FressRSS</a> para detalhes.', + 'ko' => '%s não pode ser habilitado. <a href="%s">verifique os logs do FreshRSS</a> para detalhes.', 'ok' => '%s agora está habilitado', ), 'no_access' => 'Você não tem acesso ao %s', @@ -72,7 +72,7 @@ return array( 'already_subscribed' => 'Você já está inscrito no <em>%s</em>', 'deleted' => 'o Feed foi deletado', 'error' => 'O feed não pode ser atualizado', - 'internal_problem' => 'O RSS feed não pôde ser adicionado. <a href="%s">Verifique os FressRSS logs</a> para detalhes.', + 'internal_problem' => 'O RSS feed não pôde ser adicionado. <a href="%s">Verifique os FreshRSS logs</a> para detalhes.', // @todo 'invalid_url' => 'URL <em>%s</em> é inválida', 'marked_read' => 'Feeds foram marcados como lidos', 'n_actualized' => '%d feeds foram atualizados', diff --git a/app/i18n/pt-br/gen.php b/app/i18n/pt-br/gen.php index fa1532787..932b6066d 100644 --- a/app/i18n/pt-br/gen.php +++ b/app/i18n/pt-br/gen.php @@ -169,6 +169,7 @@ return array( 'jdh' => 'Journal du hacker', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pocket' => 'Pocket', 'print' => 'Imprimir', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', diff --git a/app/i18n/pt-br/sub.php b/app/i18n/pt-br/sub.php index 09dde718f..1b084f08f 100644 --- a/app/i18n/pt-br/sub.php +++ b/app/i18n/pt-br/sub.php @@ -44,8 +44,10 @@ return array( 'main_stream' => 'Mostrar na tela principal', 'normal' => 'Show in its category', // TODO ), + 'ssl_verify' => 'Verify SSL security', //TODO 'stats' => 'Estatísticas', 'think_to_add' => 'Você deve adicionar alguns feeds.', + 'timeout' => 'Timeout in seconds', //TODO 'title' => 'Título', 'title_add' => 'Adicionar o RSS feed', 'ttl' => 'Não atualize automáticamente mais que', diff --git a/app/i18n/ru/conf.php b/app/i18n/ru/conf.php index 1b5cd8085..90a1a6797 100644 --- a/app/i18n/ru/conf.php +++ b/app/i18n/ru/conf.php @@ -42,6 +42,7 @@ return array( 'query' => array( '_' => 'User queries', 'deprecated' => 'This query is no longer valid. The referenced category or feed has been deleted.', + 'display' => 'Display user query results', // TODO 'filter' => 'Filter applied:', 'get_all' => 'Display all articles', 'get_category' => 'Display "%s" category', @@ -52,6 +53,7 @@ return array( 'number' => 'Query n°%d', 'order_asc' => 'Display oldest articles first', 'order_desc' => 'Display newest articles first', + 'remove' => 'Remove user query', // TODO 'search' => 'Search for "%s"', 'state_0' => 'Display all articles', 'state_1' => 'Display read articles', diff --git a/app/i18n/ru/feedback.php b/app/i18n/ru/feedback.php index 9416ed878..6d4e5e3fe 100644 --- a/app/i18n/ru/feedback.php +++ b/app/i18n/ru/feedback.php @@ -31,11 +31,11 @@ return array( 'extensions' => array( 'already_enabled' => '%s is already enabled', //TODO 'disable' => array( - 'ko' => '%s cannot be disabled. <a href="%s">Check FressRSS logs</a> for details.', //TODO + 'ko' => '%s cannot be disabled. <a href="%s">Check FreshRSS logs</a> for details.', //TODO 'ok' => '%s is now disabled', //TODO ), 'enable' => array( - 'ko' => '%s cannot be enabled. <a href="%s">Check FressRSS logs</a> for details.', //TODO + 'ko' => '%s cannot be enabled. <a href="%s">Check FreshRSS logs</a> for details.', //TODO 'ok' => '%s is now enabled', //TODO ), 'no_access' => 'You have no access on %s', //TODO @@ -72,7 +72,7 @@ return array( 'already_subscribed' => 'You have already subscribed to <em>%s</em>', //TODO 'deleted' => 'Feed has been deleted', //TODO 'error' => 'Feed cannot be updated', //TODO - 'internal_problem' => 'The RSS feed could not be added. <a href="%s">Check FressRSS logs</a> for details.', //TODO + 'internal_problem' => 'The newsfeed could not be added. <a href="%s">Check FreshRSS logs</a> for details. You can try force adding by appending <code>#force_feed</code> to the URL.', //TODO 'invalid_url' => 'URL <em>%s</em> is invalid', //TODO 'marked_read' => 'Feeds have been marked as read', //TODO 'n_actualized' => '%d feeds have been updated', //TODO diff --git a/app/i18n/ru/gen.php b/app/i18n/ru/gen.php index 6f9020695..ef9217d73 100644 --- a/app/i18n/ru/gen.php +++ b/app/i18n/ru/gen.php @@ -170,6 +170,7 @@ return array( 'jdh' => 'Journal du hacker', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pocket' => 'Pocket', 'print' => 'Print', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', diff --git a/app/i18n/ru/sub.php b/app/i18n/ru/sub.php index 9e360630a..bef49623f 100644 --- a/app/i18n/ru/sub.php +++ b/app/i18n/ru/sub.php @@ -44,8 +44,10 @@ return array( 'main_stream' => 'Show in main stream', // TODO 'normal' => 'Show in its category', // TODO ), + 'ssl_verify' => 'Verify SSL security', //TODO 'stats' => 'Statistics',// TODO 'think_to_add' => 'You may add some feeds.',// TODO + 'timeout' => 'Timeout in seconds', //TODO 'title' => 'Title',// TODO 'title_add' => 'Add a RSS feed',// TODO 'ttl' => 'Do not automatically refresh more often than',// TODO diff --git a/app/i18n/tr/conf.php b/app/i18n/tr/conf.php index 0671da79e..cae1e4cac 100644 --- a/app/i18n/tr/conf.php +++ b/app/i18n/tr/conf.php @@ -42,6 +42,7 @@ return array( 'query' => array( '_' => 'Kullanıcı sorguları', 'deprecated' => 'Bu sorgu artık geçerli değil. İlgili akış veya kategori silinmiş.', + 'display' => 'Display user query results', // TODO 'filter' => 'Filtre uygulandı:', 'get_all' => 'Tüm makaleleri göster', 'get_category' => '"%s" kategorisini göster', @@ -52,6 +53,7 @@ return array( 'number' => 'Sorgu n°%d', 'order_asc' => 'Önce eski makaleleri göster', 'order_desc' => 'Önce yeni makaleleri göster', + 'remove' => 'Remove user query', // TODO 'search' => '"%s" için arama', 'state_0' => 'Tüm makaleleri göster', 'state_1' => 'Okunmuş makaleleri göster', diff --git a/app/i18n/tr/feedback.php b/app/i18n/tr/feedback.php index 8f40e7d85..df7d1b264 100644 --- a/app/i18n/tr/feedback.php +++ b/app/i18n/tr/feedback.php @@ -31,11 +31,11 @@ return array( 'extensions' => array( 'already_enabled' => '%s zaten aktif', 'disable' => array( - 'ko' => '%s gösterilemiyor. Detaylar için <a href="%s">FressRSS log kayıtlarını</a> kontrol edin.', + 'ko' => '%s gösterilemiyor. Detaylar için <a href="%s">FreshRSS log kayıtlarını</a> kontrol edin.', 'ok' => '%s pasif', ), 'enable' => array( - 'ko' => '%s aktifleştirilemiyor. Detaylar için <a href="%s">FressRSS log kayıtlarını</a> kontrol edin.', + 'ko' => '%s aktifleştirilemiyor. Detaylar için <a href="%s">FreshRSS log kayıtlarını</a> kontrol edin.', 'ok' => '%s aktif', ), 'no_access' => '%s de yetkiniz yok', @@ -72,7 +72,7 @@ return array( 'already_subscribed' => '<em>%s</em> için zaten aboneliğiniz bulunmakta', 'deleted' => 'Akış silindi', 'error' => 'Akış güncellenemiyor', - 'internal_problem' => 'RSS akışı eklenemiyor. Detaylar için <a href="%s">FressRSS log kayıtlarını</a> kontrol edin.', + 'internal_problem' => 'RSS akışı eklenemiyor. Detaylar için <a href="%s">FreshRSS log kayıtlarını</a> kontrol edin.', // @todo 'invalid_url' => 'URL <em>%s</em> geçersiz', 'marked_read' => 'Akışlar okundu olarak işaretlendi', 'n_actualized' => '%d akışları güncellendi', diff --git a/app/i18n/tr/gen.php b/app/i18n/tr/gen.php index 293502e74..d99081396 100644 --- a/app/i18n/tr/gen.php +++ b/app/i18n/tr/gen.php @@ -170,6 +170,7 @@ return array( 'jdh' => 'Journal du hacker', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pocket' => 'Pocket', 'print' => 'Print', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', diff --git a/app/i18n/tr/install.php b/app/i18n/tr/install.php index d5564297b..4ae0ad7e3 100644 --- a/app/i18n/tr/install.php +++ b/app/i18n/tr/install.php @@ -103,7 +103,7 @@ return array( 'fix_errors_before' => 'Lütfen sonraki adıma geçmek için hataları düzeltin.', 'javascript_is_better' => 'FreshRSS JavaScript ile daha işlevseldir', 'js' => array( - 'confirm_reinstall' => 'FressRSS i yeniden kurarak önceki yapılandırma ayarlarınızı kaybedeceksiniz. Devam etmek istiyor musunuz ?', + 'confirm_reinstall' => 'FreshRSS i yeniden kurarak önceki yapılandırma ayarlarınızı kaybedeceksiniz. Devam etmek istiyor musunuz ?', ), 'language' => array( '_' => 'Dil', diff --git a/app/i18n/tr/sub.php b/app/i18n/tr/sub.php index 871731158..e8cd15d0d 100644 --- a/app/i18n/tr/sub.php +++ b/app/i18n/tr/sub.php @@ -44,8 +44,10 @@ return array( 'main_stream' => 'Ana akışda göster', 'normal' => 'Show in its category', // TODO ), + 'ssl_verify' => 'Verify SSL security', //TODO 'stats' => 'İstatistikler', 'think_to_add' => 'Akış ekleyebilirsiniz.', + 'timeout' => 'Timeout in seconds', //TODO 'title' => 'Başlık', 'title_add' => 'RSS akışı ekle', 'ttl' => 'Şu kadar süreden fazla otomatik yenileme yapma', diff --git a/app/i18n/zh-cn/conf.php b/app/i18n/zh-cn/conf.php index c57738c5b..00bea4d79 100644 --- a/app/i18n/zh-cn/conf.php +++ b/app/i18n/zh-cn/conf.php @@ -42,6 +42,7 @@ return array( 'query' => array( '_' => '自定义查询', 'deprecated' => '此查询不再有效。相关的分类或 RSS 源已被删除。', + 'display' => 'Display user query results', // TODO 'filter' => '生效的过滤器:', 'get_all' => '显示所有文章', 'get_category' => '显示分类 "%s"', @@ -52,6 +53,7 @@ return array( 'number' => '查询 n°%d', 'order_asc' => '由旧到新显示文章', 'order_desc' => '由新到旧显示文章', + 'remove' => 'Remove user query', // TODO 'search' => '搜索 "%s"', 'state_0' => '显示所有文章', 'state_1' => '显示已读文章', diff --git a/app/i18n/zh-cn/feedback.php b/app/i18n/zh-cn/feedback.php index a005de0ce..1db879891 100644 --- a/app/i18n/zh-cn/feedback.php +++ b/app/i18n/zh-cn/feedback.php @@ -31,11 +31,11 @@ return array( 'extensions' => array( 'already_enabled' => '%s 已启用', 'disable' => array( - 'ko' => '%s 禁用失败。<a href="%s">检查 FressRSS 日志</a> 查看详情。', + 'ko' => '%s 禁用失败。<a href="%s">检查 FreshRSS 日志</a> 查看详情。', 'ok' => '%s 现已禁用', ), 'enable' => array( - 'ko' => '%s 启用失败。<a href="%s">检查 FressRSS 日志</a> 查看详情。', + 'ko' => '%s 启用失败。<a href="%s">检查 FreshRSS 日志</a> 查看详情。', 'ok' => '%s 现已禁用', ), 'no_access' => '你无权访问 %s', @@ -72,7 +72,7 @@ return array( 'already_subscribed' => '你已订阅 <em>%s</em>', 'deleted' => 'RSS 源已删除', 'error' => 'RSS 源更新失败', - 'internal_problem' => 'RSS 源添加失败。<a href="%s">检查 FressRSS 日志</a> 查看详情。', + 'internal_problem' => 'RSS 源添加失败。<a href="%s">检查 FreshRSS 日志</a> 查看详情。', // @todo 'invalid_url' => 'URL <em>%s</em> 无效', 'marked_read' => 'RSS 源已被设为已读', 'n_actualized' => '%d 个 RSS 源已更新', diff --git a/app/i18n/zh-cn/gen.php b/app/i18n/zh-cn/gen.php index 241fce13b..9289d8571 100644 --- a/app/i18n/zh-cn/gen.php +++ b/app/i18n/zh-cn/gen.php @@ -170,6 +170,7 @@ return array( 'jdh' => 'Journal du hacker', 'mastodon' => 'Mastodon', 'movim' => 'Movim', + 'pocket' => 'Pocket', 'print' => '打印', 'shaarli' => 'Shaarli', 'twitter' => 'Twitter', diff --git a/app/i18n/zh-cn/sub.php b/app/i18n/zh-cn/sub.php index bf73f82c4..034f8a9d9 100644 --- a/app/i18n/zh-cn/sub.php +++ b/app/i18n/zh-cn/sub.php @@ -44,8 +44,10 @@ return array( 'main_stream' => '在首页中显示', 'normal' => '在分类中显示', ), + 'ssl_verify' => 'Verify SSL security', //TODO 'stats' => '统计', 'think_to_add' => '你可以添加一些 RSS 源。', + 'timeout' => 'Timeout in seconds', //TODO 'title' => '标题', 'title_add' => '添加 RSS 源', 'ttl' => '最小自动更新时间', diff --git a/app/install.php b/app/install.php index 870c93908..c30f8d583 100644 --- a/app/install.php +++ b/app/install.php @@ -537,7 +537,7 @@ function printStep2() { <div class="form-group"> <label class="group-name" for="default_user"><?php echo _t('install.default_user'); ?></label> <div class="group-controls"> - <input type="text" id="default_user" name="default_user" required="required" size="16" pattern="<?php echo FreshRSS_user_Controller::USERNAME_PATTERN; ?>" value="<?php echo isset($_SESSION['default_user']) ? $_SESSION['default_user'] : ''; ?>" placeholder="<?php echo httpAuthUser() == '' ? 'alice' : httpAuthUser(); ?>" tabindex="3" /> + <input type="text" id="default_user" name="default_user" autocomplete="username" required="required" size="16" pattern="<?php echo FreshRSS_user_Controller::USERNAME_PATTERN; ?>" value="<?php echo isset($_SESSION['default_user']) ? $_SESSION['default_user'] : ''; ?>" placeholder="<?php echo httpAuthUser() == '' ? 'alice' : httpAuthUser(); ?>" tabindex="3" /> </div> </div> diff --git a/app/layout/aside_subscription.phtml b/app/layout/aside_subscription.phtml index 6d2a5ac8f..e6a378837 100644 --- a/app/layout/aside_subscription.phtml +++ b/app/layout/aside_subscription.phtml @@ -1,15 +1,15 @@ <ul class="nav nav-list aside"> <li class="nav-header"><?php echo _t('sub.menu.subscription_management'); ?></li> - <li class="item<?php echo Minz_Request::controllerName() == 'subscription' ? ' active' : ''; ?>"> + <li class="item<?php echo Minz_Request::controllerName() === 'subscription' && Minz_Request::actionName() !== 'bookmarklet' ? ' active' : ''; ?>"> <a href="<?php echo _url('subscription', 'index'); ?>"><?php echo _t('sub.menu.subscription_management'); ?></a> </li> - <li class="item<?php echo Minz_Request::controllerName() == 'importExport' ? ' active' : ''; ?>"> + <li class="item<?php echo Minz_Request::controllerName() === 'importExport' ? ' active' : ''; ?>"> <a href="<?php echo _url('importExport', 'index'); ?>"><?php echo _t('sub.menu.import_export'); ?></a> </li> - <li class="item<?php echo Minz_Request::controllerName() == 'bookmarklet' ? ' active' : ''; ?>"> + <li class="item<?php echo Minz_Request::controllerName() === 'subscription' && Minz_Request::actionName() === 'bookmarklet' ? ' active' : ''; ?>"> <a href="<?php echo _url('subscription', 'bookmarklet'); ?>"><?php echo _t('sub.menu.subscription_tools'); ?></a> </li> </ul> diff --git a/app/shares.php b/app/shares.php index 5403fd48c..cd09aa19c 100644 --- a/app/shares.php +++ b/app/shares.php @@ -126,4 +126,10 @@ return array( 'method' => 'POST', 'field' => 'status', ), + 'pocket' => array( + 'url' => 'https://getpocket.com/save?url=~LINK~&title=~TITLE~', + 'transform' => array('rawurlencode'), + 'form' => 'simple', + 'method' => 'GET', + ), ); diff --git a/app/views/auth/formLogin.phtml b/app/views/auth/formLogin.phtml index 99be6059c..01d1d4736 100644 --- a/app/views/auth/formLogin.phtml +++ b/app/views/auth/formLogin.phtml @@ -9,7 +9,7 @@ <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" /> <div> <label for="username"><?php echo _t('gen.auth.username'); ?></label> - <input type="text" id="username" name="username" size="16" required="required" pattern="<?php echo FreshRSS_user_Controller::USERNAME_PATTERN; ?>" autofocus="autofocus" /> + <input type="text" id="username" name="username" autocomplete="username" size="16" required="required" pattern="<?php echo FreshRSS_user_Controller::USERNAME_PATTERN; ?>" autofocus="autofocus" /> </div> <div> <label for="passwordPlain"><?php echo _t('gen.auth.password'); ?></label> diff --git a/app/views/auth/register.phtml b/app/views/auth/register.phtml index 23bda25ce..19e11ef76 100644 --- a/app/views/auth/register.phtml +++ b/app/views/auth/register.phtml @@ -11,7 +11,7 @@ <div> <label class="group-name" for="new_user_passwordPlain"><?php echo _t('gen.auth.password'), '<br />', _i('help'), ' ', _t('gen.auth.password.format'); ?></label> <div class="stick"> - <input type="password" id="new_user_passwordPlain" name="new_user_passwordPlain" required="required" autocomplete="off" pattern=".{7,}" /> + <input type="password" id="new_user_passwordPlain" name="new_user_passwordPlain" required="required" autocomplete="new-password" pattern=".{7,}" /> <a class="btn toggle-password" data-toggle="new_user_passwordPlain"><?php echo _i('key'); ?></a> </div> <noscript><b><?php echo _t('gen.js.should_be_activated'); ?></b></noscript> diff --git a/app/views/configure/queries.phtml b/app/views/configure/queries.phtml index 0dffa268d..baaf74954 100644 --- a/app/views/configure/queries.phtml +++ b/app/views/configure/queries.phtml @@ -14,7 +14,7 @@ </label> <div class="group-controls"> - <input type="hidden" id="queries_<?php echo $key; ?>_search" name="queries[<?php echo $key; ?>][url]" value="<?php echo $query->getUrl(); ?>"/> + <input type="hidden" id="queries_<?php echo $key; ?>_url" name="queries[<?php echo $key; ?>][url]" value="<?php echo $query->getUrl(); ?>"/> <input type="hidden" id="queries_<?php echo $key; ?>_search" name="queries[<?php echo $key; ?>][search]" value="<?php echo $query->getSearch(); ?>"/> <input type="hidden" id="queries_<?php echo $key; ?>_state" name="queries[<?php echo $key; ?>][state]" value="<?php echo $query->getState(); ?>"/> <input type="hidden" id="queries_<?php echo $key; ?>_order" name="queries[<?php echo $key; ?>][order]" value="<?php echo $query->getOrder(); ?>"/> @@ -29,11 +29,11 @@ data-leave-validation="<?php echo $query->getName(); ?>" /> - <a class="btn" href="<?php echo $query->getUrl(); ?>"> + <a class="btn" href="<?php echo $query->getUrl(); ?>" title="<?php echo _t('conf.query.display'); ?>"> <?php echo _i('link'); ?> </a> - <a class="btn btn-attention remove" href="#" data-remove="query-group-<?php echo $key; ?>"> + <a class="btn btn-attention remove" href="#" data-remove="query-group-<?php echo $key; ?>" title="<?php echo _t('conf.query.remove'); ?>"> <?php echo _i('close'); ?> </a> </div> diff --git a/app/views/feed/add.phtml b/app/views/feed/add.phtml index 5cd59d298..823cf1b2f 100644 --- a/app/views/feed/add.phtml +++ b/app/views/feed/add.phtml @@ -73,7 +73,7 @@ <label class="group-name" for="http_pass"><?php echo _t('sub.feed.auth.password'); ?></label> <div class="group-controls"> - <input type="password" name="http_pass" id="http_pass" class="extend" value="<?php echo $auth['password']; ?>" autocomplete="off" /> + <input type="password" name="http_pass" id="http_pass" class="extend" value="<?php echo $auth['password']; ?>" autocomplete="new-password" /> </div> <div class="group-controls"> diff --git a/app/views/helpers/export/articles.phtml b/app/views/helpers/export/articles.phtml index 49c370023..75651483a 100644 --- a/app/views/helpers/export/articles.phtml +++ b/app/views/helpers/export/articles.phtml @@ -23,7 +23,7 @@ foreach ($this->entriesRaw as $entryRaw) { $entry = FreshRSS_EntryDAO::daoToEntry($entryRaw); if (!isset($this->feed)) { $feed = FreshRSS_CategoryDAO::findFeed($this->categories, $entry->feed()); - if ($feed == null) { + if ($feed === null) { $feed = $entry->feed(true); } } else { diff --git a/app/views/helpers/feed/update.phtml b/app/views/helpers/feed/update.phtml index d379c5df8..7144aab46 100644 --- a/app/views/helpers/feed/update.phtml +++ b/app/views/helpers/feed/update.phtml @@ -158,7 +158,7 @@ <label class="group-name" for="http_pass_feed<?php echo $this->feed->id(); ?>"><?php echo _t('sub.feed.auth.password'); ?></label> <div class="group-controls"> - <input type="password" name="http_pass_feed<?php echo $this->feed->id(); ?>" id="http_pass_feed<?php echo $this->feed->id(); ?>" class="extend" value="<?php echo $auth['password']; ?>" autocomplete="off" /> + <input type="password" name="http_pass_feed<?php echo $this->feed->id(); ?>" id="http_pass_feed<?php echo $this->feed->id(); ?>" class="extend" value="<?php echo $auth['password']; ?>" autocomplete="new-password" /> </div> </div> @@ -178,6 +178,55 @@ </div> </div> + <div class="form-group"> + <label class="group-name" for="mark_updated_article_unread"><?php echo _t('conf.reading.mark_updated_article_unread'); ?></label> + <div class="group-controls"> + <label class="checkbox" for="mark_updated_article_unread"> + <select name="mark_updated_article_unread" id="mark_updated_article_unread"> + <option value=""<?php echo $this->feed->attributes('mark_updated_article_unread') === null ? ' selected="selected"' : ''; ?>><?php echo _t('gen.short.by_default'); ?></option> + <option value="0"<?php echo $this->feed->attributes('mark_updated_article_unread') === false ? ' selected="selected"' : ''; ?>><?php echo _t('gen.short.no'); ?></option> + <option value="1"<?php echo $this->feed->attributes('mark_updated_article_unread') === true ? ' selected="selected"' : ''; ?>><?php echo _t('gen.short.yes'); ?></option> + </select> + </label> + </div> + </div> + + <div class="form-group"> + <label class="group-name" for="read_upon_reception"><?php echo _t('conf.reading.read.when'); ?></label> + <div class="group-controls"> + <label class="checkbox" for="read_upon_reception"> + <select name="read_upon_reception" id="read_upon_reception"> + <option value=""<?php echo $this->feed->attributes('read_upon_reception') === null ? ' selected="selected"' : ''; ?>><?php echo _t('gen.short.by_default'); ?></option> + <option value="0"<?php echo $this->feed->attributes('read_upon_reception') === false ? ' selected="selected"' : ''; ?>><?php echo _t('gen.short.no'); ?></option> + <option value="1"<?php echo $this->feed->attributes('read_upon_reception') === true ? ' selected="selected"' : ''; ?>><?php echo _t('gen.short.yes'); ?></option> + </select> + <?php echo _t('conf.reading.read.upon_reception'); ?> + </label> + </div> + </div> + + <?php if (FreshRSS_Auth::hasAccess('admin')) { ?> + <div class="form-group"> + <label class="group-name" for="timeout"><?php echo _t('sub.feed.timeout'); ?></label> + <div class="group-controls"> + <input type="number" name="timeout" id="timeout" min="3" max="120" value="<?php echo $this->feed->attributes('timeout'); ?>" placeholder="<?php echo _t('gen.short.by_default'); ?>" /> + </div> + </div> + + <div class="form-group"> + <label class="group-name" for="ssl_verify"><?php echo _t('sub.feed.ssl_verify'); ?></label> + <div class="group-controls"> + <label class="checkbox" for="ssl_verify"> + <select name="ssl_verify" id="ssl_verify"> + <option value=""<?php echo $this->feed->attributes('ssl_verify') === null ? ' selected="selected"' : ''; ?>><?php echo _t('gen.short.by_default'); ?></option> + <option value="0"<?php echo $this->feed->attributes('ssl_verify') === false ? ' selected="selected"' : ''; ?>><?php echo _t('gen.short.no'); ?></option> + <option value="1"<?php echo $this->feed->attributes('ssl_verify') === true ? ' selected="selected"' : ''; ?>><?php echo _t('gen.short.yes'); ?></option> + </select> + </label> + </div> + </div> + <?php } ?> + <div class="form-group form-actions"> <div class="group-controls"> <button type="submit" class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button> diff --git a/app/views/helpers/index/normal/entry_bottom.phtml b/app/views/helpers/index/normal/entry_bottom.phtml index bc23938b0..793c644f9 100644 --- a/app/views/helpers/index/normal/entry_bottom.phtml +++ b/app/views/helpers/index/normal/entry_bottom.phtml @@ -48,6 +48,9 @@ $title = $this->entry->title() . ' · ' . $this->feed->name(); foreach (FreshRSS_Context::$user_conf->sharing as $share_options) { $share = FreshRSS_Share::get($share_options['type']); + if ($share === null) { + continue; + } $share_options['link'] = $link; $share_options['title'] = $title; $share->update($share_options); diff --git a/app/views/subscription/index.phtml b/app/views/subscription/index.phtml index 26af0bd7c..41dd8a7df 100644 --- a/app/views/subscription/index.phtml +++ b/app/views/subscription/index.phtml @@ -40,7 +40,7 @@ <input type="text" name="http_user" id="http_user_feed" value=" " autocomplete="off" placeholder="<?php echo _t('sub.feed.auth.username'); ?>" /> </li> <li class="input"> - <input type="password" name="http_pass" id="http_pass_feed" autocomplete="off" placeholder="<?php echo _t('sub.feed.auth.password'); ?>" /> + <input type="password" name="http_pass" id="http_pass_feed" autocomplete="new-password" placeholder="<?php echo _t('sub.feed.auth.password'); ?>" /> </li> </ul> </div> diff --git a/app/views/user/manage.phtml b/app/views/user/manage.phtml index 26838fcc1..9d457f7a5 100644 --- a/app/views/user/manage.phtml +++ b/app/views/user/manage.phtml @@ -66,7 +66,7 @@ <label class="group-name" for="newPasswordPlain"><?php echo _t('admin.user.password_form'); ?></label> <div class="group-controls"> <div class="stick"> - <input type="password" id="newPasswordPlain" name="newPasswordPlain" autocomplete="off" pattern=".{7,}" <?php echo cryptAvailable() ? '' : 'disabled="disabled" '; ?>/> + <input type="password" id="newPasswordPlain" name="newPasswordPlain" autocomplete="new-password" pattern=".{7,}" <?php echo cryptAvailable() ? '' : 'disabled="disabled" '; ?>/> <a class="btn toggle-password" data-toggle="newPasswordPlain"><?php echo _i('key'); ?></a> </div> <?php echo _i('help'); ?> <?php echo _t('conf.profile.password_format'); ?> diff --git a/app/views/user/profile.phtml b/app/views/user/profile.phtml index 7a63c0941..83140376d 100644 --- a/app/views/user/profile.phtml +++ b/app/views/user/profile.phtml @@ -22,7 +22,7 @@ <label class="group-name" for="newPasswordPlain"><?php echo _t('conf.profile.password_form'); ?></label> <div class="group-controls"> <div class="stick"> - <input type="password" id="newPasswordPlain" name="newPasswordPlain" autocomplete="off" pattern=".{7,}" <?php echo cryptAvailable() ? '' : 'disabled="disabled" '; ?>/> + <input type="password" id="newPasswordPlain" name="newPasswordPlain" autocomplete="new-password" pattern=".{7,}" <?php echo cryptAvailable() ? '' : 'disabled="disabled" '; ?>/> <a class="btn toggle-password" data-toggle="newPasswordPlain"><?php echo _i('key'); ?></a> </div> <?php echo _i('help'); ?> <?php echo _t('conf.profile.password_format'); ?> @@ -35,7 +35,7 @@ <label class="group-name" for="apiPasswordPlain"><?php echo _t('conf.profile.password_api'); ?></label> <div class="group-controls"> <div class="stick"> - <input type="password" id="apiPasswordPlain" name="apiPasswordPlain" autocomplete="off" pattern=".{7,}" <?php echo cryptAvailable() ? '' : 'disabled="disabled" '; ?>/> + <input type="password" id="apiPasswordPlain" name="apiPasswordPlain" autocomplete="new-password" pattern=".{7,}" <?php echo cryptAvailable() ? '' : 'disabled="disabled" '; ?>/> <a class="btn toggle-password" data-toggle="apiPasswordPlain"><?php echo _i('key'); ?></a> </div> <?php echo _i('help'); ?> <kbd><a href="../api/"><?php echo Minz_Url::display('/api/', 'html', true); ?></a></kbd> |
