From e7dba0ce7cfaf5e84687593a8b0d58d89fbff302 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 9 Aug 2014 23:29:13 +0200 Subject: Add basic system of update - Check on update.freshrss.org for new updates - Download script - Apply script - Need translations and verifications NOTE: current script on server indicates version 0.7.3 is an update of 0.8-dev ==> IT'S ONLY FOR MY TESTS! Script just does a backup of ./data actually... See https://github.com/marienfressinaud/FreshRSS/issues/411 --- app/Controllers/updateController.php | 106 +++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 app/Controllers/updateController.php (limited to 'app/Controllers') diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php new file mode 100644 index 000000000..a15cb9fd5 --- /dev/null +++ b/app/Controllers/updateController.php @@ -0,0 +1,106 @@ +view->loginOk && Minz_Configuration::isAdmin($current_user)) { + Minz_Error::error( + 403, + array('error' => array(_t('access_denied'))) + ); + } + + Minz_View::prependTitle(_t('update_system') . ' · '); + } + + public function indexAction() { + if (file_exists(UPDATE_FILENAME)) { + // There is an update file to apply! + $this->view->message = array( + 'status' => 'good', + 'title' => _t('ok'), + 'body' => _t('update_can_apply', _url('update', 'apply')) + ); + + return; + } + } + + public function checkAction() { + $this->view->change_view('update', 'index'); + + if (file_exists(UPDATE_FILENAME)) { + // There is already an update file to apply: we don't need to check + // the webserver! + $this->view->message = array( + 'status' => 'good', + 'title' => _t('ok'), + 'body' => _t('update_can_apply', _url('update', 'apply')) + ); + + return; + } + + $c = curl_init(FRESHRSS_UPDATE_WEBSITE); + curl_setopt($c, CURLOPT_RETURNTRANSFER, true); + $result = curl_exec($c); + + if (curl_getinfo($c, CURLINFO_HTTP_CODE) == 200) { + $res_array = explode("\n", $result, 2); + $status = $res_array[0]; + + if (strpos($status, 'UPDATE') === 0) { + $script = $res_array[1]; + if (file_put_contents(UPDATE_FILENAME, $script) !== false) { + $this->view->message = array( + 'status' => 'good', + 'title' => _t('ok'), + 'body' => _t('update_can_apply', _url('update', 'apply')) + ); + } else { + $this->view->message = array( + 'status' => 'bad', + 'title' => _t('damn'), + 'body' => _t('update_problem') + ); + } + } else { + $this->view->message = array( + 'status' => 'bad', + 'title' => _t('damn'), + 'body' => _t('no_update') + ); + } + } else { + $this->view->message = array( + 'status' => 'bad', + 'title' => _t('damn'), + 'body' => _t('update_server_not_found', FRESHRSS_UPDATE_WEBSITE) + ); + } + curl_close($c); + } + + public function applyAction() { + require(UPDATE_FILENAME); + $res = apply_update(); + + if ($res === true) { + @unlink(UPDATE_FILENAME); + + Minz_Session::_param('notification', array( + 'type' => 'good', + 'content' => Minz_Translate::t('update_finished') + )); + + Minz_Request::forward(array(), true); + } else { + Minz_Session::_param('notification', array( + 'type' => 'bad', + 'content' => Minz_Translate::t('update_failed', $res) + )); + + Minz_Request::forward(array('c' => 'update'), true); + } + } +} \ No newline at end of file -- cgit v1.2.3 From 7ed111b1bf152613d17254808a4fcf89f5774297 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 10 Aug 2014 10:35:17 +0200 Subject: Add translations for update system --- app/Controllers/updateController.php | 7 +++++-- app/i18n/en.php | 9 +++++++++ app/i18n/fr.php | 11 ++++++++++- app/views/update/index.phtml | 4 +++- 4 files changed, 27 insertions(+), 4 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index a15cb9fd5..a94af4417 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -11,6 +11,7 @@ class FreshRSS_update_Controller extends Minz_ActionController { } Minz_View::prependTitle(_t('update_system') . ' · '); + $this->view->last_update_time = 'unknown'; // TODO } public function indexAction() { @@ -61,7 +62,7 @@ class FreshRSS_update_Controller extends Minz_ActionController { $this->view->message = array( 'status' => 'bad', 'title' => _t('damn'), - 'body' => _t('update_problem') + 'body' => _t('update_problem', 'Cannot save the update script') ); } } else { @@ -88,6 +89,8 @@ class FreshRSS_update_Controller extends Minz_ActionController { if ($res === true) { @unlink(UPDATE_FILENAME); + // TODO: record last update + Minz_Session::_param('notification', array( 'type' => 'good', 'content' => Minz_Translate::t('update_finished') @@ -97,7 +100,7 @@ class FreshRSS_update_Controller extends Minz_ActionController { } else { Minz_Session::_param('notification', array( 'type' => 'bad', - 'content' => Minz_Translate::t('update_failed', $res) + 'content' => Minz_Translate::t('update_problem', $res) )); Minz_Request::forward(array('c' => 'update'), true); diff --git a/app/i18n/en.php b/app/i18n/en.php index 6110ccb11..6a0b4a139 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -192,6 +192,7 @@ return array ( 'informations' => 'Information', 'damn' => 'Damn!', + 'ok' => 'Ok!', 'feed_in_error' => 'This feed has encountered a problem. Please verify that it is always reachable then actualize it.', 'feed_empty' => 'This feed is empty. Please verify that it is still maintained.', 'feed_description' => 'Description', @@ -409,5 +410,13 @@ return array ( 'stats_top_feed' => 'Top ten feeds', 'stats_entry_count' => 'Entry count', + 'update' => 'Update', + 'update_system' => 'Update system', + 'update_check' => 'Check for new updates', + 'update_last' => 'Last update: %s', 'update_can_apply' => 'There is an available update. Apply', + 'update_server_not_found' => 'Update server cannot be found. [%s]', + 'no_update' => 'No update to apply', + 'update_problem' => 'Update has encountered an error: %s', + 'update_finished' => 'Update is now finished!', ); diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 5f88aa069..d0637b9f7 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -192,6 +192,7 @@ return array ( 'informations' => 'Informations', 'damn' => 'Arf !', + 'ok' => 'Ok !', 'feed_in_error' => 'Ce flux a rencontré un problème. Veuillez vérifier qu’il est toujours accessible puis actualisez-le.', 'feed_empty' => 'Ce flux est vide. Veuillez vérifier qu’il est toujours maintenu.', 'feed_description' => 'Description', @@ -409,5 +410,13 @@ return array ( 'stats_top_feed' => 'Les dix plus gros flux', 'stats_entry_count' => 'Nombre d’articles', - 'update_can_apply' => 'Il y’a une mise à jour à appliquer. Appliquer', + 'update' => 'Mise à jour', + 'update_system' => 'Système de mise à jour', + 'update_check' => 'Vérifier les mises à jour', + 'update_last' => 'Dernière mise à jour : %s', + 'update_can_apply' => 'Il y’a une mise à jour à appliquer. Appliquer la mise à jour', + 'update_server_not_found' => 'Le serveur de mise à jour n’a pas été trouvé. [%s]', + 'no_update' => 'Aucune mise à jour à appliquer', + 'update_problem' => 'La mise à jour a rencontré un problème : %s', + 'update_finished' => 'La mise à jour est terminée !', ); diff --git a/app/views/update/index.phtml b/app/views/update/index.phtml index a1a872845..8f6ee6269 100644 --- a/app/views/update/index.phtml +++ b/app/views/update/index.phtml @@ -12,8 +12,10 @@ message) || $this->message['status'] !== 'good') { ?>

- last_update_time); ?>

+

+ +

-- cgit v1.2.3 From 9a5d6245fbeb413766362fd6b2c4f5f5b6a22a22 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 10 Aug 2014 10:55:51 +0200 Subject: Improve update API Update script must implement 4 functions: - apply_update() to perform the update (most important). Return true if all is ok, else false. - need_info_update() returns true if we need more info for update, else false. If this function always returns false, you don't need to implement following functions (but it's better to not forget) - ask_info_update() should be a HTML form to ask infos. Method must be post and action must point to _url('update', 'apply') (or leave it blank) - save_info_update() is called for POST requests (to save form from ask_info_update()) --- app/Controllers/updateController.php | 37 +++++++++++++++++++++--------------- app/views/update/apply.phtml | 9 +++++++++ app/views/update/index.phtml | 2 ++ 3 files changed, 33 insertions(+), 15 deletions(-) create mode 100644 app/views/update/apply.phtml (limited to 'app/Controllers') diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index a94af4417..1095f9da7 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -84,26 +84,33 @@ class FreshRSS_update_Controller extends Minz_ActionController { public function applyAction() { require(UPDATE_FILENAME); - $res = apply_update(); - if ($res === true) { - @unlink(UPDATE_FILENAME); + if (Minz_Request::isPost()) { + save_info_update(); + } - // TODO: record last update + if (!need_info_update()) { + $res = apply_update(); - Minz_Session::_param('notification', array( - 'type' => 'good', - 'content' => Minz_Translate::t('update_finished') - )); + if ($res === true) { + @unlink(UPDATE_FILENAME); - Minz_Request::forward(array(), true); - } else { - Minz_Session::_param('notification', array( - 'type' => 'bad', - 'content' => Minz_Translate::t('update_problem', $res) - )); + // TODO: record last update + + Minz_Session::_param('notification', array( + 'type' => 'good', + 'content' => Minz_Translate::t('update_finished') + )); - Minz_Request::forward(array('c' => 'update'), true); + Minz_Request::forward(array(), true); + } else { + Minz_Session::_param('notification', array( + 'type' => 'bad', + 'content' => Minz_Translate::t('update_problem', $res) + )); + + Minz_Request::forward(array('c' => 'update'), true); + } } } } \ No newline at end of file diff --git a/app/views/update/apply.phtml b/app/views/update/apply.phtml new file mode 100644 index 000000000..d7ea466c5 --- /dev/null +++ b/app/views/update/apply.phtml @@ -0,0 +1,9 @@ +partial('aside_configure'); ?> + +
+ + +

+ + +
\ No newline at end of file diff --git a/app/views/update/index.phtml b/app/views/update/index.phtml index 8f6ee6269..1824c02b8 100644 --- a/app/views/update/index.phtml +++ b/app/views/update/index.phtml @@ -1,6 +1,8 @@ partial('aside_configure'); ?>
+ +

message)) { ?> -- cgit v1.2.3 From 3ca8c7ec4c55b4fa751fbcdc8e28f28351c4a967 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 10 Aug 2014 11:52:18 +0200 Subject: Litlle improvements (update system) - Check UPDATE_FILENAME exists before applying update - Add empty line at the end of files --- app/Controllers/updateController.php | 7 ++++++- app/views/update/apply.phtml | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index 1095f9da7..fa62f4a70 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -79,10 +79,15 @@ class FreshRSS_update_Controller extends Minz_ActionController { 'body' => _t('update_server_not_found', FRESHRSS_UPDATE_WEBSITE) ); } + curl_close($c); } public function applyAction() { + if (!file_exists(UPDATE_FILENAME)) { + Minz_Request::forward(array('c' => 'update'), true); + } + require(UPDATE_FILENAME); if (Minz_Request::isPost()) { @@ -113,4 +118,4 @@ class FreshRSS_update_Controller extends Minz_ActionController { } } } -} \ No newline at end of file +} diff --git a/app/views/update/apply.phtml b/app/views/update/apply.phtml index d7ea466c5..30566c7ab 100644 --- a/app/views/update/apply.phtml +++ b/app/views/update/apply.phtml @@ -6,4 +6,4 @@

