From cf8ee6bd48221e73b515922e75945e9aa763f907 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 1 Feb 2014 14:04:37 +0100 Subject: Rafraîchissement des flux en cache super rapide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Contribue à https://github.com/marienfressinaud/FreshRSS/issues/351#issuecomment-31755012 Les flux non-modifiés et en cache ne coûtent maintenant presque plus rien (304, ou délai de cache SimplePie non expiré), alors qu'avant toutes les entrées étaient rechargées --- app/Controllers/feedController.php | 57 +++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 23 deletions(-) (limited to 'app/Controllers/feedController.php') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index c40b3c400..cf9c993d5 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -191,36 +191,45 @@ class FreshRSS_feed_Controller extends Minz_ActionController { foreach ($feeds as $feed) { try { $url = $feed->url(); + $feedHistory = $feed->keepHistory(); + $feed->load(false); $entries = array_reverse($feed->entries()); //We want chronological order and SimplePie uses reverse order + $hasTransaction = false; - //For this feed, check last n entry GUIDs already in database - $existingGuids = array_fill_keys ($entryDAO->listLastGuidsByFeed ($feed->id (), count($entries) + 10), 1); - $useDeclaredDate = empty($existingGuids); + if (count($entries) > 0) { + //For this feed, check last n entry GUIDs already in database + $existingGuids = array_fill_keys ($entryDAO->listLastGuidsByFeed ($feed->id (), count($entries) + 10), 1); + $useDeclaredDate = empty($existingGuids); - $feedHistory = $feed->keepHistory(); - if ($feedHistory == -2) { //default - $feedHistory = $this->view->conf->keep_history_default; - } + if ($feedHistory == -2) { //default + $feedHistory = $this->view->conf->keep_history_default; + } + + $hasTransaction = true; + $feedDAO->beginTransaction(); - // On ne vérifie pas strictement que l'article n'est pas déjà en BDD - // La BDD refusera l'ajout car (id_feed, guid) doit être unique - $feedDAO->beginTransaction (); - foreach ($entries as $entry) { - $eDate = $entry->date (true); - if ((!isset ($existingGuids[$entry->guid ()])) && - (($feedHistory != 0) || ($eDate >= $date_min))) { - $values = $entry->toArray (); - //Use declared date at first import, otherwise use discovery date - $values['id'] = ($useDeclaredDate || $eDate < $date_min) ? - min(time(), $eDate) . uSecString() : - uTimeString(); - $values['is_read'] = $is_read; - $entryDAO->addEntry ($values); + // On ne vérifie pas strictement que l'article n'est pas déjà en BDD + // La BDD refusera l'ajout car (id_feed, guid) doit être unique + foreach ($entries as $entry) { + $eDate = $entry->date (true); + if ((!isset ($existingGuids[$entry->guid ()])) && + (($feedHistory != 0) || ($eDate >= $date_min))) { + $values = $entry->toArray (); + //Use declared date at first import, otherwise use discovery date + $values['id'] = ($useDeclaredDate || $eDate < $date_min) ? + min(time(), $eDate) . uSecString() : + uTimeString(); + $values['is_read'] = $is_read; + $entryDAO->addEntry ($values); + } } } if (($feedHistory >= 0) && (rand(0, 30) === 1)) { + if (!$hasTransaction) { + $feedDAO->beginTransaction(); + } $nb = $feedDAO->cleanOldEntries ($feed->id (), $date_min, max($feedHistory, count($entries) + 10)); if ($nb > 0) { Minz_Log::record ($nb . ' old entries cleaned in feed [' . $feed->url() . ']', Minz_Log::DEBUG); @@ -228,8 +237,10 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } // on indique que le flux vient d'être mis à jour en BDD - $feedDAO->updateLastUpdate ($feed->id ()); - $feedDAO->commit (); + $feedDAO->updateLastUpdate ($feed->id (), 0, $hasTransaction); + if ($hasTransaction) { + $feedDAO->commit(); + } $flux_update++; if ($feed->url() !== $url) { //URL has changed (auto-discovery) $feedDAO->updateFeed($feed->id(), array('url' => $feed->url())); -- cgit v1.2.3 From 575d0002cc3839760f0a389eb4af8cd7d23b74c6 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 4 Feb 2014 19:07:33 +0100 Subject: Rafraîchissement plus rapide en évitant une requête MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Contribue à https://github.com/marienfressinaud/FreshRSS/issues/351 --- app/Controllers/feedController.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'app/Controllers/feedController.php') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index cf9c993d5..918f007fd 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -14,15 +14,15 @@ class FreshRSS_feed_Controller extends Minz_ActionController { ); } } - - $this->catDAO = new FreshRSS_CategoryDAO (); - $this->catDAO->checkDefault (); } public function addAction () { @set_time_limit(300); if (Minz_Request::isPost ()) { + $this->catDAO = new FreshRSS_CategoryDAO (); + $this->catDAO->checkDefault (); + $url = Minz_Request::param ('url_rss'); $cat = Minz_Request::param ('category', false); if ($cat === false) { @@ -309,6 +309,9 @@ class FreshRSS_feed_Controller extends Minz_ActionController { public function massiveImportAction () { @set_time_limit(300); + $this->catDAO = new FreshRSS_CategoryDAO (); + $this->catDAO->checkDefault (); + $entryDAO = new FreshRSS_EntryDAO (); $feedDAO = new FreshRSS_FeedDAO (); -- cgit v1.2.3 From 7fa620cce54f7fd187c477df080ebed33c818b07 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sat, 8 Feb 2014 15:57:19 +0100 Subject: SimplePie Fuite de mémoire PHP 5.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/marienfressinaud/FreshRSS/issues/415 http://simplepie.org/wiki/faq/i_m_getting_memory_leaks (Pas testé) --- app/Controllers/feedController.php | 1 + app/Models/Feed.php | 4 ++++ 2 files changed, 5 insertions(+) (limited to 'app/Controllers/feedController.php') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 918f007fd..056ed96b5 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -246,6 +246,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feedDAO->updateFeed($feed->id(), array('url' => $feed->url())); } $feed->faviconPrepare(); + unset($feed); } catch (FreshRSS_Feed_Exception $e) { Minz_Log::record ($e->getMessage (), Minz_Log::NOTICE); $feedDAO->updateLastUpdate ($feed->id (), 1); diff --git a/app/Models/Feed.php b/app/Models/Feed.php index c71fb41ae..e94ae2b3a 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -224,6 +224,9 @@ class FreshRSS_Feed extends Minz_Model { syslog(LOG_DEBUG, 'FreshRSS use cache for ' . $subscribe_url); $this->entries = array(); } + + $feed->__destruct(); //http://simplepie.org/wiki/faq/i_m_getting_memory_leaks + unset($feed); } } } @@ -273,6 +276,7 @@ class FreshRSS_Feed extends Minz_Model { $entry->loadCompleteContent($this->pathEntries()); $entries[] = $entry; + unset($item); } $this->entries = $entries; -- cgit v1.2.3 From a6b7243b1634b50bdf9852045e2b31133864b4f8 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 11 Feb 2014 15:58:13 +0100 Subject: un ->color oublié #2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Autre fichier oublié dans le patch précédent :-/ https://github.com/marienfressinaud/FreshRSS/issues/295 --- app/Controllers/feedController.php | 1 - 1 file changed, 1 deletion(-) (limited to 'app/Controllers/feedController.php') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 056ed96b5..ddbb62e24 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -431,7 +431,6 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $values = array ( 'id' => $cat->id (), 'name' => $cat->name (), - 'color' => $cat->color () ); $catDAO->addCategory ($values); } -- cgit v1.2.3 From d48f612c437009069593978fe43833fe2c7d74ea Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 11 Feb 2014 21:26:09 +0100 Subject: Bug variable $feed utilisée en dehors de la boucle foreach MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/marienfressinaud/FreshRSS/issues/415 https://github.com/marienfressinaud/FreshRSS/issues/420 --- app/Controllers/feedController.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'app/Controllers/feedController.php') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index ddbb62e24..55e8f76cf 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -246,12 +246,13 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feedDAO->updateFeed($feed->id(), array('url' => $feed->url())); } $feed->faviconPrepare(); - unset($feed); } catch (FreshRSS_Feed_Exception $e) { Minz_Log::record ($e->getMessage (), Minz_Log::NOTICE); $feedDAO->updateLastUpdate ($feed->id (), 1); } + unset($feed); + // On arrête à 10 flux pour ne pas surcharger le serveur // sauf si le paramètre $force est à vrai $i++; @@ -263,6 +264,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $url = array (); if ($flux_update === 1) { // on a mis un seul flux à jour + $feed = reset ($feeds); $notif = array ( 'type' => 'good', 'content' => Minz_Translate::t ('feed_actualized', $feed->name ()) -- cgit v1.2.3 From 0cabd1f50dd7d1cf0941a50139e6fbeed6825b4d Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 11 Feb 2014 21:48:10 +0100 Subject: Mutex par flux pour les actualisations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Contribue à https://github.com/marienfressinaud/FreshRSS/issues/351 Nouvelle constante TMP_PATH comme répertoire pour stocker des fichiers temporaires (si possible en mémoire et non sur disque, tel tmpfs pour /tmp sur certaines distributions Linux) Requiert PHP 5.2.1+ (contre 5.2.0 auparavant) pour le `sys_get_temp_dir()` --- README.md | 2 +- app/Controllers/feedController.php | 5 +++++ app/Models/Feed.php | 18 ++++++++++++++++++ app/actualize_script.php | 19 ------------------- constants.php | 2 ++ p/i/install.php | 5 +++-- 6 files changed, 29 insertions(+), 22 deletions(-) (limited to 'app/Controllers/feedController.php') diff --git a/README.md b/README.md index 247d08799..1ed6d8f82 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Privilégiez pour cela des demandes sur GitHub * Serveur modeste, par exemple sous Linux ou Windows * Fonctionne même sur un Raspberry Pi avec des temps de réponse < 1s (testé sur 150 flux, 22k articles, soit 32Mo de données partiellement compressées) * Serveur Web Apache2 ou Nginx (non testé sur les autres) -* PHP 5.2+ (PHP 5.3.7+ recommandé) +* PHP 5.2.1+ (PHP 5.3.7+ recommandé) * Requis : [PDO_MySQL](http://php.net/pdo-mysql), [cURL](http://php.net/curl), [LibXML](http://php.net/xml), [PCRE](http://php.net/pcre), [ctype](http://php.net/ctype) * Recommandés : [JSON](http://php.net/json), [zlib](http://php.net/zlib), [mbstring](http://php.net/mbstring), [iconv](http://php.net/iconv) * MySQL 5.0.3+ (ou SQLite 3.7.4+ à venir) diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 55e8f76cf..61bfc5919 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -189,6 +189,10 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $flux_update = 0; $is_read = $this->view->conf->mark_when['reception'] ? 1 : 0; foreach ($feeds as $feed) { + if (!$feed->lock()) { + Minz_Log::record('Feed already being actualized: ' . $feed->url(), Minz_Log::NOTICE); + continue; + } try { $url = $feed->url(); $feedHistory = $feed->keepHistory(); @@ -251,6 +255,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feedDAO->updateLastUpdate ($feed->id (), 1); } + $feed->unlock(); unset($feed); // On arrête à 10 flux pour ne pas surcharger le serveur diff --git a/app/Models/Feed.php b/app/Models/Feed.php index e94ae2b3a..73f9c32fb 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -281,4 +281,22 @@ class FreshRSS_Feed extends Minz_Model { $this->entries = $entries; } + + function lock() { + $lock = TMP_PATH . '/' . md5(Minz_Configuration::salt() . $this->url) . '.freshrss.lock'; + if (file_exists($lock) && ((time() - @filemtime($lock)) > 3600)) { + @unlink($lock); + } + if (($handle = @fopen($lock, 'x')) === false) { + return false; + } + //register_shutdown_function('unlink', $lock); + @fclose($handle); + return true; + } + + function unlock() { + $lock = TMP_PATH . '/' . md5(Minz_Configuration::salt() . $this->url) . '.freshrss.lock'; + @unlink($lock); + } } diff --git a/app/actualize_script.php b/app/actualize_script.php index bef9bd218..8d81e0189 100755 --- a/app/actualize_script.php +++ b/app/actualize_script.php @@ -1,24 +1,5 @@ -$lock = DATA_PATH . '/actualize.lock.txt'; -if (file_exists($lock) && ((time() - @filemtime($lock)) > 3600)) { - @unlink($lock); -} -if (($handle = @fopen($lock, 'x')) === false) { - syslog(LOG_NOTICE, 'FreshRSS actualize already running?'); - if (defined('STDERR')) { - fwrite(STDERR, 'FreshRSS actualize already running?' . "\n"); - } - echo 'FreshRSS actualize already running?', "\n"; - return; -} -register_shutdown_function('unlink', $lock); -//Could use http://php.net/function.pcntl-signal.php to catch interruptions -@fclose($handle); -// - require(LIB_PATH . '/lib_rss.php'); //Includes class autoloader session_cache_limiter(''); diff --git a/constants.php b/constants.php index a7c96f47b..4818f1565 100644 --- a/constants.php +++ b/constants.php @@ -15,3 +15,5 @@ define('FRESHRSS_PATH', dirname(__FILE__)); define('LIB_PATH', FRESHRSS_PATH . '/lib'); define('APP_PATH', FRESHRSS_PATH . '/app'); + +define('TMP_PATH', sys_get_temp_dir()); diff --git a/p/i/install.php b/p/i/install.php index bb49e3fdb..4b0b1d194 100644 --- a/p/i/install.php +++ b/p/i/install.php @@ -548,8 +548,9 @@ function checkStep0 () { 'all' => $language ? 'ok' : 'ko' ); } + function checkStep1 () { - $php = version_compare (PHP_VERSION, '5.2.0') >= 0; + $php = version_compare (PHP_VERSION, '5.2.1') >= 0; $minz = file_exists (LIB_PATH . '/Minz'); $curl = extension_loaded ('curl'); $pdo = extension_loaded ('pdo_mysql'); @@ -721,7 +722,7 @@ function printStep1 () {

