From 7c1b5e322cca0134f57b3a436129985ba9170b9f Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 2 Aug 2016 22:49:35 +0200 Subject: PostgreSQL draft https://github.com/FreshRSS/FreshRSS/issues/416 Based on @Damstre work https://github.com/FreshRSS/FreshRSS/pull/1071 Not tested --- app/Models/FeedDAO.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/Models/FeedDAO.php') diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index 475d39286..f29dac9c0 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -16,7 +16,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { ); if ($stm && $stm->execute($values)) { - return $this->bd->lastInsertId(); + return $this->bd->lastInsertId('"' . parent::prefix . 'feed_id_seq"'); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); Minz_Log::error('SQL error addFeed: ' . $info[2]); -- cgit v1.2.3 From e315192c4b3df89dddb1ac37c6c7a01531d7952f Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 14 Aug 2016 11:06:31 +0200 Subject: Bug static --- app/Models/CategoryDAO.php | 2 +- app/Models/FeedDAO.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'app/Models/FeedDAO.php') diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php index a44edb0f6..3b1519c20 100644 --- a/app/Models/CategoryDAO.php +++ b/app/Models/CategoryDAO.php @@ -10,7 +10,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable ); if ($stm && $stm->execute($values)) { - return $this->bd->lastInsertId('"' . parent::prefix . 'category_id_seq"'); + return $this->bd->lastInsertId('"' . $this->prefix . 'category_id_seq"'); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); Minz_Log::error('SQL error addCategory: ' . $info[2]); diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index f29dac9c0..ce65ed8b1 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -16,7 +16,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { ); if ($stm && $stm->execute($values)) { - return $this->bd->lastInsertId('"' . parent::prefix . 'feed_id_seq"'); + return $this->bd->lastInsertId('"' . $this->prefix . 'feed_id_seq"'); } else { $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo(); Minz_Log::error('SQL error addFeed: ' . $info[2]); -- cgit v1.2.3 From f66be86e41d89214688a28243b412ffa43ce500d Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 31 Aug 2016 21:47:12 +0200 Subject: Quoted upper-cases instead of string replace --- app/Models/CategoryDAO.php | 2 +- app/Models/EntryDAO.php | 14 +++++++------- app/Models/EntryDAOSQLite.php | 4 ++-- app/Models/FeedDAO.php | 22 +++++++++++----------- app/Models/FeedDAOSQLite.php | 4 ++-- lib/Minz/ModelPdo.php | 5 +---- 6 files changed, 24 insertions(+), 27 deletions(-) (limited to 'app/Models/FeedDAO.php') diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php index 3b1519c20..1dab60ea9 100644 --- a/app/Models/CategoryDAO.php +++ b/app/Models/CategoryDAO.php @@ -100,7 +100,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable public function listCategories($prePopulateFeeds = true, $details = false) { if ($prePopulateFeeds) { $sql = 'SELECT c.id AS c_id, c.name AS c_name, ' - . ($details ? 'f.* ' : 'f.id, f.name, f.url, f.website, f.priority, f.error, f.cache_nbEntries, f.cache_nbUnreads ') + . ($details ? 'f.* ' : 'f.id, f.name, f.url, f.website, f.priority, f.error, f.`cache_nbEntries`, f.`cache_nbUnreads` ') . 'FROM `' . $this->prefix . 'category` c ' . 'LEFT OUTER JOIN `' . $this->prefix . 'feed` f ON f.category=c.id ' . 'GROUP BY f.id, c_id ' diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 8d136cd6c..d39f0237c 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -28,7 +28,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $this->bd->beginTransaction(); $hasTransaction = true; } - $stm = $this->bd->prepare('ALTER TABLE `' . $this->prefix . 'entry` ADD COLUMN lastSeen INT(11) DEFAULT 0'); + $stm = $this->bd->prepare('ALTER TABLE `' . $this->prefix . 'entry` ADD COLUMN `lastSeen` INT(11) DEFAULT 0'); if ($stm && $stm->execute()) { $stm = $this->bd->prepare('CREATE INDEX entry_lastSeen_index ON `' . $this->prefix . 'entry`(`lastSeen`);'); //"IF NOT EXISTS" does not exist in MySQL 5.7 if ($stm && $stm->execute()) { @@ -113,7 +113,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { if ($this->addEntryPrepared === null) { $sql = 'INSERT INTO `' . $this->prefix . 'entry` (id, guid, title, author, ' . ($this->isCompressed() ? 'content_bin' : 'content') - . ', link, date, lastSeen, hash, is_read, is_favorite, id_feed, tags) ' + . ', link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags) ' . 'VALUES(:id, :guid, :title, :author, ' . ($this->isCompressed() ? 'COMPRESS(:content)' : ':content') . ', :link, :date, :last_seen, ' @@ -174,7 +174,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $sql = 'UPDATE `' . $this->prefix . 'entry` ' . 'SET title=?, author=?, ' . ($this->isCompressed() ? 'content_bin=COMPRESS(?)' : 'content=?') - . ', link=?, date=?, lastSeen=?, hash=' + . ', link=?, date=?, `lastSeen`=?, hash=' . ($this->hasNativeHex() ? 'X?' : '?') //TODO PostgreSQL . ', ' . ($valuesTmp['is_read'] === null ? '' : 'is_read=?, ') . 'tags=? ' @@ -265,7 +265,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { . 'WHERE e.is_read=0 ' . 'GROUP BY e.id_feed' . ') x ON x.id_feed=f.id ' - . 'SET f.cache_nbUnreads=COALESCE(x.nbUnreads, 0) ' + . 'SET f.`cache_nbUnreads`=COALESCE(x.nbUnreads, 0) ' . 'WHERE 1'; $values = array(); if ($feedId !== false) { @@ -328,7 +328,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } else { $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed=f.id ' . 'SET e.is_read=?,' - . 'f.cache_nbUnreads=f.cache_nbUnreads' . ($is_read ? '-' : '+') . '1 ' + . 'f.`cache_nbUnreads`=f.`cache_nbUnreads`' . ($is_read ? '-' : '+') . '1 ' . 'WHERE e.id=? AND e.is_read=?'; $values = array($is_read ? 1 : 0, $ids, $is_read ? 0 : 1); $stm = $this->bd->prepare($sql); @@ -467,7 +467,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { if ($affected > 0) { $sql = 'UPDATE `' . $this->prefix . 'feed` ' - . 'SET cache_nbUnreads=cache_nbUnreads-' . $affected + . 'SET `cache_nbUnreads`=`cache_nbUnreads`-' . $affected . ' WHERE id=?'; $values = array($id_feed); $stm = $this->bd->prepare($sql); @@ -703,7 +703,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { if (count($guids) < 1) { return 0; } - $sql = 'UPDATE `' . $this->prefix . 'entry` SET lastSeen=? WHERE id_feed=? AND guid IN (' . str_repeat('?,', count($guids) - 1). '?)'; + $sql = 'UPDATE `' . $this->prefix . 'entry` SET `lastSeen`=? WHERE id_feed=? AND guid IN (' . str_repeat('?,', count($guids) - 1). '?)'; $stm = $this->bd->prepare($sql); $values = array(time(), $id_feed); $values = array_merge($values, $guids); diff --git a/app/Models/EntryDAOSQLite.php b/app/Models/EntryDAOSQLite.php index 80dbcca6b..fd5d25bf6 100644 --- a/app/Models/EntryDAOSQLite.php +++ b/app/Models/EntryDAOSQLite.php @@ -28,7 +28,7 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { protected function updateCacheUnreads($catId = false, $feedId = false) { $sql = 'UPDATE `' . $this->prefix . 'feed` ' - . 'SET cache_nbUnreads=(' + . 'SET `cache_nbUnreads`=(' . 'SELECT COUNT(*) AS nbUnreads FROM `' . $this->prefix . 'entry` e ' . 'WHERE e.id_feed=`' . $this->prefix . 'feed`.id AND e.is_read=0) ' . 'WHERE 1'; @@ -86,7 +86,7 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { } $affected = $stm->rowCount(); if ($affected > 0) { - $sql = 'UPDATE `' . $this->prefix . 'feed` SET cache_nbUnreads=cache_nbUnreads' . ($is_read ? '-' : '+') . '1 ' + $sql = 'UPDATE `' . $this->prefix . 'feed` SET `cache_nbUnreads`=`cache_nbUnreads`' . ($is_read ? '-' : '+') . '1 ' . 'WHERE id=(SELECT e.id_feed FROM `' . $this->prefix . 'entry` e WHERE e.id=?)'; $values = array($ids); $stm = $this->bd->prepare($sql); diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index ce65ed8b1..6e6d8857b 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -2,7 +2,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { public function addFeed($valuesTmp) { - $sql = 'INSERT INTO `' . $this->prefix . 'feed` (url, category, name, website, description, lastUpdate, priority, httpAuth, error, keep_history, ttl) VALUES(?, ?, ?, ?, ?, ?, 10, ?, 0, -2, -2)'; + $sql = 'INSERT INTO `' . $this->prefix . 'feed` (url, category, name, website, description, `lastUpdate`, priority, `httpAuth`, error, keep_history, ttl) VALUES(?, ?, ?, ?, ?, ?, 10, ?, 0, -2, -2)'; $stm = $this->bd->prepare($sql); $values = array( @@ -85,13 +85,13 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { public function updateLastUpdate($id, $inError = 0, $updateCache = true) { if ($updateCache) { $sql = 'UPDATE `' . $this->prefix . 'feed` ' //2 sub-requests with FOREIGN KEY(e.id_feed), INDEX(e.is_read) faster than 1 request with GROUP BY or CASE - . 'SET cache_nbEntries=(SELECT COUNT(e1.id) FROM `' . $this->prefix . 'entry` e1 WHERE e1.id_feed=`' . $this->prefix . 'feed`.id),' - . 'cache_nbUnreads=(SELECT COUNT(e2.id) FROM `' . $this->prefix . 'entry` e2 WHERE e2.id_feed=`' . $this->prefix . 'feed`.id AND e2.is_read=0),' - . 'lastUpdate=?, error=? ' + . 'SET `cache_nbEntries`=(SELECT COUNT(e1.id) FROM `' . $this->prefix . 'entry` e1 WHERE e1.id_feed=`' . $this->prefix . 'feed`.id),' + . '`cache_nbUnreads`=(SELECT COUNT(e2.id) FROM `' . $this->prefix . 'entry` e2 WHERE e2.id_feed=`' . $this->prefix . 'feed`.id AND e2.is_read=0),' + . '`lastUpdate`=?, error=? ' . 'WHERE id=?'; } else { $sql = 'UPDATE `' . $this->prefix . 'feed` ' - . 'SET lastUpdate=?, error=? ' + . 'SET `lastUpdate`=?, error=? ' . 'WHERE id=?'; } @@ -226,10 +226,10 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { if ($defaultCacheDuration < 0) { $defaultCacheDuration = 2147483647; } - $sql = 'SELECT id, url, name, website, lastUpdate, pathEntries, httpAuth, keep_history, ttl ' + $sql = 'SELECT id, url, name, website, `lastUpdate`, `pathEntries`, `httpAuth`, keep_history, ttl ' . 'FROM `' . $this->prefix . 'feed` ' - . 'WHERE ttl <> -1 AND lastUpdate < (' . (time() + 60) . '-(CASE WHEN ttl=-2 THEN ' . intval($defaultCacheDuration) . ' ELSE ttl END)) ' - . 'ORDER BY lastUpdate'; + . 'WHERE ttl <> -1 AND `lastUpdate` < (' . (time() + 60) . '-(CASE WHEN ttl=-2 THEN ' . intval($defaultCacheDuration) . ' ELSE ttl END)) ' + . 'ORDER BY `lastUpdate`'; $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute())) { $sql2 = 'ALTER TABLE `' . $this->prefix . 'feed` ADD COLUMN ttl INT NOT NULL DEFAULT -2'; //v0.7.3 @@ -282,7 +282,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { . 'FROM `' . $this->prefix . 'entry` e ' . 'GROUP BY e.id_feed' . ') x ON x.id_feed=f.id ' - . 'SET f.cache_nbEntries=x.nbEntries, f.cache_nbUnreads=x.nbUnreads'; + . 'SET f.`cache_nbEntries`=x.nbEntries, f.`cache_nbUnreads`=x.nbUnreads'; $stm = $this->bd->prepare($sql); if ($stm && $stm->execute()) { @@ -308,7 +308,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $affected = $stm->rowCount(); $sql = 'UPDATE `' . $this->prefix . 'feed` ' - . 'SET cache_nbEntries=0, cache_nbUnreads=0 WHERE id=?'; + . 'SET `cache_nbEntries`=0, `cache_nbUnreads`=0 WHERE id=?'; $values = array($id); $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute($values))) { @@ -326,7 +326,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $sql = 'DELETE FROM `' . $this->prefix . 'entry` ' . 'WHERE id_feed=:id_feed AND id<=:id_max ' . 'AND is_favorite=0 ' //Do not remove favourites - . 'AND lastSeen < (SELECT maxLastSeen FROM (SELECT (MAX(e3.lastSeen)-99) AS maxLastSeen FROM `' . $this->prefix . 'entry` e3 WHERE e3.id_feed=:id_feed) recent) ' //Do not remove the most newly seen articles, plus a few seconds of tolerance + . 'AND `lastSeen` < (SELECT maxLastSeen FROM (SELECT (MAX(e3.`lastSeen`)-99) AS maxLastSeen FROM `' . $this->prefix . 'entry` e3 WHERE e3.id_feed=:id_feed) recent) ' //Do not remove the most newly seen articles, plus a few seconds of tolerance . 'AND id NOT IN (SELECT id FROM (SELECT e2.id FROM `' . $this->prefix . 'entry` e2 WHERE e2.id_feed=:id_feed ORDER BY id DESC LIMIT :keep) keep)'; //Double select: MySQL doesn't support 'LIMIT & IN/ALL/ANY/SOME subquery' $stm = $this->bd->prepare($sql); diff --git a/app/Models/FeedDAOSQLite.php b/app/Models/FeedDAOSQLite.php index 7599fda53..440ae74da 100644 --- a/app/Models/FeedDAOSQLite.php +++ b/app/Models/FeedDAOSQLite.php @@ -4,8 +4,8 @@ class FreshRSS_FeedDAOSQLite extends FreshRSS_FeedDAO { public function updateCachedValues() { //For one single feed, call updateLastUpdate($id) $sql = 'UPDATE `' . $this->prefix . 'feed` ' - . 'SET cache_nbEntries=(SELECT COUNT(e1.id) FROM `' . $this->prefix . 'entry` e1 WHERE e1.id_feed=`' . $this->prefix . 'feed`.id),' - . 'cache_nbUnreads=(SELECT COUNT(e2.id) FROM `' . $this->prefix . 'entry` e2 WHERE e2.id_feed=`' . $this->prefix . 'feed`.id AND e2.is_read=0)'; + . 'SET `cache_nbEntries`=(SELECT COUNT(e1.id) FROM `' . $this->prefix . 'entry` e1 WHERE e1.id_feed=`' . $this->prefix . 'feed`.id),' + . '`cache_nbUnreads`=(SELECT COUNT(e2.id) FROM `' . $this->prefix . 'entry` e2 WHERE e2.id_feed=`' . $this->prefix . 'feed`.id AND e2.is_read=0)'; $stm = $this->bd->prepare($sql); if ($stm && $stm->execute()) { return $stm->rowCount(); diff --git a/lib/Minz/ModelPdo.php b/lib/Minz/ModelPdo.php index 93a22fc3d..78b44ea7f 100644 --- a/lib/Minz/ModelPdo.php +++ b/lib/Minz/ModelPdo.php @@ -156,9 +156,6 @@ class MinzPDOMSQLite extends MinzPDO { class MinzPDOPGSQL extends MinzPDO { protected function compatibility($statement) { - return str_replace( - array('`', 'lastUpdate', 'pathEntries', 'httpAuth', 'cache_nbEntries', 'cache_nbUnreads', 'lastSeen'), - array('"', '"lastUpdate"', '"pathEntries"', '"httpAuth"', '"cache_nbEntries"', '"cache_nbUnreads"', '"lastSeen"'), - $statement); + return str_replace('`', '"', $statement); } } -- cgit v1.2.3 From 05cabe99ae48a187a77e0246dfffc60f2434b5e5 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 5 Oct 2016 00:39:54 +0200 Subject: Take better advantage of other users refresh --- app/Controllers/feedController.php | 18 ++++++++++++++++-- app/Models/EntryDAO.php | 7 +++++-- app/Models/Feed.php | 4 ++++ app/Models/FeedDAO.php | 8 ++++---- 4 files changed, 29 insertions(+), 8 deletions(-) (limited to 'app/Models/FeedDAO.php') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index c2a22aeb3..15f373833 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -242,7 +242,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feeds[] = $feed; } } else { - $feeds = $feedDAO->listFeedsOrderUpdate(FreshRSS_Context::$user_conf->ttl_default); + $feeds = $feedDAO->listFeedsOrderUpdate(-1); } // Calculate date of oldest entries we accept in DB. @@ -266,6 +266,20 @@ class FreshRSS_feed_Controller extends Minz_ActionController { continue; //When PubSubHubbub is used, do not pull refresh so often } + $mtime = 0; + $ttl = $feed->ttl(); + if ($ttl == -1) { + continue; //Feed refresh is disabled + } + if (feed->lastUpdate() < time() - ($ttl == -2 ? FreshRSS_Context::$user_conf->ttl_default : $ttl)) { + //Too early to refresh from source, but check if the feed was already updated by another user + $mtime = feed->cacheModifiedTime(); + if (feed->lastUpdate() >= $mtime + 10) { + continue; //Nothing newer from other users + } + Minz_Log::debug($feed->url() . ' was recently updated by another user'); + } + if (!$feed->lock()) { Minz_Log::notice('Feed already being actualized: ' . $feed->url()); continue; @@ -358,7 +372,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $entryDAO->addEntry($entry->toArray()); } } - $entryDAO->updateLastSeen($feed->id(), $oldGuids); + $entryDAO->updateLastSeen($feed->id(), $oldGuids, $mtime); } if ($feed_history >= 0 && rand(0, 30) === 1) { diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 63565e73a..43ac21f9e 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -707,13 +707,16 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } } - public function updateLastSeen($id_feed, $guids) { + public function updateLastSeen($id_feed, $guids, $mtime = 0) { if (count($guids) < 1) { return 0; } $sql = 'UPDATE `' . $this->prefix . 'entry` SET `lastSeen`=? WHERE id_feed=? AND guid IN (' . str_repeat('?,', count($guids) - 1). '?)'; $stm = $this->bd->prepare($sql); - $values = array(time(), $id_feed); + if ($mtime <= 0) { + $mtime = time(); + } + $values = array($mtime, $id_feed); $values = array_merge($values, $guids); if ($stm && $stm->execute($values)) { return $stm->rowCount(); diff --git a/app/Models/Feed.php b/app/Models/Feed.php index f2f345662..f435620c8 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -340,6 +340,10 @@ class FreshRSS_Feed extends Minz_Model { $this->entries = $entries; } + function cacheModifiedTime() { + return @filemtime(CACHE_PATH . '/' . md5($this->url) . '.spc'); + } + function lock() { $this->lockPath = TMP_PATH . '/' . $this->hash() . '.freshrss.lock'; if (file_exists($this->lockPath) && ((time() - @filemtime($this->lockPath)) > 3600)) { diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index 6e6d8857b..ad3cb0c2e 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -222,13 +222,13 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { return $feedCategoryNames; } + /** + * Use $defaultCacheDuration == -1 to return all feeds, without filtering them by TTL. + */ public function listFeedsOrderUpdate($defaultCacheDuration = 3600) { - if ($defaultCacheDuration < 0) { - $defaultCacheDuration = 2147483647; - } $sql = 'SELECT id, url, name, website, `lastUpdate`, `pathEntries`, `httpAuth`, keep_history, ttl ' . 'FROM `' . $this->prefix . 'feed` ' - . 'WHERE ttl <> -1 AND `lastUpdate` < (' . (time() + 60) . '-(CASE WHEN ttl=-2 THEN ' . intval($defaultCacheDuration) . ' ELSE ttl END)) ' + . ($defaultCacheDuration < 0 ? '' : 'WHERE ttl <> -1 AND `lastUpdate` < (' . (time() + 60) . '-(CASE WHEN ttl=-2 THEN ' . intval($defaultCacheDuration) . ' ELSE ttl END)) ') . 'ORDER BY `lastUpdate`'; $stm = $this->bd->prepare($sql); if (!($stm && $stm->execute())) { -- cgit v1.2.3 From fe65eec5bbdaee37177e3673e31e241b1f1b938d Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 5 Oct 2016 17:48:24 +0200 Subject: Better multiuser update --- app/Controllers/feedController.php | 9 +++++---- app/Models/FeedDAO.php | 10 +++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'app/Models/FeedDAO.php') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index d85a53446..dadc8aa83 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -271,13 +271,14 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if ($ttl == -1) { continue; //Feed refresh is disabled } - if ($feed->lastUpdate() < time() + 60 - ($ttl == -2 ? FreshRSS_Context::$user_conf->ttl_default : $ttl)) { + if ($feed->lastUpdate() + 10 >= time() - ($ttl == -2 ? FreshRSS_Context::$user_conf->ttl_default : $ttl)) { //Too early to refresh from source, but check whether the feed was updated by another user $mtime = $feed->cacheModifiedTime(); - if ($feed->lastUpdate() >= $mtime + 10) { + if ($feed->lastUpdate() + 10 >= $mtime) { continue; //Nothing newer from other users } - Minz_Log::debug($feed->url() . ' was recently updated by another user'); + //Minz_Log::debug($feed->url() . ' was updated at ' . date('c', $mtime) . ' by another user'); + //Will take advantage of the newer cache } if (!$feed->lock()) { @@ -391,7 +392,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } } - $feedDAO->updateLastUpdate($feed->id(), 0, $entryDAO->inTransaction()); + $feedDAO->updateLastUpdate($feed->id(), false, $entryDAO->inTransaction(), $mtime); if ($entryDAO->inTransaction()) { $entryDAO->commit(); } diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index ad3cb0c2e..c680d270c 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -82,7 +82,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } } - public function updateLastUpdate($id, $inError = 0, $updateCache = true) { + public function updateLastUpdate($id, $inError = false, $updateCache = true, $mtime = 0) { if ($updateCache) { $sql = 'UPDATE `' . $this->prefix . 'feed` ' //2 sub-requests with FOREIGN KEY(e.id_feed), INDEX(e.is_read) faster than 1 request with GROUP BY or CASE . 'SET `cache_nbEntries`=(SELECT COUNT(e1.id) FROM `' . $this->prefix . 'entry` e1 WHERE e1.id_feed=`' . $this->prefix . 'feed`.id),' @@ -95,9 +95,13 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { . 'WHERE id=?'; } + if ($mtime <= 0) { + $mtime = time(); + } + $values = array( - time(), - $inError, + $mtime, + $inError ? 1 : 0, $id, ); -- cgit v1.2.3 From 1893fc61e0e576519f878267fd877247445d1055 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 20 Oct 2016 01:19:59 +0200 Subject: guid and urls should not contain low/high characters It looks like SimplePie does not always filter everything Having a character not in latin1 would create MySQL collate errors --- app/Controllers/feedController.php | 4 +++- app/Controllers/importExportController.php | 4 +++- app/Models/EntryDAO.php | 4 ++++ app/Models/FeedDAO.php | 10 ++++++++++ 4 files changed, 20 insertions(+), 2 deletions(-) (limited to 'app/Models/FeedDAO.php') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 8751d2fff..d4a6c9955 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -314,7 +314,9 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if (count($entries) > 0) { $newGuids = array(); foreach ($entries as $entry) { - $newGuids[] = $entry->guid(); + $guid = $entry->guid(); + $guid = filter_var($guid, FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + $newGuids[] = $guid; } // For this feed, check existing GUIDs already in database. $existingHashForGuids = $entryDAO->listHashForFeedGuids($feed->id(), $newGuids); diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index d36c57deb..e380323c4 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -362,7 +362,9 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $newGuids = array(); foreach ($article_object['items'] as $item) { - $newGuids[] = $item['id']; + $guid = $item['id']; + $guid = filter_var($guid, FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + $newGuids[] = $guid; } // For this feed, check existing GUIDs already in database. $existingHashForGuids = $this->entryDAO->listHashForFeedGuids($feed->id(), $newGuids); diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 3959cb191..466e6f5a3 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -123,6 +123,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } $this->addEntryPrepared->bindParam(':id', $valuesTmp['id']); $valuesTmp['guid'] = substr($valuesTmp['guid'], 0, 760); + $valuesTmp['guid'] = filter_var($valuesTmp['guid'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); $this->addEntryPrepared->bindParam(':guid', $valuesTmp['guid']); $valuesTmp['title'] = substr($valuesTmp['title'], 0, 255); $this->addEntryPrepared->bindParam(':title', $valuesTmp['title']); @@ -130,6 +131,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $this->addEntryPrepared->bindParam(':author', $valuesTmp['author']); $this->addEntryPrepared->bindParam(':content', $valuesTmp['content']); $valuesTmp['link'] = substr($valuesTmp['link'], 0, 1023); + $valuesTmp['link'] = filter_var($valuesTmp['link'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); $this->addEntryPrepared->bindParam(':link', $valuesTmp['link']); $this->addEntryPrepared->bindParam(':date', $valuesTmp['date'], PDO::PARAM_INT); $valuesTmp['lastSeen'] = time(); @@ -190,6 +192,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $this->updateEntryPrepared->bindParam(':author', $valuesTmp['author']); $this->updateEntryPrepared->bindParam(':content', $valuesTmp['content']); $valuesTmp['link'] = substr($valuesTmp['link'], 0, 1023); + $valuesTmp['link'] = filter_var($valuesTmp['link'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); $this->updateEntryPrepared->bindParam(':link', $valuesTmp['link']); $this->updateEntryPrepared->bindParam(':date', $valuesTmp['date'], PDO::PARAM_INT); $valuesTmp['lastSeen'] = time(); @@ -689,6 +692,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { if (count($guids) < 1) { return array(); } + $guids = array_unique($guids); $sql = 'SELECT guid, ' . $this->sqlHexEncode('hash') . ' AS hex_hash FROM `' . $this->prefix . 'entry` WHERE id_feed=? AND guid IN (' . str_repeat('?,', count($guids) - 1). '?)'; $stm = $this->bd->prepare($sql); $values = array($id_feed); diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index c680d270c..33e19d750 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -5,6 +5,9 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $sql = 'INSERT INTO `' . $this->prefix . 'feed` (url, category, name, website, description, `lastUpdate`, priority, `httpAuth`, error, keep_history, ttl) VALUES(?, ?, ?, ?, ?, ?, 10, ?, 0, -2, -2)'; $stm = $this->bd->prepare($sql); + $valuesTmp['url'] = filter_var($valuesTmp['url'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + $valuesTmp['website'] = filter_var($valuesTmp['website'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + $values = array( substr($valuesTmp['url'], 0, 511), $valuesTmp['category'], @@ -55,6 +58,13 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } public function updateFeed($id, $valuesTmp) { + if (isset($valuesTmp['url'])) { + $valuesTmp['url'] = filter_var($valuesTmp['url'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + } + if (isset($valuesTmp['website'])) { + $valuesTmp['website'] = filter_var($valuesTmp['website'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + } + $set = ''; foreach ($valuesTmp as $key => $v) { $set .= $key . '=?, '; -- cgit v1.2.3 From 7f2b0439ec4158ee7d78571d60e9bcc995e87cac Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Thu, 20 Oct 2016 01:38:23 +0200 Subject: Extract function safe_ascii() --- app/Controllers/feedController.php | 4 +--- app/Controllers/importExportController.php | 4 +--- app/Models/EntryDAO.php | 6 +++--- app/Models/FeedDAO.php | 8 ++++---- lib/lib_rss.php | 3 +++ 5 files changed, 12 insertions(+), 13 deletions(-) (limited to 'app/Models/FeedDAO.php') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index d4a6c9955..ed3229687 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -314,9 +314,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if (count($entries) > 0) { $newGuids = array(); foreach ($entries as $entry) { - $guid = $entry->guid(); - $guid = filter_var($guid, FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); - $newGuids[] = $guid; + $newGuids[] = safe_ascii($entry->guid()); } // For this feed, check existing GUIDs already in database. $existingHashForGuids = $entryDAO->listHashForFeedGuids($feed->id(), $newGuids); diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index e380323c4..a1f789805 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -362,9 +362,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $newGuids = array(); foreach ($article_object['items'] as $item) { - $guid = $item['id']; - $guid = filter_var($guid, FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); - $newGuids[] = $guid; + $newGuids[] = safe_ascii($item['id']); } // For this feed, check existing GUIDs already in database. $existingHashForGuids = $this->entryDAO->listHashForFeedGuids($feed->id(), $newGuids); diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 466e6f5a3..4c6a9ea20 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -123,7 +123,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } $this->addEntryPrepared->bindParam(':id', $valuesTmp['id']); $valuesTmp['guid'] = substr($valuesTmp['guid'], 0, 760); - $valuesTmp['guid'] = filter_var($valuesTmp['guid'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + $valuesTmp['guid'] = safe_ascii($valuesTmp['guid']); $this->addEntryPrepared->bindParam(':guid', $valuesTmp['guid']); $valuesTmp['title'] = substr($valuesTmp['title'], 0, 255); $this->addEntryPrepared->bindParam(':title', $valuesTmp['title']); @@ -131,7 +131,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $this->addEntryPrepared->bindParam(':author', $valuesTmp['author']); $this->addEntryPrepared->bindParam(':content', $valuesTmp['content']); $valuesTmp['link'] = substr($valuesTmp['link'], 0, 1023); - $valuesTmp['link'] = filter_var($valuesTmp['link'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + $valuesTmp['link'] = safe_ascii($valuesTmp['link']); $this->addEntryPrepared->bindParam(':link', $valuesTmp['link']); $this->addEntryPrepared->bindParam(':date', $valuesTmp['date'], PDO::PARAM_INT); $valuesTmp['lastSeen'] = time(); @@ -192,7 +192,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $this->updateEntryPrepared->bindParam(':author', $valuesTmp['author']); $this->updateEntryPrepared->bindParam(':content', $valuesTmp['content']); $valuesTmp['link'] = substr($valuesTmp['link'], 0, 1023); - $valuesTmp['link'] = filter_var($valuesTmp['link'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + $valuesTmp['link'] = safe_ascii($valuesTmp['link']); $this->updateEntryPrepared->bindParam(':link', $valuesTmp['link']); $this->updateEntryPrepared->bindParam(':date', $valuesTmp['date'], PDO::PARAM_INT); $valuesTmp['lastSeen'] = time(); diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index 33e19d750..b21f19b66 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -5,8 +5,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { $sql = 'INSERT INTO `' . $this->prefix . 'feed` (url, category, name, website, description, `lastUpdate`, priority, `httpAuth`, error, keep_history, ttl) VALUES(?, ?, ?, ?, ?, ?, 10, ?, 0, -2, -2)'; $stm = $this->bd->prepare($sql); - $valuesTmp['url'] = filter_var($valuesTmp['url'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); - $valuesTmp['website'] = filter_var($valuesTmp['website'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + $valuesTmp['url'] = safe_ascii($valuesTmp['url']); + $valuesTmp['website'] = safe_ascii($valuesTmp['website']); $values = array( substr($valuesTmp['url'], 0, 511), @@ -59,10 +59,10 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { public function updateFeed($id, $valuesTmp) { if (isset($valuesTmp['url'])) { - $valuesTmp['url'] = filter_var($valuesTmp['url'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + $valuesTmp['url'] = safe_ascii($valuesTmp['url']); } if (isset($valuesTmp['website'])) { - $valuesTmp['website'] = filter_var($valuesTmp['website'], FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); + $valuesTmp['website'] = safe_ascii($valuesTmp['website']); } $set = ''; diff --git a/lib/lib_rss.php b/lib/lib_rss.php index b18512484..75046fd54 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -83,6 +83,9 @@ function checkUrl($url) { } } +function safe_ascii($text) { + return filter_var($text, FILTER_DEFAULT, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH); +} /** * Test if a given server address is publicly accessible. -- cgit v1.2.3 From fcb9280fc87c159539f5832ab35f174cd515654e Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 23 Oct 2016 13:37:48 +0200 Subject: CLI export ZIP export, OPML export. Corrected height of feeds select in Pafat theme. https://github.com/FreshRSS/FreshRSS/pull/1338 https://github.com/FreshRSS/FreshRSS/issues/1039 https://github.com/FreshRSS/FreshRSS/issues/1277 --- app/Controllers/importExportController.php | 84 +++++++++++++++++++----------- app/Models/FeedDAO.php | 7 +++ app/views/importExport/index.phtml | 2 +- cli/_cli.php | 4 +- cli/create-user.php | 14 ++--- cli/delete-user.php | 2 +- cli/export-opml-for-user.php | 24 +++++++++ cli/export-zip-for-user.php | 30 +++++++++++ cli/import-for-user.php | 3 +- p/themes/Pafat/pafat.css | 3 -- 10 files changed, 128 insertions(+), 45 deletions(-) create mode 100644 cli/export-opml-for-user.php create mode 100644 cli/export-zip-for-user.php (limited to 'app/Models/FeedDAO.php') diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index fbebb2a78..bb22ac739 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -522,26 +522,21 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { return $return; } - /** - * This action handles export action. - * - * This action must be reached by a POST request. - * - * Parameters are: - * - export_opml (default: false) - * - export_starred (default: false) - * - export_feeds (default: array()) a list of feed ids - */ - public function exportAction() { - if (!Minz_Request::isPost()) { - Minz_Request::forward(array('c' => 'importExport', 'a' => 'index'), true); - } + public function exportFile($export_opml = true, $export_starred = false, $export_feeds = array(), $maxFeedEntries = 50, $username = null) { + require_once(LIB_PATH . '/lib_opml.php'); - $this->view->_useLayout(false); + $this->catDAO = new FreshRSS_CategoryDAO($username); + $this->entryDAO = FreshRSS_Factory::createEntryDao($username); + $this->feedDAO = FreshRSS_Factory::createFeedDao($username); + + if ($export_feeds === true) { + //All feeds + $export_feeds = $this->feedDAO->listFeedsIds(); + } + if (!is_array($export_feeds)) { + $export_feeds = array(); + } - $export_opml = Minz_Request::param('export_opml', false); - $export_starred = Minz_Request::param('export_starred', false); - $export_feeds = Minz_Request::param('export_feeds', array()); $day = date('Y-m-d'); $export_files = array(); @@ -558,7 +553,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { if ($feed) { $filename = "feed_${day}_" . $feed->category() . '_' . $feed->id() . '.json'; - $export_files[$filename] = $this->generateEntries('feed', $feed); + $export_files[$filename] = $this->generateEntries('feed', $feed, $maxFeedEntries); } } @@ -566,18 +561,49 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { if ($nb_files > 1) { // If there are more than 1 file to export, we need a ZIP archive. try { - $this->exportZip($export_files); + $this->sendZip($export_files); } catch (Exception $e) { - # Oops, there is no ZIP extension! - Minz_Request::bad(_t('feedback.import_export.export_no_zip_extension'), - array('c' => 'importExport', 'a' => 'index')); + throw new FreshRSS_ZipMissing_Exception($e); } } elseif ($nb_files === 1) { // Only one file? Guess its type and export it. $filename = key($export_files); $type = self::guessFileType($filename); - $this->exportFile('freshrss_' . $filename, $export_files[$filename], $type); - } else { + $this->sendFile('freshrss_' . $filename, $export_files[$filename], $type); + } + return $nb_files; + } + + /** + * This action handles export action. + * + * This action must be reached by a POST request. + * + * Parameters are: + * - export_opml (default: false) + * - export_starred (default: false) + * - export_feeds (default: array()) a list of feed ids + */ + public function exportAction() { + if (!Minz_Request::isPost()) { + Minz_Request::forward(array('c' => 'importExport', 'a' => 'index'), true); + } + $this->view->_useLayout(false); + + $nb_files = 0; + try { + $nb_files = $this->exportFile( + Minz_Request::param('export_opml', false), + Minz_Request::param('export_starred', false), + Minz_Request::param('export_feeds', array()) + ); + } catch (FreshRSS_ZipMissing_Exception $zme) { + # Oops, there is no ZIP extension! + Minz_Request::bad(_t('feedback.import_export.export_no_zip_extension'), + array('c' => 'importExport', 'a' => 'index')); + } + + if ($nb_files < 1) { // Nothing to do... Minz_Request::forward(array('c' => 'importExport', 'a' => 'index'), true); } @@ -606,7 +632,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { * @param FreshRSS_Feed $feed feed of which we want to get entries. * @return string the JSON file content. */ - private function generateEntries($type, $feed = NULL) { + private function generateEntries($type, $feed = NULL, $maxFeedEntries = 50) { $this->view->categories = $this->catDAO->listCategories(); if ($type == 'starred') { @@ -621,7 +647,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $this->view->type = 'feed/' . $feed->id(); $this->view->entries = $this->entryDAO->listWhere( 'f', $feed->id(), FreshRSS_Entry::STATE_ALL, 'ASC', - FreshRSS_Context::$user_conf->posts_per_page + $maxFeedEntries ); $this->view->feed = $feed; } @@ -635,7 +661,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { * @param array $files list of files where key is filename and value the content. * @throws Exception if Zip extension is not loaded. */ - private function exportZip($files) { + private function sendZip($files) { if (!extension_loaded('zip')) { throw new Exception(); } @@ -667,7 +693,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { * @param string $type the file type (opml, json_feed or json_starred). * If equals to unknown, nothing happens. */ - private function exportFile($filename, $content, $type) { + private function sendFile($filename, $content, $type) { if ($type === 'unknown') { return; } diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index b21f19b66..68398efd5 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -212,6 +212,13 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable { } } + public function listFeedsIds() { + $sql = 'SELECT id FROM `' . $this->prefix . 'feed`'; + $stm = $this->bd->prepare($sql); + $stm->execute(); + return $stm->fetchAll(PDO::FETCH_COLUMN, 0); + } + public function listFeeds() { $sql = 'SELECT * FROM `' . $this->prefix . 'feed` ORDER BY name'; $stm = $this->bd->prepare($sql); diff --git a/app/views/importExport/index.phtml b/app/views/importExport/index.phtml index c0bc412c3..c5049e3ea 100644 --- a/app/views/importExport/index.phtml +++ b/app/views/importExport/index.phtml @@ -44,7 +44,7 @@ $select_args = ' size="' . min(10, count($this->feeds)) .'" multiple="multiple"'; } ?> - size="10"> '; ?> feeds as $feed) { ?> diff --git a/cli/_cli.php b/cli/_cli.php index d81d83d66..66506f07a 100644 --- a/cli/_cli.php +++ b/cli/_cli.php @@ -10,7 +10,7 @@ Minz_Configuration::register('system', DATA_PATH . '/config.php', DATA_PATH . '/config.default.php'); FreshRSS_Context::$system_conf = Minz_Configuration::get('system'); -Minz_Translate::init(); +Minz_Translate::init('en'); FreshRSS_Context::$isCli = true; @@ -39,6 +39,6 @@ function cliInitUser($username) { } function done($ok) { - echo 'Result: ', ($ok ? 'success' : 'fail'), ".\n"; + fwrite(STDERR, 'Result: ' . ($ok ? 'success' : 'fail') . "\n"); exit($ok ? 0 : 1); } diff --git a/cli/create-user.php b/cli/create-user.php index 387b503b6..243e65a35 100755 --- a/cli/create-user.php +++ b/cli/create-user.php @@ -4,16 +4,16 @@ require('_cli.php'); $options = getopt('', array( 'user:', - 'password::', - 'api-password::', - 'language::', - 'email::', - 'token::', + 'password:', + 'api-password:', + 'language:', + 'email:', + 'token:', )); if (empty($options['user'])) { - fail('Usage: ' . basename(__FILE__) . " --user=username --password='password' --api-password='api_password'" . - " --language=en --email=user@example.net --token='longRandomString'"); + fail('Usage: ' . basename(__FILE__) . " --user username --password 'password' --api-password 'api_password'" . + " --language en --email user@example.net --token 'longRandomString'"); } $username = $options['user']; if (!ctype_alnum($username)) { diff --git a/cli/delete-user.php b/cli/delete-user.php index da48103f7..6f0e86e17 100755 --- a/cli/delete-user.php +++ b/cli/delete-user.php @@ -7,7 +7,7 @@ $options = getopt('', array( )); if (empty($options['user'])) { - fail('Usage: ' . basename(__FILE__) . " --user=username"); + fail('Usage: ' . basename(__FILE__) . " --user username"); } $username = $options['user']; if (!ctype_alnum($username)) { diff --git a/cli/export-opml-for-user.php b/cli/export-opml-for-user.php new file mode 100644 index 000000000..bce4efd63 --- /dev/null +++ b/cli/export-opml-for-user.php @@ -0,0 +1,24 @@ +#!/usr/bin/php + /path/to/file.opml.xml'"); +} + +$username = cliInitUser($options['user']); + +fwrite(STDERR, 'FreshRSS exporting OPML for user “' . $username . "”…\n"); + +$importController = new FreshRSS_importExport_Controller(); + +$ok = false; +$ok = $importController->exportFile(true, false, array(), 0, $username); + +invalidateHttpCache($username); + +done($ok); diff --git a/cli/export-zip-for-user.php b/cli/export-zip-for-user.php new file mode 100644 index 000000000..f8d24238b --- /dev/null +++ b/cli/export-zip-for-user.php @@ -0,0 +1,30 @@ +#!/usr/bin/php + /path/to/file.zip'"); +} + +$username = cliInitUser($options['user']); + +fwrite(STDERR, 'FreshRSS exporting ZIP for user “' . $username . "”…\n"); + +$importController = new FreshRSS_importExport_Controller(); + +$ok = false; +try { + $ok = $importController->exportFile(true, true, true, + empty($options['max-feed-entries']) ? 100 : intval($options['max-feed-entries']), + $username); +} catch (FreshRSS_ZipMissing_Exception $zme) { + fail('FreshRSS error: Lacking php-zip extension!'); +} +invalidateHttpCache($username); + +done($ok); diff --git a/cli/import-for-user.php b/cli/import-for-user.php index 308786599..29084f062 100755 --- a/cli/import-for-user.php +++ b/cli/import-for-user.php @@ -5,11 +5,10 @@ require('_cli.php'); $options = getopt('', array( 'user:', 'filename:', - 'clear-existing', )); if (empty($options['user']) || empty($options['filename'])) { - fail('Usage: ' . basename(__FILE__) . " --user=username --filename='/path/to/file.ext' --clear-existing"); + fail('Usage: ' . basename(__FILE__) . " --user username --filename /path/to/file.ext"); } $username = cliInitUser($options['user']); diff --git a/p/themes/Pafat/pafat.css b/p/themes/Pafat/pafat.css index 5e46a63ca..abe808eab 100644 --- a/p/themes/Pafat/pafat.css +++ b/p/themes/Pafat/pafat.css @@ -48,9 +48,6 @@ input, select, textarea { vertical-align: middle; } -select{ - height:29px; -} option { padding: 0 .5em; } -- cgit v1.2.3