-
\ No newline at end of file + -- cgit v1.2.3 From 909d8747ba09f9c9a6ac895f1f4f0763bdb27a55 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 12 Aug 2014 20:15:46 +0200 Subject: Update system now uses HTTPS connection - Add some curl checks - Refactor code --- app/Controllers/updateController.php | 60 +++++++++++++++++++----------------- constants.php | 2 +- 2 files changed, 33 insertions(+), 29 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index fa62f4a70..857d975b2 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -44,43 +44,47 @@ class FreshRSS_update_Controller extends Minz_ActionController { $c = curl_init(FRESHRSS_UPDATE_WEBSITE); curl_setopt($c, CURLOPT_RETURNTRANSFER, true); + curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true); + curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2); $result = curl_exec($c); + $c_status = curl_getinfo($c, CURLINFO_HTTP_CODE); + curl_close($c); - if (curl_getinfo($c, CURLINFO_HTTP_CODE) == 200) { - $res_array = explode("\n", $result, 2); - $status = $res_array[0]; - - if (strpos($status, 'UPDATE') === 0) { - $script = $res_array[1]; - if (file_put_contents(UPDATE_FILENAME, $script) !== false) { - $this->view->message = array( - 'status' => 'good', - 'title' => _t('ok'), - 'body' => _t('update_can_apply', _url('update', 'apply')) - ); - } else { - $this->view->message = array( - 'status' => 'bad', - 'title' => _t('damn'), - 'body' => _t('update_problem', 'Cannot save the update script') - ); - } - } else { - $this->view->message = array( - 'status' => 'bad', - 'title' => _t('damn'), - 'body' => _t('no_update') - ); - } - } else { + if ($c_status !== 200) { $this->view->message = array( 'status' => 'bad', 'title' => _t('damn'), 'body' => _t('update_server_not_found', FRESHRSS_UPDATE_WEBSITE) ); + return; } - curl_close($c); + $res_array = explode("\n", $result, 2); + $status = $res_array[0]; + if (strpos($status, 'UPDATE') !== 0) { + $this->view->message = array( + 'status' => 'bad', + 'title' => _t('damn'), + 'body' => _t('no_update') + ); + + return; + } + + $script = $res_array[1]; + if (file_put_contents(UPDATE_FILENAME, $script) !== false) { + $this->view->message = array( + 'status' => 'good', + 'title' => _t('ok'), + 'body' => _t('update_can_apply', _url('update', 'apply')) + ); + } else { + $this->view->message = array( + 'status' => 'bad', + 'title' => _t('damn'), + 'body' => _t('update_problem', 'Cannot save the update script') + ); + } } public function applyAction() { diff --git a/constants.php b/constants.php index a968b82f4..ba9c508dc 100644 --- a/constants.php +++ b/constants.php @@ -1,7 +1,7 @@ Date: Mon, 1 Sep 2014 20:58:05 -0400 Subject: Add average on repartition charts. It needs some verification on the value used to calculate the averages. --- app/Controllers/statsController.php | 3 ++ app/Models/StatsDAO.php | 62 +++++++++++++++++++++++++++++++++++++ app/views/stats/repartition.phtml | 48 ++++++++++++++++++++++++---- 3 files changed, 107 insertions(+), 6 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php index 98f46f0d2..000b41dd2 100644 --- a/app/Controllers/statsController.php +++ b/app/Controllers/statsController.php @@ -67,8 +67,11 @@ class FreshRSS_stats_Controller extends Minz_ActionController { $this->view->days = $statsDAO->getDays(); $this->view->months = $statsDAO->getMonths(); $this->view->repartitionHour = $statsDAO->calculateEntryRepartitionPerFeedPerHour($id); + $this->view->averageHour = $statsDAO->calculateEntryAveragePerFeedPerHour($id); $this->view->repartitionDayOfWeek = $statsDAO->calculateEntryRepartitionPerFeedPerDayOfWeek($id); + $this->view->averageDayOfWeek = $statsDAO->calculateEntryAveragePerFeedPerDayOfWeek($id); $this->view->repartitionMonth = $statsDAO->calculateEntryRepartitionPerFeedPerMonth($id); + $this->view->averageMonth = $statsDAO->calculateEntryAveragePerFeedPerMonth($id); } public function firstAction() { diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 89be76a26..bd4271ba8 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -151,6 +151,68 @@ SQL; return $this->convertToSerie($repartition); } + /** + * Calculates the average number of article per hour per feed + * + * @param integer $feed id + * @return integer + */ + public function calculateEntryAveragePerFeedPerHour($feed = null) { + return $this->calculateEntryAveragePerFeedPerPeriod(1/24, $feed); + } + + /** + * Calculates the average number of article per day of week per feed + * + * @param integer $feed id + * @return integer + */ + public function calculateEntryAveragePerFeedPerDayOfWeek($feed = null) { + return $this->calculateEntryAveragePerFeedPerPeriod(7, $feed); + } + + /** + * Calculates the average number of article per month per feed + * + * @param integer $feed id + * @return integer + */ + public function calculateEntryAveragePerFeedPerMonth($feed = null) { + return $this->calculateEntryAveragePerFeedPerPeriod(30, $feed); + } + + /** + * Calculates the average number of article per feed + * + * @param float $period number used to divide the number of day in the period + * @param integer $feed id + * @return integer + */ + protected function calculateEntryAveragePerFeedPerPeriod($period, $feed = null) { + if ($feed) { + $restrict = "WHERE e.id_feed = {$feed}"; + } else { + $restrict = ''; + } + $sql = <<prefix}entry AS e +{$restrict} +SQL; + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetch(PDO::FETCH_NAMED); + $date_min = new \DateTime(); + $date_min->setTimestamp($res['date_min']); + $date_max = new \DateTime(); + $date_max->setTimestamp($res['date_max']); + $interval = $date_max->diff($date_min, true); + + return round($res['count'] / ($interval->format('%a') / ($period)), 2); + } + /** * Initialize an array for statistics depending on a range * diff --git a/app/views/stats/repartition.phtml b/app/views/stats/repartition.phtml index 9d2eb28e4..2331db78c 100644 --- a/app/views/stats/repartition.phtml +++ b/app/views/stats/repartition.phtml @@ -56,11 +56,22 @@ function initStats() { return; } // Entry per hour + var avg_h = []; + for (var i = -1; i <= 24; i++) { + avg_h.push([i, averageHour?>]); + } Flotr.draw(document.getElementById('statsEntryPerHour'), - [repartitionHour ?>], + [{ + data: repartitionHour ?>, + bars: {horizontal: false, show: true} + }, { + data: avg_h, + lines: {show: true}, + label: averageHour?>, + yaxis: 2 + }], { grid: {verticalLines: false}, - bars: {horizontal: false, show: true}, xaxis: {noTicks: 23, tickFormatter: function(x) { var x = parseInt(x); @@ -70,14 +81,26 @@ function initStats() { max: 23.9, tickDecimals: 0}, yaxis: {min: 0}, + y2axis: {showLabels: false}, mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}} }); // Entry per day of week + var avg_dow = []; + for (var i = -1; i <= 7; i++) { + avg_dow.push([i, averageDayOfWeek?>]); + } Flotr.draw(document.getElementById('statsEntryPerDayOfWeek'), - [repartitionDayOfWeek ?>], + [{ + data: repartitionDayOfWeek ?>, + bars: {horizontal: false, show: true} + }, { + data: avg_dow, + lines: {show: true}, + label: averageDayOfWeek?>, + yaxis: 2 + }], { grid: {verticalLines: false}, - bars: {horizontal: false, show: true}, xaxis: {noTicks: 6, tickFormatter: function(x) { var x = parseInt(x), @@ -88,14 +111,26 @@ function initStats() { max: 6.9, tickDecimals: 0}, yaxis: {min: 0}, + y2axis: {showLabels: false}, mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}} }); // Entry per month + var avg_m = []; + for (var i = 0; i <= 13; i++) { + avg_m.push([i, averageMonth?>]); + } Flotr.draw(document.getElementById('statsEntryPerMonth'), - [repartitionMonth ?>], + [{ + data: repartitionMonth ?>, + bars: {horizontal: false, show: true} + }, { + data: avg_m, + lines: {show: true}, + label: averageMonth?>, + yaxis: 2 + }], { grid: {verticalLines: false}, - bars: {horizontal: false, show: true}, xaxis: {noTicks: 12, tickFormatter: function(x) { var x = parseInt(x), @@ -106,6 +141,7 @@ function initStats() { max: 12.9, tickDecimals: 0}, yaxis: {min: 0}, + y2axis: {showLabels: false}, mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}} }); -- cgit v1.2.3 From 48f91da2e5d7da4d8a4f11987116bfc8cbf049ca Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 8 Sep 2014 19:52:21 +0200 Subject: Check FRESHRSS_PATH is writable. FRESHRSS_PATH needs to be writable before performing update. --- app/Controllers/updateController.php | 41 ++++++++++++------------------------ app/i18n/en.php | 2 ++ app/i18n/fr.php | 2 ++ 3 files changed, 18 insertions(+), 27 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index 857d975b2..5d5ec3586 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -15,15 +15,19 @@ class FreshRSS_update_Controller extends Minz_ActionController { } public function indexAction() { - if (file_exists(UPDATE_FILENAME)) { + if (file_exists(UPDATE_FILENAME) && !is_writable(FRESHRSS_PATH)) { + $this->view->message = array( + 'status' => 'bad', + 'title' => _t('damn'), + 'body' => _t('file_is_nok', FRESHRSS_PATH) + ); + } elseif (file_exists(UPDATE_FILENAME)) { // There is an update file to apply! $this->view->message = array( 'status' => 'good', 'title' => _t('ok'), 'body' => _t('update_can_apply', _url('update', 'apply')) ); - - return; } } @@ -33,11 +37,7 @@ class FreshRSS_update_Controller extends Minz_ActionController { if (file_exists(UPDATE_FILENAME)) { // There is already an update file to apply: we don't need to check // the webserver! - $this->view->message = array( - 'status' => 'good', - 'title' => _t('ok'), - 'body' => _t('update_can_apply', _url('update', 'apply')) - ); + Minz_Request::forward(array('c' => 'update')); return; } @@ -73,11 +73,7 @@ class FreshRSS_update_Controller extends Minz_ActionController { $script = $res_array[1]; if (file_put_contents(UPDATE_FILENAME, $script) !== false) { - $this->view->message = array( - 'status' => 'good', - 'title' => _t('ok'), - 'body' => _t('update_can_apply', _url('update', 'apply')) - ); + Minz_Request::forward(array('c' => 'update')); } else { $this->view->message = array( 'status' => 'bad', @@ -88,7 +84,7 @@ class FreshRSS_update_Controller extends Minz_ActionController { } public function applyAction() { - if (!file_exists(UPDATE_FILENAME)) { + if (!file_exists(UPDATE_FILENAME) || !is_writable(FRESHRSS_PATH)) { Minz_Request::forward(array('c' => 'update'), true); } @@ -104,21 +100,12 @@ class FreshRSS_update_Controller extends Minz_ActionController { if ($res === true) { @unlink(UPDATE_FILENAME); - // TODO: record last update + // TODO: record last update_finished - Minz_Session::_param('notification', array( - 'type' => 'good', - 'content' => Minz_Translate::t('update_finished') - )); - - Minz_Request::forward(array(), true); + Minz_Request::good(_t('update_finished')); } else { - Minz_Session::_param('notification', array( - 'type' => 'bad', - 'content' => Minz_Translate::t('update_problem', $res) - )); - - Minz_Request::forward(array('c' => 'update'), true); + Minz_Request::bad(_t('update_problem', $res), + array('c' => 'update', 'a' => 'index')); } } } diff --git a/app/i18n/en.php b/app/i18n/en.php index 95356af2c..c5911cde7 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -152,6 +152,8 @@ return array ( 'public' => 'Public', 'invalid_login' => 'Login is invalid', + 'file_is_nok' => 'Check permissions on %s directory. HTTP server must have rights to write into.', + // VIEWS 'save' => 'Save', 'delete' => 'Delete', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 8437e872e..789a0bb98 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -152,6 +152,8 @@ return array ( 'public' => 'Public', 'invalid_login' => 'L’identifiant est invalide !', + 'file_is_nok' => 'Veuillez vérifier les droits sur le répertoire %s. Le serveur HTTP doit être capable d’écrire dedans.', + // VIEWS 'save' => 'Enregistrer', 'delete' => 'Supprimer', -- cgit v1.2.3 From d59eebf5423afb94ff68550aa9218674889ab4ad Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 8 Sep 2014 20:07:09 +0200 Subject: Add data/last_update.txt Remember last update timestamp. --- app/Controllers/updateController.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index 5d5ec3586..5424792f4 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -11,7 +11,11 @@ class FreshRSS_update_Controller extends Minz_ActionController { } Minz_View::prependTitle(_t('update_system') . ' · '); - $this->view->last_update_time = 'unknown'; // TODO + $this->view->last_update_time = 'unknown'; + $timestamp = (int)@file_get_contents(DATA_PATH . '/last_update.txt'); + if (is_numeric($timestamp) && $timestamp > 0) { + $this->view->last_update_time = timestamptodate($timestamp); + } } public function indexAction() { @@ -99,8 +103,7 @@ class FreshRSS_update_Controller extends Minz_ActionController { if ($res === true) { @unlink(UPDATE_FILENAME); - - // TODO: record last update_finished + @file_put_contents(DATA_PATH . '/last_update.txt', time()); Minz_Request::good(_t('update_finished')); } else { -- cgit v1.2.3 From 213bc2b9ddef88fd9e3cb50ac0893742f5fdd101 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 12 Sep 2014 21:07:53 +0200 Subject: Check if update has been done during last minute Cancel check action if update has been done during last hour. --- app/Controllers/updateController.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'app/Controllers') diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index 5424792f4..ec6778d51 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -38,7 +38,11 @@ class FreshRSS_update_Controller extends Minz_ActionController { public function checkAction() { $this->view->change_view('update', 'index'); - if (file_exists(UPDATE_FILENAME)) { + // Get the last update. If already check during the last hour, do nothing. + $last_update = (int)@file_get_contents(DATA_PATH . '/last_update.txt'); + $check_last_hour = (time() - 3600) <= $last_update; + + if (file_exists(UPDATE_FILENAME) || $check_last_hour) { // There is already an update file to apply: we don't need to check // the webserver! Minz_Request::forward(array('c' => 'update')); -- cgit v1.2.3 From 098f5e6d747cf442b72f75a22a9ce43d36605d65 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 12 Sep 2014 21:10:45 +0200 Subject: Log error if update.freshrss.org is unreachable --- app/Controllers/updateController.php | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'app/Controllers') diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index ec6778d51..4c1dd002c 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -56,9 +56,14 @@ class FreshRSS_update_Controller extends Minz_ActionController { curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2); $result = curl_exec($c); $c_status = curl_getinfo($c, CURLINFO_HTTP_CODE); + $c_error = curl_error($c); curl_close($c); if ($c_status !== 200) { + Minz_Log::error( + 'Error during update (HTTP code ' . $c_status . '): ' . $c_error + ); + $this->view->message = array( 'status' => 'bad', 'title' => _t('damn'), -- cgit v1.2.3 From 3fa726a81eb1889f29115cf4d8349d15f68b03f9 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 12 Sep 2014 21:34:42 +0200 Subject: Import all .json files Before, only feed_*.json and *starred*.json was imported. Now, all *.json files are imported. --- app/Controllers/importExportController.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 5adf3878a..07c097c4a 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -119,8 +119,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { } elseif (substr_compare($filename, '.json', -5) === 0 && strpos($filename, 'starred') !== false) { return 'json_starred'; - } elseif (substr_compare($filename, '.json', -5) === 0 && - strpos($filename, 'feed_') === 0) { + } elseif (substr_compare($filename, '.json', -5) === 0) { return 'json_feed'; } else { return 'unknown'; @@ -238,6 +237,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { strpos($article_object['id'], 'com.google') !== false ); + $error = false; foreach ($article_object['items'] as $item) { $feed = $this->addFeedArticles($item['origin'], $google_compliant); @@ -263,7 +263,10 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { ); $entry->_tags($tags); - //FIME: Use entryDAO->addEntryPrepare(). Do not call entryDAO->listLastGuidsByFeed() for each entry. Consider using a transaction. + // FIXME + // Use entryDAO->addEntryPrepare(). + // Do not call entryDAO->listLastGuidsByFeed() for each entry. + // Consider using a transaction. $id = $this->entryDAO->addEntryObject( $entry, $this->view->conf, $feed->keepHistory() ); -- cgit v1.2.3 From 021457657186f019a9227e7a2a0b32148ffe4002 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 12 Sep 2014 21:46:37 +0200 Subject: FIXME (import/export) Use entryDAO addEntryPrepare --- app/Controllers/importExportController.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 07c097c4a..e7d364efd 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -239,6 +239,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $error = false; + $prepared_statement = $this->entryDAO->addEntryPrepare(); foreach ($article_object['items'] as $item) { $feed = $this->addFeedArticles($item['origin'], $google_compliant); if (is_null($feed)) { @@ -261,15 +262,14 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $item[$key_content]['content'], $item['alternate'][0]['href'], $item['published'], $is_read, $starred ); + $entry->_id(min(time(), $entry->date(true)) . uSecString()); $entry->_tags($tags); // FIXME - // Use entryDAO->addEntryPrepare(). // Do not call entryDAO->listLastGuidsByFeed() for each entry. // Consider using a transaction. - $id = $this->entryDAO->addEntryObject( - $entry, $this->view->conf, $feed->keepHistory() - ); + $values = $entry->toArray(); + $id = $this->entryDAO->addEntry($values, $prepared_statement); if (!$error && ($id === false)) { $error = true; -- cgit v1.2.3 From b7b05ca3cefbb35a5174da4d4d734107f19c24a1 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 15 Sep 2014 15:34:56 +0200 Subject: Import/Export: use transactions List of articles must be iterated twice since feeds must be in DB before using transaction for articles. It may be improved? See https://github.com/marienfressinaud/FreshRSS/issues/591 --- app/Controllers/importExportController.php | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index e7d364efd..a44991335 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -237,16 +237,28 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { strpos($article_object['id'], 'com.google') !== false ); - $error = false; - $prepared_statement = $this->entryDAO->addEntryPrepare(); + $article_to_feed = array(); + + // First, we check feeds of articles are in DB (and add them if needed). foreach ($article_object['items'] as $item) { $feed = $this->addFeedArticles($item['origin'], $google_compliant); if (is_null($feed)) { $error = true; + } else { + $article_to_feed[$item['id']] = $feed->id(); + } + } + + // Then, articles are imported. + $prepared_statement = $this->entryDAO->addEntryPrepare(); + $this->entryDAO->beginTransaction(); + foreach ($article_object['items'] as $item) { + if (!isset($article_to_feed[$item['id']])) { continue; } + $feed_id = $article_to_feed[$item['id']]; $author = isset($item['author']) ? $item['author'] : ''; $key_content = ($google_compliant && !isset($item['content'])) ? 'summary' : 'content'; @@ -258,16 +270,13 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { } $entry = new FreshRSS_Entry( - $feed->id(), $item['id'], $item['title'], $author, + $feed_id, $item['id'], $item['title'], $author, $item[$key_content]['content'], $item['alternate'][0]['href'], $item['published'], $is_read, $starred ); $entry->_id(min(time(), $entry->date(true)) . uSecString()); $entry->_tags($tags); - // FIXME - // Do not call entryDAO->listLastGuidsByFeed() for each entry. - // Consider using a transaction. $values = $entry->toArray(); $id = $this->entryDAO->addEntry($values, $prepared_statement); @@ -275,6 +284,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $error = true; } } + $this->entryDAO->commit(); return $error; } -- cgit v1.2.3 From 69c7c1aa48d42656f73c724d7e9062ca19914133 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 15 Sep 2014 15:55:35 +0200 Subject: Change loading of base-theme css If metadata.json indicates it should use "_template.css" or "_base.css", base-theme/template|base.css is used. It facilitates theme maintenance. --- app/Controllers/importExportController.php | 1 - app/FreshRSS.php | 13 +- p/themes/Dark/metadata.json | 2 +- p/themes/Dark/template.css | 698 ----------------------------- p/themes/Flat/metadata.json | 2 +- p/themes/Flat/template.css | 698 ----------------------------- p/themes/Origine/metadata.json | 2 +- p/themes/Origine/template.css | 698 ----------------------------- p/themes/Screwdriver/metadata.json | 2 +- p/themes/Screwdriver/template.css | 698 ----------------------------- 10 files changed, 15 insertions(+), 2799 deletions(-) delete mode 100644 p/themes/Dark/template.css delete mode 100644 p/themes/Flat/template.css delete mode 100644 p/themes/Origine/template.css delete mode 100644 p/themes/Screwdriver/template.css (limited to 'app/Controllers') diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index a44991335..f329766b8 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -109,7 +109,6 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { // 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'; diff --git a/app/FreshRSS.php b/app/FreshRSS.php index cf6390f68..6cca27f78 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -139,11 +139,20 @@ class FreshRSS extends Minz_FrontController { } } - private function loadStylesAndScripts ($loginOk) { + private function loadStylesAndScripts($loginOk) { $theme = FreshRSS_Themes::load($this->conf->theme); if ($theme) { foreach($theme['files'] as $file) { - Minz_View::appendStyle (Minz_Url::display ('/themes/' . $theme['id'] . '/' . $file . '?' . @filemtime(PUBLIC_PATH . '/themes/' . $theme['id'] . '/' . $file))); + $theme_id = $theme['id']; + $filename = $file; + if ($file[0] == '_') { + $theme_id = 'base-theme'; + $filename = substr($file, 1); + } + $filetime = @filemtime(PUBLIC_PATH . '/themes/' . $theme_id . '/' . $filename); + Minz_View::appendStyle(Minz_Url::display( + '/themes/' . $theme_id . '/' . $filename . '?' . $filetime + )); } } diff --git a/p/themes/Dark/metadata.json b/p/themes/Dark/metadata.json index 5eb3a05e8..bdc068c2e 100644 --- a/p/themes/Dark/metadata.json +++ b/p/themes/Dark/metadata.json @@ -3,5 +3,5 @@ "author": "AD", "description": "Le coté obscur du thème “Origine”", "version": 0.2, - "files": ["template.css", "dark.css"] + "files": ["_template.css", "dark.css"] } diff --git a/p/themes/Dark/template.css b/p/themes/Dark/template.css deleted file mode 100644 index 466ec4603..000000000 --- a/p/themes/Dark/template.css +++ /dev/null @@ -1,698 +0,0 @@ -@charset "UTF-8"; - -/*=== GENERAL */ -/*============*/ -html, body { - margin: 0; - padding: 0; - font-size: 100%; -} - -/*=== Links */ -a { - text-decoration: none; -} -a:hover { - text-decoration: underline; -} - -/*=== Lists */ -ul, ol, dd { - margin: 0; - padding: 0; -} - -/*=== Titles */ -h1 { - margin: 0.6em 0 0.3em; - font-size: 1.5em; - line-height: 1.6em; -} -h2 { - margin: 0.5em 0 0.25em; - font-size: 1.3em; - line-height: 2em; -} -h3 { - margin: 0.5em 0 0.25em; - font-size: 1.1em; - line-height: 2em; -} - -/*=== Paragraphs */ -p { - margin: 1em 0 0.5em; - font-size: 1em; -} - -/*=== Images */ -img { - height: auto; - max-width: 100%; -} -img.favicon { - height: 16px; - width: 16px; - vertical-align: middle; -} - -/*=== Videos */ -iframe, embed, object, video { - max-width: 100%; -} - -/*=== Forms */ -legend { - display: block; - width: 100%; - clear: both; -} -label { - display: block; -} -input { - width: 180px; -} -textarea { - width: 300px; -} -input, select, textarea { - display: inline-block; - max-width: 100%; -} -input[type="radio"], -input[type="checkbox"] { - width: 15px !important; - min-height: 15px !important; -} -input.extend:focus { - width: 300px; -} - -/*=== COMPONENTS */ -/*===============*/ -/*=== Forms */ -.form-group:after { - content: ""; - display: block; - clear: both; -} -.form-group.form-actions { - min-width: 250px; -} -.form-group .group-name { - display: block; - float: left; - width: 200px; -} -.form-group .group-controls { - min-width: 250px; - margin: 0 0 0 220px; -} -.form-group .group-controls .control { - display: block; -} - -/*=== Buttons */ -.stick { - display: inline-block; - white-space: nowrap; -} -.btn, -a.btn { - display: inline-block; - cursor: pointer; - overflow: hidden; -} -.btn-important { - font-weight: bold; -} - -/*=== Navigation */ -.nav-list .nav-header, -.nav-list .item { - display: block; -} -.nav-list .item, -.nav-list .item > a { - display: block; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} -.nav-head { - display: block; -} -.nav-head .item { - display: inline-block; -} - -/*=== Horizontal-list */ -.horizontal-list { - display: table; - table-layout: fixed; - width: 100%; -} -.horizontal-list .item { - display: table-cell; -} - -/*=== Dropdown */ -.dropdown { - position: relative; - display: inline-block; -} -.dropdown-target { - display: none; -} -.dropdown-menu { - display: none; - min-width: 200px; - margin: 0; - position: absolute; - right: 0; - background: #fff; - border: 1px solid #aaa; -} -.dropdown-header { - display: block; -} -.dropdown-menu > .item { - display: block; -} -.dropdown-menu > .item > a, -.dropdown-menu > .item > span { - display: block; -} -.dropdown-menu > .item[aria-checked="true"] > a:before { - content: '✓'; -} -.dropdown-menu .input { - display: block; -} -.dropdown-menu .input select, -.dropdown-menu .input input { - display: block; - max-width: 95%; -} -.dropdown-target:target ~ .dropdown-menu { - display: block; - z-index: 10; -} -.dropdown-close { - display: inline; -} -.dropdown-close a { - font-size: 0; - position: fixed; - top: 0; bottom: 0; - left: 0; right: 0; - display: block; - z-index: -10; -} -.separator { - display: block; - height: 0; - border-bottom: 1px solid #aaa; -} - -/*=== Alerts */ -.alert { - display: block; - width: 90%; -} -.group-controls .alert { - width: 100% -} -.alert-head { - margin: 0; - font-weight: bold; -} -.alert ul { - margin: 5px 20px; -} - -/*=== Icons */ -.icon { - display: inline-block; - width: 16px; - height: 16px; - vertical-align: middle; - line-height: 16px; -} - -/*=== Pagination */ -.pagination { - display: table; - width: 100%; - margin: 0; - padding: 0; - table-layout: fixed; -} -.pagination .item { - display: table-cell; -} -.pagination .pager-first, -.pagination .pager-previous, -.pagination .pager-next, -.pagination .pager-last { - width: 100px; -} - -/*=== STRUCTURE */ -/*===============*/ -/*=== Header */ -.header { - display: table; - width: 100%; - table-layout: fixed; -} -.header > .item { - display: table-cell; -} -.header > .item.title { - width: 250px; - white-space: nowrap; -} -.header > .item.title h1 { - display: inline-block; -} -.header > .item.title .logo { - display: inline-block; - height: 32px; - width: 32px; - vertical-align: middle; -} -.header > .item.configure { - width: 100px; -} - -/*=== Body */ -#global { - display: table; - width: 100%; - height: 100%; - table-layout: fixed; -} -.aside { - display: table-cell; - height: 100%; - width: 250px; - vertical-align: top; -} -.aside.aside_flux { - background: #fff; -} - -/*=== Aside main page (categories) */ -.categories { - list-style: none; - margin: 0; -} -.state_unread li:not(.active)[data-unread="0"] { - display: none; -} -.category { - display: block; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} -.category .btn:not([data-unread="0"]):after { - content: attr(data-unread); -} - -/*=== Aside main page (feeds) */ -.categories .feeds { - width: 100%; - list-style: none; -} -.categories .feeds:not(.active) { - display: none; -} -.categories .feeds .feed { - display: inline-block; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - vertical-align: middle; -} -.categories .feeds .feed:not([data-unread="0"]):before { - content: "(" attr(data-unread) ") "; -} -.categories .feeds .dropdown-menu { - left: 0; -} -.categories .feeds .item .dropdown-toggle > .icon { - visibility: hidden; - cursor: pointer; - vertical-align: top; -} -.categories .feeds .item .dropdown-target:target ~ .dropdown-toggle > .icon, -.categories .feeds .item:hover .dropdown-toggle > .icon, -.categories .feeds .item.active .dropdown-toggle > .icon { - visibility: visible; -} - -/*=== New article notification */ -#new-article { - display: none; -} -#new-article > a { - display: block; -} - -/*=== Day indication */ -.day .name { - position: absolute; - right: 0; - width: 50%; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - -/*=== Feed article header and footer */ -.flux_header { - position: relative; -} -.flux .item { - line-height: 40px; - white-space: nowrap; -} -.flux .item.manage, -.flux .item.link { - width: 40px; - text-align: center; -} -.flux .item.website { - width: 200px; -} -.flux.not_read .item.title, -.flux.current .item.title { - font-weight: bold; -} -.flux:not(.current):hover .item.title { - position: absolute; - max-width: calc(100% - 320px); - background: #fff; -} -.flux .item.title a { - color: #000; - text-decoration: none; -} -.flux .item.date { - width: 145px; - text-align: right; -} -.flux .item > a { - display: block; -} -.flux .item > a { - display: block; - text-decoration: none; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; -} -.flux .item.share > a { - display: list-item; - list-style-position: inside; - list-style-type: decimal; -} - -/*=== Feed article content */ -.hide_posts > .flux:not(.active) > .flux_content { - display: none; -} -.content { - min-height: 20em; - margin: auto; - line-height: 1.7em; - word-wrap: break-word; -} -.content.large { - max-width: 1000px; -} -.content.medium { - max-width: 800px; -} -.content.thin { - max-width: 550px; -} -.content ul, -.content ol, -.content dd { - margin: 0 0 0 15px; - padding: 0 0 5px 15px; -} -.content pre { - overflow: auto; -} - -/*=== Notification and actualize notification */ -.notification { - position: absolute; - top: 1em; - left: 25%; right: 25%; - z-index: 10; - background: #fff; - border: 1px solid #aaa; -} -.notification.closed { - display: none; -} -.notification a.close { - position: absolute; - top: 0; bottom: 0; - right: 0; - display: inline-block; -} - -#actualizeProgress { - position: fixed; -} -#actualizeProgress progress { - max-width: 100%; - vertical-align: middle; -} -#actualizeProgress .progress { - vertical-align: middle; -} - -/*=== Navigation menu (for articles) */ -#nav_entries { - position: fixed; - bottom: 0; left: 0; - display: table; - width: 250px; - background: #fff; - table-layout: fixed; -} -#nav_entries .item { - display: table-cell; - width: 30%; -} -#nav_entries a { - display: block; -} - -/*=== "Load more" part */ -#load_more { - min-height: 40px; -} -.loading { - background: url("loader.gif") center center no-repeat; - font-size: 0; -} -#bigMarkAsRead { - display: block; - padding: 3em 0; - text-align: center; -} -.bigTick { - font-size: 7em; - line-height: 1.6em; -} - -/*=== Statistiques */ -.stat > table { - width: 100%; -} - -/*=== GLOBAL VIEW */ -/*================*/ -/*=== Category boxes */ -#stream.global .box-category { - display: inline-block; - width: 19em; - max-width: 95%; - margin: 20px 10px; - border: 1px solid #ccc; - vertical-align: top; -} -#stream.global .category { - width: 100%; -} -#stream.global .btn { - display: block; -} -#stream.global .box-category .feeds { - display: block; - overflow: auto; -} -#stream.global .box-category .feed { - width: 19em; - max-width: 90%; -} - -/*=== Panel */ -#overlay { - display: none; - position: fixed; - top: 0; bottom: 0; - left: 0; right: 0; - background: rgba(0, 0, 0, 0.9); -} -#panel { - display: none; - position: fixed; - top: 1em; bottom: 1em; - left: 2em; right: 2em; - overflow: auto; - background: #fff; -} -#panel .close { - position: fixed; - top: 0; bottom: 0; - left: 0; right: 0; - display: block; -} -#panel .close img { - display: none; -} - -/*=== DIVERS */ -/*===========*/ -.nav-login, -.nav_menu .search, -.nav_menu .toggle_aside { - display: none; -} - -.aside .toggle_aside { - position: absolute; - right: 0; - display: none; - width: 30px; - height: 30px; - line-height: 30px; - text-align: center; -} - -/*=== MOBILE */ -/*===========*/ -@media(max-width: 840px) { - .header, - .aside .btn-important, - .aside .feeds .dropdown, - .flux_header .item.website span, - .item.date, .day .date, - .dropdown-menu > .no-mobile, - .no-mobile { - display: none; - } - .nav-login { - display: block; - } - .nav_menu .toggle_aside, - .aside .toggle_aside, - .nav_menu .search, - #panel .close img { - display: inline-block; - } - - .aside { - position: fixed; - top: 0; bottom: 0; - left: 0; - width: 0; - overflow: hidden; - z-index: 100; - } - .aside:target { - width: 90%; - overflow: auto; - } - .aside .categories { - margin: 10px 0 75px; - } - - .flux_header .item.website { - width: 40px; - } - - .flux:not(.current):hover .item.title { - position: relative; - width: auto; - white-space: nowrap; - } - - .notification { - top: 0; - left: 0; - right: 0; - } - - #nav_entries { - width: 100%; - } - - #stream.global .box-category { - margin: 10px 0; - } - - #panel { - top: 0; bottom: 0; - left: 0; right: 0; - } - #panel .close { - top: 0; right: 0; - left: auto; bottom: auto; - display: inline-block; - width: 30px; - height: 30px; - } -} - -/*=== PRINTER */ -/*============*/ -@media print { - .header, .aside, - .nav_menu, .day, - .flux_header, - .flux_content .bottom, - .pagination, - #nav_entries { - display: none; - } - html, body { - background: #fff; - color: #000; - font-family: Serif; - } - #global, - .flux_content { - display: block !important; - } - .flux_content .content { - width: 100% !important; - } - .flux_content .content a { - color: #000; - } - .flux_content .content a:after { - content: " [" attr(href) "] "; - font-style: italic; - } -} diff --git a/p/themes/Flat/metadata.json b/p/themes/Flat/metadata.json index 182c82470..3afdc98af 100644 --- a/p/themes/Flat/metadata.json +++ b/p/themes/Flat/metadata.json @@ -3,5 +3,5 @@ "author": "Marien Fressinaud", "description": "Thème plat pour FreshRSS", "version": 0.2, - "files": ["template.css", "flat.css"] + "files": ["_template.css", "flat.css"] } \ No newline at end of file diff --git a/p/themes/Flat/template.css b/p/themes/Flat/template.css deleted file mode 100644 index 466ec4603..000000000 --- a/p/themes/Flat/template.css +++ /dev/null @@ -1,698 +0,0 @@ -@charset "UTF-8"; - -/*=== GENERAL */ -/*============*/ -html, body { - margin: 0; - padding: 0; - font-size: 100%; -} - -/*=== Links */ -a { - text-decoration: none; -} -a:hover { - text-decoration: underline; -} - -/*=== Lists */ -ul, ol, dd { - margin: 0; - padding: 0; -} - -/*=== Titles */ -h1 { - margin: 0.6em 0 0.3em; - font-size: 1.5em; - line-height: 1.6em; -} -h2 { - margin: 0.5em 0 0.25em; - font-size: 1.3em; - line-height: 2em; -} -h3 { - margin: 0.5em 0 0.25em; - font-size: 1.1em; - line-height: 2em; -} - -/*=== Paragraphs */ -p { - margin: 1em 0 0.5em; - font-size: 1em; -} - -/*=== Images */ -img { - height: auto; - max-width: 100%; -} -img.favicon { - height: 16px; - width: 16px; - vertical-align: middle; -} - -/*=== Videos */ -iframe, embed, object, video { - max-width: 100%; -} - -/*=== Forms */ -legend { - display: block; - width: 100%; - clear: both; -} -label { - display: block; -} -input { - width: 180px; -} -textarea { - width: 300px; -} -input, select, textarea { - display: inline-block; - max-width: 100%; -} -input[type="radio"], -input[type="checkbox"] { - width: 15px !important; - min-height: 15px !important; -} -input.extend:focus { - width: 300px; -} - -/*=== COMPONENTS */ -/*===============*/ -/*=== Forms */ -.form-group:after { - content: ""; - display: block; - clear: both; -} -.form-group.form-actions { - min-width: 250px; -} -.form-group .group-name { - display: block; - float: left; - width: 200px; -} -.form-group .group-controls { - min-width: 250px; - margin: 0 0 0 220px; -} -.form-group .group-controls .control { - display: block; -} - -/*=== Buttons */ -.stick { - display: inline-block; - white-space: nowrap; -} -.btn, -a.btn { - display: inline-block; - cursor: pointer; - overflow: hidden; -} -.btn-important { - font-weight: bold; -} - -/*=== Navigation */ -.nav-list .nav-header, -.nav-list .item { - display: block; -} -.nav-list .item, -.nav-list .item > a { - display: block; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} -.nav-head { - display: block; -} -.nav-head .item { - display: inline-block; -} - -/*=== Horizontal-list */ -.horizontal-list { - display: table; - table-layout: fixed; - width: 100%; -} -.horizontal-list .item { - display: table-cell; -} - -/*=== Dropdown */ -.dropdown { - position: relative; - display: inline-block; -} -.dropdown-target { - display: none; -} -.dropdown-menu { - display: none; - min-width: 200px; - margin: 0; - position: absolute; - right: 0; - background: #fff; - border: 1px solid #aaa; -} -.dropdown-header { - display: block; -} -.dropdown-menu > .item { - display: block; -} -.dropdown-menu > .item > a, -.dropdown-menu > .item > span { - display: block; -} -.dropdown-menu > .item[aria-checked="true"] > a:before { - content: '✓'; -} -.dropdown-menu .input { - display: block; -} -.dropdown-menu .input select, -.dropdown-menu .input input { - display: block; - max-width: 95%; -} -.dropdown-target:target ~ .dropdown-menu { - display: block; - z-index: 10; -} -.dropdown-close { - display: inline; -} -.dropdown-close a { - font-size: 0; - position: fixed; - top: 0; bottom: 0; - left: 0; right: 0; - display: block; - z-index: -10; -} -.separator { - display: block; - height: 0; - border-bottom: 1px solid #aaa; -} - -/*=== Alerts */ -.alert { - display: block; - width: 90%; -} -.group-controls .alert { - width: 100% -} -.alert-head { - margin: 0; - font-weight: bold; -} -.alert ul { - margin: 5px 20px; -} - -/*=== Icons */ -.icon { - display: inline-block; - width: 16px; - height: 16px; - vertical-align: middle; - line-height: 16px; -} - -/*=== Pagination */ -.pagination { - display: table; - width: 100%; - margin: 0; - padding: 0; - table-layout: fixed; -} -.pagination .item { - display: table-cell; -} -.pagination .pager-first, -.pagination .pager-previous, -.pagination .pager-next, -.pagination .pager-last { - width: 100px; -} - -/*=== STRUCTURE */ -/*===============*/ -/*=== Header */ -.header { - display: table; - width: 100%; - table-layout: fixed; -} -.header > .item { - display: table-cell; -} -.header > .item.title { - width: 250px; - white-space: nowrap; -} -.header > .item.title h1 { - display: inline-block; -} -.header > .item.title .logo { - display: inline-block; - height: 32px; - width: 32px; - vertical-align: middle; -} -.header > .item.configure { - width: 100px; -} - -/*=== Body */ -#global { - display: table; - width: 100%; - height: 100%; - table-layout: fixed; -} -.aside { - display: table-cell; - height: 100%; - width: 250px; - vertical-align: top; -} -.aside.aside_flux { - background: #fff; -} - -/*=== Aside main page (categories) */ -.categories { - list-style: none; - margin: 0; -} -.state_unread li:not(.active)[data-unread="0"] { - display: none; -} -.category { - display: block; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} -.category .btn:not([data-unread="0"]):after { - content: attr(data-unread); -} - -/*=== Aside main page (feeds) */ -.categories .feeds { - width: 100%; - list-style: none; -} -.categories .feeds:not(.active) { - display: none; -} -.categories .feeds .feed { - display: inline-block; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - vertical-align: middle; -} -.categories .feeds .feed:not([data-unread="0"]):before { - content: "(" attr(data-unread) ") "; -} -.categories .feeds .dropdown-menu { - left: 0; -} -.categories .feeds .item .dropdown-toggle > .icon { - visibility: hidden; - cursor: pointer; - vertical-align: top; -} -.categories .feeds .item .dropdown-target:target ~ .dropdown-toggle > .icon, -.categories .feeds .item:hover .dropdown-toggle > .icon, -.categories .feeds .item.active .dropdown-toggle > .icon { - visibility: visible; -} - -/*=== New article notification */ -#new-article { - display: none; -} -#new-article > a { - display: block; -} - -/*=== Day indication */ -.day .name { - position: absolute; - right: 0; - width: 50%; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - -/*=== Feed article header and footer */ -.flux_header { - position: relative; -} -.flux .item { - line-height: 40px; - white-space: nowrap; -} -.flux .item.manage, -.flux .item.link { - width: 40px; - text-align: center; -} -.flux .item.website { - width: 200px; -} -.flux.not_read .item.title, -.flux.current .item.title { - font-weight: bold; -} -.flux:not(.current):hover .item.title { - position: absolute; - max-width: calc(100% - 320px); - background: #fff; -} -.flux .item.title a { - color: #000; - text-decoration: none; -} -.flux .item.date { - width: 145px; - text-align: right; -} -.flux .item > a { - display: block; -} -.flux .item > a { - display: block; - text-decoration: none; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; -} -.flux .item.share > a { - display: list-item; - list-style-position: inside; - list-style-type: decimal; -} - -/*=== Feed article content */ -.hide_posts > .flux:not(.active) > .flux_content { - display: none; -} -.content { - min-height: 20em; - margin: auto; - line-height: 1.7em; - word-wrap: break-word; -} -.content.large { - max-width: 1000px; -} -.content.medium { - max-width: 800px; -} -.content.thin { - max-width: 550px; -} -.content ul, -.content ol, -.content dd { - margin: 0 0 0 15px; - padding: 0 0 5px 15px; -} -.content pre { - overflow: auto; -} - -/*=== Notification and actualize notification */ -.notification { - position: absolute; - top: 1em; - left: 25%; right: 25%; - z-index: 10; - background: #fff; - border: 1px solid #aaa; -} -.notification.closed { - display: none; -} -.notification a.close { - position: absolute; - top: 0; bottom: 0; - right: 0; - display: inline-block; -} - -#actualizeProgress { - position: fixed; -} -#actualizeProgress progress { - max-width: 100%; - vertical-align: middle; -} -#actualizeProgress .progress { - vertical-align: middle; -} - -/*=== Navigation menu (for articles) */ -#nav_entries { - position: fixed; - bottom: 0; left: 0; - display: table; - width: 250px; - background: #fff; - table-layout: fixed; -} -#nav_entries .item { - display: table-cell; - width: 30%; -} -#nav_entries a { - display: block; -} - -/*=== "Load more" part */ -#load_more { - min-height: 40px; -} -.loading { - background: url("loader.gif") center center no-repeat; - font-size: 0; -} -#bigMarkAsRead { - display: block; - padding: 3em 0; - text-align: center; -} -.bigTick { - font-size: 7em; - line-height: 1.6em; -} - -/*=== Statistiques */ -.stat > table { - width: 100%; -} - -/*=== GLOBAL VIEW */ -/*================*/ -/*=== Category boxes */ -#stream.global .box-category { - display: inline-block; - width: 19em; - max-width: 95%; - margin: 20px 10px; - border: 1px solid #ccc; - vertical-align: top; -} -#stream.global .category { - width: 100%; -} -#stream.global .btn { - display: block; -} -#stream.global .box-category .feeds { - display: block; - overflow: auto; -} -#stream.global .box-category .feed { - width: 19em; - max-width: 90%; -} - -/*=== Panel */ -#overlay { - display: none; - position: fixed; - top: 0; bottom: 0; - left: 0; right: 0; - background: rgba(0, 0, 0, 0.9); -} -#panel { - display: none; - position: fixed; - top: 1em; bottom: 1em; - left: 2em; right: 2em; - overflow: auto; - background: #fff; -} -#panel .close { - position: fixed; - top: 0; bottom: 0; - left: 0; right: 0; - display: block; -} -#panel .close img { - display: none; -} - -/*=== DIVERS */ -/*===========*/ -.nav-login, -.nav_menu .search, -.nav_menu .toggle_aside { - display: none; -} - -.aside .toggle_aside { - position: absolute; - right: 0; - display: none; - width: 30px; - height: 30px; - line-height: 30px; - text-align: center; -} - -/*=== MOBILE */ -/*===========*/ -@media(max-width: 840px) { - .header, - .aside .btn-important, - .aside .feeds .dropdown, - .flux_header .item.website span, - .item.date, .day .date, - .dropdown-menu > .no-mobile, - .no-mobile { - display: none; - } - .nav-login { - display: block; - } - .nav_menu .toggle_aside, - .aside .toggle_aside, - .nav_menu .search, - #panel .close img { - display: inline-block; - } - - .aside { - position: fixed; - top: 0; bottom: 0; - left: 0; - width: 0; - overflow: hidden; - z-index: 100; - } - .aside:target { - width: 90%; - overflow: auto; - } - .aside .categories { - margin: 10px 0 75px; - } - - .flux_header .item.website { - width: 40px; - } - - .flux:not(.current):hover .item.title { - position: relative; - width: auto; - white-space: nowrap; - } - - .notification { - top: 0; - left: 0; - right: 0; - } - - #nav_entries { - width: 100%; - } - - #stream.global .box-category { - margin: 10px 0; - } - - #panel { - top: 0; bottom: 0; - left: 0; right: 0; - } - #panel .close { - top: 0; right: 0; - left: auto; bottom: auto; - display: inline-block; - width: 30px; - height: 30px; - } -} - -/*=== PRINTER */ -/*============*/ -@media print { - .header, .aside, - .nav_menu, .day, - .flux_header, - .flux_content .bottom, - .pagination, - #nav_entries { - display: none; - } - html, body { - background: #fff; - color: #000; - font-family: Serif; - } - #global, - .flux_content { - display: block !important; - } - .flux_content .content { - width: 100% !important; - } - .flux_content .content a { - color: #000; - } - .flux_content .content a:after { - content: " [" attr(href) "] "; - font-style: italic; - } -} diff --git a/p/themes/Origine/metadata.json b/p/themes/Origine/metadata.json index 59a45e8f6..774320eb4 100644 --- a/p/themes/Origine/metadata.json +++ b/p/themes/Origine/metadata.json @@ -3,5 +3,5 @@ "author": "Marien Fressinaud", "description": "Le thème par défaut pour FreshRSS", "version": 0.2, - "files": ["template.css", "origine.css"] + "files": ["_template.css", "origine.css"] } diff --git a/p/themes/Origine/template.css b/p/themes/Origine/template.css deleted file mode 100644 index 466ec4603..000000000 --- a/p/themes/Origine/template.css +++ /dev/null @@ -1,698 +0,0 @@ -@charset "UTF-8"; - -/*=== GENERAL */ -/*============*/ -html, body { - margin: 0; - padding: 0; - font-size: 100%; -} - -/*=== Links */ -a { - text-decoration: none; -} -a:hover { - text-decoration: underline; -} - -/*=== Lists */ -ul, ol, dd { - margin: 0; - padding: 0; -} - -/*=== Titles */ -h1 { - margin: 0.6em 0 0.3em; - font-size: 1.5em; - line-height: 1.6em; -} -h2 { - margin: 0.5em 0 0.25em; - font-size: 1.3em; - line-height: 2em; -} -h3 { - margin: 0.5em 0 0.25em; - font-size: 1.1em; - line-height: 2em; -} - -/*=== Paragraphs */ -p { - margin: 1em 0 0.5em; - font-size: 1em; -} - -/*=== Images */ -img { - height: auto; - max-width: 100%; -} -img.favicon { - height: 16px; - width: 16px; - vertical-align: middle; -} - -/*=== Videos */ -iframe, embed, object, video { - max-width: 100%; -} - -/*=== Forms */ -legend { - display: block; - width: 100%; - clear: both; -} -label { - display: block; -} -input { - width: 180px; -} -textarea { - width: 300px; -} -input, select, textarea { - display: inline-block; - max-width: 100%; -} -input[type="radio"], -input[type="checkbox"] { - width: 15px !important; - min-height: 15px !important; -} -input.extend:focus { - width: 300px; -} - -/*=== COMPONENTS */ -/*===============*/ -/*=== Forms */ -.form-group:after { - content: ""; - display: block; - clear: both; -} -.form-group.form-actions { - min-width: 250px; -} -.form-group .group-name { - display: block; - float: left; - width: 200px; -} -.form-group .group-controls { - min-width: 250px; - margin: 0 0 0 220px; -} -.form-group .group-controls .control { - display: block; -} - -/*=== Buttons */ -.stick { - display: inline-block; - white-space: nowrap; -} -.btn, -a.btn { - display: inline-block; - cursor: pointer; - overflow: hidden; -} -.btn-important { - font-weight: bold; -} - -/*=== Navigation */ -.nav-list .nav-header, -.nav-list .item { - display: block; -} -.nav-list .item, -.nav-list .item > a { - display: block; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} -.nav-head { - display: block; -} -.nav-head .item { - display: inline-block; -} - -/*=== Horizontal-list */ -.horizontal-list { - display: table; - table-layout: fixed; - width: 100%; -} -.horizontal-list .item { - display: table-cell; -} - -/*=== Dropdown */ -.dropdown { - position: relative; - display: inline-block; -} -.dropdown-target { - display: none; -} -.dropdown-menu { - display: none; - min-width: 200px; - margin: 0; - position: absolute; - right: 0; - background: #fff; - border: 1px solid #aaa; -} -.dropdown-header { - display: block; -} -.dropdown-menu > .item { - display: block; -} -.dropdown-menu > .item > a, -.dropdown-menu > .item > span { - display: block; -} -.dropdown-menu > .item[aria-checked="true"] > a:before { - content: '✓'; -} -.dropdown-menu .input { - display: block; -} -.dropdown-menu .input select, -.dropdown-menu .input input { - display: block; - max-width: 95%; -} -.dropdown-target:target ~ .dropdown-menu { - display: block; - z-index: 10; -} -.dropdown-close { - display: inline; -} -.dropdown-close a { - font-size: 0; - position: fixed; - top: 0; bottom: 0; - left: 0; right: 0; - display: block; - z-index: -10; -} -.separator { - display: block; - height: 0; - border-bottom: 1px solid #aaa; -} - -/*=== Alerts */ -.alert { - display: block; - width: 90%; -} -.group-controls .alert { - width: 100% -} -.alert-head { - margin: 0; - font-weight: bold; -} -.alert ul { - margin: 5px 20px; -} - -/*=== Icons */ -.icon { - display: inline-block; - width: 16px; - height: 16px; - vertical-align: middle; - line-height: 16px; -} - -/*=== Pagination */ -.pagination { - display: table; - width: 100%; - margin: 0; - padding: 0; - table-layout: fixed; -} -.pagination .item { - display: table-cell; -} -.pagination .pager-first, -.pagination .pager-previous, -.pagination .pager-next, -.pagination .pager-last { - width: 100px; -} - -/*=== STRUCTURE */ -/*===============*/ -/*=== Header */ -.header { - display: table; - width: 100%; - table-layout: fixed; -} -.header > .item { - display: table-cell; -} -.header > .item.title { - width: 250px; - white-space: nowrap; -} -.header > .item.title h1 { - display: inline-block; -} -.header > .item.title .logo { - display: inline-block; - height: 32px; - width: 32px; - vertical-align: middle; -} -.header > .item.configure { - width: 100px; -} - -/*=== Body */ -#global { - display: table; - width: 100%; - height: 100%; - table-layout: fixed; -} -.aside { - display: table-cell; - height: 100%; - width: 250px; - vertical-align: top; -} -.aside.aside_flux { - background: #fff; -} - -/*=== Aside main page (categories) */ -.categories { - list-style: none; - margin: 0; -} -.state_unread li:not(.active)[data-unread="0"] { - display: none; -} -.category { - display: block; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} -.category .btn:not([data-unread="0"]):after { - content: attr(data-unread); -} - -/*=== Aside main page (feeds) */ -.categories .feeds { - width: 100%; - list-style: none; -} -.categories .feeds:not(.active) { - display: none; -} -.categories .feeds .feed { - display: inline-block; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - vertical-align: middle; -} -.categories .feeds .feed:not([data-unread="0"]):before { - content: "(" attr(data-unread) ") "; -} -.categories .feeds .dropdown-menu { - left: 0; -} -.categories .feeds .item .dropdown-toggle > .icon { - visibility: hidden; - cursor: pointer; - vertical-align: top; -} -.categories .feeds .item .dropdown-target:target ~ .dropdown-toggle > .icon, -.categories .feeds .item:hover .dropdown-toggle > .icon, -.categories .feeds .item.active .dropdown-toggle > .icon { - visibility: visible; -} - -/*=== New article notification */ -#new-article { - display: none; -} -#new-article > a { - display: block; -} - -/*=== Day indication */ -.day .name { - position: absolute; - right: 0; - width: 50%; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - -/*=== Feed article header and footer */ -.flux_header { - position: relative; -} -.flux .item { - line-height: 40px; - white-space: nowrap; -} -.flux .item.manage, -.flux .item.link { - width: 40px; - text-align: center; -} -.flux .item.website { - width: 200px; -} -.flux.not_read .item.title, -.flux.current .item.title { - font-weight: bold; -} -.flux:not(.current):hover .item.title { - position: absolute; - max-width: calc(100% - 320px); - background: #fff; -} -.flux .item.title a { - color: #000; - text-decoration: none; -} -.flux .item.date { - width: 145px; - text-align: right; -} -.flux .item > a { - display: block; -} -.flux .item > a { - display: block; - text-decoration: none; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; -} -.flux .item.share > a { - display: list-item; - list-style-position: inside; - list-style-type: decimal; -} - -/*=== Feed article content */ -.hide_posts > .flux:not(.active) > .flux_content { - display: none; -} -.content { - min-height: 20em; - margin: auto; - line-height: 1.7em; - word-wrap: break-word; -} -.content.large { - max-width: 1000px; -} -.content.medium { - max-width: 800px; -} -.content.thin { - max-width: 550px; -} -.content ul, -.content ol, -.content dd { - margin: 0 0 0 15px; - padding: 0 0 5px 15px; -} -.content pre { - overflow: auto; -} - -/*=== Notification and actualize notification */ -.notification { - position: absolute; - top: 1em; - left: 25%; right: 25%; - z-index: 10; - background: #fff; - border: 1px solid #aaa; -} -.notification.closed { - display: none; -} -.notification a.close { - position: absolute; - top: 0; bottom: 0; - right: 0; - display: inline-block; -} - -#actualizeProgress { - position: fixed; -} -#actualizeProgress progress { - max-width: 100%; - vertical-align: middle; -} -#actualizeProgress .progress { - vertical-align: middle; -} - -/*=== Navigation menu (for articles) */ -#nav_entries { - position: fixed; - bottom: 0; left: 0; - display: table; - width: 250px; - background: #fff; - table-layout: fixed; -} -#nav_entries .item { - display: table-cell; - width: 30%; -} -#nav_entries a { - display: block; -} - -/*=== "Load more" part */ -#load_more { - min-height: 40px; -} -.loading { - background: url("loader.gif") center center no-repeat; - font-size: 0; -} -#bigMarkAsRead { - display: block; - padding: 3em 0; - text-align: center; -} -.bigTick { - font-size: 7em; - line-height: 1.6em; -} - -/*=== Statistiques */ -.stat > table { - width: 100%; -} - -/*=== GLOBAL VIEW */ -/*================*/ -/*=== Category boxes */ -#stream.global .box-category { - display: inline-block; - width: 19em; - max-width: 95%; - margin: 20px 10px; - border: 1px solid #ccc; - vertical-align: top; -} -#stream.global .category { - width: 100%; -} -#stream.global .btn { - display: block; -} -#stream.global .box-category .feeds { - display: block; - overflow: auto; -} -#stream.global .box-category .feed { - width: 19em; - max-width: 90%; -} - -/*=== Panel */ -#overlay { - display: none; - position: fixed; - top: 0; bottom: 0; - left: 0; right: 0; - background: rgba(0, 0, 0, 0.9); -} -#panel { - display: none; - position: fixed; - top: 1em; bottom: 1em; - left: 2em; right: 2em; - overflow: auto; - background: #fff; -} -#panel .close { - position: fixed; - top: 0; bottom: 0; - left: 0; right: 0; - display: block; -} -#panel .close img { - display: none; -} - -/*=== DIVERS */ -/*===========*/ -.nav-login, -.nav_menu .search, -.nav_menu .toggle_aside { - display: none; -} - -.aside .toggle_aside { - position: absolute; - right: 0; - display: none; - width: 30px; - height: 30px; - line-height: 30px; - text-align: center; -} - -/*=== MOBILE */ -/*===========*/ -@media(max-width: 840px) { - .header, - .aside .btn-important, - .aside .feeds .dropdown, - .flux_header .item.website span, - .item.date, .day .date, - .dropdown-menu > .no-mobile, - .no-mobile { - display: none; - } - .nav-login { - display: block; - } - .nav_menu .toggle_aside, - .aside .toggle_aside, - .nav_menu .search, - #panel .close img { - display: inline-block; - } - - .aside { - position: fixed; - top: 0; bottom: 0; - left: 0; - width: 0; - overflow: hidden; - z-index: 100; - } - .aside:target { - width: 90%; - overflow: auto; - } - .aside .categories { - margin: 10px 0 75px; - } - - .flux_header .item.website { - width: 40px; - } - - .flux:not(.current):hover .item.title { - position: relative; - width: auto; - white-space: nowrap; - } - - .notification { - top: 0; - left: 0; - right: 0; - } - - #nav_entries { - width: 100%; - } - - #stream.global .box-category { - margin: 10px 0; - } - - #panel { - top: 0; bottom: 0; - left: 0; right: 0; - } - #panel .close { - top: 0; right: 0; - left: auto; bottom: auto; - display: inline-block; - width: 30px; - height: 30px; - } -} - -/*=== PRINTER */ -/*============*/ -@media print { - .header, .aside, - .nav_menu, .day, - .flux_header, - .flux_content .bottom, - .pagination, - #nav_entries { - display: none; - } - html, body { - background: #fff; - color: #000; - font-family: Serif; - } - #global, - .flux_content { - display: block !important; - } - .flux_content .content { - width: 100% !important; - } - .flux_content .content a { - color: #000; - } - .flux_content .content a:after { - content: " [" attr(href) "] "; - font-style: italic; - } -} diff --git a/p/themes/Screwdriver/metadata.json b/p/themes/Screwdriver/metadata.json index f45f1a98a..46095e507 100644 --- a/p/themes/Screwdriver/metadata.json +++ b/p/themes/Screwdriver/metadata.json @@ -3,5 +3,5 @@ "author": "Mister aiR", "description": "C'est un cocktail ! C'est chaud mais « fresh » à la fois. Ce thème tue du chaton.", "version": 1.1, - "files": ["template.css","screwdriver.css"] + "files": ["_template.css","screwdriver.css"] } diff --git a/p/themes/Screwdriver/template.css b/p/themes/Screwdriver/template.css deleted file mode 100644 index ddb3f376f..000000000 --- a/p/themes/Screwdriver/template.css +++ /dev/null @@ -1,698 +0,0 @@ -@charset "UTF-8"; - -/*=== GENERAL */ -/*============*/ -html, body { - margin: 0; - padding: 0; - font-size: 92%; -} - -/*=== Links */ -a { - text-decoration: none; -} -a:hover { - text-decoration: underline; -} - -/*=== Lists */ -ul, ol, dd { - margin: 0; - padding: 0; -} - -/*=== Titles */ -h1 { - margin: 0.6em 0 0.3em; - font-size: 1.5em; - line-height: 1.6em; -} -h2 { - margin: 0.5em 0 0.25em; - font-size: 1.3em; - line-height: 2em; -} -h3 { - margin: 0.5em 0 0.25em; - font-size: 1.1em; - line-height: 2em; -} - -/*=== Paragraphs */ -p { - margin: 1em 0 0.5em; - font-size: 1em; -} - -/*=== Images */ -img { - height: auto; - max-width: 100%; -} -img.favicon { - height: 16px; - width: 16px; - vertical-align: middle; -} - -/*=== Videos */ -iframe, embed, object, video { - max-width: 100%; -} - -/*=== Forms */ -legend { - display: block; - width: 100%; - clear: both; -} -label { - display: block; -} -input { - width: 180px; -} -textarea { - width: 300px; -} -input, select, textarea { - display: inline-block; - max-width: 100%; -} -input[type="radio"], -input[type="checkbox"] { - width: 15px !important; - min-height: 15px !important; -} -input.extend:focus { - width: 300px; -} - -/*=== COMPONENTS */ -/*===============*/ -/*=== Forms */ -.form-group:after { - content: ""; - display: block; - clear: both; -} -.form-group.form-actions { - min-width: 250px; -} -.form-group .group-name { - display: block; - float: left; - width: 200px; -} -.form-group .group-controls { - min-width: 250px; - margin: 0 0 0 220px; -} -.form-group .group-controls .control { - display: block; -} - -/*=== Buttons */ -.stick { - display: inline-block; - white-space: nowrap; -} -.btn, -a.btn { - display: inline-block; - cursor: pointer; - overflow: hidden; -} -.btn-important { - font-weight: bold; -} - -/*=== Navigation */ -.nav-list .nav-header, -.nav-list .item { - display: block; -} -.nav-list .item, -.nav-list .item > a { - display: block; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} -.nav-head { - display: block; -} -.nav-head .item { - display: inline-block; -} - -/*=== Horizontal-list */ -.horizontal-list { - display: table; - table-layout: fixed; - width: 100%; -} -.horizontal-list .item { - display: table-cell; -} - -/*=== Dropdown */ -.dropdown { - position: relative; - display: inline-block; -} -.dropdown-target { - display: none; -} -.dropdown-menu { - display: none; - min-width: 200px; - margin: 0; - position: absolute; - right: 0; - background: #fff; - border: 1px solid #aaa; -} -.dropdown-header { - display: block; -} -.dropdown-menu > .item { - display: block; -} -.dropdown-menu > .item > a, -.dropdown-menu > .item > span { - display: block; -} -.dropdown-menu > .item[aria-checked="true"] > a:before { - content: '✓'; -} -.dropdown-menu .input { - display: block; -} -.dropdown-menu .input select, -.dropdown-menu .input input { - display: block; - max-width: 95%; -} -.dropdown-target:target ~ .dropdown-menu { - display: block; - z-index: 10; -} -.dropdown-close { - display: inline; -} -.dropdown-close a { - font-size: 0; - position: fixed; - top: 0; bottom: 0; - left: 0; right: 0; - display: block; - z-index: -10; -} -.separator { - display: block; - height: 0; - border-bottom: 1px solid #aaa; -} - -/*=== Alerts */ -.alert { - display: block; - width: 90%; -} -.group-controls .alert { - width: 100% -} -.alert-head { - margin: 0; - font-weight: bold; -} -.alert ul { - margin: 5px 20px; -} - -/*=== Icons */ -.icon { - display: inline-block; - width: 16px; - height: 16px; - vertical-align: middle; - line-height: 16px; -} - -/*=== Pagination */ -.pagination { - display: table; - width: 100%; - margin: 0; - padding: 0; - table-layout: fixed; -} -.pagination .item { - display: table-cell; -} -.pagination .pager-first, -.pagination .pager-previous, -.pagination .pager-next, -.pagination .pager-last { - width: 100px; -} - -/*=== STRUCTURE */ -/*===============*/ -/*=== Header */ -.header { - display: table; - width: 100%; - table-layout: fixed; -} -.header > .item { - display: table-cell; -} -.header > .item.title { - width: 250px; - white-space: nowrap; -} -.header > .item.title h1 { - display: inline-block; -} -.header > .item.title .logo { - display: inline-block; - height: 32px; - width: 32px; - vertical-align: middle; -} -.header > .item.configure { - width: 100px; -} - -/*=== Body */ -#global { - display: table; - width: 100%; - height: 100%; - table-layout: fixed; -} -.aside { - display: table-cell; - height: 100%; - width: 250px; - vertical-align: top; -} -.aside.aside_flux { - background: #fff; -} - -/*=== Aside main page (categories) */ -.categories { - list-style: none; - margin: 0; -} -.state_unread li:not(.active)[data-unread="0"] { - display: none; -} -.category { - display: block; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} -.category .btn:not([data-unread="0"]):after { - content: attr(data-unread); -} - -/*=== Aside main page (feeds) */ -.categories .feeds { - width: 100%; - list-style: none; -} -.categories .feeds:not(.active) { - display: none; -} -.categories .feeds .feed { - display: inline-block; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - vertical-align: middle; -} -.categories .feeds .feed:not([data-unread="0"]):before { - content: "(" attr(data-unread) ") "; -} -.categories .feeds .dropdown-menu { - left: 0; -} -.categories .feeds .item .dropdown-toggle > .icon { - visibility: hidden; - cursor: pointer; - vertical-align: top; -} -.categories .feeds .item .dropdown-target:target ~ .dropdown-toggle > .icon, -.categories .feeds .item:hover .dropdown-toggle > .icon, -.categories .feeds .item.active .dropdown-toggle > .icon { - visibility: visible; -} - -/*=== New article notification */ -#new-article { - display: none; -} -#new-article > a { - display: block; -} - -/*=== Day indication */ -.day .name { - position: absolute; - right: 0; - width: 50%; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - -/*=== Feed article header and footer */ -.flux_header { - position: relative; -} -.flux .item { - line-height: 40px; - white-space: nowrap; -} -.flux .item.manage, -.flux .item.link { - width: 40px; - text-align: center; -} -.flux .item.website { - width: 200px; -} -.flux.not_read .item.title, -.flux.current .item.title { - font-weight: bold; -} -.flux:not(.current):hover .item.title { - position: absolute; - max-width: calc(100% - 320px); - background: #fff; -} -.flux .item.title a { - color: #000; - text-decoration: none; -} -.flux .item.date { - width: 145px; - text-align: right; -} -.flux .item > a { - display: block; -} -.flux .item > a { - display: block; - text-decoration: none; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; -} -.flux .item.share > a { - display: list-item; - list-style-position: inside; - list-style-type: decimal; -} - -/*=== Feed article content */ -.hide_posts > .flux:not(.active) > .flux_content { - display: none; -} -.content { - min-height: 20em; - margin: auto; - line-height: 1.7em; - word-wrap: break-word; -} -.content.large { - max-width: 1000px; -} -.content.medium { - max-width: 800px; -} -.content.thin { - max-width: 550px; -} -.content ul, -.content ol, -.content dd { - margin: 0 0 0 15px; - padding: 0 0 5px 15px; -} -.content pre { - overflow: auto; -} - -/*=== Notification and actualize notification */ -.notification { - position: absolute; - top: 1em; - left: 25%; right: 25%; - z-index: 10; - background: #fff; - border: 1px solid #aaa; -} -.notification.closed { - display: none; -} -.notification a.close { - position: absolute; - top: 0; bottom: 0; - right: 0; - display: inline-block; -} - -#actualizeProgress { - position: fixed; -} -#actualizeProgress progress { - max-width: 100%; - vertical-align: middle; -} -#actualizeProgress .progress { - vertical-align: middle; -} - -/*=== Navigation menu (for articles) */ -#nav_entries { - position: fixed; - bottom: 0; left: 0; - display: table; - width: 250px; - background: #fff; - table-layout: fixed; -} -#nav_entries .item { - display: table-cell; - width: 30%; -} -#nav_entries a { - display: block; -} - -/*=== "Load more" part */ -#load_more { - min-height: 40px; -} -.loading { - background: url("loader.gif") center center no-repeat; - font-size: 0; -} -#bigMarkAsRead { - display: block; - padding: 3em 0; - text-align: center; -} -.bigTick { - font-size: 7em; - line-height: 1.6em; -} - -/*=== Statistiques */ -.stat > table { - width: 100%; -} - -/*=== GLOBAL VIEW */ -/*================*/ -/*=== Category boxes */ -#stream.global .box-category { - display: inline-block; - width: 19em; - max-width: 95%; - margin: 20px 10px; - border: 1px solid #ccc; - vertical-align: top; -} -#stream.global .category { - width: 100%; -} -#stream.global .btn { - display: block; -} -#stream.global .box-category .feeds { - display: block; - overflow: auto; -} -#stream.global .box-category .feed { - width: 19em; - max-width: 90%; -} - -/*=== Panel */ -#overlay { - display: none; - position: fixed; - top: 0; bottom: 0; - left: 0; right: 0; - background: rgba(0, 0, 0, 0.9); -} -#panel { - display: none; - position: fixed; - top: 1em; bottom: 1em; - left: 2em; right: 2em; - overflow: auto; - background: #fff; -} -#panel .close { - position: fixed; - top: 0; bottom: 0; - left: 0; right: 0; - display: block; -} -#panel .close img { - display: none; -} - -/*=== DIVERS */ -/*===========*/ -.nav-login, -.nav_menu .search, -.nav_menu .toggle_aside { - display: none; -} - -.aside .toggle_aside { - position: absolute; - right: 0; - display: none; - width: 30px; - height: 30px; - line-height: 30px; - text-align: center; -} - -/*=== MOBILE */ -/*===========*/ -@media(max-width: 840px) { - .header, - .aside .btn-important, - .aside .feeds .dropdown, - .flux_header .item.website span, - .item.date, .day .date, - .dropdown-menu > .no-mobile, - .no-mobile { - display: none; - } - .nav-login { - display: block; - } - .nav_menu .toggle_aside, - .aside .toggle_aside, - .nav_menu .search, - #panel .close img { - display: inline-block; - } - - .aside { - position: fixed; - top: 0; bottom: 0; - left: 0; - width: 0; - overflow: hidden; - z-index: 100; - } - .aside:target { - width: 90%; - overflow: auto; - } - .aside .categories { - margin: 10px 0 75px; - } - - .flux_header .item.website { - width: 40px; - } - - .flux:not(.current):hover .item.title { - position: relative; - width: auto; - white-space: nowrap; - } - - .notification { - top: 0; - left: 0; - right: 0; - } - - #nav_entries { - width: 100%; - } - - #stream.global .box-category { - margin: 10px 0; - } - - #panel { - top: 0; bottom: 0; - left: 0; right: 0; - } - #panel .close { - top: 0; right: 0; - left: auto; bottom: auto; - display: inline-block; - width: 30px; - height: 30px; - } -} - -/*=== PRINTER */ -/*============*/ -@media print { - .header, .aside, - .nav_menu, .day, - .flux_header, - .flux_content .bottom, - .pagination, - #nav_entries { - display: none; - } - html, body { - background: #fff; - color: #000; - font-family: Serif; - } - #global, - .flux_content { - display: block !important; - } - .flux_content .content { - width: 100% !important; - } - .flux_content .content a { - color: #000; - } - .flux_content .content a:after { - content: " [" attr(href) "] "; - font-style: italic; - } -} -- cgit v1.2.3 From 1e5efc92993feddb7916ef675010d0de0e470ac5 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 16 Sep 2014 14:23:04 +0200 Subject: Mark many as read must be a POST action See https://github.com/marienfressinaud/FreshRSS/issues/599 --- app/Controllers/entryController.php | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'app/Controllers') diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php index ac43587ea..ab66d9198 100755 --- a/app/Controllers/entryController.php +++ b/app/Controllers/entryController.php @@ -45,6 +45,10 @@ class FreshRSS_entry_Controller extends Minz_ActionController { $entryDAO = FreshRSS_Factory::createEntryDao(); if ($id == false) { + if (!Minz_Request::isPost()) { + return; + } + if (!$get) { $entryDAO->markReadEntries ($idMax); } else { -- cgit v1.2.3 From a4e43e9c53ac404d16af5d913a56eeb444b1ce10 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 16 Sep 2014 18:30:24 +0200 Subject: Message if last update checking is close last_update.txt is updated even if there is no update If last_update.txt has been modified during last hour, show a message See https://github.com/marienfressinaud/FreshRSS/issues/480#issuecomment-55765373 --- app/Controllers/updateController.php | 11 ++++++----- app/i18n/en.php | 2 +- app/i18n/fr.php | 2 +- app/views/update/index.phtml | 17 +++++++++++++---- 4 files changed, 21 insertions(+), 11 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index 4c1dd002c..72244e9c7 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -12,9 +12,11 @@ class FreshRSS_update_Controller extends Minz_ActionController { Minz_View::prependTitle(_t('update_system') . ' · '); $this->view->last_update_time = 'unknown'; + $this->view->check_last_hour = false; $timestamp = (int)@file_get_contents(DATA_PATH . '/last_update.txt'); if (is_numeric($timestamp) && $timestamp > 0) { $this->view->last_update_time = timestamptodate($timestamp); + $this->view->check_last_hour = (time() - 3600) <= $timestamp; } } @@ -38,13 +40,10 @@ class FreshRSS_update_Controller extends Minz_ActionController { public function checkAction() { $this->view->change_view('update', 'index'); - // Get the last update. If already check during the last hour, do nothing. - $last_update = (int)@file_get_contents(DATA_PATH . '/last_update.txt'); - $check_last_hour = (time() - 3600) <= $last_update; - - if (file_exists(UPDATE_FILENAME) || $check_last_hour) { + if (file_exists(UPDATE_FILENAME) || $this->view->check_last_hour) { // There is already an update file to apply: we don't need to check // the webserver! + // Or if already check during the last hour, do nothing. Minz_Request::forward(array('c' => 'update')); return; @@ -81,6 +80,8 @@ class FreshRSS_update_Controller extends Minz_ActionController { 'body' => _t('no_update') ); + @file_put_contents(DATA_PATH . '/last_update.txt', time()); + return; } diff --git a/app/i18n/en.php b/app/i18n/en.php index c5911cde7..8f39115ad 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -424,7 +424,7 @@ return array ( 'update' => 'Update', 'update_system' => 'Update system', 'update_check' => 'Check for new updates', - 'update_last' => 'Last update: %s', + 'update_last' => 'Last verification: %s', 'update_can_apply' => 'There is an available update. Apply', 'update_server_not_found' => 'Update server cannot be found. [%s]', 'no_update' => 'No update to apply', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 789a0bb98..48b4c1732 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -424,7 +424,7 @@ return array ( 'update' => 'Mise à jour', 'update_system' => 'Système de mise à jour', 'update_check' => 'Vérifier les mises à jour', - 'update_last' => 'Dernière mise à jour : %s', + 'update_last' => 'Dernière vérification : %s', 'update_can_apply' => 'Il y’a une mise à jour à appliquer. Appliquer la mise à jour', 'update_server_not_found' => 'Le serveur de mise à jour n’a pas été trouvé. [%s]', 'no_update' => 'Aucune mise à jour à appliquer', diff --git a/app/views/update/index.phtml b/app/views/update/index.phtml index 1824c02b8..5be8b1e8b 100644 --- a/app/views/update/index.phtml +++ b/app/views/update/index.phtml @@ -5,17 +5,26 @@

+

+ last_update_time); ?> +