-

+

-- cgit v1.2.3 From 11c4c733d6971a977748f874b4976044bab7afc0 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 11 Feb 2014 23:04:12 +0100 Subject: Bug mise à jour favicons dans le cas de flux invalides MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Controllers/configureController.php | 2 +- app/Controllers/feedController.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'app/Controllers/feedController.php') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index c0665d241..ad8bc546a 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -114,7 +114,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { if ($feedDAO->updateFeed ($id, $values)) { $this->view->flux->_category ($cat); - + $this->view->flux->faviconPrepare(); $notif = array ( 'type' => 'good', 'content' => Minz_Translate::t ('feed_updated') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 61bfc5919..d98c77558 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -249,12 +249,12 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if ($feed->url() !== $url) { //URL has changed (auto-discovery) $feedDAO->updateFeed($feed->id(), array('url' => $feed->url())); } - $feed->faviconPrepare(); } catch (FreshRSS_Feed_Exception $e) { Minz_Log::record ($e->getMessage (), Minz_Log::NOTICE); $feedDAO->updateLastUpdate ($feed->id (), 1); } + $feed->faviconPrepare(); $feed->unlock(); unset($feed); -- cgit v1.2.3 From 178af19fb0e7c13015e991593feea6a5f4aafcc0 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 13 Feb 2014 21:01:12 +0100 Subject: Add possibility to open notification in JavaScript + new message Notifications can be opened directly in JavaScript Class .notification is now id #notification New message when there is no feed to refresh See 06abbd02c2d10934155b2464f73d8ecdb2a68de1 (comments) --- app/Controllers/feedController.php | 4 ++-- app/i18n/en.php | 1 + app/i18n/fr.php | 1 + app/layout/layout.phtml | 11 ++++++--- app/views/javascript/actualize.phtml | 1 + p/scripts/main.js | 46 +++++++++++++++++++++++++++++------- p/themes/Dark/freshrss.css | 15 +++++++----- p/themes/Flat/freshrss.css | 15 +++++++----- p/themes/Origine/freshrss.css | 11 +++++---- 9 files changed, 75 insertions(+), 30 deletions(-) (limited to 'app/Controllers/feedController.php') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index d98c77558..264607216 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -283,8 +283,8 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } else { // aucun flux n'a été mis à jour, oups $notif = array ( - 'type' => 'bad', - 'content' => Minz_Translate::t ('no_feed_actualized') + 'type' => 'good', + 'content' => Minz_Translate::t ('no_feed_to_refresh') ); } diff --git a/app/i18n/en.php b/app/i18n/en.php index af051673d..369853610 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -248,6 +248,7 @@ return array ( 'rss_feeds_of' => 'RSS feed of %s', 'refresh' => 'Refresh', + 'no_feed_to_refresh' => 'There is no feed to refresh…', 'today' => 'Today', 'yesterday' => 'Yesterday', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 5dc184aa3..275c3b1d8 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -248,6 +248,7 @@ return array ( 'rss_feeds_of' => 'Flux RSS de %s', 'refresh' => 'Actualisation', + 'no_feed_to_refresh' => 'Il n’y a aucun flux à actualiser…', 'today' => 'Aujourd’hui', 'yesterday' => 'Hier', diff --git a/app/layout/layout.phtml b/app/layout/layout.phtml index d6a1737ee..1501df3c3 100644 --- a/app/layout/layout.phtml +++ b/app/layout/layout.phtml @@ -36,13 +36,18 @@ notification)) { + $msg = $this->notification['content']; + $status = $this->notification['type']; + invalidateHttpCache(); + } ?> -
- notification['content']; ?> +
+
- diff --git a/app/views/javascript/actualize.phtml b/app/views/javascript/actualize.phtml index 58c3b7c8f..a2b076ea8 100644 --- a/app/views/javascript/actualize.phtml +++ b/app/views/javascript/actualize.phtml @@ -24,6 +24,7 @@ function updateProgressBar(i) { function updateFeeds() { if (feed_count === 0) { + openNotification("", "good"); return; } initProgressBar(true); diff --git a/p/scripts/main.js b/p/scripts/main.js index e94df2a39..88ef670cd 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -665,23 +665,51 @@ function init_actualize() { } } + +// +var notification = null, + notification_interval = null, + notification_working = false; + +function openNotification(msg, status) { + if (notification_working === true) { + return false; + } + + notification_working = true; + + notification.removeClass(); + notification.addClass(status); + notification.find(".msg").html(msg); + notification.fadeIn(300); + + notification_interval = window.setInterval(closeNotification, 4000); +} + function closeNotification() { - $(".notification").fadeOut(600, function () { - $(".notification").remove(); + notification.fadeOut(600, function() { + notification.removeClass(); + notification.addClass('closed'); + + window.clearInterval(notification_interval); + notification_working = false; }); } function init_notifications() { - var notif = $(".notification"); - if (notif.length > 0) { - window.setInterval(closeNotification, 4000); + notification = $("#notification"); - notif.find("a.close").click(function () { - closeNotification(); - return false; - }); + notification.find("a.close").click(function () { + closeNotification(); + return false; + }); + + if (notification.find(".msg").html().length > 0) { + notification_working = true; + notification_interval = window.setInterval(closeNotification, 4000); } } +// function refreshUnreads() { $.getJSON('./?c=javascript&a=nbUnreadsPerFeed').done(function (data) { diff --git a/p/themes/Dark/freshrss.css b/p/themes/Dark/freshrss.css index e54a0eadd..380dee877 100644 --- a/p/themes/Dark/freshrss.css +++ b/p/themes/Dark/freshrss.css @@ -558,7 +558,7 @@ } /*** NOTIFICATION ***/ -.notification { +#notification { position: absolute; top: 10px; left: 25%; right: 25%; @@ -573,13 +573,16 @@ font-weight: bold; z-index: 10; } - .notification.good { + #notification.closed { + display: none; + } + #notification.good { border:1px solid #f4f899; } - .notification.bad { + #notification.bad { border:1px solid #f4a899; } - .notification a.close { + #notification a.close { display: inline-block; width: 16px; height: 16px; @@ -590,10 +593,10 @@ border-radius: 50px; line-height: 16px; } - .notification.good a.close{ + #notification.good a.close{ border:1px solid #f4f899; } - .notification.bad a.close{ + #notification.bad a.close{ border:1px solid #f4a899; } diff --git a/p/themes/Flat/freshrss.css b/p/themes/Flat/freshrss.css index 19f5967ea..edd67e17c 100644 --- a/p/themes/Flat/freshrss.css +++ b/p/themes/Flat/freshrss.css @@ -561,7 +561,7 @@ body { } /*** NOTIFICATION ***/ -.notification { +#notification { position: absolute; top: 10px; left: 25%; right: 25%; @@ -575,15 +575,18 @@ body { font-weight: bold; z-index: 10; } - .notification.good { + #notification.closed { + display: none; + } + #notification.good { background: #1abc9c; color: #fff; } - .notification.bad { + #notification.bad { background: #e74c3c; color: #fff; } - .notification a.close { + #notification a.close { display: inline-block; width: 16px; height: 16px; @@ -593,10 +596,10 @@ body { border-radius: 3px; line-height: 16px; } - .notification.good a.close { + #notification.good a.close { background: #1abc9c; } - .notification.bad a.close { + #notification.bad a.close { background: #e74c3c; } diff --git a/p/themes/Origine/freshrss.css b/p/themes/Origine/freshrss.css index 85a23140c..80fac05cd 100644 --- a/p/themes/Origine/freshrss.css +++ b/p/themes/Origine/freshrss.css @@ -569,7 +569,7 @@ } /*** NOTIFICATION ***/ -.notification { +#notification { position: absolute; top: 10px; left: 25%; right: 25%; @@ -584,13 +584,16 @@ font-weight: bold; z-index: 10; } - .notification.good { + #notification.closed { + display: none; + } + #notification.good { background: #f4f899; } - .notification.bad { + #notification.bad { background: #f4a899; } - .notification a.close { + #notification a.close { display: inline-block; width: 16px; height: 16px; -- cgit v1.2.3 From 4dd673157b05fea5fe3643f16e22d01bbf005fe9 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 13 Feb 2014 21:45:25 +0100 Subject: Add possibility to anonymous to refresh feeds Obviously, it's optional! (and deactivate by default) Need some more tests? See #351 --- app/Controllers/feedController.php | 4 +++- app/Controllers/usersController.php | 7 ++++++- app/i18n/en.php | 1 + app/i18n/fr.php | 1 + app/layout/nav_menu.phtml | 4 +++- app/views/configure/users.phtml | 10 ++++++++++ lib/Minz/Configuration.php | 19 ++++++++++++++++++- 7 files changed, 42 insertions(+), 4 deletions(-) (limited to 'app/Controllers/feedController.php') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 264607216..7114fc196 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -7,7 +7,9 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $token_param = Minz_Request::param ('token', ''); $token_is_ok = ($token != '' && $token == $token_param); $action = Minz_Request::actionName (); - if (!($token_is_ok && $action === 'actualize')) { + if (!(($token_is_ok || Minz_Configuration::allowAnonymousRefresh()) && + $action === 'actualize') + ) { Minz_Error::error ( 403, array ('error' => array (Minz_Translate::t ('access_denied'))) diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index 8314b75fc..bb4f34c5e 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -54,11 +54,16 @@ class FreshRSS_users_Controller extends Minz_ActionController { $anon = Minz_Request::param('anon_access', false); $anon = ((bool)$anon) && ($anon !== 'no'); + $anon_refresh = Minz_Request::param('anon_refresh', false); + $anon_refresh = ((bool)$anon_refresh) && ($anon_refresh !== 'no'); $auth_type = Minz_Request::param('auth_type', 'none'); if ($anon != Minz_Configuration::allowAnonymous() || - $auth_type != Minz_Configuration::authType()) { + $auth_type != Minz_Configuration::authType() || + $anon_refresh != Minz_Configuration::allowAnonymousRefresh()) { + Minz_Configuration::_authType($auth_type); Minz_Configuration::_allowAnonymous($anon); + Minz_Configuration::_allowAnonymousRefresh($anon_refresh); $ok &= Minz_Configuration::writeFile(); } } diff --git a/app/i18n/en.php b/app/i18n/en.php index 369853610..fd51eb1ca 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -175,6 +175,7 @@ return array ( 'password_form' => 'Password
(for the Web-form login method)', 'persona_connection_email' => 'Login mail address
(for Mozilla Persona)', 'allow_anonymous' => 'Allow anonymous reading of the articles of the default user (%s)', + 'allow_anonymous_refresh' => 'Allow anonymous refresh of the articles', 'auth_token' => 'Authentication token', 'explain_token' => 'Allows to access RSS output of the default user without authentication.
%s?output=rss&token=%s', 'login_configuration' => 'Login', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 275c3b1d8..17e26f493 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -175,6 +175,7 @@ return array ( 'default_user' => 'Nom de l’utilisateur par défaut (16 caractères alphanumériques maximum)', 'persona_connection_email' => 'Adresse courriel de connexion
(pour Mozilla Persona)', 'allow_anonymous' => 'Autoriser la lecture anonyme des articles de l’utilisateur par défaut (%s)', + 'allow_anonymous_refresh' => 'Autoriser le rafraîchissement anonyme des flux', 'auth_token' => 'Jeton d’identification', 'explain_token' => 'Permet d’accéder à la sortie RSS de l’utilisateur par défaut sans besoin de s’authentifier.
%s?output=rss&token=%s', 'login_configuration' => 'Identification', diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml index c807e6dd5..98064a6f7 100644 --- a/app/layout/nav_menu.phtml +++ b/app/layout/nav_menu.phtml @@ -6,9 +6,11 @@ - loginOk) { ?> + loginOk || Minz_Configuration::allowAnonymousRefresh()) { ?> + + loginOk) { ?>
+
+
+ +
+
+
diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php index 572b9984d..b3de9e39e 100644 --- a/lib/Minz/Configuration.php +++ b/lib/Minz/Configuration.php @@ -52,6 +52,7 @@ class Minz_Configuration { private static $delay_cache = 3600; private static $default_user = ''; private static $allow_anonymous = false; + private static $allow_anonymous_refresh = false; private static $auth_type = 'none'; private static $db = array ( @@ -118,6 +119,9 @@ class Minz_Configuration { public static function allowAnonymous() { return self::$allow_anonymous; } + public static function allowAnonymousRefresh() { + return self::$allow_anonymous_refresh; + } public static function authType() { return self::$auth_type; } @@ -131,6 +135,9 @@ class Minz_Configuration { public static function _allowAnonymous($allow = false) { self::$allow_anonymous = ((bool)$allow) && self::canLogIn(); } + public static function _allowAnonymousRefresh($allow = false) { + self::$allow_anonymous_refresh = ((bool)$allow) && self::allowAnonymous(); + } public static function _authType($value) { $value = strtolower($value); switch ($value) { @@ -170,6 +177,7 @@ class Minz_Configuration { 'title' => self::$title, 'default_user' => self::$default_user, 'allow_anonymous' => self::$allow_anonymous, + 'allow_anonymous_refresh' => self::$allow_anonymous_refresh, 'auth_type' => self::$auth_type, ), 'db' => self::$db, @@ -276,7 +284,16 @@ class Minz_Configuration { self::_authType($general['auth_type']); } if (isset ($general['allow_anonymous'])) { - self::$allow_anonymous = ((bool)($general['allow_anonymous'])) && ($general['allow_anonymous'] !== 'no'); + self::$allow_anonymous = ( + ((bool)($general['allow_anonymous'])) && + ($general['allow_anonymous'] !== 'no') + ); + } + if (isset ($general['allow_anonymous_refresh'])) { + self::$allow_anonymous_refresh = ( + ((bool)($general['allow_anonymous_refresh'])) && + ($general['allow_anonymous_refresh'] !== 'no') + ); } // Base de données -- cgit v1.2.3 From a34941f41875bcc9d260c8dfcf9d44a00f835bc9 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 15 Feb 2014 11:43:07 +0100 Subject: Improve code redirection for indexController - add comments - forward request is done in the controller (no Minz_Request::forward() in the view, please) - "soft" forward to the login form (no need of 302) - show a 403 page (no authenticated) for rss output when token is wrong --- app/Controllers/feedController.php | 5 ++++- app/Controllers/indexController.php | 11 ++++++++++- app/views/index/index.phtml | 19 +++++-------------- 3 files changed, 19 insertions(+), 16 deletions(-) (limited to 'app/Controllers/feedController.php') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 7114fc196..c718fcd5c 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -3,7 +3,10 @@ class FreshRSS_feed_Controller extends Minz_ActionController { public function firstAction () { if (!$this->view->loginOk) { - $token = $this->view->conf->token; //TODO: check the token logic again, and if it is still needed + // Token is useful in the case that anonymous refresh is forbidden + // and CRON task cannot be used with php command so the user can + // set a CRON task to refresh his feeds by using token inside url + $token = $this->view->conf->token; $token_param = Minz_Request::param ('token', ''); $token_is_ok = ($token != '' && $token == $token_param); $action = Minz_Request::actionName (); diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index af08edb46..a680c914a 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -11,7 +11,16 @@ class FreshRSS_index_Controller extends Minz_ActionController { if (!$this->view->loginOk && !Minz_Configuration::allowAnonymous()) { $token_param = Minz_Request::param ('token', ''); $token_is_ok = ($token != '' && $token === $token_param); - if (!($output === 'rss' && $token_is_ok)) { + if ($output === 'rss' && !$token_is_ok) { + Minz_Error::error ( + 403, + array ('error' => array (Minz_Translate::t ('access_denied'))) + ); + return; + } elseif ($output !== 'rss') { + // "hard" redirection is not required, just ask dispatcher to + // forward to the login form without 302 redirection + Minz_Request::forward(array('c' => 'index', 'a' => 'formLogin')); return; } } diff --git a/app/views/index/index.phtml b/app/views/index/index.phtml index 1810a95b3..78271291e 100644 --- a/app/views/index/index.phtml +++ b/app/views/index/index.phtml @@ -3,9 +3,7 @@ $output = Minz_Request::param ('output', 'normal'); if ($this->loginOk || Minz_Configuration::allowAnonymous()) { - if ($output === 'normal') { - $this->renderHelper ('view/normal_view'); - } elseif ($output === 'rss') { + if ($output === 'rss') { $this->renderHelper ('view/rss_view'); } elseif ($output === 'reader') { $this->renderHelper ('view/reader_view'); @@ -17,16 +15,9 @@ if ($this->loginOk || Minz_Configuration::allowAnonymous()) { $this->renderHelper ('view/normal_view'); } } elseif ($output === 'rss') { - // TODO: verification of token and redirection must be done in the - // controller, not in the view - $token = $this->conf->token; - $token_param = Minz_Request::param ('token', ''); - $token_is_ok = ($token != '' && $token == $token_param); - if ($token_is_ok) { - $this->renderHelper ('view/rss_view'); - } else { - Minz_Request::forward(array('c' => 'index', 'a' => 'formLogin'), true); - } + // token has already been checked in the controller so we can show the view + $this->renderHelper ('view/rss_view'); } else { - Minz_Request::forward(array('c' => 'index', 'a' => 'formLogin'), true); + // Normally, it should not happen, but log it anyway + Minz_Log::record ('Something is wrong in ' . __FILE__ . ' line ' . __LINE__, Minz_Log::ERROR); } -- cgit v1.2.3 From 3083af6288f23ba6986232798fde67b91517f287 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sun, 9 Mar 2014 21:45:25 -0400 Subject: Enhance feed adding popup I added a new option in the category select. It allows the user to add dynamically a new category and add the feed to the newly created category. See #356 --- app/Controllers/feedController.php | 8 ++++++++ app/layout/aside_feed.phtml | 5 +++++ p/scripts/main.js | 13 +++++++++++++ 3 files changed, 26 insertions(+) (limited to 'app/Controllers/feedController.php') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index c718fcd5c..9996725e4 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -30,6 +30,14 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $url = Minz_Request::param ('url_rss'); $cat = Minz_Request::param ('category', false); + if ($cat === 'nc') { + $new_cat = Minz_Request::param ('new_category'); + if (empty($new_cat['name'])) { + $cat = false; + } else { + $cat = $this->catDAO->addCategory($new_cat); + } + } if ($cat === false) { $def_cat = $this->catDAO->getDefault (); $cat = $def_cat->id (); diff --git a/app/layout/aside_feed.phtml b/app/layout/aside_feed.phtml index e324b15bd..6f3cdafb2 100644 --- a/app/layout/aside_feed.phtml +++ b/app/layout/aside_feed.phtml @@ -20,9 +20,14 @@ name (); ?> + + +
  • diff --git a/p/scripts/main.js b/p/scripts/main.js index b69ac0a2a..3a4d4e4fb 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -986,6 +986,18 @@ function init_share_observers() { }); }; +function init_feed_observers() { + $('select[id="category"]').on('change', function(){ + var detail = $(this).parent('li').next('li'); + if ($(this).val() === 'nc') { + detail.show(); + detail.find('input').focus(); + } else { + detail.hide(); + } + }); +}; + function init_all() { if (!(window.$ && window.url_freshrss && ((!full_lazyload) || $.fn.lazyload))) { if (window.console) { @@ -1017,6 +1029,7 @@ function init_all() { window.setInterval(refreshUnreads, 120000); } else { init_share_observers(); + init_feed_observers(); } if (window.console) { -- cgit v1.2.3 From 608b3a8656d986ff177e97e968256bcbf6785c13 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 10 Mar 2014 20:16:41 +0100 Subject: Link to logs in case of error when adding new feed https://github.com/marienfressinaud/FreshRSS/issues/453 --- app/Controllers/feedController.php | 4 ++-- app/i18n/en.php | 2 +- app/i18n/fr.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'app/Controllers/feedController.php') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 9996725e4..16516ad39 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -136,7 +136,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { Minz_Log::record ($e->getMessage (), Minz_Log::WARNING); $notif = array ( 'type' => 'bad', - 'content' => Minz_Translate::t ('internal_problem_feed') + 'content' => Minz_Translate::t ('internal_problem_feed', Minz_Url::display(array('a' => 'logs'))) ); Minz_Session::_param ('notification', $notif); } catch (Minz_FileNotExistException $e) { @@ -144,7 +144,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { Minz_Log::record ($e->getMessage (), Minz_Log::ERROR); $notif = array ( 'type' => 'bad', - 'content' => Minz_Translate::t ('internal_problem_feed') + 'content' => Minz_Translate::t ('internal_problem_feed', Minz_Url::display(array('a' => 'logs'))) ); Minz_Session::_param ('notification', $notif); } diff --git a/app/i18n/en.php b/app/i18n/en.php index 69247165f..7f95500ad 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -89,7 +89,7 @@ return array ( 'already_subscribed' => 'You have already subscribed to %s', 'feed_added' => 'RSS feed %s has been added', 'feed_not_added' => '%s could not be added', - 'internal_problem_feed' => 'The RSS feed could not be added. Check FressRSS logs for details.', + 'internal_problem_feed' => 'The RSS feed could not be added. Check FressRSS logs for details.', 'invalid_url' => 'URL %s is invalid', 'feed_actualized' => '%s has been updated', 'n_feeds_actualized' => '%d feeds have been updated', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index e364ed130..91daa4f51 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -89,7 +89,7 @@ return array ( 'already_subscribed' => 'Vous êtes déjà abonné à %s', 'feed_added' => 'Le flux %s a bien été ajouté', 'feed_not_added' => '%s n’a pas pu être ajouté', - 'internal_problem_feed' => 'Le flux n’a pas pu être ajouté. Consulter les logs de FreshRSS pour plus de détails.', + 'internal_problem_feed' => 'Le flux n’a pas pu être ajouté. Consulter les logs de FreshRSS pour plus de détails.', 'invalid_url' => 'L’url %s est invalide', 'feed_actualized' => '%s a été mis à jour', 'n_feeds_actualized' => '%d flux ont été mis à jour', -- cgit v1.2.3 From d464833922e9cc00948698aed0a2af1f0b55e101 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 28 Mar 2014 22:13:42 +0100 Subject: Improve import / export functionnality It is not finished yet and does not even work at all!! - ZIP archive can be uploaded - Entries are imported from starred.json and feed*.json but not added in DB for the moment. - Fix export (add author, id -> guid, content -> content.content and add alternate) See https://github.com/marienfressinaud/FreshRSS/issues/163 --- app/Controllers/feedController.php | 2 + app/Controllers/importExportController.php | 260 ++++++++++++++++++++++++----- app/views/helpers/export/articles.phtml | 11 +- 3 files changed, 228 insertions(+), 45 deletions(-) (limited to 'app/Controllers/feedController.php') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 16516ad39..43435d99d 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -328,6 +328,8 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } public function massiveImportAction () { + # TODO: this function has moved to importExportController.php + # I keep it for the moment but should be deleted in a near future. @set_time_limit(300); $this->catDAO = new FreshRSS_CategoryDAO (); diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 51f0708fd..6194ce214 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -3,21 +3,22 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { public function firstAction() { if (!$this->view->loginOk) { - Minz_Error::error ( + Minz_Error::error( 403, - array ('error' => array (Minz_Translate::t ('access_denied'))) + array('error' => array(Minz_Translate::t('access_denied'))) ); } require_once(LIB_PATH . '/lib_opml.php'); + + $this->catDAO = new FreshRSS_CategoryDAO(); + $this->entryDAO = new FreshRSS_EntryDAO(); + $this->feedDAO = new FreshRSS_FeedDAO(); } public function indexAction() { - $catDAO = new FreshRSS_CategoryDAO(); - $this->view->categories = $catDAO->listCategories(); - - $feedDAO = new FreshRSS_FeedDAO(); - $this->view->feeds = $feedDAO->listFeeds(); + $this->view->categories = $this->catDAO->listCategories(); + $this->view->feeds = $this->feedDAO->listFeeds(); // au niveau de la vue, permet de ne pas voir un flux sélectionné dans la liste $this->view->flux = false; @@ -27,38 +28,218 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { public function importAction() { if (Minz_Request::isPost() && $_FILES['file']['error'] == 0) { - invalidateHttpCache(); - // on parse le fichier OPML pour récupérer les catégories et les flux associés + @set_time_limit(300); + + $file = $_FILES['file']; + $type_file = $this->guess_file_type($file['name']); + + $list_files = array( + 'opml' => array(), + 'json_starred' => array(), + 'json_feed' => array() + ); + + // We try to list all files according to their type + // A zip file is first opened and then its files are listed + $list = array(); + if ($type_file === 'zip') { + $zip = zip_open($file['tmp_name']); + + while (($zipfile = zip_read($zip)) !== false) { + $type_zipfile = $this->guess_file_type(zip_entry_name($zipfile)); + + if ($type_file !== 'unknown') { + $list_files[$type_zipfile][] = zip_entry_read( + $zipfile, + zip_entry_filesize($zipfile) + ); + } + } + + zip_close($zip); + } elseif ($type_file !== 'unknown') { + $list_files[$type_file][] = file_get_contents($file['tmp_name']); + } + + // Import different files. + // OPML first(so categories and feeds are imported) + // Starred articles then so the "favourite" status is already set + // And finally all other files. + $error = false; + foreach ($list_files['opml'] as $opml_file) { + $error = $this->import_opml($opml_file); + } + foreach ($list_files['json_starred'] as $article_file) { + $error = $this->import_articles($article_file, true); + } + foreach ($list_files['json_feed'] as $article_file) { + $error = $this->import_articles($article_file); + } + + // And finally, we get import status and redirect to the home page + $notif = null; + if ($error === true) { + $notif = array( + 'type' => 'good', + 'content' => Minz_Translate::t('feeds_imported_with_errors') + ); + } else { + $notif = array( + 'type' => 'good', + 'content' => Minz_Translate::t('feeds_imported') + ); + } + + Minz_Session::_param('notification', $notif); + Minz_Session::_param('actualize_feeds', true); + + Minz_Request::forward(array( + 'c' => 'index', + 'a' => 'index' + ), true); + } + + // What are you doing? you have to call this controller + // with a POST request! + Minz_Request::forward(array( + 'c' => 'importExport', + 'a' => 'index' + )); + } + + private function guess_file_type($filename) { + // A *very* basic guess file type function. Only based on filename + // That's could be improved but should be enough, at least for a first + // implementation. + // TODO: improve this function? + + if (substr_compare($filename, '.zip', -4) === 0) { + return 'zip'; + } elseif (substr_compare($filename, '.opml', -5) === 0) { + return 'opml'; + } elseif (strcmp($filename, 'starred.json') === 0) { + return 'json_starred'; + } elseif (substr_compare($filename, '.json', -5) === 0 && + strpos($filename, 'feed_') === 0) { + return 'json_feed'; + } else { + return 'unknown'; + } + } + + private function import_opml($opml_file) { + $categories = array(); + $feeds = array(); + try { + list($categories, $feeds) = opml_import($opml_file); + } catch (FreshRSS_Opml_Exception $e) { + Minz_Log::warning($e->getMessage()); + return true; + } + + $this->catDAO->checkDefault(); + + // on ajoute les catégories en masse dans une fonction à part + $this->addCategories($categories); + + // on calcule la date des articles les plus anciens qu'on accepte + $nb_month_old = $this->view->conf->old_entries; + $date_min = time() -(3600 * 24 * 30 * $nb_month_old); + + // la variable $error permet de savoir si une erreur est survenue + // Le but est de ne pas arrêter l'import même en cas d'erreur + // L'utilisateur sera mis au courant s'il y a eu des erreurs, mais + // ne connaîtra pas les détails. Ceux-ci seront toutefois logguées + $error = false; + foreach ($feeds as $feed) { try { - list ($categories, $feeds) = opml_import ( - file_get_contents ($_FILES['file']['tmp_name']) + $values = array( + 'id' => $feed->id(), + 'url' => $feed->url(), + 'category' => $feed->category(), + 'name' => $feed->name(), + 'website' => $feed->website(), + 'description' => $feed->description(), + 'lastUpdate' => 0, + 'httpAuth' => $feed->httpAuth() ); - // On redirige vers le controller feed qui va se charger d'insérer les flux en BDD - // les flux sont mis au préalable dans des variables de Request - Minz_Request::_param ('categories', $categories); - Minz_Request::_param ('feeds', $feeds); - Minz_Request::forward (array ('c' => 'feed', 'a' => 'massiveImport')); - } catch (FreshRSS_Opml_Exception $e) { - Minz_Log::record ($e->getMessage (), Minz_Log::WARNING); - - $notif = array ( - 'type' => 'bad', - 'content' => Minz_Translate::t ('bad_opml_file') + // ajout du flux que s'il n'est pas déjà en BDD + if (!$this->feedDAO->searchByUrl($values['url'])) { + $id = $this->feedDAO->addFeed($values); + if ($id) { + $feed->_id($id); + $feed->faviconPrepare(); + } else { + $error = true; + } + } + } catch (FreshRSS_Feed_Exception $e) { + $error = true; + Minz_Log::record($e->getMessage(), Minz_Log::WARNING); + } + } + + return $error; + } + + private function addCategories($categories) { + foreach ($categories as $cat) { + if (!$this->catDAO->searchByName($cat->name())) { + $values = array( + 'id' => $cat->id(), + 'name' => $cat->name(), ); - Minz_Session::_param ('notification', $notif); + $this->catDAO->addCategory($values); + } + } + } + + private function import_articles($article_file, $starred = false) { + $article_object = json_decode($article_file, true); + if (is_null($article_object)) { + Minz_Log::warning('Try to import a non-JSON file'); + return true; + } + + $google_compliant = (strpos($article_object['id'], 'com.google') !== false); + + foreach ($article_object['items'] as $item) { + $key = $google_compliant ? 'htmlUrl' : 'feedUrl'; + $feed = $this->feedDAO->searchByUrl($item['origin'][$key]); + if (is_null($feed)) { + $feed = new FreshRSS_Feed($item['origin'][$key]); + $feed->_name ($item['origin']['title']); + $feed->_website ($item['origin']['htmlUrl']); + + $error = $this->addFeed($feed); // TODO - Minz_Request::forward (array ( - 'c' => 'configure', - 'a' => 'importExport' - ), true); + if ($error) { + continue; + } } + + $author = isset($item['author']) ? $item['author'] : ''; + $key_content = $google_compliant && !isset($item['content']) ? 'summary' : 'content'; + $tags = $item['categories']; + if ($google_compliant) { + $tags = array_filter($tags, function($var) { + return strpos($var, '/state/com.google') === false; + }); + } + $entry = new FreshRSS_Entry( + $feed->id(), $item['id'], $item['title'], $author, + $item[$key_content]['content'], $item['alternate'][0]['href'], + $item['published'], false, $starred, $tags + ); + + Minz_Log::debug(print_r($entry, true)); // TODO } } public function exportAction() { if (Minz_Request::isPost()) { - $this->view->_useLayout (false); + $this->view->_useLayout(false); $export_opml = Minz_Request::param('export_opml', false); $export_starred = Minz_Request::param('export_starred', false); @@ -76,9 +257,8 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { if ($export_starred) { $zip->addFromString('starred.json', $this->generate_articles('starred')); } - $feedDAO = new FreshRSS_FeedDAO (); foreach ($export_feeds as $feed_id) { - $feed = $feedDAO->searchById($feed_id); + $feed = $this->feedDAO->searchById($feed_id); $zip->addFromString( 'feed_' . $feed->category() . '_' . $feed->id() . '.json', $this->generate_articles('feed', $feed) @@ -96,13 +276,10 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { } private function generate_opml() { - $feedDAO = new FreshRSS_FeedDAO (); - $catDAO = new FreshRSS_CategoryDAO (); - - $list = array (); - foreach ($catDAO->listCategories () as $key => $cat) { - $list[$key]['name'] = $cat->name (); - $list[$key]['feeds'] = $feedDAO->listByCategory ($cat->id ()); + $list = array(); + foreach ($this->catDAO->listCategories() as $key => $cat) { + $list[$key]['name'] = $cat->name(); + $list[$key]['feeds'] = $this->feedDAO->listByCategory($cat->id()); } $this->view->categories = $list; @@ -110,22 +287,19 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { } private function generate_articles($type, $feed = NULL) { - $entryDAO = new FreshRSS_EntryDAO(); - - $catDAO = new FreshRSS_CategoryDAO(); - $this->view->categories = $catDAO->listCategories(); + $this->view->categories = $this->catDAO->listCategories(); if ($type == 'starred') { $this->view->list_title = Minz_Translate::t("starred_list"); $this->view->type = 'starred'; - $this->view->entries = $entryDAO->listWhere( + $this->view->entries = $this->entryDAO->listWhere( 's', '', 'all', 'ASC', $entryDAO->countUnreadReadFavorites()['all'] ); } elseif ($type == 'feed' && !is_null($feed)) { $this->view->list_title = Minz_Translate::t("feed_list", $feed->name()); $this->view->type = 'feed/' . $feed->id(); - $this->view->entries = $entryDAO->listWhere( + $this->view->entries = $this->entryDAO->listWhere( 'f', $feed->id(), 'all', 'ASC', $this->view->conf->posts_per_page ); diff --git a/app/views/helpers/export/articles.phtml b/app/views/helpers/export/articles.phtml index 71ac22f44..ffdca1daa 100644 --- a/app/views/helpers/export/articles.phtml +++ b/app/views/helpers/export/articles.phtml @@ -16,12 +16,19 @@ } $articles['items'][] = array( - 'id' => $entry->id(), + 'id' => $entry->guid(), 'categories' => array_values($entry->tags()), 'title' => $entry->title(), + 'author' => $entry->author(), 'published' => $entry->date(true), 'updated' => $entry->date(true), - 'content' => $entry->content(), + 'alternate' => array(array( + 'href' => $entry->link(), + 'type' => 'text/html' + )), + 'content' => array( + 'content' => $entry->content() + ), 'origin' => array( 'streamId' => $feed->id(), 'title' => $feed->name(), -- cgit v1.2.3 From 779afe9c4ee00f8099a423e1fceee40197a90cfa Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 30 Mar 2014 14:28:13 +0200 Subject: Import of articles is implemented! - Remove massiveImportAction and addCategories from FeedController - Fix typo for some methods (camelCase) - addCategoryObject and addFeedObject return id if corresponding object already exists in DB - introduce addEntryObject. Return -1 if Entry already exist (in order to keep quite good performances) - Complete importArticles method Need some more tests + better performance --- app/Controllers/feedController.php | 88 ---------------------------- app/Controllers/importExportController.php | 92 +++++++++++++++++++++--------- app/Models/CategoryDAO.php | 5 +- app/Models/EntryDAO.php | 30 ++++++++++ app/Models/FeedDAO.php | 5 +- 5 files changed, 100 insertions(+), 120 deletions(-) (limited to 'app/Controllers/feedController.php') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 43435d99d..95c9c1e9c 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -327,82 +327,6 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } } - public function massiveImportAction () { - # TODO: this function has moved to importExportController.php - # I keep it for the moment but should be deleted in a near future. - @set_time_limit(300); - - $this->catDAO = new FreshRSS_CategoryDAO (); - $this->catDAO->checkDefault (); - - $entryDAO = new FreshRSS_EntryDAO (); - $feedDAO = new FreshRSS_FeedDAO (); - - $categories = Minz_Request::param ('categories', array (), true); - $feeds = Minz_Request::param ('feeds', array (), true); - - // on ajoute les catégories en masse dans une fonction à part - $this->addCategories ($categories); - - // on calcule la date des articles les plus anciens qu'on accepte - $nb_month_old = $this->view->conf->old_entries; - $date_min = time () - (3600 * 24 * 30 * $nb_month_old); - - // la variable $error permet de savoir si une erreur est survenue - // Le but est de ne pas arrêter l'import même en cas d'erreur - // L'utilisateur sera mis au courant s'il y a eu des erreurs, mais - // ne connaîtra pas les détails. Ceux-ci seront toutefois logguées - $error = false; - $i = 0; - foreach ($feeds as $feed) { - try { - $values = array ( - 'id' => $feed->id (), - 'url' => $feed->url (), - 'category' => $feed->category (), - 'name' => $feed->name (), - 'website' => $feed->website (), - 'description' => $feed->description (), - 'lastUpdate' => 0, - 'httpAuth' => $feed->httpAuth () - ); - - // ajout du flux que s'il n'est pas déjà en BDD - if (!$feedDAO->searchByUrl ($values['url'])) { - $id = $feedDAO->addFeed ($values); - if ($id) { - $feed->_id ($id); - $feed->faviconPrepare(); - } else { - $error = true; - } - } - } catch (FreshRSS_Feed_Exception $e) { - $error = true; - Minz_Log::record ($e->getMessage (), Minz_Log::WARNING); - } - } - - if ($error) { - $res = Minz_Translate::t ('feeds_imported_with_errors'); - } else { - $res = Minz_Translate::t ('feeds_imported'); - } - - $notif = array ( - 'type' => 'good', - 'content' => $res - ); - Minz_Session::_param ('notification', $notif); - Minz_Session::_param ('actualize_feeds', true); - - // et on redirige vers la page d'accueil - Minz_Request::forward (array ( - 'c' => 'index', - 'a' => 'index' - ), true); - } - public function deleteAction () { if (Minz_Request::isPost ()) { $type = Minz_Request::param ('type', 'feed'); @@ -446,16 +370,4 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } } } - - private function addCategories ($categories) { - foreach ($categories as $cat) { - if (!$this->catDAO->searchByName ($cat->name ())) { - $values = array ( - 'id' => $cat->id (), - 'name' => $cat->name (), - ); - $catDAO->addCategory ($values); - } - } - } } diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index b6b4d0fed..3b6bf2c5c 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -31,7 +31,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { @set_time_limit(300); $file = $_FILES['file']; - $type_file = $this->guess_file_type($file['name']); + $type_file = $this->guessFileType($file['name']); $list_files = array( 'opml' => array(), @@ -46,7 +46,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $zip = zip_open($file['tmp_name']); while (($zipfile = zip_read($zip)) !== false) { - $type_zipfile = $this->guess_file_type(zip_entry_name($zipfile)); + $type_zipfile = $this->guessFileType(zip_entry_name($zipfile)); if ($type_file !== 'unknown') { $list_files[$type_zipfile][] = zip_entry_read( @@ -67,13 +67,13 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { // And finally all other files. $error = false; foreach ($list_files['opml'] as $opml_file) { - $error = $this->import_opml($opml_file); + $error = $this->importOpml($opml_file); } foreach ($list_files['json_starred'] as $article_file) { - $error = $this->import_articles($article_file, true); + $error = $this->importArticles($article_file, true); } foreach ($list_files['json_feed'] as $article_file) { - $error = $this->import_articles($article_file); + $error = $this->importArticles($article_file); } // And finally, we get import status and redirect to the home page @@ -107,7 +107,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { )); } - private function guess_file_type($filename) { + private function guessFileType($filename) { // A *very* basic guess file type function. Only based on filename // That's could be improved but should be enough, at least for a first // implementation. @@ -128,7 +128,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { } } - private function import_opml($opml_file) { + private function importOpml($opml_file) { $opml_array = array(); try { $opml_array = libopml_parse_string($opml_file); @@ -164,7 +164,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { private function addFeedOpml($feed_elt, $parent_cat) { if (is_null($parent_cat)) { // This feed has no parent category so we get the default one - $parent_cat = $catDAO->getDefault()->name(); + $parent_cat = $this->catDAO->getDefault()->name(); } $cat = $this->catDAO->searchByName($parent_cat); @@ -199,7 +199,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $id = $this->feedDAO->addFeedObject($feed); $error = ($id === false); } catch (FreshRSS_Feed_Exception $e) { - Minz_Log::record($e->getMessage(), Minz_Log::WARNING); + Minz_Log::warning($e->getMessage()); $error = true; } @@ -226,28 +226,23 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { return $error; } - private function import_articles($article_file, $starred = false) { + private function importArticles($article_file, $starred = false) { $article_object = json_decode($article_file, true); if (is_null($article_object)) { Minz_Log::warning('Try to import a non-JSON file'); return true; } + $is_read = $this->view->conf->mark_when['reception'] ? 1 : 0; + $google_compliant = (strpos($article_object['id'], 'com.google') !== false); + $error = false; foreach ($article_object['items'] as $item) { - $key = $google_compliant ? 'htmlUrl' : 'feedUrl'; - $feed = $this->feedDAO->searchByUrl($item['origin'][$key]); + $feed = $this->addFeedArticles($item['origin'], $google_compliant); if (is_null($feed)) { - $feed = new FreshRSS_Feed($item['origin'][$key]); - $feed->_name ($item['origin']['title']); - $feed->_website ($item['origin']['htmlUrl']); - - $error = $this->addFeed($feed); // TODO - - if ($error) { - continue; - } + $error = true; + continue; } $author = isset($item['author']) ? $item['author'] : ''; @@ -258,14 +253,55 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { return strpos($var, '/state/com.google') === false; }); } + $entry = new FreshRSS_Entry( $feed->id(), $item['id'], $item['title'], $author, $item[$key_content]['content'], $item['alternate'][0]['href'], - $item['published'], false, $starred, $tags + $item['published'], $is_read, $starred ); + $entry->_tags($tags); - Minz_Log::debug(print_r($entry, true)); // TODO + $id = $this->entryDAO->addEntryObject( + $entry, $this->view->conf, $feed->keepHistory() + ); + + if (!$error && ($id === false)) { + $error = true; + } } + + return $error; + } + + private function addFeedArticles($origin, $google_compliant) { + $default_cat = $this->catDAO->getDefault(); + + $return = null; + $key = $google_compliant ? 'htmlUrl' : 'feedUrl'; + $url = $origin[$key]; + $name = $origin['title']; + $website = $origin['htmlUrl']; + $error = false; + try { + // Create a Feed object and add it in DB + $feed = new FreshRSS_Feed($url); + $feed->_category($default_cat->id()); + $feed->_name($name); + $feed->_website($website); + + // addFeedObject checks if feed is already in DB so nothing else to + // check here + $id = $this->feedDAO->addFeedObject($feed); + + if ($id !== false) { + $feed->_id($id); + $return = $feed; + } + } catch (FreshRSS_Feed_Exception $e) { + Minz_Log::warning($e->getMessage()); + } + + return $return; } public function exportAction() { @@ -283,16 +319,16 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { // Stuff with content if ($export_opml) { - $zip->addFromString('feeds.opml', $this->generate_opml()); + $zip->addFromString('feeds.opml', $this->generateOpml()); } if ($export_starred) { - $zip->addFromString('starred.json', $this->generate_articles('starred')); + $zip->addFromString('starred.json', $this->generateArticles('starred')); } foreach ($export_feeds as $feed_id) { $feed = $this->feedDAO->searchById($feed_id); $zip->addFromString( 'feed_' . $feed->category() . '_' . $feed->id() . '.json', - $this->generate_articles('feed', $feed) + $this->generateArticles('feed', $feed) ); } @@ -306,7 +342,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { } } - private function generate_opml() { + private function generateOpml() { $list = array(); foreach ($this->catDAO->listCategories() as $key => $cat) { $list[$key]['name'] = $cat->name(); @@ -317,7 +353,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { return $this->view->helperToString('export/opml'); } - private function generate_articles($type, $feed = NULL) { + private function generateArticles($type, $feed = NULL) { $this->view->categories = $this->catDAO->listCategories(); if ($type == 'starred') { diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php index 8be732b98..6a9b839b9 100644 --- a/app/Models/CategoryDAO.php +++ b/app/Models/CategoryDAO.php @@ -19,7 +19,8 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { } public function addCategoryObject($category) { - if (!$this->searchByName($category->name())) { + $cat = $this->searchByName($category->name()); + if (!$cat) { // Category does not exist yet in DB so we add it before continue $values = array( 'name' => $category->name(), @@ -27,7 +28,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { return $this->addCategory($values); } - return false; + return $cat->id(); } public function updateCategory ($id, $valuesTmp) { diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index e4cf128ea..6d00967fc 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -35,6 +35,36 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { } } + public function addEntryObject($entry, $conf, $feedHistory) { + $existingGuids = array_fill_keys( + $this->listLastGuidsByFeed($entry->feed(), 20), 1 + ); + + $nb_month_old = max($conf->old_entries, 1); + $date_min = time() - (3600 * 24 * 30 * $nb_month_old); + + $eDate = $entry->date(true); + + if ($feedHistory == -2) { + $feedHistory = $conf->keep_history_default; + } + + if (!isset($existingGuids[$entry->guid()]) && + ($feedHistory != 0 || $eDate >= $date_min)) { + $values = $entry->toArray(); + + $useDeclaredDate = empty($existingGuids); + $values['id'] = ($useDeclaredDate || $eDate < $date_min) ? + min(time(), $eDate) . uSecString() : + uTimeString(); + + return $this->addEntry($values); + } + + // We don't return Entry object to avoid a research in DB + return -1; + } + public function markFavorite($ids, $is_favorite = true) { if (!is_array($ids)) { $ids = array($ids); diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index eac21df7e..b65ff4af0 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -29,7 +29,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { // should not be aware about feed class // Add feed only if we don't find it in DB - if (!$this->searchByUrl($feed->url())) { + $feed_search = $this->searchByUrl($feed->url()); + if (!$feed_search) { $values = array( 'id' => $feed->id(), 'url' => $feed->url(), @@ -50,7 +51,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { return $id; } - return false; + return $feed_search->id(); } public function updateFeed ($id, $valuesTmp) { -- cgit v1.2.3 From 19517baf13dba7ebd7d41dbbacceaea3ed75af8e Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 30 Mar 2014 17:49:39 +0200 Subject: Add a bookmark to easily subscribe to websites - FeedController->addAction (GET) shows a confirmation page - If already subscribe, redirect to Configure->feedAction - Add a bookmark in aside_feed See #425 #426 and #464 --- app/Controllers/feedController.php | 53 +++++++++++++++++++--- app/i18n/en.php | 1 + app/i18n/fr.php | 3 +- app/layout/aside_feed.phtml | 6 +++ app/views/feed/add.phtml | 91 ++++++++++++++++++++++++++++++++++++++ p/scripts/main.js | 2 +- 6 files changed, 148 insertions(+), 8 deletions(-) create mode 100644 app/views/feed/add.phtml (limited to 'app/Controllers/feedController.php') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 16516ad39..503295587 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -22,13 +22,23 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } public function addAction () { - @set_time_limit(300); + $url = Minz_Request::param('url_rss', false); + + if ($url === false) { + Minz_Request::forward(array( + 'c' => 'configure', + 'a' => 'feed' + ), true); + } + + $feedDAO = new FreshRSS_FeedDAO (); + $this->catDAO = new FreshRSS_CategoryDAO (); + $this->catDAO->checkDefault (); + + if (Minz_Request::isPost()) { + @set_time_limit(300); - if (Minz_Request::isPost ()) { - $this->catDAO = new FreshRSS_CategoryDAO (); - $this->catDAO->checkDefault (); - $url = Minz_Request::param ('url_rss'); $cat = Minz_Request::param ('category', false); if ($cat === 'nc') { $new_cat = Minz_Request::param ('new_category'); @@ -60,7 +70,6 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feed->load(true); - $feedDAO = new FreshRSS_FeedDAO (); $values = array ( 'url' => $feed->url (), 'category' => $feed->category (), @@ -154,6 +163,38 @@ class FreshRSS_feed_Controller extends Minz_ActionController { Minz_Request::forward (array ('c' => 'configure', 'a' => 'feed', 'params' => $params), true); } + + // GET request so we must ask confirmation to user + Minz_View::prependTitle(Minz_Translate::t('add_rss_feed') . ' · '); + $this->view->categories = $this->catDAO->listCategories(); + $this->view->feed = new FreshRSS_Feed($url); + try { + // We try to get some more information about the feed + $this->view->feed->load(true); + $this->view->load_ok = true; + } catch (Exception $e) { + $this->view->load_ok = false; + } + + $feed = $feedDAO->searchByUrl($this->view->feed->url()); + if ($feed) { + // Already subscribe so we redirect to the feed configuration page + $notif = array( + 'type' => 'bad', + 'content' => Minz_Translate::t( + 'already_subscribed', $feed->name() + ) + ); + Minz_Session::_param('notification', $notif); + + Minz_Request::forward(array( + 'c' => 'configure', + 'a' => 'feed', + 'params' => array( + 'id' => $feed->id() + ) + ), true); + } } public function truncateAction () { diff --git a/app/i18n/en.php b/app/i18n/en.php index e9bed39a7..3d516bbb4 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -22,6 +22,7 @@ return array ( 'add_rss_feed' => 'Add a RSS feed', 'no_rss_feed' => 'No RSS feed', 'import_export' => 'Import / export', + 'bookmark' => 'Subscribe (FreshRSS bookmark)', 'subscription_management' => 'Subscriptions management', 'main_stream' => 'Main stream', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 24f3741c8..9d745fc9a 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -22,6 +22,7 @@ return array ( 'add_rss_feed' => 'Ajouter un flux RSS', 'no_rss_feed' => 'Aucun flux RSS', 'import_export' => 'Importer / exporter', + 'bookmark' => 'S’abonner (bookmark FreshRSS)', 'subscription_management' => 'Gestion des abonnements', 'main_stream' => 'Flux principal', @@ -89,7 +90,7 @@ return array ( 'already_subscribed' => 'Vous êtes déjà abonné à %s', 'feed_added' => 'Le flux %s a bien été ajouté', 'feed_not_added' => '%s n’a pas pu être ajouté', - 'internal_problem_feed' => 'Le flux n’a pas pu être ajouté. Consulter les logs de FreshRSS pour plus de détails.', + 'internal_problem_feed' => 'Le flux ne peux pas être ajouté. Consulter les logs de FreshRSS pour plus de détails.', 'invalid_url' => 'L’url %s est invalide', 'feed_actualized' => '%s a été mis à jour', 'n_feeds_actualized' => '%d flux ont été mis à jour', diff --git a/app/layout/aside_feed.phtml b/app/layout/aside_feed.phtml index 899cafe02..7a5b2ce5e 100644 --- a/app/layout/aside_feed.phtml +++ b/app/layout/aside_feed.phtml @@ -43,6 +43,12 @@
    +
  • + + + +
  • +
  • diff --git a/app/views/feed/add.phtml b/app/views/feed/add.phtml new file mode 100644 index 000000000..56ac5f8dd --- /dev/null +++ b/app/views/feed/add.phtml @@ -0,0 +1,91 @@ +feed) { ?> +
    +

    + + load_ok) { ?> +

    + + +
    + + load_ok) { ?> +
    + +
    + +
    +
    + + feed->description(); if ($desc != '') { ?> +
    + +
    + +
    +
    + + +
    + +
    + +
    +
    + + +
    + +
    + + +   +
    +
    +
    + +
    + + + + + +
    +
    + + + feed->httpAuth(false); ?> +
    + +
    + +
    + + +
    + +
    + +
    + +
    +
    + +
    +
    + + +
    +
    +
    +
    + diff --git a/p/scripts/main.js b/p/scripts/main.js index a03be85eb..818d459b3 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -988,7 +988,7 @@ function init_share_observers() { function init_feed_observers() { $('select[id="category"]').on('change', function() { - var detail = $(this).parent('li').next('li'); + var detail = $('#new_category_name').parent(); if ($(this).val() === 'nc') { detail.show(); detail.find('input').focus(); -- cgit v1.2.3