+ message)) { ?>

message['title']; ?> message['body']; ?>

+ check_last_hour) { ?> +

+ + +

- message) || $this->message['status'] !== 'good') { ?> -

- last_update_time); ?> -

+ check_last_hour && + (empty($this->message) || $this->message['status'] !== 'good')) { + ?>

-- cgit v1.2.3 From 7d5e57b35b4eca07417c296c156edb3b88eef90b Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 17 Sep 2014 09:15:19 +0200 Subject: Load $nb/2 articles when articles are unfolded See https://github.com/marienfressinaud/FreshRSS/issues/559 --- app/Controllers/indexController.php | 5 +++++ app/layout/layout.phtml | 1 + app/views/helpers/pagination.phtml | 5 ++++- 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'app/Controllers') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index b0b051119..1d74a570b 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -83,6 +83,11 @@ class FreshRSS_index_Controller extends Minz_ActionController { $nb = Minz_Request::param ('nb', $this->view->conf->posts_per_page); $first = Minz_Request::param ('next', ''); + $ajax_request = Minz_Request::param('ajax', false); + if ($ajax_request == 1 && $this->view->conf->display_posts) { + $nb = max(1, round($nb / 2)); + } + if ($this->view->state === FreshRSS_Entry::STATE_NOT_READ) { //Any unread article in this category at all? switch ($getType) { case 'a': diff --git a/app/layout/layout.phtml b/app/layout/layout.phtml index 96a88d245..f95f45b5e 100644 --- a/app/layout/layout.phtml +++ b/app/layout/layout.phtml @@ -13,6 +13,7 @@ if (!empty($this->nextId)) { $params = Minz_Request::params(); $params['next'] = $this->nextId; + $params['ajax'] = 1; ?> diff --git a/app/views/helpers/pagination.phtml b/app/views/helpers/pagination.phtml index f6fcbc701..1b15cc632 100755 --- a/app/views/helpers/pagination.phtml +++ b/app/views/helpers/pagination.phtml @@ -9,7 +9,10 @@
  • nextId)) { ?> - nextId; ?> + nextId; + $params['ajax'] = 1; + ?> -- cgit v1.2.3 From a3b5e72729be08f79585c782d497f49edd11c064 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 17 Sep 2014 13:26:32 +0200 Subject: Move button to apply update outside the message --- app/Controllers/updateController.php | 4 +++- app/i18n/en.php | 3 ++- app/i18n/fr.php | 3 ++- app/views/update/index.phtml | 4 ++++ 4 files changed, 11 insertions(+), 3 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index 72244e9c7..78d636163 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -11,6 +11,7 @@ class FreshRSS_update_Controller extends Minz_ActionController { } Minz_View::prependTitle(_t('update_system') . ' · '); + $this->view->update_to_apply = false; $this->view->last_update_time = 'unknown'; $this->view->check_last_hour = false; $timestamp = (int)@file_get_contents(DATA_PATH . '/last_update.txt'); @@ -29,10 +30,11 @@ class FreshRSS_update_Controller extends Minz_ActionController { ); } elseif (file_exists(UPDATE_FILENAME)) { // There is an update file to apply! + $this->view->update_to_apply = true; $this->view->message = array( 'status' => 'good', 'title' => _t('ok'), - 'body' => _t('update_can_apply', _url('update', 'apply')) + 'body' => _t('update_can_apply') ); } } diff --git a/app/i18n/en.php b/app/i18n/en.php index 562697585..f84593cb5 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -428,7 +428,8 @@ return array ( 'update_system' => 'Update system', 'update_check' => 'Check for new updates', 'update_last' => 'Last verification: %s', - 'update_can_apply' => 'There is an available update. Apply', + 'update_can_apply' => 'There is an available update.', + 'update_apply' => 'Apply', 'update_server_not_found' => 'Update server cannot be found. [%s]', 'no_update' => 'No update to apply', 'update_problem' => 'Update has encountered an error: %s', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 9516f66cb..da5819529 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -428,7 +428,8 @@ return array ( 'update_system' => 'Système de mise à jour', 'update_check' => 'Vérifier les mises à jour', 'update_last' => 'Dernière vérification : %s', - 'update_can_apply' => 'Il y’a une mise à jour à appliquer. Appliquer la mise à jour', + 'update_can_apply' => 'Il y’a une mise à jour à appliquer.', + 'update_apply' => 'Appliquer la mise à jour', 'update_server_not_found' => 'Le serveur de mise à jour n’a pas été trouvé. [%s]', 'no_update' => 'Aucune mise à jour à appliquer', 'update_problem' => 'La mise à jour a rencontré un problème : %s', diff --git a/app/views/update/index.phtml b/app/views/update/index.phtml index 5be8b1e8b..401f6acd6 100644 --- a/app/views/update/index.phtml +++ b/app/views/update/index.phtml @@ -29,4 +29,8 @@

    + + update_to_apply) { ?> + + -- cgit v1.2.3 From 3b8c381689334a15e7c034425f8615860dc3fa13 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 17 Sep 2014 13:37:39 +0200 Subject: No cache for update system See https://github.com/marienfressinaud/FreshRSS/issues/616 --- app/Controllers/updateController.php | 2 ++ 1 file changed, 2 insertions(+) (limited to 'app/Controllers') diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index 78d636163..da5bddc65 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -10,6 +10,8 @@ class FreshRSS_update_Controller extends Minz_ActionController { ); } + invalidateHttpCache(); + Minz_View::prependTitle(_t('update_system') . ' · '); $this->view->update_to_apply = false; $this->view->last_update_time = 'unknown'; -- cgit v1.2.3 From 4211539c24e36531f2c5440ad454c4e208131047 Mon Sep 17 00:00:00 2001 From: plopoyop Date: Thu, 18 Sep 2014 10:46:34 +0200 Subject: Add timeout option for HTML5 notification --- app/Controllers/configureController.php | 1 + app/Models/Configuration.php | 7 +++++++ app/i18n/de.php | 2 ++ app/i18n/en.php | 2 ++ app/i18n/fr.php | 2 ++ app/views/configure/display.phtml | 7 +++++++ app/views/helpers/javascript_vars.phtml | 2 ++ p/scripts/main.js | 6 ++++++ 8 files changed, 29 insertions(+) (limited to 'app/Controllers') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index bb96bfae3..b1cd45014 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -157,6 +157,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $this->view->conf->_bottomline_tags(Minz_Request::param('bottomline_tags', false)); $this->view->conf->_bottomline_date(Minz_Request::param('bottomline_date', false)); $this->view->conf->_bottomline_link(Minz_Request::param('bottomline_link', false)); + $this->view->conf->_html5_notif_timeout(Minz_Request::param('html5_notif_timeout', 0)); $this->view->conf->save(); Minz_Session::_param('language', $this->view->conf->language); diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index e4408df73..830d39f0d 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -60,6 +60,7 @@ class FreshRSS_Configuration { 'bottomline_link' => true, 'sharing' => array(), 'queries' => array(), + 'html5_notif_timeout' => 0, ); private $available_languages = array( @@ -269,6 +270,12 @@ class FreshRSS_Configuration { $this->data['content_width'] = 'thin'; } } + + public function _html5_notif_timeout ($value) { + $value = intval($value); + $this->data['html5_notif_timeout'] = $value >= 0 ? $value : 0; + } + public function _token($value) { $this->data['token'] = $value; } diff --git a/app/i18n/de.php b/app/i18n/de.php index 4301a8b6d..3f7d8ca27 100644 --- a/app/i18n/de.php +++ b/app/i18n/de.php @@ -212,6 +212,8 @@ return array ( 'reading_icons' => 'Lese Symbol', 'top_line' => 'Kopfzeile', 'bottom_line' => 'Fusszeile', + 'html5_notif_timeout' => 'HTML5 notification timeout', + 'seconds_(0_means_no_timeout)' => 'seconds (0 means no timeout)', 'img_with_lazyload' => 'Verwende die "träge laden" Methode zum laden von Bildern', 'auto_read_when' => 'Artikel als gelesen markieren…', 'article_selected' => 'wenn der Artikel ausgewählt ist', diff --git a/app/i18n/en.php b/app/i18n/en.php index 8f39115ad..1e842a1e1 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -280,6 +280,8 @@ return array ( 'article_icons' => 'Article icons', 'top_line' => 'Top line', 'bottom_line' => 'Bottom line', + 'html5_notif_timeout' => 'HTML5 notification timeout', + 'seconds_(0_means_no_timeout)' => 'seconds (0 means no timeout)', 'img_with_lazyload' => 'Use "lazy load" mode to load pictures', 'sticky_post' => 'Stick the article to the top when opened', 'reading_confirm' => 'Display a confirmation dialog on “mark all as read” actions', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 48b4c1732..bbfa71f66 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -280,6 +280,8 @@ return array ( 'article_icons' => 'Icônes d’article', 'top_line' => 'Ligne du haut', 'bottom_line' => 'Ligne du bas', + 'html5_notif_timeout' => 'Temps d\'affichage de la notification HTML5', + 'seconds_(0_means_no_timeout)' => 'secondes (0 signifie aucun timeout ) ', 'img_with_lazyload' => 'Utiliser le mode “chargement différé” pour les images', 'sticky_post' => 'Aligner l’article en haut quand il est ouvert', 'reading_confirm' => 'Afficher une confirmation lors des actions “marquer tout comme lu”', diff --git a/app/views/configure/display.phtml b/app/views/configure/display.phtml index 955fc6747..8eb3a156b 100644 --- a/app/views/configure/display.phtml +++ b/app/views/configure/display.phtml @@ -91,6 +91,13 @@
    + +
    + +
    + +
    +
    diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 2144f1576..bf0ffdb76 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -54,6 +54,8 @@ echo 'authType="', $authType, '",', echo 'str_confirmation="', Minz_Translate::t('confirm_action'), '"', ",\n"; echo 'str_notif_title_articles="', Minz_Translate::t('notif_title_new_articles'), '"', ",\n"; echo 'str_notif_body_articles="', Minz_Translate::t('notif_body_new_articles'), '"', ",\n"; +echo 'html5_notif_timeout=', $this->conf->html5_notif_timeout,",\n"; + $autoActualise = Minz_Session::param('actualize_feeds', false); echo 'auto_actualize_feeds=', $autoActualise ? 'true' : 'false', ";\n"; diff --git a/p/scripts/main.js b/p/scripts/main.js index fd49d62ba..c568bac35 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -866,6 +866,12 @@ function notifs_html5_show(nb) { notification.onclick = function() { window.location.reload(); } + + if (html5_notif_timeout !== 0){ + setTimeout(function() { + notification.close(); + }, html5_notif_timeout * 1000); + } } function init_notifs_html5() { -- cgit v1.2.3 From 23609ad858552c54fc3fe8d9f8e2f7d966fd28a1 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 18 Sep 2014 14:18:00 +0200 Subject: Add page for reset auth type [NOT WORKING] See https://github.com/marienfressinaud/FreshRSS/issues/521 --- app/Controllers/indexController.php | 77 +++++++++++++++++++++++++++++++++++++ app/views/index/resetAuth.phtml | 33 ++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 app/views/index/resetAuth.phtml (limited to 'app/Controllers') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 1d74a570b..fccf16ecf 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -420,4 +420,81 @@ class FreshRSS_index_Controller extends Minz_ActionController { self::deleteLongTermCookie(); Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true); } + + public function resetAuthAction() { + Minz_View::prependTitle(_t('reset_auth') . ' · '); + + $this->view->no_form = false; + // Enable changement of auth only if Persona! + if (Minz_Configuration::authType() != 'persona') { + $this->view->message = array( + 'status' => 'bad', + 'title' => _t('damn'), + 'body' => _t('auth_not_persona') + ); + $this->view->no_form = true; + return; + } + + $conf = new FreshRSS_Configuration(Minz_Configuration::defaultUser()); + // Admin user must have set its master password. + if (!$conf->passwordHash) { + $this->view->message = array( + 'status' => 'bad', + 'title' => _t('damn'), + 'body' => _t('auth_no_password_set') + ); + $this->view->no_form = true; + return; + } + + if (Minz_Request::isPost()) { + $nonce = Minz_Session::param('nonce'); + $username = Minz_Request::param('username', ''); + $c = Minz_Request::param('challenge', ''); + if (!(ctype_alnum($username) && ctype_graph($c) && ctype_alnum($nonce))) { + Minz_Log::debug('Invalid credential parameters:' . + ' user=' . $username . + ' challenge=' . $c . + ' nonce=' . $nonce); + Minz_Session::_param('notification', array( + 'type' => 'bad', + 'content' => Minz_Translate::t('invalid_login') + )); + return; + } + + if (!function_exists('password_verify')) { + include_once(LIB_PATH . '/password_compat.php'); + } + + try { + $s = $conf->passwordHash; + $ok = password_verify($nonce . $s, $c); + if (!$ok) { + Minz_Log::debug('Password mismatch for user ' . $username . + ', nonce=' . $nonce . ', c=' . $c); + Minz_Session::_param('notification', array( + 'type' => 'bad', + 'content' => Minz_Translate::t('invalid_login') + )); + return; + } + + Minz_Configuration::_authType('form'); + $ok = Minz_Configuration::writeFile(); + + if ($ok) { + Minz_Request::good(_t('auth_form_set')); + } else { + Minz_Session::_param('notification', array( + 'type' => 'bad', + 'content' => _t('auth_form_not_set') + )); + } + } catch (Minz_Exception $e) { + Minz_Log::warning('Login failure: ' . $e->getMessage()); + } + } + } } diff --git a/app/views/index/resetAuth.phtml b/app/views/index/resetAuth.phtml new file mode 100644 index 000000000..7f3b54bdb --- /dev/null +++ b/app/views/index/resetAuth.phtml @@ -0,0 +1,33 @@ +
    +

    + + message)) { ?> +

    + message['title']; ?> + message['body']; ?> +

    + + + no_form) { ?> +
    +

    + + +

    + +
    + + +
    +
    + + +
    + +
    +
    + +
    +
    + +
    -- cgit v1.2.3 From f727a1383639d5bdc762f73dfe93b9a5d577cb41 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 18 Sep 2014 14:50:54 +0200 Subject: Improve reset auth system - Add bcrypt.js in resetAuthAction() - Rename init_loginForm() in init_crypto_form() - Load init_crypto_form() everytime (if no #crypto-form, do nothing) --- app/Controllers/indexController.php | 3 +++ app/views/index/formLogin.phtml | 2 +- app/views/index/resetAuth.phtml | 2 +- p/scripts/main.js | 27 +++++++++++++++------------ 4 files changed, 20 insertions(+), 14 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index fccf16ecf..86863cc84 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -423,6 +423,9 @@ class FreshRSS_index_Controller extends Minz_ActionController { public function resetAuthAction() { Minz_View::prependTitle(_t('reset_auth') . ' · '); + Minz_View::appendScript(Minz_Url::display( + '/scripts/bcrypt.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js') + )); $this->view->no_form = false; // Enable changement of auth only if Persona! diff --git a/app/views/index/formLogin.phtml b/app/views/index/formLogin.phtml index b79c1b614..34f10de4a 100644 --- a/app/views/index/formLogin.phtml +++ b/app/views/index/formLogin.phtml @@ -3,7 +3,7 @@ switch (Minz_Configuration::authType()) { case 'form': - ?>
    + ?>
    diff --git a/app/views/index/resetAuth.phtml b/app/views/index/resetAuth.phtml index 7f3b54bdb..78cc527b3 100644 --- a/app/views/index/resetAuth.phtml +++ b/app/views/index/resetAuth.phtml @@ -9,7 +9,7 @@ no_form) { ?> - +

    diff --git a/p/scripts/main.js b/p/scripts/main.js index fd49d62ba..04151c30d 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -977,7 +977,7 @@ function init_load_more(box) { } // -// +// function poormanSalt() { //If crypto.getRandomValues is not available var text = '$2a$04$', base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ.0123456789/abcdefghijklmnopqrstuvwxyz'; @@ -987,20 +987,24 @@ function poormanSalt() { //If crypto.getRandomValues is not available return text; } -function init_loginForm() { - var $loginForm = $('#loginForm'); - if ($loginForm.length === 0) { +function init_crypto_form() { + var $crypto_form = $('#crypto-form'); + if ($crypto_form.length === 0) { return; } + if (!(window.dcodeIO)) { if (window.console) { console.log('FreshRSS waiting for bcrypt.js…'); } - window.setTimeout(init_loginForm, 100); + window.setTimeout(init_crypto_form, 100); return; } - $loginForm.on('submit', function() { - $('#loginButton').attr('disabled', ''); + + $crypto_form.on('submit', function() { + var $submit_button = $(this).find('button[type="submit"]'); + $submit_button.attr('disabled', ''); + var success = false; $.ajax({ url: './?c=javascript&a=nonce&user=' + $('#username').val(), @@ -1027,11 +1031,12 @@ function init_loginForm() { }).fail(function() { alert('Communication error!'); }); - $('#loginButton').removeAttr('disabled'); + + $submit_button.removeAttr('disabled'); return success; }); } -// +// // function init_persona() { @@ -1233,14 +1238,12 @@ function init_all() { } init_notifications(); switch (authType) { - case 'form': - init_loginForm(); - break; case 'persona': init_persona(); break; } init_confirm_action(); + init_crypto_form(); $stream = $('#stream'); if ($stream.length > 0) { init_actualize(); -- cgit v1.2.3 From d2799d168e0d885cb6de24cf012e2a909215fcd8 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 18 Sep 2014 15:09:47 +0200 Subject: Improve resetAuth redirections See https://github.com/marienfressinaud/FreshRSS/issues/521 --- app/Controllers/indexController.php | 39 ++++++++++++++----------------------- 1 file changed, 15 insertions(+), 24 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 86863cc84..26e2618f0 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -451,6 +451,8 @@ class FreshRSS_index_Controller extends Minz_ActionController { return; } + invalidateHttpCache(); + if (Minz_Request::isPost()) { $nonce = Minz_Session::param('nonce'); $username = Minz_Request::param('username', ''); @@ -460,43 +462,32 @@ class FreshRSS_index_Controller extends Minz_ActionController { ' user=' . $username . ' challenge=' . $c . ' nonce=' . $nonce); - Minz_Session::_param('notification', array( - 'type' => 'bad', - 'content' => Minz_Translate::t('invalid_login') - )); - return; + Minz_Request::bad(_t('invalid_login'), + array('c' => 'index', 'a' => 'resetAuth')); } if (!function_exists('password_verify')) { include_once(LIB_PATH . '/password_compat.php'); } - try { - $s = $conf->passwordHash; - $ok = password_verify($nonce . $s, $c); - if (!$ok) { - Minz_Log::debug('Password mismatch for user ' . $username . - ', nonce=' . $nonce . ', c=' . $c); - Minz_Session::_param('notification', array( - 'type' => 'bad', - 'content' => Minz_Translate::t('invalid_login') - )); - return; - } - + $s = $conf->passwordHash; + $ok = password_verify($nonce . $s, $c); + if ($ok) { Minz_Configuration::_authType('form'); $ok = Minz_Configuration::writeFile(); if ($ok) { Minz_Request::good(_t('auth_form_set')); } else { - Minz_Session::_param('notification', array( - 'type' => 'bad', - 'content' => _t('auth_form_not_set') - )); + Minz_Request::bad(_t('auth_form_not_set'), + array('c' => 'index', 'a' => 'resetAuth')); } - } catch (Minz_Exception $e) { - Minz_Log::warning('Login failure: ' . $e->getMessage()); + } else { + Minz_Log::debug('Password mismatch for user ' . $username . + ', nonce=' . $nonce . ', c=' . $c); + + Minz_Request::bad(_t('invalid_login'), + array('c' => 'index', 'a' => 'resetAuth')); } } } -- cgit v1.2.3 From 94915f1c0a477c240e6072b6ccc2f71152181510 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 18 Sep 2014 15:32:59 +0200 Subject: Reset auth system: i18n and style See https://github.com/marienfressinaud/FreshRSS/issues/521 --- app/Controllers/indexController.php | 2 +- app/i18n/en.php | 10 ++++++++++ app/i18n/fr.php | 10 ++++++++++ app/views/index/resetAuth.phtml | 12 ++++++------ 4 files changed, 27 insertions(+), 7 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 26e2618f0..b69c09127 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -422,7 +422,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { } public function resetAuthAction() { - Minz_View::prependTitle(_t('reset_auth') . ' · '); + Minz_View::prependTitle(_t('auth_reset') . ' · '); Minz_View::appendScript(Minz_Url::display( '/scripts/bcrypt.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js') )); diff --git a/app/i18n/en.php b/app/i18n/en.php index b14b36b32..11edc603f 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -159,6 +159,7 @@ return array ( 'save' => 'Save', 'delete' => 'Delete', 'cancel' => 'Cancel', + 'submit' => 'Submit', 'back_to_rss_feeds' => '← Go back to your RSS feeds', 'feeds_moved_category_deleted' => 'When you delete a category, their feeds are automatically classified under %s.', @@ -204,6 +205,7 @@ return array ( 'informations' => 'Information', 'damn' => 'Damn!', 'ok' => 'Ok!', + 'attention' => 'Be careful!', 'feed_in_error' => 'This feed has encountered a problem. Please verify that it is always reachable then actualize it.', 'feed_empty' => 'This feed is empty. Please verify that it is still maintained.', 'feed_description' => 'Description', @@ -255,6 +257,7 @@ return array ( 'users_list' => 'List of users', 'create_user' => 'Create new user', 'username' => 'Username', + 'username_admin' => 'Administrator username', 'password' => 'Password', 'create' => 'Create', 'user_created' => 'User %s has been created', @@ -434,4 +437,11 @@ return array ( 'no_update' => 'No update to apply', 'update_problem' => 'The update process has encountered an error: %s', 'update_finished' => 'Update completed!', + + 'auth_reset' => 'Authentication reset', + 'auth_will_reset' => 'Authentication system will be reseted: form will be used instead of Persona.', + 'auth_not_persona' => 'Only Persona system can be reseted.', + 'auth_no_password_set' => 'Administrator password hasn’t been set. This feature isn’t available.', + 'auth_form_set' => 'Form is now your default authentication system.', + 'auth_form_not_set' => 'A problem occured during authentication system configuration. Please retry later.', ); diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 3dc429bbb..279cb89fa 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -159,6 +159,7 @@ return array ( 'save' => 'Enregistrer', 'delete' => 'Supprimer', 'cancel' => 'Annuler', + 'submit' => 'Valider', 'back_to_rss_feeds' => '← Retour à vos flux RSS', 'feeds_moved_category_deleted' => 'Lors de la suppression d’une catégorie, ses flux seront automatiquement classés dans %s.', @@ -204,6 +205,7 @@ return array ( 'informations' => 'Informations', 'damn' => 'Arf !', 'ok' => 'Ok !', + 'attention' => 'Attention !', 'feed_in_error' => 'Ce flux a rencontré un problème. Veuillez vérifier qu’il est toujours accessible puis actualisez-le.', 'feed_empty' => 'Ce flux est vide. Veuillez vérifier qu’il est toujours maintenu.', 'feed_description' => 'Description', @@ -255,6 +257,7 @@ return array ( 'users_list' => 'Liste des utilisateurs', 'create_user' => 'Créer un nouvel utilisateur', 'username' => 'Nom d’utilisateur', + 'username_admin' => 'Nom d’utilisateur administrateur', 'password' => 'Mot de passe', 'create' => 'Créer', 'user_created' => 'L’utilisateur %s a été créé.', @@ -434,4 +437,11 @@ return array ( 'no_update' => 'Aucune mise à jour à appliquer', 'update_problem' => 'La mise à jour a rencontré un problème : %s', 'update_finished' => 'La mise à jour est terminée !', + + 'auth_reset' => 'Reset de l’authentification', + 'auth_will_reset' => 'Le système d’authentification va être remis à zéro : le formulaire sera utilisé à la place de Persona.', + 'auth_not_persona' => 'Seul le système d’authentification Persona peut être remis à zéro.', + 'auth_no_password_set' => 'Aucun mot de passe administrateur n’a été précisé. Cette fonctionnalité n’est pas disponible.', + 'auth_form_set' => 'Le formulaire est désormais votre système d’authentification.', + 'auth_form_not_set' => 'Un problème est survenu lors de la configuration de votre système d’authentification. Veuillez réessayer plus tard.', ); diff --git a/app/views/index/resetAuth.phtml b/app/views/index/resetAuth.phtml index 78cc527b3..6d4282c14 100644 --- a/app/views/index/resetAuth.phtml +++ b/app/views/index/resetAuth.phtml @@ -1,9 +1,9 @@ -

    -

    +
    +

    message)) { ?>

    - message['title']; ?> + message['title']; ?>
    message['body']; ?>

    @@ -11,12 +11,12 @@ no_form) { ?>

    - +

    - +
    @@ -26,7 +26,7 @@
    - +
    -- cgit v1.2.3 From ba378791c2f36251a22e8a98351ab9b23a640c17 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 19 Sep 2014 13:52:50 +0200 Subject: Fix blank page for invalid user queries Add a "deprecated" information See https://github.com/marienfressinaud/FreshRSS/issues/625 --- app/Controllers/configureController.php | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index b1cd45014..f72683e34 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -328,6 +328,8 @@ class FreshRSS_configure_Controller extends Minz_ActionController { Minz_Request::forward(array('c' => 'configure', 'a' => 'queries'), true); } else { $this->view->query_get = array(); + $cat_dao = new FreshRSS_CategoryDAO(); + $feed_dao = FreshRSS_Factory::createFeedDao(); foreach ($this->view->conf->queries as $key => $query) { if (!isset($query['get'])) { continue; @@ -335,31 +337,49 @@ class FreshRSS_configure_Controller extends Minz_ActionController { switch ($query['get'][0]) { case 'c': - $dao = new FreshRSS_CategoryDAO(); - $category = $dao->searchById(substr($query['get'], 2)); + $category = $cat_dao->searchById(substr($query['get'], 2)); + + $deprecated = true; + $cat_name = ''; + if ($category) { + $cat_name = $category->name(); + $deprecated = false; + } + $this->view->query_get[$key] = array( 'type' => 'category', - 'name' => $category->name(), + 'name' => $cat_name, + 'deprecated' => $deprecated, ); break; case 'f': - $dao = FreshRSS_Factory::createFeedDao(); - $feed = $dao->searchById(substr($query['get'], 2)); + $feed = $feed_dao->searchById(substr($query['get'], 2)); + + $deprecated = true; + $feed_name = ''; + if ($feed) { + $feed_name = $feed->name(); + $deprecated = false; + } + $this->view->query_get[$key] = array( 'type' => 'feed', - 'name' => $feed->name(), + 'name' => $feed_name, + 'deprecated' => $deprecated, ); break; case 's': $this->view->query_get[$key] = array( 'type' => 'favorite', 'name' => 'favorite', + 'deprecated' => false, ); break; case 'a': $this->view->query_get[$key] = array( 'type' => 'all', 'name' => 'all', + 'deprecated' => false, ); break; } -- cgit v1.2.3 From ae4ecd8e099b23d38e761dec6de68da801816734 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 19 Sep 2014 15:44:33 +0200 Subject: Coding style (user queries) --- app/Controllers/configureController.php | 17 ++++++----------- app/i18n/en.php | 1 + app/i18n/fr.php | 1 + app/layout/nav_menu.phtml | 5 ++++- 4 files changed, 12 insertions(+), 12 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index f72683e34..91b74aa29 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -313,19 +313,14 @@ class FreshRSS_configure_Controller extends Minz_ActionController { foreach ($queries as $key => $query) { if (!$query['name']) { - $query['name'] = Minz_Translate::t('query_number', $key + 1); + $query['name'] = _t('query_number', $key + 1); } } $this->view->conf->_queries($queries); $this->view->conf->save(); - $notif = array( - 'type' => 'good', - 'content' => Minz_Translate::t('configuration_updated') - ); - Minz_Session::_param('notification', $notif); - - Minz_Request::forward(array('c' => 'configure', 'a' => 'queries'), true); + Minz_Request::good(_t('configuration_updated'), + array('c' => 'configure', 'a' => 'queries')); } else { $this->view->query_get = array(); $cat_dao = new FreshRSS_CategoryDAO(); @@ -392,14 +387,14 @@ class FreshRSS_configure_Controller extends Minz_ActionController { public function addQueryAction() { $queries = $this->view->conf->queries; $query = Minz_Request::params(); - $query['name'] = Minz_Translate::t('query_number', count($queries) + 1); + $query['name'] = _t('query_number', count($queries) + 1); unset($query['output']); unset($query['token']); $queries[] = $query; $this->view->conf->_queries($queries); $this->view->conf->save(); - // Minz_Request::forward(array('params' => $query), true); - Minz_Request::forward(array('c' => 'configure', 'a' => 'queries'), true); + Minz_Request::good(_t('query_created', $query['name']), + array('c' => 'configure', 'a' => 'queries')); } } diff --git a/app/i18n/en.php b/app/i18n/en.php index e2bd21623..e84787508 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -43,6 +43,7 @@ return array ( 'query_state_15' => 'Display all articles', 'query_number' => 'Query n°%d', 'add_query' => 'Add a query', + 'query_created' => 'Query "%s" has been created.', 'no_query' => 'You haven’t created any user query yet.', 'query_filter' => 'Filter applied:', 'no_query_filter' => 'No filter', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index e06bba487..fab5c3470 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -43,6 +43,7 @@ return array ( 'query_state_15' => 'Afficher tous les articles', 'query_number' => 'Filtre n°%d', 'add_query' => 'Créer un filtre', + 'query_created' => 'Le filtre "%s" a bien été créé.', 'no_query' => 'Vous n’avez pas encore créé de filtre.', 'query_filter' => 'Filtres appliqués :', 'no_query_filter' => 'Aucun filtre appliqué', diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml index 2a09b0c12..03f496d1f 100644 --- a/app/layout/nav_menu.phtml +++ b/app/layout/nav_menu.phtml @@ -93,7 +93,10 @@
    -- cgit v1.2.3 From d284958d52f633738e8cc736f7f4a50e0c984ecf Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 19 Sep 2014 19:44:40 +0200 Subject: Improve redirection when deleting an idle feed --- app/Controllers/feedController.php | 9 ++++++--- app/views/stats/idle.phtml | 6 +++++- lib/Minz/Request.php | 5 +++++ 3 files changed, 16 insertions(+), 4 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 3326b2059..65d4b3a37 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -412,10 +412,13 @@ class FreshRSS_feed_Controller extends Minz_ActionController { Minz_Session::_param ('notification', $notif); - if ($type == 'category') { - Minz_Request::forward (array ('c' => 'configure', 'a' => 'categorize'), true); + $redirect_url = Minz_Request::param('r', false, true); + if ($redirect_url) { + Minz_Request::forward($redirect_url); + } elseif ($type == 'category') { + Minz_Request::forward(array ('c' => 'configure', 'a' => 'categorize'), true); } else { - Minz_Request::forward (array ('c' => 'configure', 'a' => 'feed'), true); + Minz_Request::forward(array ('c' => 'configure', 'a' => 'feed'), true); } } } diff --git a/app/views/stats/idle.phtml b/app/views/stats/idle.phtml index 3ce8d3d3e..6f3d4a117 100644 --- a/app/views/stats/idle.phtml +++ b/app/views/stats/idle.phtml @@ -6,6 +6,10 @@

    'stats', 'a' => 'idle'), + 'php', true + )); $nothing = true; foreach ($this->idleFeeds as $period => $feeds) { if (!empty($feeds)) { @@ -22,7 +26,7 @@
    - +
  • diff --git a/lib/Minz/Request.php b/lib/Minz/Request.php index 52f53012f..f7a24c026 100644 --- a/lib/Minz/Request.php +++ b/lib/Minz/Request.php @@ -124,6 +124,11 @@ class Minz_Request { * > sinon, le dispatcher recharge en interne */ public static function forward($url = array(), $redirect = false) { + if (!is_array($url)) { + header('Location: ' . $url); + exit(); + } + $url = Minz_Url::checkUrl($url); if ($redirect) { -- cgit v1.2.3 From a14d325432b1d6515beaaccef73fa01f3ab3a85c Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 19 Sep 2014 20:30:54 +0200 Subject: Auto-redirect from formLogin if already logged in --- app/Controllers/indexController.php | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'app/Controllers') diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index bc03f1916..e8e26b142 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -337,6 +337,10 @@ class FreshRSS_index_Controller extends Minz_ActionController { } public function formLoginAction () { + if ($this->view->loginOk) { + Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true); + } + if (Minz_Request::isPost()) { $ok = false; $nonce = Minz_Session::param('nonce'); -- cgit v1.2.3 From ea7f21ba7f4049b51c2978b7ebaad00e17fa5af5 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sun, 21 Sep 2014 11:21:51 -0400 Subject: Add some comments It is a work in progress. I only did that for a single class so you can tell me if this is a good idea, if the content is missing something. Any comments are welcome. --- app/Controllers/configureController.php | 172 +++++++++++++++++++++++++++++++- 1 file changed, 170 insertions(+), 2 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 91b74aa29..8fae29ea2 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -1,6 +1,17 @@ view->loginOk) { Minz_Error::error( @@ -13,6 +24,17 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $catDAO->checkDefault(); } + /** + * This action handles the category configuration page + * + * It displays the category configuration page. + * If this action is reached through a POST request, it loops through + * every category to check for modification then add a new category if + * needed then sends a notification to the user. + * If a category name is emptied, the category is deleted and all + * related feeds are moved to the default category. + * If a category name is changed, it is updated. + */ public function categorizeAction() { $feedDAO = FreshRSS_Factory::createFeedDao(); $catDAO = new FreshRSS_CategoryDAO(); @@ -66,6 +88,28 @@ class FreshRSS_configure_Controller extends Minz_ActionController { Minz_View::prependTitle(Minz_Translate::t('categories_management') . ' · '); } + /** + * This action handles the feed configuration page. + * + * It displays the feed configuration page. + * If this action is reached through a POST request, it stores all new + * configuraiton values then sends a notification to the user. + * + * The options available on the page are: + * - name + * - description + * - website URL + * - feed URL + * - category id (default: default category id) + * - CSS path to article on website + * - display in main stream (default: 0) + * - HTTP authentication + * - number of article to retain (default: -2) + * - refresh frequency (default: -2) + * Default values are empty strings unless specified. + * + * @todo change the notification code + */ public function feedAction() { $catDAO = new FreshRSS_CategoryDAO(); $this->view->categories = $catDAO->listCategories(false); @@ -138,6 +182,33 @@ class FreshRSS_configure_Controller extends Minz_ActionController { } } + /** + * This action handles the display configuration page. + * + * It displays the display configuration page. + * If this action is reached through a POST request, it stores all new + * configuration values then sends a notification to the user. + * + * The options available on the page are: + * - language (default: en) + * - theme (default: Origin) + * - content width (default: thin) + * - display of read action in header + * - display of favorite action in header + * - display of date in header + * - display of open action in header + * - display of read action in footer + * - display of favorite action in footer + * - display of sharing action in footer + * - display of tags in footer + * - display of date in footer + * - display of open action in footer + * - html5 notification timeout (default: 0) + * Default values are false unless specified. + * + * @todo refactor to theme section to use the same syntax everywhere + * @todo change the notification code + */ public function displayAction() { if (Minz_Request::isPost()) { $this->view->conf->_language(Minz_Request::param('language', 'en')); @@ -178,6 +249,35 @@ class FreshRSS_configure_Controller extends Minz_ActionController { Minz_View::prependTitle(Minz_Translate::t('display_configuration') . ' · '); } + /** + * This action handles the reading configuration page. + * + * It displays the reading configuration page. + * If this action is reached through a POST request, it stores all new + * configuration values then sends a notification to the user. + * + * The options available on the page are: + * - number of posts per page (default: 10) + * - view mode (default: normal) + * - default article view (default: all) + * - load automatically articles + * - display expanded articles + * - display expanded categories + * - hide categories and feeds without unread articles + * - jump on next category or feed when marked as read + * - image lazy loading + * - stick open articles to the top + * - display a confirmation when reading all articles + * - article order (default: DESC) + * - mark articles as read when: + * - displayed + * - opened on site + * - scrolled + * - received + * Default values are false unless specified. + * + * @todo change the notification code + */ public function readingAction() { if (Minz_Request::isPost()) { $this->view->conf->_posts_per_page(Minz_Request::param('posts_per_page', 10)); @@ -216,6 +316,15 @@ class FreshRSS_configure_Controller extends Minz_ActionController { Minz_View::prependTitle(Minz_Translate::t('reading_configuration') . ' · '); } + /** + * This action handles the sharing configuration page. + * + * It displays the sharing configuration page. + * If this action is reached through a POST request, it stores all + * configuration values then sends a notification to the user. + * + * @todo change the notification code + */ public function sharingAction() { if (Minz_Request::isPost()) { $params = Minz_Request::params(); @@ -235,6 +344,22 @@ class FreshRSS_configure_Controller extends Minz_ActionController { Minz_View::prependTitle(Minz_Translate::t('sharing') . ' · '); } + /** + * This action handles the shortcut configuration page. + * + * It displays the shortcut configuration page. + * If this action is reached through a POST request, it stores all new + * configuration values then sends a notification to the user. + * + * The authorized values for shortcuts are letters (a to z), numbers (0 + * to 9), function keys (f1 to f12), backspace, delete, down, end, enter, + * escape, home, insert, left, page down, page up, return, right, space, + * tab and up. + * + * @todo remove numbers from the list of authorized shortcuts since they + * are used to access shortcuts and user queries + * @todo change the notification code + */ public function shortcutAction() { $list_keys = array('a', 'b', 'backspace', 'c', 'd', 'delete', 'down', 'e', 'end', 'enter', 'escape', 'f', 'g', 'h', 'home', 'i', 'insert', 'j', 'k', 'l', 'left', @@ -271,10 +396,31 @@ class FreshRSS_configure_Controller extends Minz_ActionController { Minz_View::prependTitle(Minz_Translate::t('shortcuts') . ' · '); } + /** + * This action display the user configuration page + * + * @todo move that action in the user controller + */ public function usersAction() { Minz_View::prependTitle(Minz_Translate::t('users') . ' · '); } + /** + * This action handles the archive configuration page. + * + * It displays the archive configuration page. + * If this action is reached through a POST request, it stores all new + * configuration values then sends a notification to the user. + * + * The options available on that page are: + * - duration to retain old article (default: 3) + * - number of article to retain per feed (default: 0) + * - refresh frequency (default: -2) + * + * @todo explain why the default value is -2 but this value does not + * exist in the drop-down list + * @todo change the notification code + */ public function archivingAction() { if (Minz_Request::isPost()) { $old = Minz_Request::param('old_entries', 3); @@ -306,7 +452,17 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $this->view->size_total = $entryDAO->size(true); } } - + + /** + * This action handles the user queries configuration page. + * + * If this action is reached through a POST request, it stores all new + * configuration values then sends a notification to the user then + * redirect to the same page. + * If this action is not reached through a POST request, it displays the + * configuration page and verifies that every user query is runable by + * checking if categories and feeds are still in use. + */ public function queriesAction() { if (Minz_Request::isPost()) { $queries = Minz_Request::param('queries', array()); @@ -383,7 +539,19 @@ class FreshRSS_configure_Controller extends Minz_ActionController { Minz_View::prependTitle(Minz_Translate::t('queries') . ' · '); } - + + /** + * This action handles the creation of a user query. + * + * It gets the GET parameters and stores them in the configuration query + * storage. Before it is saved, the unwanted parameters are unset to keep + * lean data. + * + * @todo change the way of keeping lean data to have a more defensive + * code. At the moment, the code accepts any parameters and discard those + * on the black list. I think it is safer if we maintain a whitelist + * instead. + */ public function addQueryAction() { $queries = $this->view->conf->queries; $query = Minz_Request::params(); -- cgit v1.2.3 From cf01508fa58b5bdd85606fb766a79643a04ca6b7 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sun, 21 Sep 2014 11:25:53 -0400 Subject: Fix typo --- app/Controllers/configureController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/Controllers') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 8fae29ea2..7340ca17a 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -206,7 +206,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * - html5 notification timeout (default: 0) * Default values are false unless specified. * - * @todo refactor to theme section to use the same syntax everywhere + * @todo refactor theme section to use the same syntax everywhere * @todo change the notification code */ public function displayAction() { -- cgit v1.2.3 From bad165b0c424c9c650e22fec11ceecf1748d98e7 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sun, 21 Sep 2014 11:28:46 -0400 Subject: Add a todo --- app/Controllers/configureController.php | 2 ++ 1 file changed, 2 insertions(+) (limited to 'app/Controllers') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 7340ca17a..99c72d869 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -420,6 +420,8 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * @todo explain why the default value is -2 but this value does not * exist in the drop-down list * @todo change the notification code + * @todo refactor configuration setting syntax to be consistent with the + * other methods */ public function archivingAction() { if (Minz_Request::isPost()) { -- cgit v1.2.3 From 0420a989391c9af30ee6d85638c81bfb4f605132 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sun, 21 Sep 2014 11:51:53 -0400 Subject: Add comments on the stat controller --- app/Controllers/statsController.php | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'app/Controllers') diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php index 000b41dd2..64f66f2fa 100644 --- a/app/Controllers/statsController.php +++ b/app/Controllers/statsController.php @@ -1,7 +1,21 @@ view->topFeed = $statsDAO->calculateTopFeed(); } + /** + * This action handles the idle feed statistic page. + * + * It displays the list of idle feed for different period. The supported + * periods are: + * - last year + * - last 6 months + * - last 3 months + * - last month + * - last week + */ public function idleAction() { $statsDAO = FreshRSS_Factory::createStatsDAO(); $feeds = $statsDAO->calculateFeedLastDate(); @@ -56,6 +81,18 @@ class FreshRSS_stats_Controller extends Minz_ActionController { $this->view->idleFeeds = $idleFeeds; } + /** + * This action handles the article repartition statistic page. + * + * It displays the number of article and the average of article for the + * following periods: + * - hour of the day + * - day of the week + * - month + * + * @todo verify that the metrics used here make some sense. Especially + * for the average. + */ public function repartitionAction() { $statsDAO = FreshRSS_Factory::createStatsDAO(); $categoryDAO = new FreshRSS_CategoryDAO(); @@ -74,6 +111,11 @@ class FreshRSS_stats_Controller extends Minz_ActionController { $this->view->averageMonth = $statsDAO->calculateEntryAveragePerFeedPerMonth($id); } + /** + * This action is called before every other action in that class. It is + * the common boiler plate for every action. It is triggered by the + * underlying framework. + */ public function firstAction() { if (!$this->view->loginOk) { Minz_Error::error( -- cgit v1.2.3 From 5889ef35c8ecbbae948420af9f2b05e7010593ae Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sun, 21 Sep 2014 12:01:36 -0400 Subject: Change todo align --- app/Controllers/configureController.php | 14 +++++++------- app/Controllers/statsController.php | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 99c72d869..7b8dd672f 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -10,7 +10,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * underlying framework. * * @todo see if the category default configuration is needed here or if - * we can move it to the categorize action + * we can move it to the categorize action */ public function firstAction() { if (!$this->view->loginOk) { @@ -357,7 +357,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * tab and up. * * @todo remove numbers from the list of authorized shortcuts since they - * are used to access shortcuts and user queries + * are used to access shortcuts and user queries * @todo change the notification code */ public function shortcutAction() { @@ -418,10 +418,10 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * - refresh frequency (default: -2) * * @todo explain why the default value is -2 but this value does not - * exist in the drop-down list + * exist in the drop-down list * @todo change the notification code * @todo refactor configuration setting syntax to be consistent with the - * other methods + * other methods */ public function archivingAction() { if (Minz_Request::isPost()) { @@ -550,9 +550,9 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * lean data. * * @todo change the way of keeping lean data to have a more defensive - * code. At the moment, the code accepts any parameters and discard those - * on the black list. I think it is safer if we maintain a whitelist - * instead. + * code. At the moment, the code accepts any parameters and discard + * those on the black list. I think it is safer if we maintain a + * whitelist instead. */ public function addQueryAction() { $queries = $this->view->conf->queries; diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php index 64f66f2fa..256543f37 100644 --- a/app/Controllers/statsController.php +++ b/app/Controllers/statsController.php @@ -91,7 +91,7 @@ class FreshRSS_stats_Controller extends Minz_ActionController { * - month * * @todo verify that the metrics used here make some sense. Especially - * for the average. + * for the average. */ public function repartitionAction() { $statsDAO = FreshRSS_Factory::createStatsDAO(); -- cgit v1.2.3 From f87dfbc528f4fa451a2a213fdbd3fcaf27308de8 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sun, 21 Sep 2014 18:09:10 -0400 Subject: Change notification code Before, it was using the old way to display notifications to the user. Now, it uses the encapsulated method to do that. --- app/Controllers/configureController.php | 63 +++++++-------------------------- 1 file changed, 12 insertions(+), 51 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 7b8dd672f..1e341b412 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -72,13 +72,8 @@ class FreshRSS_configure_Controller extends Minz_ActionController { } invalidateHttpCache(); - $notif = array( - 'type' => 'good', - 'content' => Minz_Translate::t('categories_updated') - ); - Minz_Session::_param('notification', $notif); - - Minz_Request::forward(array('c' => 'configure', 'a' => 'categorize'), true); + Minz_Request::good(_t('categories_updated'), + array('c' => 'configure', 'a' => 'categorize')); } $this->view->categories = $catDAO->listCategories(false); @@ -107,8 +102,6 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * - number of article to retain (default: -2) * - refresh frequency (default: -2) * Default values are empty strings unless specified. - * - * @todo change the notification code */ public function feedAction() { $catDAO = new FreshRSS_CategoryDAO(); @@ -207,7 +200,6 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * Default values are false unless specified. * * @todo refactor theme section to use the same syntax everywhere - * @todo change the notification code */ public function displayAction() { if (Minz_Request::isPost()) { @@ -235,13 +227,8 @@ class FreshRSS_configure_Controller extends Minz_ActionController { Minz_Translate::reset(); invalidateHttpCache(); - $notif = array( - 'type' => 'good', - 'content' => Minz_Translate::t('configuration_updated') - ); - Minz_Session::_param('notification', $notif); - - Minz_Request::forward(array('c' => 'configure', 'a' => 'display'), true); + Minz_Request::good(_t('configuration_updated'), + array('c' => 'configure', 'a' => 'display')); } $this->view->themes = FreshRSS_Themes::get(); @@ -275,8 +262,6 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * - scrolled * - received * Default values are false unless specified. - * - * @todo change the notification code */ public function readingAction() { if (Minz_Request::isPost()) { @@ -304,13 +289,8 @@ class FreshRSS_configure_Controller extends Minz_ActionController { Minz_Translate::reset(); invalidateHttpCache(); - $notif = array( - 'type' => 'good', - 'content' => Minz_Translate::t('configuration_updated') - ); - Minz_Session::_param('notification', $notif); - - Minz_Request::forward(array('c' => 'configure', 'a' => 'reading'), true); + Minz_Request::good(_t('configuration_updated'), + array('c' => 'configure', 'a' => 'reading')); } Minz_View::prependTitle(Minz_Translate::t('reading_configuration') . ' · '); @@ -322,8 +302,6 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * It displays the sharing configuration page. * If this action is reached through a POST request, it stores all * configuration values then sends a notification to the user. - * - * @todo change the notification code */ public function sharingAction() { if (Minz_Request::isPost()) { @@ -332,13 +310,8 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $this->view->conf->save(); invalidateHttpCache(); - $notif = array( - 'type' => 'good', - 'content' => Minz_Translate::t('configuration_updated') - ); - Minz_Session::_param('notification', $notif); - - Minz_Request::forward(array('c' => 'configure', 'a' => 'sharing'), true); + Minz_Request::good(_t('configuration_updated'), + array('c' => 'configure', 'a' => 'sharing')); } Minz_View::prependTitle(Minz_Translate::t('sharing') . ' · '); @@ -358,7 +331,6 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * * @todo remove numbers from the list of authorized shortcuts since they * are used to access shortcuts and user queries - * @todo change the notification code */ public function shortcutAction() { $list_keys = array('a', 'b', 'backspace', 'c', 'd', 'delete', 'down', 'e', 'end', 'enter', @@ -384,13 +356,8 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $this->view->conf->save(); invalidateHttpCache(); - $notif = array( - 'type' => 'good', - 'content' => Minz_Translate::t('shortcuts_updated') - ); - Minz_Session::_param('notification', $notif); - - Minz_Request::forward(array('c' => 'configure', 'a' => 'shortcut'), true); + Minz_Request::good(_t('shortcuts_updated'), + array('c' => 'configure', 'a' => 'shortcut')); } Minz_View::prependTitle(Minz_Translate::t('shortcuts') . ' · '); @@ -419,7 +386,6 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * * @todo explain why the default value is -2 but this value does not * exist in the drop-down list - * @todo change the notification code * @todo refactor configuration setting syntax to be consistent with the * other methods */ @@ -435,13 +401,8 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $this->view->conf->save(); invalidateHttpCache(); - $notif = array( - 'type' => 'good', - 'content' => Minz_Translate::t('configuration_updated') - ); - Minz_Session::_param('notification', $notif); - - Minz_Request::forward(array('c' => 'configure', 'a' => 'archiving'), true); + Minz_Request::good(_t('configuration_updated'), + array('c' => 'configure', 'a' => 'archiving')); } Minz_View::prependTitle(Minz_Translate::t('archiving_configuration') . ' · '); -- cgit v1.2.3 From 3753ea8fd673feb16a2bfb323fea2b5ff964d77e Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sun, 21 Sep 2014 18:23:25 -0400 Subject: Change parameter settings to be consistent through out the file --- app/Controllers/configureController.php | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 1e341b412..0e4c0be52 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -198,17 +198,11 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * - display of open action in footer * - html5 notification timeout (default: 0) * Default values are false unless specified. - * - * @todo refactor theme section to use the same syntax everywhere */ public function displayAction() { if (Minz_Request::isPost()) { $this->view->conf->_language(Minz_Request::param('language', 'en')); - $themeId = Minz_Request::param('theme', ''); - if ($themeId == '') { - $themeId = FreshRSS_Themes::defaultTheme; - } - $this->view->conf->_theme($themeId); + $this->view->conf->_theme(Minz_Request::param('theme', FreshRSS_Themes::$defaultTheme)); $this->view->conf->_content_width(Minz_Request::param('content_width', 'thin')); $this->view->conf->_topline_read(Minz_Request::param('topline_read', false)); $this->view->conf->_topline_favorite(Minz_Request::param('topline_favorite', false)); @@ -386,18 +380,12 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * * @todo explain why the default value is -2 but this value does not * exist in the drop-down list - * @todo refactor configuration setting syntax to be consistent with the - * other methods */ public function archivingAction() { if (Minz_Request::isPost()) { - $old = Minz_Request::param('old_entries', 3); - $keepHistoryDefault = Minz_Request::param('keep_history_default', 0); - $ttlDefault = Minz_Request::param('ttl_default', -2); - - $this->view->conf->_old_entries($old); - $this->view->conf->_keep_history_default($keepHistoryDefault); - $this->view->conf->_ttl_default($ttlDefault); + $this->view->conf->_old_entries(Minz_Request::param('old_entries', 3)); + $this->view->conf->_keep_history_default(Minz_Request::param('keep_history_default', 0)); + $this->view->conf->_ttl_default(Minz_Request::param('ttl_default', -2)); $this->view->conf->save(); invalidateHttpCache(); -- cgit v1.2.3 From 04403c5dfae2db051416ccf0b41559d02bb0d287 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sun, 21 Sep 2014 18:26:27 -0400 Subject: Remove number values for shortcuts as they are used in the default configuration --- app/Controllers/configureController.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 0e4c0be52..a44ef3104 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -322,17 +322,13 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * to 9), function keys (f1 to f12), backspace, delete, down, end, enter, * escape, home, insert, left, page down, page up, return, right, space, * tab and up. - * - * @todo remove numbers from the list of authorized shortcuts since they - * are used to access shortcuts and user queries */ public function shortcutAction() { $list_keys = array('a', 'b', 'backspace', 'c', 'd', 'delete', 'down', 'e', 'end', 'enter', 'escape', 'f', 'g', 'h', 'home', 'i', 'insert', 'j', 'k', 'l', 'left', 'm', 'n', 'o', 'p', 'page_down', 'page_up', 'q', 'r', 'return', 'right', 's', 'space', 't', 'tab', 'u', 'up', 'v', 'w', 'x', 'y', - 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', - '9', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', + 'z', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'f10', 'f11', 'f12'); $this->view->list_keys = $list_keys; -- cgit v1.2.3 From 23e4577e02944567b8ac15581d9c0a0561d82046 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sun, 21 Sep 2014 18:40:08 -0400 Subject: Change param filter for user queries Before, the filter was based on a blacklist so the user could add something and have unwanted behavior. Now, the filter is based on a whilelist so the user can use only predetermined parameters. --- app/Controllers/configureController.php | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index a44ef3104..2bd13997f 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -493,18 +493,17 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * It gets the GET parameters and stores them in the configuration query * storage. Before it is saved, the unwanted parameters are unset to keep * lean data. - * - * @todo change the way of keeping lean data to have a more defensive - * code. At the moment, the code accepts any parameters and discard - * those on the black list. I think it is safer if we maintain a - * whitelist instead. */ public function addQueryAction() { + $whitelist = array('get', 'order', 'name', 'search', 'state'); $queries = $this->view->conf->queries; $query = Minz_Request::params(); $query['name'] = _t('query_number', count($queries) + 1); - unset($query['output']); - unset($query['token']); + foreach ($query as $key => $value) { + if (!in_array($key, $whitelist)) { + unset($query[$key]); + } + } $queries[] = $query; $this->view->conf->_queries($queries); $this->view->conf->save(); -- cgit v1.2.3 From c791d84ded1eeb1b32fe81918ac1bcfa520c6bda Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sun, 21 Sep 2014 18:49:34 -0400 Subject: Fix user queries Before, when adding a user query where the state contains the strict filter, the label applied to the query was wrong. Now, the strict filter is always removed so the label applied is correct. --- app/Controllers/configureController.php | 3 +++ 1 file changed, 3 insertions(+) (limited to 'app/Controllers') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 2bd13997f..426cad34d 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -504,6 +504,9 @@ class FreshRSS_configure_Controller extends Minz_ActionController { unset($query[$key]); } } + if ($query['state'] & FreshRSS_Entry::STATE_STRICT) { + $query['state'] -= FreshRSS_Entry::STATE_STRICT; + } $queries[] = $query; $this->view->conf->_queries($queries); $this->view->conf->save(); -- cgit v1.2.3 From 0ea3a5a3943b30eb6a5d8763b698a939fe1a98ae Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 24 Sep 2014 11:49:32 +0200 Subject: Coding style configureController.php --- app/Controllers/configureController.php | 40 ++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 426cad34d..4422f33af 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -16,7 +16,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { if (!$this->view->loginOk) { Minz_Error::error( 403, - array('error' => array(Minz_Translate::t('access_denied'))) + array('error' => array(_t('access_denied'))) ); } @@ -73,14 +73,14 @@ class FreshRSS_configure_Controller extends Minz_ActionController { invalidateHttpCache(); Minz_Request::good(_t('categories_updated'), - array('c' => 'configure', 'a' => 'categorize')); + array('c' => 'configure', 'a' => 'categorize')); } $this->view->categories = $catDAO->listCategories(false); $this->view->defaultCategory = $catDAO->getDefault(); $this->view->feeds = $feedDAO->listFeeds(); - Minz_View::prependTitle(Minz_Translate::t('categories_management') . ' · '); + Minz_View::prependTitle(_t('categories_management') . ' · '); } /** @@ -122,7 +122,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { if (!$this->view->flux) { Minz_Error::error( 404, - array('error' => array(Minz_Translate::t('page_not_found'))) + array('error' => array(_t('page_not_found'))) ); } else { if (Minz_Request::isPost() && $this->view->flux) { @@ -154,12 +154,12 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $this->view->flux->faviconPrepare(); $notif = array( 'type' => 'good', - 'content' => Minz_Translate::t('feed_updated') + 'content' => _t('feed_updated') ); } else { $notif = array( 'type' => 'bad', - 'content' => Minz_Translate::t('error_occurred_update') + 'content' => _t('error_occurred_update') ); } invalidateHttpCache(); @@ -168,10 +168,10 @@ class FreshRSS_configure_Controller extends Minz_ActionController { Minz_Request::forward(array('c' => 'configure', 'a' => 'feed', 'params' => array('id' => $id)), true); } - Minz_View::prependTitle(Minz_Translate::t('rss_feed_management') . ' — ' . $this->view->flux->name() . ' · '); + Minz_View::prependTitle(_t('rss_feed_management') . ' — ' . $this->view->flux->name() . ' · '); } } else { - Minz_View::prependTitle(Minz_Translate::t('rss_feed_management') . ' · '); + Minz_View::prependTitle(_t('rss_feed_management') . ' · '); } } @@ -222,12 +222,12 @@ class FreshRSS_configure_Controller extends Minz_ActionController { invalidateHttpCache(); Minz_Request::good(_t('configuration_updated'), - array('c' => 'configure', 'a' => 'display')); + array('c' => 'configure', 'a' => 'display')); } $this->view->themes = FreshRSS_Themes::get(); - Minz_View::prependTitle(Minz_Translate::t('display_configuration') . ' · '); + Minz_View::prependTitle(_t('display_configuration') . ' · '); } /** @@ -284,10 +284,10 @@ class FreshRSS_configure_Controller extends Minz_ActionController { invalidateHttpCache(); Minz_Request::good(_t('configuration_updated'), - array('c' => 'configure', 'a' => 'reading')); + array('c' => 'configure', 'a' => 'reading')); } - Minz_View::prependTitle(Minz_Translate::t('reading_configuration') . ' · '); + Minz_View::prependTitle(_t('reading_configuration') . ' · '); } /** @@ -305,10 +305,10 @@ class FreshRSS_configure_Controller extends Minz_ActionController { invalidateHttpCache(); Minz_Request::good(_t('configuration_updated'), - array('c' => 'configure', 'a' => 'sharing')); + array('c' => 'configure', 'a' => 'sharing')); } - Minz_View::prependTitle(Minz_Translate::t('sharing') . ' · '); + Minz_View::prependTitle(_t('sharing') . ' · '); } /** @@ -347,10 +347,10 @@ class FreshRSS_configure_Controller extends Minz_ActionController { invalidateHttpCache(); Minz_Request::good(_t('shortcuts_updated'), - array('c' => 'configure', 'a' => 'shortcut')); + array('c' => 'configure', 'a' => 'shortcut')); } - Minz_View::prependTitle(Minz_Translate::t('shortcuts') . ' · '); + Minz_View::prependTitle(_t('shortcuts') . ' · '); } /** @@ -359,7 +359,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * @todo move that action in the user controller */ public function usersAction() { - Minz_View::prependTitle(Minz_Translate::t('users') . ' · '); + Minz_View::prependTitle(_t('users') . ' · '); } /** @@ -386,10 +386,10 @@ class FreshRSS_configure_Controller extends Minz_ActionController { invalidateHttpCache(); Minz_Request::good(_t('configuration_updated'), - array('c' => 'configure', 'a' => 'archiving')); + array('c' => 'configure', 'a' => 'archiving')); } - Minz_View::prependTitle(Minz_Translate::t('archiving_configuration') . ' · '); + Minz_View::prependTitle(_t('archiving_configuration') . ' · '); $entryDAO = FreshRSS_Factory::createEntryDao(); $this->view->nb_total = $entryDAO->count(); @@ -484,7 +484,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { } } - Minz_View::prependTitle(Minz_Translate::t('queries') . ' · '); + Minz_View::prependTitle(_t('queries') . ' · '); } /** -- cgit v1.2.3 From a80e12cbf7a38d5a745b8ce980e9c662f9c64dfb Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 24 Sep 2014 12:32:49 +0200 Subject: Remove queries at the same time as categories See https://github.com/marienfressinaud/FreshRSS/issues/625 --- app/Controllers/configureController.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'app/Controllers') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 4422f33af..d2ca0777f 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -32,7 +32,8 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * every category to check for modification then add a new category if * needed then sends a notification to the user. * If a category name is emptied, the category is deleted and all - * related feeds are moved to the default category. + * related feeds are moved to the default category. Related user queries + * are deleted too. * If a category name is changed, it is updated. */ public function categorizeAction() { @@ -56,6 +57,18 @@ class FreshRSS_configure_Controller extends Minz_ActionController { } elseif ($ids[$key] != $defaultId) { $feedDAO->changeCategory($ids[$key], $defaultId); $catDAO->deleteCategory($ids[$key]); + + // Remove related queries. + $final_queries = array(); + $id_cat_in_query = 'c_' . $ids[$key]; + foreach ($this->view->conf->queries as $key => $query) { + if (empty($query['get']) || + $query['get'] !== $id_cat_in_query) { + $final_queries[$key] = $query; + } + } + $this->view->conf->_queries($final_queries); + $this->view->conf->save(); } } -- cgit v1.2.3 From 666162ae56c2df8ae6a7ed6602b69f6caad10c7c Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 24 Sep 2014 12:34:44 +0200 Subject: Fix a bug when $query['state'] doesn't exist Add a test in addQueryAction(). --- app/Controllers/configureController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/Controllers') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index d2ca0777f..e6e9172e6 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -517,7 +517,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { unset($query[$key]); } } - if ($query['state'] & FreshRSS_Entry::STATE_STRICT) { + if (!empty($query['state']) && $query['state'] & FreshRSS_Entry::STATE_STRICT) { $query['state'] -= FreshRSS_Entry::STATE_STRICT; } $queries[] = $query; -- cgit v1.2.3 From 5a1baff9be7cf9fe3f59fe2a7dc34fbadacc1a99 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 24 Sep 2014 13:28:09 +0200 Subject: Refactor removing query by get param See https://github.com/marienfressinaud/FreshRSS/issues/625 --- app/Controllers/configureController.php | 10 +--------- app/Models/Configuration.php | 10 ++++++++++ 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'app/Controllers') diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index e6e9172e6..231865bd7 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -59,15 +59,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $catDAO->deleteCategory($ids[$key]); // Remove related queries. - $final_queries = array(); - $id_cat_in_query = 'c_' . $ids[$key]; - foreach ($this->view->conf->queries as $key => $query) { - if (empty($query['get']) || - $query['get'] !== $id_cat_in_query) { - $final_queries[$key] = $query; - } - } - $this->view->conf->_queries($final_queries); + $this->view->conf->remove_query_by_get('c_' . $ids[$key]); $this->view->conf->save(); } } diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index ea1556cbb..91d2ab846 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -124,6 +124,16 @@ class FreshRSS_Configuration { return $this->available_languages; } + public function remove_query_by_get($get) { + $final_queries = array(); + foreach ($this->queries as $key => $query) { + if (empty($query['get']) || $query['get'] !== $get) { + $final_queries[$key] = $query; + } + } + $this->_queries($final_queries); + } + public function _language($value) { if (!isset($this->available_languages[$value])) { $value = 'en'; -- cgit v1.2.3 From 17f686095ddebe1a7c94fe665eddfdfef9696015 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 24 Sep 2014 13:38:07 +0200 Subject: Remove queries at the same time as feeds See https://github.com/marienfressinaud/FreshRSS/issues/625 --- app/Controllers/feedController.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'app/Controllers') diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 65d4b3a37..c7cc25fbb 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -383,7 +383,16 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feedDAO = FreshRSS_Factory::createFeedDao(); if ($type == 'category') { + // List feeds to remove then related user queries. + $feeds = $feedDAO->listByCategory($id); + if ($feedDAO->deleteFeedByCategory ($id)) { + // Remove related queries + foreach ($feeds as $feed) { + $this->view->conf->remove_query_by_get('f_' . $feed->id()); + } + $this->view->conf->save(); + $notif = array ( 'type' => 'good', 'content' => Minz_Translate::t ('category_emptied') @@ -397,6 +406,10 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } } else { if ($feedDAO->deleteFeed ($id)) { + // Remove related queries + $this->view->conf->remove_query_by_get('f_' . $id); + $this->view->conf->save(); + $notif = array ( 'type' => 'good', 'content' => Minz_Translate::t ('feed_deleted') -- cgit v1.2.3