From 59c17a3c6c26d6b487e2ec5e02caa3fb26f9ff9c Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sat, 27 Sep 2014 08:20:13 -0400 Subject: Fix read all shortcut Before, the read all shortcut raised a javascript exception when we use the confirmation option. The confirmation was not even displayed. The code was failling since there was a missing variable. Now, the shortcut ask for confirmation when the option is selected in the reading configuration page. The definition of the shortcut was buggy since the confirmation was handled properly in an other location. I simplified the code by removing the confirmation code in the shortcut. --- p/scripts/main.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/p/scripts/main.js b/p/scripts/main.js index f6d5d2907..8a45ae896 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -538,14 +538,7 @@ function init_shortcuts() { }); shortcut.add("shift+" + shortcuts.mark_read, function () { // on marque tout comme lu - var btn = $(".nav_menu .read_all"); - if (btn.hasClass('confirm')) { - if (confirm(str_confirmation)) { - btn.click(); - } - } else { - btn.click(); - } + $(".nav_menu .read_all").click(); }, { 'disable_in_input': true }); -- cgit v1.2.3 From 3d288eb170091c2679cac34ee09e850b56e46861 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Mon, 29 Sep 2014 18:26:28 -0400 Subject: Add percent of total on top 10 feeds --- app/i18n/en.php | 1 + app/i18n/fr.php | 1 + app/views/stats/index.phtml | 2 ++ 3 files changed, 4 insertions(+) diff --git a/app/i18n/en.php b/app/i18n/en.php index beba02c4d..0d3654744 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -56,6 +56,7 @@ return array ( 'stats_entry_per_hour' => 'Per hour', 'stats_entry_per_day_of_week' => 'Per day of week', 'stats_entry_per_month' => 'Per month', + 'stats_percent_of_total' => '%% of total', 'last_week' => 'Last week', 'last_month' => 'Last month', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index b0fbf15ae..c72fc3e93 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -56,6 +56,7 @@ return array ( 'stats_entry_per_hour' => 'Par heure', 'stats_entry_per_day_of_week' => 'Par jour de la semaine', 'stats_entry_per_month' => 'Par mois', + 'stats_percent_of_total' => '%% du total', 'last_week' => 'Depuis la semaine dernière', 'last_month' => 'Depuis le mois dernier', diff --git a/app/views/stats/index.phtml b/app/views/stats/index.phtml index 412e77e16..31185fbe3 100644 --- a/app/views/stats/index.phtml +++ b/app/views/stats/index.phtml @@ -48,6 +48,7 @@ + @@ -56,6 +57,7 @@ + repartition['all_feeds']['total'] * 100, 1);?> -- cgit v1.2.3 From cd88414abcffd94cfce933cf578ecc640b691381 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Mon, 29 Sep 2014 18:54:03 -0400 Subject: Add an average per day for the 30 day period --- app/Controllers/statsController.php | 1 + app/Models/StatsDAO.php | 27 ++++++++++++++++++++++++--- app/Models/StatsDAOSQLite.php | 23 +++++++++++++++++++++++ app/views/stats/index.phtml | 16 +++++++++++++--- 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php index 256543f37..3069be34d 100644 --- a/app/Controllers/statsController.php +++ b/app/Controllers/statsController.php @@ -21,6 +21,7 @@ class FreshRSS_stats_Controller extends Minz_ActionController { Minz_View::appendScript(Minz_Url::display('/scripts/flotr2.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/flotr2.min.js'))); $this->view->repartition = $statsDAO->calculateEntryRepartition(); $this->view->count = $statsDAO->calculateEntryCount(); + $this->view->average = $statsDAO->calculateEntryAverage(); $this->view->feedByCategory = $statsDAO->calculateFeedByCategory(); $this->view->entryByCategory = $statsDAO->calculateEntryByCategory(); $this->view->topFeed = $statsDAO->calculateTopFeed(); diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 40505ab3e..08dd4cd5c 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -79,6 +79,27 @@ SQL; return $this->convertToSerie($count); } + /** + * Calculates entry average per day on a 30 days period. + * + * @return integer + */ + public function calculateEntryAverage() { + $period = self::ENTRY_COUNT_PERIOD; + + // Get stats per day for the last 30 days + $sql = <<prefix}entry AS e +WHERE FROM_UNIXTIME(e.date, '%Y%m%d') BETWEEN DATE_FORMAT(DATE_ADD(NOW(), INTERVAL -{$period} DAY), '%Y%m%d') AND DATE_FORMAT(DATE_ADD(NOW(), INTERVAL -1 DAY), '%Y%m%d') +SQL; + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetch(PDO::FETCH_NAMED); + + return round($res['average'], 2); + } + /** * Initialize an array for the entry count. * @@ -160,7 +181,7 @@ SQL; public function calculateEntryAveragePerFeedPerHour($feed = null) { return $this->calculateEntryAveragePerFeedPerPeriod(1/24, $feed); } - + /** * Calculates the average number of article per day of week per feed * @@ -180,10 +201,10 @@ SQL; 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 diff --git a/app/Models/StatsDAOSQLite.php b/app/Models/StatsDAOSQLite.php index 3b1256de1..bb2336532 100644 --- a/app/Models/StatsDAOSQLite.php +++ b/app/Models/StatsDAOSQLite.php @@ -34,6 +34,29 @@ SQL; return $this->convertToSerie($count); } + /** + * Calculates entry average per day on a 30 days period. + * + * @return integer + */ + public function calculateEntryAverage() { + $period = self::ENTRY_COUNT_PERIOD; + + // Get stats per day for the last 30 days + $sql = <<prefix}entry AS e +WHERE strftime('%Y%m%d', e.date, 'unixepoch') + BETWEEN strftime('%Y%m%d', 'now', '-{$period} days') + AND strftime('%Y%m%d', 'now', '-1 day') +SQL; + $stm = $this->bd->prepare($sql); + $stm->execute(); + $res = $stm->fetch(PDO::FETCH_NAMED); + + return round($res['average'], 2); + } + protected function calculateEntryRepartitionPerFeedPerPeriod($period, $feed = null) { if ($feed) { $restrict = "WHERE e.id_feed = {$feed}"; diff --git a/app/views/stats/index.phtml b/app/views/stats/index.phtml index 31185fbe3..9b19cb560 100644 --- a/app/views/stats/index.phtml +++ b/app/views/stats/index.phtml @@ -93,12 +93,22 @@ function initStats() { return; } // Entry per day + var avg = []; + for (var i = -31; i <= 0; i++) { + avg.push([i, average?>]); + } Flotr.draw(document.getElementById('statsEntryPerDay'), - [count ?>], + [{ + data: count ?>, + bars: {horizontal: false, show: true} + },{ + data: avg, + lines: {show: true}, + label: average?> + }], { grid: {verticalLines: false}, - bars: {horizontal: false, show: true}, - xaxis: {noTicks: 6, showLabels: false, tickDecimals: 0}, + xaxis: {noTicks: 6, showLabels: false, tickDecimals: 0, min: -30.75, max: -0.25}, yaxis: {min: 0}, mouse: {relative: true, track: true, trackDecimals: 0, trackFormatter: function(obj) {return numberFormat(obj.y);}} }); -- cgit v1.2.3 From fc6a3c2fd223d3c723c534768238182c917a2318 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Mon, 29 Sep 2014 18:57:40 -0400 Subject: Add string delimiters for averages. Before, if the average was equal to 0, it was displayed on the graph but the label was not displayed. Now, the label is displayed. --- app/views/stats/index.phtml | 2 +- app/views/stats/repartition.phtml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/stats/index.phtml b/app/views/stats/index.phtml index 9b19cb560..fa57a77c0 100644 --- a/app/views/stats/index.phtml +++ b/app/views/stats/index.phtml @@ -104,7 +104,7 @@ function initStats() { },{ data: avg, lines: {show: true}, - label: average?> + label: "average?>" }], { grid: {verticalLines: false}, diff --git a/app/views/stats/repartition.phtml b/app/views/stats/repartition.phtml index b425c1458..750a3ffdc 100644 --- a/app/views/stats/repartition.phtml +++ b/app/views/stats/repartition.phtml @@ -67,7 +67,7 @@ function initStats() { }, { data: avg_h, lines: {show: true}, - label: averageHour?>, + label: "averageHour?>", yaxis: 2 }], { @@ -96,7 +96,7 @@ function initStats() { }, { data: avg_dow, lines: {show: true}, - label: averageDayOfWeek?>, + label: "averageDayOfWeek?>", yaxis: 2 }], { @@ -126,7 +126,7 @@ function initStats() { }, { data: avg_m, lines: {show: true}, - label: averageMonth?>, + label: "averageMonth?>", yaxis: 2 }], { -- cgit v1.2.3 From d087f753370541b2f35f59ded7db1aaff2370e9e Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 30 Sep 2014 10:10:06 +0200 Subject: We are working on 0.10-dev... but it could be the 1.0! --- CHANGELOG | 2 +- README.fr.md | 4 ++-- README.md | 4 ++-- constants.php | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index d7de86d9b..44d3452ae 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,6 @@ # Journal des modifications -## 2014-09-xx FreshRSS 0.8.0 +## 2014-09-26 FreshRSS 0.8.0 / 0.9.0 (beta) * UI * New interface for statistics diff --git a/README.fr.md b/README.fr.md index df43ef7e8..4e6c52d68 100644 --- a/README.fr.md +++ b/README.fr.md @@ -10,8 +10,8 @@ Il permet de gérer plusieurs utilisateurs, et dispose d’un mode de lecture an * Site officiel : http://freshrss.org * Démo : http://demo.freshrss.org/ * Développeur : Marien Fressinaud -* Version actuelle : 0.8-dev -* Date de publication 2014-0x-xx +* Version actuelle : 0.10-dev +* Date de publication 2014-xx-xx * License [GNU AGPL 3](http://www.gnu.org/licenses/agpl-3.0.html) ![Logo de FreshRSS](http://marienfressinaud.fr/data/images/freshrss/freshrss_title.png) diff --git a/README.md b/README.md index 0a22df8f1..971d53ea6 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ It is a multi-user application with an anonymous reading mode. * Official website: http://freshrss.org * Demo: http://demo.freshrss.org/ * Developer: Marien Fressinaud -* Current version: 0.8-dev -* Publication date: 2014-0x-xx +* Current version: 0.10-dev +* Publication date: 2014-xx-xx * License [GNU AGPL 3](http://www.gnu.org/licenses/agpl-3.0.html) ![FreshRSS logo](http://marienfressinaud.fr/data/images/freshrss/freshrss_title.png) diff --git a/constants.php b/constants.php index 4c515d121..f66a012b0 100644 --- a/constants.php +++ b/constants.php @@ -1,5 +1,5 @@ Date: Tue, 30 Sep 2014 11:08:30 +0200 Subject: Add space after tag icon Fix https://github.com/marienfressinaud/FreshRSS/issues/643 --- app/views/helpers/view/normal_view.phtml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/views/helpers/view/normal_view.phtml b/app/views/helpers/view/normal_view.phtml index 1dbf14f4c..6d9789f8d 100644 --- a/app/views/helpers/view/normal_view.phtml +++ b/app/views/helpers/view/normal_view.phtml @@ -153,14 +153,15 @@ if (!empty($this->entries)) { if (!empty($tags)) { ?>
  • + + -- cgit v1.2.3 From 549500764e66529dae082f4f3cde4d639e8f189e Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 30 Sep 2014 12:14:28 +0200 Subject: Coding style (aside_feed.phtml) See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/layout/aside_feed.phtml | 51 +++++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/app/layout/aside_feed.phtml b/app/layout/aside_feed.phtml index 5ffb1c791..c72710c2d 100644 --- a/app/layout/aside_feed.phtml +++ b/app/layout/aside_feed.phtml @@ -1,75 +1,76 @@ -- cgit v1.2.3 From 46ae0a3f5ada751c9442eca275e15450fad85509 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 30 Sep 2014 14:33:28 +0200 Subject: BREAK CATEGORIZE SYSTEM! And begin big changes. See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/views/configure/categorize.phtml | 102 +++++++++++++++++++---------------- p/themes/base-theme/template.css | 20 +++++++ 2 files changed, 75 insertions(+), 47 deletions(-) diff --git a/app/views/configure/categorize.phtml b/app/views/configure/categorize.phtml index 23d1c9fa1..7091ff1cf 100644 --- a/app/views/configure/categorize.phtml +++ b/app/views/configure/categorize.phtml @@ -1,55 +1,63 @@ -partial ('aside_feed'); ?> +partial('aside_feed'); ?> -
    - +
    + -
    - +
    +
    -

    defaultCategory->name ()); ?>

    - - categories as $cat) { $i++; ?> -
    - -
    -
    - - - nbFeed () > 0) { ?> - - - - - -
    - (nbFeed ()); ?>) - - id () === $this->defaultCategory->id ()) { ?> - - - - -
    +
    + + + +
    - - -
    - -
    - +
    + + categories as $cat) { + $feeds = $cat->feeds(); + ?> +
    +
    + +
    -
    -
    - - -
    -
    - +
      + + inError() ? ' error' : ''; + $empty = $feed->nbEntries() == 0 ? ' empty' : ''; + ?> +
    • + + ✇ name(); ?> +
    • + +
    • Empty
    • + +
    +
    +
    diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index dc011503d..792eac299 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -559,6 +559,8 @@ br + br + br { /*=== GLOBAL VIEW */ /*================*/ /*=== Category boxes */ + +/* TODO */ #stream.global .box-category { display: inline-block; width: 19em; @@ -581,6 +583,24 @@ br + br + br { width: 19em; max-width: 90%; } +/* TODO Date: Tue, 30 Sep 2014 15:02:56 +0200 Subject: Move creation of categories in a new Controller Category names are 255 chars max --- app/Controllers/categoryController.php | 64 +++++++++++++++++++++++++++++++++ app/Controllers/configureController.php | 12 ------- app/Models/Category.php | 2 +- app/views/configure/categorize.phtml | 2 +- 4 files changed, 66 insertions(+), 14 deletions(-) create mode 100644 app/Controllers/categoryController.php diff --git a/app/Controllers/categoryController.php b/app/Controllers/categoryController.php new file mode 100644 index 000000000..e2d98a509 --- /dev/null +++ b/app/Controllers/categoryController.php @@ -0,0 +1,64 @@ +view->loginOk) { + Minz_Error::error( + 403, + array('error' => array(_t('access_denied'))) + ); + } + + $catDAO = new FreshRSS_CategoryDAO(); + $catDAO->checkDefault(); + } + + /** + * This action creates a new category. + * + * URL parameter is: + * - new-category + */ + public function createAction() { + $catDAO = new FreshRSS_CategoryDAO(); + $url_redirect = array('c' => 'configure', 'a' => 'categorize'); + + if (Minz_Request::isPost()) { + invalidateHttpCache(); + + $cat_name = Minz_Request::param('new-category'); + if (!$cat_name) { + Minz_Request::bad(_t('category_no_name'), $url_redirect); + } + + $cat = new FreshRSS_Category($cat_name); + + if ($catDAO->searchByName($cat->name()) != null) { + Minz_Request::bad(_t('category_name_exists'), $url_redirect); + } + + $values = array( + 'id' => $cat->id(), + 'name' => $cat->name(), + ); + + if ($catDAO->addCategory($values)) { + Minz_Request::good(_t('category_created', $cat->name()), $url_redirect); + } else { + Minz_Request::bad(_t('category_not_created'), $url_redirect); + } + } + + Minz_Request::forward($url_redirect, true); + } +} diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 231865bd7..7ef144090 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -45,7 +45,6 @@ class FreshRSS_configure_Controller extends Minz_ActionController { if (Minz_Request::isPost()) { $cats = Minz_Request::param('categories', array()); $ids = Minz_Request::param('ids', array()); - $newCat = trim(Minz_Request::param('new_category', '')); foreach ($cats as $key => $name) { if (strlen($name) > 0) { @@ -64,17 +63,6 @@ class FreshRSS_configure_Controller extends Minz_ActionController { } } - if ($newCat != '') { - $cat = new FreshRSS_Category($newCat); - $values = array( - 'id' => $cat->id(), - 'name' => $cat->name(), - ); - - if ($catDAO->searchByName($newCat) == null) { - $catDAO->addCategory($values); - } - } invalidateHttpCache(); Minz_Request::good(_t('categories_updated'), diff --git a/app/Models/Category.php b/app/Models/Category.php index 0a0dbd3ca..e5f6c4334 100644 --- a/app/Models/Category.php +++ b/app/Models/Category.php @@ -61,7 +61,7 @@ class FreshRSS_Category extends Minz_Model { $this->id = $value; } public function _name ($value) { - $this->name = $value; + $this->name = substr(trim($value), 0, 255); } public function _feeds ($values) { if (!is_array ($values)) { diff --git a/app/views/configure/categorize.phtml b/app/views/configure/categorize.phtml index 7091ff1cf..e7435e1c7 100644 --- a/app/views/configure/categorize.phtml +++ b/app/views/configure/categorize.phtml @@ -7,7 +7,7 @@
    -
    +
    -- cgit v1.2.3 From 9e0a62727f8ff3c6a68b4ef85089633677ff67ef Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 30 Sep 2014 15:44:45 +0200 Subject: Move empty cat action in the new Controller feedController::delete is simpler than before. Improve coding style See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/Controllers/categoryController.php | 43 ++++++++++++++++++++-- app/Controllers/feedController.php | 66 +++++++++++----------------------- app/views/configure/categorize.phtml | 8 +++-- 3 files changed, 66 insertions(+), 51 deletions(-) diff --git a/app/Controllers/categoryController.php b/app/Controllers/categoryController.php index e2d98a509..6863c3bb8 100644 --- a/app/Controllers/categoryController.php +++ b/app/Controllers/categoryController.php @@ -26,7 +26,7 @@ class FreshRSS_category_Controller extends Minz_ActionController { /** * This action creates a new category. * - * URL parameter is: + * Request parameter is: * - new-category */ public function createAction() { @@ -55,7 +55,46 @@ class FreshRSS_category_Controller extends Minz_ActionController { if ($catDAO->addCategory($values)) { Minz_Request::good(_t('category_created', $cat->name()), $url_redirect); } else { - Minz_Request::bad(_t('category_not_created'), $url_redirect); + Minz_Request::bad(_t('error_occured'), $url_redirect); + } + } + + Minz_Request::forward($url_redirect, true); + } + + /** + * This action deletes all the feeds relative to a given category + * + * Request parameter is: + * - id (of a category) + */ + public function emptyAction() { + $feedDAO = FreshRSS_Factory::createFeedDao(); + $url_redirect = array('c' => 'configure', 'a' => 'categorize'); + + if (Minz_Request::isPost()) { + invalidateHttpCache(); + + $id = Minz_Request::param('id'); + if (!$id) { + Minz_Request::bad(_t('category_no_id'), $url_redirect); + } + + // List feeds to remove then related user queries. + $feeds = $feedDAO->listByCategory($id); + + if ($feedDAO->deleteFeedByCategory($id)) { + // TODO: Delete old favicons + + // Remove related queries + foreach ($feeds as $feed) { + $this->view->conf->remove_query_by_get('f_' . $feed->id()); + } + $this->view->conf->save(); + + Minz_Request::good(_t('category_emptied'), $url_redirect); + } else { + Minz_Request::bad(_t('error_occured'), $url_redirect); } } diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index c7cc25fbb..7ef427ac2 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -376,62 +376,36 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } } - public function deleteAction () { - if (Minz_Request::isPost ()) { - $type = Minz_Request::param ('type', 'feed'); - $id = Minz_Request::param ('id'); - + public function deleteAction() { + if (Minz_Request::isPost()) { + $id = Minz_Request::param('id'); $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') - ); - //TODO: Delete old favicons - } else { - $notif = array ( - 'type' => 'bad', - 'content' => Minz_Translate::t ('error_occured') - ); - } - } else { - if ($feedDAO->deleteFeed ($id)) { - // Remove related queries - $this->view->conf->remove_query_by_get('f_' . $id); - $this->view->conf->save(); + if ($feedDAO->deleteFeed($id)) { + // TODO: Delete old favicon - $notif = array ( - 'type' => 'good', - 'content' => Minz_Translate::t ('feed_deleted') - ); - //TODO: Delete old favicon - } else { - $notif = array ( - 'type' => 'bad', - 'content' => Minz_Translate::t ('error_occured') - ); - } + // Remove related queries + $this->view->conf->remove_query_by_get('f_' . $id); + $this->view->conf->save(); + + $notif = array( + 'type' => 'good', + 'content' => _t('feed_deleted') + ); + } else { + $notif = array( + 'type' => 'bad', + 'content' => _t('error_occured') + ); } - Minz_Session::_param ('notification', $notif); + Minz_Session::_param('notification', $notif); $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/configure/categorize.phtml b/app/views/configure/categorize.phtml index e7435e1c7..2d9dd65ca 100644 --- a/app/views/configure/categorize.phtml +++ b/app/views/configure/categorize.phtml @@ -1,7 +1,6 @@ partial('aside_feed'); ?>
    -
    @@ -14,6 +13,8 @@
    + + categories as $cat) { $feeds = $cat->feeds(); @@ -32,8 +33,9 @@ + form="controller-category" + formaction="id()); ?>"> +
  • -- cgit v1.2.3 From b9ddffdade8f6b8ba32684ca7eb640338074e61b Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 30 Sep 2014 16:09:08 +0200 Subject: Additional information about cat configuration See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/views/configure/categorize.phtml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/views/configure/categorize.phtml b/app/views/configure/categorize.phtml index 2d9dd65ca..5cd962ae4 100644 --- a/app/views/configure/categorize.phtml +++ b/app/views/configure/categorize.phtml @@ -1,6 +1,13 @@ partial('aside_feed'); ?> -
    +
    + + +

    + +

    + defaultCategory->name()); ?> +

    -- cgit v1.2.3 From 13fb1170c06bd67ba69534e823ea6f5861c745dd Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 30 Sep 2014 16:31:38 +0200 Subject: Move deletion of categories into new Controller Fix i18n (occured -> occurred) See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/Controllers/categoryController.php | 47 ++++++++++++++++++++++++++++++--- app/Controllers/configureController.php | 7 ----- app/views/configure/categorize.phtml | 9 ++++++- 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/app/Controllers/categoryController.php b/app/Controllers/categoryController.php index 6863c3bb8..be8524749 100644 --- a/app/Controllers/categoryController.php +++ b/app/Controllers/categoryController.php @@ -55,7 +55,7 @@ class FreshRSS_category_Controller extends Minz_ActionController { if ($catDAO->addCategory($values)) { Minz_Request::good(_t('category_created', $cat->name()), $url_redirect); } else { - Minz_Request::bad(_t('error_occured'), $url_redirect); + Minz_Request::bad(_t('error_occurred'), $url_redirect); } } @@ -63,7 +63,48 @@ class FreshRSS_category_Controller extends Minz_ActionController { } /** - * This action deletes all the feeds relative to a given category + * This action deletes a category. + * Feeds in the given category are moved in the default category. + * Related user queries are deleted too. + * + * Request parameter is: + * - id (of a category) + */ + public function deleteAction() { + $feedDAO = FreshRSS_Factory::createFeedDao(); + $catDAO = new FreshRSS_CategoryDAO(); + $default_category = $catDAO->getDefault(); + $url_redirect = array('c' => 'configure', 'a' => 'categorize'); + + if (Minz_Request::isPost()) { + invalidateHttpCache(); + + $id = Minz_Request::param('id'); + if (!$id) { + Minz_Request::bad(_t('category_no_id'), $url_redirect); + } + + if ($feedDAO->changeCategory($id, $default_category->id()) === false) { + Minz_Request::bad(_t('error_occurred'), $url_redirect); + } + + if ($catDAO->deleteCategory($id) === false) { + Minz_Request::bad(_t('error_occurred'), $url_redirect); + } + + // Remove related queries. + $this->view->conf->remove_query_by_get('c_' . $id); + $this->view->conf->save(); + + Minz_Request::good(_t('category_deleted'), $url_redirect); + } + + Minz_Request::forward($url_redirect, true); + } + + /** + * This action deletes all the feeds relative to a given category. + * Feed-related queries are deleted. * * Request parameter is: * - id (of a category) @@ -94,7 +135,7 @@ class FreshRSS_category_Controller extends Minz_ActionController { Minz_Request::good(_t('category_emptied'), $url_redirect); } else { - Minz_Request::bad(_t('error_occured'), $url_redirect); + Minz_Request::bad(_t('error_occurred'), $url_redirect); } } diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 7ef144090..a7def6d9a 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -53,13 +53,6 @@ class FreshRSS_configure_Controller extends Minz_ActionController { 'name' => $cat->name(), ); $catDAO->updateCategory($ids[$key], $values); - } elseif ($ids[$key] != $defaultId) { - $feedDAO->changeCategory($ids[$key], $defaultId); - $catDAO->deleteCategory($ids[$key]); - - // Remove related queries. - $this->view->conf->remove_query_by_get('c_' . $ids[$key]); - $this->view->conf->save(); } } diff --git a/app/views/configure/categorize.phtml b/app/views/configure/categorize.phtml index 5cd962ae4..781c4bb14 100644 --- a/app/views/configure/categorize.phtml +++ b/app/views/configure/categorize.phtml @@ -44,7 +44,14 @@ formaction="id()); ?>"> -
  • +
  • + +
  • -- cgit v1.2.3 From dc714d3949373b79344438335cfc0edde77de036 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 30 Sep 2014 17:11:31 +0200 Subject: Cat updating system works Add a submit button Each box contains a specific form See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/Controllers/categoryController.php | 39 ++++++++++++++++++++++++ app/views/configure/categorize.phtml | 54 +++++++++++++++++++--------------- 2 files changed, 69 insertions(+), 24 deletions(-) diff --git a/app/Controllers/categoryController.php b/app/Controllers/categoryController.php index be8524749..65fe631cc 100644 --- a/app/Controllers/categoryController.php +++ b/app/Controllers/categoryController.php @@ -62,6 +62,45 @@ class FreshRSS_category_Controller extends Minz_ActionController { Minz_Request::forward($url_redirect, true); } + /** + * This action updates the given category. + * + * Request parameters are: + * - id + * - name + */ + public function updateAction() { + $catDAO = new FreshRSS_CategoryDAO(); + $url_redirect = array('c' => 'configure', 'a' => 'categorize'); + + if (Minz_Request::isPost()) { + invalidateHttpCache(); + + $id = Minz_Request::param('id'); + $name = Minz_Request::param('name', ''); + if (strlen($name) <= 0) { + Minz_Request::bad(_t('category_no_name'), $url_redirect); + } + + if ($catDAO->searchById($id) == null) { + Minz_Request::bad(_t('category_not_exist'), $url_redirect); + } + + $cat = new FreshRSS_Category($name); + $values = array( + 'name' => $cat->name(), + ); + + if ($catDAO->updateCategory($id, $values)) { + Minz_Request::good(_t('category_updated'), $url_redirect); + } else { + Minz_Request::bad(_t('error_occurred'), $url_redirect); + } + } + + Minz_Request::forward($url_redirect, true); + } + /** * This action deletes a category. * Feeds in the given category are moved in the default category. diff --git a/app/views/configure/categorize.phtml b/app/views/configure/categorize.phtml index 781c4bb14..b9d04ddb8 100644 --- a/app/views/configure/categorize.phtml +++ b/app/views/configure/categorize.phtml @@ -28,32 +28,38 @@ ?>
    - - + + +
    +
      -- cgit v1.2.3 From 0d5a1f3a659b6f407b47859c794a662075e3f48e Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 30 Sep 2014 19:45:49 +0200 Subject: Improve design of .box See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/layout/aside_feed.phtml | 16 ----------- app/views/configure/categorize.phtml | 24 +++++++++-------- p/themes/Dark/dark.css | 29 ++++++++++++++++++++ p/themes/Flat/flat.css | 30 +++++++++++++++++++++ p/themes/Origine/origine.css | 30 +++++++++++++++++++++ p/themes/Pafat/pafat.css | 29 ++++++++++++++++++++ p/themes/Screwdriver/screwdriver.css | 34 ++++++++++++++++++++++++ p/themes/base-theme/base.css | 24 +++++++++++++++++ p/themes/base-theme/template.css | 51 ++++++++++++++++++++++++------------ 9 files changed, 223 insertions(+), 44 deletions(-) diff --git a/app/layout/aside_feed.phtml b/app/layout/aside_feed.phtml index c72710c2d..c028c4918 100644 --- a/app/layout/aside_feed.phtml +++ b/app/layout/aside_feed.phtml @@ -57,20 +57,4 @@
    • - -
    • - - feeds)) { ?> - feeds as $feed) { ?> - nbEntries(); ?> -
    • - - ✇ - name(); ?> - -
    • - - -
    • -
    diff --git a/app/views/configure/categorize.phtml b/app/views/configure/categorize.phtml index b9d04ddb8..8f77f9724 100644 --- a/app/views/configure/categorize.phtml +++ b/app/views/configure/categorize.phtml @@ -12,12 +12,12 @@
    -
    +
      - - +
    • +
    • -
    +
    @@ -27,10 +27,9 @@ $feeds = $cat->feeds(); ?>
    -
    +
    - diff --git a/p/themes/Dark/dark.css b/p/themes/Dark/dark.css index 10f6e655b..f3790614e 100644 --- a/p/themes/Dark/dark.css +++ b/p/themes/Dark/dark.css @@ -435,6 +435,35 @@ a.btn { font-size: 0; } +/*=== Boxes */ +.box { + border: 1px solid #000; + border-radius: 5px; +} +.box .box-title { + margin: 0; + padding: 5px 10px; + background: #26303F; + border-bottom: 1px solid #000; + border-radius: 5px 5px 0 0; +} +.box .box-content { + max-height: 260px; +} + +.box .box-content .item { + padding: 0 10px; + font-size: 0.9rem; + line-height: 2.5em; +} + +.box .box-content .item .configure { + visibility: hidden; +} +.box .box-content .item:hover .configure { + visibility: visible; +} + /*=== STRUCTURE */ /*===============*/ /*=== Header */ diff --git a/p/themes/Flat/flat.css b/p/themes/Flat/flat.css index 484cee9f3..d0ac46fd5 100644 --- a/p/themes/Flat/flat.css +++ b/p/themes/Flat/flat.css @@ -438,6 +438,36 @@ a.btn { background: url("loader.gif") center center no-repeat #34495e; } +/*=== Boxes */ +.box { + border: 1px solid #ddd; + border-radius: 5px; +} +.box .box-title { + margin: 0; + padding: 5px 10px; + background: #ecf0f1; + color: #333; + border-bottom: 1px solid #ddd; + border-radius: 5px 5px 0 0; +} +.box .box-content { + max-height: 260px; +} + +.box .box-content .item { + padding: 0 10px; + font-size: 0.9rem; + line-height: 2.5em; +} + +.box .box-content .item .configure { + visibility: hidden; +} +.box .box-content .item:hover .configure { + visibility: visible; +} + /*=== STRUCTURE */ /*===============*/ /*=== Header */ diff --git a/p/themes/Origine/origine.css b/p/themes/Origine/origine.css index 08fc08379..e3ae85075 100644 --- a/p/themes/Origine/origine.css +++ b/p/themes/Origine/origine.css @@ -467,6 +467,36 @@ a.btn { font-size: 0; } +/*=== Boxes */ +.box { + background: #fff; + border-radius: 5px; + box-shadow: 0 0 3px #bbb; +} +.box .box-title { + margin: 0; + padding: 5px 10px; + background: #f6f6f6; + border-bottom: 1px solid #ddd; + border-radius: 5px 5px 0 0; +} +.box .box-content { + max-height: 260px; +} + +.box .box-content .item { + padding: 0 10px; + font-size: 0.9rem; + line-height: 2.5em; +} + +.box .box-content .item .configure { + visibility: hidden; +} +.box .box-content .item:hover .configure { + visibility: visible; +} + /*=== STRUCTURE */ /*===============*/ /*=== Header */ diff --git a/p/themes/Pafat/pafat.css b/p/themes/Pafat/pafat.css index a35ac861d..28b17e15f 100644 --- a/p/themes/Pafat/pafat.css +++ b/p/themes/Pafat/pafat.css @@ -491,6 +491,35 @@ a.btn { font-size: 0; } +/*=== Boxes */ +.box { + border: 1px solid #aaa; + border-radius: 5px; +} +.box .box-title { + margin: 0; + padding: 5px 10px; + background: #f6f6f6; + border-bottom: 1px solid #aaa; + border-radius: 5px 5px 0 0; +} +.box .box-content { + max-height: 260px; +} + +.box .box-content .item { + padding: 0 10px; + font-size: 0.9rem; + line-height: 2.5em; +} + +.box .box-content .item .configure { + visibility: hidden; +} +.box .box-content .item:hover .configure { + visibility: visible; +} + /*=== STRUCTURE */ /*===============*/ /*=== Header */ diff --git a/p/themes/Screwdriver/screwdriver.css b/p/themes/Screwdriver/screwdriver.css index 37fa18e10..6206504d1 100644 --- a/p/themes/Screwdriver/screwdriver.css +++ b/p/themes/Screwdriver/screwdriver.css @@ -497,6 +497,40 @@ a.btn { font-size: 0; } +/*=== Boxes */ +.box { + background: #EDE7DE; + border-radius: 4px 4px 0 0; +} +.box .box-title { + margin: 0; + padding: 5px 10px; + background: linear-gradient(0deg, #EDE7DE 0%, #fff 100%) #171717; + background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #fff 100%); + box-shadow: 0px -1px #fff inset,0 -2px #ccc inset; + color: #888; + text-shadow: 0 1px #ccc; + border-radius: 4px 4px 0 0; + font-size: 1.1rem; + font-weight: normal; +} +.box .box-content { + max-height: 260px; +} + +.box .box-content .item { + padding: 0 10px; + font-size: 0.9rem; + line-height: 2.5em; +} + +.box .box-content .item .configure { + visibility: hidden; +} +.box .box-content .item:hover .configure { + visibility: visible; +} + /*=== STRUCTURE */ /*===============*/ /*=== Header */ diff --git a/p/themes/base-theme/base.css b/p/themes/base-theme/base.css index ccfab10df..3f6ae956d 100644 --- a/p/themes/base-theme/base.css +++ b/p/themes/base-theme/base.css @@ -329,6 +329,30 @@ a.btn { font-size: 0; } +/*=== Boxes */ +.box { +} +.box .box-title { + margin: 0; + padding: 5px 10px; +} +.box .box-content { + max-height: 260px; +} + +.box .box-content .item { + padding: 0 10px; + font-size: 0.9rem; + line-height: 2.5em; +} + +.box .box-content .item .configure { + visibility: hidden; +} +.box .box-content .item:hover .configure { + visibility: visible; +} + /*=== STRUCTURE */ /*===============*/ /*=== Header */ diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index 792eac299..a5a29ab23 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -280,6 +280,40 @@ a.btn { width: 100px; } +/*=== Boxes */ +.box { + display: inline-block; + width: 20rem; + max-width: 95%; + margin: 20px 10px; + border: 1px solid #ccc; + vertical-align: top; +} +.box .box-title { + font-size: 1.2rem; + font-weight: bold; + text-align: center; +} +.box .box-title form { + margin: 0; +} +.box .box-content { + display: block; + overflow: auto; +} +.box .box-content .item { + display: block; +} + +.box .box-content-centered { + padding: 30px 5px; + text-align: center; +} +.box .box-content-centered .btn { + margin: 20px 0 0; +} + + /*=== STRUCTURE */ /*===============*/ /*=== Header */ @@ -585,23 +619,6 @@ br + br + br { } /* TODO Date: Tue, 30 Sep 2014 22:18:01 +0200 Subject: i18n minor spelling --- app/i18n/en.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/i18n/en.php b/app/i18n/en.php index beba02c4d..98f611c13 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -368,7 +368,7 @@ return array ( 'login_required' => 'Login required:', 'confirm_action' => 'Are you sure you want to perform this action? It cannot be cancelled!', - 'confirm_action_feed_cat' => 'Are you sure you want to perform this action? You may lost related favorites and user queries. It cannot be cancelled!', + 'confirm_action_feed_cat' => 'Are you sure you want to perform this action? You may lose related favorites and user queries. It cannot be cancelled!', 'notif_title_new_articles' => 'FreshRSS: new articles!', 'notif_body_new_articles' => 'There are \d new articles to read on FreshRSS.', -- cgit v1.2.3 From a5a0bd9a350836cb7e504fdb501c82cda37d2562 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 30 Sep 2014 22:28:47 +0200 Subject: SQL performance: Removed filter to hide old articles As discussed on https://github.com/marienfressinaud/FreshRSS/issues/493#issuecomment-56266415 For performance, but this is also a good simplification. Will help with PostgreSQL https://github.com/marienfressinaud/FreshRSS/issues/416 and SQLite too https://github.com/marienfressinaud/FreshRSS/issues/100 because the main query becomes simpler. Me may need to introduce another system to hide old articles, if this is a problem for some users. Also, the feature showing "empty feeds" in another colour may need to be adapted. --- app/Controllers/indexController.php | 12 +++--------- app/Models/EntryDAO.php | 29 ++++++++++------------------- 2 files changed, 13 insertions(+), 28 deletions(-) diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index e8e26b142..1b6563bb3 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -113,16 +113,10 @@ class FreshRSS_index_Controller extends Minz_ActionController { } } - $today = @strtotime('today'); - $this->view->today = $today; - - // on calcule la date des articles les plus anciens qu'on affiche - $nb_month_old = $this->view->conf->old_entries; - $date_min = $today - (3600 * 24 * 30 * $nb_month_old); //Do not use a fast changing value such as time() to allow SQL caching - $keepHistoryDefault = $this->view->conf->keep_history_default; + $this->view->today = @strtotime('today'); try { - $entries = $entryDAO->listWhere($getType, $getId, $this->view->state, $order, $nb + 1, $first, $filter, $date_min, true, $keepHistoryDefault); + $entries = $entryDAO->listWhere($getType, $getId, $this->view->state, $order, $nb + 1, $first, $filter); // Si on a récupéré aucun article "non lus" // on essaye de récupérer tous les articles @@ -135,7 +129,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { Minz_Log::record('Failed to automatically correct nbNotRead! ' + $ex->getMessage(), Minz_Log::NOTICE); } $this->view->state = FreshRSS_Entry::STATE_ALL; - $entries = $entryDAO->listWhere($getType, $getId, $this->view->state, $order, $nb, $first, $filter, $date_min, true, $keepHistoryDefault); + $entries = $entryDAO->listWhere($getType, $getId, $this->view->state, $order, $nb, $first, $filter); } Minz_Request::_param('state', $this->view->state); diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index c1f87ee34..751ee6da7 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -299,7 +299,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { return 'CONCAT(' . $s1 . ',' . $s2 . ')'; //MySQL } - private function sqlListWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) { + private function sqlListWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0) { if (!$state) { $state = FreshRSS_Entry::STATE_ALL; } @@ -356,23 +356,14 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { default: throw new FreshRSS_EntriesGetter_Exception('Bad order in Entry->listByType: [' . $order . ']!'); } - if ($firstId === '' && parent::$sharedDbType === 'mysql') { - $firstId = $order === 'DESC' ? '9000000000'. '000000' : '0'; //MySQL optimization. Tested on MySQL 5.5 with 150k articles - } + /*if ($firstId === '' && parent::$sharedDbType === 'mysql') { + $firstId = $order === 'DESC' ? '9000000000'. '000000' : '0'; //MySQL optimization. TODO: check if this is needed again, after the filtering for old articles has been removed in 0.9-dev + }*/ if ($firstId !== '') { $where .= 'AND e1.id ' . ($order === 'DESC' ? '<=' : '>=') . $firstId . ' '; } - if (($date_min > 0) && ($type !== 's')) { - $where .= 'AND (e1.id >= ' . $date_min . '000000'; - if ($showOlderUnreadsorFavorites) { //Lax date constraint - $where .= ' OR e1.is_read=0 OR e1.is_favorite=1 OR (f.keep_history <> 0'; - if (intval($keepHistoryDefault) === 0) { - $where .= ' AND f.keep_history <> -2'; //default - } - $where .= ')'; - } - $where .= ') '; - $joinFeed = true; + if ($date_min > 0) { + $where .= 'AND e1.id >= ' . $date_min . '000000 '; } $search = ''; if ($filter !== '') { @@ -434,8 +425,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { . ($limit > 0 ? ' LIMIT ' . $limit : '')); //TODO: See http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/ } - public function listWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) { - list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min, $showOlderUnreadsorFavorites, $keepHistoryDefault); + public function listWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0) { + list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min); $sql = 'SELECT e.id, e.guid, e.title, e.author, ' . ($this->isCompressed() ? 'UNCOMPRESS(content_bin) AS content' : 'content') @@ -452,8 +443,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { return self::daoToEntry($stm->fetchAll(PDO::FETCH_ASSOC)); } - public function listIdsWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) { //For API - list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min, $showOlderUnreadsorFavorites, $keepHistoryDefault); + public function listIdsWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0) { //For API + list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min); $stm = $this->bd->prepare($sql); $stm->execute($values); -- cgit v1.2.3 From 7481887db746fd2d6eefab021776b8abd4076429 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 1 Oct 2014 10:06:04 +0200 Subject: Load feed configuration on the same page Need improvements See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/Controllers/configureController.php | 4 ++++ app/views/configure/categorize.phtml | 5 ++++- app/views/configure/feed.phtml | 8 ++++++-- p/scripts/main.js | 30 ++++++++++++++++++++++++++++++ p/themes/base-theme/template.css | 5 +++++ 5 files changed, 49 insertions(+), 3 deletions(-) diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index a7def6d9a..dd7a0a441 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -90,6 +90,10 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * Default values are empty strings unless specified. */ public function feedAction() { + if (Minz_Request::param('ajax')) { + $this->view->_useLayout(false); + } + $catDAO = new FreshRSS_CategoryDAO(); $this->view->categories = $catDAO->listCategories(false); diff --git a/app/views/configure/categorize.phtml b/app/views/configure/categorize.phtml index 8f77f9724..008dc8c98 100644 --- a/app/views/configure/categorize.phtml +++ b/app/views/configure/categorize.phtml @@ -73,7 +73,7 @@ $empty = $feed->nbEntries() == 0 ? ' empty' : ''; ?>
  • - + ✇ name(); ?>
  • + +
    +
    diff --git a/app/views/configure/feed.phtml b/app/views/configure/feed.phtml index e96a28739..f58ac65af 100644 --- a/app/views/configure/feed.phtml +++ b/app/views/configure/feed.phtml @@ -1,8 +1,12 @@ -partial ('aside_feed'); ?> +partial('aside_feed'); + } +?> flux) { ?>
    - +

    flux->name (); ?>

    flux->description (); ?> diff --git a/p/scripts/main.js b/p/scripts/main.js index f6d5d2907..7fed7a819 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1240,6 +1240,35 @@ function faviconNbUnread(n) { } } +function init_slider_observers() { + var slider = $('#slider'); + if (slider.length < 1) { + return; + } + + $('.open-slider').on('click', function() { + if (ajax_loading) { + return false; + } + + ajax_loading = true; + + var url_slide = $(this).attr('href'); + + $.ajax({ + type: 'GET', + url: url_slide, + data : { ajax: true } + }).done(function (data) { + slider.html(data); + slider.show(); + ajax_loading = false; + }); + + return false; + }) +} + function init_all() { if (!(window.$ && window.url_freshrss)) { if (window.console) { @@ -1275,6 +1304,7 @@ function init_all() { init_feed_observers(); init_password_observers(); init_stats_observers(); + init_slider_observers(); } if (window.console) { diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index a5a29ab23..397f943a6 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -645,6 +645,11 @@ br + br + br { display: none; } +/*=== Slider */ +#slider { + min-height: 50px; +} + /*=== DIVERS */ /*===========*/ .nav-login, -- cgit v1.2.3 From fdb63fbbe695b6a6bc32f0e93f2ff702ca42329c Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 1 Oct 2014 10:19:38 +0200 Subject: Simplify configureController Remove useless code for category configuration. See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/Controllers/configureController.php | 33 +-------------------------------- app/views/configure/categorize.phtml | 2 +- 2 files changed, 2 insertions(+), 33 deletions(-) diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index dd7a0a441..3fd1d5149 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -28,43 +28,12 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * 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. Related user queries - * are deleted too. - * If a category name is changed, it is updated. */ public function categorizeAction() { - $feedDAO = FreshRSS_Factory::createFeedDao(); $catDAO = new FreshRSS_CategoryDAO(); - $defaultCategory = $catDAO->getDefault(); - $defaultId = $defaultCategory->id(); - - if (Minz_Request::isPost()) { - $cats = Minz_Request::param('categories', array()); - $ids = Minz_Request::param('ids', array()); - - foreach ($cats as $key => $name) { - if (strlen($name) > 0) { - $cat = new FreshRSS_Category($name); - $values = array( - 'name' => $cat->name(), - ); - $catDAO->updateCategory($ids[$key], $values); - } - } - - invalidateHttpCache(); - - Minz_Request::good(_t('categories_updated'), - array('c' => 'configure', 'a' => 'categorize')); - } $this->view->categories = $catDAO->listCategories(false); - $this->view->defaultCategory = $catDAO->getDefault(); - $this->view->feeds = $feedDAO->listFeeds(); + $this->view->default_category = $catDAO->getDefault(); Minz_View::prependTitle(_t('categories_management') . ' · '); } diff --git a/app/views/configure/categorize.phtml b/app/views/configure/categorize.phtml index 008dc8c98..f5030ef2c 100644 --- a/app/views/configure/categorize.phtml +++ b/app/views/configure/categorize.phtml @@ -6,7 +6,7 @@

    - defaultCategory->name()); ?> + default_category->name()); ?>

    -- cgit v1.2.3 From 1eef7893068655f8d145a3e06061a9e6296ac1f3 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 1 Oct 2014 11:27:41 +0200 Subject: Reorganize subscription management code There is still a lot of work to do. Some links are broken. See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/Controllers/configureController.php | 116 ------------------ app/Controllers/subscriptionController.php | 130 ++++++++++++++++++++ app/Models/Themes.php | 1 + app/layout/aside_feed.phtml | 60 ---------- app/layout/aside_flux.phtml | 4 +- app/layout/aside_subscription.phtml | 17 +++ app/views/configure/categorize.phtml | 90 -------------- app/views/configure/feed.phtml | 186 ----------------------------- app/views/importExport/index.phtml | 2 +- app/views/subscription/feed.phtml | 186 +++++++++++++++++++++++++++++ app/views/subscription/index.phtml | 132 ++++++++++++++++++++ p/themes/icons/import.svg | 9 ++ 12 files changed, 478 insertions(+), 455 deletions(-) create mode 100644 app/Controllers/subscriptionController.php delete mode 100644 app/layout/aside_feed.phtml create mode 100644 app/layout/aside_subscription.phtml delete mode 100644 app/views/configure/categorize.phtml delete mode 100644 app/views/configure/feed.phtml create mode 100644 app/views/subscription/feed.phtml create mode 100644 app/views/subscription/index.phtml create mode 100644 p/themes/icons/import.svg diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 3fd1d5149..b7b88b3ba 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -8,9 +8,6 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * 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. - * - * @todo see if the category default configuration is needed here or if - * we can move it to the categorize action */ public function firstAction() { if (!$this->view->loginOk) { @@ -19,119 +16,6 @@ class FreshRSS_configure_Controller extends Minz_ActionController { array('error' => array(_t('access_denied'))) ); } - - $catDAO = new FreshRSS_CategoryDAO(); - $catDAO->checkDefault(); - } - - /** - * This action handles the category configuration page - * - * It displays the category configuration page. - */ - public function categorizeAction() { - $catDAO = new FreshRSS_CategoryDAO(); - - $this->view->categories = $catDAO->listCategories(false); - $this->view->default_category = $catDAO->getDefault(); - - Minz_View::prependTitle(_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. - */ - public function feedAction() { - if (Minz_Request::param('ajax')) { - $this->view->_useLayout(false); - } - - $catDAO = new FreshRSS_CategoryDAO(); - $this->view->categories = $catDAO->listCategories(false); - - $feedDAO = FreshRSS_Factory::createFeedDao(); - $this->view->feeds = $feedDAO->listFeeds(); - - $id = Minz_Request::param('id'); - if ($id == false && !empty($this->view->feeds)) { - $id = current($this->view->feeds)->id(); - } - - $this->view->flux = false; - if ($id != false) { - $this->view->flux = $this->view->feeds[$id]; - - if (!$this->view->flux) { - Minz_Error::error( - 404, - array('error' => array(_t('page_not_found'))) - ); - } else { - if (Minz_Request::isPost() && $this->view->flux) { - $user = Minz_Request::param('http_user', ''); - $pass = Minz_Request::param('http_pass', ''); - - $httpAuth = ''; - if ($user != '' || $pass != '') { - $httpAuth = $user . ':' . $pass; - } - - $cat = intval(Minz_Request::param('category', 0)); - - $values = array( - 'name' => Minz_Request::param('name', ''), - 'description' => sanitizeHTML(Minz_Request::param('description', '', true)), - 'website' => Minz_Request::param('website', ''), - 'url' => Minz_Request::param('url', ''), - 'category' => $cat, - 'pathEntries' => Minz_Request::param('path_entries', ''), - 'priority' => intval(Minz_Request::param('priority', 0)), - 'httpAuth' => $httpAuth, - 'keep_history' => intval(Minz_Request::param('keep_history', -2)), - 'ttl' => intval(Minz_Request::param('ttl', -2)), - ); - - if ($feedDAO->updateFeed($id, $values)) { - $this->view->flux->_category($cat); - $this->view->flux->faviconPrepare(); - $notif = array( - 'type' => 'good', - 'content' => _t('feed_updated') - ); - } else { - $notif = array( - 'type' => 'bad', - 'content' => _t('error_occurred_update') - ); - } - invalidateHttpCache(); - - Minz_Session::_param('notification', $notif); - Minz_Request::forward(array('c' => 'configure', 'a' => 'feed', 'params' => array('id' => $id)), true); - } - - Minz_View::prependTitle(_t('rss_feed_management') . ' — ' . $this->view->flux->name() . ' · '); - } - } else { - Minz_View::prependTitle(_t('rss_feed_management') . ' · '); - } } /** diff --git a/app/Controllers/subscriptionController.php b/app/Controllers/subscriptionController.php new file mode 100644 index 000000000..ab00f3e6a --- /dev/null +++ b/app/Controllers/subscriptionController.php @@ -0,0 +1,130 @@ +view->loginOk) { + Minz_Error::error( + 403, + array('error' => array(_t('access_denied'))) + ); + } + } + + /** + * This action handles the main subscription page + * + * It displays categories and associated feeds. + */ + public function indexAction() { + $catDAO = new FreshRSS_CategoryDAO(); + + $this->view->categories = $catDAO->listCategories(false); + $this->view->default_category = $catDAO->getDefault(); + + Minz_View::prependTitle(_t('subscription_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. + */ + public function feedAction() { + if (Minz_Request::param('ajax')) { + $this->view->_useLayout(false); + } + + $catDAO = new FreshRSS_CategoryDAO(); + $this->view->categories = $catDAO->listCategories(false); + + $feedDAO = FreshRSS_Factory::createFeedDao(); + $this->view->feeds = $feedDAO->listFeeds(); + + $id = Minz_Request::param('id'); + if ($id == false && !empty($this->view->feeds)) { + $id = current($this->view->feeds)->id(); + } + + $this->view->flux = false; + if ($id != false) { + $this->view->flux = $this->view->feeds[$id]; + + if (!$this->view->flux) { + Minz_Error::error( + 404, + array('error' => array(_t('page_not_found'))) + ); + } else { + if (Minz_Request::isPost() && $this->view->flux) { + $user = Minz_Request::param('http_user', ''); + $pass = Minz_Request::param('http_pass', ''); + + $httpAuth = ''; + if ($user != '' || $pass != '') { + $httpAuth = $user . ':' . $pass; + } + + $cat = intval(Minz_Request::param('category', 0)); + + $values = array( + 'name' => Minz_Request::param('name', ''), + 'description' => sanitizeHTML(Minz_Request::param('description', '', true)), + 'website' => Minz_Request::param('website', ''), + 'url' => Minz_Request::param('url', ''), + 'category' => $cat, + 'pathEntries' => Minz_Request::param('path_entries', ''), + 'priority' => intval(Minz_Request::param('priority', 0)), + 'httpAuth' => $httpAuth, + 'keep_history' => intval(Minz_Request::param('keep_history', -2)), + 'ttl' => intval(Minz_Request::param('ttl', -2)), + ); + + if ($feedDAO->updateFeed($id, $values)) { + $this->view->flux->_category($cat); + $this->view->flux->faviconPrepare(); + $notif = array( + 'type' => 'good', + 'content' => _t('feed_updated') + ); + } else { + $notif = array( + 'type' => 'bad', + 'content' => _t('error_occurred_update') + ); + } + invalidateHttpCache(); + + Minz_Session::_param('notification', $notif); + Minz_Request::forward(array('c' => 'subscription'), true); + } + + Minz_View::prependTitle(_t('rss_feed_management') . ' · ' . $this->view->flux->name() . ' · '); + } + } else { + Minz_View::prependTitle(_t('rss_feed_management') . ' · '); + } + } +} diff --git a/app/Models/Themes.php b/app/Models/Themes.php index 68fc17a2b..e3b260261 100644 --- a/app/Models/Themes.php +++ b/app/Models/Themes.php @@ -82,6 +82,7 @@ class FreshRSS_Themes extends Minz_Model { 'favorite' => '★', 'help' => 'ⓘ', 'icon' => '⊚', + 'import' => '⤓', 'key' => '⚿', 'link' => '↗', 'login' => '🔒', diff --git a/app/layout/aside_feed.phtml b/app/layout/aside_feed.phtml deleted file mode 100644 index c028c4918..000000000 --- a/app/layout/aside_feed.phtml +++ /dev/null @@ -1,60 +0,0 @@ - diff --git a/app/layout/aside_flux.phtml b/app/layout/aside_flux.phtml index aac3c0896..341697103 100644 --- a/app/layout/aside_flux.phtml +++ b/app/layout/aside_flux.phtml @@ -7,8 +7,8 @@
  • - - + +
  • diff --git a/app/layout/aside_subscription.phtml b/app/layout/aside_subscription.phtml new file mode 100644 index 000000000..9a95763c3 --- /dev/null +++ b/app/layout/aside_subscription.phtml @@ -0,0 +1,17 @@ + diff --git a/app/views/configure/categorize.phtml b/app/views/configure/categorize.phtml deleted file mode 100644 index f5030ef2c..000000000 --- a/app/views/configure/categorize.phtml +++ /dev/null @@ -1,90 +0,0 @@ -partial('aside_feed'); ?> - -
    - - -

    - -

    - default_category->name()); ?> -

    - -
    -
    - -
      -
      -
    • -
    • -
      -
    -
    - - - - categories as $cat) { - $feeds = $cat->feeds(); - ?> -
    -
    -
    - - - -
    -
    - -
      - - inError() ? ' error' : ''; - $empty = $feed->nbEntries() == 0 ? ' empty' : ''; - ?> -
    • - - ✇ name(); ?> -
    • - -
    • - -
    -
    - -
    - -
    -
    diff --git a/app/views/configure/feed.phtml b/app/views/configure/feed.phtml deleted file mode 100644 index f58ac65af..000000000 --- a/app/views/configure/feed.phtml +++ /dev/null @@ -1,186 +0,0 @@ -partial('aside_feed'); - } -?> - -flux) { ?> -
    - - -

    flux->name (); ?>

    - flux->description (); ?> - - flux->nbEntries (); ?> - - flux->inError ()) { ?> -

    - -

    - - -
    - -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    -
    - - -
    -
    -
    -
    - -
    -
    - - -
    - - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    -
    - - - -
    -
    -
    -
    - - -
    -
    - - - -
    -
    -
    - - - - -
    -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    -
    - - -
    -
    - - - flux->httpAuth (false); ?> -
    - -
    - - -
    - - -
    - -
    -
    - -
    -
    - - -
    -
    - - -
    - -
    - - -
    -
    - -
    -
    - - -
    -
    -
    -
    - - -
    - diff --git a/app/views/importExport/index.phtml b/app/views/importExport/index.phtml index 35371faca..36c0eab4e 100644 --- a/app/views/importExport/index.phtml +++ b/app/views/importExport/index.phtml @@ -1,4 +1,4 @@ -partial('aside_feed'); ?> +partial('aside_subscription'); ?>
    diff --git a/app/views/subscription/feed.phtml b/app/views/subscription/feed.phtml new file mode 100644 index 000000000..e047741a1 --- /dev/null +++ b/app/views/subscription/feed.phtml @@ -0,0 +1,186 @@ +partial('aside_subscription'); + } +?> + +flux) { ?> +
    + + +

    flux->name (); ?>

    + flux->description (); ?> + + flux->nbEntries (); ?> + + flux->inError ()) { ?> +

    + +

    + + +
    + +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    + + +
    +
    +
    +
    + +
    +
    + + +
    + + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    + + + +
    +
    +
    +
    + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    + + +
    +
    + + + flux->httpAuth (false); ?> +
    + +
    + + +
    + + +
    + +
    +
    + +
    +
    + + +
    +
    + + +
    + +
    + + +
    +
    + +
    +
    + + +
    +
    +
    +
    + + +
    + diff --git a/app/views/subscription/index.phtml b/app/views/subscription/index.phtml new file mode 100644 index 000000000..444dc9d9b --- /dev/null +++ b/app/views/subscription/index.phtml @@ -0,0 +1,132 @@ +partial('aside_subscription'); ?> + +
    + + +

    + +
    +
    + + + +
    +
    + +

    + default_category->name()); ?> +

    + +
    +
    + +
      +
      +
    • +
    • +
      +
    +
    + + + + categories as $cat) { + $feeds = $cat->feeds(); + ?> +
    +
    +
    + + + +
    +
    + +
      + + inError() ? ' error' : ''; + $empty = $feed->nbEntries() == 0 ? ' empty' : ''; + ?> +
    • + + ✇ name(); ?> +
    • + +
    • + +
    +
    + +
    + +
    +
    diff --git a/p/themes/icons/import.svg b/p/themes/icons/import.svg new file mode 100644 index 000000000..a7f20c909 --- /dev/null +++ b/p/themes/icons/import.svg @@ -0,0 +1,9 @@ + + + + + + + + + -- cgit v1.2.3 From 89c407d7d7f739e42d9e72e40304bbbef00c9b10 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 1 Oct 2014 11:58:08 +0200 Subject: Add selected feed on main subscription page - When an id is given, corresponding feed is displayed - Refactor code - Improve coding style See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/Controllers/subscriptionController.php | 116 ++++++++---------- app/views/helpers/feed/update.phtml | 175 ++++++++++++++++++++++++++ app/views/subscription/feed.phtml | 191 ++--------------------------- app/views/subscription/index.phtml | 5 + 4 files changed, 242 insertions(+), 245 deletions(-) create mode 100644 app/views/helpers/feed/update.phtml diff --git a/app/Controllers/subscriptionController.php b/app/Controllers/subscriptionController.php index ab00f3e6a..83f803edb 100644 --- a/app/Controllers/subscriptionController.php +++ b/app/Controllers/subscriptionController.php @@ -16,6 +16,11 @@ class FreshRSS_subscription_Controller extends Minz_ActionController { array('error' => array(_t('access_denied'))) ); } + + $catDAO = new FreshRSS_CategoryDAO(); + + $this->view->categories = $catDAO->listCategories(false); + $this->view->default_category = $catDAO->getDefault(); } /** @@ -24,12 +29,13 @@ class FreshRSS_subscription_Controller extends Minz_ActionController { * It displays categories and associated feeds. */ public function indexAction() { - $catDAO = new FreshRSS_CategoryDAO(); - - $this->view->categories = $catDAO->listCategories(false); - $this->view->default_category = $catDAO->getDefault(); - Minz_View::prependTitle(_t('subscription_management') . ' · '); + + $id = Minz_Request::param('id'); + if ($id !== false) { + $feedDAO = FreshRSS_Factory::createFeedDao(); + $this->view->feed = $feedDAO->searchById($id); + } } /** @@ -57,74 +63,56 @@ class FreshRSS_subscription_Controller extends Minz_ActionController { $this->view->_useLayout(false); } - $catDAO = new FreshRSS_CategoryDAO(); - $this->view->categories = $catDAO->listCategories(false); - $feedDAO = FreshRSS_Factory::createFeedDao(); $this->view->feeds = $feedDAO->listFeeds(); $id = Minz_Request::param('id'); - if ($id == false && !empty($this->view->feeds)) { - $id = current($this->view->feeds)->id(); + if ($id === false || !isset($this->view->feeds[$id])) { + Minz_Error::error( + 404, + array('error' => array(_t('page_not_found'))) + ); + return; } - $this->view->flux = false; - if ($id != false) { - $this->view->flux = $this->view->feeds[$id]; + $this->view->feed = $this->view->feeds[$id]; + + Minz_View::prependTitle(_t('rss_feed_management') . ' · ' . $this->view->feed->name() . ' · '); + + if (Minz_Request::isPost()) { + $user = Minz_Request::param('http_user', ''); + $pass = Minz_Request::param('http_pass', ''); + + $httpAuth = ''; + if ($user != '' || $pass != '') { + $httpAuth = $user . ':' . $pass; + } + + $cat = intval(Minz_Request::param('category', 0)); + + $values = array( + 'name' => Minz_Request::param('name', ''), + 'description' => sanitizeHTML(Minz_Request::param('description', '', true)), + 'website' => Minz_Request::param('website', ''), + 'url' => Minz_Request::param('url', ''), + 'category' => $cat, + 'pathEntries' => Minz_Request::param('path_entries', ''), + 'priority' => intval(Minz_Request::param('priority', 0)), + 'httpAuth' => $httpAuth, + 'keep_history' => intval(Minz_Request::param('keep_history', -2)), + 'ttl' => intval(Minz_Request::param('ttl', -2)), + ); + + invalidateHttpCache(); + + if ($feedDAO->updateFeed($id, $values)) { + $this->view->feed->_category($cat); + $this->view->feed->faviconPrepare(); - if (!$this->view->flux) { - Minz_Error::error( - 404, - array('error' => array(_t('page_not_found'))) - ); + Minz_Request::good(_t('feed_updated'), array('c' => 'subscription', 'params' => array('id' => $id))); } else { - if (Minz_Request::isPost() && $this->view->flux) { - $user = Minz_Request::param('http_user', ''); - $pass = Minz_Request::param('http_pass', ''); - - $httpAuth = ''; - if ($user != '' || $pass != '') { - $httpAuth = $user . ':' . $pass; - } - - $cat = intval(Minz_Request::param('category', 0)); - - $values = array( - 'name' => Minz_Request::param('name', ''), - 'description' => sanitizeHTML(Minz_Request::param('description', '', true)), - 'website' => Minz_Request::param('website', ''), - 'url' => Minz_Request::param('url', ''), - 'category' => $cat, - 'pathEntries' => Minz_Request::param('path_entries', ''), - 'priority' => intval(Minz_Request::param('priority', 0)), - 'httpAuth' => $httpAuth, - 'keep_history' => intval(Minz_Request::param('keep_history', -2)), - 'ttl' => intval(Minz_Request::param('ttl', -2)), - ); - - if ($feedDAO->updateFeed($id, $values)) { - $this->view->flux->_category($cat); - $this->view->flux->faviconPrepare(); - $notif = array( - 'type' => 'good', - 'content' => _t('feed_updated') - ); - } else { - $notif = array( - 'type' => 'bad', - 'content' => _t('error_occurred_update') - ); - } - invalidateHttpCache(); - - Minz_Session::_param('notification', $notif); - Minz_Request::forward(array('c' => 'subscription'), true); - } - - Minz_View::prependTitle(_t('rss_feed_management') . ' · ' . $this->view->flux->name() . ' · '); + Minz_Request::bad(_t('error_occurred_update'), array('c' => 'subscription')); } - } else { - Minz_View::prependTitle(_t('rss_feed_management') . ' · '); } } } diff --git a/app/views/helpers/feed/update.phtml b/app/views/helpers/feed/update.phtml new file mode 100644 index 000000000..4a6425c45 --- /dev/null +++ b/app/views/helpers/feed/update.phtml @@ -0,0 +1,175 @@ +
    + + +

    feed->name (); ?>

    + feed->description (); ?> + + feed->nbEntries (); ?> + + feed->inError ()) { ?> +

    + +

    + + +
    + +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    + + +
    +
    +
    +
    + +
    +
    + + +
    + + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    + + + +
    +
    +
    +
    + + +
    +
    + + + +
    +
    +
    + + + + +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    +
    + + +
    +
    + + + feed->httpAuth (false); ?> +
    + +
    + + +
    + + +
    + +
    +
    + +
    +
    + + +
    +
    + + +
    + +
    + + +
    +
    + +
    +
    + + +
    +
    +
    +
    diff --git a/app/views/subscription/feed.phtml b/app/views/subscription/feed.phtml index e047741a1..48a401c4a 100644 --- a/app/views/subscription/feed.phtml +++ b/app/views/subscription/feed.phtml @@ -1,186 +1,15 @@ partial('aside_subscription'); - } -?> - -flux) { ?> -
    - - -

    flux->name (); ?>

    - flux->description (); ?> - - flux->nbEntries (); ?> - - flux->inError ()) { ?> -

    - -

    - - -
    - -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    -
    - - -
    -
    -
    -
    - -
    -
    - - -
    - - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    -
    - - - -
    -
    -
    -
    - - -
    -
    - +if (!Minz_Request::param('ajax')) { + $this->partial('aside_subscription'); +} -
    -
    -
    - - - - -
    -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    -
    - - -
    -
    - - - flux->httpAuth (false); ?> -
    - -
    - - -
    - - -
    - -
    -
    - -
    -
    - - -
    -
    - - -
    - -
    - - -
    -
    - -
    -
    - - -
    -
    -
    +if ($this->feed) { + $this->renderHelper('feed/update'); +} else { +?> +
    + +
    - - -
    diff --git a/app/views/subscription/index.phtml b/app/views/subscription/index.phtml index 444dc9d9b..bce9eacf1 100644 --- a/app/views/subscription/index.phtml +++ b/app/views/subscription/index.phtml @@ -129,4 +129,9 @@
    +feed) && $this->feed) { + $this->renderHelper('feed/update'); + } +?>
    -- cgit v1.2.3 From a7bf7ced369a046b487ab1cd8b3819acc5ebdafe Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 1 Oct 2014 12:18:32 +0200 Subject: Fix links for feed management See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/Controllers/categoryController.php | 8 ++++---- app/Controllers/feedController.php | 16 +++++++++------- app/layout/aside_flux.phtml | 2 +- app/views/helpers/view/global_view.phtml | 2 +- app/views/helpers/view/normal_view.phtml | 2 +- app/views/helpers/view/reader_view.phtml | 2 +- app/views/stats/idle.phtml | 2 +- app/views/stats/repartition.phtml | 2 +- 8 files changed, 19 insertions(+), 17 deletions(-) diff --git a/app/Controllers/categoryController.php b/app/Controllers/categoryController.php index 65fe631cc..2c99751a4 100644 --- a/app/Controllers/categoryController.php +++ b/app/Controllers/categoryController.php @@ -31,7 +31,7 @@ class FreshRSS_category_Controller extends Minz_ActionController { */ public function createAction() { $catDAO = new FreshRSS_CategoryDAO(); - $url_redirect = array('c' => 'configure', 'a' => 'categorize'); + $url_redirect = array('c' => 'subscription', 'a' => 'index'); if (Minz_Request::isPost()) { invalidateHttpCache(); @@ -71,7 +71,7 @@ class FreshRSS_category_Controller extends Minz_ActionController { */ public function updateAction() { $catDAO = new FreshRSS_CategoryDAO(); - $url_redirect = array('c' => 'configure', 'a' => 'categorize'); + $url_redirect = array('c' => 'subscription', 'a' => 'index'); if (Minz_Request::isPost()) { invalidateHttpCache(); @@ -113,7 +113,7 @@ class FreshRSS_category_Controller extends Minz_ActionController { $feedDAO = FreshRSS_Factory::createFeedDao(); $catDAO = new FreshRSS_CategoryDAO(); $default_category = $catDAO->getDefault(); - $url_redirect = array('c' => 'configure', 'a' => 'categorize'); + $url_redirect = array('c' => 'subscription', 'a' => 'index'); if (Minz_Request::isPost()) { invalidateHttpCache(); @@ -150,7 +150,7 @@ class FreshRSS_category_Controller extends Minz_ActionController { */ public function emptyAction() { $feedDAO = FreshRSS_Factory::createFeedDao(); - $url_redirect = array('c' => 'configure', 'a' => 'categorize'); + $url_redirect = array('c' => 'subscription', 'a' => 'index'); if (Minz_Request::isPost()) { invalidateHttpCache(); diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 7ef427ac2..e4859b110 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -26,8 +26,8 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if ($url === false) { Minz_Request::forward(array( - 'c' => 'configure', - 'a' => 'feed' + 'c' => 'subscription', + 'a' => 'index' ), true); } @@ -166,7 +166,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feedDAO->rollBack (); } - Minz_Request::forward (array ('c' => 'configure', 'a' => 'feed', 'params' => $params), true); + Minz_Request::forward (array ('c' => 'subscription', 'a' => 'index', 'params' => $params), true); } else { // GET request so we must ask confirmation to user @@ -193,8 +193,8 @@ class FreshRSS_feed_Controller extends Minz_ActionController { Minz_Session::_param('notification', $notif); Minz_Request::forward(array( - 'c' => 'configure', - 'a' => 'feed', + 'c' => 'subscription', + 'a' => 'index', 'params' => array( 'id' => $feed->id() ) @@ -214,7 +214,9 @@ class FreshRSS_feed_Controller extends Minz_ActionController { ); Minz_Session::_param ('notification', $notif); invalidateHttpCache(); - Minz_Request::forward (array ('c' => 'configure', 'a' => 'feed', 'params' => array('id' => $id)), true); + Minz_Request::forward (array ('c' => 'subscription', + 'a' => 'index', + 'params' => array('id' => $id)), true); } } @@ -405,7 +407,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if ($redirect_url) { Minz_Request::forward($redirect_url); } else { - Minz_Request::forward(array('c' => 'configure', 'a' => 'feed'), true); + Minz_Request::forward(array('c' => 'subscription', 'a' => 'index'), true); } } } diff --git a/app/layout/aside_flux.phtml b/app/layout/aside_flux.phtml index 341697103..a8ae2f424 100644 --- a/app/layout/aside_flux.phtml +++ b/app/layout/aside_flux.phtml @@ -89,7 +89,7 @@
  • loginOk) { ?>
  • -
  • +
  • conf->reading_confirm ? 'confirm' : ''; ?> diff --git a/app/views/helpers/view/global_view.phtml b/app/views/helpers/view/global_view.phtml index 72bcf4c73..5e4cad01a 100644 --- a/app/views/helpers/view/global_view.phtml +++ b/app/views/helpers/view/global_view.phtml @@ -48,6 +48,6 @@

    -

    +

    diff --git a/app/views/helpers/view/normal_view.phtml b/app/views/helpers/view/normal_view.phtml index 6d9789f8d..e469edf58 100644 --- a/app/views/helpers/view/normal_view.phtml +++ b/app/views/helpers/view/normal_view.phtml @@ -186,6 +186,6 @@ if (!empty($this->entries)) {

    -

    +

    diff --git a/app/views/helpers/view/reader_view.phtml b/app/views/helpers/view/reader_view.phtml index c80dca519..413094239 100644 --- a/app/views/helpers/view/reader_view.phtml +++ b/app/views/helpers/view/reader_view.phtml @@ -39,6 +39,6 @@ if (!empty($this->entries)) {

    -

    +

    diff --git a/app/views/stats/idle.phtml b/app/views/stats/idle.phtml index 6f3d4a117..75cba1081 100644 --- a/app/views/stats/idle.phtml +++ b/app/views/stats/idle.phtml @@ -25,7 +25,7 @@
  • - +
  • diff --git a/app/views/stats/repartition.phtml b/app/views/stats/repartition.phtml index b425c1458..dac47e189 100644 --- a/app/views/stats/repartition.phtml +++ b/app/views/stats/repartition.phtml @@ -24,7 +24,7 @@ feed) {?> - + -- cgit v1.2.3 From f400621f44c2aac0b1bb4204e95e4c35a8a35f8f Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 1 Oct 2014 13:37:10 +0200 Subject: Fix problem when deleting default category This is not allowed! See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/Controllers/categoryController.php | 4 ++++ app/Controllers/subscriptionController.php | 1 + app/views/subscription/index.phtml | 12 +++++++++--- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/app/Controllers/categoryController.php b/app/Controllers/categoryController.php index 2c99751a4..c79f37fa4 100644 --- a/app/Controllers/categoryController.php +++ b/app/Controllers/categoryController.php @@ -123,6 +123,10 @@ class FreshRSS_category_Controller extends Minz_ActionController { Minz_Request::bad(_t('category_no_id'), $url_redirect); } + if ($id === $default_category->id()) { + Minz_Request::bad(_t('category_not_delete_default'), $url_redirect); + } + if ($feedDAO->changeCategory($id, $default_category->id()) === false) { Minz_Request::bad(_t('error_occurred'), $url_redirect); } diff --git a/app/Controllers/subscriptionController.php b/app/Controllers/subscriptionController.php index 83f803edb..aabae7b8f 100644 --- a/app/Controllers/subscriptionController.php +++ b/app/Controllers/subscriptionController.php @@ -19,6 +19,7 @@ class FreshRSS_subscription_Controller extends Minz_ActionController { $catDAO = new FreshRSS_CategoryDAO(); + $catDAO->checkDefault(); $this->view->categories = $catDAO->listCategories(false); $this->view->default_category = $catDAO->getDefault(); } diff --git a/app/views/subscription/index.phtml b/app/views/subscription/index.phtml index bce9eacf1..2d55890f7 100644 --- a/app/views/subscription/index.phtml +++ b/app/views/subscription/index.phtml @@ -82,9 +82,14 @@
  • -
  • + id() === $this->default_category->id()); - + if (!$no_feed || !$is_default) { + ?> +
  • +
  • - +
  • +
    -- cgit v1.2.3 From 405f23050b18e8388edb6f8be90aa59c17ada421 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 1 Oct 2014 13:55:30 +0200 Subject: Design of the slider See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/views/subscription/index.phtml | 5 +++-- p/scripts/main.js | 14 ++++++++++---- p/themes/base-theme/template.css | 24 +++++++++++++++++++++++- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/app/views/subscription/index.phtml b/app/views/subscription/index.phtml index 2d55890f7..10578bdd3 100644 --- a/app/views/subscription/index.phtml +++ b/app/views/subscription/index.phtml @@ -134,9 +134,10 @@
    -
    + +
    feed) ? ' class="active"' : ''; ?>> feed) && $this->feed) { + if (isset($this->feed)) { $this->renderHelper('feed/update'); } ?> diff --git a/p/scripts/main.js b/p/scripts/main.js index 7fed7a819..925a93650 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1241,7 +1241,8 @@ function faviconNbUnread(n) { } function init_slider_observers() { - var slider = $('#slider'); + var slider = $('#slider'), + closer = $('#close-slider'); if (slider.length < 1) { return; } @@ -1252,7 +1253,6 @@ function init_slider_observers() { } ajax_loading = true; - var url_slide = $(this).attr('href'); $.ajax({ @@ -1261,12 +1261,18 @@ function init_slider_observers() { data : { ajax: true } }).done(function (data) { slider.html(data); - slider.show(); + closer.addClass('active'); + slider.addClass('active'); ajax_loading = false; }); return false; - }) + }); + + closer.on('click', function() { + closer.removeClass('active'); + slider.removeClass('active'); + }); } function init_all() { diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index 397f943a6..e6c832ee4 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -647,7 +647,29 @@ br + br + br { /*=== Slider */ #slider { - min-height: 50px; + position: fixed; + top: 0; bottom: 0; + left: 100%; right: 0; + overflow: auto; + background: #fff; + border-left: 1px solid #aaa; + transition: left 200ms linear; + -moz-transition: left 200ms linear; + -webkit-transition: left 200ms linear; + -o-transition: left 200ms linear; + -ms-transition: left 200ms linear; +} +#slider.active { + left: 40%; +} +#close-slider { + position: fixed; + top: 0; bottom: 0; + left: 100%; right: 0; + cursor: pointer; +} +#close-slider.active { + left: 0; } /*=== DIVERS */ -- cgit v1.2.3 From fe655e0d9d2fb1173099d77c478bbb2f7ac8b1e1 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 1 Oct 2014 13:58:09 +0200 Subject: Fix close slider when a feed is selected See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/views/subscription/index.phtml | 5 +++-- p/scripts/main.js | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/views/subscription/index.phtml b/app/views/subscription/index.phtml index 10578bdd3..577ddd972 100644 --- a/app/views/subscription/index.phtml +++ b/app/views/subscription/index.phtml @@ -134,8 +134,9 @@
    - -
    feed) ? ' class="active"' : ''; ?>> +feed) ? ' class="active"' : ''; ?> +> +
    > feed)) { $this->renderHelper('feed/update'); diff --git a/p/scripts/main.js b/p/scripts/main.js index 925a93650..005dc961b 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1272,6 +1272,7 @@ function init_slider_observers() { closer.on('click', function() { closer.removeClass('active'); slider.removeClass('active'); + return false; }); } -- cgit v1.2.3 From bbedca510bb0b88850476bf2e2aa6af8c02ac741 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 2 Oct 2014 09:21:08 +0200 Subject: Better import icon See https://github.com/marienfressinaud/FreshRSS/issues/646 --- p/themes/icons/import.svg | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/p/themes/icons/import.svg b/p/themes/icons/import.svg index a7f20c909..18a54ab59 100644 --- a/p/themes/icons/import.svg +++ b/p/themes/icons/import.svg @@ -1,9 +1 @@ - - - - - - - - - + -- cgit v1.2.3 From 9b2ad32e98e4720d5ee422fccd3069f086ee8563 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 2 Oct 2014 10:05:26 +0200 Subject: Fix a bug in main.js In global view, there is no ".category.all>a" element so we tried to apply str2int on an undefined value. In consequence, we were not able to mark several articles as read This patch need to apply on 0.8.1 and 0.9.1 See https://github.com/marienfressinaud/FreshRSS/issues/649 --- p/scripts/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p/scripts/main.js b/p/scripts/main.js index 7cd53c745..c9e8dd299 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -33,7 +33,7 @@ function needsScroll($elem) { } function str2int(str) { - if (str == '') { + if (str == '' || str === undefined) { return 0; } return parseInt(str.replace(/\D/g, ''), 10) || 0; -- cgit v1.2.3 From db4da3babc0864099c5ab48e3583d0546a2759d8 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 2 Oct 2014 11:39:51 +0200 Subject: First draft for drag and drop We can change feed category by drag and drop! Need improvements... See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/Controllers/feedController.php | 15 ++++++++ app/Controllers/subscriptionController.php | 2 ++ app/views/subscription/index.phtml | 4 +-- p/scripts/category.js | 55 ++++++++++++++++++++++++++++++ p/scripts/main.js | 2 +- p/themes/Origine/origine.css | 9 +++++ 6 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 p/scripts/category.js diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index e4859b110..315665ef3 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -378,6 +378,21 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } } + public function moveAction() { + if (Minz_Request::isPost()) { + $feed_id = Minz_Request::param('f_id'); + $cat_id = Minz_Request::param('c_id'); + + $feedDAO = FreshRSS_Factory::createFeedDao(); + + $values = array( + 'category' => $cat_id, + ); + + $feedDAO->updateFeed($feed_id, $values); + } + } + public function deleteAction() { if (Minz_Request::isPost()) { $id = Minz_Request::param('id'); diff --git a/app/Controllers/subscriptionController.php b/app/Controllers/subscriptionController.php index aabae7b8f..7cc8179a0 100644 --- a/app/Controllers/subscriptionController.php +++ b/app/Controllers/subscriptionController.php @@ -30,6 +30,8 @@ class FreshRSS_subscription_Controller extends Minz_ActionController { * It displays categories and associated feeds. */ public function indexAction() { + Minz_View::appendScript(Minz_Url::display('/scripts/category.js?' . + @filemtime(PUBLIC_PATH . '/scripts/category.js'))); Minz_View::prependTitle(_t('subscription_management') . ' · '); $id = Minz_Request::param('id'); diff --git a/app/views/subscription/index.phtml b/app/views/subscription/index.phtml index 577ddd972..3a79a34e6 100644 --- a/app/views/subscription/index.phtml +++ b/app/views/subscription/index.phtml @@ -113,14 +113,14 @@
    -
      +
        inError() ? ' error' : ''; $empty = $feed->nbEntries() == 0 ? ' empty' : ''; ?> -
      • +
      • ✇ name(); ?>
      • diff --git a/p/scripts/category.js b/p/scripts/category.js new file mode 100644 index 000000000..fe80c3b22 --- /dev/null +++ b/p/scripts/category.js @@ -0,0 +1,55 @@ +"use strict"; + + +function init_draggable() { + var feeds_draggable = '.box-content > .feed', + box_dropzone = '.box-content'; + + $('.box').on('dragstart', feeds_draggable, function(e) { + e.originalEvent.dataTransfer.effectAllowed = 'move'; + e.originalEvent.dataTransfer.setData('html', e.target.outerHTML); + e.originalEvent.dataTransfer.setData('feed-id', e.target.getAttribute('data-feed-id')); + }); + $('.box').on('dragend', feeds_draggable, function(e) { + var parent = e.target.parentNode; + parent.removeChild(e.target); + }); + + $('.box').on('dragenter', box_dropzone, function(e) { + $(e.target).addClass('drag-hover'); + }); + $('.box').on('dragleave', box_dropzone, function(e) { + $(e.target).removeClass('drag-hover'); + }); + $('.box').on('dragover', box_dropzone, function(e) { + e.originalEvent.dataTransfer.dropEffect = "move"; + + return false; + }); + $('.box').on('drop', box_dropzone, function(e) { + var feed_id = e.originalEvent.dataTransfer.getData('feed-id'), + cat_id = e.target.parentNode.getAttribute('data-cat-id'); + + $.ajax({ + type: 'POST', + url: './?c=feed&a=move', + data : { + f_id: feed_id, + c_id: cat_id + } + }); + + $(e.target).after(e.originalEvent.dataTransfer.getData('html')); + $(e.target).removeClass('drag-hover'); + return false; + }); +} + + +if (document.readyState && document.readyState !== 'loading') { + init_draggable(); +} else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', function () { + init_draggable(); + }, false); +} diff --git a/p/scripts/main.js b/p/scripts/main.js index 005dc961b..e8055e00f 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1247,7 +1247,7 @@ function init_slider_observers() { return; } - $('.open-slider').on('click', function() { + $('.post').on('click', '.open-slider', function() { if (ajax_loading) { return false; } diff --git a/p/themes/Origine/origine.css b/p/themes/Origine/origine.css index e3ae85075..cf6c9a2ef 100644 --- a/p/themes/Origine/origine.css +++ b/p/themes/Origine/origine.css @@ -497,6 +497,15 @@ a.btn { visibility: visible; } +/*=== Draggable */ +.drag-hover { + background: #dfd; + transition: all linear 0.2s; +} +[draggable=true] { + cursor: grab; +} + /*=== STRUCTURE */ /*===============*/ /*=== Header */ -- cgit v1.2.3 From 50f07febaed5e839d4e7d56a664c8a208bc2aaf5 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 2 Oct 2014 12:13:16 +0200 Subject: Add dataTransfer property to event for JQuery See https://github.com/marienfressinaud/FreshRSS/issues/646 --- p/scripts/category.js | 15 +++++++++------ p/themes/Origine/origine.css | 1 + 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/p/scripts/category.js b/p/scripts/category.js index fe80c3b22..4378aa9cd 100644 --- a/p/scripts/category.js +++ b/p/scripts/category.js @@ -2,17 +2,20 @@ function init_draggable() { + $.event.props.push('dataTransfer'); + var feeds_draggable = '.box-content > .feed', box_dropzone = '.box-content'; $('.box').on('dragstart', feeds_draggable, function(e) { - e.originalEvent.dataTransfer.effectAllowed = 'move'; - e.originalEvent.dataTransfer.setData('html', e.target.outerHTML); - e.originalEvent.dataTransfer.setData('feed-id', e.target.getAttribute('data-feed-id')); + e.dataTransfer.effectAllowed = 'move'; + e.dataTransfer.setData('html', e.target.outerHTML); + e.dataTransfer.setData('feed-id', e.target.getAttribute('data-feed-id')); }); $('.box').on('dragend', feeds_draggable, function(e) { var parent = e.target.parentNode; parent.removeChild(e.target); + }); $('.box').on('dragenter', box_dropzone, function(e) { @@ -22,12 +25,12 @@ function init_draggable() { $(e.target).removeClass('drag-hover'); }); $('.box').on('dragover', box_dropzone, function(e) { - e.originalEvent.dataTransfer.dropEffect = "move"; + e.dataTransfer.dropEffect = "move"; return false; }); $('.box').on('drop', box_dropzone, function(e) { - var feed_id = e.originalEvent.dataTransfer.getData('feed-id'), + var feed_id = e.dataTransfer.getData('feed-id'), cat_id = e.target.parentNode.getAttribute('data-cat-id'); $.ajax({ @@ -39,7 +42,7 @@ function init_draggable() { } }); - $(e.target).after(e.originalEvent.dataTransfer.getData('html')); + $(e.target).after(e.dataTransfer.getData('html')); $(e.target).removeClass('drag-hover'); return false; }); diff --git a/p/themes/Origine/origine.css b/p/themes/Origine/origine.css index cf6c9a2ef..c79f6cc4c 100644 --- a/p/themes/Origine/origine.css +++ b/p/themes/Origine/origine.css @@ -481,6 +481,7 @@ a.btn { border-radius: 5px 5px 0 0; } .box .box-content { + min-height: 2.5em; max-height: 260px; } -- cgit v1.2.3 From 6effa82cef4ea8fd98178e72b270de6ea4f9f80f Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 2 Oct 2014 15:02:42 +0200 Subject: Improve drag and drop - Refactoring - Better design - Item doesn't disappear if action is not completed See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/views/subscription/index.phtml | 11 ++++--- p/scripts/category.js | 63 +++++++++++++++++++++++++++++--------- p/themes/Origine/origine.css | 9 ------ p/themes/base-theme/template.css | 12 ++++++++ 4 files changed, 67 insertions(+), 28 deletions(-) diff --git a/app/views/subscription/index.phtml b/app/views/subscription/index.phtml index 3a79a34e6..2c56f79ed 100644 --- a/app/views/subscription/index.phtml +++ b/app/views/subscription/index.phtml @@ -1,6 +1,6 @@ partial('aside_subscription'); ?> -
        +

        @@ -113,21 +113,24 @@
        -
          +
            inError() ? ' error' : ''; $empty = $feed->nbEntries() == 0 ? ' empty' : ''; ?> -
          • +
          • ✇ name(); ?>
          • -
          • +
        diff --git a/p/scripts/category.js b/p/scripts/category.js index 4378aa9cd..37ad36b17 100644 --- a/p/scripts/category.js +++ b/p/scripts/category.js @@ -1,38 +1,66 @@ "use strict"; +var loading = false, + dnd_successful = false; + +function dragend_process(t) { + if (loading) { + window.setTimeout(function() { + dragend_process(t); + }, 50); + } + + if (!dnd_successful) { + t.style.opacity = 1.0; + } else { + t.parentNode.removeChild(t); + } +} + function init_draggable() { + if (!(window.$ && window.url_freshrss)) { + if (window.console) { + console.log('FreshRSS waiting for JS…'); + } + window.setTimeout(init_draggable, 50); + return; + } + $.event.props.push('dataTransfer'); - var feeds_draggable = '.box-content > .feed', - box_dropzone = '.box-content'; + var draggable = '[draggable="true"]', + dropzone = '[dropzone="move"]'; - $('.box').on('dragstart', feeds_draggable, function(e) { + $('.drop-section').on('dragstart', draggable, function(e) { e.dataTransfer.effectAllowed = 'move'; - e.dataTransfer.setData('html', e.target.outerHTML); - e.dataTransfer.setData('feed-id', e.target.getAttribute('data-feed-id')); + e.dataTransfer.setData('text/html', e.target.outerHTML); + e.dataTransfer.setData('text', e.target.getAttribute('data-feed-id')); + e.target.style.opacity = 0.3; + + dnd_successful = false; }); - $('.box').on('dragend', feeds_draggable, function(e) { - var parent = e.target.parentNode; - parent.removeChild(e.target); - + $('.drop-section').on('dragend', draggable, function(e) { + dragend_process(e.target); }); - $('.box').on('dragenter', box_dropzone, function(e) { + $('.drop-section').on('dragenter', dropzone, function(e) { $(e.target).addClass('drag-hover'); }); - $('.box').on('dragleave', box_dropzone, function(e) { + $('.drop-section').on('dragleave', dropzone, function(e) { $(e.target).removeClass('drag-hover'); }); - $('.box').on('dragover', box_dropzone, function(e) { + $('.drop-section').on('dragover', dropzone, function(e) { e.dataTransfer.dropEffect = "move"; return false; }); - $('.box').on('drop', box_dropzone, function(e) { - var feed_id = e.dataTransfer.getData('feed-id'), + $('.drop-section').on('drop', dropzone, function(e) { + var feed_id = e.dataTransfer.getData('text'), cat_id = e.target.parentNode.getAttribute('data-cat-id'); + loading = true; + $.ajax({ type: 'POST', url: './?c=feed&a=move', @@ -40,10 +68,15 @@ function init_draggable() { f_id: feed_id, c_id: cat_id } + }).success(function() { + $(e.target).after(e.dataTransfer.getData('text/html')); + loading = false; + }).complete(function() { + dnd_successful = true; }); - $(e.target).after(e.dataTransfer.getData('html')); $(e.target).removeClass('drag-hover'); + return false; }); } diff --git a/p/themes/Origine/origine.css b/p/themes/Origine/origine.css index c79f6cc4c..b25deab0c 100644 --- a/p/themes/Origine/origine.css +++ b/p/themes/Origine/origine.css @@ -498,15 +498,6 @@ a.btn { visibility: visible; } -/*=== Draggable */ -.drag-hover { - background: #dfd; - transition: all linear 0.2s; -} -[draggable=true] { - cursor: grab; -} - /*=== STRUCTURE */ /*===============*/ /*=== Header */ diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index e6c832ee4..06874c9fe 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -304,6 +304,10 @@ a.btn { .box .box-content .item { display: block; } +.box .box-content .item.disabled { + text-align: center; + font-style: italic; +} .box .box-content-centered { padding: 30px 5px; @@ -313,6 +317,14 @@ a.btn { margin: 20px 0 0; } +/*=== Draggable */ +.drag-hover { + margin: 0 0 5px; + border-bottom: 2px solid #ccc; +} +[draggable=true] { + cursor: grab; +} /*=== STRUCTURE */ /*===============*/ -- cgit v1.2.3 From 408ac31dd8751eba037db216243958d396df1c8e Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 2 Oct 2014 19:02:43 +0200 Subject: Hack for dragleave (triggered on children!) See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/Controllers/feedController.php | 7 ++++++- p/scripts/category.js | 33 ++++++++++++++++++++++++++------- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 315665ef3..b2b53185e 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -389,7 +389,12 @@ class FreshRSS_feed_Controller extends Minz_ActionController { 'category' => $cat_id, ); - $feedDAO->updateFeed($feed_id, $values); + if (!$feedDAO->updateFeed($feed_id, $values)) { + Minz_Error::error( + 404, + array('error' => array(_t('error_occurred'))) + ); + } } } diff --git a/p/scripts/category.js b/p/scripts/category.js index 37ad36b17..872d14490 100644 --- a/p/scripts/category.js +++ b/p/scripts/category.js @@ -4,6 +4,8 @@ var loading = false, dnd_successful = false; function dragend_process(t) { + t.style.display = 'none'; + if (loading) { window.setTimeout(function() { dragend_process(t); @@ -11,13 +13,13 @@ function dragend_process(t) { } if (!dnd_successful) { + t.style.display = 'block'; t.style.opacity = 1.0; } else { t.parentNode.removeChild(t); } } - function init_draggable() { if (!(window.$ && window.url_freshrss)) { if (window.console) { @@ -45,14 +47,31 @@ function init_draggable() { }); $('.drop-section').on('dragenter', dropzone, function(e) { - $(e.target).addClass('drag-hover'); + $(this).addClass('drag-hover'); + + e.preventDefault(); }); $('.drop-section').on('dragleave', dropzone, function(e) { - $(e.target).removeClass('drag-hover'); + var pos_this = $(this).position(), + scroll_top = $(document).scrollTop(), + top = pos_this.top, + left = pos_this.left, + right = left + $(this).width(), + bottom = top + $(this).height(), + mouse_x = e.originalEvent.screenX, + mouse_y = e.originalEvent.clientY + scroll_top; + + if (left <= mouse_x && mouse_x <= right && + top <= mouse_y && mouse_y <= bottom) { + // HACK because dragleave is triggered when hovering children! + return; + } + $(this).removeClass('drag-hover'); }); $('.drop-section').on('dragover', dropzone, function(e) { e.dataTransfer.dropEffect = "move"; + e.preventDefault(); return false; }); $('.drop-section').on('drop', dropzone, function(e) { @@ -70,14 +89,14 @@ function init_draggable() { } }).success(function() { $(e.target).after(e.dataTransfer.getData('text/html')); - loading = false; - }).complete(function() { dnd_successful = true; + }).complete(function() { + loading = false; }); - $(e.target).removeClass('drag-hover'); + $(this).removeClass('drag-hover'); - return false; + e.preventDefault(); }); } -- cgit v1.2.3 From ce43b1761b810c89e5e8660e8ae2638e97ca6339 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 2 Oct 2014 19:47:02 +0200 Subject: Fix box when no feed in category See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/views/helpers/javascript_vars.phtml | 1 + p/scripts/category.js | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 1139eb446..71798369d 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -54,6 +54,7 @@ echo 'authType="', $authType, '",', echo 'str_confirmation_default="', 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 'str_category_empty="', Minz_Translate::t('category_empty'), '"', ",\n"; echo 'html5_notif_timeout=', $this->conf->html5_notif_timeout,",\n"; diff --git a/p/scripts/category.js b/p/scripts/category.js index 872d14490..dc5df67e4 100644 --- a/p/scripts/category.js +++ b/p/scripts/category.js @@ -16,7 +16,12 @@ function dragend_process(t) { t.style.display = 'block'; t.style.opacity = 1.0; } else { - t.parentNode.removeChild(t); + var parent = $(t.parentNode); + $(t).remove(); + + if (parent.children().length <= 0) { + parent.append('
      • ' + str_category_empty + '
      • '); + } } } @@ -89,6 +94,9 @@ function init_draggable() { } }).success(function() { $(e.target).after(e.dataTransfer.getData('text/html')); + if ($(e.target).hasClass('disabled')) { + $(e.target).remove(); + } dnd_successful = true; }).complete(function() { loading = false; -- cgit v1.2.3 From 370b51815071a36574ef40f5661de4ba17f071c9 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 2 Oct 2014 21:38:18 +0200 Subject: Filter link on feed updating page See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/views/helpers/feed/update.phtml | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/app/views/helpers/feed/update.phtml b/app/views/helpers/feed/update.phtml index 4a6425c45..3f6b32076 100644 --- a/app/views/helpers/feed/update.phtml +++ b/app/views/helpers/feed/update.phtml @@ -1,9 +1,11 @@
        - -

        feed->name (); ?>

        feed->description (); ?> + + + + feed->nbEntries (); ?> feed->inError ()) { ?> @@ -67,13 +69,7 @@
    -
    -
    - - - -
    -
    +
    -- cgit v1.2.3 From 3b6b7d08d3c84dd9dc094fa3e0c0c58336552114 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 2 Oct 2014 21:41:06 +0200 Subject: Fix position of links (updating feed) See last commit --- app/views/helpers/feed/update.phtml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/app/views/helpers/feed/update.phtml b/app/views/helpers/feed/update.phtml index 3f6b32076..678c5f132 100644 --- a/app/views/helpers/feed/update.phtml +++ b/app/views/helpers/feed/update.phtml @@ -1,10 +1,13 @@

    feed->name (); ?>

    - feed->description (); ?> - - - +
    + + + +
    + +

    feed->description (); ?>

    feed->nbEntries (); ?> -- cgit v1.2.3 From 94520ee326d1ad7323172a6d92ec0645e4606b73 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 2 Oct 2014 22:02:09 +0200 Subject: Fix category not appear on feed.add page (GET) Must apply to 0.8.1 and 0.9.1 See https://github.com/marienfressinaud/FreshRSS/issues/649 --- app/Controllers/feedController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index b2b53185e..eb26d9786 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -171,7 +171,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // GET request so we must ask confirmation to user Minz_View::prependTitle(Minz_Translate::t('add_rss_feed') . ' · '); - $this->view->categories = $this->catDAO->listCategories(); + $this->view->categories = $this->catDAO->listCategories(false); $this->view->feed = new FreshRSS_Feed($url); try { // We try to get some more information about the feed -- cgit v1.2.3 From 9f8d3d0527988b768f739fd4c0e61de68dfdd822 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 3 Oct 2014 12:18:43 +0200 Subject: Fix configure icon on Flat design See https://github.com/marienfressinaud/FreshRSS/issues/468 --- p/themes/Flat/flat.css | 5 +++++ p/themes/base-theme/template.css | 7 +++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/p/themes/Flat/flat.css b/p/themes/Flat/flat.css index d0ac46fd5..7b2695781 100644 --- a/p/themes/Flat/flat.css +++ b/p/themes/Flat/flat.css @@ -464,6 +464,11 @@ a.btn { .box .box-content .item .configure { visibility: hidden; } +.box .box-content .item .configure .icon { + vertical-align: middle; + background-color: #95a5a6; + border-radius: 3px; +} .box .box-content .item:hover .configure { visibility: visible; } diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index 06874c9fe..1a96f1e2f 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -73,7 +73,9 @@ label { input { width: 180px; } -textarea { +textarea, +input[type="file"], +input.extend:focus { width: 300px; } input, select, textarea { @@ -85,9 +87,6 @@ input[type="checkbox"] { width: 15px !important; min-height: 15px !important; } -input.extend:focus { - width: 300px; -} button.as-link, button.as-link:hover, button.as-link:active { -- cgit v1.2.3 From dd945df0cb2bae216b4612364506e74aa3259c0b Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 3 Oct 2014 12:54:10 +0200 Subject: Fix category not change (updating feed on MySQL) See https://github.com/marienfressinaud/FreshRSS/issues/646 --- app/Controllers/feedController.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index eb26d9786..d694c103e 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -384,12 +384,14 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $cat_id = Minz_Request::param('c_id'); $feedDAO = FreshRSS_Factory::createFeedDao(); - $values = array( 'category' => $cat_id, ); - if (!$feedDAO->updateFeed($feed_id, $values)) { + $feed = $feedDAO->searchById($feed_id); + + if (!$feed || ($feed->category() != $cat_id && + !$feedDAO->updateFeed($feed_id, $values))) { Minz_Error::error( 404, array('error' => array(_t('error_occurred'))) -- cgit v1.2.3 From 783171011dc6256f37cbd4365f5405b5e8a4b44e Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 4 Oct 2014 10:30:40 +0200 Subject: Fix icon not appearing (Flat theme) See https://github.com/marienfressinaud/FreshRSS/issues/651 --- p/themes/Flat/flat.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/p/themes/Flat/flat.css b/p/themes/Flat/flat.css index 7b2695781..e2151b1f9 100644 --- a/p/themes/Flat/flat.css +++ b/p/themes/Flat/flat.css @@ -652,6 +652,12 @@ a.btn { padding: 5px 0; } +#dropdown-query ~ .dropdown-menu .dropdown-header .icon { + vertical-align: middle; + background-color: #95a5a6; + border-radius: 3px; +} + /*=== Feed articles */ .flux { border-left: 2px solid #ecf0f1; -- cgit v1.2.3 From 91cc88209c710e64cd8a10397e56d006d4566624 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sat, 4 Oct 2014 08:45:57 -0400 Subject: Remove debugging code --- p/scripts/main.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/p/scripts/main.js b/p/scripts/main.js index 37281a907..02d16ca64 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -384,8 +384,6 @@ function collapse_entry() { } function user_filter(key) { - console.log('user filter'); - console.warn(key); var filter = $('#dropdown-query'); var filters = filter.siblings('.dropdown-menu').find('.item.query a'); if (typeof key === "undefined") { -- cgit v1.2.3 From 7a59568dfc20589c0495235679a96a375e36cfee Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sat, 4 Oct 2014 08:46:11 -0400 Subject: Fix library with code provided in the comments of the library page. The fix was given by the owner of the project (I assume) but was never integrated in the code. There is no bug tracker so I couldn't open a ticket. It looks like the project is dead since there is modification to the library. --- p/scripts/shortcut.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/p/scripts/shortcut.js b/p/scripts/shortcut.js index debaffbaa..4137172c3 100644 --- a/p/scripts/shortcut.js +++ b/p/scripts/shortcut.js @@ -43,7 +43,9 @@ shortcut = { //Find Which key is pressed if (e.keyCode) code = e.keyCode; else if (e.which) code = e.which; - var character = String.fromCharCode(code).toLowerCase(); + if( code == 32 || (code >= 48 && code <= 90) || (code >= 96 && code <= 111) || (code >= 186 && code <= 192) || (code >= 219 && code <= 222)) { + var character = String.fromCharCode(code).toLowerCase(); + } if(code == 188) character=","; //If the user presses , when the type is onkeydown if(code == 190) character="."; //If the user presses , when the type is onkeydown -- cgit v1.2.3 From 38a6f0c4b29e5a53c21f345dd839a4fa0b2a6f47 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sat, 4 Oct 2014 09:06:35 -0400 Subject: Add a shortcut to close drop-down lists --- app/Models/Configuration.php | 1 + app/i18n/en.php | 1 + app/i18n/fr.php | 1 + app/views/configure/shortcut.phtml | 7 +++++++ app/views/helpers/javascript_vars.phtml | 3 ++- p/scripts/main.js | 6 ++++++ 6 files changed, 18 insertions(+), 1 deletion(-) diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index 95f819779..feba3d2f6 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -47,6 +47,7 @@ class FreshRSS_Configuration { 'focus_search' => 'a', 'user_filter' => 'u', 'help' => 'f1', + 'close_dropdown' => 'escape', ), 'topline_read' => true, 'topline_favorite' => true, diff --git a/app/i18n/en.php b/app/i18n/en.php index 28104196e..0456049a9 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -191,6 +191,7 @@ return array ( 'user_filter' => 'Access user filters', 'user_filter_help' => 'If there is only one user filter, it is used. Else filters are accessible by their number.', 'help' => 'Display documentation', + 'close_dropdown' => 'Close drop-down lists', 'file_to_import' => 'File to import
    (OPML, Json or Zip)', 'file_to_import_no_zip' => 'File to import
    (OPML or Json)', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index c72fc3e93..adc79d0e2 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -191,6 +191,7 @@ return array ( 'user_filter' => 'Accéder aux filtres utilisateur', 'user_filter_help' => 'S’il n’y a qu’un filtre utilisateur, celui ci est utilisé automatiquement. Sinon ils sont accessibles par leur numéro.', 'help' => 'Afficher la documentation', + 'close_dropdown' => 'Fermer les listes déroulantes', 'file_to_import' => 'Fichier à importer
    (OPML, Json ou Zip)', 'file_to_import_no_zip' => 'Fichier à importer
    (OPML ou Json)', diff --git a/app/views/configure/shortcut.phtml b/app/views/configure/shortcut.phtml index a4029b676..44727e62b 100644 --- a/app/views/configure/shortcut.phtml +++ b/app/views/configure/shortcut.phtml @@ -111,6 +111,13 @@
    +
    + +
    + +
    +
    +
    diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 71798369d..4f7e3db0c 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -28,7 +28,8 @@ echo ',shortcuts={', 'auto_share:"', $s['auto_share'], '",', 'focus_search:"', $s['focus_search'], '",', 'user_filter:"', $s['user_filter'], '",', - 'help:"', $s['help'], '"', + 'help:"', $s['help'], '",', + 'close_dropdown:"', $s['close_dropdown'], '"', "},\n"; if (Minz_Request::param ('output') === 'global') { diff --git a/p/scripts/main.js b/p/scripts/main.js index 37281a907..0d90d3d39 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -663,6 +663,12 @@ function init_shortcuts() { 'disable_in_input': true }); + shortcut.add(shortcuts.close_dropdown, function () { + window.location.hash = null; + }, { + 'disable_in_input': true + }); + } function init_stream(divStream) { -- cgit v1.2.3 From 6e6d7b3c870975b2981f653b6f53a31f800f56ec Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 5 Oct 2014 01:43:29 +0200 Subject: Minor JavaScript --- p/scripts/main.js | 2 +- p/scripts/shortcut.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/p/scripts/main.js b/p/scripts/main.js index 79a34ec29..5793bb50b 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -33,7 +33,7 @@ function needsScroll($elem) { } function str2int(str) { - if (str == '' || str === undefined) { + if (!str) { return 0; } return parseInt(str.replace(/\D/g, ''), 10) || 0; diff --git a/p/scripts/shortcut.js b/p/scripts/shortcut.js index 4137172c3..e78cf6f5e 100644 --- a/p/scripts/shortcut.js +++ b/p/scripts/shortcut.js @@ -43,7 +43,7 @@ shortcut = { //Find Which key is pressed if (e.keyCode) code = e.keyCode; else if (e.which) code = e.which; - if( code == 32 || (code >= 48 && code <= 90) || (code >= 96 && code <= 111) || (code >= 186 && code <= 192) || (code >= 219 && code <= 222)) { + if (code == 32 || (code >= 48 && code <= 90) || (code >= 96 && code <= 111) || (code >= 186 && code <= 192) || (code >= 219 && code <= 222)) { //FreshRSS var character = String.fromCharCode(code).toLowerCase(); } -- cgit v1.2.3 From 9101bdb15edb7278ea26f6aee01c2b79e0f73dd5 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 5 Oct 2014 09:58:21 +0200 Subject: Design shortcuts_navigation_help box --- app/views/configure/shortcut.phtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/configure/shortcut.phtml b/app/views/configure/shortcut.phtml index 44727e62b..5ae8069ad 100644 --- a/app/views/configure/shortcut.phtml +++ b/app/views/configure/shortcut.phtml @@ -18,6 +18,8 @@ +

    +
    @@ -46,8 +48,6 @@
    -
    -
    -- cgit v1.2.3 From 9c4f0a94d757763842ae183d7aea89044a675ba6 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 5 Oct 2014 10:00:49 +0200 Subject: Coding style shortcut.phtml --- app/views/configure/shortcut.phtml | 56 +++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/app/views/configure/shortcut.phtml b/app/views/configure/shortcut.phtml index 5ae8069ad..fc8e90590 100644 --- a/app/views/configure/shortcut.phtml +++ b/app/views/configure/shortcut.phtml @@ -1,7 +1,7 @@ -partial ('aside_configure'); ?> +partial('aside_configure'); ?>
    - + list_keys as $key) { ?> @@ -11,115 +11,115 @@ conf->shortcuts; ?> -
    - + + - + - + -

    +

    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    @@ -127,8 +127,8 @@
    - - + +
    -- cgit v1.2.3 From 5474803aa7a05e4afa851c88bf21fd8383bf59d9 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 5 Oct 2014 10:57:50 +0200 Subject: Add a TODO in feedController --- app/Controllers/feedController.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index d694c103e..92ce40634 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -390,8 +390,10 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feed = $feedDAO->searchById($feed_id); - if (!$feed || ($feed->category() != $cat_id && - !$feedDAO->updateFeed($feed_id, $values))) { + if ($feed && ($feed->category() == $cat_id || + $feedDAO->updateFeed($feed_id, $values))) { + // TODO: return something useful + } else { Minz_Error::error( 404, array('error' => array(_t('error_occurred'))) -- cgit v1.2.3 From febabccdd5e6db573ab80bd5c1758d136b91cd78 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 5 Oct 2014 12:14:22 +0200 Subject: Primitive extension system https://github.com/marienfressinaud/FreshRSS/issues/252 I have been using this extension system for a little while, in particular to include custom CSS and/or JavaScript (inclusion of PHP code is not done yet). There is very little code and it does not impact performances. I hurry to post it before https://github.com/marienfressinaud/FreshRSS/issues/655 --- app/FreshRSS.php | 21 +++++++++++++++++++++ extensions/.gitignore | 1 + extensions/Read-me.txt | 15 +++++++++++++++ p/ext.php | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 72 insertions(+) create mode 100644 extensions/.gitignore create mode 100644 extensions/Read-me.txt create mode 100644 p/ext.php diff --git a/app/FreshRSS.php b/app/FreshRSS.php index cdf8962cb..58aac4059 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -17,6 +17,7 @@ class FreshRSS extends Minz_FrontController { Minz_View::_param('loginOk', $loginOk); $this->loadStylesAndScripts($loginOk); //TODO: Do not load that when not needed, e.g. some Ajax requests $this->loadNotifications(); + $this->loadExtensions(); } private static function getCredentialsFromLongTermCookie() { @@ -179,4 +180,24 @@ class FreshRSS extends Minz_FrontController { Minz_Session::_param ('notification'); } } + + private function loadExtensions() { + $extensionPath = FRESHRSS_PATH . '/extensions/'; + //TODO: Add a preference to load only user-selected extensions + foreach (scandir($extensionPath) as $key => $extension) { + if (ctype_alpha($extension)) { + $mtime = @filemtime($extensionPath . $extension . '/style.css'); + if ($mtime !== false) { + Minz_View::appendStyle(Minz_Url::display('/ext.php?c&e=' . $extension . '&' . $mtime)); + } + $mtime = @filemtime($extensionPath . $extension . '/script.js'); + if ($mtime !== false) { + Minz_View::appendScript(Minz_Url::display('/ext.php?j&e=' . $extension . '&' . $mtime)); + } + if (file_exists($extensionPath . $extension . '/module.php')) { + //TODO: include + } + } + } + } } diff --git a/extensions/.gitignore b/extensions/.gitignore new file mode 100644 index 000000000..d93e5e396 --- /dev/null +++ b/extensions/.gitignore @@ -0,0 +1 @@ +/[xX] diff --git a/extensions/Read-me.txt b/extensions/Read-me.txt new file mode 100644 index 000000000..e7b66d5bc --- /dev/null +++ b/extensions/Read-me.txt @@ -0,0 +1,15 @@ +== FreshRSS extensions == + +You may place in this directory some custom extensions for FreshRSS. + +The structure must be: + +./FreshRSS/extensions/ + ./NameOfExtensionAlphanumeric/ + ./style.css + ./script.js + ./module.php + +Each file is optional. + +The name of non-official extensions should start by an 'x'. diff --git a/p/ext.php b/p/ext.php new file mode 100644 index 000000000..cff194343 --- /dev/null +++ b/p/ext.php @@ -0,0 +1,35 @@ + Date: Sun, 5 Oct 2014 12:38:13 +0200 Subject: Primitive extension system: minor change https://github.com/marienfressinaud/FreshRSS/issues/252 --- p/ext.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/p/ext.php b/p/ext.php index cff194343..a1dde2f93 100644 --- a/p/ext.php +++ b/p/ext.php @@ -20,6 +20,9 @@ if (isset($_GET['j'])) { header('Content-Type: text/css; charset=UTF-8'); header('Content-Disposition: inline; filename="style.css"'); $filename .= 'style.css'; +} else { + header('HTTP/1.1 400 Bad Request'); + die(); } $mtime = @filemtime($filename); -- cgit v1.2.3 From 6c8b36f04ea1bc2c022c331bb0980b6c9dccb83c Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 5 Oct 2014 15:55:20 +0200 Subject: Let's begin the big refactoring! Minz_Translate::t\s? replaces by _t See https://github.com/marienfressinaud/FreshRSS/issues/655 --- app/Controllers/entryController.php | 8 ++-- app/Controllers/errorController.php | 4 +- app/Controllers/feedController.php | 30 ++++++------- app/Controllers/indexController.php | 22 +++++----- app/Controllers/statsController.php | 4 +- app/Controllers/usersController.php | 8 ++-- app/FreshRSS.php | 2 +- app/Models/CategoryDAO.php | 2 +- app/Models/StatsDAO.php | 2 +- app/Models/UserDAO.php | 4 +- app/layout/aside_stats.phtml | 14 +++--- app/views/configure/archiving.phtml | 36 ++++++++-------- app/views/configure/display.phtml | 44 +++++++++---------- app/views/configure/reading.phtml | 64 +++++++++++++-------------- app/views/configure/sharing.phtml | 24 +++++------ app/views/configure/users.phtml | 74 ++++++++++++++++---------------- app/views/error/index.phtml | 2 +- app/views/feed/add.phtml | 34 +++++++-------- app/views/helpers/feed/update.phtml | 60 +++++++++++++------------- app/views/helpers/javascript_vars.phtml | 8 ++-- app/views/helpers/logs_pagination.phtml | 8 ++-- app/views/helpers/view/normal_view.phtml | 14 +++--- app/views/helpers/view/reader_view.phtml | 2 +- app/views/helpers/view/rss_view.phtml | 2 +- app/views/index/about.phtml | 26 +++++------ app/views/index/logs.phtml | 8 ++-- lib/lib_rss.php | 8 ++-- 27 files changed, 256 insertions(+), 258 deletions(-) diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php index ab66d9198..048ac1c69 100755 --- a/app/Controllers/entryController.php +++ b/app/Controllers/entryController.php @@ -5,7 +5,7 @@ class FreshRSS_entry_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'))) ); } @@ -75,7 +75,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { $notif = array ( 'type' => 'good', - 'content' => Minz_Translate::t ('feeds_marked_read') + 'content' => _t('feeds_marked_read') ); Minz_Session::_param ('notification', $notif); } else { @@ -111,7 +111,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { $notif = array ( 'type' => 'good', - 'content' => Minz_Translate::t ('optimization_complete') + 'content' => _t('optimization_complete') ); Minz_Session::_param ('notification', $notif); } @@ -155,7 +155,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { $notif = array( 'type' => 'good', - 'content' => Minz_Translate::t('purge_completed', $nbTotal) + 'content' => _t('purge_completed', $nbTotal) ); Minz_Session::_param('notification', $notif); diff --git a/app/Controllers/errorController.php b/app/Controllers/errorController.php index 922650b3d..64a5c06fd 100644 --- a/app/Controllers/errorController.php +++ b/app/Controllers/errorController.php @@ -24,11 +24,11 @@ class FreshRSS_error_Controller extends Minz_ActionController { if ($this->view->errorMessage == '') { switch(Minz_Request::param('code')) { case 403: - $this->view->errorMessage = Minz_Translate::t('forbidden_access'); + $this->view->errorMessage = _t('forbidden_access'); break; case 404: default: - $this->view->errorMessage = Minz_Translate::t('page_not_found'); + $this->view->errorMessage = _t('page_not_found'); break; } } diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 92ce40634..029f9fa68 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -15,7 +15,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { ) { Minz_Error::error ( 403, - array ('error' => array (Minz_Translate::t ('access_denied'))) + array ('error' => array (_t('access_denied'))) ); } } @@ -84,7 +84,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // on est déjà abonné à ce flux $notif = array ( 'type' => 'bad', - 'content' => Minz_Translate::t ('already_subscribed', $feed->name ()) + 'content' => _t('already_subscribed', $feed->name ()) ); Minz_Session::_param ('notification', $notif); } else { @@ -93,7 +93,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // problème au niveau de la base de données $notif = array ( 'type' => 'bad', - 'content' => Minz_Translate::t ('feed_not_added', $feed->name ()) + 'content' => _t('feed_not_added', $feed->name ()) ); Minz_Session::_param ('notification', $notif); } else { @@ -131,7 +131,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // ok, ajout terminé $notif = array ( 'type' => 'good', - 'content' => Minz_Translate::t ('feed_added', $feed->name ()) + 'content' => _t('feed_added', $feed->name ()) ); Minz_Session::_param ('notification', $notif); @@ -143,14 +143,14 @@ class FreshRSS_feed_Controller extends Minz_ActionController { Minz_Log::record ($e->getMessage (), Minz_Log::WARNING); $notif = array ( 'type' => 'bad', - 'content' => Minz_Translate::t ('invalid_url', $url) + 'content' => _t('invalid_url', $url) ); Minz_Session::_param ('notification', $notif); } catch (FreshRSS_Feed_Exception $e) { Minz_Log::record ($e->getMessage (), Minz_Log::WARNING); $notif = array ( 'type' => 'bad', - 'content' => Minz_Translate::t ('internal_problem_feed', Minz_Url::display(array('a' => 'logs'))) + 'content' => _t('internal_problem_feed', Minz_Url::display(array('a' => 'logs'))) ); Minz_Session::_param ('notification', $notif); } catch (Minz_FileNotExistException $e) { @@ -158,7 +158,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { Minz_Log::record ($e->getMessage (), Minz_Log::ERROR); $notif = array ( 'type' => 'bad', - 'content' => Minz_Translate::t ('internal_problem_feed', Minz_Url::display(array('a' => 'logs'))) + 'content' => _t('internal_problem_feed', Minz_Url::display(array('a' => 'logs'))) ); Minz_Session::_param ('notification', $notif); } @@ -170,7 +170,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } else { // GET request so we must ask confirmation to user - Minz_View::prependTitle(Minz_Translate::t('add_rss_feed') . ' · '); + Minz_View::prependTitle(_t('add_rss_feed') . ' · '); $this->view->categories = $this->catDAO->listCategories(false); $this->view->feed = new FreshRSS_Feed($url); try { @@ -186,9 +186,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // Already subscribe so we redirect to the feed configuration page $notif = array( 'type' => 'bad', - 'content' => Minz_Translate::t( - 'already_subscribed', $feed->name() - ) + 'content' => _t('already_subscribed', $feed->name()) ); Minz_Session::_param('notification', $notif); @@ -210,7 +208,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $n = $feedDAO->truncate($id); $notif = array( 'type' => $n === false ? 'bad' : 'good', - 'content' => Minz_Translate::t ('n_entries_deleted', $n) + 'content' => _t('n_entries_deleted', $n) ); Minz_Session::_param ('notification', $notif); invalidateHttpCache(); @@ -336,19 +334,19 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feed = reset ($feeds); $notif = array ( 'type' => 'good', - 'content' => Minz_Translate::t ('feed_actualized', $feed->name ()) + 'content' => _t('feed_actualized', $feed->name ()) ); } elseif ($flux_update > 1) { // plusieurs flux on été mis à jour $notif = array ( 'type' => 'good', - 'content' => Minz_Translate::t ('n_feeds_actualized', $flux_update) + 'content' => _t('n_feeds_actualized', $flux_update) ); } else { // aucun flux n'a été mis à jour, oups $notif = array ( 'type' => 'good', - 'content' => Minz_Translate::t ('no_feed_to_refresh') + 'content' => _t('no_feed_to_refresh') ); } @@ -370,7 +368,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // ressenti utilisateur $notif = array ( 'type' => 'good', - 'content' => Minz_Translate::t ('feeds_actualized') + 'content' => _t('feeds_actualized') ); Minz_Session::_param ('notification', $notif); // et on désactive le layout car ne sert à rien diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 1b6563bb3..346739523 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -14,7 +14,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { if ($output === 'rss' && !$token_is_ok) { Minz_Error::error ( 403, - array ('error' => array (Minz_Translate::t ('access_denied'))) + array ('error' => array (_t('access_denied'))) ); return; } elseif ($output !== 'rss') { @@ -62,7 +62,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { Minz_Log::record ('Not found [' . $getType . '][' . $getId . ']', Minz_Log::DEBUG); Minz_Error::error ( 404, - array ('error' => array (Minz_Translate::t ('page_not_found'))) + array ('error' => array (_t('page_not_found'))) ); return; } @@ -145,7 +145,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { Minz_Log::record ($e->getMessage (), Minz_Log::NOTICE); Minz_Error::error ( 404, - array ('error' => array (Minz_Translate::t ('page_not_found'))) + array ('error' => array (_t('page_not_found'))) ); } } @@ -158,12 +158,12 @@ class FreshRSS_index_Controller extends Minz_ActionController { private function checkAndProcessType ($getType, $getId) { switch ($getType) { case 'a': - $this->view->currentName = Minz_Translate::t ('your_rss_feeds'); + $this->view->currentName = _t('your_rss_feeds'); $this->nb_not_read_cat = $this->view->nb_not_read; $this->view->get_c = $getType; return true; case 's': - $this->view->currentName = Minz_Translate::t ('your_favorites'); + $this->view->currentName = _t('your_favorites'); $this->nb_not_read_cat = $this->view->nb_favorites['unread']; $this->view->get_c = $getType; return true; @@ -202,18 +202,18 @@ class FreshRSS_index_Controller extends Minz_ActionController { } public function aboutAction () { - Minz_View::prependTitle (Minz_Translate::t ('about') . ' · '); + Minz_View::prependTitle (_t('about') . ' · '); } public function logsAction () { if (!$this->view->loginOk) { Minz_Error::error ( 403, - array ('error' => array (Minz_Translate::t ('access_denied'))) + array ('error' => array (_t('access_denied'))) ); } - Minz_View::prependTitle (Minz_Translate::t ('logs') . ' · '); + Minz_View::prependTitle (_t('logs') . ' · '); if (Minz_Request::isPost ()) { FreshRSS_LogDAO::truncate(); @@ -279,7 +279,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { } else { $res = array (); $res['status'] = 'failure'; - $res['reason'] = $reason == '' ? Minz_Translate::t ('invalid_login') : $reason; + $res['reason'] = $reason == '' ? _t('invalid_login') : $reason; Minz_Log::record ('Persona: ' . $res['reason'], Minz_Log::WARNING); } @@ -368,7 +368,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { if (!$ok) { $notif = array( 'type' => 'bad', - 'content' => Minz_Translate::t('invalid_login') + 'content' => _t('invalid_login') ); Minz_Session::_param('notification', $notif); } @@ -403,7 +403,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { } elseif (!Minz_Configuration::canLogIn()) { Minz_Error::error ( 403, - array ('error' => array (Minz_Translate::t ('access_denied'))) + array ('error' => array (_t('access_denied'))) ); } invalidateHttpCache(); diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php index 3069be34d..4adb5e75d 100644 --- a/app/Controllers/statsController.php +++ b/app/Controllers/statsController.php @@ -120,11 +120,11 @@ class FreshRSS_stats_Controller extends Minz_ActionController { public function firstAction() { if (!$this->view->loginOk) { Minz_Error::error( - 403, array('error' => array(Minz_Translate::t('access_denied'))) + 403, array('error' => array(_t('access_denied'))) ); } - Minz_View::prependTitle(Minz_Translate::t('stats') . ' · '); + Minz_View::prependTitle(_t('stats') . ' · '); } } diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index a9e6c32bc..8eb82f5d5 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -8,7 +8,7 @@ class FreshRSS_users_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'))) ); } } @@ -90,7 +90,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { $notif = array( 'type' => $ok ? 'good' : 'bad', - 'content' => Minz_Translate::t($ok ? 'configuration_updated' : 'error_occurred') + 'content' => _t($ok ? 'configuration_updated' : 'error_occurred') ); Minz_Session::_param('notification', $notif); } @@ -162,7 +162,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { $notif = array( 'type' => $ok ? 'good' : 'bad', - 'content' => Minz_Translate::t($ok ? 'user_created' : 'error_occurred', $new_user_name) + 'content' => _t($ok ? 'user_created' : 'error_occurred', $new_user_name) ); Minz_Session::_param('notification', $notif); } @@ -194,7 +194,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { $notif = array( 'type' => $ok ? 'good' : 'bad', - 'content' => Minz_Translate::t($ok ? 'user_deleted' : 'error_occurred', $username) + 'content' => _t($ok ? 'user_deleted' : 'error_occurred', $username) ); Minz_Session::_param('notification', $notif); } diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 58aac4059..16f64fd8b 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -10,7 +10,7 @@ class FreshRSS extends Minz_FrontController { $loginOk = false; //Basic protection against XSRF attacks Minz_Error::error( 403, - array('error' => array(Minz_Translate::t('access_denied') . ' [HTTP_REFERER=' . + array('error' => array(_t('access_denied') . ' [HTTP_REFERER=' . htmlspecialchars(empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER']) . ']')) ); } diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php index f11f87f47..5def50a26 100644 --- a/app/Models/CategoryDAO.php +++ b/app/Models/CategoryDAO.php @@ -134,7 +134,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo { $def_cat = $this->searchById (1); if ($def_cat == null) { - $cat = new FreshRSS_Category (Minz_Translate::t ('default_category')); + $cat = new FreshRSS_Category (_t('default_category')); $cat->_id (1); $values = array ( diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 08dd4cd5c..113944508 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -416,7 +416,7 @@ SQL; */ private function convertToTranslatedJson($data = array()) { $translated = array_map(function ($a) { - return Minz_Translate::t($a); + return _t($a); }, $data); return json_encode($translated); diff --git a/app/Models/UserDAO.php b/app/Models/UserDAO.php index 9f64fb4a7..0c96d7175 100644 --- a/app/Models/UserDAO.php +++ b/app/Models/UserDAO.php @@ -9,7 +9,7 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { $ok = false; if (defined('SQL_CREATE_TABLES')) { //E.g. MySQL - $sql = sprintf(SQL_CREATE_TABLES, $db['prefix'] . $username . '_', Minz_Translate::t('default_category')); + $sql = sprintf(SQL_CREATE_TABLES, $db['prefix'] . $username . '_', _t('default_category')); $stm = $userPDO->bd->prepare($sql); $ok = $stm && $stm->execute(); } else { //E.g. SQLite @@ -17,7 +17,7 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { if (is_array($SQL_CREATE_TABLES)) { $ok = true; foreach ($SQL_CREATE_TABLES as $instruction) { - $sql = sprintf($instruction, '', Minz_Translate::t('default_category')); + $sql = sprintf($instruction, '', _t('default_category')); $stm = $userPDO->bd->prepare($sql); $ok &= ($stm && $stm->execute()); } diff --git a/app/layout/aside_stats.phtml b/app/layout/aside_stats.phtml index fbfb9d84d..1cd31a99c 100644 --- a/app/layout/aside_stats.phtml +++ b/app/layout/aside_stats.phtml @@ -1,12 +1,12 @@ diff --git a/app/views/configure/archiving.phtml b/app/views/configure/archiving.phtml index c9cc7fe02..3180fe933 100644 --- a/app/views/configure/archiving.phtml +++ b/app/views/configure/archiving.phtml @@ -1,31 +1,31 @@ partial('aside_configure'); ?>
    - +
    - -

    + +

    - +
    - -   + +  
    - +
    () + ?> ()
    - +
    () + ?> ()
    - - + +
    - +
    -

    +

    -

    nb_total), ' ', Minz_Translate::t('articles'), ', ', formatBytes($this->size_user); ?>

    +

    nb_total), ' ', _t('articles'), ', ', formatBytes($this->size_user); ?>

    - - + +
    -

    +

    size_total); ?>

    diff --git a/app/views/configure/display.phtml b/app/views/configure/display.phtml index 8eb3a156b..f1b80ab15 100644 --- a/app/views/configure/display.phtml +++ b/app/views/configure/display.phtml @@ -1,13 +1,13 @@ partial ('aside_configure'); ?>
    - + - +
    - +
    themes as $theme) { ?>conf->content_width; ?>
    - +
    - + - - - - - + + + + + - + @@ -80,7 +80,7 @@ - + @@ -93,16 +93,16 @@
    - +
    - +
    - - + +
    diff --git a/app/views/configure/reading.phtml b/app/views/configure/reading.phtml index 8b2da2a28..7e4efc264 100644 --- a/app/views/configure/reading.phtml +++ b/app/views/configure/reading.phtml @@ -1,13 +1,13 @@ partial ('aside_configure'); ?>
    - +
    - +
    - +
    @@ -15,22 +15,22 @@
    - +
    - +
    @@ -50,7 +50,7 @@
    @@ -59,8 +59,8 @@
    @@ -69,8 +69,8 @@
    @@ -79,8 +79,8 @@
    @@ -89,8 +89,8 @@
    @@ -99,8 +99,8 @@
    @@ -109,48 +109,48 @@
    - +
    - +
    - - + +
    diff --git a/app/views/configure/sharing.phtml b/app/views/configure/sharing.phtml index 02ce331da..ee276a94e 100644 --- a/app/views/configure/sharing.phtml +++ b/app/views/configure/sharing.phtml @@ -1,7 +1,7 @@ partial ('aside_configure'); ?>
    - + @@ -9,28 +9,28 @@ data-advanced='
    - - + +
    - +
    '> - + conf->sharing as $key => $sharing): ?> conf->shares[$sharing['type']]; ?>
    ' />
    - - + +
    - + @@ -42,7 +42,7 @@
    @@ -51,8 +51,8 @@
    - - + +
    diff --git a/app/views/configure/users.phtml b/app/views/configure/users.phtml index 272896fb2..04e662fa3 100644 --- a/app/views/configure/users.phtml +++ b/app/views/configure/users.phtml @@ -1,36 +1,36 @@ partial('aside_configure'); ?>
    - +
    - +
    - +
    - +
    />
    - +
    - +
    /> @@ -41,36 +41,36 @@
    - + conf->mail_login; ?>
    placeholder="alice@example.net" /> - +
    - - + +
    - +
    - +
    @@ -80,7 +80,7 @@
    @@ -90,7 +90,7 @@
    @@ -100,7 +100,7 @@
    @@ -108,12 +108,12 @@
    - + conf->token; ?>
    - /> - +
    @@ -123,24 +123,24 @@
    - - + +
    - +
    - +
    conf->availableLanguages (); ?> @@ -173,25 +173,25 @@
    - +
    - +
    - +
    - + conf->mail_login; ?>
    @@ -200,8 +200,8 @@
    - - + +
    diff --git a/app/views/error/index.phtml b/app/views/error/index.phtml index ef4fbd39d..5e1949800 100644 --- a/app/views/error/index.phtml +++ b/app/views/error/index.phtml @@ -3,7 +3,7 @@

    code; ?>

    errorMessage; ?>
    - +

    diff --git a/app/views/feed/add.phtml b/app/views/feed/add.phtml index 849dacac6..17e52a571 100644 --- a/app/views/feed/add.phtml +++ b/app/views/feed/add.phtml @@ -1,16 +1,16 @@ feed) { ?>
    -

    +

    load_ok) { ?> -

    +

    - + load_ok) { ?>
    - +
    @@ -18,7 +18,7 @@ feed->description(); if ($desc != '') { ?>
    - +
    @@ -26,7 +26,7 @@
    - +
    feed->website(); ?> @@ -35,17 +35,17 @@
    - +
    - +
    - +
    - +
    - + feed->httpAuth(false); ?>
    - +
    - +
    - +
    - - + +
    diff --git a/app/views/helpers/feed/update.phtml b/app/views/helpers/feed/update.phtml index 678c5f132..8bd645d11 100644 --- a/app/views/helpers/feed/update.phtml +++ b/app/views/helpers/feed/update.phtml @@ -12,27 +12,27 @@ feed->nbEntries (); ?> feed->inError ()) { ?> -

    +

    -

    +

    - +
    - +
    - +
    - +
    @@ -41,18 +41,18 @@
    - +
    - +
    - +
    feed->priority () > 0 ? ' checked="checked"' : ''; ?> /> - +
    @@ -83,7 +83,7 @@
    - +
    @@ -96,21 +96,21 @@
    - +
    - +
    - +
    - +
    @@ -150,24 +150,24 @@
    - - + +
    - +
    - +
    - - + +
    - - + +
    diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 4f7e3db0c..ba02b9fad 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -52,10 +52,10 @@ echo 'authType="', $authType, '",', 'url_login="', _url ('index', 'login'), '",', 'url_logout="', _url ('index', 'logout'), '",'; -echo 'str_confirmation_default="', 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 'str_category_empty="', Minz_Translate::t('category_empty'), '"', ",\n"; +echo 'str_confirmation_default="', _t('confirm_action'), '"', ",\n"; +echo 'str_notif_title_articles="', _t('notif_title_new_articles'), '"', ",\n"; +echo 'str_notif_body_articles="', _t('notif_body_new_articles'), '"', ",\n"; +echo 'str_category_empty="', _t('category_empty'), '"', ",\n"; echo 'html5_notif_timeout=', $this->conf->html5_notif_timeout,",\n"; diff --git a/app/views/helpers/logs_pagination.phtml b/app/views/helpers/logs_pagination.phtml index e3d14810e..191cfa8de 100755 --- a/app/views/helpers/logs_pagination.phtml +++ b/app/views/helpers/logs_pagination.phtml @@ -9,14 +9,14 @@
  • currentPage > 1) { ?> - « + «
  • currentPage - 1; ?>
  • currentPage > 1) { ?> - +
  • @@ -34,13 +34,13 @@ currentPage + 1; ?>
  • currentPage < $this->nbPage) { ?> - +
  • nbPage; ?>
  • currentPage < $this->nbPage) { ?> - » + »
  • diff --git a/app/views/helpers/view/normal_view.phtml b/app/views/helpers/view/normal_view.phtml index e469edf58..ee745144f 100644 --- a/app/views/helpers/view/normal_view.phtml +++ b/app/views/helpers/view/normal_view.phtml @@ -30,12 +30,12 @@ if (!empty($this->entries)) {
    - +
    entries as $item) { if ($display_today && $item->isDay (FreshRSS_Days::TODAY, $this->today)) { ?>
    currentName; ?>
    entries)) { } if ($display_yesterday && $item->isDay (FreshRSS_Days::YESTERDAY, $this->today)) { ?>
    currentName; ?>
    entries)) { } if ($display_others && $item->isDay (FreshRSS_Days::BEFORE_YESTERDAY, $this->today)) { ?>
    currentName; ?>
    entries)) {

    title (); ?>

    author(); - echo $author != '' ? '
    ' . Minz_Translate::t('by_author', $author) . '
    ' : '', + echo $author != '' ? '
    ' . _t('by_author', $author) . '
    ' : '', $lazyload && $hidePosts ? lazyimg($item->content()) : $item->content(); ?>
    @@ -133,7 +133,7 @@ if (!empty($this->entries)) { - +
    diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 31c9cdbc1..4f6beb9fd 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -77,11 +77,11 @@ function formatBytes($bytes, $precision = 2, $system = 'IEC') { } function timestamptodate ($t, $hour = true) { - $month = Minz_Translate::t (date('M', $t)); + $month = _t(date('M', $t)); if ($hour) { - $date = Minz_Translate::t ('format_date_hour', $month); + $date = _t('format_date_hour', $month); } else { - $date = Minz_Translate::t ('format_date', $month); + $date = _t('format_date', $month); } return @date ($date, $t); @@ -107,7 +107,7 @@ function html_only_entity_decode($text) { function customSimplePie() { $simplePie = new SimplePie(); - $simplePie->set_useragent(Minz_Translate::t('freshrss') . '/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ') ' . SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION); + $simplePie->set_useragent(_t('freshrss') . '/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ') ' . SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION); $simplePie->set_cache_location(CACHE_PATH); $simplePie->set_cache_duration(800); $simplePie->strip_htmltags(array( -- cgit v1.2.3 From c8fad68a4fd15857a2e3e21e7d5311dc7f87226c Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 5 Oct 2014 16:10:25 +0200 Subject: Use _i() whenever it is possible Transform FreshRSS_Themes::icon\s? in _i See https://github.com/marienfressinaud/FreshRSS/issues/655 --- app/layout/layout.phtml | 2 +- app/layout/nav_entries.phtml | 6 +++--- app/views/configure/archiving.phtml | 4 ++-- app/views/configure/display.phtml | 6 +++--- app/views/configure/sharing.phtml | 14 +++++++------- app/views/configure/users.phtml | 8 ++++---- app/views/entry/bookmark.phtml | 2 +- app/views/entry/read.phtml | 2 +- app/views/feed/add.phtml | 6 +++--- app/views/helpers/feed/update.phtml | 8 ++++---- app/views/helpers/javascript_vars.phtml | 2 +- app/views/helpers/view/global_view.phtml | 2 +- app/views/helpers/view/normal_view.phtml | 14 +++++++------- 13 files changed, 38 insertions(+), 38 deletions(-) diff --git a/app/layout/layout.phtml b/app/layout/layout.phtml index f95f45b5e..dbfac63a5 100644 --- a/app/layout/layout.phtml +++ b/app/layout/layout.phtml @@ -56,7 +56,7 @@ ?>
    - +
    diff --git a/app/layout/nav_entries.phtml b/app/layout/nav_entries.phtml index 3141e92a0..ca6849193 100644 --- a/app/layout/nav_entries.phtml +++ b/app/layout/nav_entries.phtml @@ -1,5 +1,5 @@ \ No newline at end of file diff --git a/app/views/configure/archiving.phtml b/app/views/configure/archiving.phtml index 3180fe933..a883571aa 100644 --- a/app/views/configure/archiving.phtml +++ b/app/views/configure/archiving.phtml @@ -5,7 +5,7 @@
    -

    +

    @@ -63,7 +63,7 @@

    nb_total), ' ', _t('articles'), ', ', formatBytes($this->size_user); ?>

    - +
    diff --git a/app/views/configure/display.phtml b/app/views/configure/display.phtml index f1b80ab15..34239c7b2 100644 --- a/app/views/configure/display.phtml +++ b/app/views/configure/display.phtml @@ -62,12 +62,12 @@
    - - + + - + diff --git a/app/views/configure/sharing.phtml b/app/views/configure/sharing.phtml index ee276a94e..5f657ca74 100644 --- a/app/views/configure/sharing.phtml +++ b/app/views/configure/sharing.phtml @@ -4,15 +4,15 @@ + data-simple='
    ' data-advanced='
    -
    - +
    +
    '> conf->sharing as $key => $sharing): ?> @@ -27,12 +27,12 @@
    - +
    - + - + @@ -45,7 +45,7 @@ - + diff --git a/app/views/configure/users.phtml b/app/views/configure/users.phtml index 04e662fa3..517e302e5 100644 --- a/app/views/configure/users.phtml +++ b/app/views/configure/users.phtml @@ -22,7 +22,7 @@
    /> - +
    @@ -34,7 +34,7 @@
    /> - +
    @@ -113,7 +113,7 @@
    /> - +
    @@ -184,7 +184,7 @@
    - +
    diff --git a/app/views/entry/bookmark.phtml b/app/views/entry/bookmark.phtml index c1fc32b7f..ab61fa206 100755 --- a/app/views/entry/bookmark.phtml +++ b/app/views/entry/bookmark.phtml @@ -13,4 +13,4 @@ $url = Minz_Url::display (array ( 'params' => Minz_Request::params (), )); -echo json_encode (array ('url' => str_ireplace ('&', '&', $url), 'icon' => FreshRSS_Themes::icon(Minz_Request::param ('is_favorite') ? 'non-starred' : 'starred'))); +echo json_encode (array ('url' => str_ireplace ('&', '&', $url), 'icon' => _i(Minz_Request::param ('is_favorite') ? 'non-starred' : 'starred'))); diff --git a/app/views/entry/read.phtml b/app/views/entry/read.phtml index 9e79d4c07..0ef9df7eb 100755 --- a/app/views/entry/read.phtml +++ b/app/views/entry/read.phtml @@ -13,4 +13,4 @@ $url = Minz_Url::display (array ( 'params' => Minz_Request::params (), )); -echo json_encode (array ('url' => str_ireplace ('&', '&', $url), 'icon' => FreshRSS_Themes::icon(Minz_Request::param ('is_read') ? 'unread' : 'read'))); +echo json_encode (array ('url' => str_ireplace ('&', '&', $url), 'icon' => _i(Minz_Request::param ('is_read') ? 'unread' : 'read'))); diff --git a/app/views/feed/add.phtml b/app/views/feed/add.phtml index 17e52a571..1db053b52 100644 --- a/app/views/feed/add.phtml +++ b/app/views/feed/add.phtml @@ -29,7 +29,7 @@
    feed->website(); ?> - +
    @@ -39,7 +39,7 @@
    - +
    @@ -76,7 +76,7 @@
    - +
    diff --git a/app/views/helpers/feed/update.phtml b/app/views/helpers/feed/update.phtml index 8bd645d11..9235752c3 100644 --- a/app/views/helpers/feed/update.phtml +++ b/app/views/helpers/feed/update.phtml @@ -36,7 +36,7 @@
    - +
    @@ -45,7 +45,7 @@
    - +
    @@ -139,7 +139,7 @@
    - +
    @@ -160,7 +160,7 @@
    - +
    diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index ba02b9fad..011b17b7a 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -33,7 +33,7 @@ echo ',shortcuts={', "},\n"; if (Minz_Request::param ('output') === 'global') { - echo "iconClose='", FreshRSS_Themes::icon('close'), "',\n"; + echo "iconClose='", _i('close'), "',\n"; } $authType = Minz_Configuration::authType(); diff --git a/app/views/helpers/view/global_view.phtml b/app/views/helpers/view/global_view.phtml index 5e4cad01a..0e553c957 100644 --- a/app/views/helpers/view/global_view.phtml +++ b/app/views/helpers/view/global_view.phtml @@ -42,7 +42,7 @@
    conf->display_posts ? '' : ' class="hide_posts"'; ?>> - +
    diff --git a/app/views/helpers/view/normal_view.phtml b/app/views/helpers/view/normal_view.phtml index ee745144f..66b79cd7f 100644 --- a/app/views/helpers/view/normal_view.phtml +++ b/app/views/helpers/view/normal_view.phtml @@ -66,7 +66,7 @@ if (!empty($this->entries)) { $arUrl['params']['is_read'] = 0; } ?>isRead () ? 'read' : 'unread'); ?>isRead () ? 'read' : 'unread'); ?>entries)) { $arUrl['params']['is_favorite'] = 0; } ?>isFavorite () ? 'starred' : 'non-starred'); ?>isFavorite () ? 'starred' : 'non-starred'); ?>entries)) { ?>
  • ✇ name(); ?>
  • title (); ?>
  • date (); ?> 
  • - +
    @@ -111,7 +111,7 @@ if (!empty($this->entries)) { $arUrl['params']['is_read'] = 0; } ?>isRead () ? 'read' : 'unread'); ?>isRead () ? 'read' : 'unread'); ?>entries)) { $arUrl['params']['is_favorite'] = 0; } ?>isFavorite () ? 'starred' : 'non-starred'); ?>isFavorite () ? 'starred' : 'non-starred'); ?> @@ -132,7 +132,7 @@ if (!empty($this->entries)) { ?> -- cgit v1.2.3 From 70131f776a5fa30fdf26c64578039aeeb41333c7 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 5 Oct 2014 16:53:43 +0200 Subject: SimplePie enclosure bug workaround https://github.com/marienfressinaud/FreshRSS/issues/504 --- app/Models/Feed.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 2a5ea45ac..03baf3ad2 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -288,6 +288,8 @@ class FreshRSS_Feed extends Minz_Model { $content .= '
     
    conf->topline_read ? ' checked="checked"' : ''; ?> /> conf->topline_favorite ? ' checked="checked"' : ''; ?> /> conf->topline_date ? ' checked="checked"' : ''; ?> /> conf->topline_link ? ' checked="checked"' : ''; ?> />
    conf->bottomline_read ? ' checked="checked"' : ''; ?> /> conf->bottomline_favorite ? ' checked="checked"' : ''; ?> /> conf->bottomline_sharing ? ' checked="checked"' : ''; ?> />
     
    - - + + - + - + - + - + @@ -41,14 +41,14 @@
    -

    +

     
    repartition['main_stream']['total']); ?> repartition['all_feeds']['total']); ?>
    repartition['main_stream']['read']); ?> repartition['all_feeds']['read']); ?>
    repartition['main_stream']['unread']); ?> repartition['all_feeds']['unread']); ?>
    repartition['main_stream']['favorite']); ?> repartition['all_feeds']['favorite']); ?>
    - - - - + + + + @@ -65,18 +65,18 @@
    -

    +

    -

    +

    -

    +

    diff --git a/app/views/users/index.phtml b/app/views/users/index.phtml index 517e302e5..95659f727 100644 --- a/app/views/users/index.phtml +++ b/app/views/users/index.phtml @@ -164,7 +164,7 @@
    -
    -
    - - -
    - -
    -
    - -
    - - - -- cgit v1.2.3 From 6009990935a2d06c252073f6b51ea5378536ef52 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 7 Oct 2014 10:16:38 +0200 Subject: Introduce FreshRSS_Auth::hasAccess('admin') Replace Minz_Configuration::isAdmin($user). FreshRSS_Auth::hasAccess() could be extended to others scopes later. See https://github.com/marienfressinaud/FreshRSS/issues/655 --- app/Controllers/configureController.php | 2 +- app/Controllers/updateController.php | 2 +- app/Controllers/usersController.php | 8 ++++---- app/Models/Auth.php | 19 +++++++++++++++---- app/layout/aside_configure.phtml | 5 +---- app/layout/header.phtml | 5 +---- app/views/configure/archiving.phtml | 2 +- app/views/users/index.phtml | 6 +++--- lib/Minz/Configuration.php | 3 --- 9 files changed, 27 insertions(+), 25 deletions(-) diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 7e77a757a..fb8c1466e 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -229,7 +229,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $this->view->nb_total = $entryDAO->count(); $this->view->size_user = $entryDAO->size(); - if (Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { + if (FreshRSS_Auth::hasAccess('admin')) { $this->view->size_total = $entryDAO->size(true); } } diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index 9da1e8657..9d1e1ddf5 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -3,7 +3,7 @@ class FreshRSS_update_Controller extends Minz_ActionController { public function firstAction() { $current_user = Minz_Session::param('currentUser', ''); - if (!FreshRSS_Auth::hasAccess() && Minz_Configuration::isAdmin($current_user)) { + if (!FreshRSS_Auth::hasAccess('admin')) { Minz_Error::error( 403, array('error' => array(_t('access_denied'))) diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php index c2b1d163f..11862ce27 100644 --- a/app/Controllers/usersController.php +++ b/app/Controllers/usersController.php @@ -51,7 +51,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { $this->view->conf->_apiPasswordHash($passwordHash); } - if (Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { + if (FreshRSS_Auth::hasAccess('admin')) { $this->view->conf->_mail_login(Minz_Request::param('mail_login', '', true)); } $email = $this->view->conf->mail_login; @@ -65,7 +65,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { $ok &= (file_put_contents($personaFile, Minz_Session::param('currentUser', '_')) !== false); } - if (Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { + if (FreshRSS_Auth::hasAccess('admin')) { $current_token = $this->view->conf->token; $token = Minz_Request::param('token', $current_token); $this->view->conf->_token($token); @@ -105,7 +105,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { } public function createAction() { - if (Minz_Request::isPost() && Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { + if (Minz_Request::isPost() && FreshRSS_Auth::hasAccess('admin')) { $db = Minz_Configuration::dataBase(); require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php'); @@ -177,7 +177,7 @@ class FreshRSS_users_Controller extends Minz_ActionController { } public function deleteAction() { - if (Minz_Request::isPost() && Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) { + if (Minz_Request::isPost() && FreshRSS_Auth::hasAccess('admin')) { $db = Minz_Configuration::dataBase(); require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php'); diff --git a/app/Models/Auth.php b/app/Models/Auth.php index c4a3abd98..992b444a5 100644 --- a/app/Models/Auth.php +++ b/app/Models/Auth.php @@ -99,12 +99,23 @@ class FreshRSS_Auth { } /** - * Returns if current user is connected. + * Returns if current user has access to the given scope. * - * @return boolean true if user is connected, false else. + * @param string $scope general (default) or admin + * @return boolean true if user has corresponding access, false else. */ - public static function hasAccess() { - return self::$login_ok; + public static function hasAccess($scope = 'general') { + $ok = self::$login_ok; + switch ($scope) { + case 'general': + break; + case 'admin': + $ok &= Minz_Session::param('currentUser') === Minz_Configuration::defaultUser(); + break; + default: + $ok = false; + } + return $ok; } /** diff --git a/app/layout/aside_configure.phtml b/app/layout/aside_configure.phtml index e17bcb254..59846a7c8 100644 --- a/app/layout/aside_configure.phtml +++ b/app/layout/aside_configure.phtml @@ -22,10 +22,7 @@
  • - +
  • diff --git a/app/layout/header.phtml b/app/layout/header.phtml index fadfd13d7..12c86d61d 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -64,10 +64,7 @@ if (Minz_Configuration::canLogIn()) {
  • - +
  • diff --git a/app/views/configure/archiving.phtml b/app/views/configure/archiving.phtml index a883571aa..adbfdb77e 100644 --- a/app/views/configure/archiving.phtml +++ b/app/views/configure/archiving.phtml @@ -67,7 +67,7 @@ - +

    diff --git a/app/views/users/index.phtml b/app/views/users/index.phtml index 95659f727..f1cdf01a3 100644 --- a/app/views/users/index.phtml +++ b/app/views/users/index.phtml @@ -11,7 +11,7 @@
    @@ -44,7 +44,7 @@ conf->mail_login; ?>
    - placeholder="alice@example.net" /> + placeholder="alice@example.net" />
    @@ -56,7 +56,7 @@
    - + diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php index 4e9da58b4..554bc8c96 100644 --- a/lib/Minz/Configuration.php +++ b/lib/Minz/Configuration.php @@ -100,9 +100,6 @@ class Minz_Configuration { public static function defaultUser () { return self::$default_user; } - public static function isAdmin($currentUser) { - return $currentUser === self::$default_user; - } public static function allowAnonymous() { return self::$allow_anonymous; } -- cgit v1.2.3 From 1252b3dd867e59917cf303f0c39c7da938b8ce32 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 7 Oct 2014 16:37:10 +0200 Subject: Authentication system moved + Persona comes back! AuthController is dedicated to auhentication. Persona is back, greater than ever! See https://github.com/marienfressinaud/FreshRSS/issues/655 --- app/Controllers/authController.php | 182 ++++++++++++++++++++++++++++++++ app/Controllers/indexController.php | 90 +--------------- app/FreshRSS.php | 8 ++ app/Models/Auth.php | 21 +++- app/layout/header.phtml | 23 ++-- app/views/auth/formLogin.phtml | 28 +++++ app/views/auth/logout.phtml | 0 app/views/auth/personaLogin.phtml | 24 +++++ app/views/helpers/javascript_vars.phtml | 13 ++- app/views/index/formLogin.phtml | 46 -------- p/scripts/main.js | 65 ------------ p/scripts/persona.js | 76 +++++++++++++ 12 files changed, 356 insertions(+), 220 deletions(-) create mode 100644 app/Controllers/authController.php create mode 100644 app/views/auth/formLogin.phtml create mode 100644 app/views/auth/logout.phtml create mode 100644 app/views/auth/personaLogin.phtml delete mode 100644 app/views/index/formLogin.phtml create mode 100644 p/scripts/persona.js diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php new file mode 100644 index 000000000..2b67e34b8 --- /dev/null +++ b/app/Controllers/authController.php @@ -0,0 +1,182 @@ + 'index', 'a' => 'index'), true); + } + + $auth_type = Minz_Configuration::authType(); + switch ($auth_type) { + case 'form': + Minz_Request::forward(array('c' => 'auth', 'a' => 'formLogin')); + break; + case 'persona': + Minz_Request::forward(array('c' => 'auth', 'a' => 'personaLogin')); + break; + case 'http_auth': + case 'none': + // It should not happened! + Minz_Error::error(404); + default: + // TODO load plugin instead + Minz_Error::error(404); + } + } + + /** + * This action handles form login page. + * + * If this action is reached through a POST request, username and password + * are compared to login the current user. + * + * Parameters are: + * - nonce (default: false) + * - username (default: '') + * - challenge (default: '') + * - keep_logged_in (default: false) + */ + public function formLoginAction() { + invalidateHttpCache(); + + $file_mtime = @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js'); + Minz_View::appendScript(Minz_Url::display('/scripts/bcrypt.min.js?' . $file_mtime)); + + if (Minz_Request::isPost()) { + $nonce = Minz_Session::param('nonce'); + $username = Minz_Request::param('username', ''); + $challenge = Minz_Request::param('challenge', ''); + try { + $conf = new FreshRSS_Configuration($username); + } catch(Minz_Exception $e) { + // $username is not a valid user, nor the configuration file! + Minz_Log::warning('Login failure: ' . $e->getMessage()); + Minz_Request::bad(_t('invalid_login'), + array('c' => 'auth', 'a' => 'login')); + } + + $ok = FreshRSS_FormAuth::checkCredentials( + $username, $conf->passwordHash, $nonce, $challenge + ); + if ($ok) { + // Set session parameter to give access to the user. + Minz_Session::_param('currentUser', $username); + Minz_Session::_param('passwordHash', $conf->passwordHash); + FreshRSS_Auth::giveAccess(); + + // Set cookie parameter if nedded. + if (Minz_Request::param('keep_logged_in')) { + FreshRSS_FormAuth::makeCookie($username, $conf->passwordHash); + } else { + FreshRSS_FormAuth::deleteCookie(); + } + + // All is good, go back to the index. + Minz_Request::good(_t('login'), + array('c' => 'index', 'a' => 'index')); + } else { + Minz_Log::warning('Password mismatch for' . + ' user=' . $username . + ', nonce=' . $nonce . + ', c=' . $challenge); + Minz_Request::bad(_t('invalid_login'), + array('c' => 'auth', 'a' => 'login')); + } + } + } + + /** + * This action handles Persona login page. + * + * If this action is reached through a POST request, assertion from Persona + * is verificated and user connected if all is ok. + * + * Parameter is: + * - assertion (default: false) + * + * @todo: Persona system should be moved to a plugin + */ + public function personaLoginAction() { + $this->view->res = false; + + if (Minz_Request::isPost()) { + $this->view->_useLayout(false); + + $assert = Minz_Request::param('assertion'); + $url = 'https://verifier.login.persona.org/verify'; + $params = 'assertion=' . $assert . '&audience=' . + urlencode(Minz_Url::display(null, 'php', true)); + $ch = curl_init(); + $options = array( + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => TRUE, + CURLOPT_POST => 2, + CURLOPT_POSTFIELDS => $params + ); + curl_setopt_array($ch, $options); + $result = curl_exec($ch); + curl_close($ch); + + $res = json_decode($result, true); + + $login_ok = false; + $reason = ''; + if ($res['status'] === 'okay') { + $email = filter_var($res['email'], FILTER_VALIDATE_EMAIL); + if ($email != '') { + $persona_file = DATA_PATH . '/persona/' . $email . '.txt'; + if (($current_user = @file_get_contents($persona_file)) !== false) { + $current_user = trim($current_user); + try { + $conf = new FreshRSS_Configuration($current_user); + $login_ok = strcasecmp($email, $conf->mail_login) === 0; + } catch (Minz_Exception $e) { + //Permission denied or conf file does not exist + $reason = 'Invalid configuration for user ' . + '[' . $current_user . '] ' . $e->getMessage(); + } + } + } else { + $reason = 'Invalid email format [' . $res['email'] . ']'; + } + } else { + $reason = $res['reason']; + } + + if ($login_ok) { + Minz_Session::_param('currentUser', $current_user); + Minz_Session::_param('mail', $email); + FreshRSS_Auth::giveAccess(); + invalidateHttpCache(); + } else { + Minz_Log::error($reason); + + $res = array(); + $res['status'] = 'failure'; + $res['reason'] = _t('invalid_login'); + } + + header('Content-Type: application/json; charset=UTF-8'); + $this->view->res = $res; + } + } + + /** + * This action removes all accesses of the current user. + */ + public function logoutAction() { + invalidateHttpCache(); + FreshRSS_Auth::removeAccess(); + Minz_Request::good(_t('disconnected'), + array('c' => 'index', 'a' => 'index')); + } +} diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 3006480f9..5b490e672 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -20,7 +20,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { } elseif ($output !== 'rss') { // "hard" redirection is not required, just ask dispatcher to // forward to the login form without 302 redirection - Minz_Request::forward(array('c' => 'index', 'a' => 'login')); + Minz_Request::forward(array('c' => 'auth', 'a' => 'login')); return; } } @@ -228,92 +228,4 @@ class FreshRSS_index_Controller extends Minz_ActionController { $this->view->logsPaginator->_nbItemsPerPage(50); $this->view->logsPaginator->_currentPage($page); } - - /** - * This action handles the login page. - */ - public function loginAction() { - if (FreshRSS_Auth::hasAccess()) { - Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true); - } - - invalidateHttpCache(); - - $auth_type = Minz_Configuration::authType(); - switch ($auth_type) { - case 'form': - Minz_Request::forward(array('c' => 'index', 'a' => 'formLogin')); - break; - case 'http_auth': - case 'none': - // It should not happened! - Minz_Error::error(404); - default: - // TODO load plugin instead - Minz_Error::error(404); - } - } - - /** - * - */ - public function formLoginAction() { - if (FreshRSS_Auth::hasAccess()) { - Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true); - } - - invalidateHttpCache(); - - $file_mtime = @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js'); - Minz_View::appendScript(Minz_Url::display('/scripts/bcrypt.min.js?' . $file_mtime)); - - if (Minz_Request::isPost()) { - $nonce = Minz_Session::param('nonce'); - $username = Minz_Request::param('username', ''); - $challenge = Minz_Request::param('challenge', ''); - try { - $conf = new FreshRSS_Configuration($username); - } catch(Minz_Exception $e) { - // $username is not a valid user, nor the configuration file! - Minz_Log::warning('Login failure: ' . $e->getMessage()); - Minz_Request::bad(_t('invalid_login'), - array('c' => 'index', 'a' => 'login')); - } - - $ok = FreshRSS_FormAuth::checkCredentials( - $username, $conf->passwordHash, $nonce, $challenge - ); - if ($ok) { - // Set session parameter to give access to the user. - Minz_Session::_param('currentUser', $username); - Minz_Session::_param('passwordHash', $conf->passwordHash); - FreshRSS_Auth::giveAccess(); - - // Set cookie parameter if nedded. - if (Minz_Request::param('keep_logged_in', false)) { - FreshRSS_FormAuth::makeCookie($username, $conf->passwordHash); - } else { - FreshRSS_FormAuth::deleteCookie(); - } - - // All is good, go back to the index. - Minz_Request::good(_t('login'), - array('c' => 'index', 'a' => 'index')); - } else { - Minz_Log::warning('Password mismatch for' . - ' user=' . $username . - ', nonce=' . $nonce . - ', c=' . $challenge); - Minz_Request::bad(_t('invalid_login'), - array('c' => 'index', 'a' => 'login')); - } - } - } - - public function logoutAction() { - invalidateHttpCache(); - FreshRSS_Auth::removeAccess(); - Minz_Request::good(_t('disconnected'), - array('c' => 'index', 'a' => 'index')); - } } diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 35a37b887..6b7a813bf 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -64,6 +64,14 @@ class FreshRSS extends Minz_FrontController { Minz_View::appendScript(Minz_Url::display('/scripts/jquery.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/jquery.min.js'))); Minz_View::appendScript(Minz_Url::display('/scripts/shortcut.js?' . @filemtime(PUBLIC_PATH . '/scripts/shortcut.js'))); Minz_View::appendScript(Minz_Url::display('/scripts/main.js?' . @filemtime(PUBLIC_PATH . '/scripts/main.js'))); + + if (Minz_Configuration::authType() === 'persona') { + // TODO move it in a plugin + // Needed for login AND logout with Persona. + Minz_View::appendScript('https://login.persona.org/include.js'); + $file_mtime = @filemtime(PUBLIC_PATH . '/scripts/persona.js'); + Minz_View::appendScript(Minz_Url::display('/scripts/persona.js?' . $file_mtime)); + } } private function loadNotifications() { diff --git a/app/Models/Auth.php b/app/Models/Auth.php index 992b444a5..cc23d7974 100644 --- a/app/Models/Auth.php +++ b/app/Models/Auth.php @@ -20,7 +20,7 @@ class FreshRSS_Auth { Minz_Session::_param('currentUser', $current_user); } - $access_ok = self::accessControl($current_user); + $access_ok = self::accessControl(); if ($access_ok) { self::giveAccess(); @@ -36,10 +36,9 @@ class FreshRSS_Auth { * Required session parameters are also set in this method (such as * currentUser). * - * @param string $username username of the user to check access. * @return boolean true if user can be connected, false else. */ - public static function accessControl($username) { + public static function accessControl() { if (self::$login_ok) { return true; } @@ -61,6 +60,16 @@ class FreshRSS_Auth { Minz_Session::_param('currentUser', $current_user); } return $login_ok; + case 'persona': + $email = filter_var(Minz_Session::param('mail'), FILTER_VALIDATE_EMAIL); + $persona_file = DATA_PATH . '/persona/' . $email . '.txt'; + if (($current_user = @file_get_contents($persona_file)) !== false) { + $current_user = trim($current_user); + Minz_Session::_param('currentUser', $current_user); + Minz_Session::_param('mail', $email); + return true; + } + return false; case 'none': return true; default: @@ -87,6 +96,9 @@ class FreshRSS_Auth { case 'http_auth': self::$login_ok = strcasecmp($current_user, httpAuthUser()) === 0; break; + case 'persona': + self::$login_ok = strcasecmp(Minz_Session::param('mail'), $conf->mail_login) === 0; + break; case 'none': self::$login_ok = true; break; @@ -131,6 +143,9 @@ class FreshRSS_Auth { Minz_Session::_param('passwordHash'); FreshRSS_FormAuth::deleteCookie(); break; + case 'persona': + Minz_Session::_param('mail'); + break; case 'http_auth': case 'none': // Nothing to do... diff --git a/app/layout/header.phtml b/app/layout/header.phtml index 12c86d61d..deb21edc9 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -2,9 +2,9 @@ if (Minz_Configuration::canLogIn()) { ?>
  • -
  • -
    + +
    + +
    + diff --git a/app/views/auth/formLogin.phtml b/app/views/auth/formLogin.phtml new file mode 100644 index 000000000..0194a11a5 --- /dev/null +++ b/app/views/auth/formLogin.phtml @@ -0,0 +1,28 @@ +
    +

    + +
    +
    + + +
    +
    + + +
    + +
    +
    + +
    +
    +
    + +
    + + +

    +
    diff --git a/app/views/auth/logout.phtml b/app/views/auth/logout.phtml new file mode 100644 index 000000000..e69de29bb diff --git a/app/views/auth/personaLogin.phtml b/app/views/auth/personaLogin.phtml new file mode 100644 index 000000000..d62fe5818 --- /dev/null +++ b/app/views/auth/personaLogin.phtml @@ -0,0 +1,24 @@ +res === false) { ?> +
    +

    + +

    + + +

    + + + + + +

    + +

    +
    +res); +} +?> diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 8f615ed87..3bbcc3848 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -8,6 +8,15 @@ $hide_posts = ($this->conf->display_posts || Minz_Request::param('output') === 'reader'); $s = $this->conf->shortcuts; +$url_login = Minz_Url::display(array( + 'c' => 'auth', + 'a' => 'login' +), 'php'); +$url_logout = Minz_Url::display(array( + 'c' => 'auth', + 'a' => 'logout' +), 'php'); + echo 'var context={', 'hide_posts:', $hide_posts ? 'false' : 'true', ',', 'display_order:"', Minz_Request::param('order', $this->conf->sort_order), '",', @@ -43,8 +52,8 @@ echo 'shortcuts={', echo 'url={', 'index:"', _url('index', 'index'), '",', - 'login:"', _url('index', 'login'), '",', - 'logout:"', _url('index', 'logout'), '",', + 'login:"', $url_login, '",', + 'logout:"', $url_logout, '",', 'help:"', FRESHRSS_WIKI, '"', "},\n"; diff --git a/app/views/index/formLogin.phtml b/app/views/index/formLogin.phtml deleted file mode 100644 index b05cdced4..000000000 --- a/app/views/index/formLogin.phtml +++ /dev/null @@ -1,46 +0,0 @@ -
    -

    -
    - - -
    -
    - - -
    - -
    -
    - -
    -
    -
    - -
    -

    -

    - - - - - -

    - -

    -
    diff --git a/p/scripts/main.js b/p/scripts/main.js index b01a3a34d..77e1e3f77 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1034,67 +1034,7 @@ function init_crypto_form() { } // -// -function init_persona() { - if (!(navigator.id)) { - if (window.console) { - console.log('FreshRSS waiting for Persona…'); - } - window.setTimeout(init_persona, 100); - return; - } - $('a.signin').click(function() { - navigator.id.request(); - return false; - }); - - $('a.signout').click(function() { - navigator.id.logout(); - return false; - }); - navigator.id.watch({ - loggedInUser: context['current_user_mail'], - - onlogin: function(assertion) { - // A user has logged in! Here you need to: - // 1. Send the assertion to your backend for verification and to create a session. - // 2. Update your UI. - $.ajax ({ - type: 'POST', - url: url['login'], - data: {assertion: assertion}, - success: function(res, status, xhr) { - /*if (res.status === 'failure') { - alert (res_obj.reason); - } else*/ if (res.status === 'okay') { - location.href = url['index']; - } - }, - error: function(res, status, xhr) { - alert("Login failure: " + res); - } - }); - }, - onlogout: function() { - // A user has logged out! Here you need to: - // Tear down the user's session by redirecting the user or making a call to your backend. - // Also, make sure loggedInUser will get set to null on the next page load. - // (That's a literal JavaScript null. Not false, 0, or undefined. null.) - $.ajax ({ - type: 'POST', - url: url['logout'], - success: function(res, status, xhr) { - location.href = url['index']; - }, - error: function(res, status, xhr) { - //alert("logout failure" + res); - } - }); - } - }); -} -// function init_confirm_action() { $('body').on('click', '.confirm', function () { @@ -1274,11 +1214,6 @@ function init_all() { return; } init_notifications(); - switch (context['auth_type']) { - case 'persona': - init_persona(); - break; - } init_confirm_action(); $stream = $('#stream'); if ($stream.length > 0) { diff --git a/p/scripts/persona.js b/p/scripts/persona.js new file mode 100644 index 000000000..36aeeaf56 --- /dev/null +++ b/p/scripts/persona.js @@ -0,0 +1,76 @@ +"use strict"; + +function init_persona() { + if (!(navigator.id && window.$)) { + if (window.console) { + console.log('FreshRSS (Persona) waiting for JS…'); + } + window.setTimeout(init_persona, 100); + return; + } + + $('a.signin').click(function() { + navigator.id.request(); + return false; + }); + + $('a.signout').click(function() { + navigator.id.logout(); + return false; + }); + + navigator.id.watch({ + loggedInUser: context['current_user_mail'], + + onlogin: function(assertion) { + // A user has logged in! Here you need to: + // 1. Send the assertion to your backend for verification and to create a session. + // 2. Update your UI. + $.ajax ({ + type: 'POST', + url: url['login'], + data: {assertion: assertion}, + success: function(res, status, xhr) { + if (res.status === 'failure') { + openNotification(res.reason, 'bad'); + } else if (res.status === 'okay') { + location.href = url['index']; + } + }, + error: function(res, status, xhr) { + // alert(res); + } + }); + }, + onlogout: function() { + // A user has logged out! Here you need to: + // Tear down the user's session by redirecting the user or making a call to your backend. + // Also, make sure loggedInUser will get set to null on the next page load. + // (That's a literal JavaScript null. Not false, 0, or undefined. null.) + $.ajax ({ + type: 'POST', + url: url['logout'], + success: function(res, status, xhr) { + location.href = url['index']; + }, + error: function(res, status, xhr) { + // alert(res); + } + }); + } + }); +} + +if (document.readyState && document.readyState !== 'loading') { + if (window.console) { + console.log('FreshRSS (Persona) immediate init…'); + } + init_persona(); +} else if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', function () { + if (window.console) { + console.log('FreshRSS (Persona) waiting for DOMContentLoaded…'); + } + init_persona(); + }, false); +} -- cgit v1.2.3 From dbf57266b297c3f831602ec4f451c27a5ad71e6b Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 7 Oct 2014 16:58:11 +0200 Subject: Reset auth system comes back! It has moved to authController. --- app/Controllers/authController.php | 68 ++++++++++++++++++++++++++++++++++++++ app/views/auth/personaLogin.phtml | 2 +- app/views/auth/reset.phtml | 33 ++++++++++++++++++ 3 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 app/views/auth/reset.phtml diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index 2b67e34b8..e30fa4b72 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -179,4 +179,72 @@ class FreshRSS_auth_Controller extends Minz_ActionController { Minz_Request::good(_t('disconnected'), array('c' => 'index', 'a' => 'index')); } + + /** + * This action resets the authentication system. + * + * After reseting, form auth is set by default. + */ + public function resetAction() { + Minz_View::prependTitle(_t('auth_reset') . ' · '); + + 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! + 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; + } + + invalidateHttpCache(); + + if (Minz_Request::isPost()) { + $nonce = Minz_Session::param('nonce'); + $username = Minz_Request::param('username', ''); + $challenge = Minz_Request::param('challenge', ''); + + $ok = FreshRSS_FormAuth::checkCredentials( + $username, $conf->passwordHash, $nonce, $challenge + ); + + if ($ok) { + Minz_Configuration::_authType('form'); + $ok = Minz_Configuration::writeFile(); + + if ($ok) { + Minz_Request::good(_t('auth_form_set')); + } else { + Minz_Request::bad(_t('auth_form_not_set'), + array('c' => 'auth', 'a' => 'reset')); + } + } else { + Minz_Log::warning('Password mismatch for' . + ' user=' . $username . + ', nonce=' . $nonce . + ', c=' . $challenge); + Minz_Request::bad(_t('invalid_login'), + array('c' => 'auth', 'a' => 'reset')); + } + } + } } diff --git a/app/views/auth/personaLogin.phtml b/app/views/auth/personaLogin.phtml index d62fe5818..dd3e22b52 100644 --- a/app/views/auth/personaLogin.phtml +++ b/app/views/auth/personaLogin.phtml @@ -11,7 +11,7 @@ - +

    diff --git a/app/views/auth/reset.phtml b/app/views/auth/reset.phtml new file mode 100644 index 000000000..e501555c4 --- /dev/null +++ b/app/views/auth/reset.phtml @@ -0,0 +1,33 @@ +
    +

    + + message)) { ?> +

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

    + + + no_form) { ?> +
    +

    +
    + +

    + +
    + + +
    +
    + + +
    + +
    +
    + +
    + + +
    -- cgit v1.2.3 From eb40dbccdb1e0830fcad96d333b242870cc0d0a7 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Thu, 9 Oct 2014 21:44:44 -0400 Subject: Change statistic average I was using the stats and it feels that the stat average was useless in that form since the line is always at the same position no matter what is the value. So I deleted that line and added the average in the title. It is way more useful this way. I updated some translations both on i18n files and on http://i18n.freshrss.org --- app/Models/StatsDAO.php | 2 +- app/i18n/en.php | 6 +++--- app/i18n/fr.php | 6 +++--- app/views/stats/repartition.phtml | 36 +++--------------------------------- 4 files changed, 10 insertions(+), 40 deletions(-) diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 99d4e2148..283d5dcb1 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -237,7 +237,7 @@ SQL; $interval_in_days = $period; } - return round($res['count'] / ($interval_in_days / $period), 2); + return $res['count'] / ($interval_in_days / $period); } /** diff --git a/app/i18n/en.php b/app/i18n/en.php index 9e968998a..ebc25ba0c 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -398,9 +398,9 @@ 'stats_entry_count' => 'Entry count', 'stats_entry_per_category' => 'Entries per category', 'stats_entry_per_day' => 'Entries per day (last 30 days)', - 'stats_entry_per_day_of_week' => 'Per day of week', - 'stats_entry_per_hour' => 'Per hour', - 'stats_entry_per_month' => 'Per month', + 'stats_entry_per_day_of_week' => 'Per day of week (average: %.2f messages)', + 'stats_entry_per_hour' => 'Per hour (average: %.2f messages)', + 'stats_entry_per_month' => 'Per month (average: %.2f messages)', 'stats_entry_repartition' => 'Entries repartition', 'stats_feed_per_category' => 'Feeds per category', 'stats_idle' => 'Idle feeds', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 072094026..220f8b12d 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -398,9 +398,9 @@ 'stats_entry_count' => 'Nombre d’articles', 'stats_entry_per_category' => 'Articles par catégorie', 'stats_entry_per_day' => 'Nombre d’articles par jour (30 derniers jours)', - 'stats_entry_per_day_of_week' => 'Par jour de la semaine', - 'stats_entry_per_hour' => 'Par heure', - 'stats_entry_per_month' => 'Par mois', + 'stats_entry_per_day_of_week' => 'Par jour de la semaine (moyenne : %.2f messages)', + 'stats_entry_per_hour' => 'Par heure (moyenne : %.2f messages)', + 'stats_entry_per_month' => 'Par mois (moyenne : %.2f messages)', 'stats_entry_repartition' => 'Répartition des articles', 'stats_feed_per_category' => 'Flux par catégorie', 'stats_idle' => 'Flux inactifs', diff --git a/app/views/stats/repartition.phtml b/app/views/stats/repartition.phtml index a181ae251..670714707 100644 --- a/app/views/stats/repartition.phtml +++ b/app/views/stats/repartition.phtml @@ -30,17 +30,17 @@
    -

    +

    averageHour); ?>

    -

    +

    averageDayOfWeek); ?>

    -

    +

    averageMonth); ?>

    @@ -56,19 +56,10 @@ 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'), [{ data: repartitionHour ?>, bars: {horizontal: false, show: true} - }, { - data: avg_h, - lines: {show: true}, - label: "averageHour?>", - yaxis: 2 }], { grid: {verticalLines: false}, @@ -81,23 +72,13 @@ 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'), [{ data: repartitionDayOfWeek ?>, bars: {horizontal: false, show: true} - }, { - data: avg_dow, - lines: {show: true}, - label: "averageDayOfWeek?>", - yaxis: 2 }], { grid: {verticalLines: false}, @@ -111,23 +92,13 @@ 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'), [{ data: repartitionMonth ?>, bars: {horizontal: false, show: true} - }, { - data: avg_m, - lines: {show: true}, - label: "averageMonth?>", - yaxis: 2 }], { grid: {verticalLines: false}, @@ -141,7 +112,6 @@ 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 1283e73d08a0441dbf84d7e45ff8c1c42bf188b1 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 14 Oct 2014 20:00:06 +0200 Subject: SimplePie: bug date CEST https://github.com/marienfressinaud/FreshRSS/issues/659 https://github.com/simplepie/simplepie/pull/380 --- lib/SimplePie/SimplePie/Parse/Date.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/SimplePie/SimplePie/Parse/Date.php b/lib/SimplePie/SimplePie/Parse/Date.php index ef800f125..ba7c0703e 100644 --- a/lib/SimplePie/SimplePie/Parse/Date.php +++ b/lib/SimplePie/SimplePie/Parse/Date.php @@ -331,6 +331,7 @@ class SimplePie_Parse_Date 'CCT' => 23400, 'CDT' => -18000, 'CEDT' => 7200, + 'CEST' => 7200, //FreshRSS 'CET' => 3600, 'CGST' => -7200, 'CGT' => -10800, -- cgit v1.2.3 From c5fe3bd6593d0a07c087d1e60ae2e4b8ab5f9fa9 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 16 Oct 2014 15:25:46 +0200 Subject: Reorganize user pages Three pages: - User profil - User management - Authentication --- app/Controllers/authController.php | 60 ++++++++++ app/Controllers/userController.php | 198 +++++++++++++++++++++++++++++++++ app/Controllers/usersController.php | 210 ----------------------------------- app/layout/aside_configure.phtml | 12 +- app/layout/header.phtml | 4 +- app/views/auth/index.phtml | 84 ++++++++++++++ app/views/user/manage.phtml | 76 +++++++++++++ app/views/user/profil.phtml | 59 ++++++++++ app/views/users/index.phtml | 211 ------------------------------------ 9 files changed, 490 insertions(+), 424 deletions(-) create mode 100644 app/Controllers/userController.php delete mode 100644 app/Controllers/usersController.php create mode 100644 app/views/auth/index.phtml create mode 100644 app/views/user/manage.phtml create mode 100644 app/views/user/profil.phtml delete mode 100644 app/views/users/index.phtml diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index e30fa4b72..751ce1f3f 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -4,6 +4,66 @@ * This controller handles action about authentication. */ class FreshRSS_auth_Controller extends Minz_ActionController { + /** + * This action handles authentication management page. + * + * Parameters are: + * - token (default: current token) + * - anon_access (default: false) + * - anon_refresh (default: false) + * - auth_type (default: none) + * - unsafe_autologin (default: false) + * - api_enabled (default: false) + * + * @todo move unsafe_autologin in an extension. + */ + public function indexAction() { + if (!FreshRSS_Auth::hasAccess('admin')) { + Minz_Error::error(403, + array('error' => array(_t('access_denied')))); + } + + if (Minz_Request::isPost()) { + $ok = true; + + $current_token = $this->view->conf->token; + $token = Minz_Request::param('token', $current_token); + $this->view->conf->_token($token); + $ok &= $this->view->conf->save(); + + $anon = Minz_Request::param('anon_access', false); + $anon = ((bool)$anon) && ($anon !== 'no'); + $anon_refresh = Minz_Request::param('anon_refresh', false); + $anon_refresh = ((bool)$anon_refresh) && ($anon_refresh !== 'no'); + $auth_type = Minz_Request::param('auth_type', 'none'); + $unsafe_autologin = Minz_Request::param('unsafe_autologin', false); + $api_enabled = Minz_Request::param('api_enabled', false); + if ($anon != Minz_Configuration::allowAnonymous() || + $auth_type != Minz_Configuration::authType() || + $anon_refresh != Minz_Configuration::allowAnonymousRefresh() || + $unsafe_autologin != Minz_Configuration::unsafeAutologinEnabled() || + $api_enabled != Minz_Configuration::apiEnabled()) { + + Minz_Configuration::_authType($auth_type); + Minz_Configuration::_allowAnonymous($anon); + Minz_Configuration::_allowAnonymousRefresh($anon_refresh); + Minz_Configuration::_enableAutologin($unsafe_autologin); + Minz_Configuration::_enableApi($api_enabled); + $ok &= Minz_Configuration::writeFile(); + } + + invalidateHttpCache(); + + if ($ok) { + Minz_Request::good('configuration_updated', + array('c' => 'auth', 'a' => 'index')); + } else { + Minz_Request::bad('error_occurred', + array('c' => 'auth', 'a' => 'index')); + } + } + } + /** * This action handles the login page. * diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php new file mode 100644 index 000000000..c516246c9 --- /dev/null +++ b/app/Controllers/userController.php @@ -0,0 +1,198 @@ + array(_t('access_denied'))) + ); + } + } + + /** + * This action displays the user profil page. + */ + public function profilAction() { + Minz_View::prependTitle(_t('users.profil') . ' · '); + + if (Minz_Request::isPost()) { + $ok = true; + + $passwordPlain = Minz_Request::param('passwordPlain', '', true); + if ($passwordPlain != '') { + Minz_Request::_param('passwordPlain'); //Discard plain-text password ASAP + $_POST['passwordPlain'] = ''; + if (!function_exists('password_hash')) { + include_once(LIB_PATH . '/password_compat.php'); + } + $passwordHash = password_hash($passwordPlain, PASSWORD_BCRYPT, array('cost' => self::BCRYPT_COST)); + $passwordPlain = ''; + $passwordHash = preg_replace('/^\$2[xy]\$/', '\$2a\$', $passwordHash); //Compatibility with bcrypt.js + $ok &= ($passwordHash != ''); + $this->view->conf->_passwordHash($passwordHash); + } + Minz_Session::_param('passwordHash', $this->view->conf->passwordHash); + + $passwordPlain = Minz_Request::param('apiPasswordPlain', '', true); + if ($passwordPlain != '') { + if (!function_exists('password_hash')) { + include_once(LIB_PATH . '/password_compat.php'); + } + $passwordHash = password_hash($passwordPlain, PASSWORD_BCRYPT, array('cost' => self::BCRYPT_COST)); + $passwordPlain = ''; + $passwordHash = preg_replace('/^\$2[xy]\$/', '\$2a\$', $passwordHash); //Compatibility with bcrypt.js + $ok &= ($passwordHash != ''); + $this->view->conf->_apiPasswordHash($passwordHash); + } + + // TODO: why do we need of hasAccess here? + if (FreshRSS_Auth::hasAccess('admin')) { + $this->view->conf->_mail_login(Minz_Request::param('mail_login', '', true)); + } + $email = $this->view->conf->mail_login; + Minz_Session::_param('mail', $email); + + $ok &= $this->view->conf->save(); + + if ($email != '') { + $personaFile = DATA_PATH . '/persona/' . $email . '.txt'; + @unlink($personaFile); + $ok &= (file_put_contents($personaFile, Minz_Session::param('currentUser', '_')) !== false); + } + + if ($ok) { + Minz_Request::good('users.profil.updated', + array('c' => 'user', 'a' => 'profil')); + } else { + Minz_Request::bad('error_occurred', + array('c' => 'user', 'a' => 'profil')); + } + } + } + + /** + * This action displays the user management page. + */ + public function manageAction() { + Minz_View::prependTitle(_t('users.manage') . ' · '); + } + + public function createAction() { + if (Minz_Request::isPost() && FreshRSS_Auth::hasAccess('admin')) { + $db = Minz_Configuration::dataBase(); + require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php'); + + $new_user_language = Minz_Request::param('new_user_language', $this->view->conf->language); + if (!in_array($new_user_language, $this->view->conf->availableLanguages())) { + $new_user_language = $this->view->conf->language; + } + + $new_user_name = Minz_Request::param('new_user_name'); + $ok = ($new_user_name != '') && ctype_alnum($new_user_name); + + if ($ok) { + $ok &= (strcasecmp($new_user_name, Minz_Configuration::defaultUser()) !== 0); //It is forbidden to alter the default user + + $ok &= !in_array(strtoupper($new_user_name), array_map('strtoupper', listUsers())); //Not an existing user, case-insensitive + + $configPath = DATA_PATH . '/' . $new_user_name . '_user.php'; + $ok &= !file_exists($configPath); + } + if ($ok) { + + $passwordPlain = Minz_Request::param('new_user_passwordPlain', '', true); + $passwordHash = ''; + if ($passwordPlain != '') { + Minz_Request::_param('new_user_passwordPlain'); //Discard plain-text password ASAP + $_POST['new_user_passwordPlain'] = ''; + if (!function_exists('password_hash')) { + include_once(LIB_PATH . '/password_compat.php'); + } + $passwordHash = password_hash($passwordPlain, PASSWORD_BCRYPT, array('cost' => self::BCRYPT_COST)); + $passwordPlain = ''; + $passwordHash = preg_replace('/^\$2[xy]\$/', '\$2a\$', $passwordHash); //Compatibility with bcrypt.js + $ok &= ($passwordHash != ''); + } + if (empty($passwordHash)) { + $passwordHash = ''; + } + + $new_user_email = filter_var($_POST['new_user_email'], FILTER_VALIDATE_EMAIL); + if (empty($new_user_email)) { + $new_user_email = ''; + } else { + $personaFile = DATA_PATH . '/persona/' . $new_user_email . '.txt'; + @unlink($personaFile); + $ok &= (file_put_contents($personaFile, $new_user_name) !== false); + } + } + if ($ok) { + $config_array = array( + 'language' => $new_user_language, + 'passwordHash' => $passwordHash, + 'mail_login' => $new_user_email, + ); + $ok &= (file_put_contents($configPath, "createUser($new_user_name); + } + invalidateHttpCache(); + + $notif = array( + 'type' => $ok ? 'good' : 'bad', + 'content' => _t($ok ? 'user_created' : 'error_occurred', $new_user_name) + ); + Minz_Session::_param('notification', $notif); + } + + Minz_Request::forward(array('c' => 'user', 'a' => 'manage'), true); + } + + public function deleteAction() { + if (Minz_Request::isPost() && FreshRSS_Auth::hasAccess('admin')) { + $db = Minz_Configuration::dataBase(); + require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php'); + + $username = Minz_Request::param('username'); + $ok = ctype_alnum($username); + + if ($ok) { + $ok &= (strcasecmp($username, Minz_Configuration::defaultUser()) !== 0); //It is forbidden to delete the default user + } + if ($ok) { + $configPath = DATA_PATH . '/' . $username . '_user.php'; + $ok &= file_exists($configPath); + } + if ($ok) { + $userDAO = new FreshRSS_UserDAO(); + $ok &= $userDAO->deleteUser($username); + $ok &= unlink($configPath); + //TODO: delete Persona file + } + invalidateHttpCache(); + + $notif = array( + 'type' => $ok ? 'good' : 'bad', + 'content' => _t($ok ? 'user_deleted' : 'error_occurred', $username) + ); + Minz_Session::_param('notification', $notif); + } + + Minz_Request::forward(array('c' => 'user', 'a' => 'manage'), true); + } +} diff --git a/app/Controllers/usersController.php b/app/Controllers/usersController.php deleted file mode 100644 index 11862ce27..000000000 --- a/app/Controllers/usersController.php +++ /dev/null @@ -1,210 +0,0 @@ - array(_t('access_denied'))) - ); - } - } - - /** - * This action display the user configuration page - */ - public function indexAction() { - Minz_View::prependTitle(_t('users') . ' · '); - } - - public function authAction() { - if (Minz_Request::isPost()) { - $ok = true; - - $passwordPlain = Minz_Request::param('passwordPlain', '', true); - if ($passwordPlain != '') { - Minz_Request::_param('passwordPlain'); //Discard plain-text password ASAP - $_POST['passwordPlain'] = ''; - if (!function_exists('password_hash')) { - include_once(LIB_PATH . '/password_compat.php'); - } - $passwordHash = password_hash($passwordPlain, PASSWORD_BCRYPT, array('cost' => self::BCRYPT_COST)); - $passwordPlain = ''; - $passwordHash = preg_replace('/^\$2[xy]\$/', '\$2a\$', $passwordHash); //Compatibility with bcrypt.js - $ok &= ($passwordHash != ''); - $this->view->conf->_passwordHash($passwordHash); - } - Minz_Session::_param('passwordHash', $this->view->conf->passwordHash); - - $passwordPlain = Minz_Request::param('apiPasswordPlain', '', true); - if ($passwordPlain != '') { - if (!function_exists('password_hash')) { - include_once(LIB_PATH . '/password_compat.php'); - } - $passwordHash = password_hash($passwordPlain, PASSWORD_BCRYPT, array('cost' => self::BCRYPT_COST)); - $passwordPlain = ''; - $passwordHash = preg_replace('/^\$2[xy]\$/', '\$2a\$', $passwordHash); //Compatibility with bcrypt.js - $ok &= ($passwordHash != ''); - $this->view->conf->_apiPasswordHash($passwordHash); - } - - if (FreshRSS_Auth::hasAccess('admin')) { - $this->view->conf->_mail_login(Minz_Request::param('mail_login', '', true)); - } - $email = $this->view->conf->mail_login; - Minz_Session::_param('mail', $email); - - $ok &= $this->view->conf->save(); - - if ($email != '') { - $personaFile = DATA_PATH . '/persona/' . $email . '.txt'; - @unlink($personaFile); - $ok &= (file_put_contents($personaFile, Minz_Session::param('currentUser', '_')) !== false); - } - - if (FreshRSS_Auth::hasAccess('admin')) { - $current_token = $this->view->conf->token; - $token = Minz_Request::param('token', $current_token); - $this->view->conf->_token($token); - $ok &= $this->view->conf->save(); - - $anon = Minz_Request::param('anon_access', false); - $anon = ((bool)$anon) && ($anon !== 'no'); - $anon_refresh = Minz_Request::param('anon_refresh', false); - $anon_refresh = ((bool)$anon_refresh) && ($anon_refresh !== 'no'); - $auth_type = Minz_Request::param('auth_type', 'none'); - $unsafe_autologin = Minz_Request::param('unsafe_autologin', false); - $api_enabled = Minz_Request::param('api_enabled', false); - if ($anon != Minz_Configuration::allowAnonymous() || - $auth_type != Minz_Configuration::authType() || - $anon_refresh != Minz_Configuration::allowAnonymousRefresh() || - $unsafe_autologin != Minz_Configuration::unsafeAutologinEnabled() || - $api_enabled != Minz_Configuration::apiEnabled()) { - - Minz_Configuration::_authType($auth_type); - Minz_Configuration::_allowAnonymous($anon); - Minz_Configuration::_allowAnonymousRefresh($anon_refresh); - Minz_Configuration::_enableAutologin($unsafe_autologin); - Minz_Configuration::_enableApi($api_enabled); - $ok &= Minz_Configuration::writeFile(); - } - } - - invalidateHttpCache(); - - $notif = array( - 'type' => $ok ? 'good' : 'bad', - 'content' => _t($ok ? 'configuration_updated' : 'error_occurred') - ); - Minz_Session::_param('notification', $notif); - } - Minz_Request::forward(array('c' => 'users', 'a' => 'index'), true); - } - - public function createAction() { - if (Minz_Request::isPost() && FreshRSS_Auth::hasAccess('admin')) { - $db = Minz_Configuration::dataBase(); - require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php'); - - $new_user_language = Minz_Request::param('new_user_language', $this->view->conf->language); - if (!in_array($new_user_language, $this->view->conf->availableLanguages())) { - $new_user_language = $this->view->conf->language; - } - - $new_user_name = Minz_Request::param('new_user_name'); - $ok = ($new_user_name != '') && ctype_alnum($new_user_name); - - if ($ok) { - $ok &= (strcasecmp($new_user_name, Minz_Configuration::defaultUser()) !== 0); //It is forbidden to alter the default user - - $ok &= !in_array(strtoupper($new_user_name), array_map('strtoupper', listUsers())); //Not an existing user, case-insensitive - - $configPath = DATA_PATH . '/' . $new_user_name . '_user.php'; - $ok &= !file_exists($configPath); - } - if ($ok) { - - $passwordPlain = Minz_Request::param('new_user_passwordPlain', '', true); - $passwordHash = ''; - if ($passwordPlain != '') { - Minz_Request::_param('new_user_passwordPlain'); //Discard plain-text password ASAP - $_POST['new_user_passwordPlain'] = ''; - if (!function_exists('password_hash')) { - include_once(LIB_PATH . '/password_compat.php'); - } - $passwordHash = password_hash($passwordPlain, PASSWORD_BCRYPT, array('cost' => self::BCRYPT_COST)); - $passwordPlain = ''; - $passwordHash = preg_replace('/^\$2[xy]\$/', '\$2a\$', $passwordHash); //Compatibility with bcrypt.js - $ok &= ($passwordHash != ''); - } - if (empty($passwordHash)) { - $passwordHash = ''; - } - - $new_user_email = filter_var($_POST['new_user_email'], FILTER_VALIDATE_EMAIL); - if (empty($new_user_email)) { - $new_user_email = ''; - } else { - $personaFile = DATA_PATH . '/persona/' . $new_user_email . '.txt'; - @unlink($personaFile); - $ok &= (file_put_contents($personaFile, $new_user_name) !== false); - } - } - if ($ok) { - $config_array = array( - 'language' => $new_user_language, - 'passwordHash' => $passwordHash, - 'mail_login' => $new_user_email, - ); - $ok &= (file_put_contents($configPath, "createUser($new_user_name); - } - invalidateHttpCache(); - - $notif = array( - 'type' => $ok ? 'good' : 'bad', - 'content' => _t($ok ? 'user_created' : 'error_occurred', $new_user_name) - ); - Minz_Session::_param('notification', $notif); - } - Minz_Request::forward(array('c' => 'users', 'a' => 'index'), true); - } - - public function deleteAction() { - if (Minz_Request::isPost() && FreshRSS_Auth::hasAccess('admin')) { - $db = Minz_Configuration::dataBase(); - require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php'); - - $username = Minz_Request::param('username'); - $ok = ctype_alnum($username); - - if ($ok) { - $ok &= (strcasecmp($username, Minz_Configuration::defaultUser()) !== 0); //It is forbidden to delete the default user - } - if ($ok) { - $configPath = DATA_PATH . '/' . $username . '_user.php'; - $ok &= file_exists($configPath); - } - if ($ok) { - $userDAO = new FreshRSS_UserDAO(); - $ok &= $userDAO->deleteUser($username); - $ok &= unlink($configPath); - //TODO: delete Persona file - } - invalidateHttpCache(); - - $notif = array( - 'type' => $ok ? 'good' : 'bad', - 'content' => _t($ok ? 'user_deleted' : 'error_occurred', $username) - ); - Minz_Session::_param('notification', $notif); - } - Minz_Request::forward(array('c' => 'users', 'a' => 'index'), true); - } -} diff --git a/app/layout/aside_configure.phtml b/app/layout/aside_configure.phtml index 59846a7c8..7a9d0d839 100644 --- a/app/layout/aside_configure.phtml +++ b/app/layout/aside_configure.phtml @@ -19,10 +19,18 @@
  • -
  • - +
  • +
  • +
  • + +
  • +
  • + +
  • diff --git a/app/layout/header.phtml b/app/layout/header.phtml index deb21edc9..7e7c1b477 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -63,8 +63,10 @@ if (Minz_Configuration::canLogIn()) {
  • -
  • +
  • +
  • +
  • diff --git a/app/views/auth/index.phtml b/app/views/auth/index.phtml new file mode 100644 index 000000000..c37a7aef6 --- /dev/null +++ b/app/views/auth/index.phtml @@ -0,0 +1,84 @@ +partial('aside_configure'); ?> + +
    + + +
    + + +
    + +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + + +
    + + conf->token; ?> +
    + /> + +
    +
    + + +
    +
    + +
    +
    + +
    +
    + + +
    +
    + +
    diff --git a/app/views/user/manage.phtml b/app/views/user/manage.phtml new file mode 100644 index 000000000..03746cabb --- /dev/null +++ b/app/views/user/manage.phtml @@ -0,0 +1,76 @@ +partial('aside_configure'); ?> + +
    + + +
    + + +
    + +
    + +
    +
    + +
    +
    + +
    +
    + + +
    + + +
    + +
    + +
    +
    + +
    + +
    + +
    +
    + +
    + +
    +
    + + +
    + +
    +
    + +
    + + conf->mail_login; ?> +
    + +
    +
    + +
    +
    + + +
    +
    + + +
    diff --git a/app/views/user/profil.phtml b/app/views/user/profil.phtml new file mode 100644 index 000000000..a74c7b6f8 --- /dev/null +++ b/app/views/user/profil.phtml @@ -0,0 +1,59 @@ +partial('aside_configure'); ?> + +
    + + +
    + + +
    + +
    + + +
    +
    + +
    + +
    +
    + /> + +
    + +
    +
    + + +
    + +
    +
    + /> + +
    +
    +
    + + +
    + + conf->mail_login; ?> +
    + placeholder="alice@example.net" /> + +
    +
    + +
    +
    + + +
    +
    + +
    diff --git a/app/views/users/index.phtml b/app/views/users/index.phtml deleted file mode 100644 index f1cdf01a3..000000000 --- a/app/views/users/index.phtml +++ /dev/null @@ -1,211 +0,0 @@ -partial('aside_configure'); ?> - -
    - - -
    - - -
    - -
    - - -
    -
    - -
    - -
    -
    - /> - -
    - -
    -
    - - -
    - -
    -
    - /> - -
    -
    -
    - - -
    - - conf->mail_login; ?> -
    - placeholder="alice@example.net" /> - -
    -
    - -
    -
    - - -
    -
    - - - - - -
    - -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - - -
    - - conf->token; ?> -
    - /> - -
    -
    - - -
    -
    - -
    -
    - -
    -
    - - -
    -
    - - -
    - - -
    - -
    - -
    -
    - -
    -
    - -
    -
    - - -
    - - -
    - -
    - -
    -
    - -
    - -
    - -
    -
    - -
    - -
    -
    - - -
    - -
    -
    - -
    - - conf->mail_login; ?> -
    - -
    -
    - -
    -
    - - -
    -
    - - - - -
    -- cgit v1.2.3 From 2796cc9ae559842a90fa15cba65c94a11b29195e Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 16 Oct 2014 16:43:37 +0200 Subject: User list load a new page Beginning of more options for administrator! --- app/Controllers/userController.php | 4 ++++ app/views/stats/repartition.phtml | 2 +- app/views/user/manage.phtml | 41 +++++++++++++++++++------------------- p/scripts/main.js | 2 +- 4 files changed, 26 insertions(+), 23 deletions(-) diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index c516246c9..00b51cc3d 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -88,6 +88,10 @@ class FreshRSS_user_Controller extends Minz_ActionController { */ public function manageAction() { Minz_View::prependTitle(_t('users.manage') . ' · '); + + $this->view->current_user = Minz_Request::param( + 'u', Minz_Session::param('currentUser', '_') + ); } public function createAction() { diff --git a/app/views/stats/repartition.phtml b/app/views/stats/repartition.phtml index 670714707..32268a546 100644 --- a/app/views/stats/repartition.phtml +++ b/app/views/stats/repartition.phtml @@ -5,7 +5,7 @@

    - categories as $category) { $feeds = $category->feeds(); diff --git a/app/views/user/manage.phtml b/app/views/user/manage.phtml index 03746cabb..fb569872b 100644 --- a/app/views/user/manage.phtml +++ b/app/views/user/manage.phtml @@ -3,27 +3,6 @@
    -
    - - -
    - -
    - -
    -
    - -
    -
    - -
    -
    - -
    @@ -71,6 +50,26 @@
    + + +
    + +
    + +
    + +
    +
    + +
    +
    + +
    +
    diff --git a/p/scripts/main.js b/p/scripts/main.js index 77e1e3f77..1e13ff16a 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1086,7 +1086,7 @@ function init_share_observers() { } function init_stats_observers() { - $('#feed_select').on('change', function(e) { + $('.select-change').on('change', function(e) { redirect($(this).find(':selected').data('url')); }); } -- cgit v1.2.3 From d4ad951b9b686f387056bda8f3fa6ede8d9ca3f1 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 16 Oct 2014 17:08:48 +0200 Subject: Show more information about user when selected --- app/Controllers/userController.php | 19 ++++++++++++++++--- app/Models/Factory.php | 18 +++++++++--------- app/Models/UserDAO.php | 4 ++++ app/views/configure/archiving.phtml | 2 +- app/views/user/manage.phtml | 2 ++ 5 files changed, 32 insertions(+), 13 deletions(-) diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index 00b51cc3d..4a04737f2 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -87,11 +87,24 @@ class FreshRSS_user_Controller extends Minz_ActionController { * This action displays the user management page. */ public function manageAction() { + if (!FreshRSS_Auth::hasAccess('admin')) { + Minz_Error::error(403, + array('error' => array(_t('access_denied')))); + } + Minz_View::prependTitle(_t('users.manage') . ' · '); - $this->view->current_user = Minz_Request::param( - 'u', Minz_Session::param('currentUser', '_') - ); + $userDAO = new FreshRSS_UserDAO(); + + $username = Minz_Request::param('u', Minz_Session::param('currentUser')); + if (!$userDAO->exist($username)) { + $username = Minz_Session::param('currentUser'); + } + $this->view->current_user = $username; + + $entryDAO = FreshRSS_Factory::createEntryDao($this->view->current_user); + $this->view->nb_articles = $entryDAO->count(); + $this->view->size_user = $entryDAO->size(); } public function createAction() { diff --git a/app/Models/Factory.php b/app/Models/Factory.php index 08569b2e2..93f4552f7 100644 --- a/app/Models/Factory.php +++ b/app/Models/Factory.php @@ -2,30 +2,30 @@ class FreshRSS_Factory { - public static function createFeedDao() { + public static function createFeedDao($username = null) { $db = Minz_Configuration::dataBase(); if ($db['type'] === 'sqlite') { - return new FreshRSS_FeedDAOSQLite(); + return new FreshRSS_FeedDAOSQLite($username); } else { - return new FreshRSS_FeedDAO(); + return new FreshRSS_FeedDAO($username); } } - public static function createEntryDao() { + public static function createEntryDao($username = null) { $db = Minz_Configuration::dataBase(); if ($db['type'] === 'sqlite') { - return new FreshRSS_EntryDAOSQLite(); + return new FreshRSS_EntryDAOSQLite($username); } else { - return new FreshRSS_EntryDAO(); + return new FreshRSS_EntryDAO($username); } } - public static function createStatsDAO() { + public static function createStatsDAO($username = null) { $db = Minz_Configuration::dataBase(); if ($db['type'] === 'sqlite') { - return new FreshRSS_StatsDAOSQLite(); + return new FreshRSS_StatsDAOSQLite($username); } else { - return new FreshRSS_StatsDAO(); + return new FreshRSS_StatsDAO($username); } } diff --git a/app/Models/UserDAO.php b/app/Models/UserDAO.php index 15215258c..85b45c4a7 100644 --- a/app/Models/UserDAO.php +++ b/app/Models/UserDAO.php @@ -53,4 +53,8 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { } } } + + public function exist($username) { + return file_exists(DATA_PATH . '/' . $username . '_user.php'); + } } diff --git a/app/views/configure/archiving.phtml b/app/views/configure/archiving.phtml index adbfdb77e..8f424c126 100644 --- a/app/views/configure/archiving.phtml +++ b/app/views/configure/archiving.phtml @@ -60,7 +60,7 @@

    -

    nb_total), ' ', _t('articles'), ', ', formatBytes($this->size_user); ?>

    +

    nb_total)), ' — ', formatBytes($this->size_user); ?>

    diff --git a/app/views/user/manage.phtml b/app/views/user/manage.phtml index fb569872b..65e60add5 100644 --- a/app/views/user/manage.phtml +++ b/app/views/user/manage.phtml @@ -63,6 +63,8 @@ + +

    nb_articles)), ', ', formatBytes($this->size_user); ?>

    -- cgit v1.2.3 From 5797344aff9ceebbdeb6e49305f3984a5c89f82c Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 16 Oct 2014 17:15:51 +0200 Subject: Fix a bug to get size of user (SQLite) --- app/Controllers/userController.php | 3 ++- app/Models/EntryDAOSQLite.php | 2 +- lib/Minz/ModelPdo.php | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index 4a04737f2..d5c90a382 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -94,14 +94,15 @@ class FreshRSS_user_Controller extends Minz_ActionController { Minz_View::prependTitle(_t('users.manage') . ' · '); + // Get the correct current user. $userDAO = new FreshRSS_UserDAO(); - $username = Minz_Request::param('u', Minz_Session::param('currentUser')); if (!$userDAO->exist($username)) { $username = Minz_Session::param('currentUser'); } $this->view->current_user = $username; + // Get information about the current user. $entryDAO = FreshRSS_Factory::createEntryDao($this->view->current_user); $this->view->nb_articles = $entryDAO->count(); $this->view->size_user = $entryDAO->size(); diff --git a/app/Models/EntryDAOSQLite.php b/app/Models/EntryDAOSQLite.php index 66078aca9..4a3fe24a2 100644 --- a/app/Models/EntryDAOSQLite.php +++ b/app/Models/EntryDAOSQLite.php @@ -124,6 +124,6 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { } public function size($all = false) { - return @filesize(DATA_PATH . '/' . Minz_Session::param('currentUser', '_') . '.sqlite'); + return @filesize(DATA_PATH . '/' . $this->current_user . '.sqlite'); } } diff --git a/lib/Minz/ModelPdo.php b/lib/Minz/ModelPdo.php index 66127ea22..827c89c69 100644 --- a/lib/Minz/ModelPdo.php +++ b/lib/Minz/ModelPdo.php @@ -24,6 +24,7 @@ class Minz_ModelPdo { */ protected $bd; + protected $current_user; protected $prefix; public function dbType() { @@ -46,6 +47,7 @@ class Minz_ModelPdo { if ($currentUser === null) { $currentUser = Minz_Session::param('currentUser', '_'); } + $this->current_user = $currentUser; try { $type = $db['type']; -- cgit v1.2.3 From 74be86d7e817bcccdc0052c54fefdc8379d9fe7f Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 17 Oct 2014 09:33:35 +0200 Subject: Reorganise menus (aside and header) --- app/layout/aside_configure.phtml | 2 +- app/layout/header.phtml | 3 ++- lib/lib_opml.php | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/layout/aside_configure.phtml b/app/layout/aside_configure.phtml index 7a9d0d839..2e2b87203 100644 --- a/app/layout/aside_configure.phtml +++ b/app/layout/aside_configure.phtml @@ -18,12 +18,12 @@
  • -
  • +
  • diff --git a/app/layout/header.phtml b/app/layout/header.phtml index 7e7c1b477..c680cbcdc 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -62,9 +62,10 @@ if (Minz_Configuration::canLogIn()) {
  • -
  • +
  • +
  • diff --git a/lib/lib_opml.php b/lib/lib_opml.php index 16a9921ea..f320335bb 100644 --- a/lib/lib_opml.php +++ b/lib/lib_opml.php @@ -101,6 +101,7 @@ function libopml_parse_string($xml) { // First, we get all "head" elements. Head is required but its sub-elements // are optional. + // TODO: test head exists! foreach ($opml->head->children() as $key => $value) { if (in_array($key, unserialize(HEAD_ELEMENTS), true)) { $array['head'][$key] = (string)$value; @@ -114,6 +115,7 @@ function libopml_parse_string($xml) { // Then, we get body oulines. Body must contain at least one outline // element. $at_least_one_outline = false; + // TODO: test body exists! foreach ($opml->body->children() as $key => $value) { if ($key === 'outline') { $at_least_one_outline = true; -- cgit v1.2.3 From ce0984e102f5ce7d07277425595dad74193d4528 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 17 Oct 2014 16:23:07 +0200 Subject: Fix i18n --- app/i18n/en.php | 28 +++++++++++++++++----------- app/i18n/fr.php | 32 +++++++++++++++++++------------- app/layout/aside_configure.phtml | 8 ++++---- app/layout/header.phtml | 10 +++++----- app/views/configure/archiving.phtml | 19 ++++++++++++------- app/views/user/manage.phtml | 4 +++- 6 files changed, 60 insertions(+), 41 deletions(-) diff --git a/app/i18n/en.php b/app/i18n/en.php index ebc25ba0c..f65576ea3 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -9,6 +9,7 @@ 'add_category' => 'Add a category', 'add_query' => 'Add a query', 'add_rss_feed' => 'Add a RSS feed', + 'admin.users.articles_and_size' => '%d articles (%s)', 'administration' => 'Manage', 'advanced' => 'Advanced', 'after_onread' => 'After “mark all as read”,', @@ -18,8 +19,8 @@ 'all_feeds' => 'All feeds', 'already_subscribed' => 'You have already subscribed to %s', 'api_enabled' => 'Allow API access (required for mobile apps)', - 'apr' => 'apr', 'Apr' => '\\A\\p\\r\\i\\l', + 'apr' => 'apr', 'april' => 'Apr', 'archiving_configuration' => 'Archiving', 'archiving_configuration_help' => 'More options are available in the individual stream settings', @@ -34,8 +35,8 @@ 'article_viewed' => 'when article is viewed', 'ask_empty' => 'Clear?', 'attention' => 'Attention!', - 'aug' => 'aug', 'Aug' => '\\A\\u\\g\\u\\s\\t', + 'aug' => 'aug', 'august' => 'Aug', 'author' => 'Author', 'auth_form' => 'Web form (traditional, requires JavaScript)', @@ -98,10 +99,11 @@ 'choose_language' => 'Choose a language for FreshRSS', 'clear_logs' => 'Clear the logs', 'collapse_article' => 'Collapse', + 'conf.users.articles_and_size' => '%d articles (%s)', 'configuration' => 'Configuration', 'configuration_updated' => 'Configuration has been updated', 'confirm_action' => 'Are you sure you want to perform this action? It cannot be cancelled!', - 'confirm_action_feed_cat' => 'Are you sure you want to perform this action? You may lost related favorites and user queries. It cannot be cancelled!', + 'confirm_action_feed_cat' => 'Are you sure you want to perform this action? You will lose related favorites and user queries. It cannot be cancelled!', 'congratulations' => 'Congratulations!', 'content_width' => 'Content width', 'create' => 'Create', @@ -116,8 +118,8 @@ 'current_user' => 'Current user', 'damn' => 'Damn!', 'data_is_ok' => 'Permissions on data directory are good', - 'Dec' => '\\D\\e\\c\\e\\m\\b\\e\\r', 'dec' => 'dec', + 'Dec' => '\\D\\e\\c\\e\\m\\b\\e\\r', 'december' => 'Dec', 'default_category' => 'Uncategorized', 'default_user' => 'Username of the default user (maximum 16 alphanumeric characters)', @@ -182,6 +184,10 @@ 'freshrss_installation' => 'Installation · FreshRSS', 'fri' => 'Fri', 'g+' => 'Google+', + 'gen.menu.admin' => 'Administration', + 'gen.menu.authentication' => 'Authentication', + 'gen.menu.manage_users' => 'Manage users', + 'gen.menu.profil' => 'Profil', 'general_configuration' => 'General configuration', 'general_conf_is_ok' => 'General configuration has been saved.', 'github_or_email' => 'on Github or by mail', @@ -207,18 +213,18 @@ 'invalid_login' => 'Login is invalid', 'invalid_url' => 'URL %s is invalid', 'is_admin' => 'is administrator', - 'jan' => 'jan', 'Jan' => '\\J\\a\\n\\u\\a\\r\\y', + 'jan' => 'jan', 'january' => 'Jan', 'javascript_for_shortcuts' => 'JavaScript must be enabled in order to use shortcuts', 'javascript_is_better' => 'FreshRSS is more pleasant with JavaScript enabled', 'javascript_should_be_activated' => 'JavaScript must be enabled', - 'Jul' => '\\J\\u\\l\\y', 'jul' => 'jul', + 'Jul' => '\\J\\u\\l\\y', 'july' => 'Jul', 'jump_next' => 'jump to next unread sibling (feed or category)', - 'Jun' => '\\J\\u\\n\\e', 'jun' => 'jun', + 'Jun' => '\\J\\u\\n\\e', 'june' => 'Jun', 'keep_history' => 'Minimum number of articles to keep', 'keep_logged_in' => 'Keep me logged in (1 month)', @@ -244,16 +250,16 @@ 'logs_empty' => 'Log file is empty', 'log_is_ok' => 'Permissions on logs directory are good', 'main_stream' => 'Main stream', - 'Mar' => '\\M\\a\\r\\c\\h', 'mar' => 'mar', + 'Mar' => '\\M\\a\\r\\c\\h', 'march' => 'Mar', 'mark_all_read' => 'Mark all as read', 'mark_cat_read' => 'Mark category as read', 'mark_favorite' => 'Mark as favourite', 'mark_feed_read' => 'Mark feed as read', 'mark_read' => 'Mark as read', - 'May' => '\\M\\a\\y', 'may' => 'May', + 'May' => '\\M\\a\\y', 'minz_is_nok' => 'You lack the Minz framework. You should execute build.sh script or download it on Github and install in %s directory the content of its /lib directory.', 'minz_is_ok' => 'You have the Minz framework', 'mon' => 'Mon', @@ -274,8 +280,8 @@ 'not_read' => '%d unread', 'not_reads' => '%d unread', 'not_yet_implemented' => 'Not yet implemented', - 'nov' => 'nov', 'Nov' => '\\N\\o\\v\\e\\m\\b\\e\\r', + 'nov' => 'nov', 'november' => 'Nov', 'no_feed_actualized' => 'No RSS feed has been updated', 'no_feed_to_display' => 'There is no article to show.', @@ -291,8 +297,8 @@ 'number_feeds' => '%d feeds', 'n_entries_deleted' => '%d articles have been deleted', 'n_feeds_actualized' => '%d feeds have been updated', - 'oct' => 'oct', 'Oct' => '\\O\\c\\t\\o\\b\\e\\r', + 'oct' => 'oct', 'october' => 'Oct', 'ok' => 'Ok!', 'older_first' => 'Oldest first', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 220f8b12d..ab34eed3e 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -9,6 +9,7 @@ 'add_category' => 'Ajouter une catégorie', 'add_query' => 'Créer un filtre', 'add_rss_feed' => 'Ajouter un flux RSS', + 'admin.users.articles_and_size' => '%d articles (%s)', 'administration' => 'Gérer', 'advanced' => 'Avancé', 'after_onread' => 'Après “marquer tout comme lu”,', @@ -18,8 +19,8 @@ 'all_feeds' => 'Tous les flux', 'already_subscribed' => 'Vous êtes déjà abonné à %s', 'api_enabled' => 'Autoriser l’accès par API (nécessaire pour les applis mobiles)', - 'apr' => 'avr.', 'Apr' => '\\a\\v\\r\\i\\l', + 'apr' => 'avr.', 'april' => 'avril', 'archiving_configuration' => 'Archivage', 'archiving_configuration_help' => 'D’autres options sont disponibles dans la configuration individuelle des flux.', @@ -34,8 +35,8 @@ 'article_viewed' => 'lorsque l’article est affiché', 'ask_empty' => 'Vider ?', 'attention' => 'Attention !', - 'aug' => 'août', 'Aug' => '\\a\\o\\û\\t', + 'aug' => 'août', 'august' => 'août', 'author' => 'Auteur', 'auth_form' => 'Formulaire (traditionnel, requiert JavaScript)', @@ -88,8 +89,8 @@ 'category_empty' => 'Catégorie vide', 'category_name_exists' => 'Une catégorie possède déjà ce nom.', 'category_not_delete_default' => 'Vous ne pouvez pas supprimer la catégorie par défaut !', - 'category_not_exist' => 'Cette catégorie n\'existe pas !', - 'category_no_id' => 'Vous devez préciser l\'id de la catégorie.', + 'category_not_exist' => 'Cette catégorie n’existe pas !', + 'category_no_id' => 'Vous devez préciser l’id de la catégorie.', 'category_no_name' => 'Vous devez préciser un nom pour la catégorie.', 'category_number' => 'Catégorie n°%d', 'category_updated' => 'La catégorie a été mise à jour.', @@ -98,10 +99,11 @@ 'choose_language' => 'Choisissez la langue pour FreshRSS', 'clear_logs' => 'Effacer les logs', 'collapse_article' => 'Refermer', + 'conf.users.articles_and_size' => '%d articles (%s)', 'configuration' => 'Configuration', 'configuration_updated' => 'La configuration a été mise à jour.', 'confirm_action' => 'Êtes-vous sûr(e) de vouloir continuer ? Cette action ne peut être annulée !', - 'confirm_action_feed_cat' => 'Êtes-vous sûr(e) de vouloir continuer ? Vous pourriez perdre les favoris et les filtres associés. Cette action ne peut être annulée !', + 'confirm_action_feed_cat' => 'Êtes-vous sûr(e) de vouloir continuer ? Vous perdrez les favoris et les filtres associés. Cette action ne peut être annulée !', 'congratulations' => 'Félicitations !', 'content_width' => 'Largeur du contenu', 'create' => 'Créer', @@ -116,8 +118,8 @@ 'current_user' => 'Utilisateur actuel', 'damn' => 'Arf !', 'data_is_ok' => 'Les droits sur le répertoire de data sont bons', - 'Dec' => '\\d\\é\\c\\e\\m\\b\\r\\e', 'dec' => 'déc.', + 'Dec' => '\\d\\é\\c\\e\\m\\b\\r\\e', 'december' => 'décembre', 'default_category' => 'Sans catégorie', 'default_user' => 'Nom de l’utilisateur par défaut (16 caractères alphanumériques maximum)', @@ -182,6 +184,10 @@ 'freshrss_installation' => 'Installation · FreshRSS', 'fri' => 'ven.', 'g+' => 'Google+', + 'gen.menu.admin' => 'Administration', + 'gen.menu.authentication' => 'Authentification', + 'gen.menu.manage_users' => 'Gestion des utilisateurs', + 'gen.menu.profil' => 'Profil', 'general_configuration' => 'Configuration générale', 'general_conf_is_ok' => 'La configuration générale a été enregistrée.', 'github_or_email' => 'sur Github ou par courriel', @@ -207,18 +213,18 @@ 'invalid_login' => 'L’identifiant est invalide !', 'invalid_url' => 'L’url %s est invalide.', 'is_admin' => 'est administrateur', - 'jan' => 'jan.', 'Jan' => '\\j\\a\\n\\v\\i\\e\\r', + 'jan' => 'jan.', 'january' => 'janvier', 'javascript_for_shortcuts' => 'Le JavaScript doit être activé pour pouvoir profiter des raccourcis.', 'javascript_is_better' => 'FreshRSS est plus agréable à utiliser avec JavaScript activé', 'javascript_should_be_activated' => 'Le JavaScript doit être activé.', - 'Jul' => '\\j\\u\\i\\l\\l\\e\\t', 'jul' => 'jui.', + 'Jul' => '\\j\\u\\i\\l\\l\\e\\t', 'july' => 'juillet', 'jump_next' => 'sauter au prochain voisin non lu (flux ou catégorie)', - 'Jun' => '\\j\\u\\i\\n', 'jun' => 'juin', + 'Jun' => '\\j\\u\\i\\n', 'june' => 'juin', 'keep_history' => 'Nombre minimum d’articles à conserver', 'keep_logged_in' => 'Rester connecté (1 mois)', @@ -244,16 +250,16 @@ 'logs_empty' => 'Les logs sont vides.', 'log_is_ok' => 'Les droits sur le répertoire des logs sont bons', 'main_stream' => 'Flux principal', - 'Mar' => '\\m\\a\\r\\s', 'mar' => 'mar.', + 'Mar' => '\\m\\a\\r\\s', 'march' => 'mars', 'mark_all_read' => 'Tout marquer comme lu', 'mark_cat_read' => 'Marquer la catégorie comme lue', 'mark_favorite' => 'Mettre en favori', 'mark_feed_read' => 'Marquer le flux comme lu', 'mark_read' => 'Marquer comme lu', - 'May' => '\\m\\a\\i', 'may' => 'mai.', + 'May' => '\\m\\a\\i', 'minz_is_nok' => 'Vous ne disposez pas de la librairie Minz. Vous devriez exécuter le script build.sh ou bien la télécharger sur Github et installer dans le répertoire %s le contenu de son répertoire /lib.', 'minz_is_ok' => 'Vous disposez du framework Minz', 'mon' => 'lun.', @@ -274,8 +280,8 @@ 'not_read' => '%d non lu', 'not_reads' => '%d non lus', 'not_yet_implemented' => 'Pas encore implémenté', - 'nov' => 'nov.', 'Nov' => '\\n\\o\\v\\e\\m\\b\\r\\e', + 'nov' => 'nov.', 'november' => 'novembre', 'no_feed_actualized' => 'Aucun flux n’a pu être mis à jour.', 'no_feed_to_display' => 'Il n’y a aucun article à afficher.', @@ -291,8 +297,8 @@ 'number_feeds' => '%d flux', 'n_entries_deleted' => '%d articles ont été supprimés.', 'n_feeds_actualized' => '%d flux ont été mis à jour.', - 'oct' => 'oct.', 'Oct' => '\\o\\c\\t\\o\\b\\r\\e', + 'oct' => 'oct.', 'october' => 'octobre', 'ok' => 'Ok !', 'older_first' => 'Plus anciens en premier', diff --git a/app/layout/aside_configure.phtml b/app/layout/aside_configure.phtml index 2e2b87203..20446c877 100644 --- a/app/layout/aside_configure.phtml +++ b/app/layout/aside_configure.phtml @@ -20,16 +20,16 @@
  • - +
  • - +
  • - +
  • - +
  • diff --git a/app/layout/header.phtml b/app/layout/header.phtml index c680cbcdc..e848ac4eb 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -62,12 +62,12 @@ if (Minz_Configuration::canLogIn()) {
  • -
  • -
  • +
  • - -
  • -
  • +
  • + +
  • +
  • diff --git a/app/views/configure/archiving.phtml b/app/views/configure/archiving.phtml index 8f424c126..f469d343c 100644 --- a/app/views/configure/archiving.phtml +++ b/app/views/configure/archiving.phtml @@ -58,20 +58,25 @@
    -

    +
    -

    nb_total)), ' — ', formatBytes($this->size_user); ?>

    - - - + nb_total), formatBytes($this->size_user)); ?>
    -

    +
    -

    size_total); ?>

    + size_total); ?> +
    +
    + +
    +
    + + +
    diff --git a/app/views/user/manage.phtml b/app/views/user/manage.phtml index 65e60add5..89c91e06c 100644 --- a/app/views/user/manage.phtml +++ b/app/views/user/manage.phtml @@ -64,7 +64,9 @@ -

    nb_articles)), ', ', formatBytes($this->size_user); ?>

    +

    nb_articles), + formatBytes($this->size_user)); ?>

    -- cgit v1.2.3 From 3bad4d138e5c4a86aa3f88dea3787c3335861ce4 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 17 Oct 2014 16:29:55 +0200 Subject: Fix i18n --- app/i18n/en.php | 4 ++-- app/i18n/fr.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/i18n/en.php b/app/i18n/en.php index f65576ea3..283d28dc6 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -9,7 +9,7 @@ 'add_category' => 'Add a category', 'add_query' => 'Add a query', 'add_rss_feed' => 'Add a RSS feed', - 'admin.users.articles_and_size' => '%d articles (%s)', + 'admin.users.articles_and_size' => '%s articles (%s)', 'administration' => 'Manage', 'advanced' => 'Advanced', 'after_onread' => 'After “mark all as read”,', @@ -99,7 +99,7 @@ 'choose_language' => 'Choose a language for FreshRSS', 'clear_logs' => 'Clear the logs', 'collapse_article' => 'Collapse', - 'conf.users.articles_and_size' => '%d articles (%s)', + 'conf.users.articles_and_size' => '%s articles (%s)', 'configuration' => 'Configuration', 'configuration_updated' => 'Configuration has been updated', 'confirm_action' => 'Are you sure you want to perform this action? It cannot be cancelled!', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index ab34eed3e..0517544d5 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -9,7 +9,7 @@ 'add_category' => 'Ajouter une catégorie', 'add_query' => 'Créer un filtre', 'add_rss_feed' => 'Ajouter un flux RSS', - 'admin.users.articles_and_size' => '%d articles (%s)', + 'admin.users.articles_and_size' => '%s articles (%s)', 'administration' => 'Gérer', 'advanced' => 'Avancé', 'after_onread' => 'Après “marquer tout comme lu”,', @@ -99,7 +99,7 @@ 'choose_language' => 'Choisissez la langue pour FreshRSS', 'clear_logs' => 'Effacer les logs', 'collapse_article' => 'Refermer', - 'conf.users.articles_and_size' => '%d articles (%s)', + 'conf.users.articles_and_size' => '%s articles (%s)', 'configuration' => 'Configuration', 'configuration_updated' => 'La configuration a été mise à jour.', 'confirm_action' => 'Êtes-vous sûr(e) de vouloir continuer ? Cette action ne peut être annulée !', -- cgit v1.2.3 From 7080a32650ab8b19e917d8add944a75cc98381bc Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 20 Oct 2014 11:54:31 +0200 Subject: Add checking installation feature --- app/Controllers/updateController.php | 14 +++++- app/Models/DatabaseDAO.php | 83 ++++++++++++++++++++++++++++++++++++ app/Models/DatabaseDAOSQLite.php | 48 +++++++++++++++++++++ app/Models/Factory.php | 9 ++++ app/SQL/install.sql.mysql.php | 2 - app/SQL/install.sql.sqlite.php | 2 - app/layout/aside_configure.phtml | 7 ++- app/layout/header.phtml | 1 + app/views/update/checkInstall.phtml | 30 +++++++++++++ lib/lib_rss.php | 62 +++++++++++++++++++++++++++ 10 files changed, 252 insertions(+), 6 deletions(-) create mode 100644 app/Models/DatabaseDAO.php create mode 100644 app/Models/DatabaseDAOSQLite.php create mode 100644 app/views/update/checkInstall.phtml diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index 9d1e1ddf5..4ebb11f51 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -12,7 +12,6 @@ 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'; $this->view->check_last_hour = false; @@ -24,6 +23,8 @@ class FreshRSS_update_Controller extends Minz_ActionController { } public function indexAction() { + Minz_View::prependTitle(_t('update_system') . ' · '); + if (file_exists(UPDATE_FILENAME) && !is_writable(FRESHRSS_PATH)) { $this->view->message = array( 'status' => 'bad', @@ -126,4 +127,15 @@ class FreshRSS_update_Controller extends Minz_ActionController { } } } + + /** + * This action displays information about installation. + */ + public function checkInstallAction() { + Minz_View::prependTitle(_t('gen.title.check_install') . ' · '); + + $this->view->status_php = check_install_php(); + $this->view->status_files = check_install_files(); + $this->view->status_database = check_install_database(); + } } diff --git a/app/Models/DatabaseDAO.php b/app/Models/DatabaseDAO.php new file mode 100644 index 000000000..0d85718e3 --- /dev/null +++ b/app/Models/DatabaseDAO.php @@ -0,0 +1,83 @@ +bd->prepare($sql); + $stm->execute(); + $res = $stm->fetchAll(PDO::FETCH_ASSOC); + + $tables = array( + $this->prefix . 'category' => false, + $this->prefix . 'feed' => false, + $this->prefix . 'entry' => false, + ); + foreach ($res as $value) { + $tables[array_pop($value)] = true; + } + + return count(array_keys($tables, true, true)) == count($tables); + } + + public function getSchema($table) { + $sql = 'DESC ' . $this->prefix . $table; + $stm = $this->bd->prepare($sql); + $stm->execute(); + + return $this->listDaoToSchema($stm->fetchAll(PDO::FETCH_ASSOC)); + } + + public function checkTable($table, $schema) { + $columns = $this->getSchema($table); + + $ok = (count($columns) == count($schema)); + foreach ($columns as $c) { + $ok &= in_array($c['name'], $schema); + } + + return $ok; + } + + public function categoryIsCorrect() { + return $this->checkTable('category', array( + 'id', 'name' + )); + } + + public function feedIsCorrect() { + return $this->checkTable('feed', array( + 'id', 'url', 'category', 'name', 'website', 'description', 'lastUpdate', + 'priority', 'pathEntries', 'httpAuth', 'error', 'keep_history', 'ttl', + 'cache_nbEntries', 'cache_nbUnreads' + )); + } + + public function entryIsCorrect() { + return $this->checkTable('entry', array( + 'id', 'guid', 'title', 'author', 'content_bin', 'link', 'date', 'is_read', + 'is_favorite', 'id_feed', 'tags' + )); + } + + public function daoToSchema($dao) { + return array( + 'name' => $dao['Field'], + 'type' => strtolower($dao['Type']), + 'notnull' => (bool)$dao['Null'], + 'default' => $dao['Default'], + ); + } + + public function listDaoToSchema($listDAO) { + $list = array(); + + foreach ($listDAO as $dao) { + $list[] = $this->daoToSchema($dao); + } + + return $list; + } +} diff --git a/app/Models/DatabaseDAOSQLite.php b/app/Models/DatabaseDAOSQLite.php new file mode 100644 index 000000000..7f53f967d --- /dev/null +++ b/app/Models/DatabaseDAOSQLite.php @@ -0,0 +1,48 @@ +bd->prepare($sql); + $stm->execute(); + $res = $stm->fetchAll(PDO::FETCH_ASSOC); + + $tables = array( + 'category' => false, + 'feed' => false, + 'entry' => false, + ); + foreach ($res as $value) { + $tables[$value['name']] = true; + } + + return count(array_keys($tables, true, true)) == count($tables); + } + + public function getSchema($table) { + $sql = 'PRAGMA table_info(' . $table . ')'; + $stm = $this->bd->prepare($sql); + $stm->execute(); + + return $this->listDaoToSchema($stm->fetchAll(PDO::FETCH_ASSOC)); + } + + public function entryIsCorrect() { + return $this->checkTable('entry', array( + 'id', 'guid', 'title', 'author', 'content', 'link', 'date', 'is_read', + 'is_favorite', 'id_feed', 'tags' + )); + } + + public function daoToSchema($dao) { + return array( + 'name' => $dao['name'], + 'type' => strtolower($dao['type']), + 'notnull' => $dao['notnull'] === '1' ? true : false, + 'default' => $dao['dflt_value'], + ); + } +} diff --git a/app/Models/Factory.php b/app/Models/Factory.php index 93f4552f7..91cb84998 100644 --- a/app/Models/Factory.php +++ b/app/Models/Factory.php @@ -29,4 +29,13 @@ class FreshRSS_Factory { } } + public static function createDatabaseDAO($username = null) { + $db = Minz_Configuration::dataBase(); + if ($db['type'] === 'sqlite') { + return new FreshRSS_DatabaseDAOSQLite($username); + } else { + return new FreshRSS_DatabaseDAO($username); + } + } + } diff --git a/app/SQL/install.sql.mysql.php b/app/SQL/install.sql.mysql.php index 16cb3a3b8..cf0159199 100644 --- a/app/SQL/install.sql.mysql.php +++ b/app/SQL/install.sql.mysql.php @@ -57,5 +57,3 @@ INSERT IGNORE INTO `%1$scategory` (id, name) VALUES(1, "%2$s"); '); define('SQL_DROP_TABLES', 'DROP TABLES %1$sentry, %1$sfeed, %1$scategory'); - -define('SQL_SHOW_TABLES', 'SHOW tables;'); diff --git a/app/SQL/install.sql.sqlite.php b/app/SQL/install.sql.sqlite.php index 7988ada04..30bca2810 100644 --- a/app/SQL/install.sql.sqlite.php +++ b/app/SQL/install.sql.sqlite.php @@ -55,5 +55,3 @@ $SQL_CREATE_TABLES = array( ); define('SQL_DROP_TABLES', 'DROP TABLES %1$sentry, %1$sfeed, %1$scategory'); - -define('SQL_SHOW_TABLES', 'SELECT name FROM sqlite_master WHERE type="table"'); diff --git a/app/layout/aside_configure.phtml b/app/layout/aside_configure.phtml index 20446c877..32dc19a4e 100644 --- a/app/layout/aside_configure.phtml +++ b/app/layout/aside_configure.phtml @@ -31,7 +31,12 @@
  • -
  • +
  • + +
  • +
  • diff --git a/app/layout/header.phtml b/app/layout/header.phtml index e848ac4eb..506cec175 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -68,6 +68,7 @@ if (Minz_Configuration::canLogIn()) {
  • +
  • diff --git a/app/views/update/checkInstall.phtml b/app/views/update/checkInstall.phtml new file mode 100644 index 000000000..32058714e --- /dev/null +++ b/app/views/update/checkInstall.phtml @@ -0,0 +1,30 @@ +partial('aside_configure'); ?> + +
    + + +

    + + status_php as $key => $status) { ?> +

    + +

    + + +

    + + status_files as $key => $status) { ?> +

    + +

    + + +

    + + status_database as $key => $status) { ?> +

    + +

    + + +
    diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 2f9a2ea45..dbed207d0 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -245,3 +245,65 @@ function is_referer_from_same_domain() { } return (isset($host['port']) ? $host['port'] : 0) === (isset($referer['port']) ? $referer['port'] : 0); } + + +/** + * + */ +function check_install_php() { + return array( + 'php' => version_compare(PHP_VERSION, '5.2.1') >= 0, + 'minz' => file_exists(LIB_PATH . '/Minz'), + 'curl' => extension_loaded('curl'), + 'pdo_mysql' => extension_loaded('pdo_mysql'), + 'pdo_sqlite' => extension_loaded('pdo_sqlite'), + 'pdo' => extension_loaded('pdo_mysql') || extension_loaded('pdo_sqlite'), + 'pcre' => extension_loaded('pcre'), + 'ctype' => extension_loaded('ctype'), + 'dom' => class_exists('DOMDocument'), + 'json' => extension_loaded('json'), + 'zip' => extension_loaded('zip'), + ); +} + + +/** + * + */ +function check_install_files() { + return array( + 'data' => DATA_PATH && is_writable(DATA_PATH), + 'cache' => CACHE_PATH && is_writable(CACHE_PATH), + 'logs' => LOG_PATH && is_writable(LOG_PATH), + 'favicons' => is_writable(DATA_PATH . '/favicons'), + 'persona' => is_writable(DATA_PATH . '/persona'), + 'tokens' => is_writable(DATA_PATH . '/tokens'), + ); +} + + +/** + * + */ +function check_install_database() { + $status = array( + 'connection' => true, + 'tables' => false, + 'categories' => false, + 'feeds' => false, + 'entries' => false, + ); + + try { + $dbDAO = FreshRSS_Factory::createDatabaseDAO(); + + $status['tables'] = $dbDAO->tablesAreCorrect(); + $status['categories'] = $dbDAO->categoryIsCorrect(); + $status['feeds'] = $dbDAO->feedIsCorrect(); + $status['entries'] = $dbDAO->entryIsCorrect(); + } catch(Minz_PDOConnectionException $e) { + $status['connection'] = false; + } + + return $status; +} -- cgit v1.2.3 From 61a2f9387f2d7f681040c1641c7601fa3002c8f8 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 20 Oct 2014 12:42:46 +0200 Subject: Fix i18n (french and english) --- app/i18n/en.php | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- app/i18n/fr.php | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- lib/lib_rss.php | 6 ++++++ 3 files changed, 112 insertions(+), 8 deletions(-) diff --git a/app/i18n/en.php b/app/i18n/en.php index 283d28dc6..b24af38c1 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -9,6 +9,53 @@ 'add_category' => 'Add a category', 'add_query' => 'Add a query', 'add_rss_feed' => 'Add a RSS feed', + 'admin.check_install.cache.nok' => 'Check permissions on ./data/cache directory. HTTP server must have rights to write into', + 'admin.check_install.cache.ok' => 'Permissions on cache directory are good.', + 'admin.check_install.categories.nok' => 'Category table is bad configured.', + 'admin.check_install.categories.ok' => 'Category table is ok.', + 'admin.check_install.connection.nok' => 'Connection to the database cannot being established.', + 'admin.check_install.connection.ok' => 'Connection to the database is ok.', + 'admin.check_install.ctype.nok' => 'You lack a required library for character type checking (php-ctype).', + 'admin.check_install.ctype.ok' => 'You have the required library for character type checking (ctype).', + 'admin.check_install.curl.nok' => 'You lack cURL (php5-curl package).', + 'admin.check_install.curl.ok' => 'You have version %s of cURL.', + 'admin.check_install.data.nok' => 'Check permissions on ./data directory. HTTP server must have rights to write into', + 'admin.check_install.data.ok' => 'Permissions on data directory are good.', + 'admin.check_install.database' => 'Database installation', + 'admin.check_install.dom.nok' => 'You lack a required library to browse the DOM (php-xml package).', + 'admin.check_install.dom.ok' => 'You have the required library to browse the DOM.', + 'admin.check_install.entries.nok' => 'Entry table is bad configured.', + 'admin.check_install.entries.ok' => 'Entry table is ok.', + 'admin.check_install.favicons.nok' => 'Check permissions on ./data/favicons directory. HTTP server must have rights to write into', + 'admin.check_install.favicons.ok' => 'Permissions on favicons directory are good.', + 'admin.check_install.feeds.nok' => 'Feed table is bad configured.', + 'admin.check_install.feeds.ok' => 'Feed table is ok.', + 'admin.check_install.files' => 'File installation', + 'admin.check_install.json.nok' => 'You lack JSON (php5-json package).', + 'admin.check_install.json.ok' => 'You have version %s of JSON.', + 'admin.check_install.logs.nok' => 'Check permissions on ./data/logs directory. HTTP server must have rights to write into', + 'admin.check_install.logs.ok' => 'Permissions on logs directory are good.', + 'admin.check_install.minz.nok' => 'You lack the Minz framework.', + 'admin.check_install.minz.ok' => 'You have the Minz framework.', + 'admin.check_install.pcre.nok' => 'You lack a required library for regular expressions (php-pcre).', + 'admin.check_install.pcre.ok' => 'You have the required library for regular expressions (PCRE).', + 'admin.check_install.pdo.nok' => 'You lack PDO or one of the supported drivers (pdo_mysql, pdo_sqlite).', + 'admin.check_install.pdo.ok' => 'You have PDO and at least one of the supported drivers (pdo_mysql, pdo_sqlite).', + 'admin.check_install.pdo_mysql.nok' => 'You lack PDO for MySQL (it\'s ok if PDO is good).', + 'admin.check_install.pdo_mysql.ok' => 'You have PDO for MySQL.', + 'admin.check_install.pdo_sqlite.nok' => 'You lack PDO for SQLite (it\'s ok if PDO is good).', + 'admin.check_install.pdo_sqlite.ok' => 'You have PDO for SQLite.', + 'admin.check_install.persona.nok' => 'Check permissions on ./data/persona directory. HTTP server must have rights to write into', + 'admin.check_install.persona.ok' => 'Permissions on Mozilla Persona directory are good.', + 'admin.check_install.php' => 'PHP installation', + 'admin.check_install.php.nok' => 'Your PHP version is %s but FreshRSS requires at least version %s.', + 'admin.check_install.php.ok' => 'Your PHP version is %s, which is compatible with FreshRSS.', + 'admin.check_install.tables.nok' => 'There is one or more lacking tables in the database.', + 'admin.check_install.tables.ok' => 'Tables are existing in the database.', + 'admin.check_install.tokens.nok' => 'Check permissions on ./data/tokens directory. HTTP server must have rights to write into', + 'admin.check_install.tokens.ok' => 'Permissions on tokens directory are good.', + 'admin.check_install.zip.nok' => 'You lack ZIP extension (php5-zip package).', + 'admin.check_install.zip.ok' => 'You have version %s of ZIP extension.', 'admin.users.articles_and_size' => '%s articles (%s)', 'administration' => 'Manage', 'advanced' => 'Advanced', @@ -118,8 +165,8 @@ 'current_user' => 'Current user', 'damn' => 'Damn!', 'data_is_ok' => 'Permissions on data directory are good', - 'dec' => 'dec', 'Dec' => '\\D\\e\\c\\e\\m\\b\\e\\r', + 'dec' => 'dec', 'december' => 'Dec', 'default_category' => 'Uncategorized', 'default_user' => 'Username of the default user (maximum 16 alphanumeric characters)', @@ -186,8 +233,10 @@ 'g+' => 'Google+', 'gen.menu.admin' => 'Administration', 'gen.menu.authentication' => 'Authentication', + 'gen.menu.check_install' => 'Installation checking', 'gen.menu.manage_users' => 'Manage users', 'gen.menu.profil' => 'Profil', + 'gen.title.check_install' => 'Installation checking', 'general_configuration' => 'General configuration', 'general_conf_is_ok' => 'General configuration has been saved.', 'github_or_email' => 'on Github or by mail', @@ -219,8 +268,8 @@ 'javascript_for_shortcuts' => 'JavaScript must be enabled in order to use shortcuts', 'javascript_is_better' => 'FreshRSS is more pleasant with JavaScript enabled', 'javascript_should_be_activated' => 'JavaScript must be enabled', - 'jul' => 'jul', 'Jul' => '\\J\\u\\l\\y', + 'jul' => 'jul', 'july' => 'Jul', 'jump_next' => 'jump to next unread sibling (feed or category)', 'jun' => 'jun', @@ -297,8 +346,8 @@ 'number_feeds' => '%d feeds', 'n_entries_deleted' => '%d articles have been deleted', 'n_feeds_actualized' => '%d feeds have been updated', - 'Oct' => '\\O\\c\\t\\o\\b\\e\\r', 'oct' => 'oct', + 'Oct' => '\\O\\c\\t\\o\\b\\e\\r', 'october' => 'Oct', 'ok' => 'Ok!', 'older_first' => 'Oldest first', @@ -375,8 +424,8 @@ 'seconds_(0_means_no_timeout)' => 'seconds (0 means no timeout)', 'see_on_website' => 'See on original website', 'see_website' => 'See website', - 'sep' => 'sep', 'Sep' => '\\S\\e\\p\\t\\e\\m\\b\\e\\r', + 'sep' => 'sep', 'september' => 'Sep', 'shaarli' => 'Shaarli', 'share' => 'Share', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 0517544d5..22494274c 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -9,6 +9,53 @@ 'add_category' => 'Ajouter une catégorie', 'add_query' => 'Créer un filtre', 'add_rss_feed' => 'Ajouter un flux RSS', + 'admin.check_install.cache.nok' => 'Veuillez vérifier les droits sur le répertoire ./data/cache. Le serveur HTTP doit être capable d’écrire dedans', + 'admin.check_install.cache.ok' => 'Les droits sur le répertoire de cache sont bons.', + 'admin.check_install.categories.nok' => 'La table category est mal configurée.', + 'admin.check_install.categories.ok' => 'La table category est bien configurée.', + 'admin.check_install.connection.nok' => 'La connexion à la base de données est impossible.', + 'admin.check_install.connection.ok' => 'La connexion à la base de données est bonne.', + 'admin.check_install.ctype.nok' => 'Il manque une librairie pour la vérification des types de caractères (php-ctype).', + 'admin.check_install.ctype.ok' => 'Vous disposez du nécessaire pour la vérification des types de caractères (ctype).', + 'admin.check_install.curl.nok' => 'Vous ne disposez pas de cURL (paquet php5-curl).', + 'admin.check_install.curl.ok' => 'Vous disposez de cURL dans sa version %s.', + 'admin.check_install.data.nok' => 'Veuillez vérifier les droits sur le répertoire ./data. Le serveur HTTP doit être capable d’écrire dedans', + 'admin.check_install.data.ok' => 'Les droits sur le répertoire de data sont bons.', + 'admin.check_install.database' => 'Installation de la base de données', + 'admin.check_install.dom.nok' => 'Il manque une librairie pour parcourir le DOM (paquet php-xml).', + 'admin.check_install.dom.ok' => 'Vous disposez du nécessaire pour parcourir le DOM.', + 'admin.check_install.entries.nok' => 'La table entry est mal configurée.', + 'admin.check_install.entries.ok' => 'La table entry est bien configurée.', + 'admin.check_install.favicons.nok' => 'Veuillez vérifier les droits sur le répertoire ./data/favicons. Le serveur HTTP doit être capable d’écrire dedans', + 'admin.check_install.favicons.ok' => 'Les droits sur le répertoire des favicons sont bons.', + 'admin.check_install.feeds.nok' => 'La table feed est mal configurée.', + 'admin.check_install.feeds.ok' => 'La table feed est bien configurée.', + 'admin.check_install.files' => 'Installation des fichiers', + 'admin.check_install.json.nok' => 'Vous ne disposez pas de JSON (paquet php5-json).', + 'admin.check_install.json.ok' => 'Vous disposez de JSON dans sa version %s.', + 'admin.check_install.logs.nok' => 'Veuillez vérifier les droits sur le répertoire ./data/logs. Le serveur HTTP doit être capable d’écrire dedans', + 'admin.check_install.logs.ok' => 'Les droits sur le répertoire des logs sont bons.', + 'admin.check_install.minz.nok' => 'Vous ne disposez pas de la librairie Minz.', + 'admin.check_install.minz.ok' => 'Vous disposez du framework Minz', + 'admin.check_install.pcre.nok' => 'Il manque une librairie pour les expressions régulières (php-pcre).', + 'admin.check_install.pcre.ok' => 'Vous disposez du nécessaire pour les expressions régulières (PCRE).', + 'admin.check_install.pdo.nok' => 'Vous ne disposez pas de PDO ou d’un des drivers supportés (pdo_mysql, pdo_sqlite).', + 'admin.check_install.pdo.ok' => 'Vous disposez de PDO et d’au moins un des drivers supportés (pdo_mysql, pdo_sqlite).', + 'admin.check_install.pdo_mysql.nok' => 'Vous ne possédez pas PDO pour MySQL (ok si PDO est bon).', + 'admin.check_install.pdo_mysql.ok' => 'Vous possédez PDO pour MySQL.', + 'admin.check_install.pdo_sqlite.nok' => 'Vous ne possédez pas PDO pour SQLite (ok si PDO est bon).', + 'admin.check_install.pdo_sqlite.ok' => 'Vous possédez PDO pour SQLite.', + 'admin.check_install.persona.nok' => 'Veuillez vérifier les droits sur le répertoire ./data/persona. Le serveur HTTP doit être capable d’écrire dedans', + 'admin.check_install.persona.ok' => 'Les droits sur le répertoire de Mozilla Persona sont bons.', + 'admin.check_install.php' => 'Installation de PHP', + 'admin.check_install.php.nok' => 'Votre version de PHP est la %s mais FreshRSS requiert au moins la version %s.', + 'admin.check_install.php.ok' => 'Votre version de PHP est la %s, qui est compatible avec FreshRSS.', + 'admin.check_install.tables.nok' => 'Il manque une ou plusieurs tables en base de données.', + 'admin.check_install.tables.ok' => 'Les tables sont bien présentes en base de données.', + 'admin.check_install.tokens.nok' => 'Veuillez vérifier les droits sur le répertoire ./data/tokens. Le serveur HTTP doit être capable d’écrire dedans', + 'admin.check_install.tokens.ok' => 'Les droits sur le répertoire des tokens sont bons.', + 'admin.check_install.zip.nok' => 'Vous ne disposez pas de l\'extension ZIP (paquet php5-zip).', + 'admin.check_install.zip.ok' => 'Vous disposez de l\'extension ZIP dans sa version %s.', 'admin.users.articles_and_size' => '%s articles (%s)', 'administration' => 'Gérer', 'advanced' => 'Avancé', @@ -118,8 +165,8 @@ 'current_user' => 'Utilisateur actuel', 'damn' => 'Arf !', 'data_is_ok' => 'Les droits sur le répertoire de data sont bons', - 'dec' => 'déc.', 'Dec' => '\\d\\é\\c\\e\\m\\b\\r\\e', + 'dec' => 'déc.', 'december' => 'décembre', 'default_category' => 'Sans catégorie', 'default_user' => 'Nom de l’utilisateur par défaut (16 caractères alphanumériques maximum)', @@ -186,8 +233,10 @@ 'g+' => 'Google+', 'gen.menu.admin' => 'Administration', 'gen.menu.authentication' => 'Authentification', + 'gen.menu.check_install' => 'Vérification de l\'installation', 'gen.menu.manage_users' => 'Gestion des utilisateurs', 'gen.menu.profil' => 'Profil', + 'gen.title.check_install' => 'Vérification de l\'installation', 'general_configuration' => 'Configuration générale', 'general_conf_is_ok' => 'La configuration générale a été enregistrée.', 'github_or_email' => 'sur Github ou par courriel', @@ -219,8 +268,8 @@ 'javascript_for_shortcuts' => 'Le JavaScript doit être activé pour pouvoir profiter des raccourcis.', 'javascript_is_better' => 'FreshRSS est plus agréable à utiliser avec JavaScript activé', 'javascript_should_be_activated' => 'Le JavaScript doit être activé.', - 'jul' => 'jui.', 'Jul' => '\\j\\u\\i\\l\\l\\e\\t', + 'jul' => 'jui.', 'july' => 'juillet', 'jump_next' => 'sauter au prochain voisin non lu (flux ou catégorie)', 'jun' => 'juin', @@ -297,8 +346,8 @@ 'number_feeds' => '%d flux', 'n_entries_deleted' => '%d articles ont été supprimés.', 'n_feeds_actualized' => '%d flux ont été mis à jour.', - 'Oct' => '\\o\\c\\t\\o\\b\\r\\e', 'oct' => 'oct.', + 'Oct' => '\\o\\c\\t\\o\\b\\r\\e', 'october' => 'octobre', 'ok' => 'Ok !', 'older_first' => 'Plus anciens en premier', @@ -375,8 +424,8 @@ 'seconds_(0_means_no_timeout)' => 'secondes (0 signifie aucun timeout ) ', 'see_on_website' => 'Voir sur le site d’origine', 'see_website' => 'Voir le site', - 'sep' => 'sep.', 'Sep' => '\\s\\e\\p\\t\\e\\m\\b\\r\\e', + 'sep' => 'sep.', 'september' => 'septembre', 'shaarli' => 'Shaarli', 'share' => 'Partager', diff --git a/lib/lib_rss.php b/lib/lib_rss.php index dbed207d0..9abdf18ce 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -248,7 +248,9 @@ function is_referer_from_same_domain() { /** + * Check PHP and its extensions are well-installed. * + * @return array of tested values. */ function check_install_php() { return array( @@ -268,7 +270,9 @@ function check_install_php() { /** + * Check different data files and directories exist. * + * @return array of tested values. */ function check_install_files() { return array( @@ -283,7 +287,9 @@ function check_install_files() { /** + * Check database is well-installed. * + * @return array of tested values. */ function check_install_database() { $status = array( -- cgit v1.2.3 From ae84e877c5fdda2b1a29ab0bb6c2469258fcc9a5 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 20 Oct 2014 12:52:18 +0200 Subject: Fix some i18n keys --- app/i18n/en.php | 6 +++--- app/i18n/fr.php | 6 +++--- app/views/update/checkInstall.phtml | 8 +++++++- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/app/i18n/en.php b/app/i18n/en.php index b24af38c1..2792ad7a2 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -18,7 +18,7 @@ 'admin.check_install.ctype.nok' => 'You lack a required library for character type checking (php-ctype).', 'admin.check_install.ctype.ok' => 'You have the required library for character type checking (ctype).', 'admin.check_install.curl.nok' => 'You lack cURL (php5-curl package).', - 'admin.check_install.curl.ok' => 'You have version %s of cURL.', + 'admin.check_install.curl.ok' => 'You have cURL extension.', 'admin.check_install.data.nok' => 'Check permissions on ./data directory. HTTP server must have rights to write into', 'admin.check_install.data.ok' => 'Permissions on data directory are good.', 'admin.check_install.database' => 'Database installation', @@ -32,7 +32,7 @@ 'admin.check_install.feeds.ok' => 'Feed table is ok.', 'admin.check_install.files' => 'File installation', 'admin.check_install.json.nok' => 'You lack JSON (php5-json package).', - 'admin.check_install.json.ok' => 'You have version %s of JSON.', + 'admin.check_install.json.ok' => 'You have JSON extension.', 'admin.check_install.logs.nok' => 'Check permissions on ./data/logs directory. HTTP server must have rights to write into', 'admin.check_install.logs.ok' => 'Permissions on logs directory are good.', 'admin.check_install.minz.nok' => 'You lack the Minz framework.', @@ -55,7 +55,7 @@ 'admin.check_install.tokens.nok' => 'Check permissions on ./data/tokens directory. HTTP server must have rights to write into', 'admin.check_install.tokens.ok' => 'Permissions on tokens directory are good.', 'admin.check_install.zip.nok' => 'You lack ZIP extension (php5-zip package).', - 'admin.check_install.zip.ok' => 'You have version %s of ZIP extension.', + 'admin.check_install.zip.ok' => 'You have ZIP extension.', 'admin.users.articles_and_size' => '%s articles (%s)', 'administration' => 'Manage', 'advanced' => 'Advanced', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 22494274c..85b32a737 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -18,7 +18,7 @@ 'admin.check_install.ctype.nok' => 'Il manque une librairie pour la vérification des types de caractères (php-ctype).', 'admin.check_install.ctype.ok' => 'Vous disposez du nécessaire pour la vérification des types de caractères (ctype).', 'admin.check_install.curl.nok' => 'Vous ne disposez pas de cURL (paquet php5-curl).', - 'admin.check_install.curl.ok' => 'Vous disposez de cURL dans sa version %s.', + 'admin.check_install.curl.ok' => 'Vous disposez de cURL.', 'admin.check_install.data.nok' => 'Veuillez vérifier les droits sur le répertoire ./data. Le serveur HTTP doit être capable d’écrire dedans', 'admin.check_install.data.ok' => 'Les droits sur le répertoire de data sont bons.', 'admin.check_install.database' => 'Installation de la base de données', @@ -32,7 +32,7 @@ 'admin.check_install.feeds.ok' => 'La table feed est bien configurée.', 'admin.check_install.files' => 'Installation des fichiers', 'admin.check_install.json.nok' => 'Vous ne disposez pas de JSON (paquet php5-json).', - 'admin.check_install.json.ok' => 'Vous disposez de JSON dans sa version %s.', + 'admin.check_install.json.ok' => 'Vous disposez de l\'extension JSON.', 'admin.check_install.logs.nok' => 'Veuillez vérifier les droits sur le répertoire ./data/logs. Le serveur HTTP doit être capable d’écrire dedans', 'admin.check_install.logs.ok' => 'Les droits sur le répertoire des logs sont bons.', 'admin.check_install.minz.nok' => 'Vous ne disposez pas de la librairie Minz.', @@ -55,7 +55,7 @@ 'admin.check_install.tokens.nok' => 'Veuillez vérifier les droits sur le répertoire ./data/tokens. Le serveur HTTP doit être capable d’écrire dedans', 'admin.check_install.tokens.ok' => 'Les droits sur le répertoire des tokens sont bons.', 'admin.check_install.zip.nok' => 'Vous ne disposez pas de l\'extension ZIP (paquet php5-zip).', - 'admin.check_install.zip.ok' => 'Vous disposez de l\'extension ZIP dans sa version %s.', + 'admin.check_install.zip.ok' => 'Vous disposez de l\'extension ZIP.', 'admin.users.articles_and_size' => '%s articles (%s)', 'administration' => 'Gérer', 'advanced' => 'Avancé', diff --git a/app/views/update/checkInstall.phtml b/app/views/update/checkInstall.phtml index 32058714e..5f913bccd 100644 --- a/app/views/update/checkInstall.phtml +++ b/app/views/update/checkInstall.phtml @@ -7,7 +7,13 @@ status_php as $key => $status) { ?>

    - +

    -- cgit v1.2.3 From df4ddf0e552d9113c9f55d5361212f8279a5c617 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 20 Oct 2014 13:31:49 +0200 Subject: Unsafe autologin comes back Should be moved in an extension later! See https://github.com/marienfressinaud/FreshRSS/issues/655 --- app/Controllers/authController.php | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index 751ce1f3f..d4b65d849 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -104,6 +104,8 @@ class FreshRSS_auth_Controller extends Minz_ActionController { * - username (default: '') * - challenge (default: '') * - keep_logged_in (default: false) + * + * @todo move unsafe autologin in an extension. */ public function formLoginAction() { invalidateHttpCache(); @@ -151,6 +153,42 @@ class FreshRSS_auth_Controller extends Minz_ActionController { Minz_Request::bad(_t('invalid_login'), array('c' => 'auth', 'a' => 'login')); } + } elseif (Minz_Configuration::unsafeAutologinEnabled()) { + $username = Minz_Request::param('u', ''); + $password = Minz_Request::param('p', ''); + Minz_Request::_param('p'); + + if (!$username) { + return; + } + + try { + $conf = new FreshRSS_Configuration($username); + } catch(Minz_Exception $e) { + // $username is not a valid user, nor the configuration file! + Minz_Log::warning('Login failure: ' . $e->getMessage()); + return; + } + + if (!function_exists('password_verify')) { + include_once(LIB_PATH . '/password_compat.php'); + } + + $s = $conf->passwordHash; + $ok = password_verify($password, $s); + unset($password); + if ($ok) { + Minz_Session::_param('currentUser', $username); + Minz_Session::_param('passwordHash', $s); + FreshRSS_Auth::giveAccess(); + + Minz_Request::good(_t('login'), + array('c' => 'index', 'a' => 'index')); + } else { + Minz_Log::warning('Unsafe password mismatch for user ' . $username); + Minz_Request::bad(_t('invalid_login'), + array('c' => 'auth', 'a' => 'login')); + } } } -- cgit v1.2.3 From ad92dd7dae35e7205da3172d4ba35ea01da2bc8b Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 20 Oct 2014 18:21:10 +0200 Subject: First draft for Context object. See https://github.com/marienfressinaud/FreshRSS/issues/634 --- app/FreshRSS.php | 40 ++++++++++++++++++++-------------------- app/Models/Context.php | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 20 deletions(-) create mode 100644 app/Models/Context.php diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 6b7a813bf..e1399ad78 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -1,50 +1,50 @@ loadConfiguration(); - $this->loadParamsView(); + if (Minz_Request::isPost() && !is_referer_from_same_domain()) { - //Basic protection against XSRF attacks + // Basic protection against XSRF attacks FreshRSS_Auth::removeAccess(); + $http_referer = empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER']; Minz_Error::error( 403, - array('error' => array(_t('access_denied') . ' [HTTP_REFERER=' . - htmlspecialchars(empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER']) . ']')) + array('error' => array( + _t('access_denied'), + ' [HTTP_REFERER=' . htmlspecialchars($http_referer) . ']' + )) ); } + + // Load context and configuration. + // TODO: remove $this->view->conf variable which is contained in context + FreshRSS_Context::init(); + Minz_View::_param('conf', FreshRSS_Context::$conf); + + $this->loadParamsView(); $this->loadStylesAndScripts(); $this->loadNotifications(); $this->loadExtensions(); } - private function loadConfiguration() { - $current_user = Minz_Session::param('currentUser'); - try { - $this->conf = new FreshRSS_Configuration($current_user); - Minz_View::_param('conf', $this->conf); - } catch(Minz_Exception $e) { - Minz_Log::error('Cannot load configuration file of user `' . $current_user . '`'); - die($e->getMessage()); - } - } - private function loadParamsView() { - Minz_Session::_param('language', $this->conf->language); - Minz_Translate::init(); + // TODO: outputs should be different actions. $output = Minz_Request::param('output', ''); if (($output === '') || ($output !== 'normal' && $output !== 'rss' && $output !== 'reader' && $output !== 'global')) { - $output = $this->conf->view_mode; + $output = FreshRSS_Context::$conf->view_mode; Minz_Request::_param('output', $output); } } private function loadStylesAndScripts() { - $theme = FreshRSS_Themes::load($this->conf->theme); + $theme = FreshRSS_Themes::load(FreshRSS_Context::$conf->theme); if ($theme) { foreach($theme['files'] as $file) { if ($file[0] === '_') { diff --git a/app/Models/Context.php b/app/Models/Context.php new file mode 100644 index 000000000..d984fece7 --- /dev/null +++ b/app/Models/Context.php @@ -0,0 +1,32 @@ +getMessage()); + } + + // Init i18n. + Minz_Session::_param('language', self::$conf->language); + Minz_Translate::init(); + + // Get the current state. + self::$state = self::$conf->default_view; + } + + public static function stateEnabled($state) { + return self::$state & $state; + } +} -- cgit v1.2.3 From 1a22a87fb1b1fcb61d201de399c33c2185dc1f6e Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 20 Oct 2014 18:45:22 +0200 Subject: Use FreshRSS_Context::$conf only - Replace $this->view->conf in controllers - Replace $this->conf in views --- app/Controllers/authController.php | 6 +- app/Controllers/categoryController.php | 8 +-- app/Controllers/configureController.php | 92 +++++++++++++++--------------- app/Controllers/entryController.php | 6 +- app/Controllers/feedController.php | 18 +++--- app/Controllers/importExportController.php | 4 +- app/Controllers/indexController.php | 8 +-- app/Controllers/javascriptController.php | 2 +- app/Controllers/userController.php | 18 +++--- app/FreshRSS.php | 2 - app/layout/aside_flux.phtml | 8 +-- app/layout/layout.phtml | 2 +- app/layout/nav_menu.phtml | 14 ++--- app/views/auth/index.phtml | 4 +- app/views/configure/archiving.phtml | 10 ++-- app/views/configure/display.phtml | 30 +++++----- app/views/configure/queries.phtml | 4 +- app/views/configure/reading.phtml | 42 +++++++------- app/views/configure/sharing.phtml | 6 +- app/views/configure/shortcut.phtml | 2 +- app/views/helpers/javascript_vars.phtml | 16 +++--- app/views/helpers/pagination.phtml | 2 +- app/views/helpers/view/global_view.phtml | 6 +- app/views/helpers/view/normal_view.phtml | 30 +++++----- app/views/helpers/view/reader_view.phtml | 4 +- app/views/user/manage.phtml | 6 +- app/views/user/profil.phtml | 2 +- 27 files changed, 175 insertions(+), 177 deletions(-) diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index d4b65d849..4af39cb71 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -26,10 +26,10 @@ class FreshRSS_auth_Controller extends Minz_ActionController { if (Minz_Request::isPost()) { $ok = true; - $current_token = $this->view->conf->token; + $current_token = FreshRSS_Context::$conf->token; $token = Minz_Request::param('token', $current_token); - $this->view->conf->_token($token); - $ok &= $this->view->conf->save(); + FreshRSS_Context::$conf->_token($token); + $ok &= FreshRSS_Context::$conf->save(); $anon = Minz_Request::param('anon_access', false); $anon = ((bool)$anon) && ($anon !== 'no'); diff --git a/app/Controllers/categoryController.php b/app/Controllers/categoryController.php index 537a2b210..977ce51be 100644 --- a/app/Controllers/categoryController.php +++ b/app/Controllers/categoryController.php @@ -136,8 +136,8 @@ class FreshRSS_category_Controller extends Minz_ActionController { } // Remove related queries. - $this->view->conf->remove_query_by_get('c_' . $id); - $this->view->conf->save(); + FreshRSS_Context::$conf->remove_query_by_get('c_' . $id); + FreshRSS_Context::$conf->save(); Minz_Request::good(_t('category_deleted'), $url_redirect); } @@ -172,9 +172,9 @@ class FreshRSS_category_Controller extends Minz_ActionController { // Remove related queries foreach ($feeds as $feed) { - $this->view->conf->remove_query_by_get('f_' . $feed->id()); + FreshRSS_Context::$conf->remove_query_by_get('f_' . $feed->id()); } - $this->view->conf->save(); + FreshRSS_Context::$conf->save(); Minz_Request::good(_t('category_emptied'), $url_redirect); } else { diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index fb8c1466e..8a9dcdc62 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -44,23 +44,23 @@ class FreshRSS_configure_Controller extends Minz_ActionController { */ public function displayAction() { if (Minz_Request::isPost()) { - $this->view->conf->_language(Minz_Request::param('language', 'en')); - $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)); - $this->view->conf->_topline_date(Minz_Request::param('topline_date', false)); - $this->view->conf->_topline_link(Minz_Request::param('topline_link', false)); - $this->view->conf->_bottomline_read(Minz_Request::param('bottomline_read', false)); - $this->view->conf->_bottomline_favorite(Minz_Request::param('bottomline_favorite', false)); - $this->view->conf->_bottomline_sharing(Minz_Request::param('bottomline_sharing', false)); - $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); + FreshRSS_Context::$conf->_language(Minz_Request::param('language', 'en')); + FreshRSS_Context::$conf->_theme(Minz_Request::param('theme', FreshRSS_Themes::$defaultTheme)); + FreshRSS_Context::$conf->_content_width(Minz_Request::param('content_width', 'thin')); + FreshRSS_Context::$conf->_topline_read(Minz_Request::param('topline_read', false)); + FreshRSS_Context::$conf->_topline_favorite(Minz_Request::param('topline_favorite', false)); + FreshRSS_Context::$conf->_topline_date(Minz_Request::param('topline_date', false)); + FreshRSS_Context::$conf->_topline_link(Minz_Request::param('topline_link', false)); + FreshRSS_Context::$conf->_bottomline_read(Minz_Request::param('bottomline_read', false)); + FreshRSS_Context::$conf->_bottomline_favorite(Minz_Request::param('bottomline_favorite', false)); + FreshRSS_Context::$conf->_bottomline_sharing(Minz_Request::param('bottomline_sharing', false)); + FreshRSS_Context::$conf->_bottomline_tags(Minz_Request::param('bottomline_tags', false)); + FreshRSS_Context::$conf->_bottomline_date(Minz_Request::param('bottomline_date', false)); + FreshRSS_Context::$conf->_bottomline_link(Minz_Request::param('bottomline_link', false)); + FreshRSS_Context::$conf->_html5_notif_timeout(Minz_Request::param('html5_notif_timeout', 0)); + FreshRSS_Context::$conf->save(); + + Minz_Session::_param('language', FreshRSS_Context::$conf->language); Minz_Translate::reset(); invalidateHttpCache(); @@ -102,27 +102,27 @@ class FreshRSS_configure_Controller extends Minz_ActionController { */ public function readingAction() { if (Minz_Request::isPost()) { - $this->view->conf->_posts_per_page(Minz_Request::param('posts_per_page', 10)); - $this->view->conf->_view_mode(Minz_Request::param('view_mode', 'normal')); - $this->view->conf->_default_view((int)Minz_Request::param('default_view', FreshRSS_Entry::STATE_ALL)); - $this->view->conf->_auto_load_more(Minz_Request::param('auto_load_more', false)); - $this->view->conf->_display_posts(Minz_Request::param('display_posts', false)); - $this->view->conf->_display_categories(Minz_Request::param('display_categories', false)); - $this->view->conf->_hide_read_feeds(Minz_Request::param('hide_read_feeds', false)); - $this->view->conf->_onread_jump_next(Minz_Request::param('onread_jump_next', false)); - $this->view->conf->_lazyload(Minz_Request::param('lazyload', false)); - $this->view->conf->_sticky_post(Minz_Request::param('sticky_post', false)); - $this->view->conf->_reading_confirm(Minz_Request::param('reading_confirm', false)); - $this->view->conf->_sort_order(Minz_Request::param('sort_order', 'DESC')); - $this->view->conf->_mark_when(array( + FreshRSS_Context::$conf->_posts_per_page(Minz_Request::param('posts_per_page', 10)); + FreshRSS_Context::$conf->_view_mode(Minz_Request::param('view_mode', 'normal')); + FreshRSS_Context::$conf->_default_view((int)Minz_Request::param('default_view', FreshRSS_Entry::STATE_ALL)); + FreshRSS_Context::$conf->_auto_load_more(Minz_Request::param('auto_load_more', false)); + FreshRSS_Context::$conf->_display_posts(Minz_Request::param('display_posts', false)); + FreshRSS_Context::$conf->_display_categories(Minz_Request::param('display_categories', false)); + FreshRSS_Context::$conf->_hide_read_feeds(Minz_Request::param('hide_read_feeds', false)); + FreshRSS_Context::$conf->_onread_jump_next(Minz_Request::param('onread_jump_next', false)); + FreshRSS_Context::$conf->_lazyload(Minz_Request::param('lazyload', false)); + FreshRSS_Context::$conf->_sticky_post(Minz_Request::param('sticky_post', false)); + FreshRSS_Context::$conf->_reading_confirm(Minz_Request::param('reading_confirm', false)); + FreshRSS_Context::$conf->_sort_order(Minz_Request::param('sort_order', 'DESC')); + FreshRSS_Context::$conf->_mark_when(array( 'article' => Minz_Request::param('mark_open_article', false), 'site' => Minz_Request::param('mark_open_site', false), 'scroll' => Minz_Request::param('mark_scroll', false), 'reception' => Minz_Request::param('mark_upon_reception', false), )); - $this->view->conf->save(); + FreshRSS_Context::$conf->save(); - Minz_Session::_param('language', $this->view->conf->language); + Minz_Session::_param('language', FreshRSS_Context::$conf->language); Minz_Translate::reset(); invalidateHttpCache(); @@ -143,8 +143,8 @@ class FreshRSS_configure_Controller extends Minz_ActionController { public function sharingAction() { if (Minz_Request::isPost()) { $params = Minz_Request::params(); - $this->view->conf->_sharing($params['share']); - $this->view->conf->save(); + FreshRSS_Context::$conf->_sharing($params['share']); + FreshRSS_Context::$conf->save(); invalidateHttpCache(); Minz_Request::good(_t('configuration_updated'), @@ -185,8 +185,8 @@ class FreshRSS_configure_Controller extends Minz_ActionController { } } - $this->view->conf->_shortcuts($shortcuts_ok); - $this->view->conf->save(); + FreshRSS_Context::$conf->_shortcuts($shortcuts_ok); + FreshRSS_Context::$conf->save(); invalidateHttpCache(); Minz_Request::good(_t('shortcuts_updated'), @@ -213,10 +213,10 @@ class FreshRSS_configure_Controller extends Minz_ActionController { */ public function archivingAction() { if (Minz_Request::isPost()) { - $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(); + FreshRSS_Context::$conf->_old_entries(Minz_Request::param('old_entries', 3)); + FreshRSS_Context::$conf->_keep_history_default(Minz_Request::param('keep_history_default', 0)); + FreshRSS_Context::$conf->_ttl_default(Minz_Request::param('ttl_default', -2)); + FreshRSS_Context::$conf->save(); invalidateHttpCache(); Minz_Request::good(_t('configuration_updated'), @@ -253,8 +253,8 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $query['name'] = _t('query_number', $key + 1); } } - $this->view->conf->_queries($queries); - $this->view->conf->save(); + FreshRSS_Context::$conf->_queries($queries); + FreshRSS_Context::$conf->save(); Minz_Request::good(_t('configuration_updated'), array('c' => 'configure', 'a' => 'queries')); @@ -262,7 +262,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $this->view->query_get = array(); $cat_dao = new FreshRSS_CategoryDAO(); $feed_dao = FreshRSS_Factory::createFeedDao(); - foreach ($this->view->conf->queries as $key => $query) { + foreach (FreshRSS_Context::$conf->queries as $key => $query) { if (!isset($query['get'])) { continue; } @@ -330,7 +330,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { */ public function addQueryAction() { $whitelist = array('get', 'order', 'name', 'search', 'state'); - $queries = $this->view->conf->queries; + $queries = FreshRSS_Context::$conf->queries; $query = Minz_Request::params(); $query['name'] = _t('query_number', count($queries) + 1); foreach ($query as $key => $value) { @@ -342,8 +342,8 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $query['state'] -= FreshRSS_Entry::STATE_STRICT; } $queries[] = $query; - $this->view->conf->_queries($queries); - $this->view->conf->save(); + FreshRSS_Context::$conf->_queries($queries); + FreshRSS_Context::$conf->save(); Minz_Request::good(_t('query_created', $query['name']), array('c' => 'configure', 'a' => 'queries')); diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php index a1dfacb4d..449029648 100755 --- a/app/Controllers/entryController.php +++ b/app/Controllers/entryController.php @@ -21,7 +21,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { // the end. $this->params = array(); $output = Minz_Request::param('output', ''); - if ($output != '' && $this->view->conf->view_mode !== $output) { + if ($output != '' && FreshRSS_Context::$conf->view_mode !== $output) { $this->params['output'] = $output; } @@ -167,7 +167,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { public function purgeAction() { @set_time_limit(300); - $nb_month_old = max($this->view->conf->old_entries, 1); + $nb_month_old = max(FreshRSS_Context::$conf->old_entries, 1); $date_min = time() - (3600 * 24 * 30 * $nb_month_old); $feedDAO = FreshRSS_Factory::createFeedDao(); @@ -181,7 +181,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { if ($feed_history == -2) { // TODO: -2 must be a constant! // -2 means we take the default value from configuration - $feed_history = $this->view->conf->keep_history_default; + $feed_history = FreshRSS_Context::$conf->keep_history_default; } if ($feed_history >= 0) { diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 2a7238eaf..c2859edf4 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -14,7 +14,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // Token is useful in the case that anonymous refresh is forbidden // and CRON task cannot be used with php command so the user can // set a CRON task to refresh his feeds by using token inside url - $token = $this->view->conf->token; + $token = FreshRSS_Context::$conf->token; $token_param = Minz_Request::param('token', ''); $token_is_ok = ($token != '' && $token == $token_param); $action = Minz_Request::actionName(); @@ -154,14 +154,14 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feed->_id($id); $feed->faviconPrepare(); - $is_read = $this->view->conf->mark_when['reception'] ? 1 : 0; + $is_read = FreshRSS_Context::$conf->mark_when['reception'] ? 1 : 0; $entryDAO = FreshRSS_Factory::createEntryDao(); // We want chronological order and SimplePie uses reverse order. $entries = array_reverse($feed->entries()); // Calculate date of oldest entries we accept in DB. - $nb_month_old = $this->view->conf->old_entries; + $nb_month_old = FreshRSS_Context::$conf->old_entries; $date_min = time() - (3600 * 24 * 30 * $nb_month_old); // Use a shared statement and a transaction to improve a LOT the @@ -265,15 +265,15 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feeds[] = $feed; } } else { - $feeds = $feedDAO->listFeedsOrderUpdate($this->view->conf->ttl_default); + $feeds = $feedDAO->listFeedsOrderUpdate(FreshRSS_Context::$conf->ttl_default); } // Calculate date of oldest entries we accept in DB. - $nb_month_old = max($this->view->conf->old_entries, 1); + $nb_month_old = max(FreshRSS_Context::$conf->old_entries, 1); $date_min = time() - (3600 * 24 * 30 * $nb_month_old); $updated_feeds = 0; - $is_read = $this->view->conf->mark_when['reception'] ? 1 : 0; + $is_read = FreshRSS_Context::$conf->mark_when['reception'] ? 1 : 0; foreach ($feeds as $feed) { if (!$feed->lock()) { Minz_Log::notice('Feed already being actualized: ' . $feed->url()); @@ -294,7 +294,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if ($feed_history == -2) { // TODO: -2 must be a constant! // -2 means we take the default value from configuration - $feed_history = $this->view->conf->keep_history_default; + $feed_history = FreshRSS_Context::$conf->keep_history_default; } // We want chronological order and SimplePie uses reverse order. @@ -470,8 +470,8 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // TODO: Delete old favicon // Remove related queries - $this->view->conf->remove_query_by_get('f_' . $id); - $this->view->conf->save(); + FreshRSS_Context::$conf->remove_query_by_get('f_' . $id); + FreshRSS_Context::$conf->save(); Minz_Request::good(_t('feed_deleted'), $redirect_url); } else { diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index aaac1b68b..ab277e688 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -289,7 +289,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { return true; } - $is_read = $this->view->conf->mark_when['reception'] ? 1 : 0; + $is_read = FreshRSS_Context::$conf->mark_when['reception'] ? 1 : 0; $google_compliant = strpos($article_object['id'], 'com.google') !== false; @@ -484,7 +484,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $this->view->type = 'feed/' . $feed->id(); $this->view->entries = $this->entryDAO->listWhere( 'f', $feed->id(), FreshRSS_Entry::STATE_ALL, 'ASC', - $this->view->conf->posts_per_page + FreshRSS_Context::$conf->posts_per_page ); $this->view->feed = $feed; } diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 5b490e672..f994e257c 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -5,7 +5,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { public function indexAction() { $output = Minz_Request::param('output'); - $token = $this->view->conf->token; + $token = FreshRSS_Context::$conf->token; // check if user is logged in if (!FreshRSS_Auth::hasAccess() && !Minz_Configuration::allowAnonymous()) { @@ -76,11 +76,11 @@ class FreshRSS_index_Controller extends Minz_ActionController { ); // On récupère les différents éléments de filtrage - $this->view->state = Minz_Request::param('state', $this->view->conf->default_view); + $this->view->state = Minz_Request::param('state', FreshRSS_Context::$conf->default_view); $state_param = Minz_Request::param('state', null); $filter = Minz_Request::param('search', ''); - $this->view->order = $order = Minz_Request::param('order', $this->view->conf->sort_order); - $nb = Minz_Request::param('nb', $this->view->conf->posts_per_page); + $this->view->order = $order = Minz_Request::param('order', FreshRSS_Context::$conf->sort_order); + $nb = Minz_Request::param('nb', FreshRSS_Context::$conf->posts_per_page); $first = Minz_Request::param('next', ''); $ajax_request = Minz_Request::param('ajax', false); diff --git a/app/Controllers/javascriptController.php b/app/Controllers/javascriptController.php index 14e6f36de..62f413989 100755 --- a/app/Controllers/javascriptController.php +++ b/app/Controllers/javascriptController.php @@ -8,7 +8,7 @@ class FreshRSS_javascript_Controller extends Minz_ActionController { public function actualizeAction() { header('Content-Type: text/javascript; charset=UTF-8'); $feedDAO = FreshRSS_Factory::createFeedDao(); - $this->view->feeds = $feedDAO->listFeedsOrderUpdate($this->view->conf->ttl_default); + $this->view->feeds = $feedDAO->listFeedsOrderUpdate(FreshRSS_Context::$conf->ttl_default); } public function nbUnreadsPerFeedAction() { diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index d5c90a382..61d33437d 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -42,9 +42,9 @@ class FreshRSS_user_Controller extends Minz_ActionController { $passwordPlain = ''; $passwordHash = preg_replace('/^\$2[xy]\$/', '\$2a\$', $passwordHash); //Compatibility with bcrypt.js $ok &= ($passwordHash != ''); - $this->view->conf->_passwordHash($passwordHash); + FreshRSS_Context::$conf->_passwordHash($passwordHash); } - Minz_Session::_param('passwordHash', $this->view->conf->passwordHash); + Minz_Session::_param('passwordHash', FreshRSS_Context::$conf->passwordHash); $passwordPlain = Minz_Request::param('apiPasswordPlain', '', true); if ($passwordPlain != '') { @@ -55,17 +55,17 @@ class FreshRSS_user_Controller extends Minz_ActionController { $passwordPlain = ''; $passwordHash = preg_replace('/^\$2[xy]\$/', '\$2a\$', $passwordHash); //Compatibility with bcrypt.js $ok &= ($passwordHash != ''); - $this->view->conf->_apiPasswordHash($passwordHash); + FreshRSS_Context::$conf->_apiPasswordHash($passwordHash); } // TODO: why do we need of hasAccess here? if (FreshRSS_Auth::hasAccess('admin')) { - $this->view->conf->_mail_login(Minz_Request::param('mail_login', '', true)); + FreshRSS_Context::$conf->_mail_login(Minz_Request::param('mail_login', '', true)); } - $email = $this->view->conf->mail_login; + $email = FreshRSS_Context::$conf->mail_login; Minz_Session::_param('mail', $email); - $ok &= $this->view->conf->save(); + $ok &= FreshRSS_Context::$conf->save(); if ($email != '') { $personaFile = DATA_PATH . '/persona/' . $email . '.txt'; @@ -113,9 +113,9 @@ class FreshRSS_user_Controller extends Minz_ActionController { $db = Minz_Configuration::dataBase(); require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php'); - $new_user_language = Minz_Request::param('new_user_language', $this->view->conf->language); - if (!in_array($new_user_language, $this->view->conf->availableLanguages())) { - $new_user_language = $this->view->conf->language; + $new_user_language = Minz_Request::param('new_user_language', FreshRSS_Context::$conf->language); + if (!in_array($new_user_language, FreshRSS_Context::$conf->availableLanguages())) { + $new_user_language = FreshRSS_Context::$conf->language; } $new_user_name = Minz_Request::param('new_user_name'); diff --git a/app/FreshRSS.php b/app/FreshRSS.php index e1399ad78..752b14e31 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -24,9 +24,7 @@ class FreshRSS extends Minz_FrontController { } // Load context and configuration. - // TODO: remove $this->view->conf variable which is contained in context FreshRSS_Context::init(); - Minz_View::_param('conf', FreshRSS_Context::$conf); $this->loadParamsView(); $this->loadStylesAndScripts(); diff --git a/app/layout/aside_flux.phtml b/app/layout/aside_flux.phtml index a66be2ed9..114ccbf56 100644 --- a/app/layout/aside_flux.phtml +++ b/app/layout/aside_flux.phtml @@ -1,4 +1,4 @@ -
    +
      @@ -17,7 +17,7 @@ 'index', 'a' => 'index', 'params' => array()); - if ($this->conf->view_mode !== Minz_Request::param('output', 'normal')) { + if (FreshRSS_Context::$conf->view_mode !== Minz_Request::param('output', 'normal')) { $arUrl['params']['output'] = 'normal'; } ?> @@ -47,7 +47,7 @@ $c_show = false; if ($this->get_c == $cat->id()) { $c_active = true; - if (!$this->conf->display_categories || $this->get_f) { + if (!FreshRSS_Context::$conf->display_categories || $this->get_f) { $c_show = true; } } @@ -92,7 +92,7 @@
    • - conf->reading_confirm ? 'confirm' : ''; ?> + reading_confirm ? 'confirm' : ''; ?>
    • - conf->queries as $query) { ?> + queries as $query) { ?>
    • - conf->queries) > 0) { ?> + queries) > 0) { ?>
    • @@ -132,7 +132,7 @@ $string_mark = _t('mark_cat_read'); } $nextGet = $get; - if ($this->conf->onread_jump_next && strlen($get) > 2) { + if (FreshRSS_Context::$conf->onread_jump_next && strlen($get) > 2) { $anotherUnreadId = ''; $foundCurrent = false; switch ($get[0]) { @@ -180,7 +180,7 @@ $arUrl = array('c' => 'entry', 'a' => 'read', 'params' => array('get' => $get, 'nextGet' => $nextGet, 'idMax' => $idMax)); $output = Minz_Request::param('output', ''); - if ($output != '' && $this->conf->view_mode !== $output) { + if ($output != '' && FreshRSS_Context::$conf->view_mode !== $output) { $arUrl['params']['output'] = $output; } $markReadUrl = Minz_Url::display($arUrl); @@ -190,7 +190,7 @@
    - - + + - - + + - - - - - - + + + + + +
    conf->topline_read ? ' checked="checked"' : ''; ?> />conf->topline_favorite ? ' checked="checked"' : ''; ?> />topline_read ? ' checked="checked"' : ''; ?> />topline_favorite ? ' checked="checked"' : ''; ?> /> conf->topline_date ? ' checked="checked"' : ''; ?> />conf->topline_link ? ' checked="checked"' : ''; ?> />topline_date ? ' checked="checked"' : ''; ?> />topline_link ? ' checked="checked"' : ''; ?> />
    conf->bottomline_read ? ' checked="checked"' : ''; ?> />conf->bottomline_favorite ? ' checked="checked"' : ''; ?> />conf->bottomline_sharing ? ' checked="checked"' : ''; ?> />conf->bottomline_tags ? ' checked="checked"' : ''; ?> />conf->bottomline_date ? ' checked="checked"' : ''; ?> />conf->bottomline_link ? ' checked="checked"' : ''; ?> />bottomline_read ? ' checked="checked"' : ''; ?> />bottomline_favorite ? ' checked="checked"' : ''; ?> />bottomline_sharing ? ' checked="checked"' : ''; ?> />bottomline_tags ? ' checked="checked"' : ''; ?> />bottomline_date ? ' checked="checked"' : ''; ?> />bottomline_link ? ' checked="checked"' : ''; ?> />

    @@ -95,7 +95,7 @@
    - +
    diff --git a/app/views/configure/queries.phtml b/app/views/configure/queries.phtml index e778ce078..994dfc11b 100644 --- a/app/views/configure/queries.phtml +++ b/app/views/configure/queries.phtml @@ -6,7 +6,7 @@
    - conf->queries as $key => $query) { ?> + queries as $key => $query) { ?>
    - conf->queries) > 0) { ?> + queries) > 0) { ?>
    diff --git a/app/views/configure/reading.phtml b/app/views/configure/reading.phtml index c8685acf3..ef775b4b1 100644 --- a/app/views/configure/reading.phtml +++ b/app/views/configure/reading.phtml @@ -9,7 +9,7 @@
    - +
    @@ -18,8 +18,8 @@
    @@ -28,9 +28,9 @@
    @@ -39,9 +39,9 @@
    @@ -49,7 +49,7 @@
    @@ -58,7 +58,7 @@
    @@ -68,7 +68,7 @@
    @@ -78,7 +78,7 @@
    @@ -88,7 +88,7 @@
    @@ -98,7 +98,7 @@
    @@ -108,7 +108,7 @@
    @@ -119,19 +119,19 @@
    @@ -141,7 +141,7 @@
    diff --git a/app/views/configure/sharing.phtml b/app/views/configure/sharing.phtml index 09c1e6f40..ef5e85a0c 100644 --- a/app/views/configure/sharing.phtml +++ b/app/views/configure/sharing.phtml @@ -15,8 +15,8 @@
    '> - conf->sharing as $key => $sharing): ?> - conf->shares[$sharing['type']]; ?> + sharing as $key => $sharing): ?> + shares[$sharing['type']]; ?>
    diff --git a/app/views/user/profile.phtml b/app/views/user/profile.phtml new file mode 100644 index 000000000..60257012c --- /dev/null +++ b/app/views/user/profile.phtml @@ -0,0 +1,59 @@ +partial('aside_configure'); ?> + +
    + + +
    + + +
    + +
    + + +
    +
    + +
    + +
    +
    + /> + +
    + +
    +
    + + +
    + +
    +
    + /> + +
    +
    +
    + + +
    + + mail_login; ?> +
    + placeholder="alice@example.net" /> + +
    +
    + +
    +
    + + +
    +
    +
    +
    -- cgit v1.2.3 From 4dec7bf127fdb71c78d09bb4f64995028a60c439 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 26 Oct 2014 12:37:38 +0100 Subject: Fix i18n string Order has been changed due to a little bug in sort order function. --- app/Controllers/authController.php | 6 +- app/i18n/en.php | 109 +++++++++++++++++++------------------ app/i18n/fr.php | 109 +++++++++++++++++++------------------ 3 files changed, 114 insertions(+), 110 deletions(-) diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index a08f906e3..491be8d8a 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -23,6 +23,8 @@ class FreshRSS_auth_Controller extends Minz_ActionController { array('error' => array(_t('access_denied')))); } + Minz_View::prependTitle(_t('gen.title.authentication') . ' · '); + if (Minz_Request::isPost()) { $ok = true; @@ -55,10 +57,10 @@ class FreshRSS_auth_Controller extends Minz_ActionController { invalidateHttpCache(); if ($ok) { - Minz_Request::good('configuration_updated', + Minz_Request::good(_t('configuration_updated'), array('c' => 'auth', 'a' => 'index')); } else { - Minz_Request::bad('error_occurred', + Minz_Request::bad(_t('error_occurred'), array('c' => 'auth', 'a' => 'index')); } } diff --git a/app/i18n/en.php b/app/i18n/en.php index 275471e19..1e6621c12 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -1,5 +1,17 @@ '\\A\\p\\r\\i\\l', + 'Aug' => '\\A\\u\\g\\u\\s\\t', + 'Dec' => '\\D\\e\\c\\e\\m\\b\\e\\r', + 'Feb' => '\\F\\e\\b\\r\\u\\a\\r\\y', + 'Jan' => '\\J\\a\\n\\u\\a\\r\\y', + 'Jul' => '\\J\\u\\l\\y', + 'Jun' => '\\J\\u\\n\\e', + 'Mar' => '\\M\\a\\r\\c\\h', + 'May' => '\\M\\a\\y', + 'Nov' => '\\N\\o\\v\\e\\m\\b\\e\\r', + 'Oct' => '\\O\\c\\t\\o\\b\\e\\r', + 'Sep' => '\\S\\e\\p\\t\\e\\m\\b\\e\\r', 'about' => 'About', 'about_freshrss' => 'About FreshRSS', 'access_denied' => 'You don’t have permission to access this page', @@ -61,42 +73,40 @@ 'advanced' => 'Advanced', 'after_onread' => 'After “mark all as read”,', 'agpl3' => 'AGPL 3', + 'all_feeds' => 'All feeds', 'allow_anonymous' => 'Allow anonymous reading of the articles of the default user (%s)', 'allow_anonymous_refresh' => 'Allow anonymous refresh of the articles', - 'all_feeds' => 'All feeds', 'already_subscribed' => 'You have already subscribed to %s', 'api_enabled' => 'Allow API access (required for mobile apps)', - 'Apr' => '\\A\\p\\r\\i\\l', 'apr' => 'apr', 'april' => 'Apr', 'archiving_configuration' => 'Archiving', 'archiving_configuration_help' => 'More options are available in the individual stream settings', 'article' => 'Article', - 'articles' => 'articles', - 'articles_per_page' => 'Number of articles per page', - 'articles_to_display' => 'Articles to display', 'article_icons' => 'Article icons', 'article_open_on_website' => 'when article is opened on its original website', 'article_published_on' => 'This article originally appeared on %s', 'article_published_on_author' => 'This article originally appeared on %s by %s', 'article_viewed' => 'when article is viewed', + 'articles' => 'articles', + 'articles_per_page' => 'Number of articles per page', + 'articles_to_display' => 'Articles to display', 'ask_empty' => 'Clear?', 'attention' => 'Attention!', - 'Aug' => '\\A\\u\\g\\u\\s\\t', 'aug' => 'aug', 'august' => 'Aug', - 'author' => 'Author', 'auth_form' => 'Web form (traditional, requires JavaScript)', 'auth_form_not_set' => 'A problem occured during authentication system configuration. Please retry later.', 'auth_form_set' => 'Form is now your default authentication system.', + 'auth_no_password_set' => 'Administrator password hasn’t been set. This feature isn’t available.', 'auth_none' => 'None (dangerous)', 'auth_not_persona' => 'Only Persona system can be reset.', - 'auth_no_password_set' => 'Administrator password hasn’t been set. This feature isn’t available.', 'auth_persona' => 'Mozilla Persona (modern, requires JavaScript)', 'auth_reset' => 'Authentication reset', 'auth_token' => 'Authentication token', 'auth_type' => 'Authentication method', 'auth_will_reset' => 'Authentication system will be reset: a form will be used instead of Persona.', + 'author' => 'Author', 'auto_load_more' => 'Load next articles at the page bottom', 'auto_read_when' => 'Mark article as read…', 'auto_share' => 'Share', @@ -105,9 +115,9 @@ 'bad_opml_file' => 'Your OPML file is invalid', 'base_url' => 'Base URL', 'bdd' => 'Database', - 'bdd_configuration' => 'Database configuration', 'bdd_conf_is_ko' => 'Verify your database information.', 'bdd_conf_is_ok' => 'Database configuration has been saved.', + 'bdd_configuration' => 'Database configuration', 'bdd_type' => 'Type of database', 'before_one_day' => 'Before one day', 'before_one_week' => 'Before one week', @@ -123,8 +133,8 @@ 'by_email' => 'By email', 'by_feed' => 'by feed', 'cache_is_ok' => 'Permissions on cache directory are good', - 'cancel' => 'Cancel', 'can_not_be_deleted' => 'Cannot be deleted', + 'cancel' => 'Cancel', 'categories' => 'Categories', 'categories_management' => 'Categories management', 'categories_updated' => 'Categories have been updated', @@ -135,10 +145,10 @@ 'category_emptied' => 'Category has been emptied', 'category_empty' => 'Empty category', 'category_name_exists' => 'Category name already exists.', - 'category_not_delete_default' => 'You cannot delete the default category!', - 'category_not_exist' => 'The category does not exist!', 'category_no_id' => 'You must precise the id of the category.', 'category_no_name' => 'Category name cannot be empty.', + 'category_not_delete_default' => 'You cannot delete the default category!', + 'category_not_exist' => 'The category does not exist!', 'category_number' => 'Category n°%d', 'category_updated' => 'Category has been updated.', 'change_value' => 'You should change this value by any other', @@ -165,7 +175,6 @@ 'current_user' => 'Current user', 'damn' => 'Damn!', 'data_is_ok' => 'Permissions on data directory are good', - 'Dec' => '\\D\\e\\c\\e\\m\\b\\e\\r', 'dec' => 'dec', 'december' => 'Dec', 'default_category' => 'Uncategorized', @@ -178,9 +187,9 @@ 'display_articles_unfolded' => 'Show articles unfolded by default', 'display_categories_unfolded' => 'Show categories folded by default', 'display_configuration' => 'Display', + 'do_not_change_if_doubt' => 'Don’t change if you doubt about it', 'dom_is_nok' => 'You lack a required library to browse the DOM (php-xml package)', 'dom_is_ok' => 'You have the required library to browse the DOM', - 'do_not_change_if_doubt' => 'Don’t change if you doubt about it', 'email' => 'Email', 'error_occurred' => 'An error occurred', 'error_occurred_update' => 'Nothing was changed', @@ -193,19 +202,8 @@ 'favicons_is_ok' => 'Permissions on favicons directory are good', 'favorite_feeds' => 'Favourites (%s)', 'feb' => 'feb', - 'Feb' => '\\F\\e\\b\\r\\u\\a\\r\\y', 'february' => 'Feb', 'feed' => 'Feed', - 'feedback.login.error' => 'Login is invalid', - 'feedback.login.success' => 'You are connected', - 'feedback.logout.success' => 'You are disconnected', - 'feedback.user_profile.updated' => 'Your profile has been modified', - 'feeds' => 'Feeds', - 'feeds_actualized' => 'RSS feeds have been updated', - 'feeds_imported' => 'Your feeds have been imported and will now be updated', - 'feeds_imported_with_errors' => 'Your feeds have been imported but some errors occurred', - 'feeds_marked_read' => 'Feeds have been marked as read', - 'feeds_moved_category_deleted' => 'When you delete a category, their feeds are automatically classified under %s.', 'feed_actualized' => '%s has been updated', 'feed_added' => 'RSS feed %s has been added', 'feed_deleted' => 'Feed has been deleted', @@ -217,6 +215,16 @@ 'feed_updated' => 'Feed has been updated', 'feed_url' => 'Feed URL', 'feed_validator' => 'Check the validity of the feed', + 'feedback.login.error' => 'Login is invalid', + 'feedback.login.success' => 'You are connected', + 'feedback.logout.success' => 'You are disconnected', + 'feedback.user_profile.updated' => 'Your profile has been modified', + 'feeds' => 'Feeds', + 'feeds_actualized' => 'RSS feeds have been updated', + 'feeds_imported' => 'Your feeds have been imported and will now be updated', + 'feeds_imported_with_errors' => 'Your feeds have been imported but some errors occurred', + 'feeds_marked_read' => 'Feeds have been marked as read', + 'feeds_moved_category_deleted' => 'When you delete a category, their feeds are automatically classified under %s.', 'file_cannot_be_uploaded' => 'File cannot be uploaded!', 'file_is_nok' => 'Check permissions on %s directory. HTTP server must have rights to write into', 'file_to_import' => 'File to import
    (OPML, Json or Zip)', @@ -239,12 +247,13 @@ 'gen.menu.check_install' => 'Installation checking', 'gen.menu.user_management' => 'Manage users', 'gen.menu.user_profile' => 'Profile', + 'gen.title.authentication' => 'Authentication', 'gen.title.check_install' => 'Installation checking', 'gen.title.global_view' => 'Global view', 'gen.title.user_management' => 'Manage users', 'gen.title.user_profile' => 'Profile', - 'general_configuration' => 'General configuration', 'general_conf_is_ok' => 'General configuration has been saved.', + 'general_configuration' => 'General configuration', 'github_or_email' => 'on Github or by mail', 'global_view' => 'Global view', 'help' => 'Display documentation', @@ -261,24 +270,21 @@ 'import' => 'Import', 'import_export' => 'Import / export', 'informations' => 'Information', + 'install_not_deleted' => 'Something went wrong; you must delete the file %s manually.', 'installation_is_ok' => 'The installation process was successful.
    The final step will now attempt to delete any file and database backup created during the update process.
    You may choose to skip this step by deleting ./data/do-install.txt manually.', 'installation_step' => 'Installation — step %d · FreshRSS', - 'install_not_deleted' => 'Something went wrong; you must delete the file %s manually.', 'internal_problem_feed' => 'The RSS feed could not be added. Check FressRSS logs for details.', 'invalid_login' => 'Login is invalid', 'invalid_url' => 'URL %s is invalid', 'is_admin' => 'is administrator', - 'Jan' => '\\J\\a\\n\\u\\a\\r\\y', 'jan' => 'jan', 'january' => 'Jan', 'javascript_for_shortcuts' => 'JavaScript must be enabled in order to use shortcuts', 'javascript_is_better' => 'FreshRSS is more pleasant with JavaScript enabled', 'javascript_should_be_activated' => 'JavaScript must be enabled', 'jul' => 'jul', - 'Jul' => '\\J\\u\\l\\y', 'july' => 'Jul', 'jump_next' => 'jump to next unread sibling (feed or category)', - 'Jun' => '\\J\\u\\n\\e', 'jun' => 'jun', 'june' => 'Jun', 'keep_history' => 'Minimum number of articles to keep', @@ -295,6 +301,7 @@ 'lead_developer' => 'Lead developer', 'license' => 'License', 'load_more' => 'Load more articles', + 'log_is_ok' => 'Permissions on logs directory are good', 'login' => 'Login', 'login_configuration' => 'Login', 'login_persona_problem' => 'Connection problem with Persona?', @@ -303,41 +310,30 @@ 'logout' => 'Logout', 'logs' => 'Logs', 'logs_empty' => 'Log file is empty', - 'log_is_ok' => 'Permissions on logs directory are good', 'main_stream' => 'Main stream', 'mar' => 'mar', - 'Mar' => '\\M\\a\\r\\c\\h', 'march' => 'Mar', 'mark_all_read' => 'Mark all as read', 'mark_cat_read' => 'Mark category as read', 'mark_favorite' => 'Mark as favourite', 'mark_feed_read' => 'Mark feed as read', 'mark_read' => 'Mark as read', - 'May' => '\\M\\a\\y', 'may' => 'May', 'minz_is_nok' => 'You lack the Minz framework. You should execute build.sh script or download it on Github and install in %s directory the content of its /lib directory.', 'minz_is_ok' => 'You have the Minz framework', 'mon' => 'Mon', 'month' => 'months', 'more_information' => 'More information', - 'newer_first' => 'Newer first', + 'n_entries_deleted' => '%d articles have been deleted', + 'n_feeds_actualized' => '%d feeds have been updated', 'new_article' => 'There are new available articles, click to refresh the page.', 'new_category' => 'New category', + 'newer_first' => 'Newer first', 'next' => 'Next', 'next_article' => 'Skip to the next article', 'next_page' => 'Skip to the next page', 'next_step' => 'Go to the next step', 'no' => 'No', - 'normal_view' => 'Normal view', - 'nothing_to_load' => 'There are no more articles', - 'notif_body_new_articles' => 'There are \\d new articles to read on FreshRSS.', - 'notif_title_new_articles' => 'FreshRSS: new articles!', - 'not_read' => '%d unread', - 'not_reads' => '%d unread', - 'not_yet_implemented' => 'Not yet implemented', - 'Nov' => '\\N\\o\\v\\e\\m\\b\\e\\r', - 'nov' => 'nov', - 'november' => 'Nov', 'no_feed_actualized' => 'No RSS feed has been updated', 'no_feed_to_display' => 'There is no article to show.', 'no_feed_to_refresh' => 'There is no feed to refresh…', @@ -347,12 +343,18 @@ 'no_selected_feed' => 'No feed selected.', 'no_update' => 'No update to apply', 'no_zip_extension' => 'Zip extension is not present on your server.', + 'normal_view' => 'Normal view', + 'not_read' => '%d unread', + 'not_reads' => '%d unread', + 'not_yet_implemented' => 'Not yet implemented', + 'nothing_to_load' => 'There are no more articles', + 'notif_body_new_articles' => 'There are \\d new articles to read on FreshRSS.', + 'notif_title_new_articles' => 'FreshRSS: new articles!', + 'nov' => 'nov', + 'november' => 'Nov', 'number_articles' => '%d articles', 'number_divided_when_reader' => 'Divided by 2 in the reading view.', 'number_feeds' => '%d feeds', - 'n_entries_deleted' => '%d articles have been deleted', - 'n_feeds_actualized' => '%d feeds have been updated', - 'Oct' => '\\O\\c\\t\\o\\b\\e\\r', 'oct' => 'oct', 'october' => 'Oct', 'ok' => 'Ok!', @@ -419,8 +421,8 @@ 'refresh' => 'Refresh', 'related_tags' => 'Related tags', 'retrieve_truncated_feeds' => 'Retrieves truncated RSS feeds (attention, requires more time!)', - 'rss_feeds_of' => 'RSS feed of %s', 'rss_feed_management' => 'RSS feeds management', + 'rss_feeds_of' => 'RSS feed of %s', 'rss_view' => 'RSS feed', 'sat' => 'Sat', 'save' => 'Save', @@ -431,7 +433,6 @@ 'see_on_website' => 'See on original website', 'see_website' => 'See website', 'sep' => 'sep', - 'Sep' => '\\S\\e\\p\\t\\e\\m\\b\\e\\r', 'september' => 'Sep', 'shaarli' => 'Shaarli', 'share' => 'Share', @@ -492,7 +493,6 @@ 'twitter' => 'Twitter', 'unsafe_autologin' => 'Allow unsafe automatic login using the format: ', 'update' => 'Update', - 'updated' => 'Modifications have been updated', 'update_apply' => 'Apply', 'update_can_apply' => 'An update is available.', 'update_check' => 'Check for new updates', @@ -504,15 +504,16 @@ 'update_server_not_found' => 'Update server cannot be found. [%s]', 'update_start' => 'Start update process', 'update_system' => 'Update system', + 'updated' => 'Modifications have been updated', 'upon_reception' => 'upon reception of the article', - 'username' => 'Username', - 'username_admin' => 'Administrator username', - 'users' => 'Users', - 'users_list' => 'List of users', 'user_created' => 'User %s has been created', 'user_deleted' => 'User %s has been deleted', 'user_filter' => 'Access user filters', 'user_filter_help' => 'If there is only one user filter, it is used. Else filters are accessible by their number.', + 'username' => 'Username', + 'username_admin' => 'Administrator username', + 'users' => 'Users', + 'users_list' => 'List of users', 'version' => 'Version', 'version_update' => 'Update', 'wallabag' => 'wallabag', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index e3a49d54c..61a84cc04 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -1,5 +1,17 @@ '\\a\\v\\r\\i\\l', + 'Aug' => '\\a\\o\\û\\t', + 'Dec' => '\\d\\é\\c\\e\\m\\b\\r\\e', + 'Feb' => '\\f\\é\\v\\r\\i\\e\\r', + 'Jan' => '\\j\\a\\n\\v\\i\\e\\r', + 'Jul' => '\\j\\u\\i\\l\\l\\e\\t', + 'Jun' => '\\j\\u\\i\\n', + 'Mar' => '\\m\\a\\r\\s', + 'May' => '\\m\\a\\i', + 'Nov' => '\\n\\o\\v\\e\\m\\b\\r\\e', + 'Oct' => '\\o\\c\\t\\o\\b\\r\\e', + 'Sep' => '\\s\\e\\p\\t\\e\\m\\b\\r\\e', 'about' => 'À propos', 'about_freshrss' => 'À propos de FreshRSS', 'access_denied' => 'Vous n’avez pas le droit d’accéder à cette page !', @@ -61,42 +73,40 @@ 'advanced' => 'Avancé', 'after_onread' => 'Après “marquer tout comme lu”,', 'agpl3' => 'AGPL 3', + 'all_feeds' => 'Tous les flux', 'allow_anonymous' => 'Autoriser la lecture anonyme des articles de l’utilisateur par défaut (%s)', 'allow_anonymous_refresh' => 'Autoriser le rafraîchissement anonyme des flux', - 'all_feeds' => 'Tous les flux', 'already_subscribed' => 'Vous êtes déjà abonné à %s', 'api_enabled' => 'Autoriser l’accès par API (nécessaire pour les applis mobiles)', - 'Apr' => '\\a\\v\\r\\i\\l', 'apr' => 'avr.', 'april' => 'avril', 'archiving_configuration' => 'Archivage', 'archiving_configuration_help' => 'D’autres options sont disponibles dans la configuration individuelle des flux.', 'article' => 'Article', - 'articles' => 'articles', - 'articles_per_page' => 'Nombre d’articles par page', - 'articles_to_display' => 'Articles à afficher', 'article_icons' => 'Icônes d’article', 'article_open_on_website' => 'lorsque l’article est ouvert sur le site d’origine', 'article_published_on' => 'Article publié initialement sur %s', 'article_published_on_author' => 'Article publié initialement sur %s par %s', 'article_viewed' => 'lorsque l’article est affiché', + 'articles' => 'articles', + 'articles_per_page' => 'Nombre d’articles par page', + 'articles_to_display' => 'Articles à afficher', 'ask_empty' => 'Vider ?', 'attention' => 'Attention !', - 'Aug' => '\\a\\o\\û\\t', 'aug' => 'août', 'august' => 'août', - 'author' => 'Auteur', 'auth_form' => 'Formulaire (traditionnel, requiert JavaScript)', 'auth_form_not_set' => 'Un problème est survenu lors de la configuration de votre système d’authentification. Veuillez réessayer plus tard.', 'auth_form_set' => 'Le formulaire est désormais votre système d’authentification.', + 'auth_no_password_set' => 'Aucun mot de passe administrateur n’a été précisé. Cette fonctionnalité n’est pas disponible.', 'auth_none' => 'Aucune (dangereux)', 'auth_not_persona' => 'Seul le système d’authentification Persona peut être réinitialisé.', - 'auth_no_password_set' => 'Aucun mot de passe administrateur n’a été précisé. Cette fonctionnalité n’est pas disponible.', 'auth_persona' => 'Mozilla Persona (moderne, requiert JavaScript)', 'auth_reset' => 'Réinitialisation de l’authentification', 'auth_token' => 'Jeton d’identification', 'auth_type' => 'Méthode d’authentification', 'auth_will_reset' => 'Le système d’authentification va être réinitialisé : un formulaire sera utilisé à la place de Persona.', + 'author' => 'Auteur', 'auto_load_more' => 'Charger les articles suivants en bas de page', 'auto_read_when' => 'Marquer un article comme lu…', 'auto_share' => 'Partager', @@ -105,9 +115,9 @@ 'bad_opml_file' => 'Votre fichier OPML n’est pas valide.', 'base_url' => 'Base de l’URL', 'bdd' => 'Base de données', - 'bdd_configuration' => 'Base de données', 'bdd_conf_is_ko' => 'Vérifiez les informations d’accès à la base de données.', 'bdd_conf_is_ok' => 'La configuration de la base de données a été enregistrée.', + 'bdd_configuration' => 'Base de données', 'bdd_type' => 'Type de base de données', 'before_one_day' => 'Antérieurs à 1 jour', 'before_one_week' => 'Antérieurs à 1 semaine', @@ -123,8 +133,8 @@ 'by_email' => 'Par courriel', 'by_feed' => 'par flux', 'cache_is_ok' => 'Les droits sur le répertoire de cache sont bons', - 'cancel' => 'Annuler', 'can_not_be_deleted' => 'Ne peut pas être supprimée.', + 'cancel' => 'Annuler', 'categories' => 'Catégories', 'categories_management' => 'Gestion des catégories', 'categories_updated' => 'Les catégories ont été mises à jour.', @@ -135,10 +145,10 @@ 'category_emptied' => 'La catégorie a été vidée.', 'category_empty' => 'Catégorie vide', 'category_name_exists' => 'Une catégorie possède déjà ce nom.', - 'category_not_delete_default' => 'Vous ne pouvez pas supprimer la catégorie par défaut !', - 'category_not_exist' => 'Cette catégorie n’existe pas !', 'category_no_id' => 'Vous devez préciser l’id de la catégorie.', 'category_no_name' => 'Vous devez préciser un nom pour la catégorie.', + 'category_not_delete_default' => 'Vous ne pouvez pas supprimer la catégorie par défaut !', + 'category_not_exist' => 'Cette catégorie n’existe pas !', 'category_number' => 'Catégorie n°%d', 'category_updated' => 'La catégorie a été mise à jour.', 'change_value' => 'Vous devriez changer cette valeur par n’importe quelle autre', @@ -165,7 +175,6 @@ 'current_user' => 'Utilisateur actuel', 'damn' => 'Arf !', 'data_is_ok' => 'Les droits sur le répertoire de data sont bons', - 'Dec' => '\\d\\é\\c\\e\\m\\b\\r\\e', 'dec' => 'déc.', 'december' => 'décembre', 'default_category' => 'Sans catégorie', @@ -178,9 +187,9 @@ 'display_articles_unfolded' => 'Afficher les articles dépliés par défaut', 'display_categories_unfolded' => 'Afficher les catégories pliées par défaut', 'display_configuration' => 'Affichage', + 'do_not_change_if_doubt' => 'Laissez tel quel dans le doute', 'dom_is_nok' => 'Il manque une librairie pour parcourir le DOM (paquet php-xml)', 'dom_is_ok' => 'Vous disposez du nécessaire pour parcourir le DOM', - 'do_not_change_if_doubt' => 'Laissez tel quel dans le doute', 'email' => 'Courriel', 'error_occurred' => 'Une erreur est survenue !', 'error_occurred_update' => 'Rien n’a été modifié !', @@ -193,19 +202,8 @@ 'favicons_is_ok' => 'Les droits sur le répertoire des favicons sont bons', 'favorite_feeds' => 'Favoris (%s)', 'feb' => 'fév.', - 'Feb' => '\\f\\é\\v\\r\\i\\e\\r', 'february' => 'février', 'feed' => 'Flux', - 'feedback.login.error' => 'L’identifiant est invalide !', - 'feedback.login.success' => 'Vous êtes désormais connecté', - 'feedback.logout.success' => 'Vous avez été déconnecté', - 'feedback.user_profile.updated' => 'Votre profil a été mis à jour', - 'feeds' => 'Flux', - 'feeds_actualized' => 'Les flux ont été mis à jour.', - 'feeds_imported' => 'Vos flux ont été importés et vont maintenant être actualisés.', - 'feeds_imported_with_errors' => 'Vos flux ont été importés mais des erreurs sont survenues.', - 'feeds_marked_read' => 'Les flux ont été marqués comme lus.', - 'feeds_moved_category_deleted' => 'Lors de la suppression d’une catégorie, ses flux seront automatiquement classés dans %s.', 'feed_actualized' => '%s a été mis à jour.', 'feed_added' => 'Le flux %s a bien été ajouté.', 'feed_deleted' => 'Le flux a été supprimé.', @@ -217,6 +215,16 @@ 'feed_updated' => 'Le flux a été mis à jour.', 'feed_url' => 'URL du flux', 'feed_validator' => 'Vérifier la valididé du flux', + 'feedback.login.error' => 'L’identifiant est invalide !', + 'feedback.login.success' => 'Vous êtes désormais connecté', + 'feedback.logout.success' => 'Vous avez été déconnecté', + 'feedback.user_profile.updated' => 'Votre profil a été mis à jour', + 'feeds' => 'Flux', + 'feeds_actualized' => 'Les flux ont été mis à jour.', + 'feeds_imported' => 'Vos flux ont été importés et vont maintenant être actualisés.', + 'feeds_imported_with_errors' => 'Vos flux ont été importés mais des erreurs sont survenues.', + 'feeds_marked_read' => 'Les flux ont été marqués comme lus.', + 'feeds_moved_category_deleted' => 'Lors de la suppression d’une catégorie, ses flux seront automatiquement classés dans %s.', 'file_cannot_be_uploaded' => 'Le fichier ne peut pas être téléchargé !', 'file_is_nok' => 'Veuillez vérifier les droits sur le répertoire %s. Le serveur HTTP doit être capable d’écrire dedans', 'file_to_import' => 'Fichier à importer
    (OPML, Json ou Zip)', @@ -239,12 +247,13 @@ 'gen.menu.check_install' => 'Vérification de l\'installation', 'gen.menu.user_management' => 'Gestion des utilisateurs', 'gen.menu.user_profile' => 'Profil', + 'gen.title.authentication' => 'Authentification', 'gen.title.check_install' => 'Vérification de l\'installation', 'gen.title.global_view' => 'Vue globale', 'gen.title.user_management' => 'Gestion des utilisateurs', 'gen.title.user_profile' => 'Profil', - 'general_configuration' => 'Configuration générale', 'general_conf_is_ok' => 'La configuration générale a été enregistrée.', + 'general_configuration' => 'Configuration générale', 'github_or_email' => 'sur Github ou par courriel', 'global_view' => 'Vue globale', 'help' => 'Afficher la documentation', @@ -261,24 +270,21 @@ 'import' => 'Importer', 'import_export' => 'Importer / exporter', 'informations' => 'Informations', + 'install_not_deleted' => 'Quelque chose s’est mal passé, vous devez supprimer le fichier %s à la main.', 'installation_is_ok' => 'L’installation s’est bien passée.
    La dernière étape va maintenant tenter de supprimer les fichiers ainsi que d’éventuelles copies de base de données créés durant le processus de mise à jour.
    Vous pouvez choisir de sauter cette étape en supprimant ./data/do-install.txt manuellement.', 'installation_step' => 'Installation — étape %d · FreshRSS', - 'install_not_deleted' => 'Quelque chose s’est mal passé, vous devez supprimer le fichier %s à la main.', 'internal_problem_feed' => 'Le flux ne peut pas être ajouté. Consulter les logs de FreshRSS pour plus de détails.', 'invalid_login' => 'L’identifiant est invalide !', 'invalid_url' => 'L’url %s est invalide.', 'is_admin' => 'est administrateur', - 'Jan' => '\\j\\a\\n\\v\\i\\e\\r', 'jan' => 'jan.', 'january' => 'janvier', 'javascript_for_shortcuts' => 'Le JavaScript doit être activé pour pouvoir profiter des raccourcis.', 'javascript_is_better' => 'FreshRSS est plus agréable à utiliser avec JavaScript activé', 'javascript_should_be_activated' => 'Le JavaScript doit être activé.', 'jul' => 'jui.', - 'Jul' => '\\j\\u\\i\\l\\l\\e\\t', 'july' => 'juillet', 'jump_next' => 'sauter au prochain voisin non lu (flux ou catégorie)', - 'Jun' => '\\j\\u\\i\\n', 'jun' => 'juin', 'june' => 'juin', 'keep_history' => 'Nombre minimum d’articles à conserver', @@ -295,6 +301,7 @@ 'lead_developer' => 'Développeur principal', 'license' => 'Licence', 'load_more' => 'Charger plus d’articles', + 'log_is_ok' => 'Les droits sur le répertoire des logs sont bons', 'login' => 'Connexion', 'login_configuration' => 'Identification', 'login_persona_problem' => 'Problème de connexion à Persona ?', @@ -303,41 +310,30 @@ 'logout' => 'Déconnexion', 'logs' => 'Logs', 'logs_empty' => 'Les logs sont vides.', - 'log_is_ok' => 'Les droits sur le répertoire des logs sont bons', 'main_stream' => 'Flux principal', 'mar' => 'mar.', - 'Mar' => '\\m\\a\\r\\s', 'march' => 'mars', 'mark_all_read' => 'Tout marquer comme lu', 'mark_cat_read' => 'Marquer la catégorie comme lue', 'mark_favorite' => 'Mettre en favori', 'mark_feed_read' => 'Marquer le flux comme lu', 'mark_read' => 'Marquer comme lu', - 'May' => '\\m\\a\\i', 'may' => 'mai.', 'minz_is_nok' => 'Vous ne disposez pas de la librairie Minz. Vous devriez exécuter le script build.sh ou bien la télécharger sur Github et installer dans le répertoire %s le contenu de son répertoire /lib.', 'minz_is_ok' => 'Vous disposez du framework Minz', 'mon' => 'lun.', 'month' => 'mois', 'more_information' => 'Plus d’informations', - 'newer_first' => 'Plus récents en premier', + 'n_entries_deleted' => '%d articles ont été supprimés.', + 'n_feeds_actualized' => '%d flux ont été mis à jour.', 'new_article' => 'Il y a de nouveaux articles disponibles, cliquez pour rafraîchir la page.', 'new_category' => 'Nouvelle catégorie', + 'newer_first' => 'Plus récents en premier', 'next' => 'Suivant', 'next_article' => 'Passer à l’article suivant', 'next_page' => 'Passer à la page suivante', 'next_step' => 'Passer à l’étape suivante', 'no' => 'Non', - 'normal_view' => 'Vue normale', - 'nothing_to_load' => 'Fin des articles', - 'notif_body_new_articles' => 'Il y a \\d nouveaux articles à lire sur FreshRSS.', - 'notif_title_new_articles' => 'FreshRSS : nouveaux articles !', - 'not_read' => '%d non lu', - 'not_reads' => '%d non lus', - 'not_yet_implemented' => 'Pas encore implémenté', - 'Nov' => '\\n\\o\\v\\e\\m\\b\\r\\e', - 'nov' => 'nov.', - 'november' => 'novembre', 'no_feed_actualized' => 'Aucun flux n’a pu être mis à jour.', 'no_feed_to_display' => 'Il n’y a aucun article à afficher.', 'no_feed_to_refresh' => 'Il n’y a aucun flux à actualiser…', @@ -347,12 +343,18 @@ 'no_selected_feed' => 'Aucun flux sélectionné.', 'no_update' => 'Aucune mise à jour à appliquer', 'no_zip_extension' => 'L’extension Zip n’est pas présente sur votre serveur.', + 'normal_view' => 'Vue normale', + 'not_read' => '%d non lu', + 'not_reads' => '%d non lus', + 'not_yet_implemented' => 'Pas encore implémenté', + 'nothing_to_load' => 'Fin des articles', + 'notif_body_new_articles' => 'Il y a \\d nouveaux articles à lire sur FreshRSS.', + 'notif_title_new_articles' => 'FreshRSS : nouveaux articles !', + 'nov' => 'nov.', + 'november' => 'novembre', 'number_articles' => '%d articles', 'number_divided_when_reader' => 'Divisé par 2 dans la vue de lecture.', 'number_feeds' => '%d flux', - 'n_entries_deleted' => '%d articles ont été supprimés.', - 'n_feeds_actualized' => '%d flux ont été mis à jour.', - 'Oct' => '\\o\\c\\t\\o\\b\\r\\e', 'oct' => 'oct.', 'october' => 'octobre', 'ok' => 'Ok !', @@ -419,8 +421,8 @@ 'refresh' => 'Actualisation', 'related_tags' => 'Tags associés', 'retrieve_truncated_feeds' => 'Permet de récupérer les flux tronqués (attention, demande plus de temps !)', - 'rss_feeds_of' => 'Flux RSS de %s', 'rss_feed_management' => 'Gestion des flux RSS', + 'rss_feeds_of' => 'Flux RSS de %s', 'rss_view' => 'Flux RSS', 'sat' => 'sam.', 'save' => 'Enregistrer', @@ -431,7 +433,6 @@ 'see_on_website' => 'Voir sur le site d’origine', 'see_website' => 'Voir le site', 'sep' => 'sep.', - 'Sep' => '\\s\\e\\p\\t\\e\\m\\b\\r\\e', 'september' => 'septembre', 'shaarli' => 'Shaarli', 'share' => 'Partager', @@ -492,7 +493,6 @@ 'twitter' => 'Twitter', 'unsafe_autologin' => 'Autoriser les connexions automatiques non-sûres au format : ', 'update' => 'Mise à jour', - 'updated' => 'Modifications enregistrées.', 'update_apply' => 'Appliquer la mise à jour', 'update_can_apply' => 'Une mise à jour est disponible.', 'update_check' => 'Vérifier les mises à jour', @@ -504,15 +504,16 @@ 'update_server_not_found' => 'Le serveur de mise à jour n’a pas été trouvé. [%s]', 'update_start' => 'Lancer la mise à jour', 'update_system' => 'Système de mise à jour', + 'updated' => 'Modifications enregistrées.', 'upon_reception' => 'dès la réception du nouvel article', - 'username' => 'Nom d’utilisateur', - 'username_admin' => 'Nom d’utilisateur administrateur', - 'users' => 'Utilisateurs', - 'users_list' => 'Liste des utilisateurs', 'user_created' => 'L’utilisateur %s a été créé.', 'user_deleted' => 'L’utilisateur %s a été supprimé.', 'user_filter' => 'Accéder aux filtres utilisateur', 'user_filter_help' => 'S’il n’y a qu’un filtre utilisateur, celui-ci est utilisé automatiquement. Sinon ils sont accessibles par leur numéro.', + 'username' => 'Nom d’utilisateur', + 'username_admin' => 'Nom d’utilisateur administrateur', + 'users' => 'Utilisateurs', + 'users_list' => 'Liste des utilisateurs', 'version' => 'Version', 'version_update' => 'Mise à jour', 'wallabag' => 'wallabag', -- cgit v1.2.3 From e86a3d001745656c6ec94837ff3275d4bc93aa5a Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 26 Oct 2014 12:40:42 +0100 Subject: Fix pdo checking Show only one message for both mysql and sqlite pdo conf. If one of them is ok, PDO is ok. See https://github.com/marienfressinaud/FreshRSS/issues/678 --- lib/lib_rss.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 80eb206d2..8ae357f02 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -257,13 +257,13 @@ function is_referer_from_same_domain() { * @return array of tested values. */ function check_install_php() { + $pdo_mysql = extension_loaded('pdo_mysql'); + $pdo_sqlite = extension_loaded('pdo_sqlite'); return array( 'php' => version_compare(PHP_VERSION, '5.2.1') >= 0, 'minz' => file_exists(LIB_PATH . '/Minz'), 'curl' => extension_loaded('curl'), - 'pdo_mysql' => extension_loaded('pdo_mysql'), - 'pdo_sqlite' => extension_loaded('pdo_sqlite'), - 'pdo' => extension_loaded('pdo_mysql') || extension_loaded('pdo_sqlite'), + 'pdo' => $pdo_mysql || $pdo_sqlite, 'pcre' => extension_loaded('pcre'), 'ctype' => extension_loaded('ctype'), 'dom' => class_exists('DOMDocument'), -- cgit v1.2.3 From 659515862566744fc90511bc4182fc32ccf2e6b3 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 26 Oct 2014 14:13:05 +0100 Subject: Fix themes (aside_feed) --- p/themes/Dark/dark.css | 3 +-- p/themes/Flat/flat.css | 3 +-- p/themes/Origine/origine.css | 4 +--- p/themes/Pafat/pafat.css | 1 - p/themes/Screwdriver/screwdriver.css | 1 - p/themes/base-theme/base.css | 1 - p/themes/base-theme/template.css | 14 ++++++++++++-- 7 files changed, 15 insertions(+), 12 deletions(-) diff --git a/p/themes/Dark/dark.css b/p/themes/Dark/dark.css index e551aa9c0..03bf3c985 100644 --- a/p/themes/Dark/dark.css +++ b/p/themes/Dark/dark.css @@ -474,7 +474,6 @@ a.btn { line-height: 2.5rem; font-size: 1rem; background: #1c1c1c; - font-weight: bold; } .tree-folder-title .title { background: inherit; @@ -485,6 +484,7 @@ a.btn { } .tree-folder.active .tree-folder-title { background: #2c2c2c; + font-weight: bold; } .tree-folder-items { border-top: 1px solid #222; @@ -594,7 +594,6 @@ a.btn { .aside_feed .tree-folder-items .item:hover .dropdown-toggle > .icon, .aside_feed .tree-folder-items .item.active .dropdown-toggle > .icon { border-radius: 3px; - vertical-align: middle; background-color: #111; } diff --git a/p/themes/Flat/flat.css b/p/themes/Flat/flat.css index eb7737c5d..313bee0ee 100644 --- a/p/themes/Flat/flat.css +++ b/p/themes/Flat/flat.css @@ -483,7 +483,6 @@ a.btn { background: #34495e; line-height: 2.5rem; font-size: 1rem; - font-weight: bold; } .tree-folder-title .title { background: inherit; @@ -494,6 +493,7 @@ a.btn { } .tree-folder.active .tree-folder-title { background: #2980b9; + font-weight: bold; } .tree-folder-items { background: #2c3e50; @@ -597,7 +597,6 @@ a.btn { .aside_feed .tree-folder-items .item:hover .dropdown-toggle > .icon, .aside_feed .tree-folder-items .item.active .dropdown-toggle > .icon { border-radius: 3px; - vertical-align: middle; } /*=== Configuration pages */ diff --git a/p/themes/Origine/origine.css b/p/themes/Origine/origine.css index 464422a0b..afd6ec04f 100644 --- a/p/themes/Origine/origine.css +++ b/p/themes/Origine/origine.css @@ -508,7 +508,6 @@ a.btn { background: #fff; line-height: 2.5rem; font-size: 1rem; - font-weight: bold; } .tree-folder-title .title { background: inherit; @@ -519,6 +518,7 @@ a.btn { } .tree-folder.active .tree-folder-title { background: #f0f0f0; + font-weight: bold; } .tree-folder.active .tree-folder-title .title { color: #0062BE; @@ -629,11 +629,9 @@ a.btn { left: 2px; } .aside_feed .tree-folder-items .item .dropdown-target:target ~ .dropdown-toggle > .icon, -.aside_feed .tree-folder-items .item:hover .dropdown-toggle > .icon, .aside_feed .tree-folder-items .item.active .dropdown-toggle > .icon { background-color: #fff; border-radius: 3px; - vertical-align: middle; } /*=== Configuration pages */ diff --git a/p/themes/Pafat/pafat.css b/p/themes/Pafat/pafat.css index 49cb3bc17..8b1e7866c 100644 --- a/p/themes/Pafat/pafat.css +++ b/p/themes/Pafat/pafat.css @@ -642,7 +642,6 @@ a.btn { .aside_feed .tree-folder-items .item:hover .dropdown-toggle > .icon, .aside_feed .tree-folder-items .item.active .dropdown-toggle > .icon { border-radius: 3px; - vertical-align: middle; background-color: #fff; } diff --git a/p/themes/Screwdriver/screwdriver.css b/p/themes/Screwdriver/screwdriver.css index 4f55d752e..b6c2e670e 100644 --- a/p/themes/Screwdriver/screwdriver.css +++ b/p/themes/Screwdriver/screwdriver.css @@ -664,7 +664,6 @@ a.btn { .aside_feed .tree-folder-items .item:hover .dropdown-toggle > .icon, .aside_feed .tree-folder-items .item.active .dropdown-toggle > .icon { border-radius: 3px; - vertical-align: middle; } /*=== Configuration pages */ diff --git a/p/themes/base-theme/base.css b/p/themes/base-theme/base.css index 871a632d8..ac30dbfea 100644 --- a/p/themes/base-theme/base.css +++ b/p/themes/base-theme/base.css @@ -465,7 +465,6 @@ a.btn { .aside_feed .tree-folder-items .item:hover .dropdown-toggle > .icon, .aside_feed .tree-folder-items .item.active .dropdown-toggle > .icon { border-radius: 3px; - vertical-align: middle; } /*=== Configuration pages */ diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index a79d539d8..ffb104af2 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -401,14 +401,23 @@ a.btn { .aside { display: table-cell; height: 100%; - width: 250px; + width: 300px; vertical-align: top; } -/*=== Aside main page (feeds) */ +/*=== Aside main page */ +.aside_feed .tree-folder-title .icon { + padding: 5px; +} +.aside_feed .tree-folder-items .item.feed { + padding: 0px 15px; +} .aside_feed .tree-folder-items:not(.active) { display: none; } +.aside_feed .tree-folder-items .dropdown { + vertical-align: top; +} .aside_feed .tree-folder-items .dropdown-menu { left: 0; } @@ -472,6 +481,7 @@ a.btn { .flux .item.date { width: 145px; text-align: right; + overflow: hidden; } .flux .item > a { display: block; -- cgit v1.2.3 From 956896bf87275317ba822188c14e07eb21fae3de Mon Sep 17 00:00:00 2001 From: Luc Didry Date: Sun, 26 Oct 2014 17:01:31 +0100 Subject: Fixes #683 --- app/actualize_script.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/actualize_script.php b/app/actualize_script.php index e5925514e..74840215b 100755 --- a/app/actualize_script.php +++ b/app/actualize_script.php @@ -7,6 +7,11 @@ ob_implicit_flush(false); ob_start(); echo 'Results: ', "\n"; //Buffered +if (defined('STDOUT')) { + $begin_date = date_create('now'); + fwrite(STDOUT, 'Starting feed actualization at ' . $begin_date->format('H:i:s (O)') . "\n"); //Unbuffered +} + Minz_Configuration::init(); $users = listUsers(); @@ -52,6 +57,10 @@ foreach ($users as $myUser) { syslog(LOG_INFO, 'FreshRSS actualize done.'); if (defined('STDOUT')) { fwrite(STDOUT, 'Done.' . "\n"); + $end_date = date_create('now'); + $duration = date_diff($end_date, $begin_date); + fwrite(STDOUT, 'Ending feed actualization at ' . $begin_date->format('H:i:s (O)') . "\n"); //Unbuffered + fwrite(STDOUT, 'Feed actualizations took ' . $duration->format('%H hours %M minutes and %S') . ' secondes for ' . count($users) . " users\n"); //Unbuffered } echo 'End.', "\n"; ob_end_flush(); -- cgit v1.2.3 From 01ef0ef2b8b5f8eda53b2dff19f460dd9d1b8276 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 26 Oct 2014 18:58:43 +0100 Subject: Fix nav_entries menu width See https://github.com/marienfressinaud/FreshRSS/issues/678 --- p/themes/base-theme/template.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index ffb104af2..6640284f9 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -569,7 +569,7 @@ br + br + br { position: fixed; bottom: 0; left: 0; display: table; - width: 250px; + width: 300px; background: #fff; table-layout: fixed; } -- cgit v1.2.3 From e861e5789d52fab6c4055e39fb92d64194eaab5e Mon Sep 17 00:00:00 2001 From: Luc Didry Date: Sun, 26 Oct 2014 19:00:00 +0100 Subject: Fix errors + improvements on bug #683 fix. --- app/actualize_script.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/actualize_script.php b/app/actualize_script.php index 74840215b..9fe499cc9 100755 --- a/app/actualize_script.php +++ b/app/actualize_script.php @@ -9,7 +9,7 @@ echo 'Results: ', "\n"; //Buffered if (defined('STDOUT')) { $begin_date = date_create('now'); - fwrite(STDOUT, 'Starting feed actualization at ' . $begin_date->format('H:i:s (O)') . "\n"); //Unbuffered + fwrite(STDOUT, 'Starting feed actualization at ' . $begin_date->format('c') . "\n"); //Unbuffered } Minz_Configuration::init(); @@ -59,8 +59,8 @@ if (defined('STDOUT')) { fwrite(STDOUT, 'Done.' . "\n"); $end_date = date_create('now'); $duration = date_diff($end_date, $begin_date); - fwrite(STDOUT, 'Ending feed actualization at ' . $begin_date->format('H:i:s (O)') . "\n"); //Unbuffered - fwrite(STDOUT, 'Feed actualizations took ' . $duration->format('%H hours %M minutes and %S') . ' secondes for ' . count($users) . " users\n"); //Unbuffered + fwrite(STDOUT, 'Ending feed actualization at ' . $end_date->format('c') . "\n"); //Unbuffered + fwrite(STDOUT, 'Feed actualizations took ' . $duration->format('%a day(s), %h hour(s), %i minute(s) and %s seconds') . ' for ' . count($users) . " users\n"); //Unbuffered } echo 'End.', "\n"; ob_end_flush(); -- cgit v1.2.3 From 482f995d61f4b172f7b79becc25d0d7157098daf Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 26 Oct 2014 21:21:07 +0100 Subject: All the category area is clickable See https://github.com/marienfressinaud/FreshRSS/issues/646 --- p/themes/base-theme/template.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index 6640284f9..79fe506f2 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -348,6 +348,8 @@ a.btn { text-overflow: ellipsis; } .tree-folder-title .title { + display: inline-block; + width: 100%; vertical-align: middle; } .tree-folder-items > .item { @@ -406,6 +408,10 @@ a.btn { } /*=== Aside main page */ +.aside_feed .category .title { + width: calc(100% - 35px); +} + .aside_feed .tree-folder-title .icon { padding: 5px; } -- cgit v1.2.3 From 299495d0820dd6a8c26842264a3b15b95884b9fb Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Sun, 26 Oct 2014 22:33:00 +0100 Subject: Crypto update bcrypt.js + bug https://github.com/marienfressinaud/FreshRSS/issues/676 --- p/scripts/bcrypt.min.js | 78 ++++++++++++++++++++++++++----------------------- p/scripts/main.js | 2 +- 2 files changed, 42 insertions(+), 38 deletions(-) diff --git a/p/scripts/bcrypt.min.js b/p/scripts/bcrypt.min.js index 6892caddc..614f0c259 100644 --- a/p/scripts/bcrypt.min.js +++ b/p/scripts/bcrypt.min.js @@ -1,41 +1,45 @@ -/* +(function(){/* bcrypt.js (c) 2013 Daniel Wirtz Released under the Apache License, Version 2.0 see: https://github.com/dcodeIO/bcrypt.js for details */ -function p(n){throw n;}var q=null; -(function(n){function u(c,a,b,f){for(var d,e=c[a],l=c[a+1],e=e^b[0],h=0;14>=h;)d=f[e>>24&255],d+=f[256|e>>16&255],d^=f[512|e>>8&255],d+=f[768|e&255],l^=d^b[++h],d=f[l>>24&255],d+=f[256|l>>16&255],d^=f[512|l>>8&255],d+=f[768|l&255],e^=d^b[++h];c[a]=l^b[17];c[a+1]=e;return c}function s(c,a){var b,f=0;for(b=0;4>b;b++)f=f<<8|c[a]&255,a=(a+1)%c.length;return{key:f,a:a}}function y(c,a,b){for(var f=0,d=[0,0],e=a.length,l=b.length,h=0;hk;k++)for(m=0;m>1;m++)u(e,m<<1,h,g);n=[];for(k=0;k>24&255)>>>0),n.push((e[k]>>16&255)>>>0),n.push((e[k]>>8&255)>>>0),n.push((e[k]&255)>>>0);return f?(f(q,n),q):n}f&&z(d);return q}var e=B.slice(),l=e.length;(4>b||31>=8;while(a);f=f.concat(b.reverse())}return f}function w(c,a,b){function f(a){var b=[];b.push("$2");"a"<=d&&b.push(d);b.push("$");10>l&&b.push("0");b.push(l.toString());b.push("$");b.push(v.b(h,h.length));b.push(v.b(a,4*B.length-1));return b.join("")}var d,e;("$"!=a.charAt(0)||"2"!=a.charAt(1))&&p(Error("Invalid salt version: "+ -a.substring(0,2)));"$"==a.charAt(2)?(d=String.fromCharCode(0),e=3):(d=a.charAt(2),("a"!=d||"$"!=a.charAt(3))&&p(Error("Invalid salt revision: "+a.substring(2,4))),e=4);"$"=a||a>c.length)&&p(Error("Invalid 'len': "+a));b>2&63]);d=(d&3)<<4;if(b>=a){f.push(t[d&63]);break}e=c[b++]&255;d|=e>>4&15;f.push(t[d&63]);d=(e&15)<< -2;if(b>=a){f.push(t[d&63]);break}e=c[b++]&255;d|=e>>6&3;f.push(t[d&63]);f.push(t[e&63])}return f.join("")},c:function(c,a){var b=0,f=c.length,d=0,e=[],l,h,g;for(0>=a&&p(Error("Illegal 'len': "+a));b>>0;g|=(h&48)>>4;e.push(String.fromCharCode(g));if(++d>=a||b>=f)break;g=c.charCodeAt(b++);l=g>>0;g|=(l&60)>>2;e.push(String.fromCharCode(g)); -if(++d>=a||b>=f)break;g=c.charCodeAt(b++);h=g>>0;g|=h;e.push(String.fromCharCode(g));++d}f=[];for(b=0;bc||31c&&b.push("0");b.push(c.toString());b.push("$");try{b.push(v.b(G(),16)),a=b.join("")}catch(f){p(f)}return a};m.genSalt=function(c,a,b){"function"==typeof a&&(b=a,a=-1);var f;"function"==typeof c?(b=c,f=10):f=parseInt(c,10);"function"!=typeof b&&p(Error("Illegal or missing 'callback': "+b));z(function(){try{var a=m.genSaltSync(f);b(q,a)}catch(c){b(c,q)}})};m.hashSync=function(c,a){a||(a=10);"number"==typeof a&&(a=m.genSaltSync(a));return w(c,a)};m.hash=function(c,a,b){"function"!= -typeof b&&p(Error("Illegal 'callback': "+b));"number"==typeof a?m.genSalt(a,function(a,d){w(c,d,b)}):w(c,a,b)};m.compareSync=function(c,a){("string"!=typeof c||"string"!=typeof a)&&p(Error("Illegal argument types: "+typeof c+", "+typeof a));60!=a.length&&p(Error("Illegal hash length: "+a.length+" != 60"));for(var b=m.hashSync(c,a.substr(0,a.length-31)),f=b.length==a.length,d=b.length=e&&(a.length>=e&&b[e]!=a[e])&&(f=!1);return f};m.compare=function(c, -a,b){"function"!=typeof b&&p(Error("Illegal 'callback': "+b));m.hash(c,a.substr(0,29),function(c,d){b(c,a===d)})};m.getRounds=function(c){"string"!=typeof c&&p(Error("Illegal type of 'hash': "+typeof c));return parseInt(c.split("$")[2],10)};m.getSalt=function(c){"string"!=typeof c&&p(Error("Illegal type of 'hash': "+typeof c));60!=c.length&&p(Error("Illegal hash length: "+c.length+" != 60"));return c.substring(0,29)};"undefined"!=typeof module&&module.exports?module.exports=m:"undefined"!=typeof define&& -define.amd?define("bcrypt",function(){return m}):(n.dcodeIO||(n.dcodeIO={}),n.dcodeIO.bcrypt=m)})(this); +function l(t){throw t;}var p=null; +(function(t){function B(c){if("undefined"!==typeof module&&module&&module.exports)try{return require("crypto").randomBytes(c)}catch(a){}try{var b;(t.crypto||t.msCrypto).getRandomValues(b=new Uint32Array(c));return Array.prototype.slice.call(b)}catch(d){}x||l(Error("Neither WebCryptoAPI nor a crypto module is available. Use bcrypt.setRandomFallback to set an alternative"));return x(c)}function F(c){var a=[],b=0;G.f(function(){return b>=c.length?p:c.charCodeAt(b++)},function(b){a.push(b)});return a} +function y(c,a){var b=0,d=[],f,e;for((0>=a||a>c.length)&&l(Error("Illegal len: "+a));b>2&63]);f=(f&3)<<4;if(b>=a){d.push(u[f&63]);break}e=c[b++]&255;f|=e>>4&15;d.push(u[f&63]);f=(e&15)<<2;if(b>=a){d.push(u[f&63]);break}e=c[b++]&255;f|=e>>6&3;d.push(u[f&63]);d.push(u[e&63])}return d.join("")}function H(c){for(var a=0,b=c.length,d=0,f=[],e,k,h;ad;){h=c.charCodeAt(a++);e=h>>0; +h|=(k&48)>>4;f.push(z(h));if(16<=++d||a>=b)break;h=c.charCodeAt(a++);e=h>>0;h|=(e&60)>>2;f.push(z(h));if(16<=++d||a>=b)break;h=c.charCodeAt(a++);k=h>>0;h|=k;f.push(z(h));++d}c=[];for(a=0;a=h;)f=d[e>>24&255],f+=d[256|e>>16&255],f^=d[512|e>>8&255],f+=d[768|e&255],k^=f^b[++h],f=d[k>>24&255],f+=d[256|k>>16&255],f^=d[512|k>>8& +255],f+=d[768|k&255],e^=f^b[++h];c[a]=k^b[17];c[a+1]=e;return c}function v(c,a){for(var b=0,d=0;4>b;++b)d=d<<8|c[a]&255,a=(a+1)%c.length;return{key:d,a:a}}function C(c,a,b){for(var d=0,f=[0,0],e=a.length,k=b.length,h,g=0;gq;q++)for(r=0;r>1;r++)w(k,r<<1,m,n);g=[];for(q=0;q>24&255)>>>0),g.push((k[q]>>16&255)>>>0),g.push((k[q]>>8&255)>>>0),g.push((k[q]&255)>>>0);if(d){d(p,g);return}return g}d&& +s(e)}var k=E.slice(),h=k.length,g;if(4>b||31g&&b.push("0");b.push(g.toString());b.push("$"); +b.push(y(m,m.length));b.push(y(a,4*E.length-1));return b.join("")}var e;if("string"!==typeof c||"string"!==typeof a){e=Error("Invalid string / salt: Not a string");if(b){s(b.bind(this,e));return}l(e)}var k,h;if("$"!==a.charAt(0)||"2"!==a.charAt(1)){e=Error("Invalid salt version: "+a.substring(0,2));if(b){s(b.bind(this,e));return}l(e)}if("$"===a.charAt(2))k=String.fromCharCode(0),h=3;else{k=a.charAt(2);if("a"!==k&&"y"!==k||"$"!==a.charAt(3)){e=Error("Invalid salt revision: "+a.substring(2,4));if(b){s(b.bind(this, +e));return}l(e)}h=4}if("$"c||31c&&b.push("0");b.push(c.toString());b.push("$");b.push(y(B(16),16));return b.join("")};n.genSalt=function(c,a,b){"function"===typeof a&&(b=a,a=void 0);"function"===typeof c&&(b=c,c=10);"function"!==typeof b&&l(Error("Illegal callback: "+typeof b));"number"!==typeof c?s(b.bind(this,Error("Illegal arguments: "+typeof c))):s(function(){try{b(p,n.genSaltSync(c))}catch(a){b(a)}})};n.hashSync=function(c, +a){"undefined"===typeof a&&(a=10);"number"===typeof a&&(a=n.genSaltSync(a));("string"!==typeof c||"string"!==typeof a)&&l(Error("Illegal arguments: "+typeof c+", "+typeof a));return A(c,a)};n.hash=function(c,a,b,d){"function"!==typeof b&&l(Error("Illegal callback: "+typeof b));"string"===typeof c&&"number"===typeof a?n.genSalt(a,function(a,e){A(c,e,b,d)}):"string"===typeof c&&"string"===typeof a?A(c,a,b,d):s(b.bind(this,Error("Illegal arguments: "+typeof c+", "+typeof a)))};n.compareSync=function(c, +a){("string"!==typeof c||"string"!==typeof a)&&l(Error("Illegal arguments: "+typeof c+", "+typeof a));if(60!==a.length)return!1;for(var b=n.hashSync(c,a.substr(0,a.length-31)),d=b.length===a.length,f=b.length=e&&(a.length>=e&&b[e]!=a[e])&&(d=!1);return d};n.compare=function(c,a,b,d){"function"!==typeof b&&l(Error("Illegal callback: "+typeof b));"string"!==typeof c||"string"!==typeof a?s(b.bind(this,Error("Illegal arguments: "+typeof c+", "+typeof a))): +n.hash(c,a.substr(0,29),function(d,c){b(d,a===c)},d)};n.getRounds=function(c){"string"!==typeof c&&l(Error("Illegal arguments: "+typeof c));return parseInt(c.split("$")[2],10)};n.getSalt=function(c){"string"!==typeof c&&l(Error("Illegal arguments: "+typeof c));60!==c.length&&l(Error("Illegal hash length: "+c.length+" != 60"));return c.substring(0,29)};var s="undefined"!==typeof process&&process&&"function"===typeof process.nextTick?"function"===typeof setImmediate?setImmediate:process.nextTick:setTimeout, +u="./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".split(""),r=[-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,54,55,56,57,58,59,60,61,62,63,-1,-1,-1,-1,-1,-1,-1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,-1,-1,-1,-1,-1,-1,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,-1,-1,-1,-1,-1],z=String.fromCharCode,G=function(){var c={h:1114111, +g:function(a,b){var d=p;"number"===typeof a&&(d=a,a=function(){return p});for(;d!==p||(d=a())!==p;)128>d?b(d&127):(2048>d?b(d>>6&31|192):(65536>d?b(d>>12&15|224):(b(d>>18&7|240),b(d>>12&63|128)),b(d>>6&63|128)),b(d&63|128)),d=p},e:function(a,b){function d(a){a=a.slice(0,a.indexOf(p));var b=Error(a.toString());b.name="TruncatedError";b.bytes=a;l(b)}for(var c,e,k,h;(c=a())!==p;)0===(c&128)?b(c):192===(c&224)?((e=a())===p&&d([c,e]),b((c&31)<<6|e&63)):224===(c&240)?(((e=a())===p||(k=a())===p)&&d([c,e, +k]),b((c&15)<<12|(e&63)<<6|k&63)):240===(c&248)?(((e=a())===p||(k=a())===p||(h=a())===p)&&d([c,e,k,h]),b((c&7)<<18|(e&63)<<12|(k&63)<<6|h&63)):l(RangeError("Illegal starting byte: "+c))},b:function(a,b){for(var c,f=p;(c=f!==p?f:a())!==p;)55296<=c&&57343>=c&&(f=a())!==p&&56320<=f&&57343>=f?(b(1024*(c-55296)+f-56320+65536),f=p):b(c);f!==p&&b(f)},d:function(a,b){var c=p;"number"===typeof a&&(c=a,a=function(){return p});for(;c!==p||(c=a())!==p;)65535>=c?b(c):(c-=65536,b((c>>10)+55296),b(c%1024+56320)), +c=p},f:function(a,b){c.b(a,function(a){c.g(a,b)})},k:function(a,b){c.e(a,function(a){c.d(a,b)})},c:function(a){return 128>a?1:2048>a?2:65536>a?3:4},j:function(a){for(var b,d=0;(b=a())!==p;)d+=c.c(b);return d},i:function(a){var b=0,d=0;c.b(a,function(a){++b;d+=c.c(a)});return[b,d]}};return c}();Date.now=Date.now||function(){return+new Date};var J=[608135816,2242054355,320440878,57701188,2752067618,698298832,137296536,3964562569,1160258022,953160567,3193202383,887688300,3232508343,3380367581,1065670069, +3041331479,2450970073,2306472731],K=[3509652390,2564797868,805139163,3491422135,3101798381,1780907670,3128725573,4046225305,614570311,3012652279,134345442,2240740374,1667834072,1901547113,2757295779,4103290238,227898511,1921955416,1904987480,2182433518,2069144605,3260701109,2620446009,720527379,3318853667,677414384,3393288472,3101374703,2390351024,1614419982,1822297739,2954791486,3608508353,3174124327,2024746970,1432378464,3864339955,2857741204,1464375394,1676153920,1439316330,715854006,3033291828, +289532110,2706671279,2087905683,3018724369,1668267050,732546397,1947742710,3462151702,2609353502,2950085171,1814351708,2050118529,680887927,999245976,1800124847,3300911131,1713906067,1641548236,4213287313,1216130144,1575780402,4018429277,3917837745,3693486850,3949271944,596196993,3549867205,258830323,2213823033,772490370,2760122372,1774776394,2652871518,566650946,4142492826,1728879713,2882767088,1783734482,3629395816,2517608232,2874225571,1861159788,326777828,3124490320,2130389656,2716951837,967770486, +1724537150,2185432712,2364442137,1164943284,2105845187,998989502,3765401048,2244026483,1075463327,1455516326,1322494562,910128902,469688178,1117454909,936433444,3490320968,3675253459,1240580251,122909385,2157517691,634681816,4142456567,3825094682,3061402683,2540495037,79693498,3249098678,1084186820,1583128258,426386531,1761308591,1047286709,322548459,995290223,1845252383,2603652396,3431023940,2942221577,3202600964,3727903485,1712269319,422464435,3234572375,1170764815,3523960633,3117677531,1434042557, +442511882,3600875718,1076654713,1738483198,4213154764,2393238008,3677496056,1014306527,4251020053,793779912,2902807211,842905082,4246964064,1395751752,1040244610,2656851899,3396308128,445077038,3742853595,3577915638,679411651,2892444358,2354009459,1767581616,3150600392,3791627101,3102740896,284835224,4246832056,1258075500,768725851,2589189241,3069724005,3532540348,1274779536,3789419226,2764799539,1660621633,3471099624,4011903706,913787905,3497959166,737222580,2514213453,2928710040,3937242737,1804850592, +3499020752,2949064160,2386320175,2390070455,2415321851,4061277028,2290661394,2416832540,1336762016,1754252060,3520065937,3014181293,791618072,3188594551,3933548030,2332172193,3852520463,3043980520,413987798,3465142937,3030929376,4245938359,2093235073,3534596313,375366246,2157278981,2479649556,555357303,3870105701,2008414854,3344188149,4221384143,3956125452,2067696032,3594591187,2921233993,2428461,544322398,577241275,1471733935,610547355,4027169054,1432588573,1507829418,2025931657,3646575487,545086370, +48609733,2200306550,1653985193,298326376,1316178497,3007786442,2064951626,458293330,2589141269,3591329599,3164325604,727753846,2179363840,146436021,1461446943,4069977195,705550613,3059967265,3887724982,4281599278,3313849956,1404054877,2845806497,146425753,1854211946,1266315497,3048417604,3681880366,3289982499,290971E4,1235738493,2632868024,2414719590,3970600049,1771706367,1449415276,3266420449,422970021,1963543593,2690192192,3826793022,1062508698,1531092325,1804592342,2583117782,2714934279,4024971509, +1294809318,4028980673,1289560198,2221992742,1669523910,35572830,157838143,1052438473,1016535060,1802137761,1753167236,1386275462,3080475397,2857371447,1040679964,2145300060,2390574316,1461121720,2956646967,4031777805,4028374788,33600511,2920084762,1018524850,629373528,3691585981,3515945977,2091462646,2486323059,586499841,988145025,935516892,3367335476,2599673255,2839830854,265290510,3972581182,2759138881,3795373465,1005194799,847297441,406762289,1314163512,1332590856,1866599683,4127851711,750260880, +613907577,1450815602,3165620655,3734664991,3650291728,3012275730,3704569646,1427272223,778793252,1343938022,2676280711,2052605720,1946737175,3164576444,3914038668,3967478842,3682934266,1661551462,3294938066,4011595847,840292616,3712170807,616741398,312560963,711312465,1351876610,322626781,1910503582,271666773,2175563734,1594956187,70604529,3617834859,1007753275,1495573769,4069517037,2549218298,2663038764,504708206,2263041392,3941167025,2249088522,1514023603,1998579484,1312622330,694541497,2582060303, +2151582166,1382467621,776784248,2618340202,3323268794,2497899128,2784771155,503983604,4076293799,907881277,423175695,432175456,1378068232,4145222326,3954048622,3938656102,3820766613,2793130115,2977904593,26017576,3274890735,3194772133,1700274565,1756076034,4006520079,3677328699,720338349,1533947780,354530856,688349552,3973924725,1637815568,332179504,3949051286,53804574,2852348879,3044236432,1282449977,3583942155,3416972820,4006381244,1617046695,2628476075,3002303598,1686838959,431878346,2686675385, +1700445008,1080580658,1009431731,832498133,3223435511,2605976345,2271191193,2516031870,1648197032,4164389018,2548247927,300782431,375919233,238389289,3353747414,2531188641,2019080857,1475708069,455242339,2609103871,448939670,3451063019,1395535956,2413381860,1841049896,1491858159,885456874,4264095073,4001119347,1565136089,3898914787,1108368660,540939232,1173283510,2745871338,3681308437,4207628240,3343053890,4016749493,1699691293,1103962373,3625875870,2256883143,3830138730,1031889488,3479347698,1535977030, +4236805024,3251091107,2132092099,1774941330,1199868427,1452454533,157007616,2904115357,342012276,595725824,1480756522,206960106,497939518,591360097,863170706,2375253569,3596610801,1814182875,2094937945,3421402208,1082520231,3463918190,2785509508,435703966,3908032597,1641649973,2842273706,3305899714,1510255612,2148256476,2655287854,3276092548,4258621189,236887753,3681803219,274041037,1734335097,3815195456,3317970021,1899903192,1026095262,4050517792,356393447,2410691914,3873677099,3682840055,3913112168, +2491498743,4132185628,2489919796,1091903735,1979897079,3170134830,3567386728,3557303409,857797738,1136121015,1342202287,507115054,2535736646,337727348,3213592640,1301675037,2528481711,1895095763,1721773893,3216771564,62756741,2142006736,835421444,2531993523,1442658625,3659876326,2882144922,676362277,1392781812,170690266,3921047035,1759253602,3611846912,1745797284,664899054,1329594018,3901205900,3045908486,2062866102,2865634940,3543621612,3464012697,1080764994,553557557,3656615353,3996768171,991055499, +499776247,1265440854,648242737,3940784050,980351604,3713745714,1749149687,3396870395,4211799374,3640570775,1161844396,3125318951,1431517754,545492359,4268468663,3499529547,1437099964,2702547544,3433638243,2581715763,2787789398,1060185593,1593081372,2418618748,4260947970,69676912,2159744348,86519011,2512459080,3838209314,1220612927,3339683548,133810670,1090789135,1078426020,1569222167,845107691,3583754449,4072456591,1091646820,628848692,1613405280,3757631651,526609435,236106946,48312990,2942717905, +3402727701,1797494240,859738849,992217954,4005476642,2243076622,3870952857,3732016268,765654824,3490871365,2511836413,1685915746,3888969200,1414112111,2273134842,3281911079,4080962846,172450625,2569994100,980381355,4109958455,2819808352,2716589560,2568741196,3681446669,3329971472,1835478071,660984891,3704678404,4045999559,3422617507,3040415634,1762651403,1719377915,3470491036,2693910283,3642056355,3138596744,1364962596,2073328063,1983633131,926494387,3423689081,2150032023,4096667949,1749200295,3328846651, +309677260,2016342300,1779581495,3079819751,111262694,1274766160,443224088,298511866,1025883608,3806446537,1145181785,168956806,3641502830,3584813610,1689216846,3666258015,3200248200,1692713982,2646376535,4042768518,1618508792,1610833997,3523052358,4130873264,2001055236,3610705100,2202168115,4028541809,2961195399,1006657119,2006996926,3186142756,1430667929,3210227297,1314452623,4074634658,4101304120,2273951170,1399257539,3367210612,3027628629,1190975929,2062231137,2333990788,2221543033,2438960610, +1181637006,548689776,2362791313,3372408396,3104550113,3145860560,296247880,1970579870,3078560182,3769228297,1714227617,3291629107,3898220290,166772364,1251581989,493813264,448347421,195405023,2709975567,677966185,3703036547,1463355134,2715995803,1338867538,1343315457,2802222074,2684532164,233230375,2599980071,2000651841,3277868038,1638401717,4028070440,3237316320,6314154,819756386,300326615,590932579,1405279636,3267499572,3150704214,2428286686,3959192993,3461946742,1862657033,1266418056,963775037, +2089974820,2263052895,1917689273,448879540,3550394620,3981727096,150775221,3627908307,1303187396,508620638,2975983352,2726630617,1817252668,1876281319,1457606340,908771278,3720792119,3617206836,2455994898,1729034894,1080033504,976866871,3556439503,2881648439,1522871579,1555064734,1336096578,3548522304,2579274686,3574697629,3205460757,3593280638,3338716283,3079412587,564236357,2993598910,1781952180,1464380207,3163844217,3332601554,1699332808,1393555694,1183702653,3581086237,1288719814,691649499,2847557200, +2895455976,3193889540,2717570544,1781354906,1676643554,2592534050,3230253752,1126444790,2770207658,2633158820,2210423226,2615765581,2414155088,3127139286,673620729,2805611233,1269405062,4015350505,3341807571,4149409754,1057255273,2012875353,2162469141,2276492801,2601117357,993977747,3918593370,2654263191,753973209,36408145,2530585658,25011837,3520020182,2088578344,530523599,2918365339,1524020338,1518925132,3760827505,3759777254,1202760957,3985898139,3906192525,674977740,4174734889,2031300136,2019492241, +3983892565,4153806404,3822280332,352677332,2297720250,60907813,90501309,3286998549,1016092578,2535922412,2839152426,457141659,509813237,4120667899,652014361,1966332200,2975202805,55981186,2327461051,676427537,3255491064,2882294119,3433927263,1307055953,942726286,933058658,2468411793,3933900994,4215176142,1361170020,2001714738,2830558078,3274259782,1222529897,1679025792,2729314320,3714953764,1770335741,151462246,3013232138,1682292957,1483529935,471910574,1539241949,458788160,3436315007,1807016891, +3718408830,978976581,1043663428,3165965781,1927990952,4200891579,2372276910,3208408903,3533431907,1412390302,2931980059,4132332400,1947078029,3881505623,4168226417,2941484381,1077988104,1320477388,886195818,18198404,3786409E3,2509781533,112762804,3463356488,1866414978,891333506,18488651,661792760,1628790961,3885187036,3141171499,876946877,2693282273,1372485963,791857591,2686433993,3759982718,3167212022,3472953795,2716379847,445679433,3561995674,3504004811,3574258232,54117162,3331405415,2381918588, +3769707343,4154350007,1140177722,4074052095,668550556,3214352940,367459370,261225585,2610173221,4209349473,3468074219,3265815641,314222801,3066103646,3808782860,282218597,3406013506,3773591054,379116347,1285071038,846784868,2669647154,3771962079,3550491691,2305946142,453669953,1268987020,3317592352,3279303384,3744833421,2610507566,3859509063,266596637,3847019092,517658769,3462560207,3443424879,370717030,4247526661,2224018117,4143653529,4112773975,2788324899,2477274417,1456262402,2901442914,1517677493, +1846949527,2295493580,3734397586,2176403920,1280348187,1908823572,3871786941,846861322,1172426758,3287448474,3383383037,1655181056,3139813346,901632758,1897031941,2986607138,3066810236,3447102507,1393639104,373351379,950779232,625454576,3124240540,4148612726,2007998917,544563296,2244738638,2330496472,2058025392,1291430526,424198748,50039436,29584100,3605783033,2429876329,2791104160,1057563949,3255363231,3075367218,3463963227,1469046755,985887462],E=[1332899944,1700884034,1701343084,1684370003,1668446532, +1869963892];"undefined"!==typeof module&&module.exports?module.exports=n:"undefined"!==typeof define&&define.amd?define(function(){return n}):(t.dcodeIO=t.dcodeIO||{}).bcrypt=n})(this);})(); diff --git a/p/scripts/main.js b/p/scripts/main.js index b6370866f..dc5428048 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -1014,7 +1014,7 @@ function init_crypto_form() { try { var strong = window.Uint32Array && window.crypto && (typeof window.crypto.getRandomValues === 'function'), s = dcodeIO.bcrypt.hashSync($('#passwordPlain').val(), data.salt1), - c = dcodeIO.bcrypt.hashSync(data.nonce + s, strong ? 4 : poormanSalt()); + c = dcodeIO.bcrypt.hashSync(data.nonce + s, strong ? dcodeIO.bcrypt.genSaltSync(4) : poormanSalt()); $('#challenge').val(c); if (s == '' || c == '') { openNotification('Crypto error!', 'bad'); -- cgit v1.2.3 From c6f35ef51c2c536efb4f8e73603ae46b8512cc24 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Mon, 27 Oct 2014 21:45:30 +0100 Subject: Global limits for number of feeds and categories New 'limits' sub-array in config.php with 'max_feeds' and 'max_categories'. If the values are < 0, then it is the default value (16384). https://github.com/marienfressinaud/FreshRSS/issues/680 --- app/Controllers/categoryController.php | 7 +++++++ app/Controllers/feedController.php | 7 +++++++ lib/Minz/Configuration.php | 26 ++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/app/Controllers/categoryController.php b/app/Controllers/categoryController.php index 977ce51be..ef8af7ed6 100644 --- a/app/Controllers/categoryController.php +++ b/app/Controllers/categoryController.php @@ -33,6 +33,13 @@ class FreshRSS_category_Controller extends Minz_ActionController { $catDAO = new FreshRSS_CategoryDAO(); $url_redirect = array('c' => 'subscription', 'a' => 'index'); + $limits = Minz_Configuration::limits(); + $this->view->categories = $catDAO->listCategories(false); + if (count($this->view->categories) >= $limits['max_categories']) { + Minz_Request::bad(_t('over_max_categories', $limits['max_categories']), $url_redirect); + return; + } + if (Minz_Request::isPost()) { invalidateHttpCache(); diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index c2859edf4..39e4b5761 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -68,6 +68,13 @@ class FreshRSS_feed_Controller extends Minz_ActionController { 'params' => array(), ); + $limits = Minz_Configuration::limits(); + $this->view->feeds = $feedDAO->listFeeds(); + if (count($this->view->feeds) >= $limits['max_feeds']) { + Minz_Request::bad(_t('over_max_feeds', $limits['max_feeds']), $url_redirect); + return; + } + if (Minz_Request::isPost()) { @set_time_limit(300); diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php index 554bc8c96..fe9ea6b2e 100644 --- a/lib/Minz/Configuration.php +++ b/lib/Minz/Configuration.php @@ -60,6 +60,12 @@ class Minz_Configuration { 'prefix' => '', ); + const MAX_SMALL_INT = 16384; + private static $limits = array( + 'max_feeds' => Minz_Configuration::MAX_SMALL_INT, + 'max_categories' => Minz_Configuration::MAX_SMALL_INT, + ); + /* * Getteurs */ @@ -97,6 +103,9 @@ class Minz_Configuration { public static function dataBase () { return self::$db; } + public static function limits() { + return self::$limits; + } public static function defaultUser () { return self::$default_user; } @@ -178,6 +187,7 @@ class Minz_Configuration { 'api_enabled' => self::$api_enabled, 'unsafe_autologin_enabled' => self::$unsafe_autologin_enabled, ), + 'limits' => self::$limits, 'db' => self::$db, ); @rename(DATA_PATH . self::CONF_PATH_NAME, DATA_PATH . self::CONF_PATH_NAME . '.bak.php'); @@ -291,6 +301,22 @@ class Minz_Configuration { ); } + if (isset($ini_array['limits'])) { + $limits = $ini_array['limits']; + if (isset($limits['max_feeds'])) { + self::$limits['max_feeds'] = intval($limits['max_feeds']); + if (self::$limits['max_feeds'] < 0 || self::$limits['max_feeds'] > Minz_Configuration::MAX_SMALL_INT) { + self::$limits['max_feeds'] = Minz_Configuration::MAX_SMALL_INT; + } + } + if (isset($limits['max_categories'])) { + self::$limits['max_categories'] = intval($limits['max_categories']); + if (self::$limits['max_categories'] < 0 || self::$limits['max_categories'] > Minz_Configuration::MAX_SMALL_INT) { + self::$limits['max_categories'] = Minz_Configuration::MAX_SMALL_INT; + } + } + } + // Base de données if (isset ($ini_array['db'])) { $db = $ini_array['db']; -- cgit v1.2.3 From 2e5d4d97c989f55c3506ceb918126eaf9c68f1d6 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 28 Oct 2014 22:29:55 +0100 Subject: More limit options in config.php See e.g. https://github.com/marienfressinaud/FreshRSS/issues/681 https://github.com/marienfressinaud/FreshRSS/issues/680 https://github.com/marienfressinaud/FreshRSS/issues/656 --- CHANGELOG | 6 ++++++ lib/Minz/Configuration.php | 26 ++++++++++++++++++++------ lib/lib_rss.php | 5 +++-- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 44d3452ae..688a286e3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,11 @@ # Journal des modifications +## + +* Configuration + * New options in config.php for cache duration, timeout, max number of feeds and categories per user. + + ## 2014-09-26 FreshRSS 0.8.0 / 0.9.0 (beta) * UI diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php index fe9ea6b2e..9511cb357 100644 --- a/lib/Minz/Configuration.php +++ b/lib/Minz/Configuration.php @@ -62,6 +62,8 @@ class Minz_Configuration { const MAX_SMALL_INT = 16384; private static $limits = array( + 'cache_duration' => 800, //SimplePie cache duration in seconds + 'timeout' => 10, //SimplePie timeout in seconds 'max_feeds' => Minz_Configuration::MAX_SMALL_INT, 'max_categories' => Minz_Configuration::MAX_SMALL_INT, ); @@ -303,16 +305,28 @@ class Minz_Configuration { if (isset($ini_array['limits'])) { $limits = $ini_array['limits']; + if (isset($limits['cache_duration'])) { + $v = intval($limits['cache_duration']); + if ($v > 0) { + self::$limits['cache_duration'] = $v; + } + } + if (isset($limits['timeout'])) { + $v = intval($limits['timeout']); + if ($v > 0) { + self::$limits['timeout'] = $v; + } + } if (isset($limits['max_feeds'])) { - self::$limits['max_feeds'] = intval($limits['max_feeds']); - if (self::$limits['max_feeds'] < 0 || self::$limits['max_feeds'] > Minz_Configuration::MAX_SMALL_INT) { - self::$limits['max_feeds'] = Minz_Configuration::MAX_SMALL_INT; + $v = intval($limits['max_feeds']); + if ($v > 0 && $v < Minz_Configuration::MAX_SMALL_INT) { + self::$limits['max_feeds'] = $v; } } if (isset($limits['max_categories'])) { - self::$limits['max_categories'] = intval($limits['max_categories']); - if (self::$limits['max_categories'] < 0 || self::$limits['max_categories'] > Minz_Configuration::MAX_SMALL_INT) { - self::$limits['max_categories'] = Minz_Configuration::MAX_SMALL_INT; + $v = intval($limits['max_categories']); + if ($v > 0 && $v < Minz_Configuration::MAX_SMALL_INT) { + self::$limits['max_categories'] = $v; } } } diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 8ae357f02..3648a4582 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -110,11 +110,12 @@ function html_only_entity_decode($text) { } function customSimplePie() { + $limits = Minz_Configuration::limits(); $simplePie = new SimplePie(); $simplePie->set_useragent(_t('freshrss') . '/' . FRESHRSS_VERSION . ' (' . PHP_OS . '; ' . FRESHRSS_WEBSITE . ') ' . SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION); $simplePie->set_cache_location(CACHE_PATH); - $simplePie->set_cache_duration(800); - $simplePie->set_timeout(10); //TODO: Make a user setting + $simplePie->set_cache_duration($limits['cache_duration']); + $simplePie->set_timeout($limits['timeout']); $simplePie->strip_htmltags(array( 'base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', -- cgit v1.2.3 From 4cbd7e0583709912d790ed04a72b75d79da31b73 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 28 Oct 2014 23:32:55 +0100 Subject: Bug: unlock was not done for feeds with error --- app/Controllers/feedController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 39e4b5761..7ac083d56 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -293,6 +293,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } catch (FreshRSS_Feed_Exception $e) { Minz_Log::notice($e->getMessage()); $feedDAO->updateLastUpdate($feed->id(), 1); + $feed->unlock(); continue; } -- cgit v1.2.3 From 00127f07c5fc784130d658e3f26519b0279fc6b8 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 28 Oct 2014 23:52:46 +0100 Subject: SimplePie: cache feeds with errors Before the cache system was not used for feeds with errors, which was problematic especially if several users have this feed. Furthermore, there was no protection against repetitive refresh. Bonus: slightly better performance by avoiding some superfluous file_exists(). Warning: needs a bit of testing https://github.com/marienfressinaud/FreshRSS/issues/681 --- app/Models/Feed.php | 3 ++- lib/SimplePie/SimplePie.php | 24 +++++++++++++++--------- lib/SimplePie/SimplePie/Cache/File.php | 12 ++++++------ 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/app/Models/Feed.php b/app/Models/Feed.php index 03baf3ad2..bd1babeea 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -217,7 +217,8 @@ class FreshRSS_Feed extends Minz_Model { $mtime = $feed->init(); if ((!$mtime) || $feed->error()) { - throw new FreshRSS_Feed_Exception($feed->error() . ' [' . $url . ']'); + $errorMessage = $feed->error(); + throw new FreshRSS_Feed_Exception(($errorMessage == '' ? 'Feed error' : $errorMessage) . ' [' . $url . ']'); } if ($loadDetails) { diff --git a/lib/SimplePie/SimplePie.php b/lib/SimplePie/SimplePie.php index 06c100f59..84001dd9a 100644 --- a/lib/SimplePie/SimplePie.php +++ b/lib/SimplePie/SimplePie.php @@ -1455,7 +1455,11 @@ class SimplePie { // Load the Cache $this->data = $cache->load(); - if (!empty($this->data)) + if ($cache->mtime() + $this->cache_duration > time()) { //FreshRSS + $this->raw_data = false; + return true; // If the cache is still valid, just return true + } + elseif (!empty($this->data)) { // If the cache is for an outdated build of SimplePie if (!isset($this->data['build']) || $this->data['build'] !== SIMPLEPIE_BUILD) @@ -1487,7 +1491,7 @@ class SimplePie } } // Check if the cache has been updated - elseif ($cache->mtime() + $this->cache_duration < time()) + else //if ($cache->mtime() + $this->cache_duration < time()) //FreshRSS removed { // If we have last-modified and/or etag set //if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag'])) //FreshRSS removed @@ -1516,6 +1520,7 @@ class SimplePie } else { + $cache->touch(); //FreshRSS $this->error = $file->error; //FreshRSS return !empty($this->data); //FreshRSS //unset($file); //FreshRSS removed @@ -1533,17 +1538,18 @@ class SimplePie } } } - // If the cache is still valid, just return true - else - { - $this->raw_data = false; - return true; - } + //// If the cache is still valid, just return true + //else //FreshRSS removed + //{ + // $this->raw_data = false; + // return true; + //} } // If the cache is empty, delete it else { - $cache->unlink(); + //$cache->unlink(); //FreshRSS removed + $cache->touch(); //FreshRSS $this->data = array(); } } diff --git a/lib/SimplePie/SimplePie/Cache/File.php b/lib/SimplePie/SimplePie/Cache/File.php index 3b163545b..cb4b528c4 100644 --- a/lib/SimplePie/SimplePie/Cache/File.php +++ b/lib/SimplePie/SimplePie/Cache/File.php @@ -136,11 +136,11 @@ class SimplePie_Cache_File implements SimplePie_Cache_Base */ public function mtime() { - if (file_exists($this->name)) + //if (file_exists($this->name)) //FreshRSS removed { - return filemtime($this->name); + return @filemtime($this->name); //FreshRSS } - return false; + //return false; //FreshRSS removed } /** @@ -150,11 +150,11 @@ class SimplePie_Cache_File implements SimplePie_Cache_Base */ public function touch() { - if (file_exists($this->name)) + //if (file_exists($this->name)) //FreshRSS removed { - return touch($this->name); + return @touch($this->name); //FreshRSS } - return false; + //return false; //FreshRSS removed } /** -- cgit v1.2.3 From 9f97f7df8822ed2f32a9bc9d46ece92dee93089c Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 29 Oct 2014 00:45:42 +0100 Subject: Ne pas rafraîchir les flux des utilisateurs non logués depuis x jours MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/marienfressinaud/FreshRSS/issues/681 Warning: needs some testing --- CHANGELOG | 2 +- app/Controllers/userController.php | 3 +-- app/Models/Auth.php | 13 +++++-------- app/Models/UserDAO.php | 10 +++++++++- app/actualize_script.php | 10 ++++++++++ lib/Minz/Configuration.php | 7 +++++++ 6 files changed, 33 insertions(+), 12 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 688a286e3..a556fcc13 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,7 +3,7 @@ ## * Configuration - * New options in config.php for cache duration, timeout, max number of feeds and categories per user. + * New options in config.php for cache duration, timeout, max inactivity, max number of feeds and categories per user. ## 2014-09-26 FreshRSS 0.8.0 / 0.9.0 (beta) diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index 2343520ca..39db1d879 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -95,9 +95,8 @@ class FreshRSS_user_Controller extends Minz_ActionController { Minz_View::prependTitle(_t('gen.title.user_management') . ' · '); // Get the correct current user. - $userDAO = new FreshRSS_UserDAO(); $username = Minz_Request::param('u', Minz_Session::param('currentUser')); - if (!$userDAO->exist($username)) { + if (!FreshRSS_UserDAO::exist($username)) { $username = Minz_Session::param('currentUser'); } $this->view->current_user = $username; diff --git a/app/Models/Auth.php b/app/Models/Auth.php index cc23d7974..2971d65c8 100644 --- a/app/Models/Auth.php +++ b/app/Models/Auth.php @@ -20,10 +20,11 @@ class FreshRSS_Auth { Minz_Session::_param('currentUser', $current_user); } - $access_ok = self::accessControl(); - - if ($access_ok) { + if (self::$login_ok) { self::giveAccess(); + } elseif (self::accessControl()) { + self::giveAccess(); + FreshRSS_UserDAO::touch($current_user); } else { // Be sure all accesses are removed! self::removeAccess(); @@ -38,11 +39,7 @@ class FreshRSS_Auth { * * @return boolean true if user can be connected, false else. */ - public static function accessControl() { - if (self::$login_ok) { - return true; - } - + private static function accessControl() { switch (Minz_Configuration::authType()) { case 'form': $credentials = FreshRSS_FormAuth::getCredentialsFromCookie(); diff --git a/app/Models/UserDAO.php b/app/Models/UserDAO.php index 85b45c4a7..60fca71b1 100644 --- a/app/Models/UserDAO.php +++ b/app/Models/UserDAO.php @@ -54,7 +54,15 @@ class FreshRSS_UserDAO extends Minz_ModelPdo { } } - public function exist($username) { + public static function exist($username) { return file_exists(DATA_PATH . '/' . $username . '_user.php'); } + + public static function touch($username) { + return touch(DATA_PATH . '/' . $username . '_user.php'); + } + + public static function mtime($username) { + return @filemtime(DATA_PATH . '/' . $username . '_user.php'); + } } diff --git a/app/actualize_script.php b/app/actualize_script.php index 9fe499cc9..6ce4178cd 100755 --- a/app/actualize_script.php +++ b/app/actualize_script.php @@ -22,7 +22,17 @@ if (Minz_Configuration::defaultUser() !== ''){ $users = array_unique($users); } +$limits = Minz_Configuration::limits(); +$minLastActivity = time() - $limits['max_inactivity']; + foreach ($users as $myUser) { + if (($myUser !== Minz_Configuration::defaultUser()) && (FreshRSS_UserDAO::mtime($myUser) < $minLastActivity)) { + syslog(LOG_INFO, 'FreshRSS skip inactive user ' . $myUser); + if (defined('STDOUT')) { + fwrite(STDOUT, 'FreshRSS skip inactive user ' . $myUser . "\n"); //Unbuffered + } + continue; + } syslog(LOG_INFO, 'FreshRSS actualize ' . $myUser); if (defined('STDOUT')) { fwrite(STDOUT, 'Actualize ' . $myUser . "...\n"); //Unbuffered diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php index 9511cb357..6cbc9fc0b 100644 --- a/lib/Minz/Configuration.php +++ b/lib/Minz/Configuration.php @@ -64,6 +64,7 @@ class Minz_Configuration { private static $limits = array( 'cache_duration' => 800, //SimplePie cache duration in seconds 'timeout' => 10, //SimplePie timeout in seconds + 'max_inactivity' => PHP_INT_MAX, //Time in seconds after which a user who has not used the account is considered inactive (no auto-refresh of feeds). 'max_feeds' => Minz_Configuration::MAX_SMALL_INT, 'max_categories' => Minz_Configuration::MAX_SMALL_INT, ); @@ -317,6 +318,12 @@ class Minz_Configuration { self::$limits['timeout'] = $v; } } + if (isset($limits['max_inactivity'])) { + $v = intval($limits['max_inactivity']); + if ($v > 0) { + self::$limits['max_inactivity'] = $v; + } + } if (isset($limits['max_feeds'])) { $v = intval($limits['max_feeds']); if ($v > 0 && $v < Minz_Configuration::MAX_SMALL_INT) { -- cgit v1.2.3 From 1ea996c4eaa0f07f4fd906e7cade68a9bee3b11d Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 29 Oct 2014 10:15:22 +0100 Subject: Update i18n for limit of category. --- app/Controllers/categoryController.php | 5 +++-- app/i18n/en.php | 5 +---- app/i18n/fr.php | 5 +---- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/app/Controllers/categoryController.php b/app/Controllers/categoryController.php index ef8af7ed6..609284559 100644 --- a/app/Controllers/categoryController.php +++ b/app/Controllers/categoryController.php @@ -35,9 +35,10 @@ class FreshRSS_category_Controller extends Minz_ActionController { $limits = Minz_Configuration::limits(); $this->view->categories = $catDAO->listCategories(false); + if (count($this->view->categories) >= $limits['max_categories']) { - Minz_Request::bad(_t('over_max_categories', $limits['max_categories']), $url_redirect); - return; + Minz_Request::bad(_t('sub.categories.over_max', $limits['max_categories']), + $url_redirect); } if (Minz_Request::isPost()) { diff --git a/app/i18n/en.php b/app/i18n/en.php index 1e6621c12..2c61d822d 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -53,10 +53,6 @@ 'admin.check_install.pcre.ok' => 'You have the required library for regular expressions (PCRE).', 'admin.check_install.pdo.nok' => 'You lack PDO or one of the supported drivers (pdo_mysql, pdo_sqlite).', 'admin.check_install.pdo.ok' => 'You have PDO and at least one of the supported drivers (pdo_mysql, pdo_sqlite).', - 'admin.check_install.pdo_mysql.nok' => 'You lack PDO for MySQL (it\'s ok if PDO is good).', - 'admin.check_install.pdo_mysql.ok' => 'You have PDO for MySQL.', - 'admin.check_install.pdo_sqlite.nok' => 'You lack PDO for SQLite (it\'s ok if PDO is good).', - 'admin.check_install.pdo_sqlite.ok' => 'You have PDO for SQLite.', 'admin.check_install.persona.nok' => 'Check permissions on ./data/persona directory. HTTP server must have rights to write into', 'admin.check_install.persona.ok' => 'Permissions on Mozilla Persona directory are good.', 'admin.check_install.php' => 'PHP installation', @@ -477,6 +473,7 @@ 'status_unread' => 'Unread', 'steps' => 'Steps', 'sticky_post' => 'Stick the article to the top when opened', + 'sub.categories.over_max' => 'You have reached your limit of categories (%d)', 'submit' => 'Submit', 'subscription_management' => 'Subscriptions management', 'sun' => 'Sun', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 61a84cc04..2420b20c3 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -53,10 +53,6 @@ 'admin.check_install.pcre.ok' => 'Vous disposez du nécessaire pour les expressions régulières (PCRE).', 'admin.check_install.pdo.nok' => 'Vous ne disposez pas de PDO ou d’un des drivers supportés (pdo_mysql, pdo_sqlite).', 'admin.check_install.pdo.ok' => 'Vous disposez de PDO et d’au moins un des drivers supportés (pdo_mysql, pdo_sqlite).', - 'admin.check_install.pdo_mysql.nok' => 'Vous ne possédez pas PDO pour MySQL (ok si PDO est bon).', - 'admin.check_install.pdo_mysql.ok' => 'Vous possédez PDO pour MySQL.', - 'admin.check_install.pdo_sqlite.nok' => 'Vous ne possédez pas PDO pour SQLite (ok si PDO est bon).', - 'admin.check_install.pdo_sqlite.ok' => 'Vous possédez PDO pour SQLite.', 'admin.check_install.persona.nok' => 'Veuillez vérifier les droits sur le répertoire ./data/persona. Le serveur HTTP doit être capable d’écrire dedans', 'admin.check_install.persona.ok' => 'Les droits sur le répertoire de Mozilla Persona sont bons.', 'admin.check_install.php' => 'Installation de PHP', @@ -477,6 +473,7 @@ 'status_unread' => 'non lus', 'steps' => 'Étapes', 'sticky_post' => 'Aligner l’article en haut quand il est ouvert', + 'sub.categories.over_max' => 'Vous avez atteint votre limite de catégories (%d)', 'submit' => 'Valider', 'subscription_management' => 'Gestion des abonnements', 'sun' => 'dim.', -- cgit v1.2.3 From cf7350af4768809c8b5117ba586f5165a4e2b1a8 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 29 Oct 2014 10:21:34 +0100 Subject: Update i18n for limit of feeds See https://github.com/marienfressinaud/FreshRSS/issues/680 --- app/Controllers/feedController.php | 4 ++-- app/i18n/en.php | 1 + app/i18n/fr.php | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 7ac083d56..8563b1c0f 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -71,8 +71,8 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $limits = Minz_Configuration::limits(); $this->view->feeds = $feedDAO->listFeeds(); if (count($this->view->feeds) >= $limits['max_feeds']) { - Minz_Request::bad(_t('over_max_feeds', $limits['max_feeds']), $url_redirect); - return; + Minz_Request::bad(_t('sub.feeds.over_max', $limits['max_feeds']), + $url_redirect); } if (Minz_Request::isPost()) { diff --git a/app/i18n/en.php b/app/i18n/en.php index 2c61d822d..a35a6ccf1 100644 --- a/app/i18n/en.php +++ b/app/i18n/en.php @@ -474,6 +474,7 @@ 'steps' => 'Steps', 'sticky_post' => 'Stick the article to the top when opened', 'sub.categories.over_max' => 'You have reached your limit of categories (%d)', + 'sub.feeds.over_max' => 'You have reached your limit of feeds (%d)', 'submit' => 'Submit', 'subscription_management' => 'Subscriptions management', 'sun' => 'Sun', diff --git a/app/i18n/fr.php b/app/i18n/fr.php index 2420b20c3..c29b6c9ac 100644 --- a/app/i18n/fr.php +++ b/app/i18n/fr.php @@ -474,6 +474,7 @@ 'steps' => 'Étapes', 'sticky_post' => 'Aligner l’article en haut quand il est ouvert', 'sub.categories.over_max' => 'Vous avez atteint votre limite de catégories (%d)', + 'sub.feeds.over_max' => 'Vous avez atteint votre limite de flux (%d)', 'submit' => 'Valider', 'subscription_management' => 'Gestion des abonnements', 'sun' => 'dim.', -- cgit v1.2.3 From fb3cda8ac9f7c8895ed33d7db432a92b063a7198 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 29 Oct 2014 11:08:31 +0100 Subject: Fix limits in import OPML files See https://github.com/marienfressinaud/FreshRSS/issues/680 --- app/Controllers/importExportController.php | 55 +++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index ab277e688..514077bbd 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -176,19 +176,43 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { */ private function addOpmlElements($opml_elements, $parent_cat = null) { $error = false; + + $nb_feeds = count($this->feedDAO->listFeeds()); + $nb_cats = count($this->catDAO->listCategories(false)); + $limits = Minz_Configuration::limits(); + foreach ($opml_elements as $elt) { - $res = false; + $is_error = false; if (isset($elt['xmlUrl'])) { // If xmlUrl exists, it means it is a feed - $res = $this->addFeedOpml($elt, $parent_cat); + if ($nb_feeds >= $limits['max_feeds']) { + Minz_Log::warning(_t('sub.feeds.over_max', + $limits['max_feeds'])); + $is_error = true; + continue; + } + + $is_error = $this->addFeedOpml($elt, $parent_cat); + if (!$is_error) { + $nb_feeds += 1; + } } else { // No xmlUrl? It should be a category! - $res = $this->addCategoryOpml($elt, $parent_cat); + $limit_reached = ($nb_cats >= $limits['max_categories']); + if ($limit_reached) { + Minz_Log::warning(_t('sub.categories.over_max', + $limits['max_categories'])); + } + + $is_error = $this->addCategoryOpml($elt, $parent_cat, $limit_reached); + if (!$is_error) { + $nb_cats += 1; + } } - if (!$error && $res) { + if (!$error && $is_error) { // oops: there is at least one error! - $error = $res; + $error = $is_error; } } @@ -203,16 +227,18 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { * @return boolean true if an error occured, false else. */ private function addFeedOpml($feed_elt, $parent_cat) { + $default_cat = $this->catDAO->getDefault(); if (is_null($parent_cat)) { // This feed has no parent category so we get the default one - $parent_cat = $this->catDAO->getDefault()->name(); + $parent_cat = $default_cat->name(); } $cat = $this->catDAO->searchByName($parent_cat); - if (!$cat) { + if (is_null($cat)) { // If there is not $cat, it means parent category does not exist in - // database. It should not happened! - return true; + // database. + // If it happens, take the default category. + $cat = $default_cat; } // We get different useful information @@ -253,14 +279,19 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { * * @param array $cat_elt an OPML element (must be a category element). * @param string $parent_cat the name of the parent category. + * @param boolean $cat_limit_reached indicates if category limit has been reached. + * if yes, category is not added (but we try for feeds!) * @return boolean true if an error occured, false else. */ - private function addCategoryOpml($cat_elt, $parent_cat) { + private function addCategoryOpml($cat_elt, $parent_cat, $cat_limit_reached) { // Create a new Category object $cat = new FreshRSS_Category(Minz_Helper::htmlspecialchars_utf8($cat_elt['text'])); - $id = $this->catDAO->addCategoryObject($cat); - $error = ($id === false); + $error = true; + if (!$cat_limit_reached) { + $id = $this->catDAO->addCategoryObject($cat); + $error = ($id === false); + } if (isset($cat_elt['@outlines'])) { // Our cat_elt contains more categories or more feeds, so we -- cgit v1.2.3 From d20b5a127fe95f91b55f3ae9391365c67f96c4cc Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 29 Oct 2014 11:47:51 +0100 Subject: Fix limit in import Json files See https://github.com/marienfressinaud/FreshRSS/issues/680 --- app/Controllers/importExportController.php | 28 +++++++++++++++++++++++++--- app/Models/FeedDAO.php | 2 +- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 514077bbd..8028af8ed 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -327,12 +327,34 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $error = false; $article_to_feed = array(); + $nb_feeds = count($this->feedDAO->listFeeds()); + $limits = Minz_Configuration::limits(); + // First, we check feeds of articles are in DB (and add them if needed). foreach ($article_object['items'] as $item) { - $feed = $this->addFeedJson($item['origin'], $google_compliant); + $key = $google_compliant ? 'htmlUrl' : 'feedUrl'; + $feed = new FreshRSS_Feed($item['origin'][$key]); + $feed = $this->feedDAO->searchByUrl($feed->url()); + if (is_null($feed)) { - $error = true; - } else { + // Feed does not exist in DB,we should to try to add it. + if ($nb_feeds >= $limits['max_feeds']) { + // Oops, no more place! + Minz_Log::warning(_t('sub.feeds.over_max', $limits['max_feeds'])); + } else { + $feed = $this->addFeedJson($item['origin'], $google_compliant); + } + + if (is_null($feed)) { + // Still null? It means something went wrong. + $error = true; + } else { + // Nice! Increase the counter. + $nb_feeds += 1; + } + } + + if (!is_null($feed)) { $article_to_feed[$item['id']] = $feed->id(); } } diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php index 852de6e36..74597c730 100644 --- a/app/Models/FeedDAO.php +++ b/app/Models/FeedDAO.php @@ -191,7 +191,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo { $res = $stm->fetchAll(PDO::FETCH_ASSOC); $feed = current(self::daoToFeed($res)); - if (isset($feed)) { + if (isset($feed) && $feed !== false) { return $feed; } else { return null; -- cgit v1.2.3 From 9478d2f0116be69e08071dd02c0f945c5f78d7e0 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 30 Oct 2014 12:43:52 +0100 Subject: Add do_post_update support --- app/Controllers/updateController.php | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index 4ebb11f51..4ef5357ea 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -109,6 +109,19 @@ class FreshRSS_update_Controller extends Minz_ActionController { require(UPDATE_FILENAME); + if (Minz_Request::param('post_conf', false)) { + $res = do_post_update(); + + if ($res === true) { + @unlink(UPDATE_FILENAME); + @file_put_contents(DATA_PATH . '/last_update.txt', time()); + Minz_Request::good(_t('update_finished')); + } else { + Minz_Request::bad(_t('update_problem', $res), + array('c' => 'update', 'a' => 'index')); + } + } + if (Minz_Request::isPost()) { save_info_update(); } @@ -117,10 +130,11 @@ class FreshRSS_update_Controller extends Minz_ActionController { $res = apply_update(); if ($res === true) { - @unlink(UPDATE_FILENAME); - @file_put_contents(DATA_PATH . '/last_update.txt', time()); - - Minz_Request::good(_t('update_finished')); + Minz_Request::forward(array( + 'c' => 'update', + 'a' => 'apply', + 'params' => array('post_conf' => true) + ), true); } else { Minz_Request::bad(_t('update_problem', $res), array('c' => 'update', 'a' => 'index')); -- cgit v1.2.3 From ee5bbe48269a2fd5bc9c175fdb1e5a92a2c04502 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 30 Oct 2014 19:19:09 +0100 Subject: Fix bug size with SQLite --- app/Controllers/configureController.php | 2 +- lib/Minz/ModelPdo.php | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index cafd0e8a8..deb8cc849 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -225,7 +225,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { Minz_View::prependTitle(_t('archiving_configuration') . ' · '); - $entryDAO = FreshRSS_Factory::createEntryDao(); + $entryDAO = FreshRSS_Factory::createEntryDao('freshrss'); $this->view->nb_total = $entryDAO->count(); $this->view->size_user = $entryDAO->size(); diff --git a/lib/Minz/ModelPdo.php b/lib/Minz/ModelPdo.php index 827c89c69..6198cd85c 100644 --- a/lib/Minz/ModelPdo.php +++ b/lib/Minz/ModelPdo.php @@ -17,6 +17,7 @@ class Minz_ModelPdo { private static $sharedBd = null; private static $sharedPrefix; private static $has_transaction = false; + private static $sharedCurrentUser; protected static $sharedDbType; /** @@ -39,6 +40,7 @@ class Minz_ModelPdo { if (self::$useSharedBd && self::$sharedBd != null && $currentUser === null) { $this->bd = self::$sharedBd; $this->prefix = self::$sharedPrefix; + $this->current_user = self::$sharedCurrentUser; return; } @@ -48,6 +50,7 @@ class Minz_ModelPdo { $currentUser = Minz_Session::param('currentUser', '_'); } $this->current_user = $currentUser; + self::$sharedCurrentUser = $currentUser; try { $type = $db['type']; -- cgit v1.2.3 From 036240ab01999c8eff1b9b3a98a7313cf43f5836 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 30 Oct 2014 19:31:32 +0100 Subject: Fix coding style formatNumber and formatBytes --- app/views/configure/archiving.phtml | 4 ++-- app/views/stats/index.phtml | 20 ++++++++++---------- app/views/user/manage.phtml | 4 ++-- lib/lib_rss.php | 14 ++++++-------- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/app/views/configure/archiving.phtml b/app/views/configure/archiving.phtml index 410434599..7c2d79343 100644 --- a/app/views/configure/archiving.phtml +++ b/app/views/configure/archiving.phtml @@ -60,7 +60,7 @@
    - nb_total), formatBytes($this->size_user)); ?> + nb_total), format_bytes($this->size_user)); ?>
    @@ -68,7 +68,7 @@
    - size_total); ?> + size_total); ?>
    diff --git a/app/views/stats/index.phtml b/app/views/stats/index.phtml index ba4258b71..c75810850 100644 --- a/app/views/stats/index.phtml +++ b/app/views/stats/index.phtml @@ -18,23 +18,23 @@ - repartition['main_stream']['total']); ?> - repartition['all_feeds']['total']); ?> + repartition['main_stream']['total']); ?> + repartition['all_feeds']['total']); ?> - repartition['main_stream']['read']); ?> - repartition['all_feeds']['read']); ?> + repartition['main_stream']['read']); ?> + repartition['all_feeds']['read']); ?> - repartition['main_stream']['unread']); ?> - repartition['all_feeds']['unread']); ?> + repartition['main_stream']['unread']); ?> + repartition['all_feeds']['unread']); ?> - repartition['main_stream']['favorite']); ?> - repartition['all_feeds']['favorite']); ?> + repartition['main_stream']['favorite']); ?> + repartition['all_feeds']['favorite']); ?> @@ -56,8 +56,8 @@ - - repartition['all_feeds']['total'] * 100, 1);?> + + repartition['all_feeds']['total'] * 100, 1);?> diff --git a/app/views/user/manage.phtml b/app/views/user/manage.phtml index 2bfd633a2..e46e02572 100644 --- a/app/views/user/manage.phtml +++ b/app/views/user/manage.phtml @@ -65,8 +65,8 @@

    nb_articles), - formatBytes($this->size_user)); ?>

    + format_number($this->nb_articles), + format_bytes($this->size_user)); ?>

    diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 3648a4582..317c6852f 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -56,16 +56,14 @@ function checkUrl($url) { } } -function formatNumber($n, $precision = 0) { - return str_replace(' ', ' ', //Espace insécable //TODO: remplacer par une espace _fine_ insécable - number_format($n, $precision, '.', ' ')); //number_format does not seem to be Unicode-compatible -} function format_number($n, $precision = 0) { - // TODO: coding style, prefer THIS function. Remove formatNumber. - return formatNumber($n, $precision); + // number_format does not seem to be Unicode-compatible + return str_replace(' ', ' ', //Espace insécable //TODO: remplacer par une espace _fine_ insécable + number_format($n, $precision, '.', ' ') + ); } -function formatBytes($bytes, $precision = 2, $system = 'IEC') { +function format_bytes($bytes, $precision = 2, $system = 'IEC') { if ($system === 'IEC') { $base = 1024; $units = array('B', 'KiB', 'MiB', 'GiB', 'TiB'); @@ -77,7 +75,7 @@ function formatBytes($bytes, $precision = 2, $system = 'IEC') { $pow = $bytes === 0 ? 0 : floor(log($bytes) / log($base)); $pow = min($pow, count($units) - 1); $bytes /= pow($base, $pow); - return formatNumber($bytes, $precision) . ' ' . $units[$pow]; + return format_number($bytes, $precision) . ' ' . $units[$pow]; } function timestamptodate ($t, $hour = true) { -- cgit v1.2.3 From ba832bef4de4a02df46023b389f752b01d43c98b Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 30 Oct 2014 19:34:36 +0100 Subject: Fix TODO in format_number() --- lib/lib_rss.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 317c6852f..e7ca95aba 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -58,7 +58,7 @@ function checkUrl($url) { function format_number($n, $precision = 0) { // number_format does not seem to be Unicode-compatible - return str_replace(' ', ' ', //Espace insécable //TODO: remplacer par une espace _fine_ insécable + return str_replace(' ', ' ', //Espace fine insécable number_format($n, $precision, '.', ' ') ); } -- cgit v1.2.3 From 58deab37cdd97e93ac25aba574a32befe1db2243 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 30 Oct 2014 19:57:08 +0100 Subject: Fix Minz_Error::error() -> use default values --- app/Controllers/authController.php | 3 +-- app/Controllers/categoryController.php | 5 +---- app/Controllers/configureController.php | 5 +---- app/Controllers/entryController.php | 5 +---- app/Controllers/feedController.php | 10 ++-------- app/Controllers/importExportController.php | 5 +---- app/Controllers/statsController.php | 29 +++++++++++++---------------- app/Controllers/subscriptionController.php | 10 ++-------- app/Controllers/updateController.php | 5 +---- app/Controllers/userController.php | 8 ++------ 10 files changed, 25 insertions(+), 60 deletions(-) diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index 491be8d8a..44496cd3e 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -19,8 +19,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { */ public function indexAction() { if (!FreshRSS_Auth::hasAccess('admin')) { - Minz_Error::error(403, - array('error' => array(_t('access_denied')))); + Minz_Error::error(403); } Minz_View::prependTitle(_t('gen.title.authentication') . ' · '); diff --git a/app/Controllers/categoryController.php b/app/Controllers/categoryController.php index 609284559..50b1d841a 100644 --- a/app/Controllers/categoryController.php +++ b/app/Controllers/categoryController.php @@ -13,10 +13,7 @@ class FreshRSS_category_Controller extends Minz_ActionController { */ public function firstAction() { if (!FreshRSS_Auth::hasAccess()) { - Minz_Error::error( - 403, - array('error' => array(_t('access_denied'))) - ); + Minz_Error::error(403); } $catDAO = new FreshRSS_CategoryDAO(); diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index deb8cc849..1c8ac9111 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -11,10 +11,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { */ public function firstAction() { if (!FreshRSS_Auth::hasAccess()) { - Minz_Error::error( - 403, - array('error' => array(_t('access_denied'))) - ); + Minz_Error::error(403); } } diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php index d11f3a520..b4beed619 100755 --- a/app/Controllers/entryController.php +++ b/app/Controllers/entryController.php @@ -11,10 +11,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { */ public function firstAction() { if (!FreshRSS_Auth::hasAccess()) { - Minz_Error::error( - 403, - array('error' => array(_t('access_denied'))) - ); + Minz_Error::error(403); } // If ajax request, we do not print layout diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 8563b1c0f..9990a852c 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -20,10 +20,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $action = Minz_Request::actionName(); if ($action !== 'actualize' || !(Minz_Configuration::allowAnonymousRefresh() || $token_is_ok)) { - Minz_Error::error( - 403, - array('error' => array(_t('access_denied'))) - ); + Minz_Error::error(403); } } } @@ -442,10 +439,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { } else { Minz_Log::warning('Cannot move feed `' . $feed_id . '` ' . 'in the category `' . $cat_id . '`'); - Minz_Error::error( - 404, - array('error' => array(_t('error_occurred'))) - ); + Minz_Error::error(404); } } diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 8028af8ed..4e2dbd157 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -11,10 +11,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { */ public function firstAction() { if (!FreshRSS_Auth::hasAccess()) { - Minz_Error::error( - 403, - array('error' => array(_t('access_denied'))) - ); + Minz_Error::error(403); } require_once(LIB_PATH . '/lib_opml.php'); diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php index 0e3430fcc..18fbca6df 100644 --- a/app/Controllers/statsController.php +++ b/app/Controllers/statsController.php @@ -5,6 +5,19 @@ */ class FreshRSS_stats_Controller extends Minz_ActionController { + /** + * This action is called before every other action in that class. It is + * the common boiler plate for every action. It is triggered by the + * underlying framework. + */ + public function firstAction() { + if (!FreshRSS_Auth::hasAccess()) { + Minz_Error::error(403); + } + + Minz_View::prependTitle(_t('stats') . ' · '); + } + /** * This action handles the statistic main page. * @@ -111,20 +124,4 @@ class FreshRSS_stats_Controller extends Minz_ActionController { $this->view->repartitionMonth = $statsDAO->calculateEntryRepartitionPerFeedPerMonth($id); $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 (!FreshRSS_Auth::hasAccess()) { - Minz_Error::error( - 403, array('error' => array(_t('access_denied'))) - ); - } - - Minz_View::prependTitle(_t('stats') . ' · '); - } - } diff --git a/app/Controllers/subscriptionController.php b/app/Controllers/subscriptionController.php index a89168eb3..67b95eba6 100644 --- a/app/Controllers/subscriptionController.php +++ b/app/Controllers/subscriptionController.php @@ -11,10 +11,7 @@ class FreshRSS_subscription_Controller extends Minz_ActionController { */ public function firstAction() { if (!FreshRSS_Auth::hasAccess()) { - Minz_Error::error( - 403, - array('error' => array(_t('access_denied'))) - ); + Minz_Error::error(403); } $catDAO = new FreshRSS_CategoryDAO(); @@ -71,10 +68,7 @@ class FreshRSS_subscription_Controller extends Minz_ActionController { $id = Minz_Request::param('id'); if ($id === false || !isset($this->view->feeds[$id])) { - Minz_Error::error( - 404, - array('error' => array(_t('page_not_found'))) - ); + Minz_Error::error(404); return; } diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php index 4ef5357ea..0896b13ac 100644 --- a/app/Controllers/updateController.php +++ b/app/Controllers/updateController.php @@ -4,10 +4,7 @@ class FreshRSS_update_Controller extends Minz_ActionController { public function firstAction() { $current_user = Minz_Session::param('currentUser', ''); if (!FreshRSS_Auth::hasAccess('admin')) { - Minz_Error::error( - 403, - array('error' => array(_t('access_denied'))) - ); + Minz_Error::error(403); } invalidateHttpCache(); diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index 39db1d879..5050571a9 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -15,10 +15,7 @@ class FreshRSS_user_Controller extends Minz_ActionController { */ public function firstAction() { if (!FreshRSS_Auth::hasAccess()) { - Minz_Error::error( - 403, - array('error' => array(_t('access_denied'))) - ); + Minz_Error::error(403); } } @@ -88,8 +85,7 @@ class FreshRSS_user_Controller extends Minz_ActionController { */ public function manageAction() { if (!FreshRSS_Auth::hasAccess('admin')) { - Minz_Error::error(403, - array('error' => array(_t('access_denied')))); + Minz_Error::error(403); } Minz_View::prependTitle(_t('gen.title.user_management') . ' · '); -- cgit v1.2.3 From 39d2a26cf0cbdf9238ba7a43c812225565f094b1 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 30 Oct 2014 20:00:25 +0100 Subject: Fix bug in stats/index.phtml --- app/views/stats/index.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/stats/index.phtml b/app/views/stats/index.phtml index c75810850..1300cb2c7 100644 --- a/app/views/stats/index.phtml +++ b/app/views/stats/index.phtml @@ -23,7 +23,7 @@ - repartition['main_stream']['read']); ?> + repartition['main_stream']['read']); ?> repartition['all_feeds']['read']); ?> -- cgit v1.2.3 From 3d3dc81e0fd382112a98e895559980836970bf80 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 31 Oct 2014 14:23:11 +0100 Subject: Update CHANGELOG --- CHANGELOG | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index a556fcc13..1543847df 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,9 +1,42 @@ # Journal des modifications -## +## 2014-10-31 FreshRSS 0.9.2 (beta) +* UI + * New subscription page (introduce .box items) + * Change feed category by drag and drop + * New feed aside on the main page + * New configuration / administration organization * Configuration * New options in config.php for cache duration, timeout, max inactivity, max number of feeds and categories per user. +* Refactoring + * Refactor authentication system (introduce FreshRSS_Auth model) + * Refactor indexController (introduce FreshRSS_Context model) + * Use ```_t()```, ```_i()```, ```_url()```, ```Minz_Request::good()``` and ```Minz_Request::bad()``` as much as possible + * Refactor javascript_vars.phtml + * Better coding style +* I18n + * Introduce a new system for i18n keys (not finished yet) +* Misc. + * Fix global view (didn't work anymore) + * Add do_post_update for update system + * Introduce ```checkInstallAction``` to test if FreshRSS installation is ok + + + +## 2014-10-09 FreshRSS 0.8.1 / 0.9.1 (beta) + +* UI + * Add a space after tag icon +* Statistics + * Add an average per day on the 30 day period graph + * Add percent of total on top 10 feed +* Bug fixes + * Fix "mark as read" in global view + * Fix "read all" shortcut + * Fix categories not appearing when adding a new feed (GET action) + * Fix enclosure problem + * Fix getExtension() on PHP < 5.3.7 ## 2014-09-26 FreshRSS 0.8.0 / 0.9.0 (beta) -- cgit v1.2.3 From d9c56fb6f76a0a79ec193188e7416d624944c8f3 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 31 Oct 2014 15:58:19 +0100 Subject: Remove check database for next beta See https://github.com/FreshRSS/FreshRSS/issues/678 --- app/views/update/checkInstall.phtml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/views/update/checkInstall.phtml b/app/views/update/checkInstall.phtml index 5f913bccd..b36551340 100644 --- a/app/views/update/checkInstall.phtml +++ b/app/views/update/checkInstall.phtml @@ -25,6 +25,7 @@

    + status_database as $key => $status) { ?> @@ -32,5 +33,6 @@

    + */ ?>
    -- cgit v1.2.3 From 724e13f0a6419b046b33da71e66058e279551edd Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 31 Oct 2014 16:43:05 +0100 Subject: Fix global view mark as read --- app/views/index/global.phtml | 5 +++-- p/scripts/global_view.js | 12 ++++++------ p/themes/base-theme/template.css | 6 +++--- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/app/views/index/global.phtml b/app/views/index/global.phtml index 0975a5a00..ae7f5ffbc 100644 --- a/app/views/index/global.phtml +++ b/app/views/index/global.phtml @@ -47,7 +47,8 @@ ?>
    -
    -
    display_posts ? '' : ' class="hide_posts"'; ?>> +
    +
    display_posts ? '' : ' class="hide_posts"'; ?>> +
    diff --git a/p/scripts/global_view.js b/p/scripts/global_view.js index 14909f44e..7d7ba22b5 100644 --- a/p/scripts/global_view.js +++ b/p/scripts/global_view.js @@ -24,12 +24,13 @@ function load_panel(link) { // en en ouvrant une autre ensuite, on se retrouve au même point de scroll $("#panel").scrollTop(0); - $('#panel').on('click', '#nav_menu_read_all > a, #nav_menu_read_all .item > a, #bigMarkAsRead', function () { + $('#panel').on('click', '#nav_menu_read_all button, #bigMarkAsRead', function () { + console.log($(this).attr("formaction")); $.ajax({ - url: $(this).attr("href"), + type: "POST", + url: $(this).attr("formaction"), async: false }); - //$("#panel .close").first().click(); window.location.reload(false); return false; }); @@ -39,9 +40,8 @@ function load_panel(link) { } function init_close_panel() { - $("#panel .close").click(function () { - $("#panel").html('' + icons['close'] + ''); - init_close_panel(); + $("#overlay .close").click(function () { + $("#panel").html(''); $("#panel").slideToggle(); $("#overlay").fadeOut(); diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index 79fe506f2..5ba621415 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -645,13 +645,13 @@ br + br + br { overflow: auto; background: #fff; } -#panel .close { +#overlay .close { position: fixed; top: 0; bottom: 0; left: 0; right: 0; display: block; } -#panel .close img { +#overlay .close img { display: none; } @@ -762,7 +762,7 @@ br + br + br { } #panel { - top: 0; bottom: 0; + top: 25px; bottom: 30px; left: 0; right: 0; } #panel .close { -- cgit v1.2.3 From afe51884d9258e26a3aecfe422e69ede9f86fa7e Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sat, 1 Nov 2014 09:58:06 -0400 Subject: Add CSS numbering on user query list --- p/themes/base-theme/template.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index 5ba621415..f696ac237 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -499,7 +499,8 @@ a.btn { text-overflow: ellipsis; overflow: hidden; } -.flux .item.share > a { +.flux .item.share > a, +.item.query > a { display: list-item; list-style-position: inside; list-style-type: decimal; -- cgit v1.2.3 From 2dcea37e70cf4520faadd0d4862a44fce6cb8fc7 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sat, 1 Nov 2014 10:11:11 -0400 Subject: Remove border on Dark and Origin for unread entry counters --- p/themes/Dark/dark.css | 1 - p/themes/Origine/origine.css | 1 - 2 files changed, 2 deletions(-) diff --git a/p/themes/Dark/dark.css b/p/themes/Dark/dark.css index 03bf3c985..909444d43 100644 --- a/p/themes/Dark/dark.css +++ b/p/themes/Dark/dark.css @@ -561,7 +561,6 @@ a.btn { font-size: 0.9rem; line-height: 1.5rem; background: inherit; - border-left: 1px solid #666; } /*=== Aside main page (feeds) */ diff --git a/p/themes/Origine/origine.css b/p/themes/Origine/origine.css index afd6ec04f..eb2ecd5e8 100644 --- a/p/themes/Origine/origine.css +++ b/p/themes/Origine/origine.css @@ -601,7 +601,6 @@ a.btn { font-size: 0.9rem; line-height: 1.5rem; background: inherit; - border-left: 1px solid #aaa; } /*=== Aside main page (feeds) */ -- cgit v1.2.3 From 960f86ba20fdf7320c957141a9983d17c7e521fa Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sun, 2 Nov 2014 10:05:26 -0500 Subject: Add a feature to hide articles when they are read This is a new reading option to hide articles when they are read. The hidding process occurs when the article is left for an other article. This way, even when the article is marked as read on opening, it is hidden only while navigating to an other article. I'm not really happy with the behavior when the "mark while scrolling" option is enabled. Please review. It is missing the i18n since we're not supposed to push them before it exists on i18n.freshrss.org. Or maybe I misunderstood the process. See #476 --- app/Controllers/configureController.php | 2 ++ app/Models/Configuration.php | 4 ++++ app/Models/Context.php | 22 ++++++++++++++++++++++ app/views/configure/reading.phtml | 10 ++++++++++ app/views/helpers/javascript_vars.phtml | 1 + p/scripts/main.js | 8 ++++++++ 6 files changed, 47 insertions(+) diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 1c8ac9111..53536afce 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -89,6 +89,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { * - image lazy loading * - stick open articles to the top * - display a confirmation when reading all articles + * - auto remove article after reading * - article order (default: DESC) * - mark articles as read when: * - displayed @@ -110,6 +111,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { FreshRSS_Context::$conf->_lazyload(Minz_Request::param('lazyload', false)); FreshRSS_Context::$conf->_sticky_post(Minz_Request::param('sticky_post', false)); FreshRSS_Context::$conf->_reading_confirm(Minz_Request::param('reading_confirm', false)); + FreshRSS_Context::$conf->_auto_remove_article(Minz_Request::param('auto_remove_article', false)); FreshRSS_Context::$conf->_sort_order(Minz_Request::param('sort_order', 'DESC')); FreshRSS_Context::$conf->_mark_when(array( 'article' => Minz_Request::param('mark_open_article', false), diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index 53f136513..8668470b0 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -24,6 +24,7 @@ class FreshRSS_Configuration { 'lazyload' => true, 'sticky_post' => true, 'reading_confirm' => false, + 'auto_remove_article' => false, 'sort_order' => 'DESC', 'anon_access' => false, 'mark_when' => array( @@ -191,6 +192,9 @@ class FreshRSS_Configuration { public function _reading_confirm($value) { $this->data['reading_confirm'] = ((bool)$value) && $value !== 'no'; } + public function _auto_remove_article($value) { + $this->data['auto_remove_article'] = ((bool)$value) && $value !== 'no'; + } public function _sort_order($value) { $this->data['sort_order'] = $value === 'ASC' ? 'ASC' : 'DESC'; } diff --git a/app/Models/Context.php b/app/Models/Context.php index 36c4087eb..cbd6a5888 100644 --- a/app/Models/Context.php +++ b/app/Models/Context.php @@ -265,4 +265,26 @@ class FreshRSS_Context { } } } + + /** + * Determine if the auto remove is available in the current context. + * This feature is available if: + * - it is activated in the configuration + * - the "read" state is not enable + * - the "unread" state is enable + * + * @return boolean + */ + public static function isAutoRemoveAvailable() { + if (!self::$conf->auto_remove_article) { + return false; + } + if (self::isStateEnabled(FreshRSS_Entry::STATE_READ)) { + return false; + } + if (!self::isStateEnabled(FreshRSS_Entry::STATE_NOT_READ)) { + return false; + } + return true; + } } diff --git a/app/views/configure/reading.phtml b/app/views/configure/reading.phtml index b8f673466..0f7a3347a 100644 --- a/app/views/configure/reading.phtml +++ b/app/views/configure/reading.phtml @@ -115,6 +115,16 @@
    +
    +
    + +
    +
    +
    diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 8e9141d4e..6424d8d04 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -18,6 +18,7 @@ $url_logout = Minz_Url::display(array( ), 'php'); echo 'var context={', + 'auto_remove_article:', FreshRSS_Context::isAutoRemoveAvailable() ? 'true' : 'false', ',', 'hide_posts:', $hide_posts ? 'false' : 'true', ',', 'display_order:"', Minz_Request::param('order', FreshRSS_Context::$conf->sort_order), '",', 'auto_mark_article:', $mark['article'] ? 'true' : 'false', ',', diff --git a/p/scripts/main.js b/p/scripts/main.js index dc5428048..d1d31c801 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -231,6 +231,14 @@ function toggleContent(new_active, old_active) { } old_active.removeClass("active current"); new_active.addClass("current"); + if (context['auto_remove_article'] && !old_active.hasClass('not_read')) { + var p = old_active.prev(); + var n = old_active.next(); + if (p.hasClass('day') && n.hasClass('day')) { + p.remove(); + } + old_active.remove(); + } } else { new_active.toggleClass('active'); } -- cgit v1.2.3 From 4c4604120e41ad8f40e6299bd7baaa7ea9c7c3db Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sun, 2 Nov 2014 18:22:59 -0500 Subject: Fix view title --- app/layout/nav_menu.phtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml index 775daf088..dd7cbea30 100644 --- a/app/layout/nav_menu.phtml +++ b/app/layout/nav_menu.phtml @@ -139,7 +139,7 @@ - + -- cgit v1.2.3 From ba7d63e5cac1c98e28dc831112bc21dbd76aebbb Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Tue, 4 Nov 2014 08:47:23 +0100 Subject: Temporarily remove scheme check in referer If needed, we may re-introduce the check for scheme with proper support for proxy https://github.com/FreshRSS/FreshRSS/issues/565#issuecomment-61602425 --- lib/lib_rss.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/lib_rss.php b/lib/lib_rss.php index e7ca95aba..8170c7fd9 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -242,11 +242,14 @@ function is_referer_from_same_domain() { $host = parse_url(((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') ? 'https://' : 'http://') . (empty($_SERVER['HTTP_HOST']) ? $_SERVER['SERVER_NAME'] : $_SERVER['HTTP_HOST'])); $referer = parse_url($_SERVER['HTTP_REFERER']); - if (empty($host['scheme']) || empty($referer['scheme']) || $host['scheme'] !== $referer['scheme'] || - empty($host['host']) || empty($referer['host']) || $host['host'] !== $referer['host']) { + if (empty($host['host']) || empty($referer['host']) || $host['host'] !== $referer['host']) { return false; } - return (isset($host['port']) ? $host['port'] : 0) === (isset($referer['port']) ? $referer['port'] : 0); + //TODO: check 'scheme', taking into account the case of a proxy + if ((isset($host['port']) ? $host['port'] : 0) !== (isset($referer['port']) ? $referer['port'] : 0)) { + return false; + } + return true; } -- cgit v1.2.3 From 0b7af8f8719f698b67e31b5a84fa19b0f20c0590 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 31 Oct 2014 17:21:35 +0100 Subject: Fix bug on archiving page Introduced by https://github.com/FreshRSS/FreshRSS/commit/ee5bbe48269a2fd5bc9c175fdb1e5a92a2c04502 --- app/Controllers/configureController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index 1c8ac9111..f8d9b47c3 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -222,7 +222,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { Minz_View::prependTitle(_t('archiving_configuration') . ' · '); - $entryDAO = FreshRSS_Factory::createEntryDao('freshrss'); + $entryDAO = FreshRSS_Factory::createEntryDao(); $this->view->nb_total = $entryDAO->count(); $this->view->size_user = $entryDAO->size(); -- cgit v1.2.3 From 38cf7a109ee80cc03edfd420b641676ecd1dfae6 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sat, 8 Nov 2014 09:26:01 -0500 Subject: Add more info in article repartition page I added the same information than on the main stat page (total, read, unread and favorite) on the repartition page. Some refactoring was needed. --- app/Controllers/statsController.php | 1 + app/Models/StatsDAO.php | 48 ++++++++++++++++++++----------------- app/views/stats/repartition.phtml | 17 +++++++++++++ 3 files changed, 44 insertions(+), 22 deletions(-) diff --git a/app/Controllers/statsController.php b/app/Controllers/statsController.php index 18fbca6df..578df9434 100644 --- a/app/Controllers/statsController.php +++ b/app/Controllers/statsController.php @@ -117,6 +117,7 @@ class FreshRSS_stats_Controller extends Minz_ActionController { $this->view->feed = $feedDAO->searchById($id); $this->view->days = $statsDAO->getDays(); $this->view->months = $statsDAO->getMonths(); + $this->view->repartition = $statsDAO->calculateEntryRepartitionPerFeed($id); $this->view->repartitionHour = $statsDAO->calculateEntryRepartitionPerFeedPerHour($id); $this->view->averageHour = $statsDAO->calculateEntryAveragePerFeedPerHour($id); $this->view->repartitionDayOfWeek = $statsDAO->calculateEntryRepartitionPerFeedPerDayOfWeek($id); diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 283d5dcb1..0ca251228 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -6,18 +6,36 @@ class FreshRSS_StatsDAO extends Minz_ModelPdo { /** * Calculates entry repartition for all feeds and for main stream. + * + * @return array + */ + public function calculateEntryRepartition() { + return array( + 'main_stream' => $this->calculateEntryRepartitionPerFeed(null, true), + 'all_feeds' => $this->calculateEntryRepartitionPerFeed(null, false), + ); + } + + /** + * Calculates entry repartition for the selection. * The repartition includes: * - total entries * - read entries * - unread entries * - favorite entries * - * @return type + * @param null|integer $feed feed id + * @param boolean $only_main + * @return array */ - public function calculateEntryRepartition() { - $repartition = array(); - - // Generates the repartition for the main stream of entry + public function calculateEntryRepartitionPerFeed($feed = null, $only_main = false) { + $filter = ''; + if ($only_main) { + $filter .= 'AND f.priority = 10'; + } + if (!is_null($feed)) { + $filter .= "AND e.id_feed = {$feed}"; + } $sql = <<prefix}entry AS e , {$this->prefix}feed AS f WHERE e.id_feed = f.id -AND f.priority = 10 -SQL; - $stm = $this->bd->prepare($sql); - $stm->execute(); - $res = $stm->fetchAll(PDO::FETCH_ASSOC); - $repartition['main_stream'] = $res[0]; - - // Generates the repartition for all entries - $sql = <<prefix}entry AS e +{$filter} SQL; $stm = $this->bd->prepare($sql); $stm->execute(); $res = $stm->fetchAll(PDO::FETCH_ASSOC); - $repartition['all_feeds'] = $res[0]; - return $repartition; + return $res[0]; } /** @@ -179,7 +183,7 @@ SQL; * @return integer */ public function calculateEntryAveragePerFeedPerHour($feed = null) { - return $this->calculateEntryAveragePerFeedPerPeriod(1/24, $feed); + return $this->calculateEntryAveragePerFeedPerPeriod(1 / 24, $feed); } /** diff --git a/app/views/stats/repartition.phtml b/app/views/stats/repartition.phtml index 32268a546..85a750bd0 100644 --- a/app/views/stats/repartition.phtml +++ b/app/views/stats/repartition.phtml @@ -29,6 +29,23 @@ +
    + + + + + + + + + + + + + +
    repartition['total']; ?>repartition['read']; ?>repartition['unread']; ?>repartition['favorite']; ?>
    +
    +

    averageHour); ?>

    -- cgit v1.2.3 From 960abfcc6558d8421423a42b7781184dad0d9bc7 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sat, 8 Nov 2014 09:29:51 -0500 Subject: Refactor some if statements --- app/Models/StatsDAO.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php index 0ca251228..255a2b1ff 100644 --- a/app/Models/StatsDAO.php +++ b/app/Models/StatsDAO.php @@ -151,10 +151,9 @@ SQL; * @return string */ protected function calculateEntryRepartitionPerFeedPerPeriod($period, $feed = null) { + $restrict = ''; if ($feed) { $restrict = "WHERE e.id_feed = {$feed}"; - } else { - $restrict = ''; } $sql = << Date: Sat, 8 Nov 2014 10:04:43 -0500 Subject: Small format fix --- app/views/stats/repartition.phtml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/stats/repartition.phtml b/app/views/stats/repartition.phtml index 85a750bd0..4ea71cfb5 100644 --- a/app/views/stats/repartition.phtml +++ b/app/views/stats/repartition.phtml @@ -38,10 +38,10 @@ - repartition['total']; ?> - repartition['read']; ?> - repartition['unread']; ?> - repartition['favorite']; ?> + repartition['total']; ?> + repartition['read']; ?> + repartition['unread']; ?> + repartition['favorite']; ?>
    -- cgit v1.2.3 From 56ac35095a6923661453916c472e117643cdea84 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 12 Nov 2014 22:23:59 +0100 Subject: Better error message for inaccessible feeds https://github.com/FreshRSS/FreshRSS/issues/456 --- lib/SimplePie/SimplePie.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/SimplePie/SimplePie.php b/lib/SimplePie/SimplePie.php index 84001dd9a..dc4bbb6cb 100644 --- a/lib/SimplePie/SimplePie.php +++ b/lib/SimplePie/SimplePie.php @@ -1582,13 +1582,15 @@ class SimplePie if (!$locate->is_feed($file)) { + $copyStatusCode = $file->status_code; //FreshRSS + $copyContentType = $file->headers['content-type']; //FreshRSS // We need to unset this so that if SimplePie::set_file() has been called that object is untouched unset($file); try { if (!($file = $locate->find($this->autodiscovery, $this->all_discovered_feeds))) { - $this->error = "A feed could not be found at $this->feed_url. A feed with an invalid mime type may fall victim to this error, or " . SIMPLEPIE_NAME . " was unable to auto-discover it.. Use force_feed() if you are certain this URL is a real feed."; + $this->error = "A feed could not be found at `$this->feed_url`; the status code is `$copyStatusCode` and content-type is `$copyContentType`"; //FreshRSS $this->registry->call('Misc', 'error', array($this->error, E_USER_NOTICE, __FILE__, __LINE__)); return false; } -- cgit v1.2.3 From e4ea629f590192faf19a9cbdf33d400fdd6d5569 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 12 Nov 2014 22:42:47 +0100 Subject: SimplePie: Added unconventional mime type for RSS Since `application/rss+xml` is not official http://www.iana.org/assignments/media-types/media-types.xhtml, then it is fair enough to use the `x-` prefix. https://github.com/FreshRSS/FreshRSS/issues/706 --- lib/SimplePie/SimplePie/Locator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/SimplePie/SimplePie/Locator.php b/lib/SimplePie/SimplePie/Locator.php index 90ee7a302..4e5f7c1ca 100644 --- a/lib/SimplePie/SimplePie/Locator.php +++ b/lib/SimplePie/SimplePie/Locator.php @@ -148,7 +148,7 @@ class SimplePie_Locator { $sniffer = $this->registry->create('Content_Type_Sniffer', array($file)); $sniffed = $sniffer->get_type(); - if (in_array($sniffed, array('application/rss+xml', 'application/rdf+xml', 'text/rdf', 'application/atom+xml', 'text/xml', 'application/xml'))) + if (in_array($sniffed, array('application/rss+xml', 'application/rdf+xml', 'text/rdf', 'application/atom+xml', 'text/xml', 'application/xml', 'application/x-rss+xml'))) //FreshRSS { return true; } -- cgit v1.2.3 From a235f003bd5b78f2c94ccbbe56614f5828918962 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 12 Nov 2014 22:58:33 +0100 Subject: Better log in case of nonce errors https://github.com/FreshRSS/FreshRSS/issues/676 --- app/Controllers/javascriptController.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/Controllers/javascriptController.php b/app/Controllers/javascriptController.php index 62f413989..113f58ea9 100755 --- a/app/Controllers/javascriptController.php +++ b/app/Controllers/javascriptController.php @@ -39,6 +39,8 @@ class FreshRSS_javascript_Controller extends Minz_ActionController { } catch (Minz_Exception $me) { Minz_Log::warning('Nonce failure: ' . $me->getMessage()); } + } else { + Minz_Log::notice('Nonce failure due to invalid username!'); } $this->view->nonce = ''; //Failure $this->view->salt1 = ''; -- cgit v1.2.3 From 764946814f2b9af2022925d3edd185f9874c5357 Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 12 Nov 2014 23:28:47 +0100 Subject: force_feed option By adding #force_feed at the end of the URL of a feed sent with a wrong content-type (mime) https://github.com/FreshRSS/FreshRSS/issues/456 --- app/Models/Feed.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/Models/Feed.php b/app/Models/Feed.php index bd1babeea..8f4b60097 100644 --- a/app/Models/Feed.php +++ b/app/Models/Feed.php @@ -210,6 +210,10 @@ class FreshRSS_Feed extends Minz_Model { $url = preg_replace('#((.+)://)(.+)#', '${1}' . $this->httpAuth . '@${3}', $url); } $feed = customSimplePie(); + if (substr($url, -11) === '#force_feed') { + $feed->force_feed(true); + $url = substr($url, 0, -11); + } $feed->set_feed_url($url); if (!$loadDetails) { //Only activates auto-discovery when adding a new feed $feed->set_autodiscovery_level(SIMPLEPIE_LOCATOR_NONE); @@ -226,7 +230,7 @@ class FreshRSS_Feed extends Minz_Model { $subscribe_url = $feed->subscribe_url(false); $title = strtr(html_only_entity_decode($feed->get_title()), array('<' => '<', '>' => '>', '"' => '"')); //HTML to HTML-PRE //ENT_COMPAT except & - $this->_name($title == '' ? $this->url : $title); + $this->_name($title == '' ? $url : $title); $this->_website(html_only_entity_decode($feed->get_link())); $this->_description(html_only_entity_decode($feed->get_description())); @@ -235,7 +239,7 @@ class FreshRSS_Feed extends Minz_Model { $subscribe_url = $feed->subscribe_url(true); } - if ($subscribe_url !== null && $subscribe_url !== $this->url) { + if ($subscribe_url !== null && $subscribe_url !== $url) { if ($this->httpAuth != '') { // on enlève les id si authentification HTTP $subscribe_url = preg_replace('#((.+)://)((.+)@)(.+)#', '${1}${5}', $subscribe_url); -- cgit v1.2.3 From dab266a922be0d27536239d62e9dfef650666e9e Mon Sep 17 00:00:00 2001 From: Alexandre Alapetite Date: Wed, 12 Nov 2014 23:33:47 +0100 Subject: SimplePie changelog https://github.com/FreshRSS/FreshRSS/issues/456 https://github.com/FreshRSS/FreshRSS/issues/706 --- CHANGELOG | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index 1543847df..e09b55d21 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,13 @@ # Journal des modifications +## Dev + +* SimplePie + * Support for content-type application/x-rss+xml + * New force_feed option (for feeds sent with the wrong content-type / MIME) by adding #force_feed at the end of the feed URL + * Improved error messages + + ## 2014-10-31 FreshRSS 0.9.2 (beta) * UI -- cgit v1.2.3 From ec55aa94bfb30cdb0cd701785189215dfaf2094a Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sat, 15 Nov 2014 18:02:22 -0500 Subject: Theme selection redesign I made a CSS3 gallery to select the theme. Now you can see the theme before applying it. Comments are welcome. See #571 --- app/views/configure/display.phtml | 34 ++++++++---- p/themes/Dark/thumbs/original.png | Bin 0 -> 123928 bytes p/themes/Flat/thumbs/original.png | Bin 0 -> 133420 bytes p/themes/Origine/thumbs/original.png | Bin 0 -> 135886 bytes p/themes/Pafat/thumbs/original.png | Bin 0 -> 129220 bytes p/themes/Screwdriver/thumbs/original.png | Bin 0 -> 133107 bytes p/themes/base-theme/template.css | 92 +++++++++++++++++++++++++++++++ 7 files changed, 115 insertions(+), 11 deletions(-) create mode 100644 p/themes/Dark/thumbs/original.png create mode 100644 p/themes/Flat/thumbs/original.png create mode 100644 p/themes/Origine/thumbs/original.png create mode 100644 p/themes/Pafat/thumbs/original.png create mode 100644 p/themes/Screwdriver/thumbs/original.png diff --git a/app/views/configure/display.phtml b/app/views/configure/display.phtml index 69205fa93..39582249e 100644 --- a/app/views/configure/display.phtml +++ b/app/views/configure/display.phtml @@ -21,17 +21,29 @@
    - +
      + themes); $i = 1; ?> + themes as $theme) { ?> + theme === $theme['id']) {echo "checked";}?> value=""/> +
    • +
      + +
      + +
      + +
      +
    • + + +
    diff --git a/p/themes/Dark/thumbs/original.png b/p/themes/Dark/thumbs/original.png new file mode 100644 index 000000000..fd574319f Binary files /dev/null and b/p/themes/Dark/thumbs/original.png differ diff --git a/p/themes/Flat/thumbs/original.png b/p/themes/Flat/thumbs/original.png new file mode 100644 index 000000000..b9cafa9c8 Binary files /dev/null and b/p/themes/Flat/thumbs/original.png differ diff --git a/p/themes/Origine/thumbs/original.png b/p/themes/Origine/thumbs/original.png new file mode 100644 index 000000000..d26d4fbed Binary files /dev/null and b/p/themes/Origine/thumbs/original.png differ diff --git a/p/themes/Pafat/thumbs/original.png b/p/themes/Pafat/thumbs/original.png new file mode 100644 index 000000000..fe05f7260 Binary files /dev/null and b/p/themes/Pafat/thumbs/original.png differ diff --git a/p/themes/Screwdriver/thumbs/original.png b/p/themes/Screwdriver/thumbs/original.png new file mode 100644 index 000000000..ba9bacf90 Binary files /dev/null and b/p/themes/Screwdriver/thumbs/original.png differ diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index f696ac237..aab511fb9 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -683,6 +683,98 @@ br + br + br { left: 0; } +/*=== SLIDESHOW */ +/*==============*/ +.slides { + padding: 0; + height: 320px; + display: block; + position: relative; + min-width: 260px; + max-width: 640px; +} +.slides * { + user-select: none; + -ms-user-select: none; + -moz-user-select: none; + -khtml-user-select: none; + -webkit-user-select: none; + -webkit-touch-callout: none; +} +.slides input { + display: none; +} +.slide-container { + display: block; +} +.slide { + top: 0; + opacity: 0; + width: 100%; + height: 100%; + display: block; + position: absolute; + transform: scale(0); + transition: all .7s ease-in-out; +} +.slide img { + width: 100%; + height: 100%; +} +.nav label { + width: 10%; + height: 100%; + display: none; + position: absolute; + opacity: 0; + z-index: 9; + cursor: pointer; + transition: opacity .2s; + color: #FFF; + font-size: 1000%; + text-align: center; + line-height: 225%; + font-family: "Varela Round", sans-serif; + background-color: rgba(255, 255, 255, .3); + text-shadow: 0px 0px 15px rgb(119, 119, 119); + padding: 0; +} +.properties { + bottom: 15px; + display: none; + left: 15%; + padding: 5px; + position: absolute; + text-align: center; + width: 70%; + font-size: 15pt; + text-shadow: 0px 0px 15px rgb(119, 119, 119); + border-radius: 5px; + box-shadow: 5px 5px 10px; + border: 1px solid; + background-color: #fff; +} +.slide:hover + .nav label { + opacity: 0.5; +} +.slide:hover ~ .properties { + display: block; +} +.nav label:hover { + opacity: 1; +} +.nav .next { + right: 0; +} +input:checked + .slide-container .slide { + opacity: 1; + transform: scale(1); + transition: opacity 1s ease-in-out; +} +input:checked + .slide-container .nav label { + display: block; +} + /*=== DIVERS */ /*===========*/ .category .title:not([data-unread="0"]):after { -- cgit v1.2.3 From 91388c5b7602af44894e8283c18ca76b5b06ed43 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sun, 16 Nov 2014 08:55:19 -0500 Subject: Theme properties are more visible --- app/views/configure/display.phtml | 4 +++- p/themes/base-theme/template.css | 25 +++++++++++-------------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/app/views/configure/display.phtml b/app/views/configure/display.phtml index 39582249e..1c925a5ca 100644 --- a/app/views/configure/display.phtml +++ b/app/views/configure/display.phtml @@ -38,7 +38,9 @@
    - +
    +
    +
    diff --git a/p/themes/base-theme/template.css b/p/themes/base-theme/template.css index aab511fb9..80f76e80b 100644 --- a/p/themes/base-theme/template.css +++ b/p/themes/base-theme/template.css @@ -692,6 +692,7 @@ br + br + br { position: relative; min-width: 260px; max-width: 640px; + margin-bottom: 30px; } .slides * { user-select: none; @@ -740,26 +741,19 @@ br + br + br { padding: 0; } .properties { - bottom: 15px; + bottom: -35px; + position: absolute; + width: 100%; display: none; - left: 15%; - padding: 5px; +} +.properties .page-number { + right: 0; + top: 0; position: absolute; - text-align: center; - width: 70%; - font-size: 15pt; - text-shadow: 0px 0px 15px rgb(119, 119, 119); - border-radius: 5px; - box-shadow: 5px 5px 10px; - border: 1px solid; - background-color: #fff; } .slide:hover + .nav label { opacity: 0.5; } -.slide:hover ~ .properties { - display: block; -} .nav label:hover { opacity: 1; } @@ -774,6 +768,9 @@ input:checked + .slide-container .slide { input:checked + .slide-container .nav label { display: block; } +input:checked + .slide-container .properties { + display: block; +} /*=== DIVERS */ /*===========*/ -- cgit v1.2.3 From a3a77b09e96f66eec4e31e638b58c785cfb369a3 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sat, 22 Nov 2014 08:01:31 -0500 Subject: Add an automatic sticky post configuration Before, when the article while marked as read while scrolling and auto removed after reading, the display was in the middle of the following article. Now, the article is forced to be a sticky article so the user display is forced to be on top of the following article. --- app/Models/Context.php | 18 ++++++++++++++++++ app/views/helpers/javascript_vars.phtml | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/app/Models/Context.php b/app/Models/Context.php index cbd6a5888..3dc5349ad 100644 --- a/app/Models/Context.php +++ b/app/Models/Context.php @@ -287,4 +287,22 @@ class FreshRSS_Context { } return true; } + + /** + * Determine if the "sticky post" option is enabled. It can be enable + * by the user when it is selected in the configuration page or by the + * application when the context allows to auto-remove articles when they + * are read. + * + * @return boolean + */ + public static function isStickyPostEnabled() { + if (self::$conf->sticky_post) { + return true; + } + if (self::isAutoRemoveAvailable()) { + return true; + } + return false; + } } diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 6424d8d04..0961ac3fe 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -27,7 +27,7 @@ echo 'var context={', 'auto_load_more:', FreshRSS_Context::$conf->auto_load_more ? 'true' : 'false', ',', 'auto_actualize_feeds:', $auto_actualize ? 'true' : 'false', ',', 'does_lazyload:', FreshRSS_Context::$conf->lazyload ? 'true' : 'false', ',', - 'sticky_post:', FreshRSS_Context::$conf->sticky_post ? 'true' : 'false', ',', + 'sticky_post:', FreshRSS_Context::isStickyPostEnabled() ? 'true' : 'false', ',', 'html5_notif_timeout:', FreshRSS_Context::$conf->html5_notif_timeout, ',', 'auth_type:"', Minz_Configuration::authType(), '",', 'current_user_mail:', $mail ? ('"' . $mail . '"') : 'null', ',', -- cgit v1.2.3 From 7781add6dab45e890bb873e7fd42f83a6227e62c Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 24 Nov 2014 15:45:47 +0100 Subject: Update Screwdriver theme --- p/themes/Screwdriver/icons/favicon-16-32-48-64.ico | Bin 0 -> 1150 bytes p/themes/Screwdriver/icons/favicon-256.png | Bin 0 -> 15724 bytes p/themes/Screwdriver/icons/favicon.svg | 280 +++++++++++++++++++++ p/themes/Screwdriver/icons/icon.svg | 271 ++++++++++++++++++++ p/themes/Screwdriver/screwdriver.css | 105 ++++---- 5 files changed, 610 insertions(+), 46 deletions(-) create mode 100644 p/themes/Screwdriver/icons/favicon-16-32-48-64.ico create mode 100644 p/themes/Screwdriver/icons/favicon-256.png create mode 100644 p/themes/Screwdriver/icons/favicon.svg create mode 100644 p/themes/Screwdriver/icons/icon.svg diff --git a/p/themes/Screwdriver/icons/favicon-16-32-48-64.ico b/p/themes/Screwdriver/icons/favicon-16-32-48-64.ico new file mode 100644 index 000000000..7c5eb5517 Binary files /dev/null and b/p/themes/Screwdriver/icons/favicon-16-32-48-64.ico differ diff --git a/p/themes/Screwdriver/icons/favicon-256.png b/p/themes/Screwdriver/icons/favicon-256.png new file mode 100644 index 000000000..235b18c97 Binary files /dev/null and b/p/themes/Screwdriver/icons/favicon-256.png differ diff --git a/p/themes/Screwdriver/icons/favicon.svg b/p/themes/Screwdriver/icons/favicon.svg new file mode 100644 index 000000000..aaab5de99 --- /dev/null +++ b/p/themes/Screwdriver/icons/favicon.svg @@ -0,0 +1,280 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/p/themes/Screwdriver/icons/icon.svg b/p/themes/Screwdriver/icons/icon.svg new file mode 100644 index 000000000..7f3d76af2 --- /dev/null +++ b/p/themes/Screwdriver/icons/icon.svg @@ -0,0 +1,271 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/p/themes/Screwdriver/screwdriver.css b/p/themes/Screwdriver/screwdriver.css index b6c2e670e..8dbd2ec34 100644 --- a/p/themes/Screwdriver/screwdriver.css +++ b/p/themes/Screwdriver/screwdriver.css @@ -52,7 +52,7 @@ input, select, textarea { color: #222; line-height: 25px; vertical-align: middle; - box-shadow: 0 2px 2px #eee inset, 0 1px #fff; + box-shadow: 0 1px 2px #ccc inset, 0 1px #fff; } option { padding: 0 .5em; @@ -121,30 +121,14 @@ form th { } /*=== Buttons */ -form#add_rss .stick input, .dropdown-menu select{ - background:#393939; - box-shadow: 0 2px 2px #171717 inset,0 1px rgba(255,255,255,0.08); - border-left:solid 1px #171717; - border-top:solid 1px #171717; - border-bottom:solid 1px #171717; - border-right:none; + +.dropdown-menu .input select, .dropdown-menu .input input { + background:#444; color:#fff; + box-shadow:0 2px 2px #222 inset, 0px 1px rgba(255, 255, 255, 0.08); + border:solid 1px #171717; } -form#add_rss .stick .btn{ - background:linear-gradient(180deg, #222 0%, #171717 100%) #171717; - background: -webkit-linear-gradient(top, #222 0%, #171717 100%); - box-shadow:0 1px rgba(255,255,255,0.08), 0px 1px rgba(255, 255, 255, 0.08) inset; - border-right:solid 1px #171717; - border-top:solid 1px #171717; - border-bottom:solid 1px #171717; - border-left:none; -} -form#add_rss .stick .btn.dropdown-toggle{ - border-right:solid 1px #171717; - border-top:solid 1px #171717; - border-bottom:solid 1px #171717; - border-left:solid 1px #171717; -} + .stick { vertical-align: middle; font-size: 0; @@ -206,14 +190,13 @@ a.btn { background: linear-gradient(180deg, #EDE7DE 0%, #FFF 100%) #EDE7DE; background: -webkit-linear-gradient(top, #EDE7DE 0%, #FFF 100%); } -#loginButton.btn{ - border:none; - box-shadow: 0px 1px rgba(255, 255, 255, 0.08) inset,0 -1px #171717,0px 1px rgba(255, 255, 255, 0.08); -} + .nav_menu .btn.active, .nav_menu .btn:active, .nav_menu .dropdown-target:target ~ .btn.dropdown-toggle{ - box-shadow: 0px 2px #E2972A; - border-radius: 0; - background:transparent; + box-shadow: 0 1px #fff; + border-radius: 4px; + background: linear-gradient(180deg, #EDE7DE 0%, #F6F6F6 100%) #EDE7DE; + background: -webkit-linear-gradient(top, #EDE7DE 0%, #F6F6F6 100%); + border: solid 1px #ccc; } .nav_menu .btn { border: 0; @@ -500,7 +483,8 @@ a.btn { /*=== Boxes */ .box { background: #EDE7DE; - border-radius: 4px 4px 0 0; + border-radius: 4px; + box-shadow: 0 1px #fff; } .box .box-title { margin: 0; @@ -575,6 +559,7 @@ a.btn { .tree-folder-items > .item > a { text-decoration: none; color: #fff; + font-size: 0.92em; } .tree-folder-items > .item.active > a { } @@ -593,7 +578,8 @@ a.btn { text-align: center; } .header > .item.title .logo { - display: none; + height: 60px; + width: 60px; } .header > .item.title{ width: 250px; @@ -603,9 +589,9 @@ a.btn { } .header > .item.title h1 a { text-decoration: none; - font-size: 38px; - color:#ccc; - text-shadow: 0 1px #fff, 0 -1px rgba(162, 162, 162, 1); + font-size: 28px; + color:#222; + text-shadow: 0 1px #fff; } .header > .item.search input { width: 230px; @@ -681,11 +667,8 @@ a.btn { /*=== Prompt (centered) */ .prompt { text-align: center; - color: #FFF; - background: #222; padding: 14px 0px; - box-shadow: 0px -1px #FFF, 0px 1px #FFF, 0px 2px 2px #171717 inset, 0px -2px 2px #171717 inset; - text-shadow: 0 -1px #171717, 0 1px rgba(255,255,255,0.08); + text-shadow: 0 1px rgba(255,255,255,0.08); } .prompt label { text-align: left; @@ -702,9 +685,9 @@ a.btn { margin: 20px 0; } .prompt input#username,.prompt input#passwordPlain{ - border:none; - box-shadow: 0px 1px rgba(255, 255, 255, 0.08) inset,0 -1px #171717,0px 1px rgba(255, 255, 255, 0.08); - background:#EDE7DE; + border:solid 1px #ccc; + box-shadow: 0 4px -4px #ccc inset,0px 1px rgba(255, 255, 255, 0.08); + background:#fff; } .prompt input#username:focus,.prompt input#passwordPlain:focus{ border: solid 1px #E7AB34; @@ -734,7 +717,11 @@ a.btn { padding: 0 10px; font-style:italic; line-height: 3em; - background: #fff; + box-shadow: 0 1px #BDB7AE inset, 0 -1px rgba(255,255,255,0.28) inset; + background: linear-gradient(0deg, #EDE7DE 0%, #C2BCB3 100%) #EDE7DE; + background: -webkit-linear-gradient(bottom, #C2BCB3 0%, #FFF 100%); + color: #666; + text-shadow: 0 1px rgba(255,255,255,0.28); text-align: center; } #new-article + .day { @@ -748,10 +735,26 @@ a.btn { .nav_menu { background: #EDE7DE; border-bottom: 1px solid #ccc; - box-shadow:0 -1px #fff inset; + box-shadow:0 -1px rgba(255, 255, 255, 0.28) inset; text-align: center; padding: 5px 0; } +#panel >.nav_menu{ + background: linear-gradient(0deg, #EDE7DE 0%, #FFF 100%) #EDE7DE; + background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #FFF 100%); +} +#panel > .nav_menu > #nav_menu_read_all{ + background: linear-gradient(0deg, #EDE7DE 0%, #FFF 100%) #EDE7DE; + background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #FFF 100%); + border-radius: 4px; + border: 1px solid #CCC; + box-shadow: 0px 1px #FFF; +} +#panel > .nav_menu > #nav_menu_read_all > .dropdown > .btn.dropdown-toggle{ + border-radius: 0 4px 4px 0; + border:none; + border-left: solid 1px #ccc; +} /*=== Feed articles */ .flux_content { @@ -810,6 +813,7 @@ opacity: 1; border-top: 1px solid #ddd; font-size: 0.8rem; cursor: pointer; + box-shadow: 0 -1px rgba(255,255,255,0.28) inset; } .flux_header .title { font-size: 0.9rem; @@ -917,6 +921,7 @@ opacity: 1; text-shadow: 0 -1px 0 #aaa; color: #666; background: #EDE7DE; + box-shadow: 0 1px rgba(255,255,255,0.28)inset; } #bigMarkAsRead:hover { color: #000; @@ -956,9 +961,8 @@ opacity: 1; /*=== GLOBAL VIEW */ /*================*/ #stream.global { - background: #222; padding: 24px 0; - box-shadow: 0 1px #fff, 0 -2px 2px #171717 inset, 0 2px 2px #171717 inset; + box-shadow: 0px 8px 8px #C2BCB3 inset; } .box.category .box-title { @@ -1004,6 +1008,7 @@ opacity: 1; #panel { box-shadow: 0px 0px 4px #000; border-radius: 8px; + background:#EDE7DE; } /*=== DIVERS */ /*===========*/ @@ -1084,6 +1089,14 @@ opacity: 1; color: #eee; } +#slider.active { + box-shadow: -4px 0 4px rgba(15, 15, 15, 0.55); + background: #F8F8F8; +} +#close-slider.active { + background: rgba(15, 15, 15, 0.35); +} + /*=== MOBILE */ /*===========*/ @media screen and (max-width: 840px) { -- cgit v1.2.3 From b9b3e963b49b255dd694b001b303e75f58519b67 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 24 Nov 2014 15:49:13 +0100 Subject: Add BlueLagoon theme --- p/themes/BlueLagoon/BlueLagoon.css | 1210 +++++++++++++++++++++ p/themes/BlueLagoon/README.md | 38 + p/themes/BlueLagoon/icons/bookmark.svg | 61 ++ p/themes/BlueLagoon/icons/favicon-16-32-48-64.ico | Bin 0 -> 1150 bytes p/themes/BlueLagoon/icons/favicon-256.png | Bin 0 -> 16517 bytes p/themes/BlueLagoon/icons/favicon.svg | 273 +++++ p/themes/BlueLagoon/icons/icon.svg | 291 +++++ p/themes/BlueLagoon/icons/non-starred.svg | 59 + p/themes/BlueLagoon/icons/read.svg | 72 ++ p/themes/BlueLagoon/icons/starred.svg | 60 + p/themes/BlueLagoon/icons/unread.svg | 65 ++ p/themes/BlueLagoon/loader.gif | Bin 0 -> 3164 bytes p/themes/BlueLagoon/metadata.json | 7 + p/themes/BlueLagoon/template.css | 695 ++++++++++++ p/themes/BlueLagoon/thumbs/original.png | Bin 0 -> 153829 bytes 15 files changed, 2831 insertions(+) create mode 100644 p/themes/BlueLagoon/BlueLagoon.css create mode 100644 p/themes/BlueLagoon/README.md create mode 100644 p/themes/BlueLagoon/icons/bookmark.svg create mode 100644 p/themes/BlueLagoon/icons/favicon-16-32-48-64.ico create mode 100644 p/themes/BlueLagoon/icons/favicon-256.png create mode 100644 p/themes/BlueLagoon/icons/favicon.svg create mode 100644 p/themes/BlueLagoon/icons/icon.svg create mode 100644 p/themes/BlueLagoon/icons/non-starred.svg create mode 100644 p/themes/BlueLagoon/icons/read.svg create mode 100644 p/themes/BlueLagoon/icons/starred.svg create mode 100644 p/themes/BlueLagoon/icons/unread.svg create mode 100644 p/themes/BlueLagoon/loader.gif create mode 100644 p/themes/BlueLagoon/metadata.json create mode 100644 p/themes/BlueLagoon/template.css create mode 100644 p/themes/BlueLagoon/thumbs/original.png diff --git a/p/themes/BlueLagoon/BlueLagoon.css b/p/themes/BlueLagoon/BlueLagoon.css new file mode 100644 index 000000000..ae1c24604 --- /dev/null +++ b/p/themes/BlueLagoon/BlueLagoon.css @@ -0,0 +1,1210 @@ +@charset "UTF-8"; + +/*=== FONTS */ +@font-face { + font-family: "OpenSans"; + src: url("../fonts/openSans.woff") format("woff"); +} + +/*=== GENERAL */ +/*============*/ +html, body { + height: 100%; + font-family: "OpenSans", "Cantarell", "Helvetica", "Arial", sans-serif; + background: #fafafa; + font-size: 92%; +} + +/*=== Links */ +a, button.as-link { + color: #0062BE; + outline: none; +} + +/*=== Forms */ +.form-group{ + width: 100%; + float: left; + height: auto; + display: inline-block; +} +legend { + margin: 20px 0 5px; + padding: 5px 0; + border-bottom: 1px solid #ddd; + font-size: 1.4em; +} +label { + min-height: 25px; + padding: 5px 0; + cursor: pointer; +} +textarea { + width: 360px; + height: 100px; +} +input, select, textarea { + min-height: 25px; + padding: 5px; + background: #fff; + border: 1px solid #ccc; + border-radius: 3px; + color: #222; + line-height: 25px; + vertical-align: middle; + box-shadow: 0 1px 2px #ccc inset, 0 1px #fff; +} +option { + padding: 0 .5em; +} +input:focus, select:focus, textarea:focus { + color: #0F0F0F; + box-shadow: 0 0 3px #0062BF; + border: solid 1px #0062BF; +} +input:invalid, select:invalid { + border-color: #f00; + box-shadow: 0 0 2px 2px #fdd inset; +} +input:disabled, select:disabled { + background: #eee; +} +input.extend { + transition: width 200ms linear; + -moz-transition: width 200ms linear; + -webkit-transition: width 200ms linear; + -o-transition: width 200ms linear; + -ms-transition: width 200ms linear; +} + +/*=== Tables */ +table { + border-collapse: collapse; +} + +tr, th, td { + padding: 0.5em; + border: 1px solid #ddd; +} +th { + background: #f6f6f6; +} +form td, +form th { + font-weight: normal; + text-align: center; +} + +/*=== COMPONENTS */ +/*===============*/ +/*=== Forms */ +.form-group.form-actions { + padding: 5px 0; + background: #f4f4f4; + border-top: 1px solid #ddd; +} +.form-group.form-actions .btn { + margin: 0 10px; + border-radius: 4px; + box-shadow:0 1px rgba(255,255,255,0.08) inset; +} +.form-group .group-name { + padding: 10px 0; + text-align: right; +} +.form-group .group-controls { + min-height: 25px; + padding: 5px 0; +} +.form-group table { + margin: 10px 0 0 220px; +} + +/*=== Buttons */ + +.dropdown-menu .input select, .dropdown-menu .input input { + background:#444; + color:#fff; + box-shadow:0 2px 2px #222 inset, 0px 1px rgba(255, 255, 255, 0.08); + border:solid 1px #171717; +} + +.stick { + vertical-align: middle; + font-size: 0; +} +.stick input, +.stick .btn { + border-radius: 0; +} +.stick .btn:first-child,.stick input:first-child { + border-radius: 6px 0 0 6px; +} +.stick .btn-important:first-child { +} +.stick .btn:last-child, .stick input:last-child { + border-radius: 0 6px 6px 0; +} +.stick .btn + .btn, +.stick .btn + input, +.stick .btn + .dropdown > .btn, +.stick input + .btn, +.stick input + input, +.stick input + .dropdown > .btn, +.stick .dropdown + .btn, +.stick .dropdown + input, +.stick .dropdown + .dropdown > .btn { + border-left: none; +} +.stick .btn + .dropdown > .btn { + border-left: none; + border-radius: 0 3px 3px 0; +} + +.btn { + display: inline-block; + min-height: 37px; + min-width: 15px; + margin: 0; + padding: 5px 10px; + color:#222; + border: solid 1px #ccc; + border-radius: 4px; + background: linear-gradient(0deg, #EDE7DE 0%, #FFF 100%) #EDE7DE; + background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #FFF 100%); + text-shadow: 0px -1px rgba(255,255,255,0.08); + font-size: 0.9rem; + vertical-align: middle; + cursor: pointer; + overflow: hidden; +} +a.btn { + min-height: 25px; + line-height: 25px; +} +.btn:hover { + text-shadow: 0 0 2px #fff; + text-decoration:none; +} +.btn.active,.btn:active,.dropdown-target:target ~ .btn.dropdown-toggle { + background: linear-gradient(180deg, #EDE7DE 0%, #FFF 100%) #EDE7DE; + background: -webkit-linear-gradient(top, #EDE7DE 0%, #FFF 100%); +} + +.nav_menu .btn.active, .nav_menu .btn:active, .nav_menu .dropdown-target:target ~ .btn.dropdown-toggle{ + box-shadow: 0 1px #fff; + border-radius: 4px; + background: linear-gradient(180deg, #EDE7DE 0%, #F6F6F6 100%) #EDE7DE; + background: -webkit-linear-gradient(top, #EDE7DE 0%, #F6F6F6 100%); + border: solid 1px #ccc; +} +.nav_menu .btn { + border: 0; + background:transparent; +} + +.read_all { + color:#222; +} +.btn.dropdown-toggle[href="#dropdown-configure"]{ + background: linear-gradient(0deg, #EDE7DE 0%, #FFF 100%) #EDE7DE; + background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #FFF 100%); + border-radius: 4px; + border: solid 1px #ccc; + box-shadow: 0 1px #fff; +} +.btn.dropdown-toggle:active { + background:transparent; +} +.btn-important { + background: linear-gradient(180deg, #0090FF 0%, #0062BE 100%) #E4992C; + background: -webkit-linear-gradient(top, #0090FF 0%, #0062BE 100%); + color: #FFF; + box-shadow: 0 1px rgba(255,255,255,0.08) inset; + border-radius: 4px; + text-shadow: 0px -1px rgba(255,255,255,0.08); + font-weight: normal; +} +.btn-important:hover { +} +.btn-important:active { + background: linear-gradient(0deg, #E4992C 0%, #D18114 100%) #E4992C; + background: -webkit-linear-gradient(bottom, #E4992C 0%, #D18114 100%); +} + +.btn-attention { + background: #E95B57; + background: linear-gradient(to bottom, #E95B57, #BD362F); + background: -webkit-linear-gradient(top, #E95B57 0%, #BD362F 100%); + color: #fff; + border: 1px solid #C44742; + text-shadow: 0px -1px 0px #666; +} +.btn-attention:hover { + background: linear-gradient(to bottom, #D14641, #BD362F); + background: -webkit-linear-gradient(top, #D14641 0%, #BD362F 100%); +} +.btn-attention:active { + background: #BD362F; + box-shadow: none; +} +.btn[type="reset"]{ + color: #fff; + background:linear-gradient(180deg, #222 0%, #171717 100%) #171717; + background: -webkit-linear-gradient(top, #222 0%, #171717 100%); + box-shadow:0 -1px rgba(255,255,255,0.08) inset; +} +/*=== Navigation */ +.nav-list .nav-header, +.nav-list .item { + height: 2.5em; + line-height: 2.5em; + font-size: 0.9rem; +} +.nav-list .item:hover { + text-shadow: 0 0 2px rgba(255,255,255,0.28); + color:#fff; +} + +.nav-list .item.active { + background: linear-gradient(180deg, #0090FF 0%, #0062BE 100%) #E4992C; + background: -webkit-linear-gradient(top, #0090FF 0%, #0062BE 100%); + border-width: medium medium 1px; + border-style: none none solid; + border-color: -moz-use-text-color -moz-use-text-color #171717; + box-shadow: -1px 2px 2px #171717, 0px 1px rgba(255, 255, 255, 0.08) inset; + margin: 0; +} +.nav-list .item.active a { + color: #fff; +} +.nav-list .disable { + color: #aaa; + background: #fafafa; + text-align: center; +} +.nav-list .item > a { + padding: 0 10px; + color:#ccc; +} +.nav-list a:hover { + text-decoration: none; +} +.nav-list .item.empty a { + color: #f39c12; +} +.nav-list .item.active.empty a { + color: #fff; + background: linear-gradient(180deg, #E4992C 0%, #D18114 100%) #E4992C; + background: -webkit-linear-gradient(180deg, #E4992C 0%, #D18114 100%); +} +.nav-list .item.error a { + color: #BD362F; +} +.nav-list .item.active.error a { + color: #fff; + background: #BD362F; +} + +.nav-list .nav-header { + padding: 0 10px; + color: #222; + background: transparent; +} + +.nav-list .nav-form { + padding: 3px; + text-align: center; +} + +.nav-head { + margin: 0; + background: linear-gradient(0deg, #EDE7DE 0%, #FFF 100%) #EDE7DE; + background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #FFF 100%); + text-align: right; +} +.nav-head .item { + padding: 5px 10px; + font-size: 0.9rem; + line-height: 1.5rem; +} + +/*=== Horizontal-list */ +.horizontal-list { + margin: 0; + padding: 0; +} +.horizontal-list .item { + vertical-align: middle; +} + +/*=== Dropdown */ +.dropdown-menu { + margin: 5px 0 0; + padding: 5px 0; + border: 1px solid #171717; + border-radius: 4px; + box-shadow: 0 0 3px #000; + font-size: 0.8rem; + text-align: left; + background: #222; +} +.dropdown-menu:after { + content: ""; + position: absolute; + top: -6px; + right: 13px; + width: 10px; + height: 10px; + background: #222; + border-top: 1px solid #171717; + border-left: 1px solid #171717; + z-index: -10; + transform: rotate(45deg); + -moz-transform: rotate(45deg); + -webkit-transform: rotate(45deg); + -ms-transform: rotate(45deg); +} +.dropdown-header { + display:none; +} +.dropdown-menu > .item > a { + padding: 0 25px; + line-height: 2.5em; + color: #ccc; +} +.dropdown-menu > .item > span, +.dropdown-menu > .item > .as-link { + padding: 0 22px; + line-height: 2em; + color: #ccc; +} +.dropdown-menu > .item:hover { + background: linear-gradient(180deg, #0090FF 0%, #0062BE 100%) #E4992C; + background: -webkit-linear-gradient(top, #0090FF 0%, #0062BE 100%); + color: #fff; +} +.dropdown-menu > .item[aria-checked="true"] > a:before { + font-weight: bold; + margin: 0 0 0 -14px; +} +.dropdown-menu > .item:hover > a { + color: #fff; + text-decoration: none; +} +.dropdown-menu .input select, +.dropdown-menu .input input { + margin: 0 auto 5px; + padding: 2px 5px; + border-radius: 3px; +} + +.separator { + margin: 5px 0; + border-bottom: 1px solid #171717; + box-shadow: 0 1px rgba(255,255,255,0.08); +} + +/*=== Alerts */ +.alert { + margin: 15px auto; + padding: 10px 15px; + background: #f4f4f4; + border: 1px solid #ccc; + border-right: 1px solid #aaa; + border-bottom: 1px solid #aaa; + border-radius: 5px; + color: #aaa; + text-shadow: 0 0 1px #eee; + font-size: 0.9em; +} +.alert-head { + font-size: 1.15em; +} +.alert > a { + color: inherit; + text-decoration: underline; +} +.alert-warn { + background: #ffe; + border: 1px solid #eeb; + color: #c95; +} +.alert-success { + background: #dfd; + border: 1px solid #cec; + color: #484; +} +.alert-error { + background: #fdd; + border: 1px solid #ecc; + color: #844; +} + +/*=== Pagination */ +.pagination { + background: #fafafa; + text-align: center; + color: #333; + font-size: 0.8em; +} +.content .pagination { + margin: 0; + padding: 0; +} +.pagination .item.pager-current { + font-weight: bold; + font-size: 1.5em; +} +.pagination .item a { + display: block; + color: #333; + font-style: italic; + line-height: 3em; + text-decoration: none; +} +.pagination .item a:hover { + background: #ddd; +} +.pagination:first-child .item { + border-bottom: 1px solid #aaa; +} +.pagination:last-child .item { + border-top: 1px solid #ddd; +} + +.pagination .loading, +.pagination a:hover.loading { + background: url("loader.gif") center center no-repeat #fff; + font-size: 0; + height:55px +} + +/*=== Boxes */ +.box { + background: #F9F7F4; + border-radius: 4px; + box-shadow: 0 1px #fff; +} +.box .box-title { + margin: 0; + padding: 5px 10px; + background: linear-gradient(0deg, #EDE7DE 0%, #fff 100%) #171717; + background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #fff 100%); + box-shadow: 0px -1px #fff inset,0 -2px #ccc inset; + color: #888; + text-shadow: 0 1px #ccc; + border-radius: 4px 4px 0 0; + font-size: 1.1rem; + font-weight: normal; +} +.box .box-content { + max-height: 260px; +} + +.box .box-content .item { + padding: 0 10px; + font-size: 0.9rem; + line-height: 2.5em; +} + +.box .box-content .item .configure { + visibility: hidden; +} +.box .box-content .item:hover .configure { + visibility: visible; +} + +/*=== Tree */ +.tree { + margin: 10px 0; +} +.tree-folder-title { + position: relative; + padding: 0 10px; + line-height: 2.5rem; + font-size: 0.9rem; +} +.tree-folder-title .title { + background: inherit; + color: #fff; +} +.tree-folder-title .title:hover { + text-decoration: none; +} +.tree-folder.active .tree-folder-title { + background: linear-gradient(180deg, #222 0%, #171717 100%) #171717; + background: -webkit-linear-gradient(top, #222 0%, #171717 100%); + box-shadow: 0px 1px #171717, 0px 1px rgba(255, 255, 255, 0.08) inset; + text-shadow: 0 0 2px rgba(255,255,255,0.28); + color: #fff; +} +.tree-folder.active > .tree-folder-title > a.title{ + color: #0090FF; + text-shadow: 0 1px rgba(255,255,255,0.08); +} +.tree-folder-items { + background: #171717; + padding: 8px 0; + box-shadow: 0 4px 4px #171717 inset, 0 1px rgba(255,255,255,0.08),0 -1px rgba(255,255,255,0.08); +} +.tree-folder-items > .item { + padding: 0 10px; + line-height: 2.5rem; + font-size: 0.8rem; +} +.tree-folder-items > .item.active { + background: linear-gradient(180deg, #222 0%, #171717 100%) #171717; + background: -webkit-linear-gradient(top, #222 0%, #171717 100%); + border-radius: 4px; + margin: 0px 8px; + box-shadow: 0px 1px #171717, 0px 1px rgba(255, 255, 255, 0.08) inset, 0 2px 2px #111; +} +.tree-folder-items > .item > a { + text-decoration: none; + color: #fff; + font-size: 0.92em; +} +.tree-folder-items > .item.active > a { + color: #0090FF +} + +/*=== STRUCTURE */ +/*===============*/ +/*=== Header */ +.header { + height: 55px; + background: linear-gradient(0deg, #EDE7DE 0%, #FFF 100%) #EDE7DE; + background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #FFF 100%); + border-bottom: solid 1px #BDB7AE; + box-shadow: 0 -1px rgba(255,255,255,0.28) inset; +} +.header > .item { + padding: 0; + vertical-align: middle; + text-align: center; +} +.header > .item.title .logo { + height: 60px; + width: 60px; +} +.header > .item.title{ + width: 250px; +} +.header > .item.title h1 { + margin: 0.5em 0; +} +.header > .item.title h1 a { + text-decoration: none; + font-size: 28px; + color:#222; + text-shadow: 0 1px #fff; +} +.header > .item.search input { + width: 230px; +} +.header .item.search input:focus { + width: 350px; +} + +/*=== Body */ +#global { + background:#F9F7F4; + height: calc(100% - 60px); +} +.aside { + box-shadow: 0 2px 2px #171717 inset; + background: #222; + width: 235px; +} +.aside.aside_feed { + padding: 10px 0; + text-align: center; +} +.aside.aside_feed .tree { + position: sticky; + top: 0; + margin: 10px 0 50px; +} + +/*=== Aside main page (categories) */ +.aside_feed .tree-folder-title > .title:not([data-unread="0"]):after { + position: absolute; + right: 3px; + padding: 1px 5px; + color: #fff; + text-shadow: 0 1px rgba(255,255,255,0.08); +} +.aside_feed .btn-important { + border: none; +} + +/*=== Aside main page (feeds) */ +.feed.item.empty, +.feed.item.empty > a { + color: #e67e22; +} +.feed.item.error, +.feed.item.error > a { + color: #BD362F; +} +.aside_feed .tree-folder-items .dropdown-menu:after { + left: 2px; +} +.aside_feed .tree-folder-items .item .dropdown-target:target ~ .dropdown-toggle > .icon, +.aside_feed .tree-folder-items .item:hover .dropdown-toggle > .icon, +.aside_feed .tree-folder-items .item.active .dropdown-toggle > .icon { + border-radius: 3px; +} + +/*=== Configuration pages */ +.post { + padding: 10px 50px; + font-size: 0.9em; +} +.post form { + margin: 10px 0; +} +.post.content { + max-width: 550px; +} + +/*=== Prompt (centered) */ +.prompt { + text-align: center; + padding: 14px 0px; + text-shadow: 0 1px rgba(255,255,255,0.08); +} +.prompt label { + text-align: left; +} +.prompt form { + margin: 10px auto 20px auto; + width: 180px; +} +.prompt input { + margin: 5px auto; + width: 100%; +} +.prompt p { + margin: 20px 0; +} +.prompt input#username,.prompt input#passwordPlain{ + border:solid 1px #ccc; + box-shadow: 0 4px -4px #ccc inset,0px 1px rgba(255, 255, 255, 0.08); + background:#fff; +} +.prompt input#username:focus,.prompt input#passwordPlain:focus{ + border: solid 1px #0062BE; + box-shadow: 0 0 3px #0062BE; +} + +/*=== New article notification */ +#new-article { + background: #0084CC; + text-align: center; + font-size: 0.9em; +} +#new-article:hover { + background: #0066CC; +} +#new-article > a { + line-height: 3em; + color: #fff; + font-weight: bold; +} +#new-article > a:hover { + text-decoration: none; +} + +/*=== Day indication */ +.day { + padding: 0 10px; + font-style:italic; + line-height: 3em; + box-shadow: 0 -1px #ccc, 0 -1px rgba(255,255,255,0.28) inset; + background: #F9F7F4; + color: #666; + text-shadow: 0 1px rgba(255,255,255,0.28); + text-align: center; +} +#new-article + .day { + border-top: none; +} +.day .name { + display: none; +} + +/*=== Index menu */ +.nav_menu { + background: linear-gradient(0deg, #EDE7DE 0%, #C2BCB3 100%) #EDE7DE; + background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #C2BCB3 100%); + border-bottom: 1px solid #ccc; + box-shadow:0 -1px rgba(255, 255, 255, 0.28) inset; + text-align: center; + padding: 5px 0; +} +#panel >.nav_menu{ + background: linear-gradient(0deg, #EDE7DE 0%, #FFF 100%) #EDE7DE; + background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #FFF 100%); +} +#panel > .nav_menu > #nav_menu_read_all{ + background: linear-gradient(0deg, #EDE7DE 0%, #FFF 100%) #EDE7DE; + background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #FFF 100%); + border-radius: 4px; + border: 1px solid #CCC; + box-shadow: 0px 1px #FFF; +} +#panel > .nav_menu > #nav_menu_read_all > .dropdown > .btn.dropdown-toggle{ + border-radius: 0 4px 4px 0; + border:none; + border-left: solid 1px #ccc; +} + +/*=== Feed articles */ +.flux_content { + background: #FFF; +} +.flux { + background: #F9F7F4; +} +.flux:hover { + background: #F9F7F4; +} +.flux:not(.current):hover .item.title { + background: #F9F7F4; +} +.flux.current .flux .item.title a { + text-shadow:0 0 2px #ccc; +} +.flux.not_read:not(.current):hover .item.title { + opacity:0.85; +} +.flux.favorite { + background: #FFF6DA; +} +.flux.favorite:not(.current):hover{ + background: #F9F7F4; +} +.flux.favorite:not(.current):hover .item.title { + background: #F9F7F4; +} +.flux.current { + background: linear-gradient(0deg, #DAD4CB 0%, #FFF 100%) #DAD4CB; + background: -webkit-linear-gradient(bottom, #DAD4CB 0%, #FFF 100%); + box-shadow: 0 -1px #fff inset, 0 2px #ccc; + border-left: solid 4px #0062BF; +} + +.flux .item.title { +opacity: 0.35; +} +.flux.favorite .item.title { +opacity: 1; +} +.flux.not_read .item.title { +opacity: 1; +} +.flux.current .item.title a { + color: #0f0f0f; +} +.flux .item.title a { + color: #333; +} + +.flux_header { + border-top: 1px solid #ddd; + font-size: 0.8rem; + cursor: pointer; + box-shadow: 0 -1px rgba(255,255,255,0.28) inset; +} +.flux_header .title { + font-size: 0.9rem; +} +.flux .website .favicon { + padding: 5px; +} +.flux .date { + color: #666; + font-size: 0.7rem; +} + +.flux .bottom { + font-size: 0.8rem; + text-align: center; +} + +/*=== Content of feed articles */ +.content { + padding: 20px 10px; +} +.content > h1.title > a { + color: #000; +} + +.content hr { + margin: 30px 10px; + height: 1px; + background: #ddd; + border: 0; + box-shadow: 0 2px 5px #ccc; +} + +.content pre { + margin: 10px auto; + padding: 10px 20px; + overflow: auto; + background: #222; + color: #fff; + font-size: 0.9rem; + border-radius: 3px; +} +.content code { + padding: 2px 5px; + color: #dd1144; + background: #fafafa; + border: 1px solid #eee; + border-radius: 3px; +} +.content pre code { + background: transparent; + color: #fff; + border: none; +} + +.content blockquote { + display: block; + margin: 0; + padding: 5px 20px; + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + background: #fafafa; + color: #333; +} +.content blockquote p { + margin: 0; +} + +/*=== Notification and actualize notification */ +.notification { + padding: 0 0 0 5px; + text-align: center; + background:#222; + border: none; + border-radius: 0 0 6px 6px; + box-shadow: 0px 0px 4px rgba(0,0,0,0.45), 0 -1px rgba(255,255,255,0.08) inset, 0 2px 2px #171717 inset; + color:#fff; + font-weight: bold; + font-size: 0.9em; + line-height: 3em; + position:absolute; + top:0; + z-index: 10; + vertical-align: middle; +} +.notification.good { + color: #fff; +} +.notification.bad { + background: #222222; + color: #EB2901; +} +.notification a.close { + padding: 0 15px; + line-height: 3em; +} +.notification#actualizeProgress { + line-height: 2em; +} + +/*=== "Load more" part */ +#bigMarkAsRead { + text-align: center; + text-decoration: none; + text-shadow: 0 -1px 0 #aaa; + color: #666; + background: #F9F7F4; + box-shadow: 0 1px rgba(255,255,255,0.28)inset; +} +#bigMarkAsRead:hover { + color: #000; + background: #F9F7F4; + background: radial-gradient(circle at 50% -25% , #ccc 0%, #F9F7F4 50%); +} +#bigMarkAsRead:hover .bigTick { + text-shadow: 0 0 10px #666; +} + +/*=== Navigation menu (for articles) */ +#nav_entries { + background: linear-gradient(180deg, #222 0%, #171717 100%) #222; + background: -webkit-linear-gradient(top, #222 0%, #171717 100%); + border-top: 1px solid #171717; + text-align: center; + line-height: 3em; + table-layout: fixed; + box-shadow: 0 1px rgba(255,255,255,0.08) inset, 0 -2px 2px #171717; + width:235px; +} + +/*=== READER VIEW */ +/*================*/ +#stream.reader .flux { + padding: 0 0 50px; + border: none; + background: #f0f0f0; + color: #333; +} +#stream.reader .flux .author { + margin: 0 0 10px; + font-size: 90%; + color: #666; +} + +/*=== GLOBAL VIEW */ +/*================*/ +#stream.global { + padding: 24px 0; +} + +.box.category .box-title { + background: linear-gradient(0deg, #EDE7DE 0%, #fff 100%) #171717; + background: -webkit-linear-gradient(bottom, #EDE7DE 0%, #fff 100%); + box-shadow: 0px -1px #fff inset,0 -2px #ccc inset; + border-radius: none; + line-height: 2em; + font-size: 1.2rem; + text-shadow:0 1px #ccc; +} +.box.category .box-title .title { + font-weight: normal; + text-decoration: none; + text-align: left; + color: #888; +} +.box.category:not([data-unread="0"]) .box-title { +} +.box.category:not([data-unread="0"]) .box-title:active { +} +.box.category:not([data-unread="0"]) .box-title .title { + color: #222; + font-weight: bold; +} +.box.category .title:not([data-unread="0"]):after { + position: absolute; + top: 5px; right: 10px; + border: 0; + background: none; + font-weight: bold; +} +.box.category .item.feed { + padding: 2px 10px; + font-size: 0.8rem; +} +.box.category .item.feed:not(.empty):not(.error) .item-title { + color: #222; +} + +/*=== PANEL */ +/*===========*/ +#panel { + box-shadow: 0px 0px 4px #000; + border-radius: 8px; + background:#F9F7F4; +} +/*=== DIVERS */ +/*===========*/ +.aside.aside_feed .nav-form input,.aside.aside_feed .nav-form select { + width: 130px; +} +.aside.aside_feed .nav-form .dropdown .dropdown-menu { + right: -20px; +} +.aside.aside_feed .nav-form .dropdown .dropdown-menu:after { + right: 33px; +} + +/*=== STATISTICS */ +/*===============*/ +.stat { + margin: 10px 0 20px; +} + +.stat th, +.stat td, +.stat tr { + border: none; +} +.stat > table td, +.stat > table th { + border-bottom: 1px solid #ccc; + background: rgba(255,255,255,0.38); + box-shadow: 0 1px #fff; +} + +.stat > .horizontal-list { + margin: 0 0 5px; +} +.stat > .horizontal-list .item { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.stat > .horizontal-list .item:first-child { + width: 250px; +} + +/*=== LOGS */ +/*=========*/ +.logs { + border: 1px solid #aaa; + border-radius: 5px; + overflow: hidden; +} +.log { + padding: 5px 10px; + background: #fafafa; + color: #333; + font-size: 0.8rem; +} +.log+.log { + border-top: 1px solid #aaa; +} +.log .date { + display: block; + font-weight: bold; +} +.log.error { + background: #fdd; + color: #844; +} +.log.warning { + background: #ffe; + color: #c95; +} +.log.notice { + background: #f4f4f4; + color: #aaa; +} +.log.debug { + background: #333; + color: #eee; +} + +#slider.active { + box-shadow: -4px 0 4px rgba(15, 15, 15, 0.55); + background: #F8F8F8; +} +#close-slider.active { + background: rgba(15, 15, 15, 0.35); +} + +/*=== MOBILE */ +/*===========*/ +@media screen and (max-width: 840px) { + .header { + display: table; + } + .nav-login { + display: none; + } + + .aside { + width: 0; + border-top: none; + box-shadow: 3px 0 3px #000; + transition: width 200ms linear; + -moz-transition: width 200ms linear; + -webkit-transition: width 200ms linear; + -o-transition: width 200ms linear; + -ms-transition: width 200ms linear; + } + .aside:target { + width: 235px; + } + .aside .toggle_aside, + #panel .close { + display: block; + width: 100%; + height: 40px; + line-height: 40px; + text-align: center; + background: #171717; + box-shadow: 0 1px rgba(255,255,255,0.08); + } + .aside .btn-important { + display: inline-block; + margin: 20px 0 0; + } + + .aside.aside_feed { + padding: 0; + } + .aside.aside_feed .tree { + position: static; + } + + .nav_menu .btn { + margin: 5px 10px; + } + .nav_menu .stick { + margin: 0 10px; + } + .nav_menu .stick .btn { + margin: 5px 0; + } + .nav_menu .search { + display: inline-block; + max-width: 97%; + } + .nav_menu .search input { + max-width: 97%; + width: 90px; + } + .nav_menu .search input:focus { + width: 400px; + } + + .day .name { + display: none; + } + + .pagination { + margin: 0 0 3.5em; + } + + .notification a.close { + display: block; + left: 0; + background: transparent; + } + .notification a.close:hover { + opacity: 0.5; + } + .notification a.close .icon { + display: none; + } + .nav_menu .search { + display: none; + } + + #nav_entries { + width: 100%; + } +} + +@media (max-width: 700px) { + .header{ + display: none; + } + .nav-login { + display: inline-block; + width: 100%; + } + .nav_menu .search { + display: inline-block; + } + .aside .btn-important { + display: none; + } +} diff --git a/p/themes/BlueLagoon/README.md b/p/themes/BlueLagoon/README.md new file mode 100644 index 000000000..62afc234b --- /dev/null +++ b/p/themes/BlueLagoon/README.md @@ -0,0 +1,38 @@ +Blue Lagoon +======= + +**C'est un cocktail (bis)! C'est la version plus "fresh" de [Screwdriver](https://github.com/misterair/Screwdriver). C'est... c'est... un thème pour l'agrégateur de flux RSS [FreshRSS](https://github.com/marienfressinaud/FreshRSS/)** + + +En toute modestie, ce thème tue du Nyan Cat. + +![screenshot](https://raw.githubusercontent.com/misterair/BlueLagoon/master/screenshot.png) + + +Installation +----------------- +1. Placez le dossier du thème dans ledossier /FreshRSS/p/themes/Screwdriver de votre FreshRSS; +2. Allez dans les paramètres d'Affichage et changez de thème; +3. Profitez de votre Blue Laggon sans modération! +4. Remontez les problèmes sur Github (*facultatif mais fortement apprécié*) + + + +Blue Lagoon est distribué sous license AlcoholWare: +----------------- + +« LICENCE ALCOHOLWARE » (Révision 42): + +mister.air@gmail.com a créé ce fichier. Tant que vous conservez cet avertissement, + +vous pouvez faire ce que vous voulez de ce truc. Si on se rencontre un jour et + +que vous pensez que ce truc vaut le coup, vous pouvez me payer un verre (rempli) en retour. + +*Mister aiR* + + + + + + diff --git a/p/themes/BlueLagoon/icons/bookmark.svg b/p/themes/BlueLagoon/icons/bookmark.svg new file mode 100644 index 000000000..b77dc5518 --- /dev/null +++ b/p/themes/BlueLagoon/icons/bookmark.svg @@ -0,0 +1,61 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/p/themes/BlueLagoon/icons/favicon-16-32-48-64.ico b/p/themes/BlueLagoon/icons/favicon-16-32-48-64.ico new file mode 100644 index 000000000..7c5eb5517 Binary files /dev/null and b/p/themes/BlueLagoon/icons/favicon-16-32-48-64.ico differ diff --git a/p/themes/BlueLagoon/icons/favicon-256.png b/p/themes/BlueLagoon/icons/favicon-256.png new file mode 100644 index 000000000..dbe4ec4b7 Binary files /dev/null and b/p/themes/BlueLagoon/icons/favicon-256.png differ diff --git a/p/themes/BlueLagoon/icons/favicon.svg b/p/themes/BlueLagoon/icons/favicon.svg new file mode 100644 index 000000000..ac816d68c --- /dev/null +++ b/p/themes/BlueLagoon/icons/favicon.svg @@ -0,0 +1,273 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/p/themes/BlueLagoon/icons/icon.svg b/p/themes/BlueLagoon/icons/icon.svg new file mode 100644 index 000000000..083eeb685 --- /dev/null +++ b/p/themes/BlueLagoon/icons/icon.svg @@ -0,0 +1,291 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/p/themes/BlueLagoon/icons/non-starred.svg b/p/themes/BlueLagoon/icons/non-starred.svg new file mode 100644 index 000000000..2762b060a --- /dev/null +++ b/p/themes/BlueLagoon/icons/non-starred.svg @@ -0,0 +1,59 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/p/themes/BlueLagoon/icons/read.svg b/p/themes/BlueLagoon/icons/read.svg new file mode 100644 index 000000000..28980576b --- /dev/null +++ b/p/themes/BlueLagoon/icons/read.svg @@ -0,0 +1,72 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/p/themes/BlueLagoon/icons/starred.svg b/p/themes/BlueLagoon/icons/starred.svg new file mode 100644 index 000000000..4c749ce26 --- /dev/null +++ b/p/themes/BlueLagoon/icons/starred.svg @@ -0,0 +1,60 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/p/themes/BlueLagoon/icons/unread.svg b/p/themes/BlueLagoon/icons/unread.svg new file mode 100644 index 000000000..596dec0ac --- /dev/null +++ b/p/themes/BlueLagoon/icons/unread.svg @@ -0,0 +1,65 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/p/themes/BlueLagoon/loader.gif b/p/themes/BlueLagoon/loader.gif new file mode 100644 index 000000000..a0839dcc7 Binary files /dev/null and b/p/themes/BlueLagoon/loader.gif differ diff --git a/p/themes/BlueLagoon/metadata.json b/p/themes/BlueLagoon/metadata.json new file mode 100644 index 000000000..2c415a613 --- /dev/null +++ b/p/themes/BlueLagoon/metadata.json @@ -0,0 +1,7 @@ +{ + "name": "Blue Lagoon", + "author": "Mister aiR", + "description": "C'est un cocktail (bis)! C'est la version plus fresh de Screwdriver. C'est... c'est... un thème pour l'agrégateur de flux RSS FreshRSS. En toute modestie, ce thème tue du Nyan Cat.", + "version": 1.0, + "files": ["_template.css","BlueLagoon.css"] +} diff --git a/p/themes/BlueLagoon/template.css b/p/themes/BlueLagoon/template.css new file mode 100644 index 000000000..bf421e322 --- /dev/null +++ b/p/themes/BlueLagoon/template.css @@ -0,0 +1,695 @@ +@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; +} +.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/BlueLagoon/thumbs/original.png b/p/themes/BlueLagoon/thumbs/original.png new file mode 100644 index 000000000..bb8695945 Binary files /dev/null and b/p/themes/BlueLagoon/thumbs/original.png differ -- cgit v1.2.3 From 498f8315f724a5e85b28907c3bc4dc08699d679e Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Wed, 26 Nov 2014 17:54:41 -0500 Subject: Optimize bluelagoon theme icons. In the future, we should pay attention to those icons since I've done that a couple of time now. We should have some documentation for new contributions. --- p/themes/BlueLagoon/icons/bookmark.svg | 64 +----- p/themes/BlueLagoon/icons/favicon.svg | 303 +++------------------------- p/themes/BlueLagoon/icons/icon.svg | 321 +++--------------------------- p/themes/BlueLagoon/icons/non-starred.svg | 62 +----- p/themes/BlueLagoon/icons/read.svg | 74 +------ p/themes/BlueLagoon/icons/starred.svg | 63 +----- p/themes/BlueLagoon/icons/unread.svg | 66 +----- 7 files changed, 80 insertions(+), 873 deletions(-) diff --git a/p/themes/BlueLagoon/icons/bookmark.svg b/p/themes/BlueLagoon/icons/bookmark.svg index b77dc5518..7f33d9753 100644 --- a/p/themes/BlueLagoon/icons/bookmark.svg +++ b/p/themes/BlueLagoon/icons/bookmark.svg @@ -1,61 +1,5 @@ - - - - - - image/svg+xml - - - - - - - - - + + + + diff --git a/p/themes/BlueLagoon/icons/favicon.svg b/p/themes/BlueLagoon/icons/favicon.svg index ac816d68c..1b6801a26 100644 --- a/p/themes/BlueLagoon/icons/favicon.svg +++ b/p/themes/BlueLagoon/icons/favicon.svg @@ -1,273 +1,32 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/p/themes/BlueLagoon/icons/icon.svg b/p/themes/BlueLagoon/icons/icon.svg index 083eeb685..8abfea179 100644 --- a/p/themes/BlueLagoon/icons/icon.svg +++ b/p/themes/BlueLagoon/icons/icon.svg @@ -1,291 +1,34 @@ - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/p/themes/BlueLagoon/icons/non-starred.svg b/p/themes/BlueLagoon/icons/non-starred.svg index 2762b060a..d5c1f5ee0 100644 --- a/p/themes/BlueLagoon/icons/non-starred.svg +++ b/p/themes/BlueLagoon/icons/non-starred.svg @@ -1,59 +1,5 @@ - - - - - - image/svg+xml - - - - - - - - - + + + + diff --git a/p/themes/BlueLagoon/icons/read.svg b/p/themes/BlueLagoon/icons/read.svg index 28980576b..269b75738 100644 --- a/p/themes/BlueLagoon/icons/read.svg +++ b/p/themes/BlueLagoon/icons/read.svg @@ -1,72 +1,4 @@ - - - - - - image/svg+xml - - - - - - - - - - - + + + diff --git a/p/themes/BlueLagoon/icons/starred.svg b/p/themes/BlueLagoon/icons/starred.svg index 4c749ce26..10a16f04a 100644 --- a/p/themes/BlueLagoon/icons/starred.svg +++ b/p/themes/BlueLagoon/icons/starred.svg @@ -1,60 +1,5 @@ - - - - - - image/svg+xml - - - - - - - - - + + + + diff --git a/p/themes/BlueLagoon/icons/unread.svg b/p/themes/BlueLagoon/icons/unread.svg index 596dec0ac..bd39d683a 100644 --- a/p/themes/BlueLagoon/icons/unread.svg +++ b/p/themes/BlueLagoon/icons/unread.svg @@ -1,65 +1,3 @@ - - - - - - image/svg+xml - - - - - - - - - - + + -- cgit v1.2.3 From 82745a509a1284a9fe6a7f8d5d153eda953d9e11 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Wed, 26 Nov 2014 18:14:17 -0500 Subject: Optimize screwdriver theme icons. --- p/themes/Screwdriver/icons/favicon.svg | 312 ++++----------------------------- p/themes/Screwdriver/icons/icon.svg | 303 ++++---------------------------- 2 files changed, 66 insertions(+), 549 deletions(-) diff --git a/p/themes/Screwdriver/icons/favicon.svg b/p/themes/Screwdriver/icons/favicon.svg index aaab5de99..895a727bb 100644 --- a/p/themes/Screwdriver/icons/favicon.svg +++ b/p/themes/Screwdriver/icons/favicon.svg @@ -1,280 +1,34 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/p/themes/Screwdriver/icons/icon.svg b/p/themes/Screwdriver/icons/icon.svg index 7f3d76af2..268814463 100644 --- a/p/themes/Screwdriver/icons/icon.svg +++ b/p/themes/Screwdriver/icons/icon.svg @@ -1,271 +1,34 @@ - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3 From adaec6176ca04ee38306bd348eba9a8350f19405 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Tue, 2 Dec 2014 23:34:31 -0500 Subject: Add article auto-remove after clicking on the read link --- p/scripts/main.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/p/scripts/main.js b/p/scripts/main.js index d1d31c801..19eba206d 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -690,6 +690,9 @@ function init_stream(divStream) { divStream.on('click', '.flux a.read', function () { var active = $(this).parents(".flux"); mark_read(active, false); + if (context['auto_remove_article']) { + active.remove(); + } return false; }); -- cgit v1.2.3 From aa232d8fd52cf548c0b2e7d96e026e684eadda53 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 3 Dec 2014 16:45:51 +0100 Subject: Update the i18n system. Follow recommendations from https://github.com/FreshRSS/FreshRSS/issues/334 --- app/i18n/en.php | 533 ----------------------------------------------- app/i18n/en/admin.php | 92 ++++++++ app/i18n/en/conf.php | 7 + app/i18n/en/feedback.php | 14 ++ app/i18n/en/gen.php | 487 +++++++++++++++++++++++++++++++++++++++++++ app/i18n/en/index.php | 5 + app/i18n/en/install.php | 5 + app/i18n/en/sub.php | 10 + app/i18n/fr.php | 533 ----------------------------------------------- app/i18n/fr/admin.php | 92 ++++++++ app/i18n/fr/conf.php | 7 + app/i18n/fr/feedback.php | 14 ++ app/i18n/fr/gen.php | 487 +++++++++++++++++++++++++++++++++++++++++++ app/i18n/fr/index.php | 5 + app/i18n/fr/install.php | 5 + app/i18n/fr/sub.php | 10 + lib/Minz/Translate.php | 114 +++++++--- 17 files changed, 1320 insertions(+), 1100 deletions(-) delete mode 100644 app/i18n/en.php create mode 100644 app/i18n/en/admin.php create mode 100644 app/i18n/en/conf.php create mode 100644 app/i18n/en/feedback.php create mode 100644 app/i18n/en/gen.php create mode 100644 app/i18n/en/index.php create mode 100644 app/i18n/en/install.php create mode 100644 app/i18n/en/sub.php delete mode 100644 app/i18n/fr.php create mode 100644 app/i18n/fr/admin.php create mode 100644 app/i18n/fr/conf.php create mode 100644 app/i18n/fr/feedback.php create mode 100644 app/i18n/fr/gen.php create mode 100644 app/i18n/fr/index.php create mode 100644 app/i18n/fr/install.php create mode 100644 app/i18n/fr/sub.php diff --git a/app/i18n/en.php b/app/i18n/en.php deleted file mode 100644 index a35a6ccf1..000000000 --- a/app/i18n/en.php +++ /dev/null @@ -1,533 +0,0 @@ - '\\A\\p\\r\\i\\l', - 'Aug' => '\\A\\u\\g\\u\\s\\t', - 'Dec' => '\\D\\e\\c\\e\\m\\b\\e\\r', - 'Feb' => '\\F\\e\\b\\r\\u\\a\\r\\y', - 'Jan' => '\\J\\a\\n\\u\\a\\r\\y', - 'Jul' => '\\J\\u\\l\\y', - 'Jun' => '\\J\\u\\n\\e', - 'Mar' => '\\M\\a\\r\\c\\h', - 'May' => '\\M\\a\\y', - 'Nov' => '\\N\\o\\v\\e\\m\\b\\e\\r', - 'Oct' => '\\O\\c\\t\\o\\b\\e\\r', - 'Sep' => '\\S\\e\\p\\t\\e\\m\\b\\e\\r', - 'about' => 'About', - 'about_freshrss' => 'About FreshRSS', - 'access_denied' => 'You don’t have permission to access this page', - 'access_protected_feeds' => 'Connection allows to access HTTP protected RSS feeds', - 'activate_sharing' => 'Activate sharing', - 'actualize' => 'Actualize', - 'add_category' => 'Add a category', - 'add_query' => 'Add a query', - 'add_rss_feed' => 'Add a RSS feed', - 'admin.check_install.cache.nok' => 'Check permissions on ./data/cache directory. HTTP server must have rights to write into', - 'admin.check_install.cache.ok' => 'Permissions on cache directory are good.', - 'admin.check_install.categories.nok' => 'Category table is bad configured.', - 'admin.check_install.categories.ok' => 'Category table is ok.', - 'admin.check_install.connection.nok' => 'Connection to the database cannot being established.', - 'admin.check_install.connection.ok' => 'Connection to the database is ok.', - 'admin.check_install.ctype.nok' => 'You lack a required library for character type checking (php-ctype).', - 'admin.check_install.ctype.ok' => 'You have the required library for character type checking (ctype).', - 'admin.check_install.curl.nok' => 'You lack cURL (php5-curl package).', - 'admin.check_install.curl.ok' => 'You have cURL extension.', - 'admin.check_install.data.nok' => 'Check permissions on ./data directory. HTTP server must have rights to write into', - 'admin.check_install.data.ok' => 'Permissions on data directory are good.', - 'admin.check_install.database' => 'Database installation', - 'admin.check_install.dom.nok' => 'You lack a required library to browse the DOM (php-xml package).', - 'admin.check_install.dom.ok' => 'You have the required library to browse the DOM.', - 'admin.check_install.entries.nok' => 'Entry table is bad configured.', - 'admin.check_install.entries.ok' => 'Entry table is ok.', - 'admin.check_install.favicons.nok' => 'Check permissions on ./data/favicons directory. HTTP server must have rights to write into', - 'admin.check_install.favicons.ok' => 'Permissions on favicons directory are good.', - 'admin.check_install.feeds.nok' => 'Feed table is bad configured.', - 'admin.check_install.feeds.ok' => 'Feed table is ok.', - 'admin.check_install.files' => 'File installation', - 'admin.check_install.json.nok' => 'You lack JSON (php5-json package).', - 'admin.check_install.json.ok' => 'You have JSON extension.', - 'admin.check_install.logs.nok' => 'Check permissions on ./data/logs directory. HTTP server must have rights to write into', - 'admin.check_install.logs.ok' => 'Permissions on logs directory are good.', - 'admin.check_install.minz.nok' => 'You lack the Minz framework.', - 'admin.check_install.minz.ok' => 'You have the Minz framework.', - 'admin.check_install.pcre.nok' => 'You lack a required library for regular expressions (php-pcre).', - 'admin.check_install.pcre.ok' => 'You have the required library for regular expressions (PCRE).', - 'admin.check_install.pdo.nok' => 'You lack PDO or one of the supported drivers (pdo_mysql, pdo_sqlite).', - 'admin.check_install.pdo.ok' => 'You have PDO and at least one of the supported drivers (pdo_mysql, pdo_sqlite).', - 'admin.check_install.persona.nok' => 'Check permissions on ./data/persona directory. HTTP server must have rights to write into', - 'admin.check_install.persona.ok' => 'Permissions on Mozilla Persona directory are good.', - 'admin.check_install.php' => 'PHP installation', - 'admin.check_install.php.nok' => 'Your PHP version is %s but FreshRSS requires at least version %s.', - 'admin.check_install.php.ok' => 'Your PHP version is %s, which is compatible with FreshRSS.', - 'admin.check_install.tables.nok' => 'There is one or more lacking tables in the database.', - 'admin.check_install.tables.ok' => 'Tables are existing in the database.', - 'admin.check_install.tokens.nok' => 'Check permissions on ./data/tokens directory. HTTP server must have rights to write into', - 'admin.check_install.tokens.ok' => 'Permissions on tokens directory are good.', - 'admin.check_install.zip.nok' => 'You lack ZIP extension (php5-zip package).', - 'admin.check_install.zip.ok' => 'You have ZIP extension.', - 'admin.users.articles_and_size' => '%s articles (%s)', - 'administration' => 'Manage', - 'advanced' => 'Advanced', - 'after_onread' => 'After “mark all as read”,', - 'agpl3' => 'AGPL 3', - 'all_feeds' => 'All feeds', - 'allow_anonymous' => 'Allow anonymous reading of the articles of the default user (%s)', - 'allow_anonymous_refresh' => 'Allow anonymous refresh of the articles', - 'already_subscribed' => 'You have already subscribed to %s', - 'api_enabled' => 'Allow API access (required for mobile apps)', - 'apr' => 'apr', - 'april' => 'Apr', - 'archiving_configuration' => 'Archiving', - 'archiving_configuration_help' => 'More options are available in the individual stream settings', - 'article' => 'Article', - 'article_icons' => 'Article icons', - 'article_open_on_website' => 'when article is opened on its original website', - 'article_published_on' => 'This article originally appeared on %s', - 'article_published_on_author' => 'This article originally appeared on %s by %s', - 'article_viewed' => 'when article is viewed', - 'articles' => 'articles', - 'articles_per_page' => 'Number of articles per page', - 'articles_to_display' => 'Articles to display', - 'ask_empty' => 'Clear?', - 'attention' => 'Attention!', - 'aug' => 'aug', - 'august' => 'Aug', - 'auth_form' => 'Web form (traditional, requires JavaScript)', - 'auth_form_not_set' => 'A problem occured during authentication system configuration. Please retry later.', - 'auth_form_set' => 'Form is now your default authentication system.', - 'auth_no_password_set' => 'Administrator password hasn’t been set. This feature isn’t available.', - 'auth_none' => 'None (dangerous)', - 'auth_not_persona' => 'Only Persona system can be reset.', - 'auth_persona' => 'Mozilla Persona (modern, requires JavaScript)', - 'auth_reset' => 'Authentication reset', - 'auth_token' => 'Authentication token', - 'auth_type' => 'Authentication method', - 'auth_will_reset' => 'Authentication system will be reset: a form will be used instead of Persona.', - 'author' => 'Author', - 'auto_load_more' => 'Load next articles at the page bottom', - 'auto_read_when' => 'Mark article as read…', - 'auto_share' => 'Share', - 'auto_share_help' => 'If there is only one sharing mode, it is used. Else modes are accessible by their number.', - 'back_to_rss_feeds' => '← Go back to your RSS feeds', - 'bad_opml_file' => 'Your OPML file is invalid', - 'base_url' => 'Base URL', - 'bdd' => 'Database', - 'bdd_conf_is_ko' => 'Verify your database information.', - 'bdd_conf_is_ok' => 'Database configuration has been saved.', - 'bdd_configuration' => 'Database configuration', - 'bdd_type' => 'Type of database', - 'before_one_day' => 'Before one day', - 'before_one_week' => 'Before one week', - 'before_yesterday' => 'Before yesterday', - 'blank_to_disable' => 'Leave blank to disable', - 'blogotext' => 'Blogotext', - 'bookmark' => 'Subscribe (FreshRSS bookmark)', - 'bottom_line' => 'Bottom line', - 'bugs_reports' => 'Bugs reports', - 'by' => 'by', - 'by_author' => 'By %s', - 'by_default' => 'By default', - 'by_email' => 'By email', - 'by_feed' => 'by feed', - 'cache_is_ok' => 'Permissions on cache directory are good', - 'can_not_be_deleted' => 'Cannot be deleted', - 'cancel' => 'Cancel', - 'categories' => 'Categories', - 'categories_management' => 'Categories management', - 'categories_updated' => 'Categories have been updated', - 'categorize' => 'Store in a category', - 'category' => 'Category', - 'category_created' => 'Category %s has been created.', - 'category_deleted' => 'Category has been deleted.', - 'category_emptied' => 'Category has been emptied', - 'category_empty' => 'Empty category', - 'category_name_exists' => 'Category name already exists.', - 'category_no_id' => 'You must precise the id of the category.', - 'category_no_name' => 'Category name cannot be empty.', - 'category_not_delete_default' => 'You cannot delete the default category!', - 'category_not_exist' => 'The category does not exist!', - 'category_number' => 'Category n°%d', - 'category_updated' => 'Category has been updated.', - 'change_value' => 'You should change this value by any other', - 'checks' => 'Checks', - 'choose_language' => 'Choose a language for FreshRSS', - 'clear_logs' => 'Clear the logs', - 'collapse_article' => 'Collapse', - 'conf.users.articles_and_size' => '%s articles (%s)', - 'configuration' => 'Configuration', - 'configuration_updated' => 'Configuration has been updated', - 'confirm_action' => 'Are you sure you want to perform this action? It cannot be cancelled!', - 'confirm_action_feed_cat' => 'Are you sure you want to perform this action? You will lose related favorites and user queries. It cannot be cancelled!', - 'congratulations' => 'Congratulations!', - 'content_width' => 'Content width', - 'create' => 'Create', - 'create_user' => 'Create new user', - 'credits' => 'Credits', - 'credits_content' => 'Some design elements come from Bootstrap although FreshRSS doesn’t use this framework. Icons come from GNOME project. Open Sans font police has been created by Steve Matteson. Favicons are collected with getFavicon API. FreshRSS is based on Minz, a PHP framework.', - 'css_path_on_website' => 'Articles CSS path on original website', - 'ctype_is_nok' => 'You lack a required library for character type checking (php-ctype)', - 'ctype_is_ok' => 'You have the required library for character type checking (ctype)', - 'curl_is_nok' => 'You lack cURL (php5-curl package)', - 'curl_is_ok' => 'You have version %s of cURL', - 'current_user' => 'Current user', - 'damn' => 'Damn!', - 'data_is_ok' => 'Permissions on data directory are good', - 'dec' => 'dec', - 'december' => 'Dec', - 'default_category' => 'Uncategorized', - 'default_user' => 'Username of the default user (maximum 16 alphanumeric characters)', - 'default_view' => 'Default view', - 'delete' => 'Delete', - 'delete_articles_every' => 'Remove articles after', - 'diaspora' => 'Diaspora*', - 'display' => 'Display', - 'display_articles_unfolded' => 'Show articles unfolded by default', - 'display_categories_unfolded' => 'Show categories folded by default', - 'display_configuration' => 'Display', - 'do_not_change_if_doubt' => 'Don’t change if you doubt about it', - 'dom_is_nok' => 'You lack a required library to browse the DOM (php-xml package)', - 'dom_is_ok' => 'You have the required library to browse the DOM', - 'email' => 'Email', - 'error_occurred' => 'An error occurred', - 'error_occurred_update' => 'Nothing was changed', - 'explain_token' => 'Allows to access RSS output of the default user without authentication.
    %s?output=rss&token=%s', - 'export' => 'Export', - 'export_no_zip_extension' => 'Zip extension is not present on your server. Please try to export files one by one.', - 'export_opml' => 'Export list of feeds (OPML)', - 'export_starred' => 'Export your favourites', - 'facebook' => 'Facebook', - 'favicons_is_ok' => 'Permissions on favicons directory are good', - 'favorite_feeds' => 'Favourites (%s)', - 'feb' => 'feb', - 'february' => 'Feb', - 'feed' => 'Feed', - 'feed_actualized' => '%s has been updated', - 'feed_added' => 'RSS feed %s has been added', - 'feed_deleted' => 'Feed has been deleted', - 'feed_description' => 'Description', - 'feed_empty' => 'This feed is empty. Please verify that it is still maintained.', - 'feed_in_error' => 'This feed has encountered a problem. Please verify that it is always reachable then actualize it.', - 'feed_list' => 'List of %s articles', - 'feed_not_added' => '%s could not be added', - 'feed_updated' => 'Feed has been updated', - 'feed_url' => 'Feed URL', - 'feed_validator' => 'Check the validity of the feed', - 'feedback.login.error' => 'Login is invalid', - 'feedback.login.success' => 'You are connected', - 'feedback.logout.success' => 'You are disconnected', - 'feedback.user_profile.updated' => 'Your profile has been modified', - 'feeds' => 'Feeds', - 'feeds_actualized' => 'RSS feeds have been updated', - 'feeds_imported' => 'Your feeds have been imported and will now be updated', - 'feeds_imported_with_errors' => 'Your feeds have been imported but some errors occurred', - 'feeds_marked_read' => 'Feeds have been marked as read', - 'feeds_moved_category_deleted' => 'When you delete a category, their feeds are automatically classified under %s.', - 'file_cannot_be_uploaded' => 'File cannot be uploaded!', - 'file_is_nok' => 'Check permissions on %s directory. HTTP server must have rights to write into', - 'file_to_import' => 'File to import
    (OPML, Json or Zip)', - 'file_to_import_no_zip' => 'File to import
    (OPML or Json)', - 'filter' => 'Filter', - 'finish_installation' => 'Complete installation', - 'first' => 'First', - 'first_article' => 'Skip to the first article', - 'fix_errors_before' => 'Fix errors before skip to the next step.', - 'focus_search' => 'Access search box', - 'format_date' => '%s j\\<\\s\\u\\p\\>S\\<\\/\\s\\u\\p\\> Y', - 'format_date_hour' => '%s j\\<\\s\\u\\p\\>S\\<\\/\\s\\u\\p\\> Y \\a\\t H\\:i', - 'freshrss' => 'FreshRSS', - 'freshrss_description' => 'FreshRSS is a RSS feeds aggregator to self-host like Kriss Feed or Leed. It is light and easy to take in hand while being powerful and configurable tool.', - 'freshrss_installation' => 'Installation · FreshRSS', - 'fri' => 'Fri', - 'g+' => 'Google+', - 'gen.menu.admin' => 'Administration', - 'gen.menu.authentication' => 'Authentication', - 'gen.menu.check_install' => 'Installation checking', - 'gen.menu.user_management' => 'Manage users', - 'gen.menu.user_profile' => 'Profile', - 'gen.title.authentication' => 'Authentication', - 'gen.title.check_install' => 'Installation checking', - 'gen.title.global_view' => 'Global view', - 'gen.title.user_management' => 'Manage users', - 'gen.title.user_profile' => 'Profile', - 'general_conf_is_ok' => 'General configuration has been saved.', - 'general_configuration' => 'General configuration', - 'github_or_email' => 'on Github or by mail', - 'global_view' => 'Global view', - 'help' => 'Display documentation', - 'hide_read_feeds' => 'Hide categories & feeds with no unread article (does not work with “Show all articles” configuration)', - 'host' => 'Host', - 'html5_notif_timeout' => 'HTML5 notification timeout', - 'http_auth' => 'HTTP (for advanced users with HTTPS)', - 'http_authentication' => 'HTTP Authentication', - 'http_password' => 'HTTP password', - 'http_referer_is_nok' => 'Please check that you are not altering your HTTP REFERER.', - 'http_referer_is_ok' => 'Your HTTP REFERER is known and corresponds to your server.', - 'http_username' => 'HTTP username', - 'img_with_lazyload' => 'Use "lazy load" mode to load pictures', - 'import' => 'Import', - 'import_export' => 'Import / export', - 'informations' => 'Information', - 'install_not_deleted' => 'Something went wrong; you must delete the file %s manually.', - 'installation_is_ok' => 'The installation process was successful.
    The final step will now attempt to delete any file and database backup created during the update process.
    You may choose to skip this step by deleting ./data/do-install.txt manually.', - 'installation_step' => 'Installation — step %d · FreshRSS', - 'internal_problem_feed' => 'The RSS feed could not be added. Check FressRSS logs for details.', - 'invalid_login' => 'Login is invalid', - 'invalid_url' => 'URL %s is invalid', - 'is_admin' => 'is administrator', - 'jan' => 'jan', - 'january' => 'Jan', - 'javascript_for_shortcuts' => 'JavaScript must be enabled in order to use shortcuts', - 'javascript_is_better' => 'FreshRSS is more pleasant with JavaScript enabled', - 'javascript_should_be_activated' => 'JavaScript must be enabled', - 'jul' => 'jul', - 'july' => 'Jul', - 'jump_next' => 'jump to next unread sibling (feed or category)', - 'jun' => 'jun', - 'june' => 'Jun', - 'keep_history' => 'Minimum number of articles to keep', - 'keep_logged_in' => 'Keep me logged in (1 month)', - 'language' => 'Language', - 'language_defined' => 'Language has been defined.', - 'last' => 'Last', - 'last_3_month' => 'Last three months', - 'last_6_month' => 'Last six months', - 'last_article' => 'Skip to the last article', - 'last_month' => 'Last month', - 'last_week' => 'Last week', - 'last_year' => 'Last year', - 'lead_developer' => 'Lead developer', - 'license' => 'License', - 'load_more' => 'Load more articles', - 'log_is_ok' => 'Permissions on logs directory are good', - 'login' => 'Login', - 'login_configuration' => 'Login', - 'login_persona_problem' => 'Connection problem with Persona?', - 'login_required' => 'Login required:', - 'login_with_persona' => 'Login with Persona', - 'logout' => 'Logout', - 'logs' => 'Logs', - 'logs_empty' => 'Log file is empty', - 'main_stream' => 'Main stream', - 'mar' => 'mar', - 'march' => 'Mar', - 'mark_all_read' => 'Mark all as read', - 'mark_cat_read' => 'Mark category as read', - 'mark_favorite' => 'Mark as favourite', - 'mark_feed_read' => 'Mark feed as read', - 'mark_read' => 'Mark as read', - 'may' => 'May', - 'minz_is_nok' => 'You lack the Minz framework. You should execute build.sh script or download it on Github and install in %s directory the content of its /lib directory.', - 'minz_is_ok' => 'You have the Minz framework', - 'mon' => 'Mon', - 'month' => 'months', - 'more_information' => 'More information', - 'n_entries_deleted' => '%d articles have been deleted', - 'n_feeds_actualized' => '%d feeds have been updated', - 'new_article' => 'There are new available articles, click to refresh the page.', - 'new_category' => 'New category', - 'newer_first' => 'Newer first', - 'next' => 'Next', - 'next_article' => 'Skip to the next article', - 'next_page' => 'Skip to the next page', - 'next_step' => 'Go to the next step', - 'no' => 'No', - 'no_feed_actualized' => 'No RSS feed has been updated', - 'no_feed_to_display' => 'There is no article to show.', - 'no_feed_to_refresh' => 'There is no feed to refresh…', - 'no_query' => 'You haven’t created any user query yet.', - 'no_query_filter' => 'No filter', - 'no_rss_feed' => 'No RSS feed', - 'no_selected_feed' => 'No feed selected.', - 'no_update' => 'No update to apply', - 'no_zip_extension' => 'Zip extension is not present on your server.', - 'normal_view' => 'Normal view', - 'not_read' => '%d unread', - 'not_reads' => '%d unread', - 'not_yet_implemented' => 'Not yet implemented', - 'nothing_to_load' => 'There are no more articles', - 'notif_body_new_articles' => 'There are \\d new articles to read on FreshRSS.', - 'notif_title_new_articles' => 'FreshRSS: new articles!', - 'nov' => 'nov', - 'november' => 'Nov', - 'number_articles' => '%d articles', - 'number_divided_when_reader' => 'Divided by 2 in the reading view.', - 'number_feeds' => '%d feeds', - 'oct' => 'oct', - 'october' => 'Oct', - 'ok' => 'Ok!', - 'older_first' => 'Oldest first', - 'oops' => 'Oops!', - 'optimization_complete' => 'Optimization complete', - 'optimize_bdd' => 'Optimize database', - 'optimize_todo_sometimes' => 'To do occasionally to reduce the size of the database', - 'or' => 'or', - 'page_not_found' => 'You are looking for a page which doesn’t exist', - 'password' => 'Password', - 'password_api' => 'Password API
    (e.g., for mobile apps)', - 'password_form' => 'Password
    (for the Web-form login method)', - 'pcre_is_nok' => 'You lack a required library for regular expressions (php-pcre)', - 'pcre_is_ok' => 'You have the required library for regular expressions (PCRE)', - 'pdo_is_nok' => 'You lack PDO or one of the supported drivers (pdo_mysql, pdo_sqlite)', - 'pdo_is_ok' => 'You have PDO and at least one of the supported drivers (pdo_mysql, pdo_sqlite)', - 'persona_connection_email' => 'Login mail address
    (for Mozilla Persona)', - 'persona_is_ok' => 'Permissions on Mozilla Persona directory are good', - 'php_is_nok' => 'Your PHP version is %s but FreshRSS requires at least version %s', - 'php_is_ok' => 'Your PHP version is %s, which is compatible with FreshRSS', - 'prefix' => 'Table prefix', - 'previous' => 'Previous', - 'previous_article' => 'Skip to the previous article', - 'previous_page' => 'Skip to the previous page', - 'print' => 'Print', - 'project_website' => 'Project website', - 'public' => 'Public', - 'publication_date' => 'Date of publication', - 'purge_completed' => 'Purge completed (%d articles deleted)', - 'purge_now' => 'Purge now', - 'queries' => 'User queries', - 'query_created' => 'Query "%s" has been created.', - 'query_deprecated' => 'This query is no longer valid. The referenced category or feed has been deleted.', - 'query_filter' => 'Filter applied:', - 'query_get_all' => 'Display all articles', - 'query_get_category' => 'Display "%s" category', - 'query_get_favorite' => 'Display favorite articles', - 'query_get_feed' => 'Display "%s" feed', - 'query_number' => 'Query n°%d', - 'query_order_asc' => 'Display oldest articles first', - 'query_order_desc' => 'Display newest articles first', - 'query_search' => 'Search for "%s"', - 'query_state_0' => 'Display all articles', - 'query_state_1' => 'Display read articles', - 'query_state_2' => 'Display unread articles', - 'query_state_3' => 'Display all articles', - 'query_state_4' => 'Display favorite articles', - 'query_state_5' => 'Display read favorite articles', - 'query_state_6' => 'Display unread favorite articles', - 'query_state_7' => 'Display favorite articles', - 'query_state_8' => 'Display not favorite articles', - 'query_state_9' => 'Display read not favorite articles', - 'query_state_10' => 'Display unread not favorite articles', - 'query_state_11' => 'Display not favorite articles', - 'query_state_12' => 'Display all articles', - 'query_state_13' => 'Display read articles', - 'query_state_14' => 'Display unread articles', - 'query_state_15' => 'Display all articles', - 'random_string' => 'Random string', - 'reader_view' => 'Reading view', - 'reading_configuration' => 'Reading', - 'reading_confirm' => 'Display a confirmation dialog on “mark all as read” actions', - 'refresh' => 'Refresh', - 'related_tags' => 'Related tags', - 'retrieve_truncated_feeds' => 'Retrieves truncated RSS feeds (attention, requires more time!)', - 'rss_feed_management' => 'RSS feeds management', - 'rss_feeds_of' => 'RSS feed of %s', - 'rss_view' => 'RSS feed', - 'sat' => 'Sat', - 'save' => 'Save', - 'scroll' => 'while scrolling', - 'search' => 'Search words or #tags', - 'search_short' => 'Search', - 'seconds_(0_means_no_timeout)' => 'seconds (0 means no timeout)', - 'see_on_website' => 'See on original website', - 'see_website' => 'See website', - 'sep' => 'sep', - 'september' => 'Sep', - 'shaarli' => 'Shaarli', - 'share' => 'Share', - 'share_name' => 'Share name to display', - 'share_url' => 'Share URL to use', - 'sharing' => 'Sharing', - 'sharing_management' => 'Sharing options management', - 'shift_for_all_read' => '+ shift to mark all articles as read', - 'shortcuts' => 'Shortcuts', - 'shortcuts_article_action' => 'Article actions', - 'shortcuts_navigation' => 'Navigation', - 'shortcuts_navigation_help' => 'With the "Shift" modifier, navigation shortcuts apply on feeds.
    With the "Alt" modifier, navigation shortcuts apply on categories.', - 'shortcuts_other_action' => 'Other actions', - 'shortcuts_updated' => 'Shortcuts have been updated', - 'show_adaptive' => 'Adjust showing', - 'show_all_articles' => 'Show all articles', - 'show_favorite' => 'Show only favorites', - 'show_in_all_flux' => 'Show in main stream', - 'show_not_favorite' => 'Show all but favorites', - 'show_not_reads' => 'Show only unread', - 'show_read' => 'Show only read', - 'sort_order' => 'Sort order', - 'starred_list' => 'List of favourite articles', - 'stats' => 'Statistics', - 'stats_entry_count' => 'Entry count', - 'stats_entry_per_category' => 'Entries per category', - 'stats_entry_per_day' => 'Entries per day (last 30 days)', - 'stats_entry_per_day_of_week' => 'Per day of week (average: %.2f messages)', - 'stats_entry_per_hour' => 'Per hour (average: %.2f messages)', - 'stats_entry_per_month' => 'Per month (average: %.2f messages)', - 'stats_entry_repartition' => 'Entries repartition', - 'stats_feed_per_category' => 'Feeds per category', - 'stats_idle' => 'Idle feeds', - 'stats_main' => 'Main statistics', - 'stats_no_idle' => 'There is no idle feed!', - 'stats_percent_of_total' => '%% of total', - 'stats_repartition' => 'Articles repartition', - 'stats_top_feed' => 'Top ten feeds', - 'status_favorites' => 'Favourites', - 'status_read' => 'Read', - 'status_total' => 'Total', - 'status_unread' => 'Unread', - 'steps' => 'Steps', - 'sticky_post' => 'Stick the article to the top when opened', - 'sub.categories.over_max' => 'You have reached your limit of categories (%d)', - 'sub.feeds.over_max' => 'You have reached your limit of feeds (%d)', - 'submit' => 'Submit', - 'subscription_management' => 'Subscriptions management', - 'sun' => 'Sun', - 'theme' => 'Theme', - 'think_to_add' => 'You may add some feeds.', - 'this_is_the_end' => 'This is the end', - 'thu' => 'Thu', - 'title' => 'Title', - 'today' => 'Today', - 'top_line' => 'Top line', - 'truncate' => 'Delete all articles', - 'ttl' => 'Do not automatically refresh more often than', - 'tue' => 'Tue', - 'twitter' => 'Twitter', - 'unsafe_autologin' => 'Allow unsafe automatic login using the format: ', - 'update' => 'Update', - 'update_apply' => 'Apply', - 'update_can_apply' => 'An update is available.', - 'update_check' => 'Check for new updates', - 'update_end' => 'Update process is completed, now you can go to the final step.', - 'update_finished' => 'Update completed!', - 'update_last' => 'Last verification: %s', - 'update_long' => 'This can take a long time, depending on the size of your database. You may have to wait for this page to time out (~5 minutes) and then refresh this page.', - 'update_problem' => 'The update process has encountered an error: %s', - 'update_server_not_found' => 'Update server cannot be found. [%s]', - 'update_start' => 'Start update process', - 'update_system' => 'Update system', - 'updated' => 'Modifications have been updated', - 'upon_reception' => 'upon reception of the article', - 'user_created' => 'User %s has been created', - 'user_deleted' => 'User %s has been deleted', - 'user_filter' => 'Access user filters', - 'user_filter_help' => 'If there is only one user filter, it is used. Else filters are accessible by their number.', - 'username' => 'Username', - 'username_admin' => 'Administrator username', - 'users' => 'Users', - 'users_list' => 'List of users', - 'version' => 'Version', - 'version_update' => 'Update', - 'wallabag' => 'wallabag', - 'website' => 'Website', - 'website_url' => 'Website URL', - 'wed' => 'Wed', - 'width_large' => 'Large', - 'width_medium' => 'Medium', - 'width_no_limit' => 'No limit', - 'width_thin' => 'Thin', - 'yes' => 'Yes', - 'yesterday' => 'Yesterday', - 'your_diaspora_pod' => 'Your Diaspora* pod', - 'your_favorites' => 'Your favourites', - 'your_rss_feeds' => 'Your RSS feeds', - 'your_shaarli' => 'Your Shaarli', - 'your_wallabag' => 'Your wallabag', - 'zip_error' => 'An error occured during Zip import.', -); \ No newline at end of file diff --git a/app/i18n/en/admin.php b/app/i18n/en/admin.php new file mode 100644 index 000000000..74f01ae06 --- /dev/null +++ b/app/i18n/en/admin.php @@ -0,0 +1,92 @@ + array( + 'cache' => array( + 'nok' => 'Check permissions on ./data/cache directory. HTTP server must have rights to write into', + 'ok' => 'Permissions on cache directory are good.', + ), + 'categories' => array( + 'nok' => 'Category table is bad configured.', + 'ok' => 'Category table is ok.', + ), + 'connection' => array( + 'nok' => 'Connection to the database cannot being established.', + 'ok' => 'Connection to the database is ok.', + ), + 'ctype' => array( + 'nok' => 'You lack a required library for character type checking (php-ctype).', + 'ok' => 'You have the required library for character type checking (ctype).', + ), + 'curl' => array( + 'nok' => 'You lack cURL (php5-curl package).', + 'ok' => 'You have cURL extension.', + ), + 'data' => array( + 'nok' => 'Check permissions on ./data directory. HTTP server must have rights to write into', + 'ok' => 'Permissions on data directory are good.', + ), + 'database' => 'Database installation', + 'dom' => array( + 'nok' => 'You lack a required library to browse the DOM (php-xml package).', + 'ok' => 'You have the required library to browse the DOM.', + ), + 'entries' => array( + 'nok' => 'Entry table is bad configured.', + 'ok' => 'Entry table is ok.', + ), + 'favicons' => array( + 'nok' => 'Check permissions on ./data/favicons directory. HTTP server must have rights to write into', + 'ok' => 'Permissions on favicons directory are good.', + ), + 'feeds' => array( + 'nok' => 'Feed table is bad configured.', + 'ok' => 'Feed table is ok.', + ), + 'files' => 'File installation', + 'json' => array( + 'nok' => 'You lack JSON (php5-json package).', + 'ok' => 'You have JSON extension.', + ), + 'logs' => array( + 'nok' => 'Check permissions on ./data/logs directory. HTTP server must have rights to write into', + 'ok' => 'Permissions on logs directory are good.', + ), + 'minz' => array( + 'nok' => 'You lack the Minz framework.', + 'ok' => 'You have the Minz framework.', + ), + 'pcre' => array( + 'nok' => 'You lack a required library for regular expressions (php-pcre).', + 'ok' => 'You have the required library for regular expressions (PCRE).', + ), + 'pdo' => array( + 'nok' => 'You lack PDO or one of the supported drivers (pdo_mysql, pdo_sqlite).', + 'ok' => 'You have PDO and at least one of the supported drivers (pdo_mysql, pdo_sqlite).', + ), + 'persona' => array( + 'nok' => 'Check permissions on ./data/persona directory. HTTP server must have rights to write into', + 'ok' => 'Permissions on Mozilla Persona directory are good.', + ), + 'php' => array( + '_' => 'PHP installation', + 'nok' => 'Your PHP version is %s but FreshRSS requires at least version %s.', + 'ok' => 'Your PHP version is %s, which is compatible with FreshRSS.', + ), + 'tables' => array( + 'nok' => 'There is one or more lacking tables in the database.', + 'ok' => 'Tables are existing in the database.', + ), + 'tokens' => array( + 'nok' => 'Check permissions on ./data/tokens directory. HTTP server must have rights to write into', + 'ok' => 'Permissions on tokens directory are good.', + ), + 'zip' => array( + 'nok' => 'You lack ZIP extension (php5-zip package).', + 'ok' => 'You have ZIP extension.', + ), + ), + 'users' => array( + 'articles_and_size' => '%s articles (%s)', + ), +); diff --git a/app/i18n/en/conf.php b/app/i18n/en/conf.php new file mode 100644 index 000000000..460804774 --- /dev/null +++ b/app/i18n/en/conf.php @@ -0,0 +1,7 @@ + array( + 'articles_and_size' => '%s articles (%s)', + ), +); diff --git a/app/i18n/en/feedback.php b/app/i18n/en/feedback.php new file mode 100644 index 000000000..b3866f1dc --- /dev/null +++ b/app/i18n/en/feedback.php @@ -0,0 +1,14 @@ + array( + 'error' => 'Login is invalid', + 'success' => 'You are connected', + ), + 'logout' => array( + 'success' => 'You are disconnected', + ), + 'user_profile' => array( + 'updated' => 'Your profile has been modified', + ), +); diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php new file mode 100644 index 000000000..9e06357bc --- /dev/null +++ b/app/i18n/en/gen.php @@ -0,0 +1,487 @@ + '\\A\\p\\r\\i\\l', + 'Aug' => '\\A\\u\\g\\u\\s\\t', + 'Dec' => '\\D\\e\\c\\e\\m\\b\\e\\r', + 'Feb' => '\\F\\e\\b\\r\\u\\a\\r\\y', + 'Jan' => '\\J\\a\\n\\u\\a\\r\\y', + 'Jul' => '\\J\\u\\l\\y', + 'Jun' => '\\J\\u\\n\\e', + 'Mar' => '\\M\\a\\r\\c\\h', + 'May' => '\\M\\a\\y', + 'Nov' => '\\N\\o\\v\\e\\m\\b\\e\\r', + 'Oct' => '\\O\\c\\t\\o\\b\\e\\r', + 'Sep' => '\\S\\e\\p\\t\\e\\m\\b\\e\\r', + 'about' => 'About', + 'about_freshrss' => 'About FreshRSS', + 'access_denied' => 'You don’t have permission to access this page', + 'access_protected_feeds' => 'Connection allows to access HTTP protected RSS feeds', + 'activate_sharing' => 'Activate sharing', + 'actualize' => 'Actualize', + 'add_category' => 'Add a category', + 'add_query' => 'Add a query', + 'add_rss_feed' => 'Add a RSS feed', + 'administration' => 'Manage', + 'advanced' => 'Advanced', + 'after_onread' => 'After “mark all as read”,', + 'agpl3' => 'AGPL 3', + 'all_feeds' => 'All feeds', + 'allow_anonymous' => 'Allow anonymous reading of the articles of the default user (%s)', + 'allow_anonymous_refresh' => 'Allow anonymous refresh of the articles', + 'already_subscribed' => 'You have already subscribed to %s', + 'api_enabled' => 'Allow API access (required for mobile apps)', + 'apr' => 'apr', + 'april' => 'Apr', + 'archiving_configuration' => 'Archiving', + 'archiving_configuration_help' => 'More options are available in the individual stream settings', + 'article' => 'Article', + 'article_icons' => 'Article icons', + 'article_open_on_website' => 'when article is opened on its original website', + 'article_published_on' => 'This article originally appeared on %s', + 'article_published_on_author' => 'This article originally appeared on %s by %s', + 'article_viewed' => 'when article is viewed', + 'articles' => 'articles', + 'articles_per_page' => 'Number of articles per page', + 'articles_to_display' => 'Articles to display', + 'ask_empty' => 'Clear?', + 'attention' => 'Attention!', + 'aug' => 'aug', + 'august' => 'Aug', + 'auth_form' => 'Web form (traditional, requires JavaScript)', + 'auth_form_not_set' => 'A problem occured during authentication system configuration. Please retry later.', + 'auth_form_set' => 'Form is now your default authentication system.', + 'auth_no_password_set' => 'Administrator password hasn’t been set. This feature isn’t available.', + 'auth_none' => 'None (dangerous)', + 'auth_not_persona' => 'Only Persona system can be reset.', + 'auth_persona' => 'Mozilla Persona (modern, requires JavaScript)', + 'auth_reset' => 'Authentication reset', + 'auth_token' => 'Authentication token', + 'auth_type' => 'Authentication method', + 'auth_will_reset' => 'Authentication system will be reset: a form will be used instead of Persona.', + 'author' => 'Author', + 'auto_load_more' => 'Load next articles at the page bottom', + 'auto_read_when' => 'Mark article as read…', + 'auto_share' => 'Share', + 'auto_share_help' => 'If there is only one sharing mode, it is used. Else modes are accessible by their number.', + 'back_to_rss_feeds' => '← Go back to your RSS feeds', + 'bad_opml_file' => 'Your OPML file is invalid', + 'base_url' => 'Base URL', + 'bdd' => 'Database', + 'bdd_conf_is_ko' => 'Verify your database information.', + 'bdd_conf_is_ok' => 'Database configuration has been saved.', + 'bdd_configuration' => 'Database configuration', + 'bdd_type' => 'Type of database', + 'before_one_day' => 'Before one day', + 'before_one_week' => 'Before one week', + 'before_yesterday' => 'Before yesterday', + 'blank_to_disable' => 'Leave blank to disable', + 'blogotext' => 'Blogotext', + 'bookmark' => 'Subscribe (FreshRSS bookmark)', + 'bottom_line' => 'Bottom line', + 'bugs_reports' => 'Bugs reports', + 'by' => 'by', + 'by_author' => 'By %s', + 'by_default' => 'By default', + 'by_email' => 'By email', + 'by_feed' => 'by feed', + 'cache_is_ok' => 'Permissions on cache directory are good', + 'can_not_be_deleted' => 'Cannot be deleted', + 'cancel' => 'Cancel', + 'categories' => 'Categories', + 'categories_management' => 'Categories management', + 'categories_updated' => 'Categories have been updated', + 'categorize' => 'Store in a category', + 'category' => 'Category', + 'category_created' => 'Category %s has been created.', + 'category_deleted' => 'Category has been deleted.', + 'category_emptied' => 'Category has been emptied', + 'category_empty' => 'Empty category', + 'category_name_exists' => 'Category name already exists.', + 'category_no_id' => 'You must precise the id of the category.', + 'category_no_name' => 'Category name cannot be empty.', + 'category_not_delete_default' => 'You cannot delete the default category!', + 'category_not_exist' => 'The category does not exist!', + 'category_number' => 'Category n°%d', + 'category_updated' => 'Category has been updated.', + 'change_value' => 'You should change this value by any other', + 'checks' => 'Checks', + 'choose_language' => 'Choose a language for FreshRSS', + 'clear_logs' => 'Clear the logs', + 'collapse_article' => 'Collapse', + 'configuration' => 'Configuration', + 'configuration_updated' => 'Configuration has been updated', + 'confirm_action' => 'Are you sure you want to perform this action? It cannot be cancelled!', + 'confirm_action_feed_cat' => 'Are you sure you want to perform this action? You will lose related favorites and user queries. It cannot be cancelled!', + 'congratulations' => 'Congratulations!', + 'content_width' => 'Content width', + 'create' => 'Create', + 'create_user' => 'Create new user', + 'credits' => 'Credits', + 'credits_content' => 'Some design elements come from Bootstrap although FreshRSS doesn’t use this framework. Icons come from GNOME project. Open Sans font police has been created by Steve Matteson. Favicons are collected with getFavicon API. FreshRSS is based on Minz, a PHP framework.', + 'css_path_on_website' => 'Articles CSS path on original website', + 'ctype_is_nok' => 'You lack a required library for character type checking (php-ctype)', + 'ctype_is_ok' => 'You have the required library for character type checking (ctype)', + 'curl_is_nok' => 'You lack cURL (php5-curl package)', + 'curl_is_ok' => 'You have version %s of cURL', + 'current_user' => 'Current user', + 'damn' => 'Damn!', + 'data_is_ok' => 'Permissions on data directory are good', + 'dec' => 'dec', + 'december' => 'Dec', + 'default_category' => 'Uncategorized', + 'default_user' => 'Username of the default user (maximum 16 alphanumeric characters)', + 'default_view' => 'Default view', + 'delete' => 'Delete', + 'delete_articles_every' => 'Remove articles after', + 'diaspora' => 'Diaspora*', + 'display' => 'Display', + 'display_articles_unfolded' => 'Show articles unfolded by default', + 'display_categories_unfolded' => 'Show categories folded by default', + 'display_configuration' => 'Display', + 'do_not_change_if_doubt' => 'Don’t change if you doubt about it', + 'dom_is_nok' => 'You lack a required library to browse the DOM (php-xml package)', + 'dom_is_ok' => 'You have the required library to browse the DOM', + 'email' => 'Email', + 'error_occurred' => 'An error occurred', + 'error_occurred_update' => 'Nothing was changed', + 'explain_token' => 'Allows to access RSS output of the default user without authentication.
    %s?output=rss&token=%s', + 'export' => 'Export', + 'export_no_zip_extension' => 'Zip extension is not present on your server. Please try to export files one by one.', + 'export_opml' => 'Export list of feeds (OPML)', + 'export_starred' => 'Export your favourites', + 'facebook' => 'Facebook', + 'favicons_is_ok' => 'Permissions on favicons directory are good', + 'favorite_feeds' => 'Favourites (%s)', + 'feb' => 'feb', + 'february' => 'Feb', + 'feed' => 'Feed', + 'feed_actualized' => '%s has been updated', + 'feed_added' => 'RSS feed %s has been added', + 'feed_deleted' => 'Feed has been deleted', + 'feed_description' => 'Description', + 'feed_empty' => 'This feed is empty. Please verify that it is still maintained.', + 'feed_in_error' => 'This feed has encountered a problem. Please verify that it is always reachable then actualize it.', + 'feed_list' => 'List of %s articles', + 'feed_not_added' => '%s could not be added', + 'feed_updated' => 'Feed has been updated', + 'feed_url' => 'Feed URL', + 'feed_validator' => 'Check the validity of the feed', + 'feeds' => 'Feeds', + 'feeds_actualized' => 'RSS feeds have been updated', + 'feeds_imported' => 'Your feeds have been imported and will now be updated', + 'feeds_imported_with_errors' => 'Your feeds have been imported but some errors occurred', + 'feeds_marked_read' => 'Feeds have been marked as read', + 'feeds_moved_category_deleted' => 'When you delete a category, their feeds are automatically classified under %s.', + 'file_cannot_be_uploaded' => 'File cannot be uploaded!', + 'file_is_nok' => 'Check permissions on %s directory. HTTP server must have rights to write into', + 'file_to_import' => 'File to import
    (OPML, Json or Zip)', + 'file_to_import_no_zip' => 'File to import
    (OPML or Json)', + 'filter' => 'Filter', + 'finish_installation' => 'Complete installation', + 'first' => 'First', + 'first_article' => 'Skip to the first article', + 'fix_errors_before' => 'Fix errors before skip to the next step.', + 'focus_search' => 'Access search box', + 'format_date' => '%s j\\<\\s\\u\\p\\>S\\<\\/\\s\\u\\p\\> Y', + 'format_date_hour' => '%s j\\<\\s\\u\\p\\>S\\<\\/\\s\\u\\p\\> Y \\a\\t H\\:i', + 'freshrss' => 'FreshRSS', + 'freshrss_description' => 'FreshRSS is a RSS feeds aggregator to self-host like Kriss Feed or Leed. It is light and easy to take in hand while being powerful and configurable tool.', + 'freshrss_installation' => 'Installation · FreshRSS', + 'fri' => 'Fri', + 'g+' => 'Google+', + 'menu' => array( + 'admin' => 'Administration', + 'authentication' => 'Authentication', + 'check_install' => 'Installation checking', + 'user_management' => 'Manage users', + 'user_profile' => 'Profile', + ), + 'title' => array( + '_' => 'Title', + 'authentication' => 'Authentication', + 'check_install' => 'Installation checking', + 'global_view' => 'Global view', + 'user_management' => 'Manage users', + 'user_profile' => 'Profile', + ), + 'general_conf_is_ok' => 'General configuration has been saved.', + 'general_configuration' => 'General configuration', + 'github_or_email' => 'on Github or by mail', + 'global_view' => 'Global view', + 'help' => 'Display documentation', + 'hide_read_feeds' => 'Hide categories & feeds with no unread article (does not work with “Show all articles” configuration)', + 'host' => 'Host', + 'html5_notif_timeout' => 'HTML5 notification timeout', + 'http_auth' => 'HTTP (for advanced users with HTTPS)', + 'http_authentication' => 'HTTP Authentication', + 'http_password' => 'HTTP password', + 'http_referer_is_nok' => 'Please check that you are not altering your HTTP REFERER.', + 'http_referer_is_ok' => 'Your HTTP REFERER is known and corresponds to your server.', + 'http_username' => 'HTTP username', + 'img_with_lazyload' => 'Use "lazy load" mode to load pictures', + 'import' => 'Import', + 'import_export' => 'Import / export', + 'informations' => 'Information', + 'install_not_deleted' => 'Something went wrong; you must delete the file %s manually.', + 'installation_is_ok' => 'The installation process was successful.
    The final step will now attempt to delete any file and database backup created during the update process.
    You may choose to skip this step by deleting ./data/do-install.txt manually.', + 'installation_step' => 'Installation — step %d · FreshRSS', + 'internal_problem_feed' => 'The RSS feed could not be added. Check FressRSS logs for details.', + 'invalid_login' => 'Login is invalid', + 'invalid_url' => 'URL %s is invalid', + 'is_admin' => 'is administrator', + 'jan' => 'jan', + 'january' => 'Jan', + 'javascript_for_shortcuts' => 'JavaScript must be enabled in order to use shortcuts', + 'javascript_is_better' => 'FreshRSS is more pleasant with JavaScript enabled', + 'javascript_should_be_activated' => 'JavaScript must be enabled', + 'jul' => 'jul', + 'july' => 'Jul', + 'jump_next' => 'jump to next unread sibling (feed or category)', + 'jun' => 'jun', + 'june' => 'Jun', + 'keep_history' => 'Minimum number of articles to keep', + 'keep_logged_in' => 'Keep me logged in (1 month)', + 'language' => 'Language', + 'language_defined' => 'Language has been defined.', + 'last' => 'Last', + 'last_3_month' => 'Last three months', + 'last_6_month' => 'Last six months', + 'last_article' => 'Skip to the last article', + 'last_month' => 'Last month', + 'last_week' => 'Last week', + 'last_year' => 'Last year', + 'lead_developer' => 'Lead developer', + 'license' => 'License', + 'load_more' => 'Load more articles', + 'log_is_ok' => 'Permissions on logs directory are good', + 'login' => 'Login', + 'login_configuration' => 'Login', + 'login_persona_problem' => 'Connection problem with Persona?', + 'login_required' => 'Login required:', + 'login_with_persona' => 'Login with Persona', + 'logout' => 'Logout', + 'logs' => 'Logs', + 'logs_empty' => 'Log file is empty', + 'main_stream' => 'Main stream', + 'mar' => 'mar', + 'march' => 'Mar', + 'mark_all_read' => 'Mark all as read', + 'mark_cat_read' => 'Mark category as read', + 'mark_favorite' => 'Mark as favourite', + 'mark_feed_read' => 'Mark feed as read', + 'mark_read' => 'Mark as read', + 'may' => 'May', + 'minz_is_nok' => 'You lack the Minz framework. You should execute build.sh script or download it on Github and install in %s directory the content of its /lib directory.', + 'minz_is_ok' => 'You have the Minz framework', + 'mon' => 'Mon', + 'month' => 'months', + 'more_information' => 'More information', + 'n_entries_deleted' => '%d articles have been deleted', + 'n_feeds_actualized' => '%d feeds have been updated', + 'new_article' => 'There are new available articles, click to refresh the page.', + 'new_category' => 'New category', + 'newer_first' => 'Newer first', + 'next' => 'Next', + 'next_article' => 'Skip to the next article', + 'next_page' => 'Skip to the next page', + 'next_step' => 'Go to the next step', + 'no' => 'No', + 'no_feed_actualized' => 'No RSS feed has been updated', + 'no_feed_to_display' => 'There is no article to show.', + 'no_feed_to_refresh' => 'There is no feed to refresh…', + 'no_query' => 'You haven’t created any user query yet.', + 'no_query_filter' => 'No filter', + 'no_rss_feed' => 'No RSS feed', + 'no_selected_feed' => 'No feed selected.', + 'no_update' => 'No update to apply', + 'no_zip_extension' => 'Zip extension is not present on your server.', + 'normal_view' => 'Normal view', + 'not_read' => '%d unread', + 'not_reads' => '%d unread', + 'not_yet_implemented' => 'Not yet implemented', + 'nothing_to_load' => 'There are no more articles', + 'notif_body_new_articles' => 'There are \\d new articles to read on FreshRSS.', + 'notif_title_new_articles' => 'FreshRSS: new articles!', + 'nov' => 'nov', + 'november' => 'Nov', + 'number_articles' => '%d articles', + 'number_divided_when_reader' => 'Divided by 2 in the reading view.', + 'number_feeds' => '%d feeds', + 'oct' => 'oct', + 'october' => 'Oct', + 'ok' => 'Ok!', + 'older_first' => 'Oldest first', + 'oops' => 'Oops!', + 'optimization_complete' => 'Optimization complete', + 'optimize_bdd' => 'Optimize database', + 'optimize_todo_sometimes' => 'To do occasionally to reduce the size of the database', + 'or' => 'or', + 'page_not_found' => 'You are looking for a page which doesn’t exist', + 'password' => 'Password', + 'password_api' => 'Password API
    (e.g., for mobile apps)', + 'password_form' => 'Password
    (for the Web-form login method)', + 'pcre_is_nok' => 'You lack a required library for regular expressions (php-pcre)', + 'pcre_is_ok' => 'You have the required library for regular expressions (PCRE)', + 'pdo_is_nok' => 'You lack PDO or one of the supported drivers (pdo_mysql, pdo_sqlite)', + 'pdo_is_ok' => 'You have PDO and at least one of the supported drivers (pdo_mysql, pdo_sqlite)', + 'persona_connection_email' => 'Login mail address
    (for Mozilla Persona)', + 'persona_is_ok' => 'Permissions on Mozilla Persona directory are good', + 'php_is_nok' => 'Your PHP version is %s but FreshRSS requires at least version %s', + 'php_is_ok' => 'Your PHP version is %s, which is compatible with FreshRSS', + 'prefix' => 'Table prefix', + 'previous' => 'Previous', + 'previous_article' => 'Skip to the previous article', + 'previous_page' => 'Skip to the previous page', + 'print' => 'Print', + 'project_website' => 'Project website', + 'public' => 'Public', + 'publication_date' => 'Date of publication', + 'purge_completed' => 'Purge completed (%d articles deleted)', + 'purge_now' => 'Purge now', + 'queries' => 'User queries', + 'query_created' => 'Query "%s" has been created.', + 'query_deprecated' => 'This query is no longer valid. The referenced category or feed has been deleted.', + 'query_filter' => 'Filter applied:', + 'query_get_all' => 'Display all articles', + 'query_get_category' => 'Display "%s" category', + 'query_get_favorite' => 'Display favorite articles', + 'query_get_feed' => 'Display "%s" feed', + 'query_number' => 'Query n°%d', + 'query_order_asc' => 'Display oldest articles first', + 'query_order_desc' => 'Display newest articles first', + 'query_search' => 'Search for "%s"', + 'query_state_0' => 'Display all articles', + 'query_state_1' => 'Display read articles', + 'query_state_2' => 'Display unread articles', + 'query_state_3' => 'Display all articles', + 'query_state_4' => 'Display favorite articles', + 'query_state_5' => 'Display read favorite articles', + 'query_state_6' => 'Display unread favorite articles', + 'query_state_7' => 'Display favorite articles', + 'query_state_8' => 'Display not favorite articles', + 'query_state_9' => 'Display read not favorite articles', + 'query_state_10' => 'Display unread not favorite articles', + 'query_state_11' => 'Display not favorite articles', + 'query_state_12' => 'Display all articles', + 'query_state_13' => 'Display read articles', + 'query_state_14' => 'Display unread articles', + 'query_state_15' => 'Display all articles', + 'random_string' => 'Random string', + 'reader_view' => 'Reading view', + 'reading_configuration' => 'Reading', + 'reading_confirm' => 'Display a confirmation dialog on “mark all as read” actions', + 'refresh' => 'Refresh', + 'related_tags' => 'Related tags', + 'retrieve_truncated_feeds' => 'Retrieves truncated RSS feeds (attention, requires more time!)', + 'rss_feed_management' => 'RSS feeds management', + 'rss_feeds_of' => 'RSS feed of %s', + 'rss_view' => 'RSS feed', + 'sat' => 'Sat', + 'save' => 'Save', + 'scroll' => 'while scrolling', + 'search' => 'Search words or #tags', + 'search_short' => 'Search', + 'seconds_(0_means_no_timeout)' => 'seconds (0 means no timeout)', + 'see_on_website' => 'See on original website', + 'see_website' => 'See website', + 'sep' => 'sep', + 'september' => 'Sep', + 'shaarli' => 'Shaarli', + 'share' => 'Share', + 'share_name' => 'Share name to display', + 'share_url' => 'Share URL to use', + 'sharing' => 'Sharing', + 'sharing_management' => 'Sharing options management', + 'shift_for_all_read' => '+ shift to mark all articles as read', + 'shortcuts' => 'Shortcuts', + 'shortcuts_article_action' => 'Article actions', + 'shortcuts_navigation' => 'Navigation', + 'shortcuts_navigation_help' => 'With the "Shift" modifier, navigation shortcuts apply on feeds.
    With the "Alt" modifier, navigation shortcuts apply on categories.', + 'shortcuts_other_action' => 'Other actions', + 'shortcuts_updated' => 'Shortcuts have been updated', + 'show_adaptive' => 'Adjust showing', + 'show_all_articles' => 'Show all articles', + 'show_favorite' => 'Show only favorites', + 'show_in_all_flux' => 'Show in main stream', + 'show_not_favorite' => 'Show all but favorites', + 'show_not_reads' => 'Show only unread', + 'show_read' => 'Show only read', + 'sort_order' => 'Sort order', + 'starred_list' => 'List of favourite articles', + 'stats' => 'Statistics', + 'stats_entry_count' => 'Entry count', + 'stats_entry_per_category' => 'Entries per category', + 'stats_entry_per_day' => 'Entries per day (last 30 days)', + 'stats_entry_per_day_of_week' => 'Per day of week (average: %.2f messages)', + 'stats_entry_per_hour' => 'Per hour (average: %.2f messages)', + 'stats_entry_per_month' => 'Per month (average: %.2f messages)', + 'stats_entry_repartition' => 'Entries repartition', + 'stats_feed_per_category' => 'Feeds per category', + 'stats_idle' => 'Idle feeds', + 'stats_main' => 'Main statistics', + 'stats_no_idle' => 'There is no idle feed!', + 'stats_percent_of_total' => '%% of total', + 'stats_repartition' => 'Articles repartition', + 'stats_top_feed' => 'Top ten feeds', + 'status_favorites' => 'Favourites', + 'status_read' => 'Read', + 'status_total' => 'Total', + 'status_unread' => 'Unread', + 'steps' => 'Steps', + 'sticky_post' => 'Stick the article to the top when opened', + 'submit' => 'Submit', + 'subscription_management' => 'Subscriptions management', + 'sun' => 'Sun', + 'theme' => 'Theme', + 'think_to_add' => 'You may add some feeds.', + 'this_is_the_end' => 'This is the end', + 'thu' => 'Thu', + 'today' => 'Today', + 'top_line' => 'Top line', + 'truncate' => 'Delete all articles', + 'ttl' => 'Do not automatically refresh more often than', + 'tue' => 'Tue', + 'twitter' => 'Twitter', + 'unsafe_autologin' => 'Allow unsafe automatic login using the format: ', + 'update' => 'Update', + 'update_apply' => 'Apply', + 'update_can_apply' => 'An update is available.', + 'update_check' => 'Check for new updates', + 'update_end' => 'Update process is completed, now you can go to the final step.', + 'update_finished' => 'Update completed!', + 'update_last' => 'Last verification: %s', + 'update_long' => 'This can take a long time, depending on the size of your database. You may have to wait for this page to time out (~5 minutes) and then refresh this page.', + 'update_problem' => 'The update process has encountered an error: %s', + 'update_server_not_found' => 'Update server cannot be found. [%s]', + 'update_start' => 'Start update process', + 'update_system' => 'Update system', + 'updated' => 'Modifications have been updated', + 'upon_reception' => 'upon reception of the article', + 'user_created' => 'User %s has been created', + 'user_deleted' => 'User %s has been deleted', + 'user_filter' => 'Access user filters', + 'user_filter_help' => 'If there is only one user filter, it is used. Else filters are accessible by their number.', + 'username' => 'Username', + 'username_admin' => 'Administrator username', + 'users' => 'Users', + 'users_list' => 'List of users', + 'version' => 'Version', + 'version_update' => 'Update', + 'wallabag' => 'wallabag', + 'website' => 'Website', + 'website_url' => 'Website URL', + 'wed' => 'Wed', + 'width_large' => 'Large', + 'width_medium' => 'Medium', + 'width_no_limit' => 'No limit', + 'width_thin' => 'Thin', + 'yes' => 'Yes', + 'yesterday' => 'Yesterday', + 'your_diaspora_pod' => 'Your Diaspora* pod', + 'your_favorites' => 'Your favourites', + 'your_rss_feeds' => 'Your RSS feeds', + 'your_shaarli' => 'Your Shaarli', + 'your_wallabag' => 'Your wallabag', + 'zip_error' => 'An error occured during Zip import.', +); diff --git a/app/i18n/en/index.php b/app/i18n/en/index.php new file mode 100644 index 000000000..afca37ed3 --- /dev/null +++ b/app/i18n/en/index.php @@ -0,0 +1,5 @@ + array( + 'over_max' => 'You have reached your limit of categories (%d)', + ), + 'feeds' => array( + 'over_max' => 'You have reached your limit of feeds (%d)', + ), +); diff --git a/app/i18n/fr.php b/app/i18n/fr.php deleted file mode 100644 index c29b6c9ac..000000000 --- a/app/i18n/fr.php +++ /dev/null @@ -1,533 +0,0 @@ - '\\a\\v\\r\\i\\l', - 'Aug' => '\\a\\o\\û\\t', - 'Dec' => '\\d\\é\\c\\e\\m\\b\\r\\e', - 'Feb' => '\\f\\é\\v\\r\\i\\e\\r', - 'Jan' => '\\j\\a\\n\\v\\i\\e\\r', - 'Jul' => '\\j\\u\\i\\l\\l\\e\\t', - 'Jun' => '\\j\\u\\i\\n', - 'Mar' => '\\m\\a\\r\\s', - 'May' => '\\m\\a\\i', - 'Nov' => '\\n\\o\\v\\e\\m\\b\\r\\e', - 'Oct' => '\\o\\c\\t\\o\\b\\r\\e', - 'Sep' => '\\s\\e\\p\\t\\e\\m\\b\\r\\e', - 'about' => 'À propos', - 'about_freshrss' => 'À propos de FreshRSS', - 'access_denied' => 'Vous n’avez pas le droit d’accéder à cette page !', - 'access_protected_feeds' => 'La connexion permet d’accéder aux flux protégés par une authentification HTTP.', - 'activate_sharing' => 'Activer le partage', - 'actualize' => 'Actualiser', - 'add_category' => 'Ajouter une catégorie', - 'add_query' => 'Créer un filtre', - 'add_rss_feed' => 'Ajouter un flux RSS', - 'admin.check_install.cache.nok' => 'Veuillez vérifier les droits sur le répertoire ./data/cache. Le serveur HTTP doit être capable d’écrire dedans', - 'admin.check_install.cache.ok' => 'Les droits sur le répertoire de cache sont bons.', - 'admin.check_install.categories.nok' => 'La table category est mal configurée.', - 'admin.check_install.categories.ok' => 'La table category est bien configurée.', - 'admin.check_install.connection.nok' => 'La connexion à la base de données est impossible.', - 'admin.check_install.connection.ok' => 'La connexion à la base de données est bonne.', - 'admin.check_install.ctype.nok' => 'Il manque une librairie pour la vérification des types de caractères (php-ctype).', - 'admin.check_install.ctype.ok' => 'Vous disposez du nécessaire pour la vérification des types de caractères (ctype).', - 'admin.check_install.curl.nok' => 'Vous ne disposez pas de cURL (paquet php5-curl).', - 'admin.check_install.curl.ok' => 'Vous disposez de cURL.', - 'admin.check_install.data.nok' => 'Veuillez vérifier les droits sur le répertoire ./data. Le serveur HTTP doit être capable d’écrire dedans', - 'admin.check_install.data.ok' => 'Les droits sur le répertoire de data sont bons.', - 'admin.check_install.database' => 'Installation de la base de données', - 'admin.check_install.dom.nok' => 'Il manque une librairie pour parcourir le DOM (paquet php-xml).', - 'admin.check_install.dom.ok' => 'Vous disposez du nécessaire pour parcourir le DOM.', - 'admin.check_install.entries.nok' => 'La table entry est mal configurée.', - 'admin.check_install.entries.ok' => 'La table entry est bien configurée.', - 'admin.check_install.favicons.nok' => 'Veuillez vérifier les droits sur le répertoire ./data/favicons. Le serveur HTTP doit être capable d’écrire dedans', - 'admin.check_install.favicons.ok' => 'Les droits sur le répertoire des favicons sont bons.', - 'admin.check_install.feeds.nok' => 'La table feed est mal configurée.', - 'admin.check_install.feeds.ok' => 'La table feed est bien configurée.', - 'admin.check_install.files' => 'Installation des fichiers', - 'admin.check_install.json.nok' => 'Vous ne disposez pas de JSON (paquet php5-json).', - 'admin.check_install.json.ok' => 'Vous disposez de l\'extension JSON.', - 'admin.check_install.logs.nok' => 'Veuillez vérifier les droits sur le répertoire ./data/logs. Le serveur HTTP doit être capable d’écrire dedans', - 'admin.check_install.logs.ok' => 'Les droits sur le répertoire des logs sont bons.', - 'admin.check_install.minz.nok' => 'Vous ne disposez pas de la librairie Minz.', - 'admin.check_install.minz.ok' => 'Vous disposez du framework Minz', - 'admin.check_install.pcre.nok' => 'Il manque une librairie pour les expressions régulières (php-pcre).', - 'admin.check_install.pcre.ok' => 'Vous disposez du nécessaire pour les expressions régulières (PCRE).', - 'admin.check_install.pdo.nok' => 'Vous ne disposez pas de PDO ou d’un des drivers supportés (pdo_mysql, pdo_sqlite).', - 'admin.check_install.pdo.ok' => 'Vous disposez de PDO et d’au moins un des drivers supportés (pdo_mysql, pdo_sqlite).', - 'admin.check_install.persona.nok' => 'Veuillez vérifier les droits sur le répertoire ./data/persona. Le serveur HTTP doit être capable d’écrire dedans', - 'admin.check_install.persona.ok' => 'Les droits sur le répertoire de Mozilla Persona sont bons.', - 'admin.check_install.php' => 'Installation de PHP', - 'admin.check_install.php.nok' => 'Votre version de PHP est la %s mais FreshRSS requiert au moins la version %s.', - 'admin.check_install.php.ok' => 'Votre version de PHP est la %s, qui est compatible avec FreshRSS.', - 'admin.check_install.tables.nok' => 'Il manque une ou plusieurs tables en base de données.', - 'admin.check_install.tables.ok' => 'Les tables sont bien présentes en base de données.', - 'admin.check_install.tokens.nok' => 'Veuillez vérifier les droits sur le répertoire ./data/tokens. Le serveur HTTP doit être capable d’écrire dedans', - 'admin.check_install.tokens.ok' => 'Les droits sur le répertoire des tokens sont bons.', - 'admin.check_install.zip.nok' => 'Vous ne disposez pas de l\'extension ZIP (paquet php5-zip).', - 'admin.check_install.zip.ok' => 'Vous disposez de l\'extension ZIP.', - 'admin.users.articles_and_size' => '%s articles (%s)', - 'administration' => 'Gérer', - 'advanced' => 'Avancé', - 'after_onread' => 'Après “marquer tout comme lu”,', - 'agpl3' => 'AGPL 3', - 'all_feeds' => 'Tous les flux', - 'allow_anonymous' => 'Autoriser la lecture anonyme des articles de l’utilisateur par défaut (%s)', - 'allow_anonymous_refresh' => 'Autoriser le rafraîchissement anonyme des flux', - 'already_subscribed' => 'Vous êtes déjà abonné à %s', - 'api_enabled' => 'Autoriser l’accès par API (nécessaire pour les applis mobiles)', - 'apr' => 'avr.', - 'april' => 'avril', - 'archiving_configuration' => 'Archivage', - 'archiving_configuration_help' => 'D’autres options sont disponibles dans la configuration individuelle des flux.', - 'article' => 'Article', - 'article_icons' => 'Icônes d’article', - 'article_open_on_website' => 'lorsque l’article est ouvert sur le site d’origine', - 'article_published_on' => 'Article publié initialement sur %s', - 'article_published_on_author' => 'Article publié initialement sur %s par %s', - 'article_viewed' => 'lorsque l’article est affiché', - 'articles' => 'articles', - 'articles_per_page' => 'Nombre d’articles par page', - 'articles_to_display' => 'Articles à afficher', - 'ask_empty' => 'Vider ?', - 'attention' => 'Attention !', - 'aug' => 'août', - 'august' => 'août', - 'auth_form' => 'Formulaire (traditionnel, requiert JavaScript)', - 'auth_form_not_set' => 'Un problème est survenu lors de la configuration de votre système d’authentification. Veuillez réessayer plus tard.', - 'auth_form_set' => 'Le formulaire est désormais votre système d’authentification.', - 'auth_no_password_set' => 'Aucun mot de passe administrateur n’a été précisé. Cette fonctionnalité n’est pas disponible.', - 'auth_none' => 'Aucune (dangereux)', - 'auth_not_persona' => 'Seul le système d’authentification Persona peut être réinitialisé.', - 'auth_persona' => 'Mozilla Persona (moderne, requiert JavaScript)', - 'auth_reset' => 'Réinitialisation de l’authentification', - 'auth_token' => 'Jeton d’identification', - 'auth_type' => 'Méthode d’authentification', - 'auth_will_reset' => 'Le système d’authentification va être réinitialisé : un formulaire sera utilisé à la place de Persona.', - 'author' => 'Auteur', - 'auto_load_more' => 'Charger les articles suivants en bas de page', - 'auto_read_when' => 'Marquer un article comme lu…', - 'auto_share' => 'Partager', - 'auto_share_help' => 'S’il n’y a qu’un mode de partage, celui-ci est utilisé automatiquement. Sinon ils sont accessibles par leur numéro.', - 'back_to_rss_feeds' => '← Retour à vos flux RSS', - 'bad_opml_file' => 'Votre fichier OPML n’est pas valide.', - 'base_url' => 'Base de l’URL', - 'bdd' => 'Base de données', - 'bdd_conf_is_ko' => 'Vérifiez les informations d’accès à la base de données.', - 'bdd_conf_is_ok' => 'La configuration de la base de données a été enregistrée.', - 'bdd_configuration' => 'Base de données', - 'bdd_type' => 'Type de base de données', - 'before_one_day' => 'Antérieurs à 1 jour', - 'before_one_week' => 'Antérieurs à 1 semaine', - 'before_yesterday' => 'À partir d’avant-hier', - 'blank_to_disable' => 'Laissez vide pour désactiver', - 'blogotext' => 'Blogotext', - 'bookmark' => 'S’abonner (bookmark FreshRSS)', - 'bottom_line' => 'Ligne du bas', - 'bugs_reports' => 'Rapports de bugs', - 'by' => 'par', - 'by_author' => 'Par %s', - 'by_default' => 'Par défaut', - 'by_email' => 'Par courriel', - 'by_feed' => 'par flux', - 'cache_is_ok' => 'Les droits sur le répertoire de cache sont bons', - 'can_not_be_deleted' => 'Ne peut pas être supprimée.', - 'cancel' => 'Annuler', - 'categories' => 'Catégories', - 'categories_management' => 'Gestion des catégories', - 'categories_updated' => 'Les catégories ont été mises à jour.', - 'categorize' => 'Ranger dans une catégorie', - 'category' => 'Catégorie', - 'category_created' => 'La catégorie %s a été créée.', - 'category_deleted' => 'La catégorie a été supprimée.', - 'category_emptied' => 'La catégorie a été vidée.', - 'category_empty' => 'Catégorie vide', - 'category_name_exists' => 'Une catégorie possède déjà ce nom.', - 'category_no_id' => 'Vous devez préciser l’id de la catégorie.', - 'category_no_name' => 'Vous devez préciser un nom pour la catégorie.', - 'category_not_delete_default' => 'Vous ne pouvez pas supprimer la catégorie par défaut !', - 'category_not_exist' => 'Cette catégorie n’existe pas !', - 'category_number' => 'Catégorie n°%d', - 'category_updated' => 'La catégorie a été mise à jour.', - 'change_value' => 'Vous devriez changer cette valeur par n’importe quelle autre', - 'checks' => 'Vérifications', - 'choose_language' => 'Choisissez la langue pour FreshRSS', - 'clear_logs' => 'Effacer les logs', - 'collapse_article' => 'Refermer', - 'conf.users.articles_and_size' => '%s articles (%s)', - 'configuration' => 'Configuration', - 'configuration_updated' => 'La configuration a été mise à jour.', - 'confirm_action' => 'Êtes-vous sûr(e) de vouloir continuer ? Cette action ne peut être annulée !', - 'confirm_action_feed_cat' => 'Êtes-vous sûr(e) de vouloir continuer ? Vous perdrez les favoris et les filtres associés. Cette action ne peut être annulée !', - 'congratulations' => 'Félicitations !', - 'content_width' => 'Largeur du contenu', - 'create' => 'Créer', - 'create_user' => 'Créer un nouvel utilisateur', - 'credits' => 'Crédits', - 'credits_content' => 'Des éléments de design sont issus du projet Bootstrap bien que FreshRSS n’utilise pas ce framework. Les icônes sont issues du projet GNOME. La police Open Sans utilisée a été créée par Steve Matteson. Les favicons sont récupérés grâce au site getFavicon. FreshRSS repose sur Minz, un framework PHP.', - 'css_path_on_website' => 'Sélecteur CSS des articles sur le site d’origine', - 'ctype_is_nok' => 'Il manque une librairie pour la vérification des types de caractères (php-ctype)', - 'ctype_is_ok' => 'Vous disposez du nécessaire pour la vérification des types de caractères (ctype)', - 'curl_is_nok' => 'Vous ne disposez pas de cURL (paquet php5-curl)', - 'curl_is_ok' => 'Vous disposez de cURL dans sa version %s', - 'current_user' => 'Utilisateur actuel', - 'damn' => 'Arf !', - 'data_is_ok' => 'Les droits sur le répertoire de data sont bons', - 'dec' => 'déc.', - 'december' => 'décembre', - 'default_category' => 'Sans catégorie', - 'default_user' => 'Nom de l’utilisateur par défaut (16 caractères alphanumériques maximum)', - 'default_view' => 'Vue par défaut', - 'delete' => 'Supprimer', - 'delete_articles_every' => 'Supprimer les articles après', - 'diaspora' => 'Diaspora*', - 'display' => 'Affichage', - 'display_articles_unfolded' => 'Afficher les articles dépliés par défaut', - 'display_categories_unfolded' => 'Afficher les catégories pliées par défaut', - 'display_configuration' => 'Affichage', - 'do_not_change_if_doubt' => 'Laissez tel quel dans le doute', - 'dom_is_nok' => 'Il manque une librairie pour parcourir le DOM (paquet php-xml)', - 'dom_is_ok' => 'Vous disposez du nécessaire pour parcourir le DOM', - 'email' => 'Courriel', - 'error_occurred' => 'Une erreur est survenue !', - 'error_occurred_update' => 'Rien n’a été modifié !', - 'explain_token' => 'Permet d’accéder à la sortie RSS de l’utilisateur par défaut sans besoin de s’authentifier.
    %s?output=rss&token=%s', - 'export' => 'Exporter', - 'export_no_zip_extension' => 'L’extension Zip n’est pas présente sur votre serveur. Veuillez essayer d’exporter les fichiers un par un.', - 'export_opml' => 'Exporter la liste des flux (OPML)', - 'export_starred' => 'Exporter les favoris', - 'facebook' => 'Facebook', - 'favicons_is_ok' => 'Les droits sur le répertoire des favicons sont bons', - 'favorite_feeds' => 'Favoris (%s)', - 'feb' => 'fév.', - 'february' => 'février', - 'feed' => 'Flux', - 'feed_actualized' => '%s a été mis à jour.', - 'feed_added' => 'Le flux %s a bien été ajouté.', - 'feed_deleted' => 'Le flux a été supprimé.', - 'feed_description' => 'Description', - 'feed_empty' => 'Ce flux est vide. Veuillez vérifier qu’il est toujours maintenu.', - 'feed_in_error' => 'Ce flux a rencontré un problème. Veuillez vérifier qu’il est toujours accessible puis actualisez-le.', - 'feed_list' => 'Liste des articles de %s', - 'feed_not_added' => '%s n’a pas pu être ajouté.', - 'feed_updated' => 'Le flux a été mis à jour.', - 'feed_url' => 'URL du flux', - 'feed_validator' => 'Vérifier la valididé du flux', - 'feedback.login.error' => 'L’identifiant est invalide !', - 'feedback.login.success' => 'Vous êtes désormais connecté', - 'feedback.logout.success' => 'Vous avez été déconnecté', - 'feedback.user_profile.updated' => 'Votre profil a été mis à jour', - 'feeds' => 'Flux', - 'feeds_actualized' => 'Les flux ont été mis à jour.', - 'feeds_imported' => 'Vos flux ont été importés et vont maintenant être actualisés.', - 'feeds_imported_with_errors' => 'Vos flux ont été importés mais des erreurs sont survenues.', - 'feeds_marked_read' => 'Les flux ont été marqués comme lus.', - 'feeds_moved_category_deleted' => 'Lors de la suppression d’une catégorie, ses flux seront automatiquement classés dans %s.', - 'file_cannot_be_uploaded' => 'Le fichier ne peut pas être téléchargé !', - 'file_is_nok' => 'Veuillez vérifier les droits sur le répertoire %s. Le serveur HTTP doit être capable d’écrire dedans', - 'file_to_import' => 'Fichier à importer
    (OPML, Json ou Zip)', - 'file_to_import_no_zip' => 'Fichier à importer
    (OPML ou Json)', - 'filter' => 'Filtrer', - 'finish_installation' => 'Terminer l’installation', - 'first' => 'Début', - 'first_article' => 'Passer au premier article', - 'fix_errors_before' => 'Veuillez corriger les erreurs avant de passer à l’étape suivante.', - 'focus_search' => 'Accéder à la recherche', - 'format_date' => 'j %s Y', - 'format_date_hour' => 'j %s Y \\à H\\:i', - 'freshrss' => 'FreshRSS', - 'freshrss_description' => 'FreshRSS est un agrégateur de flux RSS à auto-héberger à l’image de Kriss Feed ou Leed. Il se veut léger et facile à prendre en main tout en étant un outil puissant et paramétrable.', - 'freshrss_installation' => 'Installation · FreshRSS', - 'fri' => 'ven.', - 'g+' => 'Google+', - 'gen.menu.admin' => 'Administration', - 'gen.menu.authentication' => 'Authentification', - 'gen.menu.check_install' => 'Vérification de l\'installation', - 'gen.menu.user_management' => 'Gestion des utilisateurs', - 'gen.menu.user_profile' => 'Profil', - 'gen.title.authentication' => 'Authentification', - 'gen.title.check_install' => 'Vérification de l\'installation', - 'gen.title.global_view' => 'Vue globale', - 'gen.title.user_management' => 'Gestion des utilisateurs', - 'gen.title.user_profile' => 'Profil', - 'general_conf_is_ok' => 'La configuration générale a été enregistrée.', - 'general_configuration' => 'Configuration générale', - 'github_or_email' => 'sur Github ou par courriel', - 'global_view' => 'Vue globale', - 'help' => 'Afficher la documentation', - 'hide_read_feeds' => 'Cacher les catégories & flux sans article non-lu (ne fonctionne pas avec la configuration “Afficher tous les articles”)', - 'host' => 'Hôte', - 'html5_notif_timeout' => 'Temps d’affichage de la notification HTML5', - 'http_auth' => 'HTTP (pour utilisateurs avancés avec HTTPS)', - 'http_authentication' => 'Authentification HTTP', - 'http_password' => 'Mot de passe HTTP', - 'http_referer_is_nok' => 'Veuillez vérifier que vous ne modifiez pas votre HTTP REFERER.', - 'http_referer_is_ok' => 'Le HTTP REFERER est connu et semble correspondre à votre serveur.', - 'http_username' => 'Identifiant HTTP', - 'img_with_lazyload' => 'Utiliser le mode “chargement différé” pour les images', - 'import' => 'Importer', - 'import_export' => 'Importer / exporter', - 'informations' => 'Informations', - 'install_not_deleted' => 'Quelque chose s’est mal passé, vous devez supprimer le fichier %s à la main.', - 'installation_is_ok' => 'L’installation s’est bien passée.
    La dernière étape va maintenant tenter de supprimer les fichiers ainsi que d’éventuelles copies de base de données créés durant le processus de mise à jour.
    Vous pouvez choisir de sauter cette étape en supprimant ./data/do-install.txt manuellement.', - 'installation_step' => 'Installation — étape %d · FreshRSS', - 'internal_problem_feed' => 'Le flux ne peut pas être ajouté. Consulter les logs de FreshRSS pour plus de détails.', - 'invalid_login' => 'L’identifiant est invalide !', - 'invalid_url' => 'L’url %s est invalide.', - 'is_admin' => 'est administrateur', - 'jan' => 'jan.', - 'january' => 'janvier', - 'javascript_for_shortcuts' => 'Le JavaScript doit être activé pour pouvoir profiter des raccourcis.', - 'javascript_is_better' => 'FreshRSS est plus agréable à utiliser avec JavaScript activé', - 'javascript_should_be_activated' => 'Le JavaScript doit être activé.', - 'jul' => 'jui.', - 'july' => 'juillet', - 'jump_next' => 'sauter au prochain voisin non lu (flux ou catégorie)', - 'jun' => 'juin', - 'june' => 'juin', - 'keep_history' => 'Nombre minimum d’articles à conserver', - 'keep_logged_in' => 'Rester connecté (1 mois)', - 'language' => 'Langue', - 'language_defined' => 'La langue a bien été définie.', - 'last' => 'Fin', - 'last_3_month' => 'Depuis les trois derniers mois', - 'last_6_month' => 'Depuis les six derniers mois', - 'last_article' => 'Passer au dernier article', - 'last_month' => 'Depuis le mois dernier', - 'last_week' => 'Depuis la semaine dernière', - 'last_year' => 'Depuis l’année dernière', - 'lead_developer' => 'Développeur principal', - 'license' => 'Licence', - 'load_more' => 'Charger plus d’articles', - 'log_is_ok' => 'Les droits sur le répertoire des logs sont bons', - 'login' => 'Connexion', - 'login_configuration' => 'Identification', - 'login_persona_problem' => 'Problème de connexion à Persona ?', - 'login_required' => 'Accès protégé par mot de passe :', - 'login_with_persona' => 'Connexion avec Persona', - 'logout' => 'Déconnexion', - 'logs' => 'Logs', - 'logs_empty' => 'Les logs sont vides.', - 'main_stream' => 'Flux principal', - 'mar' => 'mar.', - 'march' => 'mars', - 'mark_all_read' => 'Tout marquer comme lu', - 'mark_cat_read' => 'Marquer la catégorie comme lue', - 'mark_favorite' => 'Mettre en favori', - 'mark_feed_read' => 'Marquer le flux comme lu', - 'mark_read' => 'Marquer comme lu', - 'may' => 'mai.', - 'minz_is_nok' => 'Vous ne disposez pas de la librairie Minz. Vous devriez exécuter le script build.sh ou bien la télécharger sur Github et installer dans le répertoire %s le contenu de son répertoire /lib.', - 'minz_is_ok' => 'Vous disposez du framework Minz', - 'mon' => 'lun.', - 'month' => 'mois', - 'more_information' => 'Plus d’informations', - 'n_entries_deleted' => '%d articles ont été supprimés.', - 'n_feeds_actualized' => '%d flux ont été mis à jour.', - 'new_article' => 'Il y a de nouveaux articles disponibles, cliquez pour rafraîchir la page.', - 'new_category' => 'Nouvelle catégorie', - 'newer_first' => 'Plus récents en premier', - 'next' => 'Suivant', - 'next_article' => 'Passer à l’article suivant', - 'next_page' => 'Passer à la page suivante', - 'next_step' => 'Passer à l’étape suivante', - 'no' => 'Non', - 'no_feed_actualized' => 'Aucun flux n’a pu être mis à jour.', - 'no_feed_to_display' => 'Il n’y a aucun article à afficher.', - 'no_feed_to_refresh' => 'Il n’y a aucun flux à actualiser…', - 'no_query' => 'Vous n’avez pas encore créé de filtre.', - 'no_query_filter' => 'Aucun filtre appliqué', - 'no_rss_feed' => 'Aucun flux RSS', - 'no_selected_feed' => 'Aucun flux sélectionné.', - 'no_update' => 'Aucune mise à jour à appliquer', - 'no_zip_extension' => 'L’extension Zip n’est pas présente sur votre serveur.', - 'normal_view' => 'Vue normale', - 'not_read' => '%d non lu', - 'not_reads' => '%d non lus', - 'not_yet_implemented' => 'Pas encore implémenté', - 'nothing_to_load' => 'Fin des articles', - 'notif_body_new_articles' => 'Il y a \\d nouveaux articles à lire sur FreshRSS.', - 'notif_title_new_articles' => 'FreshRSS : nouveaux articles !', - 'nov' => 'nov.', - 'november' => 'novembre', - 'number_articles' => '%d articles', - 'number_divided_when_reader' => 'Divisé par 2 dans la vue de lecture.', - 'number_feeds' => '%d flux', - 'oct' => 'oct.', - 'october' => 'octobre', - 'ok' => 'Ok !', - 'older_first' => 'Plus anciens en premier', - 'oops' => 'Oups !', - 'optimization_complete' => 'Optimisation terminée.', - 'optimize_bdd' => 'Optimiser la base de données', - 'optimize_todo_sometimes' => 'À faire de temps en temps pour réduire la taille de la BDD', - 'or' => 'ou', - 'page_not_found' => 'La page que vous cherchez n’existe pas !', - 'password' => 'Mot de passe', - 'password_api' => 'Mot de passe API
    (ex. : pour applis mobiles)', - 'password_form' => 'Mot de passe
    (pour connexion par formulaire)', - 'pcre_is_nok' => 'Il manque une librairie pour les expressions régulières (php-pcre)', - 'pcre_is_ok' => 'Vous disposez du nécessaire pour les expressions régulières (PCRE)', - 'pdo_is_nok' => 'Vous ne disposez pas de PDO ou d’un des drivers supportés (pdo_mysql, pdo_sqlite)', - 'pdo_is_ok' => 'Vous disposez de PDO et d’au moins un des drivers supportés (pdo_mysql, pdo_sqlite)', - 'persona_connection_email' => 'Adresse courriel de connexion
    (pour Mozilla Persona)', - 'persona_is_ok' => 'Les droits sur le répertoire de Mozilla Persona sont bons', - 'php_is_nok' => 'Votre version de PHP est la %s mais FreshRSS requiert au moins la version %s', - 'php_is_ok' => 'Votre version de PHP est la %s, qui est compatible avec FreshRSS', - 'prefix' => 'Préfixe des tables', - 'previous' => 'Précédent', - 'previous_article' => 'Passer à l’article précédent', - 'previous_page' => 'Passer à la page précédente', - 'print' => 'Imprimer', - 'project_website' => 'Site du projet', - 'public' => 'Public', - 'publication_date' => 'Date de publication', - 'purge_completed' => 'Purge effectuée (%d articles supprimés).', - 'purge_now' => 'Purger maintenant', - 'queries' => 'Filtres utilisateurs', - 'query_created' => 'Le filtre "%s" a bien été créé.', - 'query_deprecated' => 'Ce filtre n’est plus valide. La catégorie ou le flux concerné a été supprimé.', - 'query_filter' => 'Filtres appliqués :', - 'query_get_all' => 'Afficher tous les articles', - 'query_get_category' => 'Afficher la catégorie "%s"', - 'query_get_favorite' => 'Afficher les articles favoris', - 'query_get_feed' => 'Afficher le flux "%s"', - 'query_number' => 'Filtre n°%d', - 'query_order_asc' => 'Afficher les articles les plus anciens en premier', - 'query_order_desc' => 'Afficher les articles les plus récents en premier', - 'query_search' => 'Recherche de "%s"', - 'query_state_0' => 'Afficher tous les articles', - 'query_state_1' => 'Afficher les articles lus', - 'query_state_2' => 'Afficher les articles non lus', - 'query_state_3' => 'Afficher tous les articles', - 'query_state_4' => 'Afficher les articles favoris', - 'query_state_5' => 'Afficher les articles lus et favoris', - 'query_state_6' => 'Afficher les articles non lus et favoris', - 'query_state_7' => 'Afficher les articles favoris', - 'query_state_8' => 'Afficher les articles non favoris', - 'query_state_9' => 'Afficher les articles lus et non favoris', - 'query_state_10' => 'Afficher les articles non lus et non favoris', - 'query_state_11' => 'Afficher les articles non favoris', - 'query_state_12' => 'Afficher tous les articles', - 'query_state_13' => 'Afficher les articles lus', - 'query_state_14' => 'Afficher les articles non lus', - 'query_state_15' => 'Afficher tous les articles', - 'random_string' => 'Chaîne aléatoire', - 'reader_view' => 'Vue lecture', - 'reading_configuration' => 'Lecture', - 'reading_confirm' => 'Afficher une confirmation lors des actions “marquer tout comme lu”', - 'refresh' => 'Actualisation', - 'related_tags' => 'Tags associés', - 'retrieve_truncated_feeds' => 'Permet de récupérer les flux tronqués (attention, demande plus de temps !)', - 'rss_feed_management' => 'Gestion des flux RSS', - 'rss_feeds_of' => 'Flux RSS de %s', - 'rss_view' => 'Flux RSS', - 'sat' => 'sam.', - 'save' => 'Enregistrer', - 'scroll' => 'au défilement de la page', - 'search' => 'Rechercher des mots ou des #tags', - 'search_short' => 'Rechercher', - 'seconds_(0_means_no_timeout)' => 'secondes (0 signifie aucun timeout ) ', - 'see_on_website' => 'Voir sur le site d’origine', - 'see_website' => 'Voir le site', - 'sep' => 'sep.', - 'september' => 'septembre', - 'shaarli' => 'Shaarli', - 'share' => 'Partager', - 'share_name' => 'Nom du partage à afficher', - 'share_url' => 'URL du partage à utiliser', - 'sharing' => 'Partage', - 'sharing_management' => 'Gestion des options de partage', - 'shift_for_all_read' => '+ shift pour marquer tous les articles comme lus', - 'shortcuts' => 'Raccourcis', - 'shortcuts_article_action' => 'Actions associées à l’article courant', - 'shortcuts_navigation' => 'Navigation', - 'shortcuts_navigation_help' => 'Avec le modificateur "Shift", les raccourcis de navigation s’appliquent aux flux.
    Avec le modificateur "Alt", les raccourcis de navigation s’appliquent aux catégories.', - 'shortcuts_other_action' => 'Autres actions', - 'shortcuts_updated' => 'Les raccourcis ont été mis à jour.', - 'show_adaptive' => 'Adapter l’affichage', - 'show_all_articles' => 'Afficher tous les articles', - 'show_favorite' => 'Afficher les favoris', - 'show_in_all_flux' => 'Afficher dans le flux principal', - 'show_not_favorite' => 'Afficher tout sauf les favoris', - 'show_not_reads' => 'Afficher les non lus', - 'show_read' => 'Afficher les lus', - 'sort_order' => 'Ordre de tri', - 'starred_list' => 'Liste des articles favoris', - 'stats' => 'Statistiques', - 'stats_entry_count' => 'Nombre d’articles', - 'stats_entry_per_category' => 'Articles par catégorie', - 'stats_entry_per_day' => 'Nombre d’articles par jour (30 derniers jours)', - 'stats_entry_per_day_of_week' => 'Par jour de la semaine (moyenne : %.2f messages)', - 'stats_entry_per_hour' => 'Par heure (moyenne : %.2f messages)', - 'stats_entry_per_month' => 'Par mois (moyenne : %.2f messages)', - 'stats_entry_repartition' => 'Répartition des articles', - 'stats_feed_per_category' => 'Flux par catégorie', - 'stats_idle' => 'Flux inactifs', - 'stats_main' => 'Statistiques principales', - 'stats_no_idle' => 'Il n’y a aucun flux inactif !', - 'stats_percent_of_total' => '%% du total', - 'stats_repartition' => 'Répartition des articles', - 'stats_top_feed' => 'Les dix plus gros flux', - 'status_favorites' => 'favoris', - 'status_read' => 'lus', - 'status_total' => 'total', - 'status_unread' => 'non lus', - 'steps' => 'Étapes', - 'sticky_post' => 'Aligner l’article en haut quand il est ouvert', - 'sub.categories.over_max' => 'Vous avez atteint votre limite de catégories (%d)', - 'sub.feeds.over_max' => 'Vous avez atteint votre limite de flux (%d)', - 'submit' => 'Valider', - 'subscription_management' => 'Gestion des abonnements', - 'sun' => 'dim.', - 'theme' => 'Thème', - 'think_to_add' => 'Vous pouvez ajouter des flux.', - 'this_is_the_end' => 'This is the end', - 'thu' => 'jeu.', - 'title' => 'Titre', - 'today' => 'Aujourd’hui', - 'top_line' => 'Ligne du haut', - 'truncate' => 'Supprimer tous les articles', - 'ttl' => 'Ne pas automatiquement rafraîchir plus souvent que', - 'tue' => 'mar.', - 'twitter' => 'Twitter', - 'unsafe_autologin' => 'Autoriser les connexions automatiques non-sûres au format : ', - 'update' => 'Mise à jour', - 'update_apply' => 'Appliquer la mise à jour', - 'update_can_apply' => 'Une mise à jour est disponible.', - 'update_check' => 'Vérifier les mises à jour', - 'update_end' => 'La mise à jour est terminée, vous pouvez maintenant passer à l’étape finale.', - 'update_finished' => 'La mise à jour est terminée !', - 'update_last' => 'Dernière vérification : %s', - 'update_long' => 'Ce processus peut prendre longtemps, selon la taille de votre base de données. Vous aurez peut-être à attendre que cette page dépasse son temps maximum d’exécution (~5 minutes) puis à la recharger.', - 'update_problem' => 'La mise à jour a rencontré un problème : %s', - 'update_server_not_found' => 'Le serveur de mise à jour n’a pas été trouvé. [%s]', - 'update_start' => 'Lancer la mise à jour', - 'update_system' => 'Système de mise à jour', - 'updated' => 'Modifications enregistrées.', - 'upon_reception' => 'dès la réception du nouvel article', - 'user_created' => 'L’utilisateur %s a été créé.', - 'user_deleted' => 'L’utilisateur %s a été supprimé.', - 'user_filter' => 'Accéder aux filtres utilisateur', - 'user_filter_help' => 'S’il n’y a qu’un filtre utilisateur, celui-ci est utilisé automatiquement. Sinon ils sont accessibles par leur numéro.', - 'username' => 'Nom d’utilisateur', - 'username_admin' => 'Nom d’utilisateur administrateur', - 'users' => 'Utilisateurs', - 'users_list' => 'Liste des utilisateurs', - 'version' => 'Version', - 'version_update' => 'Mise à jour', - 'wallabag' => 'wallabag', - 'website' => 'Site Internet', - 'website_url' => 'URL du site', - 'wed' => 'mer.', - 'width_large' => 'Large', - 'width_medium' => 'Moyenne', - 'width_no_limit' => 'Pas de limite', - 'width_thin' => 'Fine', - 'yes' => 'Oui', - 'yesterday' => 'Hier', - 'your_diaspora_pod' => 'Votre pod Diaspora*', - 'your_favorites' => 'Vos favoris', - 'your_rss_feeds' => 'Vos flux RSS', - 'your_shaarli' => 'Votre Shaarli', - 'your_wallabag' => 'Votre wallabag', - 'zip_error' => 'Une erreur est survenue durant l’import du fichier Zip.', -); \ No newline at end of file diff --git a/app/i18n/fr/admin.php b/app/i18n/fr/admin.php new file mode 100644 index 000000000..ad1fae6c0 --- /dev/null +++ b/app/i18n/fr/admin.php @@ -0,0 +1,92 @@ + array( + 'cache' => array( + 'nok' => 'Veuillez vérifier les droits sur le répertoire ./data/cache. Le serveur HTTP doit être capable d’écrire dedans', + 'ok' => 'Les droits sur le répertoire de cache sont bons.', + ), + 'categories' => array( + 'nok' => 'La table category est mal configurée.', + 'ok' => 'La table category est bien configurée.', + ), + 'connection' => array( + 'nok' => 'La connexion à la base de données est impossible.', + 'ok' => 'La connexion à la base de données est bonne.', + ), + 'ctype' => array( + 'nok' => 'Il manque une librairie pour la vérification des types de caractères (php-ctype).', + 'ok' => 'Vous disposez du nécessaire pour la vérification des types de caractères (ctype).', + ), + 'curl' => array( + 'nok' => 'Vous ne disposez pas de cURL (paquet php5-curl).', + 'ok' => 'Vous disposez de cURL.', + ), + 'data' => array( + 'nok' => 'Veuillez vérifier les droits sur le répertoire ./data. Le serveur HTTP doit être capable d’écrire dedans', + 'ok' => 'Les droits sur le répertoire de data sont bons.', + ), + 'database' => 'Installation de la base de données', + 'dom' => array( + 'nok' => 'Il manque une librairie pour parcourir le DOM (paquet php-xml).', + 'ok' => 'Vous disposez du nécessaire pour parcourir le DOM.', + ), + 'entries' => array( + 'nok' => 'La table entry est mal configurée.', + 'ok' => 'La table entry est bien configurée.', + ), + 'favicons' => array( + 'nok' => 'Veuillez vérifier les droits sur le répertoire ./data/favicons. Le serveur HTTP doit être capable d’écrire dedans', + 'ok' => 'Les droits sur le répertoire des favicons sont bons.', + ), + 'feeds' => array( + 'nok' => 'La table feed est mal configurée.', + 'ok' => 'La table feed est bien configurée.', + ), + 'files' => 'Installation des fichiers', + 'json' => array( + 'nok' => 'Vous ne disposez pas de JSON (paquet php5-json).', + 'ok' => 'Vous disposez de l\'extension JSON.', + ), + 'logs' => array( + 'nok' => 'Veuillez vérifier les droits sur le répertoire ./data/logs. Le serveur HTTP doit être capable d’écrire dedans', + 'ok' => 'Les droits sur le répertoire des logs sont bons.', + ), + 'minz' => array( + 'nok' => 'Vous ne disposez pas de la librairie Minz.', + 'ok' => 'Vous disposez du framework Minz', + ), + 'pcre' => array( + 'nok' => 'Il manque une librairie pour les expressions régulières (php-pcre).', + 'ok' => 'Vous disposez du nécessaire pour les expressions régulières (PCRE).', + ), + 'pdo' => array( + 'nok' => 'Vous ne disposez pas de PDO ou d’un des drivers supportés (pdo_mysql, pdo_sqlite).', + 'ok' => 'Vous disposez de PDO et d’au moins un des drivers supportés (pdo_mysql, pdo_sqlite).', + ), + 'persona' => array( + 'nok' => 'Veuillez vérifier les droits sur le répertoire ./data/persona. Le serveur HTTP doit être capable d’écrire dedans', + 'ok' => 'Les droits sur le répertoire de Mozilla Persona sont bons.', + ), + 'php' => array( + '_' => 'Installation de PHP', + 'nok' => 'Votre version de PHP est la %s mais FreshRSS requiert au moins la version %s.', + 'ok' => 'Votre version de PHP est la %s, qui est compatible avec FreshRSS.', + ), + 'tables' => array( + 'nok' => 'Il manque une ou plusieurs tables en base de données.', + 'ok' => 'Les tables sont bien présentes en base de données.', + ), + 'tokens' => array( + 'nok' => 'Veuillez vérifier les droits sur le répertoire ./data/tokens. Le serveur HTTP doit être capable d’écrire dedans', + 'ok' => 'Les droits sur le répertoire des tokens sont bons.', + ), + 'zip' => array( + 'nok' => 'Vous ne disposez pas de l\'extension ZIP (paquet php5-zip).', + 'ok' => 'Vous disposez de l\'extension ZIP.', + ), + ), + 'users' => array( + 'articles_and_size' => '%s articles (%s)', + ), +); diff --git a/app/i18n/fr/conf.php b/app/i18n/fr/conf.php new file mode 100644 index 000000000..460804774 --- /dev/null +++ b/app/i18n/fr/conf.php @@ -0,0 +1,7 @@ + array( + 'articles_and_size' => '%s articles (%s)', + ), +); diff --git a/app/i18n/fr/feedback.php b/app/i18n/fr/feedback.php new file mode 100644 index 000000000..f4bb7cccf --- /dev/null +++ b/app/i18n/fr/feedback.php @@ -0,0 +1,14 @@ + array( + 'error' => 'L’identifiant est invalide !', + 'success' => 'Vous êtes désormais connecté', + ), + 'logout' => array( + 'success' => 'Vous avez été déconnecté', + ), + 'user_profile' => array( + 'updated' => 'Votre profil a été mis à jour', + ), +); diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php new file mode 100644 index 000000000..8a4a9750b --- /dev/null +++ b/app/i18n/fr/gen.php @@ -0,0 +1,487 @@ + '\\a\\v\\r\\i\\l', + 'Aug' => '\\a\\o\\û\\t', + 'Dec' => '\\d\\é\\c\\e\\m\\b\\r\\e', + 'Feb' => '\\f\\é\\v\\r\\i\\e\\r', + 'Jan' => '\\j\\a\\n\\v\\i\\e\\r', + 'Jul' => '\\j\\u\\i\\l\\l\\e\\t', + 'Jun' => '\\j\\u\\i\\n', + 'Mar' => '\\m\\a\\r\\s', + 'May' => '\\m\\a\\i', + 'Nov' => '\\n\\o\\v\\e\\m\\b\\r\\e', + 'Oct' => '\\o\\c\\t\\o\\b\\r\\e', + 'Sep' => '\\s\\e\\p\\t\\e\\m\\b\\r\\e', + 'about' => 'À propos', + 'about_freshrss' => 'À propos de FreshRSS', + 'access_denied' => 'Vous n’avez pas le droit d’accéder à cette page !', + 'access_protected_feeds' => 'La connexion permet d’accéder aux flux protégés par une authentification HTTP.', + 'activate_sharing' => 'Activer le partage', + 'actualize' => 'Actualiser', + 'add_category' => 'Ajouter une catégorie', + 'add_query' => 'Créer un filtre', + 'add_rss_feed' => 'Ajouter un flux RSS', + 'administration' => 'Gérer', + 'advanced' => 'Avancé', + 'after_onread' => 'Après “marquer tout comme lu”,', + 'agpl3' => 'AGPL 3', + 'all_feeds' => 'Tous les flux', + 'allow_anonymous' => 'Autoriser la lecture anonyme des articles de l’utilisateur par défaut (%s)', + 'allow_anonymous_refresh' => 'Autoriser le rafraîchissement anonyme des flux', + 'already_subscribed' => 'Vous êtes déjà abonné à %s', + 'api_enabled' => 'Autoriser l’accès par API (nécessaire pour les applis mobiles)', + 'apr' => 'avr.', + 'april' => 'avril', + 'archiving_configuration' => 'Archivage', + 'archiving_configuration_help' => 'D’autres options sont disponibles dans la configuration individuelle des flux.', + 'article' => 'Article', + 'article_icons' => 'Icônes d’article', + 'article_open_on_website' => 'lorsque l’article est ouvert sur le site d’origine', + 'article_published_on' => 'Article publié initialement sur %s', + 'article_published_on_author' => 'Article publié initialement sur %s par %s', + 'article_viewed' => 'lorsque l’article est affiché', + 'articles' => 'articles', + 'articles_per_page' => 'Nombre d’articles par page', + 'articles_to_display' => 'Articles à afficher', + 'ask_empty' => 'Vider ?', + 'attention' => 'Attention !', + 'aug' => 'août', + 'august' => 'août', + 'auth_form' => 'Formulaire (traditionnel, requiert JavaScript)', + 'auth_form_not_set' => 'Un problème est survenu lors de la configuration de votre système d’authentification. Veuillez réessayer plus tard.', + 'auth_form_set' => 'Le formulaire est désormais votre système d’authentification.', + 'auth_no_password_set' => 'Aucun mot de passe administrateur n’a été précisé. Cette fonctionnalité n’est pas disponible.', + 'auth_none' => 'Aucune (dangereux)', + 'auth_not_persona' => 'Seul le système d’authentification Persona peut être réinitialisé.', + 'auth_persona' => 'Mozilla Persona (moderne, requiert JavaScript)', + 'auth_reset' => 'Réinitialisation de l’authentification', + 'auth_token' => 'Jeton d’identification', + 'auth_type' => 'Méthode d’authentification', + 'auth_will_reset' => 'Le système d’authentification va être réinitialisé : un formulaire sera utilisé à la place de Persona.', + 'author' => 'Auteur', + 'auto_load_more' => 'Charger les articles suivants en bas de page', + 'auto_read_when' => 'Marquer un article comme lu…', + 'auto_share' => 'Partager', + 'auto_share_help' => 'S’il n’y a qu’un mode de partage, celui-ci est utilisé automatiquement. Sinon ils sont accessibles par leur numéro.', + 'back_to_rss_feeds' => '← Retour à vos flux RSS', + 'bad_opml_file' => 'Votre fichier OPML n’est pas valide.', + 'base_url' => 'Base de l’URL', + 'bdd' => 'Base de données', + 'bdd_conf_is_ko' => 'Vérifiez les informations d’accès à la base de données.', + 'bdd_conf_is_ok' => 'La configuration de la base de données a été enregistrée.', + 'bdd_configuration' => 'Base de données', + 'bdd_type' => 'Type de base de données', + 'before_one_day' => 'Antérieurs à 1 jour', + 'before_one_week' => 'Antérieurs à 1 semaine', + 'before_yesterday' => 'À partir d’avant-hier', + 'blank_to_disable' => 'Laissez vide pour désactiver', + 'blogotext' => 'Blogotext', + 'bookmark' => 'S’abonner (bookmark FreshRSS)', + 'bottom_line' => 'Ligne du bas', + 'bugs_reports' => 'Rapports de bugs', + 'by' => 'par', + 'by_author' => 'Par %s', + 'by_default' => 'Par défaut', + 'by_email' => 'Par courriel', + 'by_feed' => 'par flux', + 'cache_is_ok' => 'Les droits sur le répertoire de cache sont bons', + 'can_not_be_deleted' => 'Ne peut pas être supprimée.', + 'cancel' => 'Annuler', + 'categories' => 'Catégories', + 'categories_management' => 'Gestion des catégories', + 'categories_updated' => 'Les catégories ont été mises à jour.', + 'categorize' => 'Ranger dans une catégorie', + 'category' => 'Catégorie', + 'category_created' => 'La catégorie %s a été créée.', + 'category_deleted' => 'La catégorie a été supprimée.', + 'category_emptied' => 'La catégorie a été vidée.', + 'category_empty' => 'Catégorie vide', + 'category_name_exists' => 'Une catégorie possède déjà ce nom.', + 'category_no_id' => 'Vous devez préciser l’id de la catégorie.', + 'category_no_name' => 'Vous devez préciser un nom pour la catégorie.', + 'category_not_delete_default' => 'Vous ne pouvez pas supprimer la catégorie par défaut !', + 'category_not_exist' => 'Cette catégorie n’existe pas !', + 'category_number' => 'Catégorie n°%d', + 'category_updated' => 'La catégorie a été mise à jour.', + 'change_value' => 'Vous devriez changer cette valeur par n’importe quelle autre', + 'checks' => 'Vérifications', + 'choose_language' => 'Choisissez la langue pour FreshRSS', + 'clear_logs' => 'Effacer les logs', + 'collapse_article' => 'Refermer', + 'configuration' => 'Configuration', + 'configuration_updated' => 'La configuration a été mise à jour.', + 'confirm_action' => 'Êtes-vous sûr(e) de vouloir continuer ? Cette action ne peut être annulée !', + 'confirm_action_feed_cat' => 'Êtes-vous sûr(e) de vouloir continuer ? Vous perdrez les favoris et les filtres associés. Cette action ne peut être annulée !', + 'congratulations' => 'Félicitations !', + 'content_width' => 'Largeur du contenu', + 'create' => 'Créer', + 'create_user' => 'Créer un nouvel utilisateur', + 'credits' => 'Crédits', + 'credits_content' => 'Des éléments de design sont issus du projet Bootstrap bien que FreshRSS n’utilise pas ce framework. Les icônes sont issues du projet GNOME. La police Open Sans utilisée a été créée par Steve Matteson. Les favicons sont récupérés grâce au site getFavicon. FreshRSS repose sur Minz, un framework PHP.', + 'css_path_on_website' => 'Sélecteur CSS des articles sur le site d’origine', + 'ctype_is_nok' => 'Il manque une librairie pour la vérification des types de caractères (php-ctype)', + 'ctype_is_ok' => 'Vous disposez du nécessaire pour la vérification des types de caractères (ctype)', + 'curl_is_nok' => 'Vous ne disposez pas de cURL (paquet php5-curl)', + 'curl_is_ok' => 'Vous disposez de cURL dans sa version %s', + 'current_user' => 'Utilisateur actuel', + 'damn' => 'Arf !', + 'data_is_ok' => 'Les droits sur le répertoire de data sont bons', + 'dec' => 'déc.', + 'december' => 'décembre', + 'default_category' => 'Sans catégorie', + 'default_user' => 'Nom de l’utilisateur par défaut (16 caractères alphanumériques maximum)', + 'default_view' => 'Vue par défaut', + 'delete' => 'Supprimer', + 'delete_articles_every' => 'Supprimer les articles après', + 'diaspora' => 'Diaspora*', + 'display' => 'Affichage', + 'display_articles_unfolded' => 'Afficher les articles dépliés par défaut', + 'display_categories_unfolded' => 'Afficher les catégories pliées par défaut', + 'display_configuration' => 'Affichage', + 'do_not_change_if_doubt' => 'Laissez tel quel dans le doute', + 'dom_is_nok' => 'Il manque une librairie pour parcourir le DOM (paquet php-xml)', + 'dom_is_ok' => 'Vous disposez du nécessaire pour parcourir le DOM', + 'email' => 'Courriel', + 'error_occurred' => 'Une erreur est survenue !', + 'error_occurred_update' => 'Rien n’a été modifié !', + 'explain_token' => 'Permet d’accéder à la sortie RSS de l’utilisateur par défaut sans besoin de s’authentifier.
    %s?output=rss&token=%s', + 'export' => 'Exporter', + 'export_no_zip_extension' => 'L’extension Zip n’est pas présente sur votre serveur. Veuillez essayer d’exporter les fichiers un par un.', + 'export_opml' => 'Exporter la liste des flux (OPML)', + 'export_starred' => 'Exporter les favoris', + 'facebook' => 'Facebook', + 'favicons_is_ok' => 'Les droits sur le répertoire des favicons sont bons', + 'favorite_feeds' => 'Favoris (%s)', + 'feb' => 'fév.', + 'february' => 'février', + 'feed' => 'Flux', + 'feed_actualized' => '%s a été mis à jour.', + 'feed_added' => 'Le flux %s a bien été ajouté.', + 'feed_deleted' => 'Le flux a été supprimé.', + 'feed_description' => 'Description', + 'feed_empty' => 'Ce flux est vide. Veuillez vérifier qu’il est toujours maintenu.', + 'feed_in_error' => 'Ce flux a rencontré un problème. Veuillez vérifier qu’il est toujours accessible puis actualisez-le.', + 'feed_list' => 'Liste des articles de %s', + 'feed_not_added' => '%s n’a pas pu être ajouté.', + 'feed_updated' => 'Le flux a été mis à jour.', + 'feed_url' => 'URL du flux', + 'feed_validator' => 'Vérifier la valididé du flux', + 'feeds' => 'Flux', + 'feeds_actualized' => 'Les flux ont été mis à jour.', + 'feeds_imported' => 'Vos flux ont été importés et vont maintenant être actualisés.', + 'feeds_imported_with_errors' => 'Vos flux ont été importés mais des erreurs sont survenues.', + 'feeds_marked_read' => 'Les flux ont été marqués comme lus.', + 'feeds_moved_category_deleted' => 'Lors de la suppression d’une catégorie, ses flux seront automatiquement classés dans %s.', + 'file_cannot_be_uploaded' => 'Le fichier ne peut pas être téléchargé !', + 'file_is_nok' => 'Veuillez vérifier les droits sur le répertoire %s. Le serveur HTTP doit être capable d’écrire dedans', + 'file_to_import' => 'Fichier à importer
    (OPML, Json ou Zip)', + 'file_to_import_no_zip' => 'Fichier à importer
    (OPML ou Json)', + 'filter' => 'Filtrer', + 'finish_installation' => 'Terminer l’installation', + 'first' => 'Début', + 'first_article' => 'Passer au premier article', + 'fix_errors_before' => 'Veuillez corriger les erreurs avant de passer à l’étape suivante.', + 'focus_search' => 'Accéder à la recherche', + 'format_date' => 'j %s Y', + 'format_date_hour' => 'j %s Y \\à H\\:i', + 'freshrss' => 'FreshRSS', + 'freshrss_description' => 'FreshRSS est un agrégateur de flux RSS à auto-héberger à l’image de Kriss Feed ou Leed. Il se veut léger et facile à prendre en main tout en étant un outil puissant et paramétrable.', + 'freshrss_installation' => 'Installation · FreshRSS', + 'fri' => 'ven.', + 'g+' => 'Google+', + 'menu' => array( + 'admin' => 'Administration', + 'authentication' => 'Authentification', + 'check_install' => 'Vérification de l’installation', + 'user_management' => 'Gestion des utilisateurs', + 'user_profile' => 'Profil', + ), + 'title' => array( + '_' => 'Titre', + 'authentication' => 'Authentification', + 'check_install' => 'Vérification de l’installation', + 'global_view' => 'Vue globale', + 'user_management' => 'Gestion des utilisateurs', + 'user_profile' => 'Profil', + ), + 'general_conf_is_ok' => 'La configuration générale a été enregistrée.', + 'general_configuration' => 'Configuration générale', + 'github_or_email' => 'sur Github ou par courriel', + 'global_view' => 'Vue globale', + 'help' => 'Afficher la documentation', + 'hide_read_feeds' => 'Cacher les catégories & flux sans article non-lu (ne fonctionne pas avec la configuration “Afficher tous les articles”)', + 'host' => 'Hôte', + 'html5_notif_timeout' => 'Temps d’affichage de la notification HTML5', + 'http_auth' => 'HTTP (pour utilisateurs avancés avec HTTPS)', + 'http_authentication' => 'Authentification HTTP', + 'http_password' => 'Mot de passe HTTP', + 'http_referer_is_nok' => 'Veuillez vérifier que vous ne modifiez pas votre HTTP REFERER.', + 'http_referer_is_ok' => 'Le HTTP REFERER est connu et semble correspondre à votre serveur.', + 'http_username' => 'Identifiant HTTP', + 'img_with_lazyload' => 'Utiliser le mode “chargement différé” pour les images', + 'import' => 'Importer', + 'import_export' => 'Importer / exporter', + 'informations' => 'Informations', + 'install_not_deleted' => 'Quelque chose s’est mal passé, vous devez supprimer le fichier %s à la main.', + 'installation_is_ok' => 'L’installation s’est bien passée.
    La dernière étape va maintenant tenter de supprimer les fichiers ainsi que d’éventuelles copies de base de données créés durant le processus de mise à jour.
    Vous pouvez choisir de sauter cette étape en supprimant ./data/do-install.txt manuellement.', + 'installation_step' => 'Installation — étape %d · FreshRSS', + 'internal_problem_feed' => 'Le flux ne peut pas être ajouté. Consulter les logs de FreshRSS pour plus de détails.', + 'invalid_login' => 'L’identifiant est invalide !', + 'invalid_url' => 'L’url %s est invalide.', + 'is_admin' => 'est administrateur', + 'jan' => 'jan.', + 'january' => 'janvier', + 'javascript_for_shortcuts' => 'Le JavaScript doit être activé pour pouvoir profiter des raccourcis.', + 'javascript_is_better' => 'FreshRSS est plus agréable à utiliser avec JavaScript activé', + 'javascript_should_be_activated' => 'Le JavaScript doit être activé.', + 'jul' => 'jui.', + 'july' => 'juillet', + 'jump_next' => 'sauter au prochain voisin non lu (flux ou catégorie)', + 'jun' => 'juin', + 'june' => 'juin', + 'keep_history' => 'Nombre minimum d’articles à conserver', + 'keep_logged_in' => 'Rester connecté (1 mois)', + 'language' => 'Langue', + 'language_defined' => 'La langue a bien été définie.', + 'last' => 'Fin', + 'last_3_month' => 'Depuis les trois derniers mois', + 'last_6_month' => 'Depuis les six derniers mois', + 'last_article' => 'Passer au dernier article', + 'last_month' => 'Depuis le mois dernier', + 'last_week' => 'Depuis la semaine dernière', + 'last_year' => 'Depuis l’année dernière', + 'lead_developer' => 'Développeur principal', + 'license' => 'Licence', + 'load_more' => 'Charger plus d’articles', + 'log_is_ok' => 'Les droits sur le répertoire des logs sont bons', + 'login' => 'Connexion', + 'login_configuration' => 'Identification', + 'login_persona_problem' => 'Problème de connexion à Persona ?', + 'login_required' => 'Accès protégé par mot de passe :', + 'login_with_persona' => 'Connexion avec Persona', + 'logout' => 'Déconnexion', + 'logs' => 'Logs', + 'logs_empty' => 'Les logs sont vides.', + 'main_stream' => 'Flux principal', + 'mar' => 'mar.', + 'march' => 'mars', + 'mark_all_read' => 'Tout marquer comme lu', + 'mark_cat_read' => 'Marquer la catégorie comme lue', + 'mark_favorite' => 'Mettre en favori', + 'mark_feed_read' => 'Marquer le flux comme lu', + 'mark_read' => 'Marquer comme lu', + 'may' => 'mai.', + 'minz_is_nok' => 'Vous ne disposez pas de la librairie Minz. Vous devriez exécuter le script build.sh ou bien la télécharger sur Github et installer dans le répertoire %s le contenu de son répertoire /lib.', + 'minz_is_ok' => 'Vous disposez du framework Minz', + 'mon' => 'lun.', + 'month' => 'mois', + 'more_information' => 'Plus d’informations', + 'n_entries_deleted' => '%d articles ont été supprimés.', + 'n_feeds_actualized' => '%d flux ont été mis à jour.', + 'new_article' => 'Il y a de nouveaux articles disponibles, cliquez pour rafraîchir la page.', + 'new_category' => 'Nouvelle catégorie', + 'newer_first' => 'Plus récents en premier', + 'next' => 'Suivant', + 'next_article' => 'Passer à l’article suivant', + 'next_page' => 'Passer à la page suivante', + 'next_step' => 'Passer à l’étape suivante', + 'no' => 'Non', + 'no_feed_actualized' => 'Aucun flux n’a pu être mis à jour.', + 'no_feed_to_display' => 'Il n’y a aucun article à afficher.', + 'no_feed_to_refresh' => 'Il n’y a aucun flux à actualiser…', + 'no_query' => 'Vous n’avez pas encore créé de filtre.', + 'no_query_filter' => 'Aucun filtre appliqué', + 'no_rss_feed' => 'Aucun flux RSS', + 'no_selected_feed' => 'Aucun flux sélectionné.', + 'no_update' => 'Aucune mise à jour à appliquer', + 'no_zip_extension' => 'L’extension Zip n’est pas présente sur votre serveur.', + 'normal_view' => 'Vue normale', + 'not_read' => '%d non lu', + 'not_reads' => '%d non lus', + 'not_yet_implemented' => 'Pas encore implémenté', + 'nothing_to_load' => 'Fin des articles', + 'notif_body_new_articles' => 'Il y a \\d nouveaux articles à lire sur FreshRSS.', + 'notif_title_new_articles' => 'FreshRSS : nouveaux articles !', + 'nov' => 'nov.', + 'november' => 'novembre', + 'number_articles' => '%d articles', + 'number_divided_when_reader' => 'Divisé par 2 dans la vue de lecture.', + 'number_feeds' => '%d flux', + 'oct' => 'oct.', + 'october' => 'octobre', + 'ok' => 'Ok !', + 'older_first' => 'Plus anciens en premier', + 'oops' => 'Oups !', + 'optimization_complete' => 'Optimisation terminée.', + 'optimize_bdd' => 'Optimiser la base de données', + 'optimize_todo_sometimes' => 'À faire de temps en temps pour réduire la taille de la BDD', + 'or' => 'ou', + 'page_not_found' => 'La page que vous cherchez n’existe pas !', + 'password' => 'Mot de passe', + 'password_api' => 'Mot de passe API
    (ex. : pour applis mobiles)', + 'password_form' => 'Mot de passe
    (pour connexion par formulaire)', + 'pcre_is_nok' => 'Il manque une librairie pour les expressions régulières (php-pcre)', + 'pcre_is_ok' => 'Vous disposez du nécessaire pour les expressions régulières (PCRE)', + 'pdo_is_nok' => 'Vous ne disposez pas de PDO ou d’un des drivers supportés (pdo_mysql, pdo_sqlite)', + 'pdo_is_ok' => 'Vous disposez de PDO et d’au moins un des drivers supportés (pdo_mysql, pdo_sqlite)', + 'persona_connection_email' => 'Adresse courriel de connexion
    (pour Mozilla Persona)', + 'persona_is_ok' => 'Les droits sur le répertoire de Mozilla Persona sont bons', + 'php_is_nok' => 'Votre version de PHP est la %s mais FreshRSS requiert au moins la version %s', + 'php_is_ok' => 'Votre version de PHP est la %s, qui est compatible avec FreshRSS', + 'prefix' => 'Préfixe des tables', + 'previous' => 'Précédent', + 'previous_article' => 'Passer à l’article précédent', + 'previous_page' => 'Passer à la page précédente', + 'print' => 'Imprimer', + 'project_website' => 'Site du projet', + 'public' => 'Public', + 'publication_date' => 'Date de publication', + 'purge_completed' => 'Purge effectuée (%d articles supprimés).', + 'purge_now' => 'Purger maintenant', + 'queries' => 'Filtres utilisateurs', + 'query_created' => 'Le filtre "%s" a bien été créé.', + 'query_deprecated' => 'Ce filtre n’est plus valide. La catégorie ou le flux concerné a été supprimé.', + 'query_filter' => 'Filtres appliqués :', + 'query_get_all' => 'Afficher tous les articles', + 'query_get_category' => 'Afficher la catégorie "%s"', + 'query_get_favorite' => 'Afficher les articles favoris', + 'query_get_feed' => 'Afficher le flux "%s"', + 'query_number' => 'Filtre n°%d', + 'query_order_asc' => 'Afficher les articles les plus anciens en premier', + 'query_order_desc' => 'Afficher les articles les plus récents en premier', + 'query_search' => 'Recherche de "%s"', + 'query_state_0' => 'Afficher tous les articles', + 'query_state_1' => 'Afficher les articles lus', + 'query_state_2' => 'Afficher les articles non lus', + 'query_state_3' => 'Afficher tous les articles', + 'query_state_4' => 'Afficher les articles favoris', + 'query_state_5' => 'Afficher les articles lus et favoris', + 'query_state_6' => 'Afficher les articles non lus et favoris', + 'query_state_7' => 'Afficher les articles favoris', + 'query_state_8' => 'Afficher les articles non favoris', + 'query_state_9' => 'Afficher les articles lus et non favoris', + 'query_state_10' => 'Afficher les articles non lus et non favoris', + 'query_state_11' => 'Afficher les articles non favoris', + 'query_state_12' => 'Afficher tous les articles', + 'query_state_13' => 'Afficher les articles lus', + 'query_state_14' => 'Afficher les articles non lus', + 'query_state_15' => 'Afficher tous les articles', + 'random_string' => 'Chaîne aléatoire', + 'reader_view' => 'Vue lecture', + 'reading_configuration' => 'Lecture', + 'reading_confirm' => 'Afficher une confirmation lors des actions “marquer tout comme lu”', + 'refresh' => 'Actualisation', + 'related_tags' => 'Tags associés', + 'retrieve_truncated_feeds' => 'Permet de récupérer les flux tronqués (attention, demande plus de temps !)', + 'rss_feed_management' => 'Gestion des flux RSS', + 'rss_feeds_of' => 'Flux RSS de %s', + 'rss_view' => 'Flux RSS', + 'sat' => 'sam.', + 'save' => 'Enregistrer', + 'scroll' => 'au défilement de la page', + 'search' => 'Rechercher des mots ou des #tags', + 'search_short' => 'Rechercher', + 'seconds_(0_means_no_timeout)' => 'secondes (0 signifie aucun timeout ) ', + 'see_on_website' => 'Voir sur le site d’origine', + 'see_website' => 'Voir le site', + 'sep' => 'sep.', + 'september' => 'septembre', + 'shaarli' => 'Shaarli', + 'share' => 'Partager', + 'share_name' => 'Nom du partage à afficher', + 'share_url' => 'URL du partage à utiliser', + 'sharing' => 'Partage', + 'sharing_management' => 'Gestion des options de partage', + 'shift_for_all_read' => '+ shift pour marquer tous les articles comme lus', + 'shortcuts' => 'Raccourcis', + 'shortcuts_article_action' => 'Actions associées à l’article courant', + 'shortcuts_navigation' => 'Navigation', + 'shortcuts_navigation_help' => 'Avec le modificateur "Shift", les raccourcis de navigation s’appliquent aux flux.
    Avec le modificateur "Alt", les raccourcis de navigation s’appliquent aux catégories.', + 'shortcuts_other_action' => 'Autres actions', + 'shortcuts_updated' => 'Les raccourcis ont été mis à jour.', + 'show_adaptive' => 'Adapter l’affichage', + 'show_all_articles' => 'Afficher tous les articles', + 'show_favorite' => 'Afficher les favoris', + 'show_in_all_flux' => 'Afficher dans le flux principal', + 'show_not_favorite' => 'Afficher tout sauf les favoris', + 'show_not_reads' => 'Afficher les non lus', + 'show_read' => 'Afficher les lus', + 'sort_order' => 'Ordre de tri', + 'starred_list' => 'Liste des articles favoris', + 'stats' => 'Statistiques', + 'stats_entry_count' => 'Nombre d’articles', + 'stats_entry_per_category' => 'Articles par catégorie', + 'stats_entry_per_day' => 'Nombre d’articles par jour (30 derniers jours)', + 'stats_entry_per_day_of_week' => 'Par jour de la semaine (moyenne : %.2f messages)', + 'stats_entry_per_hour' => 'Par heure (moyenne : %.2f messages)', + 'stats_entry_per_month' => 'Par mois (moyenne : %.2f messages)', + 'stats_entry_repartition' => 'Répartition des articles', + 'stats_feed_per_category' => 'Flux par catégorie', + 'stats_idle' => 'Flux inactifs', + 'stats_main' => 'Statistiques principales', + 'stats_no_idle' => 'Il n’y a aucun flux inactif !', + 'stats_percent_of_total' => '%% du total', + 'stats_repartition' => 'Répartition des articles', + 'stats_top_feed' => 'Les dix plus gros flux', + 'status_favorites' => 'favoris', + 'status_read' => 'lus', + 'status_total' => 'total', + 'status_unread' => 'non lus', + 'steps' => 'Étapes', + 'sticky_post' => 'Aligner l’article en haut quand il est ouvert', + 'submit' => 'Valider', + 'subscription_management' => 'Gestion des abonnements', + 'sun' => 'dim.', + 'theme' => 'Thème', + 'think_to_add' => 'Vous pouvez ajouter des flux.', + 'this_is_the_end' => 'This is the end', + 'thu' => 'jeu.', + 'today' => 'Aujourd’hui', + 'top_line' => 'Ligne du haut', + 'truncate' => 'Supprimer tous les articles', + 'ttl' => 'Ne pas automatiquement rafraîchir plus souvent que', + 'tue' => 'mar.', + 'twitter' => 'Twitter', + 'unsafe_autologin' => 'Autoriser les connexions automatiques non-sûres au format : ', + 'update' => 'Mise à jour', + 'update_apply' => 'Appliquer la mise à jour', + 'update_can_apply' => 'Une mise à jour est disponible.', + 'update_check' => 'Vérifier les mises à jour', + 'update_end' => 'La mise à jour est terminée, vous pouvez maintenant passer à l’étape finale.', + 'update_finished' => 'La mise à jour est terminée !', + 'update_last' => 'Dernière vérification : %s', + 'update_long' => 'Ce processus peut prendre longtemps, selon la taille de votre base de données. Vous aurez peut-être à attendre que cette page dépasse son temps maximum d’exécution (~5 minutes) puis à la recharger.', + 'update_problem' => 'La mise à jour a rencontré un problème : %s', + 'update_server_not_found' => 'Le serveur de mise à jour n’a pas été trouvé. [%s]', + 'update_start' => 'Lancer la mise à jour', + 'update_system' => 'Système de mise à jour', + 'updated' => 'Modifications enregistrées.', + 'upon_reception' => 'dès la réception du nouvel article', + 'user_created' => 'L’utilisateur %s a été créé.', + 'user_deleted' => 'L’utilisateur %s a été supprimé.', + 'user_filter' => 'Accéder aux filtres utilisateur', + 'user_filter_help' => 'S’il n’y a qu’un filtre utilisateur, celui-ci est utilisé automatiquement. Sinon ils sont accessibles par leur numéro.', + 'username' => 'Nom d’utilisateur', + 'username_admin' => 'Nom d’utilisateur administrateur', + 'users' => 'Utilisateurs', + 'users_list' => 'Liste des utilisateurs', + 'version' => 'Version', + 'version_update' => 'Mise à jour', + 'wallabag' => 'wallabag', + 'website' => 'Site Internet', + 'website_url' => 'URL du site', + 'wed' => 'mer.', + 'width_large' => 'Large', + 'width_medium' => 'Moyenne', + 'width_no_limit' => 'Pas de limite', + 'width_thin' => 'Fine', + 'yes' => 'Oui', + 'yesterday' => 'Hier', + 'your_diaspora_pod' => 'Votre pod Diaspora*', + 'your_favorites' => 'Vos favoris', + 'your_rss_feeds' => 'Vos flux RSS', + 'your_shaarli' => 'Votre Shaarli', + 'your_wallabag' => 'Votre wallabag', + 'zip_error' => 'Une erreur est survenue durant l’import du fichier Zip.', +); diff --git a/app/i18n/fr/index.php b/app/i18n/fr/index.php new file mode 100644 index 000000000..afca37ed3 --- /dev/null +++ b/app/i18n/fr/index.php @@ -0,0 +1,5 @@ + array( + 'over_max' => 'Vous avez atteint votre limite de catégories (%d)', + ), + 'feeds' => array( + 'over_max' => 'Vous avez atteint votre limite de flux (%d)', + ), +); diff --git a/lib/Minz/Translate.php b/lib/Minz/Translate.php index 8c2f90041..084bd7e07 100644 --- a/lib/Minz/Translate.php +++ b/lib/Minz/Translate.php @@ -5,71 +5,117 @@ */ /** - * La classe Translate se charge de la traduction - * Utilise les fichiers du répertoire /app/i18n/ + * This class is used for the internationalization. + * It uses files in `./app/i18n/` */ class Minz_Translate { /** - * $language est la langue à afficher + * $lang_name is the name of the current language to use. */ - private static $language; - + private static $lang_name; + + /** + * $lang_path is the pathname of i18n files (e.g. ./app/i18n/en/). + */ + private static $lang_path; + /** - * $translates est le tableau de correspondance - * $key => $traduction + * $translates is a cache for i18n translation. */ private static $translates = array(); - + /** - * Inclus le fichier de langue qui va bien - * l'enregistre dans $translates + * Load $lang_name and $lang_path based on configuration and selected language. */ public static function init() { $l = Minz_Configuration::language(); - self::$language = Minz_Session::param('language', $l); - - $l_path = APP_PATH . '/i18n/' . self::$language . '.php'; - - if (file_exists($l_path)) { - self::$translates = include($l_path); - } + self::$lang_name = Minz_Session::param('language', $l); + self::$lang_path = APP_PATH . '/i18n/' . self::$lang_name . '/'; } - + /** - * Alias de init + * Alias for init(). */ public static function reset() { self::init(); } - + /** - * Traduit une clé en sa valeur du tableau $translates - * @param $key la clé à traduire - * @return la valeur correspondante à la clé - * > si non présente dans le tableau, on retourne la clé elle-même + * Translate a key into its corresponding value based on selected language. + * @param $key the key to translate. + * @param additional parameters for variable keys. + * @return the value corresponding to the key. + * If no value is found, return the key itself. */ public static function t($key) { - $translate = $key; - - if (isset(self::$translates[$key])) { - $translate = self::$translates[$key]; + $group = explode('.', $key); + + if (count($group) < 2) { + // Minz_Log::debug($key . ' is not in a valid format'); + $top_level = 'gen'; + } else { + $top_level = array_shift($group); } + $filename = self::$lang_path . $top_level . '.php'; + + // Try to load the i18n file if it's not done yet. + if (!isset(self::$translates[$top_level])) { + if (!file_exists($filename)) { + Minz_Log::debug($top_level . ' is not a valid top level key'); + return $key; + } + + self::$translates[$top_level] = include($filename); + } + + // Go through the i18n keys to get the correct translation value. + $translates = self::$translates[$top_level]; + $size_group = count($group); + $level_processed = 0; + $translation_value = $key; + foreach ($group as $i18n_level) { + $level_processed++; + if (!isset($translates[$i18n_level])) { + Minz_Log::debug($key . ' is not a valid key'); + return $key; + } + + if ($level_processed < $size_group) { + $translates = $translates[$i18n_level]; + } else { + $translation_value = $translates[$i18n_level]; + } + } + + if (is_array($translation_value)) { + if (isset($translation_value['_'])) { + $translation_value = $translation_value['_']; + } else { + Minz_Log::debug($key . ' is not a valid key'); + return $key; + } + } + + // Get the facultative arguments to replace i18n variables. $args = func_get_args(); unset($args[0]); - - return vsprintf($translate, $args); + + return vsprintf($translation_value, $args); } - + /** - * Retourne la langue utilisée actuellement - * @return la langue + * Return the current language. */ public static function language() { - return self::$language; + return self::$lang_name; } } + +/** + * Alias for Minz_Translate::t() + */ function _t($key) { $args = func_get_args(); unset($args[0]); -- cgit v1.2.3 From ddc50090b55cd744e24995c872435a3fed7092da Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 3 Dec 2014 16:58:12 +0100 Subject: Fix i18n for installation script See https://github.com/FreshRSS/FreshRSS/issues/334 --- app/install.php | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/app/install.php b/app/install.php index cfdd733ce..f54565c73 100644 --- a/app/install.php +++ b/app/install.php @@ -42,18 +42,12 @@ function param($key, $default = false) { // gestion internationalisation -$translates = array(); -$actual = 'en'; function initTranslate() { - global $translates; - global $actual; - - $actual = isset($_SESSION['language']) ? $_SESSION['language'] : getBetterLanguage('en'); - - $file = APP_PATH . '/i18n/' . $actual . '.php'; - if (file_exists($file)) { - $translates = array_merge($translates, include($file)); + if (!isset($_SESSION['language'])) { + $_SESSION['language'] = getBetterLanguage('en'); } + + Minz_Translate::init(); } function getBetterLanguage($fallback) { @@ -75,19 +69,6 @@ function availableLanguages() { ); } -function _t($key) { - global $translates; - $translate = $key; - if (isset($translates[$key])) { - $translate = $translates[$key]; - } - - $args = func_get_args(); - unset($args[0]); - - return vsprintf($translate, $args); -} - /*** SAUVEGARDES ***/ function saveLanguage() { -- cgit v1.2.3 From 7161eacb4042de4fd994b727800038d3ec286374 Mon Sep 17 00:00:00 2001 From: Alwaysin Date: Wed, 3 Dec 2014 23:42:38 +0100 Subject: Add i18n (french) for auto_remove_article #2 Reference : #694 --- app/i18n/fr/gen.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php index 8a4a9750b..0b2395bd0 100644 --- a/app/i18n/fr/gen.php +++ b/app/i18n/fr/gen.php @@ -62,6 +62,7 @@ return array( 'author' => 'Auteur', 'auto_load_more' => 'Charger les articles suivants en bas de page', 'auto_read_when' => 'Marquer un article comme lu…', + 'auto_remove_article' => 'Cacher les articles après lecture', 'auto_share' => 'Partager', 'auto_share_help' => 'S’il n’y a qu’un mode de partage, celui-ci est utilisé automatiquement. Sinon ils sont accessibles par leur numéro.', 'back_to_rss_feeds' => '← Retour à vos flux RSS', -- cgit v1.2.3 From 93af0cf61e6e9368888eedb2d2e36397da3f87bd Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Wed, 3 Dec 2014 18:13:59 -0500 Subject: Fix behavior when marking an article as unread --- p/scripts/main.js | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/p/scripts/main.js b/p/scripts/main.js index 19eba206d..32cf55a3c 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -144,6 +144,7 @@ function mark_read(active, only_not_read) { inc = 0; if (active.hasClass("not_read")) { active.removeClass("not_read"); + hide_article(active); inc--; } else if (only_not_read !== true || active.hasClass("not_read")) { active.addClass("not_read"); @@ -231,14 +232,7 @@ function toggleContent(new_active, old_active) { } old_active.removeClass("active current"); new_active.addClass("current"); - if (context['auto_remove_article'] && !old_active.hasClass('not_read')) { - var p = old_active.prev(); - var n = old_active.next(); - if (p.hasClass('day') && n.hasClass('day')) { - p.remove(); - } - old_active.remove(); - } + hide_article(old_active); } else { new_active.toggleClass('active'); } @@ -283,6 +277,17 @@ function toggleContent(new_active, old_active) { } } +function hide_article(article) { + if (context['auto_remove_article'] && !article.hasClass('not_read')) { + var p = article.prev(); + var n = article.next(); + if (p.hasClass('day') && n.hasClass('day')) { + p.remove(); + } + article.remove(); + } +} + function prev_entry() { var old_active = $(".flux.current"), new_active = old_active.length === 0 ? $(".flux:last") : old_active.prevAll(".flux:first"); @@ -690,9 +695,6 @@ function init_stream(divStream) { divStream.on('click', '.flux a.read', function () { var active = $(this).parents(".flux"); mark_read(active, false); - if (context['auto_remove_article']) { - active.remove(); - } return false; }); -- cgit v1.2.3 From 5617911644bf85718430bb096c4ae9a0a0e8c75c Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Wed, 3 Dec 2014 18:35:42 -0500 Subject: Revert "Fix behavior when marking an article as unread" This reverts commit 93af0cf61e6e9368888eedb2d2e36397da3f87bd. --- p/scripts/main.js | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/p/scripts/main.js b/p/scripts/main.js index 32cf55a3c..19eba206d 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -144,7 +144,6 @@ function mark_read(active, only_not_read) { inc = 0; if (active.hasClass("not_read")) { active.removeClass("not_read"); - hide_article(active); inc--; } else if (only_not_read !== true || active.hasClass("not_read")) { active.addClass("not_read"); @@ -232,7 +231,14 @@ function toggleContent(new_active, old_active) { } old_active.removeClass("active current"); new_active.addClass("current"); - hide_article(old_active); + if (context['auto_remove_article'] && !old_active.hasClass('not_read')) { + var p = old_active.prev(); + var n = old_active.next(); + if (p.hasClass('day') && n.hasClass('day')) { + p.remove(); + } + old_active.remove(); + } } else { new_active.toggleClass('active'); } @@ -277,17 +283,6 @@ function toggleContent(new_active, old_active) { } } -function hide_article(article) { - if (context['auto_remove_article'] && !article.hasClass('not_read')) { - var p = article.prev(); - var n = article.next(); - if (p.hasClass('day') && n.hasClass('day')) { - p.remove(); - } - article.remove(); - } -} - function prev_entry() { var old_active = $(".flux.current"), new_active = old_active.length === 0 ? $(".flux:last") : old_active.prevAll(".flux:first"); @@ -695,6 +690,9 @@ function init_stream(divStream) { divStream.on('click', '.flux a.read', function () { var active = $(this).parents(".flux"); mark_read(active, false); + if (context['auto_remove_article']) { + active.remove(); + } return false; }); -- cgit v1.2.3 From 53410887c94157f3d11f2c30d92ff5d3d8a3a9bd Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Wed, 3 Dec 2014 18:57:53 -0500 Subject: Fix behavior to hide articles I do not like it since it is partly duplicated. We need to find something better. --- p/scripts/main.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/p/scripts/main.js b/p/scripts/main.js index 19eba206d..e48630d89 100644 --- a/p/scripts/main.js +++ b/p/scripts/main.js @@ -689,10 +689,15 @@ function init_stream(divStream) { divStream.on('click', '.flux a.read', function () { var active = $(this).parents(".flux"); - mark_read(active, false); - if (context['auto_remove_article']) { + if (context['auto_remove_article'] && active.hasClass('not_read')) { + var p = active.prev(); + var n = active.next(); + if (p.hasClass('day') && n.hasClass('day')) { + p.remove(); + } active.remove(); } + mark_read(active, false); return false; }); -- cgit v1.2.3 From 86f69ca396572ca4d7668a33e84cb4f3b523fc4e Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 4 Dec 2014 19:33:29 +0100 Subject: First draft for the new extension feature - Only system extensions can be loaded for the moment by adding them in the config.php file. - Remove previous system (it will be added properly in the new system in the next step). --- app/FreshRSS.php | 42 +++++------ constants.php | 3 +- extensions/README.md | 15 ++++ extensions/Read-me.txt | 15 ---- lib/Minz/Configuration.php | 10 +++ lib/Minz/Extension.php | 96 +++++++++++++++++++++++++ lib/Minz/ExtensionException.php | 15 ++++ lib/Minz/ExtensionManager.php | 150 ++++++++++++++++++++++++++++++++++++++++ 8 files changed, 310 insertions(+), 36 deletions(-) create mode 100644 extensions/README.md delete mode 100644 extensions/Read-me.txt create mode 100644 lib/Minz/Extension.php create mode 100644 lib/Minz/ExtensionException.php create mode 100644 lib/Minz/ExtensionManager.php diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 6114a5d1a..2db811a71 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -6,6 +6,9 @@ class FreshRSS extends Minz_FrontController { Minz_Session::init('FreshRSS'); } + // Load list of extensions and initialize the "system" ones. + Minz_ExtensionManager::init(); + // Need to be called just after session init because it initializes // current user. FreshRSS_Auth::init(); @@ -32,7 +35,6 @@ class FreshRSS extends Minz_FrontController { $this->loadStylesAndScripts(); $this->loadNotifications(); - $this->loadExtensions(); } private function loadStylesAndScripts() { @@ -74,23 +76,23 @@ class FreshRSS extends Minz_FrontController { } } - private function loadExtensions() { - $extensionPath = FRESHRSS_PATH . '/extensions/'; - //TODO: Add a preference to load only user-selected extensions - foreach (scandir($extensionPath) as $key => $extension) { - if (ctype_alpha($extension)) { - $mtime = @filemtime($extensionPath . $extension . '/style.css'); - if ($mtime !== false) { - Minz_View::appendStyle(Minz_Url::display('/ext.php?c&e=' . $extension . '&' . $mtime)); - } - $mtime = @filemtime($extensionPath . $extension . '/script.js'); - if ($mtime !== false) { - Minz_View::appendScript(Minz_Url::display('/ext.php?j&e=' . $extension . '&' . $mtime)); - } - if (file_exists($extensionPath . $extension . '/module.php')) { - //TODO: include - } - } - } - } + // private function loadExtensions() { + // $extensionPath = FRESHRSS_PATH . '/extensions/'; + // //TODO: Add a preference to load only user-selected extensions + // foreach (scandir($extensionPath) as $key => $extension) { + // if (ctype_alpha($extension)) { + // $mtime = @filemtime($extensionPath . $extension . '/style.css'); + // if ($mtime !== false) { + // Minz_View::appendStyle(Minz_Url::display('/ext.php?c&e=' . $extension . '&' . $mtime)); + // } + // $mtime = @filemtime($extensionPath . $extension . '/script.js'); + // if ($mtime !== false) { + // Minz_View::appendScript(Minz_Url::display('/ext.php?j&e=' . $extension . '&' . $mtime)); + // } + // if (file_exists($extensionPath . $extension . '/module.php')) { + // //TODO: include + // } + // } + // } + // } } diff --git a/constants.php b/constants.php index f66a012b0..999e703ba 100644 --- a/constants.php +++ b/constants.php @@ -20,6 +20,7 @@ define('FRESHRSS_PATH', dirname(__FILE__)); define('CACHE_PATH', DATA_PATH . '/cache'); define('LIB_PATH', FRESHRSS_PATH . '/lib'); - define('APP_PATH', FRESHRSS_PATH . '/app'); + define('APP_PATH', FRESHRSS_PATH . '/app'); + define('EXTENSIONS_PATH', FRESHRSS_PATH . '/extensions'); define('TMP_PATH', sys_get_temp_dir()); diff --git a/extensions/README.md b/extensions/README.md new file mode 100644 index 000000000..e7b66d5bc --- /dev/null +++ b/extensions/README.md @@ -0,0 +1,15 @@ +== FreshRSS extensions == + +You may place in this directory some custom extensions for FreshRSS. + +The structure must be: + +./FreshRSS/extensions/ + ./NameOfExtensionAlphanumeric/ + ./style.css + ./script.js + ./module.php + +Each file is optional. + +The name of non-official extensions should start by an 'x'. diff --git a/extensions/Read-me.txt b/extensions/Read-me.txt deleted file mode 100644 index e7b66d5bc..000000000 --- a/extensions/Read-me.txt +++ /dev/null @@ -1,15 +0,0 @@ -== FreshRSS extensions == - -You may place in this directory some custom extensions for FreshRSS. - -The structure must be: - -./FreshRSS/extensions/ - ./NameOfExtensionAlphanumeric/ - ./style.css - ./script.js - ./module.php - -Each file is optional. - -The name of non-official extensions should start by an 'x'. diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php index 6cbc9fc0b..4d3ab0964 100644 --- a/lib/Minz/Configuration.php +++ b/lib/Minz/Configuration.php @@ -69,6 +69,8 @@ class Minz_Configuration { 'max_categories' => Minz_Configuration::MAX_SMALL_INT, ); + private static $extensions_enabled = array(); + /* * Getteurs */ @@ -133,6 +135,9 @@ class Minz_Configuration { public static function unsafeAutologinEnabled() { return self::$unsafe_autologin_enabled; } + public static function extensionsEnabled() { + return self::$extensions_enabled; + } public static function _allowAnonymous($allow = false) { self::$allow_anonymous = ((bool)$allow) && self::canLogIn(); @@ -338,6 +343,11 @@ class Minz_Configuration { } } + // Extensions + if (isset($ini_array['extensions']) && is_array($ini_array['extensions'])) { + self::$extensions_enabled = $ini_array['extensions']; + } + // Base de données if (isset ($ini_array['db'])) { $db = $ini_array['db']; diff --git a/lib/Minz/Extension.php b/lib/Minz/Extension.php new file mode 100644 index 000000000..f442344a3 --- /dev/null +++ b/lib/Minz/Extension.php @@ -0,0 +1,96 @@ +name = $meta_info['name']; + $this->entrypoint = $meta_info['entrypoint']; + $this->path = $meta_info['path']; + $this->author = isset($meta_info['author']) ? $meta_info['author'] : ''; + $this->description = isset($meta_info['description']) ? $meta_info['description'] : ''; + $this->version = isset($meta_info['version']) ? $meta_info['version'] : '0.1'; + $this->setType(isset($meta_info['type']) ? $meta_info['type'] : 'user'); + } + + /** + * Used when installing an extension (e.g. update the database scheme). + * + * It must be redefined by child classes. + */ + public function install() {} + + /** + * Used when uninstalling an extension (e.g. revert the database scheme to + * cancel changes from install). + * + * It must be redefined by child classes. + */ + public function uninstall() {} + + /** + * Call at the initialization of the extension (i.e. when the extension is + * enabled by the extension manager). + * + * It must be redefined by child classes. + */ + public function init() {} + + /** + * Getters and setters. + */ + public function getName() { + return $this->name; + } + public function getEntrypoint() { + return $this->entrypoint; + } + public function getAuthor() { + return $this->author; + } + public function getDescription() { + return $this->description; + } + public function getVersion() { + return $this->version; + } + public function getType() { + return $this->type; + } + private function setType($type) { + if (!in_array($type, self::$authorized_types)) { + throw new Minz_ExtensionException('invalid `type` info', $this->name); + } + $this->type = $type; + } +} diff --git a/lib/Minz/ExtensionException.php b/lib/Minz/ExtensionException.php new file mode 100644 index 000000000..647f1a9b9 --- /dev/null +++ b/lib/Minz/ExtensionException.php @@ -0,0 +1,15 @@ +Extension where + * must match with the entry point in metadata.json. This class must + * inherit from Minz_Extension class. + */ + public static function init() { + $list_potential_extensions = array_values(array_diff( + scandir(EXTENSIONS_PATH), + array('..', '.') + )); + + self::$ext_auto_enabled = Minz_Configuration::extensionsEnabled(); + + foreach ($list_potential_extensions as $ext_dir) { + $ext_pathname = EXTENSIONS_PATH . '/' . $ext_dir; + $metadata_filename = $ext_pathname . '/' . self::$ext_metaname; + + // Try to load metadata file. + if (!file_exists($metadata_filename)) { + // No metadata file? Invalid! + continue; + } + $meta_raw_content = file_get_contents($metadata_filename); + $meta_json = json_decode($meta_raw_content, true); + if (!$meta_json || !self::is_valid_metadata($meta_json)) { + // metadata.json is not a json file? Invalid! + // or metadata.json is invalid (no required information), invalid! + Minz_Log::warning('`' . $metadata_filename . '` is not a valid metadata file'); + continue; + } + + $meta_json['path'] = $ext_pathname; + + // Try to load extension itself + $extension = self::load($meta_json); + if (!is_null($extension)) { + self::register($extension); + } + } + } + + /** + * Indicates if the given parameter is a valid metadata array. + * + * Required fields are: + * - `name`: the name of the extension + * - `entry_point`: a class name to load the extension source code + * If the extension class name is `TestExtension`, entry point will be `Test`. + * `entry_point` must be composed of alphanumeric characters. + * + * @param $meta is an array of values. + * @return true if the array is valid, false else. + */ + public static function is_valid_metadata($meta) { + return !(empty($meta['name']) || + empty($meta['entrypoint']) || + !ctype_alnum($meta['entrypoint'])); + } + + /** + * Load the extension source code based on info metadata. + * + * @param $info an array containing information about extension. + * @return an extension inheriting from Minz_Extension. + */ + public static function load($info) { + $entry_point_filename = $info['path'] . '/' . self::$ext_entry_point; + $ext_class_name = $info['entrypoint'] . 'Extension'; + + include($entry_point_filename); + + // Test if the given extension class exists. + if (!class_exists($ext_class_name)) { + Minz_Log::warning('`' . $ext_class_name . + '` cannot be found in `' . $entry_point_filename . '`'); + return null; + } + + // Try to load the class. + $extension = null; + try { + $extension = new $ext_class_name($info); + } catch (Minz_ExtensionException $e) { + // We cannot load the extension? Invalid! + Minz_Log::warning('In `' . $metadata_filename . '`: ' . $e->getMessage()); + return null; + } + + // Test if class is correct. + if (!($extension instanceof Minz_Extension)) { + Minz_Log::warning('`' . $ext_class_name . + '` is not an instance of `Minz_Extension`'); + return null; + } + + return $extension; + } + + /** + * Add the extension to the list of the known extensions ($ext_list). + * + * If the extension is present in $ext_auto_enabled and if its type is "system", + * it will be enabled in the same time. + * + * @param $ext a valid extension. + */ + public static function register($ext) { + $name = $ext->getName(); + self::$ext_list[$name] = $ext; + + if ($ext->getType() === 'system' && + in_array($name, self::$ext_auto_enabled)) { + self::enable($ext->getName()); + } + } + + /** + * Enable an extension so it will be called when necessary. + * + * The extension init() method will be called. + * + * @param $ext_name is the name of a valid extension present in $ext_list. + */ + public static function enable($ext_name) { + if (isset(self::$ext_list[$ext_name])) { + $ext = self::$ext_list[$ext_name]; + self::$ext_list_enabled[$ext_name] = $ext; + $ext->init(); + } + } +} -- cgit v1.2.3 From 1086ba4a2bbe43a0101105624f831516b59ba9e9 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 4 Dec 2014 19:47:43 +0100 Subject: Enable extensions for users --- app/FreshRSS.php | 6 +++++- app/Models/Configuration.php | 8 ++++++++ lib/Minz/ExtensionManager.php | 11 +++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 2db811a71..166ee1709 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -6,7 +6,7 @@ class FreshRSS extends Minz_FrontController { Minz_Session::init('FreshRSS'); } - // Load list of extensions and initialize the "system" ones. + // Load list of extensions and enable the "system" ones. Minz_ExtensionManager::init(); // Need to be called just after session init because it initializes @@ -29,6 +29,10 @@ class FreshRSS extends Minz_FrontController { // Load context and configuration. FreshRSS_Context::init(); + // Enable extensions for the current user. + $ext_list = FreshRSS_Context::$conf->extensions_enabled; + Minz_ExtensionManager::enable_by_list($ext_list); + // Init i18n. Minz_Session::_param('language', FreshRSS_Context::$conf->language); Minz_Translate::init(); diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index 8668470b0..13ce43990 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -64,6 +64,7 @@ class FreshRSS_Configuration { 'sharing' => array(), 'queries' => array(), 'html5_notif_timeout' => 0, + 'extensions_enabled' => array(), ); private $available_languages = array( @@ -342,4 +343,11 @@ class FreshRSS_Configuration { public function _bottomline_link($value) { $this->data['bottomline_link'] = ((bool)$value) && $value !== 'no'; } + + public function _extensions_enabled($value) { + if (!is_array($value)) { + $value = array($value); + } + $this->data['extensions_enabled'] = $value; + } } diff --git a/lib/Minz/ExtensionManager.php b/lib/Minz/ExtensionManager.php index ae648fe0d..789557b9e 100644 --- a/lib/Minz/ExtensionManager.php +++ b/lib/Minz/ExtensionManager.php @@ -147,4 +147,15 @@ class Minz_ExtensionManager { $ext->init(); } } + + /** + * Enable a list of extensions. + * + * @param $ext_list the names of extensions we want to load. + */ + public static function enable_by_list($ext_list) { + foreach ($ext_list as $ext_name) { + self::enable($ext_name); + } + } } -- cgit v1.2.3 From 0316badf649ef285f068847ef094ace80dd51290 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 4 Dec 2014 19:52:07 +0100 Subject: Update gitignore for extensions --- extensions/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/.gitignore b/extensions/.gitignore index d93e5e396..cd5592022 100644 --- a/extensions/.gitignore +++ b/extensions/.gitignore @@ -1 +1 @@ -/[xX] +[xX]* -- cgit v1.2.3 From f9b037742a0aeb49cab86782d1a59913c2de47bf Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Thu, 4 Dec 2014 20:41:01 +0100 Subject: Update ext.php to serve any file from extensions Add an extension->getFileUrl() method to facilitate url generation --- lib/Minz/Extension.php | 23 +++++++++++++++++++++++ p/ext.php | 37 +++++++++++++++++++------------------ 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/lib/Minz/Extension.php b/lib/Minz/Extension.php index f442344a3..72a375a6d 100644 --- a/lib/Minz/Extension.php +++ b/lib/Minz/Extension.php @@ -75,6 +75,9 @@ class Minz_Extension { public function getEntrypoint() { return $this->entrypoint; } + public function getPath() { + return $this->path; + } public function getAuthor() { return $this->author; } @@ -93,4 +96,24 @@ class Minz_Extension { } $this->type = $type; } + + /** + * Return the url for a given file. + * + * @param $filename name of the file to serve. + * @param $type the type (js or css) of the file to serve. + * @return the url corresponding to the file. + */ + public function getFileUrl($filename, $type) { + $dir = end(explode('/', $this->path)); + $file_name_url = urlencode($dir . '/' . $filename); + + $absolute_path = $this->path . '/' . $filename; + $mtime = @filemtime($absolute_path); + + $url = '/ext.php?f=' . $file_name_url . + '&t=' . $type . + '&' . $mtime; + return Minz_Url::display($url); + } } diff --git a/p/ext.php b/p/ext.php index a1dde2f93..39c224a84 100644 --- a/p/ext.php +++ b/p/ext.php @@ -1,32 +1,33 @@ Date: Thu, 4 Dec 2014 20:43:05 +0100 Subject: Remove old code for extensions --- app/FreshRSS.php | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 166ee1709..dc7d0b375 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -79,24 +79,4 @@ class FreshRSS extends Minz_FrontController { Minz_Session::_param('notification'); } } - - // private function loadExtensions() { - // $extensionPath = FRESHRSS_PATH . '/extensions/'; - // //TODO: Add a preference to load only user-selected extensions - // foreach (scandir($extensionPath) as $key => $extension) { - // if (ctype_alpha($extension)) { - // $mtime = @filemtime($extensionPath . $extension . '/style.css'); - // if ($mtime !== false) { - // Minz_View::appendStyle(Minz_Url::display('/ext.php?c&e=' . $extension . '&' . $mtime)); - // } - // $mtime = @filemtime($extensionPath . $extension . '/script.js'); - // if ($mtime !== false) { - // Minz_View::appendScript(Minz_Url::display('/ext.php?j&e=' . $extension . '&' . $mtime)); - // } - // if (file_exists($extensionPath . $extension . '/module.php')) { - // //TODO: include - // } - // } - // } - // } } -- cgit v1.2.3 From 2a74b9e9a69fcfe74b513c487430669540ef18fc Mon Sep 17 00:00:00 2001 From: Alwaysin Date: Fri, 5 Dec 2014 09:41:54 +0100 Subject: Add i18n (english) for auto_remove_article #2 Reference : https://github.com/FreshRSS/FreshRSS/pull/694 --- app/i18n/en/gen.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index 9e06357bc..5dc2c3e28 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -62,6 +62,7 @@ return array( 'author' => 'Author', 'auto_load_more' => 'Load next articles at the page bottom', 'auto_read_when' => 'Mark article as read…', + 'auto_remove_article' => 'Hide articles after reading' 'auto_share' => 'Share', 'auto_share_help' => 'If there is only one sharing mode, it is used. Else modes are accessible by their number.', 'back_to_rss_feeds' => '← Go back to your RSS feeds', -- cgit v1.2.3 From a2da70fd119cc43438f8dd88de54a7d19fafbe1a Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 5 Dec 2014 10:51:34 +0100 Subject: Fix security hole from ext.php script. Now, ext.php can only serve file under a EXTENSIONS_PATH/ext_dir/static/ directory. A 400 Bad Request error will be returned for other files. See https://github.com/FreshRSS/FreshRSS/issues/252 And https://github.com/FreshRSS/FreshRSS/commit/f9b037742a0aeb49cab86782d1a59913c2de47b --- lib/Minz/Extension.php | 4 ++-- p/ext.php | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/lib/Minz/Extension.php b/lib/Minz/Extension.php index 72a375a6d..ecf510ea2 100644 --- a/lib/Minz/Extension.php +++ b/lib/Minz/Extension.php @@ -106,9 +106,9 @@ class Minz_Extension { */ public function getFileUrl($filename, $type) { $dir = end(explode('/', $this->path)); - $file_name_url = urlencode($dir . '/' . $filename); + $file_name_url = urlencode($dir . '/static/' . $filename); - $absolute_path = $this->path . '/' . $filename; + $absolute_path = $this->path . '/static/' . $filename; $mtime = @filemtime($absolute_path); $url = '/ext.php?f=' . $file_name_url . diff --git a/p/ext.php b/p/ext.php index 39c224a84..5c9f9125f 100644 --- a/p/ext.php +++ b/p/ext.php @@ -7,10 +7,42 @@ if (!isset($_GET['f']) || require('../constants.php'); +/** + * Check if a file can be served by ext.php. A valid file is under a + * EXTENSIONS_PATH/extension_name/static/ directory. + * + * You should sanitize path by using the realpath() function. + * + * @param $path the path to the file we want to serve. + * @return true if it can be served, false else. + * + */ +function is_valid_path($path) { + // It must be under the extension path. + $in_ext_path = (substr($path, 0, strlen(EXTENSIONS_PATH)) === EXTENSIONS_PATH); + if (!$in_ext_path) { + return false; + } + + // File to serve must be under a `ext_dir/static/` directory. + $path_relative_to_ext = substr($path, strlen(EXTENSIONS_PATH) + 1); + $path_splitted = explode('/', $path_relative_to_ext); + if (count($path_splitted) < 3 || $path_splitted[1] !== 'static') { + return false; + } + + return true; +} + $file_name = urldecode($_GET['f']); $file_type = $_GET['t']; -$absolute_filename = EXTENSIONS_PATH . '/' . $file_name; +$absolute_filename = realpath(EXTENSIONS_PATH . '/' . $file_name); + +if (!is_valid_path($absolute_filename)) { + header('HTTP/1.1 400 Bad Request'); + die(); +} switch ($file_type) { case 'css': -- cgit v1.2.3 From 6a706c95df557d1897608c89d3f5e0d0e9cd20ac Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Fri, 5 Dec 2014 07:07:23 -0500 Subject: fix typo --- app/i18n/en/gen.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index 5dc2c3e28..a7f51e8f9 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -62,7 +62,7 @@ return array( 'author' => 'Author', 'auto_load_more' => 'Load next articles at the page bottom', 'auto_read_when' => 'Mark article as read…', - 'auto_remove_article' => 'Hide articles after reading' + 'auto_remove_article' => 'Hide articles after reading', 'auto_share' => 'Share', 'auto_share_help' => 'If there is only one sharing mode, it is used. Else modes are accessible by their number.', 'back_to_rss_feeds' => '← Go back to your RSS feeds', -- cgit v1.2.3 From 9fc60317eecba785b66011f04b9a5150296f2df6 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 5 Dec 2014 14:17:02 +0100 Subject: First draft for listing and manipulate extensions See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/extensionController.php | 43 +++++++++++++++++++++++++++++++++ app/layout/aside_configure.phtml | 4 +++ app/layout/header.phtml | 1 + app/views/extension/index.phtml | 35 +++++++++++++++++++++++++++ lib/Minz/Extension.php | 20 +++++++++++++++ lib/Minz/ExtensionManager.php | 17 +++++++++++++ 6 files changed, 120 insertions(+) create mode 100644 app/Controllers/extensionController.php create mode 100644 app/views/extension/index.phtml diff --git a/app/Controllers/extensionController.php b/app/Controllers/extensionController.php new file mode 100644 index 000000000..504be56d3 --- /dev/null +++ b/app/Controllers/extensionController.php @@ -0,0 +1,43 @@ +view->extension_list = Minz_ExtensionManager::list_extensions(); + } + + public function configureAction() { + if (Minz_Request::param('ajax')) { + $this->view->_useLayout(false); + } + } + + public function enableAction() { + + } + + public function disableAction() { + + } + + public function removeAction() { + + } +} diff --git a/app/layout/aside_configure.phtml b/app/layout/aside_configure.phtml index 53c52d3e3..f7f3617c4 100644 --- a/app/layout/aside_configure.phtml +++ b/app/layout/aside_configure.phtml @@ -22,6 +22,10 @@ Minz_Request::actionName() === 'profile'? ' active' : ''; ?>"> +
  • + +
  • +
  • diff --git a/app/views/extension/index.phtml b/app/views/extension/index.phtml new file mode 100644 index 000000000..c6b7c84a1 --- /dev/null +++ b/app/views/extension/index.phtml @@ -0,0 +1,35 @@ +partial('aside_configure'); ?> + +
    + + +

    + + extension_list)) { ?> + + extension_list as $ext) { ?> +
      +
    • + getName()); ?> +
      + + is_enabled()) { ?> + + + + + + + +
      +
    • +
    • getName(); ?>
    • +
    + + +

    + +
    + + +
    diff --git a/lib/Minz/Extension.php b/lib/Minz/Extension.php index ecf510ea2..a1fdd659b 100644 --- a/lib/Minz/Extension.php +++ b/lib/Minz/Extension.php @@ -17,6 +17,8 @@ class Minz_Extension { 'user', ); + private $is_enabled; + /** * The constructor to assign specific information to the extension. * @@ -41,6 +43,8 @@ class Minz_Extension { $this->description = isset($meta_info['description']) ? $meta_info['description'] : ''; $this->version = isset($meta_info['version']) ? $meta_info['version'] : '0.1'; $this->setType(isset($meta_info['type']) ? $meta_info['type'] : 'user'); + + $this->is_enabled = false; } /** @@ -66,6 +70,22 @@ class Minz_Extension { */ public function init() {} + /** + * Set the current extension to enable. + */ + public function enable() { + $this->is_enabled = true; + } + + /** + * Return if the extension is currently enabled. + * + * @return true if extension is enabled, false else. + */ + public function is_enabled() { + return $this->is_enabled; + } + /** * Getters and setters. */ diff --git a/lib/Minz/ExtensionManager.php b/lib/Minz/ExtensionManager.php index 789557b9e..6c32ccf19 100644 --- a/lib/Minz/ExtensionManager.php +++ b/lib/Minz/ExtensionManager.php @@ -144,6 +144,7 @@ class Minz_ExtensionManager { if (isset(self::$ext_list[$ext_name])) { $ext = self::$ext_list[$ext_name]; self::$ext_list_enabled[$ext_name] = $ext; + $ext->enable(); $ext->init(); } } @@ -158,4 +159,20 @@ class Minz_ExtensionManager { self::enable($ext_name); } } + + + + /** + * Returns a list of extensions. + * + * @param $only_enabled if true returns only the enabled extensions (false by default). + * @return an array of extensions. + */ + public static function list_extensions($only_enabled = false) { + if ($only_enabled) { + return self::$ext_list_enabled; + } else { + return self::$ext_list; + } + } } -- cgit v1.2.3 From f8aa66152fcab24ae7cd9663dab0c0c96a45ca24 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 5 Dec 2014 14:48:09 +0100 Subject: Give possibility to register a new Controller. - Add a Extension->registerController(name) method - Controllers must be written in extension_dir/controllers/nameController.php - Controllers must be named as FreshExtension_name_Controller - Controllers must extend Minz_ActionController See https://github.com/FreshRSS/FreshRSS/issues/252 --- lib/Minz/Dispatcher.php | 47 ++++++++++++++++++++++++++++++++++++++++++++--- lib/Minz/Extension.php | 13 +++++++++++++ 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/lib/Minz/Dispatcher.php b/lib/Minz/Dispatcher.php index f62a92911..66789a3d3 100644 --- a/lib/Minz/Dispatcher.php +++ b/lib/Minz/Dispatcher.php @@ -15,6 +15,7 @@ class Minz_Dispatcher { /* singleton */ private static $instance = null; private static $needsReset; + private static $registrations = array(); private $controller; @@ -38,7 +39,7 @@ class Minz_Dispatcher { self::$needsReset = false; try { - $this->createController ('FreshRSS_' . Minz_Request::controllerName () . '_Controller'); + $this->createController (Minz_Request::controllerName ()); $this->controller->init (); $this->controller->firstAction (); if (!self::$needsReset) { @@ -73,8 +74,11 @@ class Minz_Dispatcher { * > pas une instance de ActionController */ private function createController ($controller_name) { - $filename = APP_PATH . self::CONTROLLERS_PATH_NAME . '/' - . $controller_name . '.php'; + if (self::isRegistered($controller_name)) { + $controller_name = self::loadController($controller_name); + } else { + $controller_name = 'FreshRSS_' . $controller_name . '_Controller'; + } if (!class_exists ($controller_name)) { throw new Minz_ControllerNotExistException ( @@ -114,4 +118,41 @@ class Minz_Dispatcher { $action_name )); } + + /** + * Register a controller file. + * + * @param $base_name the base name of the controller (i.e. ./?c=) + * @param $controller_name the name of the controller (e.g. HelloWorldController). + * @param $filename the file which contains the controller. + */ + public static function registerController($base_name, $controller_name, $filename) { + if (file_exists($filename)) { + self::$registrations[$base_name] = array( + $controller_name, + $filename, + ); + } + } + + /** + * Return if a controller is registered. + * + * @param $base_name the base name of the controller. + * @return true if the controller has been registered, false else. + */ + public static function isRegistered($base_name) { + return isset(self::$registrations[$base_name]); + } + + /** + * Load a controller file (include) and return its name. + * + * @param $base_name the base name of the controller. + */ + private static function loadController($base_name) { + list($controller_name, $filename) = self::$registrations[$base_name]; + include($filename); + return $controller_name; + } } diff --git a/lib/Minz/Extension.php b/lib/Minz/Extension.php index a1fdd659b..ad3465640 100644 --- a/lib/Minz/Extension.php +++ b/lib/Minz/Extension.php @@ -136,4 +136,17 @@ class Minz_Extension { '&' . $mtime; return Minz_Url::display($url); } + + /** + * Register a controller in the Dispatcher. + * + * @param @base_name the base name of the controller. Final name will be: + * FreshExtension__Controller. + */ + public function registerController($base_name) { + $controller_name = 'FreshExtension_' . $base_name . '_Controller'; + $filename = $this->path . '/controllers/' . $base_name . 'Controller.php'; + + Minz_Dispatcher::registerController($base_name, $controller_name, $filename); + } } -- cgit v1.2.3 From c6a682deb94111c1e14cf10e565da3f4214f02dc Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Fri, 5 Dec 2014 15:27:56 +0100 Subject: Extensions can define new views - View base pathname is set to the extension directory - An extension can now override an existing controller / view See https://github.com/FreshRSS/FreshRSS/issues/252 --- lib/Minz/Dispatcher.php | 40 +++++++++++++++++++++++----------------- lib/Minz/Extension.php | 5 +---- lib/Minz/View.php | 10 +++++++--- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/lib/Minz/Dispatcher.php b/lib/Minz/Dispatcher.php index 66789a3d3..edd59c7cc 100644 --- a/lib/Minz/Dispatcher.php +++ b/lib/Minz/Dispatcher.php @@ -68,16 +68,17 @@ class Minz_Dispatcher { /** * Instancie le Controller - * @param $controller_name le nom du controller à instancier + * @param $base_name le nom du controller à instancier * @exception ControllerNotExistException le controller n'existe pas * @exception ControllerNotActionControllerException controller n'est * > pas une instance de ActionController */ - private function createController ($controller_name) { - if (self::isRegistered($controller_name)) { - $controller_name = self::loadController($controller_name); + private function createController ($base_name) { + if (self::isRegistered($base_name)) { + self::loadController($base_name); + $controller_name = 'FreshExtension_' . $base_name . '_Controller'; } else { - $controller_name = 'FreshRSS_' . $controller_name . '_Controller'; + $controller_name = 'FreshRSS_' . $base_name . '_Controller'; } if (!class_exists ($controller_name)) { @@ -94,6 +95,10 @@ class Minz_Dispatcher { Minz_Exception::ERROR ); } + + if (self::isRegistered($base_name)) { + $this->setViewPath($this->controller, $base_name); + } } /** @@ -123,15 +128,11 @@ class Minz_Dispatcher { * Register a controller file. * * @param $base_name the base name of the controller (i.e. ./?c=) - * @param $controller_name the name of the controller (e.g. HelloWorldController). - * @param $filename the file which contains the controller. + * @param $base_path the base path where we should look into to find info. */ - public static function registerController($base_name, $controller_name, $filename) { - if (file_exists($filename)) { - self::$registrations[$base_name] = array( - $controller_name, - $filename, - ); + public static function registerController($base_name, $base_path) { + if (!self::isRegistered($base_name)) { + self::$registrations[$base_name] = $base_path; } } @@ -146,13 +147,18 @@ class Minz_Dispatcher { } /** - * Load a controller file (include) and return its name. + * Load a controller file (include). * * @param $base_name the base name of the controller. */ private static function loadController($base_name) { - list($controller_name, $filename) = self::$registrations[$base_name]; - include($filename); - return $controller_name; + $base_path = self::$registrations[$base_name]; + $controller_filename = $base_path . '/controllers/' . $base_name . 'Controller.php'; + include($controller_filename); + } + + private static function setViewPath($controller, $base_name) { + $base_path = self::$registrations[$base_name]; + $controller->view()->setBasePathname($base_path); } } diff --git a/lib/Minz/Extension.php b/lib/Minz/Extension.php index ad3465640..5a61ba2e0 100644 --- a/lib/Minz/Extension.php +++ b/lib/Minz/Extension.php @@ -144,9 +144,6 @@ class Minz_Extension { * FreshExtension__Controller. */ public function registerController($base_name) { - $controller_name = 'FreshExtension_' . $base_name . '_Controller'; - $filename = $this->path . '/controllers/' . $base_name . 'Controller.php'; - - Minz_Dispatcher::registerController($base_name, $controller_name, $filename); + Minz_Dispatcher::registerController($base_name, $this->path); } } diff --git a/lib/Minz/View.php b/lib/Minz/View.php index b40448491..bdfbbe63c 100644 --- a/lib/Minz/View.php +++ b/lib/Minz/View.php @@ -12,6 +12,7 @@ class Minz_View { const LAYOUT_PATH_NAME = '/layout'; const LAYOUT_FILENAME = '/layout.phtml'; + private $base_pathname = APP_PATH; private $view_filename = ''; private $use_layout = null; @@ -35,12 +36,15 @@ class Minz_View { * Change le fichier de vue en fonction d'un controller / action */ public function change_view($controller_name, $action_name) { - $this->view_filename = APP_PATH - . self::VIEWS_PATH_NAME . '/' + $this->view_filename = self::VIEWS_PATH_NAME . '/' . $controller_name . '/' . $action_name . '.phtml'; } + public function setBasePathname($base_pathname) { + $this->base_pathname = $base_pathname; + } + /** * Construit la vue */ @@ -70,7 +74,7 @@ class Minz_View { * Affiche la Vue en elle-même */ public function render () { - if ((include($this->view_filename)) === false) { + if ((include($this->base_pathname . $this->view_filename)) === false) { Minz_Log::notice('File not found: `' . $this->view_filename . '`'); } } -- cgit v1.2.3 From a08c382e0651f22a7db06feba225f3d49289763d Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 6 Dec 2014 15:20:20 +0100 Subject: Separate views registration from controllers one. - Add an Extension->registerViews() method. - Views are first searched in extension paths, then in APP_PATH. - It gives a way to override easily existing controllers / views. - Change include into an include_once in Dispatcher for new controllers. See https://github.com/FreshRSS/FreshRSS/issues/252 --- lib/Minz/Dispatcher.php | 6 +----- lib/Minz/Extension.php | 7 +++++++ lib/Minz/View.php | 28 ++++++++++++++++++++++++---- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/lib/Minz/Dispatcher.php b/lib/Minz/Dispatcher.php index edd59c7cc..125ce5757 100644 --- a/lib/Minz/Dispatcher.php +++ b/lib/Minz/Dispatcher.php @@ -95,10 +95,6 @@ class Minz_Dispatcher { Minz_Exception::ERROR ); } - - if (self::isRegistered($base_name)) { - $this->setViewPath($this->controller, $base_name); - } } /** @@ -154,7 +150,7 @@ class Minz_Dispatcher { private static function loadController($base_name) { $base_path = self::$registrations[$base_name]; $controller_filename = $base_path . '/controllers/' . $base_name . 'Controller.php'; - include($controller_filename); + include_once $controller_filename; } private static function setViewPath($controller, $base_name) { diff --git a/lib/Minz/Extension.php b/lib/Minz/Extension.php index 5a61ba2e0..490a5c5cb 100644 --- a/lib/Minz/Extension.php +++ b/lib/Minz/Extension.php @@ -146,4 +146,11 @@ class Minz_Extension { public function registerController($base_name) { Minz_Dispatcher::registerController($base_name, $this->path); } + + /** + * Register the views in order to be accessible by the application. + */ + public function registerViews() { + Minz_View::addBasePathname($this->path); + } } diff --git a/lib/Minz/View.php b/lib/Minz/View.php index bdfbbe63c..1bc2e862d 100644 --- a/lib/Minz/View.php +++ b/lib/Minz/View.php @@ -12,10 +12,10 @@ class Minz_View { const LAYOUT_PATH_NAME = '/layout'; const LAYOUT_FILENAME = '/layout.phtml'; - private $base_pathname = APP_PATH; private $view_filename = ''; private $use_layout = null; + private static $base_pathnames = array(APP_PATH); private static $title = ''; private static $styles = array (); private static $scripts = array (); @@ -41,8 +41,15 @@ class Minz_View { . $action_name . '.phtml'; } - public function setBasePathname($base_pathname) { - $this->base_pathname = $base_pathname; + /** + * Add a base pathname to search views. + * + * New pathnames will be added at the beginning of the list. + * + * @param $base_pathname the new base pathname. + */ + public static function addBasePathname($base_pathname) { + array_unshift(self::$base_pathnames, $base_pathname); } /** @@ -74,7 +81,20 @@ class Minz_View { * Affiche la Vue en elle-même */ public function render () { - if ((include($this->base_pathname . $this->view_filename)) === false) { + $view_found = false; + + // We search the view in the list of base pathnames. Only the first view + // found is considered. + foreach (self::$base_pathnames as $base) { + $filename = $base . $this->view_filename; + if (file_exists($filename)) { + include $filename; + $view_found = true; + break; + } + } + + if (!$view_found) { Minz_Log::notice('File not found: `' . $this->view_filename . '`'); } } -- cgit v1.2.3 From 2e4682ebd451f8dd291e11141553add9164cbbef Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 6 Dec 2014 16:17:11 +0100 Subject: Add enable / disable extension features See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/extensionController.php | 72 ++++++++++++++++++++++++++++++++- app/Models/Configuration.php | 12 ++++++ lib/Minz/ExtensionManager.php | 18 +++++++-- 3 files changed, 97 insertions(+), 5 deletions(-) diff --git a/app/Controllers/extensionController.php b/app/Controllers/extensionController.php index 504be56d3..415f489a6 100644 --- a/app/Controllers/extensionController.php +++ b/app/Controllers/extensionController.php @@ -29,12 +29,80 @@ class FreshRSS_extension_Controller extends Minz_ActionController { } } + /** + * This action enables a disabled extension for the current user. + * + * System extensions can only be enabled by an administrator. + * + * Parameter is: + * - e: the extension name (urlencoded). + */ public function enableAction() { - + $url_redirect = array('c' => 'extension', 'a' => 'index'); + + if (Minz_Request::isPost()) { + $ext_name = urldecode(Minz_Request::param('e')); + $ext = Minz_ExtensionManager::find_extension($ext_name); + + if (is_null($ext)) { + Minz_Request::bad('feedback.extension.not_found', $url_redirect); + } + + if ($ext->is_enabled()) { + Minz_Request::bad('feedback.extension.already_enabled', $url_redirect); + } + + if ($ext->getType() === 'system' && !FreshRSS_Auth::hasAccess('admin')) { + Minz_Request::bad('feedback.extension.no_access', $url_redirect); + } + + $ext->install(); + + FreshRSS_Context::$conf->addExtension($ext_name); + FreshRSS_Context::$conf->save(); + + Minz_Request::good('feedback.extension.enabled', $url_redirect); + } + + Minz_Request::forward($url_redirect, true); } + /** + * This action disables an enabled extension for the current user. + * + * System extensions can only be disabled by an administrator. + * + * Parameter is: + * - e: the extension name (urlencoded). + */ public function disableAction() { - + $url_redirect = array('c' => 'extension', 'a' => 'index'); + + if (Minz_Request::isPost()) { + $ext_name = urldecode(Minz_Request::param('e')); + $ext = Minz_ExtensionManager::find_extension($ext_name); + + if (is_null($ext)) { + Minz_Request::bad('feedback.extension.not_found', $url_redirect); + } + + if (!$ext->is_enabled()) { + Minz_Request::bad('feedback.extension.not_enabled', $url_redirect); + } + + if ($ext->getType() === 'system' && !FreshRSS_Auth::hasAccess('admin')) { + Minz_Request::bad('feedback.extension.no_access', $url_redirect); + } + + $ext->uninstall(); + + FreshRSS_Context::$conf->removeExtension($ext_name); + FreshRSS_Context::$conf->save(); + + Minz_Request::good('feedback.extension.disabled', $url_redirect); + } + + Minz_Request::forward($url_redirect, true); } public function removeAction() { diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php index 13ce43990..83a00d4bb 100644 --- a/app/Models/Configuration.php +++ b/app/Models/Configuration.php @@ -350,4 +350,16 @@ class FreshRSS_Configuration { } $this->data['extensions_enabled'] = $value; } + public function removeExtension($ext_name) { + $this->data['extensions_enabled'] = array_diff( + $this->data['extensions_enabled'], + array($ext_name) + ); + } + public function addExtension($ext_name) { + $found = array_search($ext_name, $this->data['extensions_enabled']) !== false; + if (!$found) { + $this->data['extensions_enabled'][] = $ext_name; + } + } } diff --git a/lib/Minz/ExtensionManager.php b/lib/Minz/ExtensionManager.php index 6c32ccf19..46e421bac 100644 --- a/lib/Minz/ExtensionManager.php +++ b/lib/Minz/ExtensionManager.php @@ -160,10 +160,8 @@ class Minz_ExtensionManager { } } - - /** - * Returns a list of extensions. + * Return a list of extensions. * * @param $only_enabled if true returns only the enabled extensions (false by default). * @return an array of extensions. @@ -175,4 +173,18 @@ class Minz_ExtensionManager { return self::$ext_list; } } + + /** + * Return an extension by its name. + * + * @param $ext_name the name of the extension. + * @return the corresponding extension or null if it doesn't exist. + */ + public static function find_extension($ext_name) { + if (!isset(self::$ext_list[$ext_name])) { + return null; + } + + return self::$ext_list[$ext_name]; + } } -- cgit v1.2.3 From eaaf8cdbf1e87ad22d25257eb99a4b80b579e661 Mon Sep 17 00:00:00 2001 From: Alexis Degrugillier Date: Sat, 6 Dec 2014 10:15:34 -0500 Subject: Add comments --- app/Models/EntryDAO.php | 77 +++++++++++++++++++++++++++++++++++++++++++ app/Models/EntryDAOSQLite.php | 45 +++++++++++++++++++++++++ 2 files changed, 122 insertions(+) diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php index 5d2909c62..4d06ac028 100644 --- a/app/Models/EntryDAO.php +++ b/app/Models/EntryDAO.php @@ -80,6 +80,16 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { return -1; } + /** + * Toggle favorite marker on one or more article + * + * @todo simplify the query by removing the str_repeat. I am pretty sure + * there is an other way to do that. + * + * @param integer|array $ids + * @param boolean $is_favorite + * @return false|integer + */ public function markFavorite($ids, $is_favorite = true) { if (!is_array($ids)) { $ids = array($ids); @@ -99,6 +109,17 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { } } + /** + * Update the unread article cache held on every feed details. + * Depending on the parameters, it updates the cache on one feed, on all + * feeds from one category or on all feeds. + * + * @todo It can use the query builder refactoring to build that query + * + * @param false|integer $catId category ID + * @param false|integer $feedId feed ID + * @return boolean + */ protected function updateCacheUnreads($catId = false, $feedId = false) { $sql = 'UPDATE `' . $this->prefix . 'feed` f ' . 'LEFT OUTER JOIN (' @@ -129,6 +150,19 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { } } + /** + * Toggle the read marker on one or more article. + * Then the cache is updated. + * + * @todo change the way the query is build because it seems there is + * unnecessary code in here. For instance, the part with the str_repeat. + * @todo remove code duplication. It seems the code is basically the + * same if it is an array or not. + * + * @param integer|array $ids + * @param boolean $is_read + * @return integer affected rows + */ public function markRead($ids, $is_read = true) { if (is_array($ids)) { //Many IDs at once (used by API) if (count($ids) < 6) { //Speed heuristics @@ -172,6 +206,27 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { } } + /** + * Mark all entries as read depending on parameters. + * If $onlyFavorites is true, it is used when the user mark as read in + * the favorite pseudo-category. + * If $priorityMin is greater than 0, it is used when the user mark as + * read in the main feed pseudo-category. + * Then the cache is updated. + * + * If $idMax equals 0, a deprecated debug message is logged + * + * @todo refactor this method along with markReadCat and markReadFeed + * since they are all doing the same thing. I think we need to build a + * tool to generate the query instead of having queries all over the + * place. It will be reused also for the filtering making every thing + * separated. + * + * @param integer $idMax fail safe article ID + * @param boolean $onlyFavorites + * @param integer $priorityMin + * @return integer affected rows + */ public function markReadEntries($idMax = 0, $onlyFavorites = false, $priorityMin = 0) { if ($idMax == 0) { $idMax = time() . '000000'; @@ -200,6 +255,17 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { return $affected; } + /** + * Mark all the articles in a category as read. + * There is a fail safe to prevent to mark as read articles that are + * loaded during the mark as read action. Then the cache is updated. + * + * If $idMax equals 0, a deprecated debug message is logged + * + * @param integer $id category ID + * @param integer $idMax fail safe article ID + * @return integer affected rows + */ public function markReadCat($id, $idMax = 0) { if ($idMax == 0) { $idMax = time() . '000000'; @@ -223,6 +289,17 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo { return $affected; } + /** + * Mark all the articles in a feed as read. + * There is a fail safe to prevent to mark as read articles that are + * loaded during the mark as read action. Then the cache is updated. + * + * If $idMax equals 0, a deprecated debug message is logged + * + * @param integer $id feed ID + * @param integer $idMax fail safe article ID + * @return integer affected rows + */ public function markReadFeed($id, $idMax = 0) { if ($idMax == 0) { $idMax = time() . '000000'; diff --git a/app/Models/EntryDAOSQLite.php b/app/Models/EntryDAOSQLite.php index 4a3fe24a2..bb1539e0c 100644 --- a/app/Models/EntryDAOSQLite.php +++ b/app/Models/EntryDAOSQLite.php @@ -31,6 +31,19 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { } } + /** + * Toggle the read marker on one or more article. + * Then the cache is updated. + * + * @todo change the way the query is build because it seems there is + * unnecessary code in here. For instance, the part with the str_repeat. + * @todo remove code duplication. It seems the code is basically the + * same if it is an array or not. + * + * @param integer|array $ids + * @param boolean $is_read + * @return integer affected rows + */ public function markRead($ids, $is_read = true) { if (is_array($ids)) { //Many IDs at once (used by API) if (true) { //Speed heuristics //TODO: Not implemented yet for SQLite (so always call IDs one by one) @@ -69,6 +82,27 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { } } + /** + * Mark all entries as read depending on parameters. + * If $onlyFavorites is true, it is used when the user mark as read in + * the favorite pseudo-category. + * If $priorityMin is greater than 0, it is used when the user mark as + * read in the main feed pseudo-category. + * Then the cache is updated. + * + * If $idMax equals 0, a deprecated debug message is logged + * + * @todo refactor this method along with markReadCat and markReadFeed + * since they are all doing the same thing. I think we need to build a + * tool to generate the query instead of having queries all over the + * place. It will be reused also for the filtering making every thing + * separated. + * + * @param integer $idMax fail safe article ID + * @param boolean $onlyFavorites + * @param integer $priorityMin + * @return integer affected rows + */ public function markReadEntries($idMax = 0, $onlyFavorites = false, $priorityMin = 0) { if ($idMax == 0) { $idMax = time() . '000000'; @@ -95,6 +129,17 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO { return $affected; } + /** + * Mark all the articles in a category as read. + * There is a fail safe to prevent to mark as read articles that are + * loaded during the mark as read action. Then the cache is updated. + * + * If $idMax equals 0, a deprecated debug message is logged + * + * @param integer $id category ID + * @param integer $idMax fail safe article ID + * @return integer affected rows + */ public function markReadCat($id, $idMax = 0) { if ($idMax == 0) { $idMax = time() . '000000'; -- cgit v1.2.3 From 4c888590e6f0fd89fc1dccebb5e815883eeaa54c Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 6 Dec 2014 16:39:10 +0100 Subject: Improve system/user types for extensions - system extensions can only be managed by an administrator - system extensions are loaded for all users (even if not logged) - user extensions are loaded for logged users only - system extensions loading is saved in global config.php file See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/extensionController.php | 42 ++++++++++++++++++++++----------- app/FreshRSS.php | 8 ++++--- app/views/extension/index.phtml | 4 ++++ lib/Minz/Configuration.php | 19 +++++++++++++-- 4 files changed, 54 insertions(+), 19 deletions(-) diff --git a/app/Controllers/extensionController.php b/app/Controllers/extensionController.php index 415f489a6..e348d9f31 100644 --- a/app/Controllers/extensionController.php +++ b/app/Controllers/extensionController.php @@ -52,16 +52,23 @@ class FreshRSS_extension_Controller extends Minz_ActionController { Minz_Request::bad('feedback.extension.already_enabled', $url_redirect); } - if ($ext->getType() === 'system' && !FreshRSS_Auth::hasAccess('admin')) { - Minz_Request::bad('feedback.extension.no_access', $url_redirect); - } + if ($ext->getType() === 'system' && FreshRSS_Auth::hasAccess('admin')) { + $ext->install(); + + Minz_Configuration::addExtension($ext_name); + Minz_Configuration::writeFile(); - $ext->install(); + Minz_Request::good('feedback.extension.enabled', $url_redirect); + } elseif ($ext->getType() === 'user') { + $ext->install(); - FreshRSS_Context::$conf->addExtension($ext_name); - FreshRSS_Context::$conf->save(); + FreshRSS_Context::$conf->addExtension($ext_name); + FreshRSS_Context::$conf->save(); - Minz_Request::good('feedback.extension.enabled', $url_redirect); + Minz_Request::good('feedback.extension.enabled', $url_redirect); + } else { + Minz_Request::bad('feedback.extension.no_access', $url_redirect); + } } Minz_Request::forward($url_redirect, true); @@ -90,16 +97,23 @@ class FreshRSS_extension_Controller extends Minz_ActionController { Minz_Request::bad('feedback.extension.not_enabled', $url_redirect); } - if ($ext->getType() === 'system' && !FreshRSS_Auth::hasAccess('admin')) { - Minz_Request::bad('feedback.extension.no_access', $url_redirect); - } + if ($ext->getType() === 'system' && FreshRSS_Auth::hasAccess('admin')) { + $ext->uninstall(); + + Minz_Configuration::removeExtension($ext_name); + Minz_Configuration::writeFile(); - $ext->uninstall(); + Minz_Request::good('feedback.extension.disabled', $url_redirect); + } elseif ($ext->getType() === 'user') { + $ext->uninstall(); - FreshRSS_Context::$conf->removeExtension($ext_name); - FreshRSS_Context::$conf->save(); + FreshRSS_Context::$conf->removeExtension($ext_name); + FreshRSS_Context::$conf->save(); - Minz_Request::good('feedback.extension.disabled', $url_redirect); + Minz_Request::good('feedback.extension.disabled', $url_redirect); + } else { + Minz_Request::bad('feedback.extension.no_access', $url_redirect); + } } Minz_Request::forward($url_redirect, true); diff --git a/app/FreshRSS.php b/app/FreshRSS.php index dc7d0b375..b91dfcc46 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -29,9 +29,11 @@ class FreshRSS extends Minz_FrontController { // Load context and configuration. FreshRSS_Context::init(); - // Enable extensions for the current user. - $ext_list = FreshRSS_Context::$conf->extensions_enabled; - Minz_ExtensionManager::enable_by_list($ext_list); + // Enable extensions for the current (logged) user. + if (FreshRSS_Auth::hasAccess()) { + $ext_list = FreshRSS_Context::$conf->extensions_enabled; + Minz_ExtensionManager::enable_by_list($ext_list); + } // Init i18n. Minz_Session::_param('language', FreshRSS_Context::$conf->language); diff --git a/app/views/extension/index.phtml b/app/views/extension/index.phtml index c6b7c84a1..0be03d7b5 100644 --- a/app/views/extension/index.phtml +++ b/app/views/extension/index.phtml @@ -10,6 +10,7 @@ extension_list as $ext) { ?>
    • + getType() === 'user' || FreshRSS_Auth::hasAccess('admin')) { ?> getName()); ?>
      @@ -22,6 +23,9 @@
      + + +
    • getName(); ?>
    diff --git a/lib/Minz/Configuration.php b/lib/Minz/Configuration.php index 4d3ab0964..4a3221ef5 100644 --- a/lib/Minz/Configuration.php +++ b/lib/Minz/Configuration.php @@ -165,6 +165,19 @@ class Minz_Configuration { self::$unsafe_autologin_enabled = (bool)$value; } + public function removeExtension($ext_name) { + self::$extensions_enabled = array_diff( + self::$extensions_enabled, + array($ext_name) + ); + } + public function addExtension($ext_name) { + $found = array_search($ext_name, self::$extensions_enabled) !== false; + if (!$found) { + self::$extensions_enabled[] = $ext_name; + } + } + /** * Initialise les variables de configuration * @exception Minz_FileNotExistException si le CONF_PATH_NAME n'existe pas @@ -197,6 +210,7 @@ class Minz_Configuration { ), 'limits' => self::$limits, 'db' => self::$db, + 'extensions_enabled' => self::$extensions_enabled, ); @rename(DATA_PATH . self::CONF_PATH_NAME, DATA_PATH . self::CONF_PATH_NAME . '.bak.php'); $result = file_put_contents(DATA_PATH . self::CONF_PATH_NAME, " Date: Sat, 6 Dec 2014 16:48:13 +0100 Subject: Fix typo (extensions) - change feedback.extension into feedback.extensions - disable button is pushed by default See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/extensionController.php | 20 ++++++++++---------- app/views/extension/index.phtml | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/Controllers/extensionController.php b/app/Controllers/extensionController.php index e348d9f31..543398b05 100644 --- a/app/Controllers/extensionController.php +++ b/app/Controllers/extensionController.php @@ -45,11 +45,11 @@ class FreshRSS_extension_Controller extends Minz_ActionController { $ext = Minz_ExtensionManager::find_extension($ext_name); if (is_null($ext)) { - Minz_Request::bad('feedback.extension.not_found', $url_redirect); + Minz_Request::bad('feedback.extensions.not_found', $url_redirect); } if ($ext->is_enabled()) { - Minz_Request::bad('feedback.extension.already_enabled', $url_redirect); + Minz_Request::bad('feedback.extensions.already_enabled', $url_redirect); } if ($ext->getType() === 'system' && FreshRSS_Auth::hasAccess('admin')) { @@ -58,16 +58,16 @@ class FreshRSS_extension_Controller extends Minz_ActionController { Minz_Configuration::addExtension($ext_name); Minz_Configuration::writeFile(); - Minz_Request::good('feedback.extension.enabled', $url_redirect); + Minz_Request::good('feedback.extensions.enabled', $url_redirect); } elseif ($ext->getType() === 'user') { $ext->install(); FreshRSS_Context::$conf->addExtension($ext_name); FreshRSS_Context::$conf->save(); - Minz_Request::good('feedback.extension.enabled', $url_redirect); + Minz_Request::good('feedback.extensions.enabled', $url_redirect); } else { - Minz_Request::bad('feedback.extension.no_access', $url_redirect); + Minz_Request::bad('feedback.extensions.no_access', $url_redirect); } } @@ -90,11 +90,11 @@ class FreshRSS_extension_Controller extends Minz_ActionController { $ext = Minz_ExtensionManager::find_extension($ext_name); if (is_null($ext)) { - Minz_Request::bad('feedback.extension.not_found', $url_redirect); + Minz_Request::bad('feedback.extensions.not_found', $url_redirect); } if (!$ext->is_enabled()) { - Minz_Request::bad('feedback.extension.not_enabled', $url_redirect); + Minz_Request::bad('feedback.extensions.not_enabled', $url_redirect); } if ($ext->getType() === 'system' && FreshRSS_Auth::hasAccess('admin')) { @@ -103,16 +103,16 @@ class FreshRSS_extension_Controller extends Minz_ActionController { Minz_Configuration::removeExtension($ext_name); Minz_Configuration::writeFile(); - Minz_Request::good('feedback.extension.disabled', $url_redirect); + Minz_Request::good('feedback.extensions.disabled', $url_redirect); } elseif ($ext->getType() === 'user') { $ext->uninstall(); FreshRSS_Context::$conf->removeExtension($ext_name); FreshRSS_Context::$conf->save(); - Minz_Request::good('feedback.extension.disabled', $url_redirect); + Minz_Request::good('feedback.extensions.disabled', $url_redirect); } else { - Minz_Request::bad('feedback.extension.no_access', $url_redirect); + Minz_Request::bad('feedback.extensions.no_access', $url_redirect); } } diff --git a/app/views/extension/index.phtml b/app/views/extension/index.phtml index 0be03d7b5..142ee4bc2 100644 --- a/app/views/extension/index.phtml +++ b/app/views/extension/index.phtml @@ -15,7 +15,7 @@
    is_enabled()) { ?> - + -- cgit v1.2.3 From 2da7c05fa6768b95a5cd0bd1c8f9934bbff05a03 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 6 Dec 2014 17:15:20 +0100 Subject: Update i18n (extensions) See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/extensionController.php | 30 ++++++++++++++++++++---------- app/i18n/en/admin.php | 5 +++++ app/i18n/en/feedback.php | 8 ++++++++ app/i18n/en/gen.php | 7 +++++++ app/i18n/fr/admin.php | 5 +++++ app/i18n/fr/feedback.php | 8 ++++++++ app/i18n/fr/gen.php | 7 +++++++ app/views/extension/index.phtml | 8 ++++---- 8 files changed, 64 insertions(+), 14 deletions(-) diff --git a/app/Controllers/extensionController.php b/app/Controllers/extensionController.php index 543398b05..35b001094 100644 --- a/app/Controllers/extensionController.php +++ b/app/Controllers/extensionController.php @@ -45,11 +45,13 @@ class FreshRSS_extension_Controller extends Minz_ActionController { $ext = Minz_ExtensionManager::find_extension($ext_name); if (is_null($ext)) { - Minz_Request::bad('feedback.extensions.not_found', $url_redirect); + Minz_Request::bad(_t('feedback.extensions.not_found', $ext_name), + $url_redirect); } if ($ext->is_enabled()) { - Minz_Request::bad('feedback.extensions.already_enabled', $url_redirect); + Minz_Request::bad(_t('feedback.extensions.already_enabled', $ext_name), + $url_redirect); } if ($ext->getType() === 'system' && FreshRSS_Auth::hasAccess('admin')) { @@ -58,16 +60,19 @@ class FreshRSS_extension_Controller extends Minz_ActionController { Minz_Configuration::addExtension($ext_name); Minz_Configuration::writeFile(); - Minz_Request::good('feedback.extensions.enabled', $url_redirect); + Minz_Request::good(_t('feedback.extensions.enabled', $ext_name), + $url_redirect); } elseif ($ext->getType() === 'user') { $ext->install(); FreshRSS_Context::$conf->addExtension($ext_name); FreshRSS_Context::$conf->save(); - Minz_Request::good('feedback.extensions.enabled', $url_redirect); + Minz_Request::good(_t('feedback.extensions.enabled', $ext_name), + $url_redirect); } else { - Minz_Request::bad('feedback.extensions.no_access', $url_redirect); + Minz_Request::bad(_t('feedback.extensions.no_access', $ext_name), + $url_redirect); } } @@ -90,11 +95,13 @@ class FreshRSS_extension_Controller extends Minz_ActionController { $ext = Minz_ExtensionManager::find_extension($ext_name); if (is_null($ext)) { - Minz_Request::bad('feedback.extensions.not_found', $url_redirect); + Minz_Request::bad(_t('feedback.extensions.not_found', $ext_name), + $url_redirect); } if (!$ext->is_enabled()) { - Minz_Request::bad('feedback.extensions.not_enabled', $url_redirect); + Minz_Request::bad(_t('feedback.extensions.not_enabled', $ext_name), + $url_redirect); } if ($ext->getType() === 'system' && FreshRSS_Auth::hasAccess('admin')) { @@ -103,16 +110,19 @@ class FreshRSS_extension_Controller extends Minz_ActionController { Minz_Configuration::removeExtension($ext_name); Minz_Configuration::writeFile(); - Minz_Request::good('feedback.extensions.disabled', $url_redirect); + Minz_Request::good(_t('feedback.extensions.disabled', $ext_name), + $url_redirect); } elseif ($ext->getType() === 'user') { $ext->uninstall(); FreshRSS_Context::$conf->removeExtension($ext_name); FreshRSS_Context::$conf->save(); - Minz_Request::good('feedback.extensions.disabled', $url_redirect); + Minz_Request::good(_t('feedback.extensions.disabled', $ext_name), + $url_redirect); } else { - Minz_Request::bad('feedback.extensions.no_access', $url_redirect); + Minz_Request::bad(_t('feedback.extensions.no_access', $ext_name), + $url_redirect); } } diff --git a/app/i18n/en/admin.php b/app/i18n/en/admin.php index 74f01ae06..d73775d96 100644 --- a/app/i18n/en/admin.php +++ b/app/i18n/en/admin.php @@ -86,6 +86,11 @@ return array( 'ok' => 'You have ZIP extension.', ), ), + 'extensions' => array( + 'empty_list' => 'There is no installed extension', + 'system' => 'System extension (you have no rights on it)', + 'title' => 'Extensions', + ), 'users' => array( 'articles_and_size' => '%s articles (%s)', ), diff --git a/app/i18n/en/feedback.php b/app/i18n/en/feedback.php index b3866f1dc..df1dc5725 100644 --- a/app/i18n/en/feedback.php +++ b/app/i18n/en/feedback.php @@ -1,6 +1,14 @@ array( + 'already_enabled' => '%s is already enabled', + 'disabled' => '%s is now disabled', + 'enabled' => '%s is now enabled', + 'no_access' => 'You have no access on %s', + 'not_enabled' => '%s is not enabled yet', + 'not_found' => '%s does not exist', + ), 'login' => array( 'error' => 'Login is invalid', 'success' => 'You are connected', diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index 9e06357bc..ba5f0c86d 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -190,10 +190,17 @@ return array( 'freshrss_installation' => 'Installation · FreshRSS', 'fri' => 'Fri', 'g+' => 'Google+', + 'actions' => array( + 'disable' => 'Disable', + 'enable' => 'Enable', + 'manage' => 'Manage', + 'remove' => 'Remove', + ), 'menu' => array( 'admin' => 'Administration', 'authentication' => 'Authentication', 'check_install' => 'Installation checking', + 'extensions' => 'Extensions', 'user_management' => 'Manage users', 'user_profile' => 'Profile', ), diff --git a/app/i18n/fr/admin.php b/app/i18n/fr/admin.php index ad1fae6c0..e46a5a7b0 100644 --- a/app/i18n/fr/admin.php +++ b/app/i18n/fr/admin.php @@ -86,6 +86,11 @@ return array( 'ok' => 'Vous disposez de l\'extension ZIP.', ), ), + 'extensions' => array( + 'empty_list' => 'Il n’y a aucune extension installée.', + 'system' => 'Extension système (vous n’avez aucun droit dessus)', + 'title' => 'Extensions', + ), 'users' => array( 'articles_and_size' => '%s articles (%s)', ), diff --git a/app/i18n/fr/feedback.php b/app/i18n/fr/feedback.php index f4bb7cccf..7d3ab9db7 100644 --- a/app/i18n/fr/feedback.php +++ b/app/i18n/fr/feedback.php @@ -1,6 +1,14 @@ array( + 'already_enabled' => '%s est déjà activée', + 'disabled' => '%s est désormais désactivée', + 'enabled' => '%s est désormais activée', + 'no_access' => 'Vous n’avez aucun accès sur %s', + 'not_enabled' => '%s n’est pas encore activée', + 'not_found' => '%s n’existe pas', + ), 'login' => array( 'error' => 'L’identifiant est invalide !', 'success' => 'Vous êtes désormais connecté', diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php index 0b2395bd0..44d8fb837 100644 --- a/app/i18n/fr/gen.php +++ b/app/i18n/fr/gen.php @@ -191,10 +191,17 @@ return array( 'freshrss_installation' => 'Installation · FreshRSS', 'fri' => 'ven.', 'g+' => 'Google+', + 'actions' => array( + 'disable' => 'Désactiver', + 'enable' => 'Activer', + 'manage' => 'Gérer', + 'remove' => 'Supprimer', + ), 'menu' => array( 'admin' => 'Administration', 'authentication' => 'Authentification', 'check_install' => 'Vérification de l’installation', + 'extensions' => 'Extensions', 'user_management' => 'Gestion des utilisateurs', 'user_profile' => 'Profil', ), diff --git a/app/views/extension/index.phtml b/app/views/extension/index.phtml index 142ee4bc2..d34a84452 100644 --- a/app/views/extension/index.phtml +++ b/app/views/extension/index.phtml @@ -13,14 +13,14 @@ getType() === 'user' || FreshRSS_Auth::hasAccess('admin')) { ?> getName()); ?>
    - + is_enabled()) { ?> - + - + - +
    -- cgit v1.2.3 From bc81979a6b25554c4832d5ccb41b427023096463 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 6 Dec 2014 17:25:01 +0100 Subject: Add default behaviour for configure / remove ext See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/extensionController.php | 7 ++++++- app/views/extension/configure.phtml | 12 ++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 app/views/extension/configure.phtml diff --git a/app/Controllers/extensionController.php b/app/Controllers/extensionController.php index 35b001094..a1e39af37 100644 --- a/app/Controllers/extensionController.php +++ b/app/Controllers/extensionController.php @@ -130,6 +130,11 @@ class FreshRSS_extension_Controller extends Minz_ActionController { } public function removeAction() { - + if (!FreshRSS_Auth::hasAccess('admin')) { + Minz_Error::error(403); + } + + $url_redirect = array('c' => 'extension', 'a' => 'index'); + Minz_Request::bad('not implemented yet!', $url_redirect); } } diff --git a/app/views/extension/configure.phtml b/app/views/extension/configure.phtml new file mode 100644 index 000000000..a79e9baac --- /dev/null +++ b/app/views/extension/configure.phtml @@ -0,0 +1,12 @@ +partial('aside_configure'); +} + +?> + +
    +

    Extension name

    + Not implemented yet! +
    \ No newline at end of file -- cgit v1.2.3 From 08546af75ff9a25eac3409649ea4660fe070720c Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sat, 6 Dec 2014 18:48:00 +0100 Subject: Add a first draft for hooks - New Extension->registerHook($hook_name, $hook_function) method to register a new hook - Only one hook works for the moment: entry_before_insert - ExtensionManager::callHook will need to evolve based on future hooks See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/feedController.php | 11 ++++++-- lib/Minz/Extension.php | 10 +++++++ lib/Minz/ExtensionManager.php | 55 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 2 deletions(-) diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 9990a852c..dce79c57a 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -329,9 +329,16 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $id = min(time(), $entry_date) . uSecString(); } + $entry->_id($id); + $entry->_isRead($is_read); + + $entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry); + if (is_null($entry)) { + // An extension has returned a null value, there is nothing to insert. + continue; + } + $values = $entry->toArray(); - $values['id'] = $id; - $values['is_read'] = $is_read; $entryDAO->addEntry($values, $prepared_statement); } } diff --git a/lib/Minz/Extension.php b/lib/Minz/Extension.php index 490a5c5cb..c93ba2520 100644 --- a/lib/Minz/Extension.php +++ b/lib/Minz/Extension.php @@ -153,4 +153,14 @@ class Minz_Extension { public function registerViews() { Minz_View::addBasePathname($this->path); } + + /** + * Register a new hook. + * + * @param $hook_name the hook name (must exist). + * @param $hook_function the function name to call (must be callable). + */ + public function registerHook($hook_name, $hook_function) { + Minz_ExtensionManager::addHook($hook_name, $hook_function, $this); + } } diff --git a/lib/Minz/ExtensionManager.php b/lib/Minz/ExtensionManager.php index 46e421bac..7557e178f 100644 --- a/lib/Minz/ExtensionManager.php +++ b/lib/Minz/ExtensionManager.php @@ -2,6 +2,8 @@ /** * An extension manager to load extensions present in EXTENSIONS_PATH. + * + * @todo see coding style for methods!! */ class Minz_ExtensionManager { private static $ext_metaname = 'metadata.json'; @@ -11,6 +13,11 @@ class Minz_ExtensionManager { private static $ext_auto_enabled = array(); + private static $hook_list = array( + 'entry_before_insert' => array(), // function($entry) + ); + private static $ext_to_hooks = array(); + /** * Initialize the extension manager by loading extensions in EXTENSIONS_PATH. * @@ -131,6 +138,8 @@ class Minz_ExtensionManager { in_array($name, self::$ext_auto_enabled)) { self::enable($ext->getName()); } + + self::$ext_to_hooks[$name] = array(); } /** @@ -187,4 +196,50 @@ class Minz_ExtensionManager { return self::$ext_list[$ext_name]; } + + /** + * Add a hook function to a given hook. + * + * The hook name must be a valid one. For the valid list, see self::$hook_list + * array keys. + * + * @param $hook_name the hook name (must exist). + * @param $hook_function the function name to call (must be callable). + * @param $ext the extension which register the hook. + */ + public static function addHook($hook_name, $hook_function, $ext) { + if (isset(self::$hook_list[$hook_name]) && is_callable($hook_function)) { + self::$hook_list[$hook_name][] = $hook_function; + self::$ext_to_hooks[$ext->getName()][] = $hook_name; + } + } + + /** + * Call functions related to a given hook. + * + * The hook name must be a valid one. For the valid list, see self::$hook_list + * array keys. + * + * @param $hook_name the hook to call. + * @param additionnal parameters (for signature, please see self::$hook_list comments) + * @todo hook functions will have different signatures. So the $res = func($args); + * $args = $res; will not work for all of them in the future. We must + * find a better way to call hooks. + */ + public static function callHook($hook_name) { + $args = func_get_args(); + unset($args[0]); + + $result = $args; + foreach (self::$hook_list[$hook_name] as $function) { + $result = call_user_func_array($function, $args); + + if (is_null($result)) { + break; + } + + $args = $result; + } + return $result; + } } -- cgit v1.2.3 From 5932c3427b060d4f0aeab92d7ed17c8e8d4fd1d7 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 7 Dec 2014 14:31:50 +0100 Subject: Add entry_before_display hook See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/views/index/normal.phtml | 5 +++++ app/views/index/reader.phtml | 11 +++++++---- lib/Minz/ExtensionManager.php | 6 ++++-- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/app/views/index/normal.phtml b/app/views/index/normal.phtml index 02d621bd0..9cbd367d0 100644 --- a/app/views/index/normal.phtml +++ b/app/views/index/normal.phtml @@ -35,6 +35,11 @@ if (!empty($this->entries)) {
    entries as $item) { + $item = Minz_ExtensionManager::callHook('entry_before_display', $item); + if (is_null($item)) { + continue; + } + if ($display_today && $item->isDay(FreshRSS_Days::TODAY, $today)) { ?>
    entries)) { $content_width = FreshRSS_Context::$conf->content_width; ?> -
    - entries as $item) { ?> - -
    +
    entries as $item) { + $item = Minz_ExtensionManager::callHook('entry_before_display', $item); + if (is_null($item)) { + continue; + } + ?>
    array(), // function($entry) + 'entry_before_display' => array(), // function($entry) -> Entry | null + 'entry_before_insert' => array(), // function($entry) -> Entry | null ); private static $ext_to_hooks = array(); @@ -230,7 +232,7 @@ class Minz_ExtensionManager { $args = func_get_args(); unset($args[0]); - $result = $args; + $result = $args[1]; foreach (self::$hook_list[$hook_name] as $function) { $result = call_user_func_array($function, $args); -- cgit v1.2.3 From 7ef4d6c033d6d12a644b6cf39940591901fdcb3b Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 7 Dec 2014 14:39:02 +0100 Subject: Fix entry_before_insert hook The hook must be called also in: - feedController->addAction() - importExportController->importJson() See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/feedController.php | 13 ++++++++++--- app/Controllers/importExportController.php | 6 ++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index dce79c57a..0a7edbee3 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -174,10 +174,17 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feedDAO->beginTransaction(); foreach ($entries as $entry) { // Entries are added without any verification. + $entry->_feed($feed->id()); + $entry->_id(min(time(), $entry->date(true)) . uSecString()); + $entry->_isRead($is_read); + + $entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry); + if (is_null($entry)) { + // An extension has returned a null value, there is nothing to insert. + continue; + } + $values = $entry->toArray(); - $values['id_feed'] = $feed->id(); - $values['id'] = min(time(), $entry->date(true)) . uSecString(); - $values['is_read'] = $is_read; $entryDAO->addEntry($values, $prepared_statement); } $feedDAO->updateLastUpdate($feed->id()); diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 4e2dbd157..c67b30431 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -385,6 +385,12 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $entry->_id(min(time(), $entry->date(true)) . uSecString()); $entry->_tags($tags); + $entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry); + if (is_null($entry)) { + // An extension has returned a null value, there is nothing to insert. + continue; + } + $values = $entry->toArray(); $id = $this->entryDAO->addEntry($values, $prepared_statement); -- cgit v1.2.3 From ea849d7c68cc3de33825c1daafd06b9f8bbf747c Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 7 Dec 2014 15:03:42 +0100 Subject: Prepare better organization of view files for exts View files must be well-splitted to simplify work for extensions. See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/views/helpers/index/normal/entry_bottom.phtml | 84 ++++++++++++ app/views/helpers/index/normal/entry_header.phtml | 40 ++++++ app/views/index/index.phtml | 23 ---- app/views/index/normal.phtml | 157 +++------------------- 4 files changed, 144 insertions(+), 160 deletions(-) create mode 100644 app/views/helpers/index/normal/entry_bottom.phtml create mode 100644 app/views/helpers/index/normal/entry_header.phtml diff --git a/app/views/helpers/index/normal/entry_bottom.phtml b/app/views/helpers/index/normal/entry_bottom.phtml new file mode 100644 index 000000000..704644f99 --- /dev/null +++ b/app/views/helpers/index/normal/entry_bottom.phtml @@ -0,0 +1,84 @@ +sharing; + } + + $bottomline_read = FreshRSS_Context::$conf->bottomline_read; + $bottomline_favorite = FreshRSS_Context::$conf->bottomline_favorite; + $bottomline_sharing = FreshRSS_Context::$conf->bottomline_sharing && (count($sharing) > 0); + $bottomline_tags = FreshRSS_Context::$conf->bottomline_tags; + $bottomline_date = FreshRSS_Context::$conf->bottomline_date; + $bottomline_link = FreshRSS_Context::$conf->bottomline_link; +?>
    • 'entry', 'a' => 'read', 'params' => array('id' => $this->entry->id())); + if ($this->entry->isRead()) { + $arUrl['params']['is_read'] = 0; + } + ?>entry->isRead() ? 'read' : 'unread'); ?>
    • 'entry', 'a' => 'bookmark', 'params' => array('id' => $this->entry->id())); + if ($this->entry->isFavorite()) { + $arUrl['params']['is_favorite'] = 0; + } + ?>entry->isFavorite() ? 'starred' : 'non-starred'); ?>
    • +
    • entry->link()); + $title = urlencode($this->entry->title() . ' · ' . $feed->name()); + ?> + +
    • entry->tags() : null; + if (!empty($tags)) { + ?>
    • + +
    • entry->date(); ?>
    • +
    diff --git a/app/views/helpers/index/normal/entry_header.phtml b/app/views/helpers/index/normal/entry_header.phtml new file mode 100644 index 000000000..b751b884f --- /dev/null +++ b/app/views/helpers/index/normal/entry_header.phtml @@ -0,0 +1,40 @@ +topline_read; + $topline_favorite = FreshRSS_Context::$conf->topline_favorite; + $topline_date = FreshRSS_Context::$conf->topline_date; + $topline_link = FreshRSS_Context::$conf->topline_link; +?>
    • 'entry', 'a' => 'read', 'params' => array('id' => $this->entry->id())); + if ($this->entry->isRead()) { + $arUrl['params']['is_read'] = 0; + } + ?>entry->isRead() ? 'read' : 'unread'); ?>
    • 'entry', 'a' => 'bookmark', 'params' => array('id' => $this->entry->id())); + if ($this->entry->isFavorite()) { + $arUrl['params']['is_favorite'] = 0; + } + ?>entry->isFavorite() ? 'starred' : 'non-starred'); ?>
    • categories, $this->entry->feed()); //We most likely already have the feed object in cache + if ($feed == null) { + $feed = $this->entry->feed(true); + if ($feed == null) { + $feed = FreshRSS_Feed::example(); + } + } + ?>
    • ✇ name(); ?>
    • +
    • entry->title(); ?>
    • +
    • entry->date(); ?> 
    • + +
    diff --git a/app/views/index/index.phtml b/app/views/index/index.phtml index 8b93461dd..e69de29bb 100644 --- a/app/views/index/index.phtml +++ b/app/views/index/index.phtml @@ -1,23 +0,0 @@ -renderHelper('view/normal_view'); - } elseif ($output === 'reader') { - $this->renderHelper('view/reader_view'); - } elseif ($output === 'rss') { - $this->renderHelper('view/rss_view'); - } else { - Minz_Request::_param('output', 'normal'); - $output = 'normal'; - $this->renderHelper('view/normal_view'); - } -} elseif ($output === 'rss') { - // token has already been checked in the controller so we can show the view - $this->renderHelper('view/rss_view'); -} else { - // Normally, it should not happen, but log it anyway - Minz_Log::error('Something is wrong in ' . __FILE__ . ' line ' . __LINE__); -} diff --git a/app/views/index/normal.phtml b/app/views/index/normal.phtml index 9cbd367d0..fd2289365 100644 --- a/app/views/index/normal.phtml +++ b/app/views/index/normal.phtml @@ -7,23 +7,8 @@ if (!empty($this->entries)) { $display_today = true; $display_yesterday = true; $display_others = true; - if (FreshRSS_Auth::hasAccess()) { - $sharing = FreshRSS_Context::$conf->sharing; - } else { - $sharing = array(); - } $hidePosts = !FreshRSS_Context::$conf->display_posts; $lazyload = FreshRSS_Context::$conf->lazyload; - $topline_read = FreshRSS_Context::$conf->topline_read; - $topline_favorite = FreshRSS_Context::$conf->topline_favorite; - $topline_date = FreshRSS_Context::$conf->topline_date; - $topline_link = FreshRSS_Context::$conf->topline_link; - $bottomline_read = FreshRSS_Context::$conf->bottomline_read; - $bottomline_favorite = FreshRSS_Context::$conf->bottomline_favorite; - $bottomline_sharing = FreshRSS_Context::$conf->bottomline_sharing && (count($sharing)); - $bottomline_tags = FreshRSS_Context::$conf->bottomline_tags; - $bottomline_date = FreshRSS_Context::$conf->bottomline_date; - $bottomline_link = FreshRSS_Context::$conf->bottomline_link; $content_width = FreshRSS_Context::$conf->content_width; @@ -35,12 +20,12 @@ if (!empty($this->entries)) {
    entries as $item) { - $item = Minz_ExtensionManager::callHook('entry_before_display', $item); - if (is_null($item)) { + $this->entry = Minz_ExtensionManager::callHook('entry_before_display', $item); + if (is_null($this->entry)) { continue; } - if ($display_today && $item->isDay(FreshRSS_Days::TODAY, $today)) { + if ($display_today && $this->entry->isDay(FreshRSS_Days::TODAY, $today)) { ?>
    entries)) { ?>
    isDay(FreshRSS_Days::YESTERDAY, $today)) { + if ($display_yesterday && $this->entry->isDay(FreshRSS_Days::YESTERDAY, $today)) { ?>
    entries)) { ?>
    isDay(FreshRSS_Days::BEFORE_YESTERDAY, $today)) { + if ($display_others && $this->entry->isDay(FreshRSS_Days::BEFORE_YESTERDAY, $today)) { ?>
    -
    • 'entry', 'a' => 'read', 'params' => array('id' => $item->id())); - if ($item->isRead()) { - $arUrl['params']['is_read'] = 0; - } - ?>isRead() ? 'read' : 'unread'); ?>
    • 'entry', 'a' => 'bookmark', 'params' => array('id' => $item->id())); - if ($item->isFavorite()) { - $arUrl['params']['is_favorite'] = 0; - } - ?>isFavorite() ? 'starred' : 'non-starred'); ?>
    • categories, $item->feed()); //We most likely already have the feed object in cache - if ($feed == null) { - $feed = $item->feed(true); - if ($feed == null) { - $feed = FreshRSS_Feed::example(); - } - } - ?>
    • ✇ name(); ?>
    • -
    • title(); ?>
    • -
    • date(); ?> 
    • - -
    + ?>
    renderHelper('index/normal/entry_header'); -
    + ?>
    -

    title(); ?>

    +

    entry->title(); ?>

    author(); + $author = $this->entry->author(); echo $author != '' ? '
    ' . _t('by_author', $author) . '
    ' : '', - $lazyload && $hidePosts ? lazyimg($item->content()) : $item->content(); + $lazyload && $hidePosts ? lazyimg($this->entry->content()) : $this->entry->content(); ?> -
    -
    • 'entry', 'a' => 'read', 'params' => array('id' => $item->id())); - if ($item->isRead()) { - $arUrl['params']['is_read'] = 0; - } - ?>isRead() ? 'read' : 'unread'); ?>
    • 'entry', 'a' => 'bookmark', 'params' => array('id' => $item->id())); - if ($item->isFavorite()) { - $arUrl['params']['is_favorite'] = 0; - } - ?>isFavorite() ? 'starred' : 'non-starred'); ?>
    • -
    • link()); - $title = urlencode($item->title() . ' · ' . $feed->name()); - ?> -
    • - - - -
    -
    - - tags() : null; - if (!empty($tags)) { - ?>
  • - -
  • date(); ?>
  • - -
    -
    - + $this->renderHelper('index/normal/entry_bottom'); - renderHelper('pagination'); ?> -
    + ?>
    +
    renderHelper('pagination'); +?>
    partial('nav_entries'); ?> -- cgit v1.2.3 From 198b154064a12cfbeefd494afaa69378e77ffce9 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 7 Dec 2014 15:30:24 +0100 Subject: Fix View files inclusion. Now, each part of the view (layout, partials, helpers, views) is included based on the $base_pathnames attribute. Extensions can now override all of these files. See https://github.com/FreshRSS/FreshRSS/issues/252 --- lib/Minz/View.php | 62 ++++++++++++++++++++++++++----------------------------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/lib/Minz/View.php b/lib/Minz/View.php index 1bc2e862d..44034ae9a 100644 --- a/lib/Minz/View.php +++ b/lib/Minz/View.php @@ -13,7 +13,7 @@ class Minz_View { const LAYOUT_FILENAME = '/layout.phtml'; private $view_filename = ''; - private $use_layout = null; + private $use_layout = true; private static $base_pathnames = array(APP_PATH); private static $title = ''; @@ -56,9 +56,6 @@ class Minz_View { * Construit la vue */ public function build () { - if ($this->use_layout === null) { //TODO: avoid file_exists and require views to be explicit - $this->use_layout = file_exists (APP_PATH . self::LAYOUT_PATH_NAME . self::LAYOUT_FILENAME); - } if ($this->use_layout) { $this->buildLayout (); } else { @@ -66,35 +63,40 @@ class Minz_View { } } + /** + * Include a view file. + * + * The file is searched inside list of $base_pathnames. + * + * @param $filename the name of the file to include. + * @return true if the file has been included, false else. + */ + private function includeFile($filename) { + // We search the filename in the list of base pathnames. Only the first view + // found is considered. + foreach (self::$base_pathnames as $base) { + $absolute_filename = $base . $filename; + if (file_exists($absolute_filename)) { + include $absolute_filename; + return true; + } + } + + return false; + } + /** * Construit le layout */ public function buildLayout () { - include ( - APP_PATH - . self::LAYOUT_PATH_NAME - . self::LAYOUT_FILENAME - ); + $this->includeFile(self::LAYOUT_PATH_NAME . self::LAYOUT_FILENAME); } /** * Affiche la Vue en elle-même */ public function render () { - $view_found = false; - - // We search the view in the list of base pathnames. Only the first view - // found is considered. - foreach (self::$base_pathnames as $base) { - $filename = $base . $this->view_filename; - if (file_exists($filename)) { - include $filename; - $view_found = true; - break; - } - } - - if (!$view_found) { + if (!$this->includeFile($this->view_filename)) { Minz_Log::notice('File not found: `' . $this->view_filename . '`'); } } @@ -104,11 +106,8 @@ class Minz_View { * @param $part l'élément partial à ajouter */ public function partial ($part) { - $fic_partial = APP_PATH - . self::LAYOUT_PATH_NAME . '/' - . $part . '.phtml'; - - if ((include($fic_partial)) === false) { + $fic_partial = self::LAYOUT_PATH_NAME . '/' . $part . '.phtml'; + if (!$this->includeFile($fic_partial)) { Minz_Log::warning('File not found: `' . $fic_partial . '`'); } } @@ -118,11 +117,8 @@ class Minz_View { * @param $helper l'élément à afficher */ public function renderHelper ($helper) { - $fic_helper = APP_PATH - . '/views/helpers/' - . $helper . '.phtml'; - - if ((include($fic_helper)) === false) {; + $fic_helper = '/views/helpers/' . $helper . '.phtml'; + if (!$this->includeFile($fic_helper)) { Minz_Log::warning('File not found: `' . $fic_helper . '`'); } } -- cgit v1.2.3 From 2232d1e02a4bc9dbaa99cdbd22efad116ec01403 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Sun, 7 Dec 2014 15:45:34 +0100 Subject: Load user extensions after all the global inits See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/FreshRSS.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/FreshRSS.php b/app/FreshRSS.php index b91dfcc46..88fe60850 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -29,18 +29,18 @@ class FreshRSS extends Minz_FrontController { // Load context and configuration. FreshRSS_Context::init(); - // Enable extensions for the current (logged) user. - if (FreshRSS_Auth::hasAccess()) { - $ext_list = FreshRSS_Context::$conf->extensions_enabled; - Minz_ExtensionManager::enable_by_list($ext_list); - } - // Init i18n. Minz_Session::_param('language', FreshRSS_Context::$conf->language); Minz_Translate::init(); $this->loadStylesAndScripts(); $this->loadNotifications(); + + // Enable extensions for the current (logged) user. + if (FreshRSS_Auth::hasAccess()) { + $ext_list = FreshRSS_Context::$conf->extensions_enabled; + Minz_ExtensionManager::enable_by_list($ext_list); + } } private function loadStylesAndScripts() { -- cgit v1.2.3 From c6dfec3ad351ee3b828c6a2c0a273bad5d9ac0df Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 8 Dec 2014 12:01:47 +0100 Subject: Add behaviour to configure action (extensions) - Put extension configure view in dir_ext/configure.phtml - Handle POST action in Extension->handleConfigureAction() method See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/extensionController.php | 16 ++++++++++++++++ app/views/extension/configure.phtml | 17 ++++++++++++++--- lib/Minz/Extension.php | 21 +++++++++++++++++++++ 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/app/Controllers/extensionController.php b/app/Controllers/extensionController.php index a1e39af37..73b8070cb 100644 --- a/app/Controllers/extensionController.php +++ b/app/Controllers/extensionController.php @@ -27,6 +27,22 @@ class FreshRSS_extension_Controller extends Minz_ActionController { if (Minz_Request::param('ajax')) { $this->view->_useLayout(false); } + + $ext_name = urldecode(Minz_Request::param('e')); + $ext = Minz_ExtensionManager::find_extension($ext_name); + + if (is_null($ext)) { + Minz_Error::error(404); + } + if ($ext->getType() === 'system' && !FreshRSS_Auth::hasAccess('admin')) { + Minz_Error::error(403); + } + + $this->view->extension = $ext; + + if (Minz_Request::isPost()) { + $this->view->extension->handleConfigureAction(); + } } /** diff --git a/app/views/extension/configure.phtml b/app/views/extension/configure.phtml index a79e9baac..295080d5e 100644 --- a/app/views/extension/configure.phtml +++ b/app/views/extension/configure.phtml @@ -7,6 +7,17 @@ if (!Minz_Request::param('ajax')) { ?>
    -

    Extension name

    - Not implemented yet! -
    \ No newline at end of file +

    extension->getName(); ?> (extension->getVersion(); ?>) — extension->getType(); ?>

    + +

    extension->getDescription(); ?> — extension->getAuthor(); ?>

    + +

    + extension->getConfigureView(); + if ($configure_view !== false) { + echo $configure_view; + } else { + ?> +

    + +
    diff --git a/lib/Minz/Extension.php b/lib/Minz/Extension.php index c93ba2520..1d706ed80 100644 --- a/lib/Minz/Extension.php +++ b/lib/Minz/Extension.php @@ -86,6 +86,27 @@ class Minz_Extension { return $this->is_enabled; } + /** + * Return the content of the configure view for the current extension. + * + * @return the html content from ext_dir/configure.phtml, false if it does + * not exist. + */ + public function getConfigureView() { + $filename = $this->path . '/configure.phtml'; + if (!file_exists($filename)) { + return false; + } + return @file_get_contents($filename); + } + + /** + * Handle the configure POST action. + * + * It must be redefined by child classes. + */ + public function handleConfigureAction() {} + /** * Getters and setters. */ -- cgit v1.2.3 From a596385343a0307bb81d1662f78106d8f7e2dbfb Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 8 Dec 2014 12:37:06 +0100 Subject: Fix a security issue in Minz_Error::error() Mehtod must redirect automatically by default to avoid code execution after calling the method. --- lib/Minz/Error.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Minz/Error.php b/lib/Minz/Error.php index c8222a430..e5f3dff07 100644 --- a/lib/Minz/Error.php +++ b/lib/Minz/Error.php @@ -19,7 +19,7 @@ class Minz_Error { * > $logs['notice'] * @param $redirect indique s'il faut forcer la redirection (les logs ne seront pas transmis) */ - public static function error ($code = 404, $logs = array (), $redirect = false) { + public static function error ($code = 404, $logs = array (), $redirect = true) { $logs = self::processLogs ($logs); $error_filename = APP_PATH . '/Controllers/errorController.php'; -- cgit v1.2.3 From 188b517daa174ce494f31dec02ae2cff122488ff Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 8 Dec 2014 13:05:56 +0100 Subject: Add a feed_before_insert hook See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/feedController.php | 6 ++++++ app/Controllers/importExportController.php | 30 ++++++++++++++++++++---------- lib/Minz/ExtensionManager.php | 1 + 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 0a7edbee3..7dda3840e 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -138,6 +138,12 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feed->_category($cat); $feed->_httpAuth($http_auth); + // Call the extension hook + $feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed); + if (is_null($feed)) { + Minz_Request::bad(_t('feed_not_added', $feed->name()), $url_redirect); + } + $values = array( 'url' => $feed->url(), 'category' => $feed->category(), diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index c67b30431..52df5bf8b 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -259,10 +259,16 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $feed->_website($website); $feed->_description($description); - // addFeedObject checks if feed is already in DB so nothing else to - // check here - $id = $this->feedDAO->addFeedObject($feed); - $error = ($id === false); + // Call the extension hook + $feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed); + if (!is_null($feed)) { + // addFeedObject checks if feed is already in DB so nothing else to + // check here + $id = $this->feedDAO->addFeedObject($feed); + $error = ($id === false); + } else { + $error = true; + } } catch (FreshRSS_Feed_Exception $e) { Minz_Log::warning($e->getMessage()); $error = true; @@ -427,13 +433,17 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $feed->_name($name); $feed->_website($website); - // addFeedObject checks if feed is already in DB so nothing else to - // check here. - $id = $this->feedDAO->addFeedObject($feed); + // Call the extension hook + $feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed); + if (!is_null($feed)) { + // addFeedObject checks if feed is already in DB so nothing else to + // check here. + $id = $this->feedDAO->addFeedObject($feed); - if ($id !== false) { - $feed->_id($id); - $return = $feed; + if ($id !== false) { + $feed->_id($id); + $return = $feed; + } } } catch (FreshRSS_Feed_Exception $e) { Minz_Log::warning($e->getMessage()); diff --git a/lib/Minz/ExtensionManager.php b/lib/Minz/ExtensionManager.php index 5491c7cf6..9e6a3155a 100644 --- a/lib/Minz/ExtensionManager.php +++ b/lib/Minz/ExtensionManager.php @@ -17,6 +17,7 @@ class Minz_ExtensionManager { private static $hook_list = array( 'entry_before_display' => array(), // function($entry) -> Entry | null 'entry_before_insert' => array(), // function($entry) -> Entry | null + 'feed_before_insert' => array(), // function($feed) -> Feed | null ); private static $ext_to_hooks = array(); -- cgit v1.2.3 From 28c77f22900a10ac43c6d61b2b2d1a146feac42a Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 8 Dec 2014 13:12:12 +0100 Subject: Fix a bug with feed_before_insert hook $feed->name() was called on a null value. See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/feedController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 7dda3840e..379b8d8da 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -139,9 +139,10 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feed->_httpAuth($http_auth); // Call the extension hook + $name = $feed->name(); $feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed); if (is_null($feed)) { - Minz_Request::bad(_t('feed_not_added', $feed->name()), $url_redirect); + Minz_Request::bad(_t('feed_not_added', $name), $url_redirect); } $values = array( -- cgit v1.2.3 From 0543f96a97fa860fdec38d61b117e6b5addf94b6 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 8 Dec 2014 13:22:11 +0100 Subject: Update comments for ExtensionController See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/extensionController.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/app/Controllers/extensionController.php b/app/Controllers/extensionController.php index 73b8070cb..cd56de9eb 100644 --- a/app/Controllers/extensionController.php +++ b/app/Controllers/extensionController.php @@ -23,6 +23,16 @@ class FreshRSS_extension_Controller extends Minz_ActionController { $this->view->extension_list = Minz_ExtensionManager::list_extensions(); } + /** + * This action handles configuration of a given extension. + * + * Only administrator can configure a system extension. + * + * Parameters are: + * - e: the extension name (urlencoded) + * - additional parameters which should be handle by the extension + * handleConfigureAction() method (POST request). + */ public function configureAction() { if (Minz_Request::param('ajax')) { $this->view->_useLayout(false); @@ -49,6 +59,7 @@ class FreshRSS_extension_Controller extends Minz_ActionController { * This action enables a disabled extension for the current user. * * System extensions can only be enabled by an administrator. + * This action must be reached by a POST request. * * Parameter is: * - e: the extension name (urlencoded). @@ -99,6 +110,7 @@ class FreshRSS_extension_Controller extends Minz_ActionController { * This action disables an enabled extension for the current user. * * System extensions can only be disabled by an administrator. + * This action must be reached by a POST request. * * Parameter is: * - e: the extension name (urlencoded). @@ -145,6 +157,15 @@ class FreshRSS_extension_Controller extends Minz_ActionController { Minz_Request::forward($url_redirect, true); } + /** + * This action handles deletion of an extension. + * + * Only administrator can remove an extension. + * This action must be reached by a POST request. + * + * Parameter is: + * -e: extension name (urlencoded) + */ public function removeAction() { if (!FreshRSS_Auth::hasAccess('admin')) { Minz_Error::error(403); -- cgit v1.2.3 From 76358846abe2eba95668d66d3847cbdfe3f8bcdc Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 8 Dec 2014 13:36:08 +0100 Subject: Implement extension deletion See https://github.com/FreshRSS/FreshRSS/issues/252 --- app/Controllers/extensionController.php | 22 +++++++++++++++++++++- lib/lib_rss.php | 26 ++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/app/Controllers/extensionController.php b/app/Controllers/extensionController.php index cd56de9eb..adb3e1864 100644 --- a/app/Controllers/extensionController.php +++ b/app/Controllers/extensionController.php @@ -172,6 +172,26 @@ class FreshRSS_extension_Controller extends Minz_ActionController { } $url_redirect = array('c' => 'extension', 'a' => 'index'); - Minz_Request::bad('not implemented yet!', $url_redirect); + + if (Minz_Request::isPost()) { + $ext_name = urldecode(Minz_Request::param('e')); + $ext = Minz_ExtensionManager::find_extension($ext_name); + + if (is_null($ext)) { + Minz_Request::bad(_t('feedback.extensions.not_found', $ext_name), + $url_redirect); + } + + $res = recursive_unlink($ext->getPath()); + if ($res) { + Minz_Request::good(_t('feedback.extensions.removed', $ext_name), + $url_redirect); + } else { + Minz_Request::bad(_t('feedback.extensions.cannot_delete', $ext_name), + $url_redirect); + } + } + + Minz_Request::forward($url_redirect, true); } } diff --git a/lib/lib_rss.php b/lib/lib_rss.php index 8170c7fd9..e466bcb15 100644 --- a/lib/lib_rss.php +++ b/lib/lib_rss.php @@ -319,3 +319,29 @@ function check_install_database() { return $status; } + +/** + * Remove a directory recursively. + * + * From http://php.net/rmdir#110489 + * + * @param $dir the directory to remove + */ +function recursive_unlink($dir) { + if (!is_dir($dir)) { + return true; + } + + $files = array_diff(scandir($dir), array('.', '..')); + foreach ($files as $filename) { + $filename = $dir . '/' . $filename; + if (is_dir($filename)) { + @chmod($filename, 0777); + recursive_unlink($filename); + } else { + unlink($filename); + } + } + + return rmdir($dir); +} -- cgit v1.2.3 From 70c1f0ebb08e2edf1721e2d3f8f98837c5910da4 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 9 Dec 2014 12:43:33 +0100 Subject: Fix redirection after feed refresh Fix https://github.com/FreshRSS/FreshRSS/issues/716 --- app/Controllers/feedController.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 9990a852c..c8727c727 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -392,8 +392,9 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // Redirect to the main page with correct notification. if ($updated_feeds === 1) { $feed = reset($feeds); - Minz_Request::good(_t('feed_actualized', $feed->name()), - array('get' => 'f_' . $feed->id())); + Minz_Request::good(_t('feed_actualized', $feed->name()), array( + 'params' => array('get' => 'f_' . $feed->id()) + )); } elseif ($updated_feeds > 1) { Minz_Request::good(_t('n_feeds_actualized', $updated_feeds), array()); } else { -- cgit v1.2.3 From 0b9fa9896ed3b12b7e0d6300f0122d25d9576aa3 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Tue, 9 Dec 2014 15:44:13 +0100 Subject: Update CHANGELOG --- CHANGELOG | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index e09b55d21..15582e82a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,11 +1,24 @@ # Journal des modifications -## Dev +## 2014-12-xx FreshRSS 0.9.3 (beta) * SimplePie * Support for content-type application/x-rss+xml * New force_feed option (for feeds sent with the wrong content-type / MIME) by adding #force_feed at the end of the feed URL * Improved error messages +* Statistics + * Add information on feed repartition pages + * Add percent repartition for the bigger feeds +* UI + * New theme selector + * Update Screwdriver theme + * Add BlueLagoon theme by Mister aiR +* Misc. + * Add option to remove articles after reading them + * Add comments + * Refactor i18n system to not load unnecessary strings + * Fix security issue in Minz_Error::error() method + * Fix redirection after refreshing a given feed ## 2014-10-31 FreshRSS 0.9.2 (beta) -- cgit v1.2.3 From f807a6f5c1e9aa5aadf338c5242e54e1930b4088 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 10 Dec 2014 22:10:01 +0100 Subject: Fix i18n for header and aside_configure --- app/i18n/en/gen.php | 58 +++++++++++++++++++++------------------- app/i18n/fr/gen.php | 58 +++++++++++++++++++++------------------- app/layout/aside_configure.phtml | 16 +++++------ app/layout/header.phtml | 32 +++++++++++----------- 4 files changed, 84 insertions(+), 80 deletions(-) diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index a7f51e8f9..bd386f6a0 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -1,6 +1,36 @@ array( + 'login' => 'Login', + 'logout' => 'Logout', + ), + 'menu' => array( + 'about' => 'About', + 'admin' => 'Administration', + 'archiving' => 'Archiving', + 'authentication' => 'Authentication', + 'check_install' => 'Installation checking', + 'configuration' => 'Configuration', + 'display' => 'Display', + 'logs' => 'Logs', + 'queries' => 'User queries', + 'reading' => 'Reading', + 'sharing' => 'Sharing', + 'shortcuts' => 'Shortcuts', + 'stats' => 'Statistics', + 'update' => 'Update', + 'user_management' => 'Manage users', + 'user_profile' => 'Profile', + ), + 'title' => array( + '_' => 'Title', + 'authentication' => 'Authentication', + 'check_install' => 'Installation checking', + 'global_view' => 'Global view', + 'user_management' => 'Manage users', + 'user_profile' => 'Profile', + ), 'Apr' => '\\A\\p\\r\\i\\l', 'Aug' => '\\A\\u\\g\\u\\s\\t', 'Dec' => '\\D\\e\\c\\e\\m\\b\\e\\r', @@ -13,7 +43,6 @@ return array( 'Nov' => '\\N\\o\\v\\e\\m\\b\\e\\r', 'Oct' => '\\O\\c\\t\\o\\b\\e\\r', 'Sep' => '\\S\\e\\p\\t\\e\\m\\b\\e\\r', - 'about' => 'About', 'about_freshrss' => 'About FreshRSS', 'access_denied' => 'You don’t have permission to access this page', 'access_protected_feeds' => 'Connection allows to access HTTP protected RSS feeds', @@ -33,7 +62,6 @@ return array( 'api_enabled' => 'Allow API access (required for mobile apps)', 'apr' => 'apr', 'april' => 'Apr', - 'archiving_configuration' => 'Archiving', 'archiving_configuration_help' => 'More options are available in the individual stream settings', 'article' => 'Article', 'article_icons' => 'Article icons', @@ -110,7 +138,6 @@ return array( 'choose_language' => 'Choose a language for FreshRSS', 'clear_logs' => 'Clear the logs', 'collapse_article' => 'Collapse', - 'configuration' => 'Configuration', 'configuration_updated' => 'Configuration has been updated', 'confirm_action' => 'Are you sure you want to perform this action? It cannot be cancelled!', 'confirm_action_feed_cat' => 'Are you sure you want to perform this action? You will lose related favorites and user queries. It cannot be cancelled!', @@ -136,7 +163,6 @@ return array( 'delete' => 'Delete', 'delete_articles_every' => 'Remove articles after', 'diaspora' => 'Diaspora*', - 'display' => 'Display', 'display_articles_unfolded' => 'Show articles unfolded by default', 'display_categories_unfolded' => 'Show categories folded by default', 'display_configuration' => 'Display', @@ -191,21 +217,6 @@ return array( 'freshrss_installation' => 'Installation · FreshRSS', 'fri' => 'Fri', 'g+' => 'Google+', - 'menu' => array( - 'admin' => 'Administration', - 'authentication' => 'Authentication', - 'check_install' => 'Installation checking', - 'user_management' => 'Manage users', - 'user_profile' => 'Profile', - ), - 'title' => array( - '_' => 'Title', - 'authentication' => 'Authentication', - 'check_install' => 'Installation checking', - 'global_view' => 'Global view', - 'user_management' => 'Manage users', - 'user_profile' => 'Profile', - ), 'general_conf_is_ok' => 'General configuration has been saved.', 'general_configuration' => 'General configuration', 'github_or_email' => 'on Github or by mail', @@ -256,13 +267,10 @@ return array( 'license' => 'License', 'load_more' => 'Load more articles', 'log_is_ok' => 'Permissions on logs directory are good', - 'login' => 'Login', 'login_configuration' => 'Login', 'login_persona_problem' => 'Connection problem with Persona?', 'login_required' => 'Login required:', 'login_with_persona' => 'Login with Persona', - 'logout' => 'Logout', - 'logs' => 'Logs', 'logs_empty' => 'Log file is empty', 'main_stream' => 'Main stream', 'mar' => 'mar', @@ -340,7 +348,6 @@ return array( 'publication_date' => 'Date of publication', 'purge_completed' => 'Purge completed (%d articles deleted)', 'purge_now' => 'Purge now', - 'queries' => 'User queries', 'query_created' => 'Query "%s" has been created.', 'query_deprecated' => 'This query is no longer valid. The referenced category or feed has been deleted.', 'query_filter' => 'Filter applied:', @@ -370,7 +377,6 @@ return array( 'query_state_15' => 'Display all articles', 'random_string' => 'Random string', 'reader_view' => 'Reading view', - 'reading_configuration' => 'Reading', 'reading_confirm' => 'Display a confirmation dialog on “mark all as read” actions', 'refresh' => 'Refresh', 'related_tags' => 'Related tags', @@ -392,10 +398,8 @@ return array( 'share' => 'Share', 'share_name' => 'Share name to display', 'share_url' => 'Share URL to use', - 'sharing' => 'Sharing', 'sharing_management' => 'Sharing options management', 'shift_for_all_read' => '+ shift to mark all articles as read', - 'shortcuts' => 'Shortcuts', 'shortcuts_article_action' => 'Article actions', 'shortcuts_navigation' => 'Navigation', 'shortcuts_navigation_help' => 'With the "Shift" modifier, navigation shortcuts apply on feeds.
    With the "Alt" modifier, navigation shortcuts apply on categories.', @@ -410,7 +414,6 @@ return array( 'show_read' => 'Show only read', 'sort_order' => 'Sort order', 'starred_list' => 'List of favourite articles', - 'stats' => 'Statistics', 'stats_entry_count' => 'Entry count', 'stats_entry_per_category' => 'Entries per category', 'stats_entry_per_day' => 'Entries per day (last 30 days)', @@ -445,7 +448,6 @@ return array( 'tue' => 'Tue', 'twitter' => 'Twitter', 'unsafe_autologin' => 'Allow unsafe automatic login using the format: ', - 'update' => 'Update', 'update_apply' => 'Apply', 'update_can_apply' => 'An update is available.', 'update_check' => 'Check for new updates', diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php index 0b2395bd0..b33dc49bc 100644 --- a/app/i18n/fr/gen.php +++ b/app/i18n/fr/gen.php @@ -1,6 +1,36 @@ array( + 'login' => 'Connexion', + 'logout' => 'Déconnexion', + ), + 'menu' => array( + 'about' => 'À propos', + 'admin' => 'Administration', + 'archiving' => 'Archivage', + 'authentication' => 'Authentification', + 'check_install' => 'Vérification de l’installation', + 'configuration' => 'Configuration', + 'display' => 'Affichage', + 'logs' => 'Logs', + 'queries' => 'Filtres utilisateurs', + 'reading' => 'Lecture', + 'sharing' => 'Partage', + 'shortcuts' => 'Raccourcis', + 'stats' => 'Statistiques', + 'update' => 'Mise à jour', + 'user_management' => 'Gestion des utilisateurs', + 'user_profile' => 'Profil', + ), + 'title' => array( + '_' => 'Titre', + 'authentication' => 'Authentification', + 'check_install' => 'Vérification de l’installation', + 'global_view' => 'Vue globale', + 'user_management' => 'Gestion des utilisateurs', + 'user_profile' => 'Profil', + ), 'Apr' => '\\a\\v\\r\\i\\l', 'Aug' => '\\a\\o\\û\\t', 'Dec' => '\\d\\é\\c\\e\\m\\b\\r\\e', @@ -13,7 +43,6 @@ return array( 'Nov' => '\\n\\o\\v\\e\\m\\b\\r\\e', 'Oct' => '\\o\\c\\t\\o\\b\\r\\e', 'Sep' => '\\s\\e\\p\\t\\e\\m\\b\\r\\e', - 'about' => 'À propos', 'about_freshrss' => 'À propos de FreshRSS', 'access_denied' => 'Vous n’avez pas le droit d’accéder à cette page !', 'access_protected_feeds' => 'La connexion permet d’accéder aux flux protégés par une authentification HTTP.', @@ -33,7 +62,6 @@ return array( 'api_enabled' => 'Autoriser l’accès par API (nécessaire pour les applis mobiles)', 'apr' => 'avr.', 'april' => 'avril', - 'archiving_configuration' => 'Archivage', 'archiving_configuration_help' => 'D’autres options sont disponibles dans la configuration individuelle des flux.', 'article' => 'Article', 'article_icons' => 'Icônes d’article', @@ -110,7 +138,6 @@ return array( 'choose_language' => 'Choisissez la langue pour FreshRSS', 'clear_logs' => 'Effacer les logs', 'collapse_article' => 'Refermer', - 'configuration' => 'Configuration', 'configuration_updated' => 'La configuration a été mise à jour.', 'confirm_action' => 'Êtes-vous sûr(e) de vouloir continuer ? Cette action ne peut être annulée !', 'confirm_action_feed_cat' => 'Êtes-vous sûr(e) de vouloir continuer ? Vous perdrez les favoris et les filtres associés. Cette action ne peut être annulée !', @@ -139,7 +166,6 @@ return array( 'display' => 'Affichage', 'display_articles_unfolded' => 'Afficher les articles dépliés par défaut', 'display_categories_unfolded' => 'Afficher les catégories pliées par défaut', - 'display_configuration' => 'Affichage', 'do_not_change_if_doubt' => 'Laissez tel quel dans le doute', 'dom_is_nok' => 'Il manque une librairie pour parcourir le DOM (paquet php-xml)', 'dom_is_ok' => 'Vous disposez du nécessaire pour parcourir le DOM', @@ -191,21 +217,6 @@ return array( 'freshrss_installation' => 'Installation · FreshRSS', 'fri' => 'ven.', 'g+' => 'Google+', - 'menu' => array( - 'admin' => 'Administration', - 'authentication' => 'Authentification', - 'check_install' => 'Vérification de l’installation', - 'user_management' => 'Gestion des utilisateurs', - 'user_profile' => 'Profil', - ), - 'title' => array( - '_' => 'Titre', - 'authentication' => 'Authentification', - 'check_install' => 'Vérification de l’installation', - 'global_view' => 'Vue globale', - 'user_management' => 'Gestion des utilisateurs', - 'user_profile' => 'Profil', - ), 'general_conf_is_ok' => 'La configuration générale a été enregistrée.', 'general_configuration' => 'Configuration générale', 'github_or_email' => 'sur Github ou par courriel', @@ -256,13 +267,10 @@ return array( 'license' => 'Licence', 'load_more' => 'Charger plus d’articles', 'log_is_ok' => 'Les droits sur le répertoire des logs sont bons', - 'login' => 'Connexion', 'login_configuration' => 'Identification', 'login_persona_problem' => 'Problème de connexion à Persona ?', 'login_required' => 'Accès protégé par mot de passe :', 'login_with_persona' => 'Connexion avec Persona', - 'logout' => 'Déconnexion', - 'logs' => 'Logs', 'logs_empty' => 'Les logs sont vides.', 'main_stream' => 'Flux principal', 'mar' => 'mar.', @@ -340,7 +348,6 @@ return array( 'publication_date' => 'Date de publication', 'purge_completed' => 'Purge effectuée (%d articles supprimés).', 'purge_now' => 'Purger maintenant', - 'queries' => 'Filtres utilisateurs', 'query_created' => 'Le filtre "%s" a bien été créé.', 'query_deprecated' => 'Ce filtre n’est plus valide. La catégorie ou le flux concerné a été supprimé.', 'query_filter' => 'Filtres appliqués :', @@ -370,7 +377,6 @@ return array( 'query_state_15' => 'Afficher tous les articles', 'random_string' => 'Chaîne aléatoire', 'reader_view' => 'Vue lecture', - 'reading_configuration' => 'Lecture', 'reading_confirm' => 'Afficher une confirmation lors des actions “marquer tout comme lu”', 'refresh' => 'Actualisation', 'related_tags' => 'Tags associés', @@ -392,10 +398,8 @@ return array( 'share' => 'Partager', 'share_name' => 'Nom du partage à afficher', 'share_url' => 'URL du partage à utiliser', - 'sharing' => 'Partage', 'sharing_management' => 'Gestion des options de partage', 'shift_for_all_read' => '+ shift pour marquer tous les articles comme lus', - 'shortcuts' => 'Raccourcis', 'shortcuts_article_action' => 'Actions associées à l’article courant', 'shortcuts_navigation' => 'Navigation', 'shortcuts_navigation_help' => 'Avec le modificateur "Shift", les raccourcis de navigation s’appliquent aux flux.
    Avec le modificateur "Alt", les raccourcis de navigation s’appliquent aux catégories.', @@ -410,7 +414,6 @@ return array( 'show_read' => 'Afficher les lus', 'sort_order' => 'Ordre de tri', 'starred_list' => 'Liste des articles favoris', - 'stats' => 'Statistiques', 'stats_entry_count' => 'Nombre d’articles', 'stats_entry_per_category' => 'Articles par catégorie', 'stats_entry_per_day' => 'Nombre d’articles par jour (30 derniers jours)', @@ -445,7 +448,6 @@ return array( 'tue' => 'mar.', 'twitter' => 'Twitter', 'unsafe_autologin' => 'Autoriser les connexions automatiques non-sûres au format : ', - 'update' => 'Mise à jour', 'update_apply' => 'Appliquer la mise à jour', 'update_can_apply' => 'Une mise à jour est disponible.', 'update_check' => 'Vérifier les mises à jour', diff --git a/app/layout/aside_configure.phtml b/app/layout/aside_configure.phtml index 53c52d3e3..25b8037e6 100644 --- a/app/layout/aside_configure.phtml +++ b/app/layout/aside_configure.phtml @@ -1,22 +1,22 @@ diff --git a/app/layout/header.phtml b/app/layout/header.phtml index c73d9cdbb..429cfc1d2 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -2,9 +2,9 @@ if (Minz_Configuration::canLogIn()) { ?>" method="get">
    - + @@ -55,13 +55,13 @@ if (Minz_Configuration::canLogIn()) {
    - +
    -- cgit v1.2.3 From 7dee863577aff2103277e08bf6db2f8e16b029a7 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Wed, 10 Dec 2014 22:29:13 +0100 Subject: Fix i18n for aside_feed --- app/i18n/en/gen.php | 14 ++++++-------- app/i18n/en/index.php | 13 ++++++++++++- app/i18n/fr/gen.php | 14 ++++++-------- app/i18n/fr/index.php | 13 ++++++++++++- app/layout/aside_feed.phtml | 20 ++++++++++---------- 5 files changed, 46 insertions(+), 28 deletions(-) diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index bd386f6a0..3bc2c5ac6 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -1,6 +1,12 @@ array( + 'disable' => 'Disable', + 'enable' => 'Enable', + 'manage' => 'Manage', + 'remove' => 'Remove', + ), 'auth' => array( 'login' => 'Login', 'logout' => 'Logout', @@ -43,11 +49,9 @@ return array( 'Nov' => '\\N\\o\\v\\e\\m\\b\\e\\r', 'Oct' => '\\O\\c\\t\\o\\b\\e\\r', 'Sep' => '\\S\\e\\p\\t\\e\\m\\b\\e\\r', - 'about_freshrss' => 'About FreshRSS', 'access_denied' => 'You don’t have permission to access this page', 'access_protected_feeds' => 'Connection allows to access HTTP protected RSS feeds', 'activate_sharing' => 'Activate sharing', - 'actualize' => 'Actualize', 'add_category' => 'Add a category', 'add_query' => 'Add a query', 'add_rss_feed' => 'Add a RSS feed', @@ -179,7 +183,6 @@ return array( 'export_starred' => 'Export your favourites', 'facebook' => 'Facebook', 'favicons_is_ok' => 'Permissions on favicons directory are good', - 'favorite_feeds' => 'Favourites (%s)', 'feb' => 'feb', 'february' => 'Feb', 'feed' => 'Feed', @@ -204,7 +207,6 @@ return array( 'file_is_nok' => 'Check permissions on %s directory. HTTP server must have rights to write into', 'file_to_import' => 'File to import
    (OPML, Json or Zip)', 'file_to_import_no_zip' => 'File to import
    (OPML or Json)', - 'filter' => 'Filter', 'finish_installation' => 'Complete installation', 'first' => 'First', 'first_article' => 'Skip to the first article', @@ -272,14 +274,12 @@ return array( 'login_required' => 'Login required:', 'login_with_persona' => 'Login with Persona', 'logs_empty' => 'Log file is empty', - 'main_stream' => 'Main stream', 'mar' => 'mar', 'march' => 'Mar', 'mark_all_read' => 'Mark all as read', 'mark_cat_read' => 'Mark category as read', 'mark_favorite' => 'Mark as favourite', 'mark_feed_read' => 'Mark feed as read', - 'mark_read' => 'Mark as read', 'may' => 'May', 'minz_is_nok' => 'You lack the Minz framework. You should execute build.sh script or download it on Github and install in %s directory the content of its /lib directory.', 'minz_is_ok' => 'You have the Minz framework', @@ -391,7 +391,6 @@ return array( 'search_short' => 'Search', 'seconds_(0_means_no_timeout)' => 'seconds (0 means no timeout)', 'see_on_website' => 'See on original website', - 'see_website' => 'See website', 'sep' => 'sep', 'september' => 'Sep', 'shaarli' => 'Shaarli', @@ -435,7 +434,6 @@ return array( 'steps' => 'Steps', 'sticky_post' => 'Stick the article to the top when opened', 'submit' => 'Submit', - 'subscription_management' => 'Subscriptions management', 'sun' => 'Sun', 'theme' => 'Theme', 'think_to_add' => 'You may add some feeds.', diff --git a/app/i18n/en/index.php b/app/i18n/en/index.php index afca37ed3..ca15bcc25 100644 --- a/app/i18n/en/index.php +++ b/app/i18n/en/index.php @@ -1,5 +1,16 @@ array( + 'about' => 'About FreshRSS', + 'actualize' => 'Actualize', + 'favorites' => 'Favourites (%s)', + 'filter' => 'Filter', + 'main_stream' => 'Main stream', + 'manage' => 'Manage', + 'mark_read' => 'Mark as read', + 'see_website' => 'See website', + 'stats' => 'Statistics', + 'subscription' => 'Subscriptions management', + ), ); diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php index b33dc49bc..9d9624cc8 100644 --- a/app/i18n/fr/gen.php +++ b/app/i18n/fr/gen.php @@ -1,6 +1,12 @@ array( + 'disable' => 'Désactiver', + 'enable' => 'Activer', + 'manage' => 'Gérer', + 'remove' => 'Supprimer', + ), 'auth' => array( 'login' => 'Connexion', 'logout' => 'Déconnexion', @@ -43,11 +49,9 @@ return array( 'Nov' => '\\n\\o\\v\\e\\m\\b\\r\\e', 'Oct' => '\\o\\c\\t\\o\\b\\r\\e', 'Sep' => '\\s\\e\\p\\t\\e\\m\\b\\r\\e', - 'about_freshrss' => 'À propos de FreshRSS', 'access_denied' => 'Vous n’avez pas le droit d’accéder à cette page !', 'access_protected_feeds' => 'La connexion permet d’accéder aux flux protégés par une authentification HTTP.', 'activate_sharing' => 'Activer le partage', - 'actualize' => 'Actualiser', 'add_category' => 'Ajouter une catégorie', 'add_query' => 'Créer un filtre', 'add_rss_feed' => 'Ajouter un flux RSS', @@ -179,7 +183,6 @@ return array( 'export_starred' => 'Exporter les favoris', 'facebook' => 'Facebook', 'favicons_is_ok' => 'Les droits sur le répertoire des favicons sont bons', - 'favorite_feeds' => 'Favoris (%s)', 'feb' => 'fév.', 'february' => 'février', 'feed' => 'Flux', @@ -204,7 +207,6 @@ return array( 'file_is_nok' => 'Veuillez vérifier les droits sur le répertoire %s. Le serveur HTTP doit être capable d’écrire dedans', 'file_to_import' => 'Fichier à importer
    (OPML, Json ou Zip)', 'file_to_import_no_zip' => 'Fichier à importer
    (OPML ou Json)', - 'filter' => 'Filtrer', 'finish_installation' => 'Terminer l’installation', 'first' => 'Début', 'first_article' => 'Passer au premier article', @@ -272,14 +274,12 @@ return array( 'login_required' => 'Accès protégé par mot de passe :', 'login_with_persona' => 'Connexion avec Persona', 'logs_empty' => 'Les logs sont vides.', - 'main_stream' => 'Flux principal', 'mar' => 'mar.', 'march' => 'mars', 'mark_all_read' => 'Tout marquer comme lu', 'mark_cat_read' => 'Marquer la catégorie comme lue', 'mark_favorite' => 'Mettre en favori', 'mark_feed_read' => 'Marquer le flux comme lu', - 'mark_read' => 'Marquer comme lu', 'may' => 'mai.', 'minz_is_nok' => 'Vous ne disposez pas de la librairie Minz. Vous devriez exécuter le script build.sh ou bien la télécharger sur Github et installer dans le répertoire %s le contenu de son répertoire /lib.', 'minz_is_ok' => 'Vous disposez du framework Minz', @@ -391,7 +391,6 @@ return array( 'search_short' => 'Rechercher', 'seconds_(0_means_no_timeout)' => 'secondes (0 signifie aucun timeout ) ', 'see_on_website' => 'Voir sur le site d’origine', - 'see_website' => 'Voir le site', 'sep' => 'sep.', 'september' => 'septembre', 'shaarli' => 'Shaarli', @@ -435,7 +434,6 @@ return array( 'steps' => 'Étapes', 'sticky_post' => 'Aligner l’article en haut quand il est ouvert', 'submit' => 'Valider', - 'subscription_management' => 'Gestion des abonnements', 'sun' => 'dim.', 'theme' => 'Thème', 'think_to_add' => 'Vous pouvez ajouter des flux.', diff --git a/app/i18n/fr/index.php b/app/i18n/fr/index.php index afca37ed3..408d7ee4a 100644 --- a/app/i18n/fr/index.php +++ b/app/i18n/fr/index.php @@ -1,5 +1,16 @@ array( + 'about' => 'À propos de FreshRSS', + 'actualize' => 'Actualiser', + 'favorites' => 'Favoris (%s)', + 'filter' => 'Filtrer', + 'main_stream' => 'Flux principal', + 'manage' => 'Gérer', + 'mark_read' => 'Marquer comme lu', + 'see_website' => 'Voir le site', + 'stats' => 'Statistiques', + 'subscription' => 'Gestion des abonnements', + ), ); diff --git a/app/layout/aside_feed.phtml b/app/layout/aside_feed.phtml index 3c23e0178..ca220dcd4 100644 --- a/app/layout/aside_feed.phtml +++ b/app/layout/aside_feed.phtml @@ -12,11 +12,11 @@
    - +
    - + @@ -24,13 +24,13 @@
    • - +
    • - +
    • @@ -74,21 +74,21 @@ "> - + diff --git a/app/views/helpers/javascript_vars.phtml b/app/views/helpers/javascript_vars.phtml index 6577e0109..02f2014ee 100644 --- a/app/views/helpers/javascript_vars.phtml +++ b/app/views/helpers/javascript_vars.phtml @@ -1,6 +1,7 @@ "use strict"; mark_when; $mail = Minz_Session::param('mail', false); $auto_actualize = Minz_Session::param('actualize_feeds', false); @@ -29,7 +30,7 @@ echo 'var context={', 'does_lazyload:', FreshRSS_Context::$conf->lazyload ? 'true' : 'false', ',', 'sticky_post:', FreshRSS_Context::isStickyPostEnabled() ? 'true' : 'false', ',', 'html5_notif_timeout:', FreshRSS_Context::$conf->html5_notif_timeout, ',', - 'auth_type:"', Minz_Configuration::authType(), '",', + 'auth_type:"', $conf->general['auth_type'], '",', 'current_user_mail:', $mail ? ('"' . $mail . '"') : 'null', ',', 'current_view:"', Minz_Request::param('output', 'normal'), '"', "},\n"; diff --git a/data/config.default.php b/data/config.default.php new file mode 100644 index 000000000..a69d8050b --- /dev/null +++ b/data/config.default.php @@ -0,0 +1,32 @@ + array( + 'environment' => 'production', + 'salt' => '', + 'base_url' => '', + 'language' => 'en', + 'title' => 'FreshRSS', + 'default_user' => '_', + 'allow_anonymous' => false, + 'allow_anonymous_refresh' => false, + 'auth_type' => 'none', + 'api_enabled' => false, + 'unsafe_autologin_enabled' => false, + ), + 'limits' => array( + 'cache_duration' => 800, + 'timeout' => 10, + 'max_inactivity' => PHP_INT_MAX, + 'max_feeds' => 16384, + 'max_categories' => 16384, + ), + 'db' => array( + 'type' => 'sqlite', + 'host' => '', + 'user' => '', + 'password' => '', + 'base' => '', + 'prefix' => '', + ), +); diff --git a/data/users/_/config.default.php b/data/users/_/config.default.php new file mode 100644 index 000000000..56d54b293 --- /dev/null +++ b/data/users/_/config.default.php @@ -0,0 +1,66 @@ + 'en', + 'old_entries' => 3, + 'keep_history_default' => 0, + 'ttl_default' => 3600, + 'mail_login' => '', + 'token' => '', + 'passwordHash' => '', + 'apiPasswordHash' => '', + 'posts_per_page' => 20, + 'view_mode' => 'normal', + 'default_view' => 'adaptive', + 'default_state' => FreshRSS_Entry::STATE_NOT_READ, + 'auto_load_more' => true, + 'display_posts' => false, + 'display_categories' => false, + 'hide_read_feeds' => true, + 'onread_jump_next' => true, + 'lazyload' => true, + 'sticky_post' => true, + 'reading_confirm' => false, + 'auto_remove_article' => false, + 'sort_order' => 'DESC', + 'anon_access' => false, + 'mark_when' => array ( + 'article' => true, + 'site' => true, + 'scroll' => false, + 'reception' => false, + ), + 'theme' => 'Origine', + 'content_width' => 'thin', + 'shortcuts' => array ( + 'mark_read' => 'r', + 'mark_favorite' => 'f', + 'go_website' => 'space', + 'next_entry' => 'j', + 'prev_entry' => 'k', + 'first_entry' => 'home', + 'last_entry' => 'end', + 'collapse_entry' => 'c', + 'load_more' => 'm', + 'auto_share' => 's', + 'focus_search' => 'a', + 'user_filter' => 'u', + 'help' => 'f1', + 'close_dropdown' => 'escape', + ), + 'topline_read' => true, + 'topline_favorite' => true, + 'topline_date' => true, + 'topline_link' => true, + 'bottomline_read' => true, + 'bottomline_favorite' => true, + 'bottomline_sharing' => true, + 'bottomline_tags' => true, + 'bottomline_date' => true, + 'bottomline_link' => true, + 'sharing' => array ( + ), + 'queries' => array ( + ), + 'html5_notif_timeout' => 0, +); diff --git a/lib/Minz/BadConfigurationException.php b/lib/Minz/BadConfigurationException.php deleted file mode 100644 index a7b77d687..000000000 --- a/lib/Minz/BadConfigurationException.php +++ /dev/null @@ -1,9 +0,0 @@ - -*/ /** - * La classe Configuration permet de gérer la configuration de l'application + * Manage configuration for the application. */ class Minz_Configuration { - const CONF_PATH_NAME = '/config.php'; - /** - * VERSION est la version actuelle de MINZ + * The list of configurations. */ - const VERSION = '1.3.1.freshrss'; // version spéciale FreshRSS + private static $config_list = array(); /** - * valeurs possibles pour l'"environment" - * SILENT rend l'application muette (pas de log) - * PRODUCTION est recommandée pour une appli en production - * (log les erreurs critiques) - * DEVELOPMENT log toutes les erreurs + * Add a new configuration to the list of configuration. + * + * @param $namespace the name of the current configuration + * @param $config_filename the filename of the configuration + * @param $default_filename a filename containing default values for the configuration + * @throws Minz_ConfigurationNamespaceException if the namespace already exists. */ - const SILENT = 0; - const PRODUCTION = 1; - const DEVELOPMENT = 2; + public static function register($namespace, $config_filename, $default_filename = null) { + if (isset(self::$config_list[$namespace])) { + throw new Minz_ConfigurationNamespaceException( + $namespace . ' namespace already exists' + ); + } + + self::$config_list[$namespace] = new Minz_Configuration( + $namespace, $config_filename, $default_filename + ); + } /** - * définition des variables de configuration - * $salt une chaîne de caractères aléatoires (obligatoire) - * $environment gère le niveau d'affichage pour log et erreurs - * $base_url le chemin de base pour accéder à l'application - * $title le nom de l'application - * $language la langue par défaut de l'application - * $db paramètres pour la base de données (tableau) - * - host le serveur de la base - * - user nom d'utilisateur - * - password mot de passe de l'utilisateur - * - base le nom de la base de données + * Parse a file and return its data. + * + * If the file does not contain a valid PHP code returning an array, an + * empty array is returned anyway. + * + * @param $filename the name of the file to parse. + * @return an array of values + * @throws Minz_FileNotExistException if the file does not exist. */ - private static $salt = ''; - private static $environment = Minz_Configuration::PRODUCTION; - private static $base_url = ''; - private static $title = ''; - private static $language = 'en'; - private static $default_user = ''; - private static $allow_anonymous = false; - private static $allow_anonymous_refresh = false; - private static $auth_type = 'none'; - private static $api_enabled = false; - private static $unsafe_autologin_enabled = false; - - private static $db = array ( - 'type' => 'mysql', - 'host' => '', - 'user' => '', - 'password' => '', - 'base' => '', - 'prefix' => '', - ); - - const MAX_SMALL_INT = 16384; - private static $limits = array( - 'cache_duration' => 800, //SimplePie cache duration in seconds - 'timeout' => 10, //SimplePie timeout in seconds - 'max_inactivity' => PHP_INT_MAX, //Time in seconds after which a user who has not used the account is considered inactive (no auto-refresh of feeds). - 'max_feeds' => Minz_Configuration::MAX_SMALL_INT, - 'max_categories' => Minz_Configuration::MAX_SMALL_INT, - ); + public static function parseFile($filename) { + if (!file_exists($filename)) { + throw new Minz_FileNotExistException($filename); + } - /* - * Getteurs - */ - public static function salt () { - return self::$salt; + $data = @include($filename); + if (is_array($data)) { + return $data; + } else { + return array(); + } } - public static function environment ($str = false) { - $env = self::$environment; - if ($str) { - switch (self::$environment) { - case self::SILENT: - $env = 'silent'; - break; - case self::DEVELOPMENT: - $env = 'development'; - break; - case self::PRODUCTION: - default: - $env = 'production'; - } + /** + * Return the configuration related to a given namespace. + * + * @param $namespace the name of the configuration to get. + * @return a Minz_Configuration object + * @throws Minz_ConfigurationNamespaceException if the namespace does not exist. + */ + public static function get($namespace) { + if (!isset(self::$config_list[$namespace])) { + throw new Minz_ConfigurationNamespaceException( + $namespace . ' namespace does not exist' + ); } - return $env; - } - public static function baseUrl () { - return self::$base_url; - } - public static function title () { - return self::$title; - } - public static function language () { - return self::$language; - } - public static function dataBase () { - return self::$db; - } - public static function limits() { - return self::$limits; - } - public static function defaultUser () { - return self::$default_user; - } - public static function allowAnonymous() { - return self::$allow_anonymous; - } - public static function allowAnonymousRefresh() { - return self::$allow_anonymous_refresh; - } - public static function authType() { - return self::$auth_type; - } - public static function needsLogin() { - return self::$auth_type !== 'none'; - } - public static function canLogIn() { - return self::$auth_type === 'form' || self::$auth_type === 'persona'; - } - public static function apiEnabled() { - return self::$api_enabled; - } - public static function unsafeAutologinEnabled() { - return self::$unsafe_autologin_enabled; + return self::$config_list[$namespace]; } - public static function _allowAnonymous($allow = false) { - self::$allow_anonymous = ((bool)$allow) && self::canLogIn(); - } - public static function _allowAnonymousRefresh($allow = false) { - self::$allow_anonymous_refresh = ((bool)$allow) && self::allowAnonymous(); - } - public static function _authType($value) { - $value = strtolower($value); - switch ($value) { - case 'form': - case 'http_auth': - case 'persona': - case 'none': - self::$auth_type = $value; - break; - } - self::_allowAnonymous(self::$allow_anonymous); - } + /** + * The namespace of the current configuration. + */ + private $namespace = ''; - public static function _enableApi($value = false) { - self::$api_enabled = (bool)$value; - } - public static function _enableAutologin($value = false) { - self::$unsafe_autologin_enabled = (bool)$value; - } + /** + * The filename for the current configuration. + */ + private $config_filename = ''; + + /** + * The filename for the current default values, null by default. + */ + private $default_filename = null; + + /** + * The configuration values, an empty array by default. + */ + private $data = array(); + + /** + * The default values, an empty array by default. + */ + private $data_default = array(); /** - * Initialise les variables de configuration - * @exception Minz_FileNotExistException si le CONF_PATH_NAME n'existe pas - * @exception Minz_BadConfigurationException si CONF_PATH_NAME mal formaté + * Create a new Minz_Configuration object. + * + * @param $namespace the name of the current configuration. + * @param $config_filename the file containing configuration values. + * @param $default_filename the file containing default values, null by default. */ - public static function init () { + private function __construct($namespace, $config_filename, $default_filename = null) { + $this->namespace = $namespace; + $this->config_filename = $config_filename; + try { - self::parseFile (); - self::setReporting (); + $this->data = self::parseFile($this->config_filename); } catch (Minz_FileNotExistException $e) { - throw $e; - } catch (Minz_BadConfigurationException $e) { - throw $e; + if (is_null($default_filename)) { + throw $e; + } } - } - public static function writeFile() { - $ini_array = array( - 'general' => array( - 'environment' => self::environment(true), - 'salt' => self::$salt, - 'base_url' => self::$base_url, - 'title' => self::$title, - 'default_user' => self::$default_user, - 'allow_anonymous' => self::$allow_anonymous, - 'allow_anonymous_refresh' => self::$allow_anonymous_refresh, - 'auth_type' => self::$auth_type, - 'api_enabled' => self::$api_enabled, - 'unsafe_autologin_enabled' => self::$unsafe_autologin_enabled, - ), - 'limits' => self::$limits, - 'db' => self::$db, - ); - @rename(DATA_PATH . self::CONF_PATH_NAME, DATA_PATH . self::CONF_PATH_NAME . '.bak.php'); - $result = file_put_contents(DATA_PATH . self::CONF_PATH_NAME, "default_filename = $default_filename; + if (!is_null($this->default_filename)) { + $this->data_default = self::parseFile($this->default_filename); } - return (bool)$result; } /** - * Parse un fichier de configuration - * @exception Minz_PermissionDeniedException si le CONF_PATH_NAME n'est pas accessible - * @exception Minz_BadConfigurationException si CONF_PATH_NAME mal formaté + * Return the value of the given param. + * + * @param $key the name of the param. + * @param $default default value to return if key does not exist. + * @return the value corresponding to the key. + * @throws Minz_ConfigurationParamException if the param does not exist */ - private static function parseFile () { - $ini_array = include(DATA_PATH . self::CONF_PATH_NAME); - - if (!is_array($ini_array)) { - throw new Minz_PermissionDeniedException ( - DATA_PATH . self::CONF_PATH_NAME, - Minz_Exception::ERROR + public function param($key, $default = null) { + if (isset($this->data[$key])) { + return $this->data[$key]; + } elseif (!is_null($default)) { + return $default; + } elseif (isset($this->data_default[$key])) { + return $this->data_default[$key]; + } else { + throw new Minz_ConfigurationParamException( + $key . ' param does not exist' ); } + } - // [general] est obligatoire - if (!isset ($ini_array['general'])) { - throw new Minz_BadConfigurationException ( - '[general]', - Minz_Exception::ERROR - ); - } - $general = $ini_array['general']; + /** + * A wrapper for param(). + */ + public function __get($key) { + return $this->param($key); + } - // salt est obligatoire - if (!isset ($general['salt'])) { - if (isset($general['sel_application'])) { //v0.6 - $general['salt'] = $general['sel_application']; - } else { - throw new Minz_BadConfigurationException ( - 'salt', - Minz_Exception::ERROR - ); - } + /** + * Set or remove a param. + * + * @param $key the param name to set. + * @param $value the value to set. If null, the key is removed from the configuration. + */ + public function _param($key, $value = null) { + if (isset($this->data[$key]) && is_null($value)) { + unset($this->data[$key]); + } else { + $this->data[$key] = $value; } - self::$salt = $general['salt']; - - if (isset ($general['environment'])) { - switch ($general['environment']) { - case 'silent': - self::$environment = Minz_Configuration::SILENT; - break; - case 'development': - self::$environment = Minz_Configuration::DEVELOPMENT; - break; - case 'production': - self::$environment = Minz_Configuration::PRODUCTION; - break; - default: - if ($general['environment'] >= 0 && - $general['environment'] <= 2) { - // fallback 0.7-beta - self::$environment = $general['environment']; - } else { - throw new Minz_BadConfigurationException ( - 'environment', - Minz_Exception::ERROR - ); - } - } + } - } - if (isset ($general['base_url'])) { - self::$base_url = $general['base_url']; - } + /** + * A wrapper for _param(). + */ + public function __set($key, $value) { + $this->_param($key, $value); + } - if (isset ($general['title'])) { - self::$title = $general['title']; - } - if (isset ($general['language'])) { - self::$language = $general['language']; - } - if (isset ($general['default_user'])) { - self::$default_user = $general['default_user']; - } - if (isset ($general['auth_type'])) { - self::_authType($general['auth_type']); - } - if (isset ($general['allow_anonymous'])) { - self::$allow_anonymous = ( - ((bool)($general['allow_anonymous'])) && - ($general['allow_anonymous'] !== 'no') - ); - } - if (isset ($general['allow_anonymous_refresh'])) { - self::$allow_anonymous_refresh = ( - ((bool)($general['allow_anonymous_refresh'])) && - ($general['allow_anonymous_refresh'] !== 'no') - ); - } - if (isset ($general['api_enabled'])) { - self::$api_enabled = ( - ((bool)($general['api_enabled'])) && - ($general['api_enabled'] !== 'no') - ); - } - if (isset ($general['unsafe_autologin_enabled'])) { - self::$unsafe_autologin_enabled = ( - ((bool)($general['unsafe_autologin_enabled'])) && - ($general['unsafe_autologin_enabled'] !== 'no') - ); - } + /** + * Save the current configuration in the configuration file. + */ + public function save() { + $back_filename = $this->config_filename . '.bak.php'; + @rename($this->config_filename, $back_filename); - if (isset($ini_array['limits'])) { - $limits = $ini_array['limits']; - if (isset($limits['cache_duration'])) { - $v = intval($limits['cache_duration']); - if ($v > 0) { - self::$limits['cache_duration'] = $v; - } - } - if (isset($limits['timeout'])) { - $v = intval($limits['timeout']); - if ($v > 0) { - self::$limits['timeout'] = $v; - } - } - if (isset($limits['max_inactivity'])) { - $v = intval($limits['max_inactivity']); - if ($v > 0) { - self::$limits['max_inactivity'] = $v; - } - } - if (isset($limits['max_feeds'])) { - $v = intval($limits['max_feeds']); - if ($v > 0 && $v < Minz_Configuration::MAX_SMALL_INT) { - self::$limits['max_feeds'] = $v; - } - } - if (isset($limits['max_categories'])) { - $v = intval($limits['max_categories']); - if ($v > 0 && $v < Minz_Configuration::MAX_SMALL_INT) { - self::$limits['max_categories'] = $v; - } - } + if (file_put_contents($this->config_filename, + "data, true) . ';', + LOCK_EX) === false) { + return false; } - // Base de données - if (isset ($ini_array['db'])) { - $db = $ini_array['db']; - if (empty($db['type'])) { - throw new Minz_BadConfigurationException ( - 'type', - Minz_Exception::ERROR - ); - } - switch ($db['type']) { - case 'mysql': - if (empty($db['host'])) { - throw new Minz_BadConfigurationException ( - 'host', - Minz_Exception::ERROR - ); - } - if (empty($db['user'])) { - throw new Minz_BadConfigurationException ( - 'user', - Minz_Exception::ERROR - ); - } - if (!isset($db['password'])) { - throw new Minz_BadConfigurationException ( - 'password', - Minz_Exception::ERROR - ); - } - if (empty($db['base'])) { - throw new Minz_BadConfigurationException ( - 'base', - Minz_Exception::ERROR - ); - } - self::$db['host'] = $db['host']; - self::$db['user'] = $db['user']; - self::$db['password'] = $db['password']; - self::$db['base'] = $db['base']; - if (isset($db['prefix'])) { - self::$db['prefix'] = $db['prefix']; - } - break; - case 'sqlite': - self::$db['host'] = ''; - self::$db['user'] = ''; - self::$db['password'] = ''; - self::$db['base'] = ''; - self::$db['prefix'] = ''; - break; - default: - throw new Minz_BadConfigurationException ( - 'type', - Minz_Exception::ERROR - ); - break; - } - self::$db['type'] = $db['type']; + // Clear PHP 5.5+ cache for include + if (function_exists('opcache_invalidate')) { + opcache_invalidate($this->config_filename); } - } - private static function setReporting() { - switch (self::$environment) { - case self::PRODUCTION: - error_reporting(E_ALL); - ini_set('display_errors','Off'); - ini_set('log_errors', 'On'); - break; - case self::DEVELOPMENT: - error_reporting(E_ALL); - ini_set('display_errors','On'); - ini_set('log_errors', 'On'); - break; - case self::SILENT: - error_reporting(0); - break; - } + return true; } } diff --git a/lib/Minz/ConfigurationException.php b/lib/Minz/ConfigurationException.php new file mode 100644 index 000000000..f294c3341 --- /dev/null +++ b/lib/Minz/ConfigurationException.php @@ -0,0 +1,8 @@ + en fonction de l'environment */ private static function processLogs ($logs) { - $env = Minz_Configuration::environment (); + $conf = Minz_Configuration::get('system'); + $env = $conf->general['environment']; $logs_ok = array (); $error = array (); $warning = array (); @@ -98,10 +99,10 @@ class Minz_Error { $notice = $logs['notice']; } - if ($env == Minz_Configuration::PRODUCTION) { + if ($env == 'production') { $logs_ok = $error; } - if ($env == Minz_Configuration::DEVELOPMENT) { + if ($env == 'development') { $logs_ok = array_merge ($error, $warning, $notice); } diff --git a/lib/Minz/FrontController.php b/lib/Minz/FrontController.php index 3dac1e438..974cf4260 100644 --- a/lib/Minz/FrontController.php +++ b/lib/Minz/FrontController.php @@ -31,9 +31,12 @@ class Minz_FrontController { */ public function __construct () { try { - Minz_Configuration::init (); + Minz_Configuration::register('system', + DATA_PATH . '/config.php', + DATA_PATH . '/config.default.php'); + $this->setReporting(); - Minz_Request::init (); + Minz_Request::init(); $url = $this->buildUrl(); $url['params'] = array_merge ( @@ -110,4 +113,23 @@ class Minz_FrontController { } exit ('### Application problem ###
      '."\n".$txt); } + + private function setReporting() { + $conf = Minz_Configuration::get('system'); + switch($conf->general['environment']) { + case 'production': + error_reporting(E_ALL); + ini_set('display_errors','Off'); + ini_set('log_errors', 'On'); + break; + case 'development': + error_reporting(E_ALL); + ini_set('display_errors','On'); + ini_set('log_errors', 'On'); + break; + case 'silent': + error_reporting(0); + break; + } + } } diff --git a/lib/Minz/Log.php b/lib/Minz/Log.php index d19edc1dc..2063efe7e 100644 --- a/lib/Minz/Log.php +++ b/lib/Minz/Log.php @@ -31,10 +31,15 @@ class Minz_Log { * @param $file_name fichier de log */ public static function record ($information, $level, $file_name = null) { - $env = Minz_Configuration::environment (); + try { + $conf = Minz_Configuration::get('system'); + $env = $conf->general['environment']; + } catch (Minz_ConfigurationException $e) { + $env = 'production'; + } - if (! ($env === Minz_Configuration::SILENT - || ($env === Minz_Configuration::PRODUCTION + if (! ($env === 'silent' + || ($env === 'production' && ($level >= Minz_Log::NOTICE)))) { if ($file_name === null) { $file_name = join_path(USERS_PATH, Minz_Session::param('currentUser', '_'), 'log.txt'); diff --git a/lib/Minz/ModelPdo.php b/lib/Minz/ModelPdo.php index 118d89ad2..ac7a1bed7 100644 --- a/lib/Minz/ModelPdo.php +++ b/lib/Minz/ModelPdo.php @@ -44,7 +44,8 @@ class Minz_ModelPdo { return; } - $db = Minz_Configuration::dataBase(); + $conf = Minz_Configuration::get('system'); + $db = $conf->db; if ($currentUser === null) { $currentUser = Minz_Session::param('currentUser', '_'); diff --git a/lib/Minz/Request.php b/lib/Minz/Request.php index 4b97a3caf..5f2f6a858 100644 --- a/lib/Minz/Request.php +++ b/lib/Minz/Request.php @@ -96,7 +96,8 @@ class Minz_Request { * @return la base de l'url */ public static function getBaseUrl() { - $defaultBaseUrl = Minz_Configuration::baseUrl(); + $conf = Minz_Configuration::get('system'); + $defaultBaseUrl = $conf->general['base_url']; if (!empty($defaultBaseUrl)) { return $defaultBaseUrl; } elseif (isset($_SERVER['REQUEST_URI'])) { diff --git a/lib/Minz/Translate.php b/lib/Minz/Translate.php index e7efb8665..7525e95cc 100644 --- a/lib/Minz/Translate.php +++ b/lib/Minz/Translate.php @@ -28,7 +28,8 @@ class Minz_Translate { * Load $lang_name and $lang_path based on configuration and selected language. */ public static function init() { - $l = Minz_Configuration::language(); + $conf = Minz_Configuration::get('system'); + $l = $conf->general['language']; self::$lang_name = Minz_Session::param('language', $l); self::$lang_path = APP_PATH . '/i18n/' . self::$lang_name . '/'; } diff --git a/lib/Minz/View.php b/lib/Minz/View.php index b40448491..24ad630d0 100644 --- a/lib/Minz/View.php +++ b/lib/Minz/View.php @@ -28,7 +28,9 @@ class Minz_View { public function __construct () { $this->change_view(Minz_Request::controllerName(), Minz_Request::actionName()); - self::$title = Minz_Configuration::title (); + + $conf = Minz_Configuration::get('system'); + self::$title = $conf->general['title']; } /** diff --git a/p/i/index.php b/p/i/index.php index 009d56bc3..d3fc0b37c 100755 --- a/p/i/index.php +++ b/p/i/index.php @@ -33,7 +33,7 @@ if (file_exists(DATA_PATH . '/do-install.txt')) { $currentUser = Minz_Session::param('currentUser', ''); $dateLastModification = $currentUser === '' ? time() : max( @filemtime(join_path(USERS_PATH, $currentUser, 'log.txt')), - @filemtime(join_path(DATA_PATH . 'config.php')) + @filemtime(join_path(DATA_PATH, 'config.php')) ); if (httpConditional($dateLastModification, 0, 0, false, PHP_COMPRESSION, true)) { exit(); //No need to send anything -- cgit v1.2.3 From 7cca47d1ab5838f5440b1a1e08fa4c0d43989664 Mon Sep 17 00:00:00 2001 From: Marien Fressinaud Date: Mon, 5 Jan 2015 22:43:15 +0100 Subject: Change name of user configuration var in Context - FreshRSS_Context::$conf is replaced by FreshRSS_Context::$user_conf - Introduce FreshRSS_Context::$system_conf - Remove FreshRSS_Configuration object See https://github.com/FreshRSS/FreshRSS/issues/730 --- app/Controllers/authController.php | 24 +- app/Controllers/categoryController.php | 10 +- app/Controllers/configureController.php | 94 ++++---- app/Controllers/entryController.php | 4 +- app/Controllers/feedController.php | 18 +- app/Controllers/importExportController.php | 4 +- app/Controllers/indexController.php | 12 +- app/Controllers/javascriptController.php | 2 +- app/Controllers/userController.php | 18 +- app/FreshRSS.php | 7 +- app/Models/Configuration.php | 345 ----------------------------- app/Models/Context.php | 20 +- app/layout/aside_feed.phtml | 6 +- app/layout/layout.phtml | 2 +- app/layout/nav_menu.phtml | 10 +- app/views/auth/index.phtml | 4 +- app/views/configure/archiving.phtml | 10 +- app/views/configure/display.phtml | 30 +-- app/views/configure/queries.phtml | 4 +- app/views/configure/reading.phtml | 44 ++-- app/views/configure/sharing.phtml | 6 +- app/views/configure/shortcut.phtml | 2 +- app/views/helpers/javascript_vars.phtml | 14 +- app/views/helpers/pagination.phtml | 2 +- app/views/index/global.phtml | 4 +- app/views/index/normal.phtml | 32 +-- app/views/index/reader.phtml | 4 +- app/views/user/manage.phtml | 6 +- app/views/user/profile.phtml | 2 +- 29 files changed, 196 insertions(+), 544 deletions(-) delete mode 100644 app/Models/Configuration.php diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php index f68ea8da5..3a1ad4605 100644 --- a/app/Controllers/authController.php +++ b/app/Controllers/authController.php @@ -27,12 +27,11 @@ class FreshRSS_auth_Controller extends Minz_ActionController { if (Minz_Request::isPost()) { $ok = true; - $system_conf = Minz_Configuration::get('system'); - $general = $system_conf->general; - $current_token = FreshRSS_Context::$conf->token; + $general = FreshRSS_Context::$system_conf->general; + $current_token = FreshRSS_Context::$user_conf->token; $token = Minz_Request::param('token', $current_token); - FreshRSS_Context::$conf->_token($token); - $ok &= FreshRSS_Context::$conf->save(); + FreshRSS_Context::$user_conf->_token($token); + $ok &= FreshRSS_Context::$user_conf->save(); $anon = Minz_Request::param('anon_access', false); $anon = ((bool)$anon) && ($anon !== 'no'); @@ -81,8 +80,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true); } - $conf = Minz_Configuration::get('system'); - $auth_type = $conf->general['auth_type']; + $auth_type = FreshRSS_Context::$system_conf->general['auth_type']; switch ($auth_type) { case 'form': Minz_Request::forward(array('c' => 'auth', 'a' => 'formLogin')); @@ -120,12 +118,12 @@ class FreshRSS_auth_Controller extends Minz_ActionController { $file_mtime = @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js'); Minz_View::appendScript(Minz_Url::display('/scripts/bcrypt.min.js?' . $file_mtime)); - $conf = Minz_Configuration::get('system'); - if (Minz_Request::isPost()) { $nonce = Minz_Session::param('nonce'); $username = Minz_Request::param('username', ''); $challenge = Minz_Request::param('challenge', ''); + + // TODO #730: change the way to get the configuration try { $conf = new FreshRSS_Configuration($username); } catch(Minz_Exception $e) { @@ -162,7 +160,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { Minz_Request::bad(_t('feedback.auth.login.invalid'), array('c' => 'auth', 'a' => 'login')); } - } elseif ($conf->general['unsafe_autologin_enabled']) { + } elseif (FreshRSS_Context::$system_conf->general['unsafe_autologin_enabled']) { $username = Minz_Request::param('u', ''); $password = Minz_Request::param('p', ''); Minz_Request::_param('p'); @@ -171,6 +169,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { return; } + // TODO #730: change the way to get the configuration try { $conf = new FreshRSS_Configuration($username); } catch(Minz_Exception $e) { @@ -243,6 +242,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { $persona_file = DATA_PATH . '/persona/' . $email . '.txt'; if (($current_user = @file_get_contents($persona_file)) !== false) { $current_user = trim($current_user); + // TODO #730: change the way to get the configuration try { $conf = new FreshRSS_Configuration($current_user); $login_ok = strcasecmp($email, $conf->mail_login) === 0; @@ -301,7 +301,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { $this->view->no_form = false; // Enable changement of auth only if Persona! - if (Minz_Configuration::authType() != 'persona') { + if (FreshRSS_Context::$system_conf->general['auth_type'] != 'persona') { $this->view->message = array( 'status' => 'bad', 'title' => _t('gen.short.damn'), @@ -311,6 +311,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { return; } + // TODO #730 $conf = new FreshRSS_Configuration(Minz_Configuration::defaultUser()); // Admin user must have set its master password. if (!$conf->passwordHash) { @@ -335,6 +336,7 @@ class FreshRSS_auth_Controller extends Minz_ActionController { ); if ($ok) { + // TODO #730 Minz_Configuration::_authType('form'); $ok = Minz_Configuration::writeFile(); diff --git a/app/Controllers/categoryController.php b/app/Controllers/categoryController.php index 5f1beae90..c90e55ea7 100644 --- a/app/Controllers/categoryController.php +++ b/app/Controllers/categoryController.php @@ -30,7 +30,7 @@ class FreshRSS_category_Controller extends Minz_ActionController { $catDAO = new FreshRSS_CategoryDAO(); $url_redirect = array('c' => 'subscription', 'a' => 'index'); - $limits = Minz_Configuration::limits(); + $limits = FreshRSS_Context::$system_conf->limits; $this->view->categories = $catDAO->listCategories(false); if (count($this->view->categories) >= $limits['max_categories']) { @@ -141,8 +141,8 @@ class FreshRSS_category_Controller extends Minz_ActionController { } // Remove related queries. - FreshRSS_Context::$conf->remove_query_by_get('c_' . $id); - FreshRSS_Context::$conf->save(); + FreshRSS_Context::$user_conf->remove_query_by_get('c_' . $id); + FreshRSS_Context::$user_conf->save(); Minz_Request::good(_t('feedback.sub.category.deleted'), $url_redirect); } @@ -177,9 +177,9 @@ class FreshRSS_category_Controller extends Minz_ActionController { // Remove related queries foreach ($feeds as $feed) { - FreshRSS_Context::$conf->remove_query_by_get('f_' . $feed->id()); + FreshRSS_Context::$user_conf->remove_query_by_get('f_' . $feed->id()); } - FreshRSS_Context::$conf->save(); + FreshRSS_Context::$user_conf->save(); Minz_Request::good(_t('feedback.sub.category.emptied'), $url_redirect); } else { diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php index feb5483fb..6e7a40ea6 100755 --- a/app/Controllers/configureController.php +++ b/app/Controllers/configureController.php @@ -41,23 +41,23 @@ class FreshRSS_configure_Controller extends Minz_ActionController { */ public function displayAction() { if (Minz_Request::isPost()) { - FreshRSS_Context::$conf->_language(Minz_Request::param('language', 'en')); - FreshRSS_Context::$conf->_theme(Minz_Request::param('theme', FreshRSS_Themes::$defaultTheme)); - FreshRSS_Context::$conf->_content_width(Minz_Request::param('content_width', 'thin')); - FreshRSS_Context::$conf->_topline_read(Minz_Request::param('topline_read', false)); - FreshRSS_Context::$conf->_topline_favorite(Minz_Request::param('topline_favorite', false)); - FreshRSS_Context::$conf->_topline_date(Minz_Request::param('topline_date', false)); - FreshRSS_Context::$conf->_topline_link(Minz_Request::param('topline_link', false)); - FreshRSS_Context::$conf->_bottomline_read(Minz_Request::param('bottomline_read', false)); - FreshRSS_Context::$conf->_bottomline_favorite(Minz_Request::param('bottomline_favorite', false)); - FreshRSS_Context::$conf->_bottomline_sharing(Minz_Request::param('bottomline_sharing', false)); - FreshRSS_Context::$conf->_bottomline_tags(Minz_Request::param('bottomline_tags', false)); - FreshRSS_Context::$conf->_bottomline_date(Minz_Request::param('bottomline_date', false)); - FreshRSS_Context::$conf->_bottomline_link(Minz_Request::param('bottomline_link', false)); - FreshRSS_Context::$conf->_html5_notif_timeout(Minz_Request::param('html5_notif_timeout', 0)); - FreshRSS_Context::$conf->save(); - - Minz_Session::_param('language', FreshRSS_Context::$conf->language); + FreshRSS_Context::$user_conf->_language(Minz_Request::param('language', 'en')); + FreshRSS_Context::$user_conf->_theme(Minz_Request::param('theme', FreshRSS_Themes::$defaultTheme)); + FreshRSS_Context::$user_conf->_content_width(Minz_Request::param('content_width', 'thin')); + FreshRSS_Context::$user_conf->_topline_read(Minz_Request::param('topline_read', false)); + FreshRSS_Context::$user_conf->_topline_favorite(Minz_Request::param('topline_favorite', false)); + FreshRSS_Context::$user_conf->_topline_date(Minz_Request::param('topline_date', false)); + FreshRSS_Context::$user_conf->_topline_link(Minz_Request::param('topline_link', false)); + FreshRSS_Context::$user_conf->_bottomline_read(Minz_Request::param('bottomline_read', false)); + FreshRSS_Context::$user_conf->_bottomline_favorite(Minz_Request::param('bottomline_favorite', false)); + FreshRSS_Context::$user_conf->_bottomline_sharing(Minz_Request::param('bottomline_sharing', false)); + FreshRSS_Context::$user_conf->_bottomline_tags(Minz_Request::param('bottomline_tags', false)); + FreshRSS_Context::$user_conf->_bottomline_date(Minz_Request::param('bottomline_date', false)); + FreshRSS_Context::$user_conf->_bottomline_link(Minz_Request::param('bottomline_link', false)); + FreshRSS_Context::$user_conf->_html5_notif_timeout(Minz_Request::param('html5_notif_timeout', 0)); + FreshRSS_Context::$user_conf->save(); + + Minz_Session::_param('language', FreshRSS_Context::$user_conf->language); Minz_Translate::reset(); invalidateHttpCache(); @@ -100,28 +100,28 @@ class FreshRSS_configure_Controller extends Minz_ActionController { */ public function readingAction() { if (Minz_Request::isPost()) { - FreshRSS_Context::$conf->_posts_per_page(Minz_Request::param('posts_per_page', 10)); - FreshRSS_Context::$conf->_view_mode(Minz_Request::param('view_mode', 'normal')); - FreshRSS_Context::$conf->_default_view(Minz_Request::param('default_view', 'adaptive')); - FreshRSS_Context::$conf->_auto_load_more(Minz_Request::param('auto_load_more', false)); - FreshRSS_Context::$conf->_display_posts(Minz_Request::param('display_posts', false)); - FreshRSS_Context::$conf->_display_categories(Minz_Request::param('display_categories', false)); - FreshRSS_Context::$conf->_hide_read_feeds(Minz_Request::param('hide_read_feeds', false)); - FreshRSS_Context::$conf->_onread_jump_next(Minz_Request::param('onread_jump_next', false)); - FreshRSS_Context::$conf->_lazyload(Minz_Request::param('lazyload', false)); - FreshRSS_Context::$conf->_sticky_post(Minz_Request::param('sticky_post', false)); - FreshRSS_Context::$conf->_reading_confirm(Minz_Request::param('reading_confirm', false)); - FreshRSS_Context::$conf->_auto_remove_article(Minz_Request::param('auto_remove_article', false)); - FreshRSS_Context::$conf->_sort_order(Minz_Request::param('sort_order', 'DESC')); - FreshRSS_Context::$conf->_mark_when(array( + FreshRSS_Context::$user_conf->_posts_per_page(Minz_Request::param('posts_per_page', 10)); + FreshRSS_Context::$user_conf->_view_mode(Minz_Request::param('view_mode', 'normal')); + FreshRSS_Context::$user_conf->_default_view(Minz_Request::param('default_view', 'adaptive')); + FreshRSS_Context::$user_conf->_auto_load_more(Minz_Request::param('auto_load_more', false)); + FreshRSS_Context::$user_conf->_display_posts(Minz_Request::param('display_posts', false)); + FreshRSS_Context::$user_conf->_display_categories(Minz_Request::param('display_categories', false)); + FreshRSS_Context::$user_conf->_hide_read_feeds(Minz_Request::param('hide_read_feeds', false)); + FreshRSS_Context::$user_conf->_onread_jump_next(Minz_Request::param('onread_jump_next', false)); + FreshRSS_Context::$user_conf->_lazyload(Minz_Request::param('lazyload', false)); + FreshRSS_Context::$user_conf->_sticky_post(Minz_Request::param('sticky_post', false)); + FreshRSS_Context::$user_conf->_reading_confirm(Minz_Request::param('reading_confirm', false)); + FreshRSS_Context::$user_conf->_auto_remove_article(Minz_Request::param('auto_remove_article', false)); + FreshRSS_Context::$user_conf->_sort_order(Minz_Request::param('sort_order', 'DESC')); + FreshRSS_Context::$user_conf->_mark_when(array( 'article' => Minz_Request::param('mark_open_article', false), 'site' => Minz_Request::param('mark_open_site', false), 'scroll' => Minz_Request::param('mark_scroll', false), 'reception' => Minz_Request::param('mark_upon_reception', false), )); - FreshRSS_Context::$conf->save(); + FreshRSS_Context::$user_conf->save(); - Minz_Session::_param('language', FreshRSS_Context::$conf->language); + Minz_Session::_param('language', FreshRSS_Context::$user_conf->language); Minz_Translate::reset(); invalidateHttpCache(); @@ -142,8 +142,8 @@ class FreshRSS_configure_Controller extends Minz_ActionController { public function sharingAction() { if (Minz_Request::isPost()) { $params = Minz_Request::params(); - FreshRSS_Context::$conf->_sharing($params['share']); - FreshRSS_Context::$conf->save(); + FreshRSS_Context::$user_conf->_sharing($params['share']); + FreshRSS_Context::$user_conf->save(); invalidateHttpCache(); Minz_Request::good(_t('feedback.conf.updated'), @@ -184,8 +184,8 @@ class FreshRSS_configure_Controller extends Minz_ActionController { } } - FreshRSS_Context::$conf->_shortcuts($shortcuts_ok); - FreshRSS_Context::$conf->save(); + FreshRSS_Context::$user_conf->_shortcuts($shortcuts_ok); + FreshRSS_Context::$user_conf->save(); invalidateHttpCache(); Minz_Request::good(_t('feedback.conf.shortcuts_updated'), @@ -212,10 +212,10 @@ class FreshRSS_configure_Controller extends Minz_ActionController { */ public function archivingAction() { if (Minz_Request::isPost()) { - FreshRSS_Context::$conf->_old_entries(Minz_Request::param('old_entries', 3)); - FreshRSS_Context::$conf->_keep_history_default(Minz_Request::param('keep_history_default', 0)); - FreshRSS_Context::$conf->_ttl_default(Minz_Request::param('ttl_default', -2)); - FreshRSS_Context::$conf->save(); + FreshRSS_Context::$user_conf->_old_entries(Minz_Request::param('old_entries', 3)); + FreshRSS_Context::$user_conf->_keep_history_default(Minz_Request::param('keep_history_default', 0)); + FreshRSS_Context::$user_conf->_ttl_default(Minz_Request::param('ttl_default', -2)); + FreshRSS_Context::$user_conf->save(); invalidateHttpCache(); Minz_Request::good(_t('feedback.conf.updated'), @@ -252,8 +252,8 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $query['name'] = _t('conf.query.number', $key + 1); } } - FreshRSS_Context::$conf->_queries($queries); - FreshRSS_Context::$conf->save(); + FreshRSS_Context::$user_conf->_queries($queries); + FreshRSS_Context::$user_conf->save(); Minz_Request::good(_t('feedback.conf.updated'), array('c' => 'configure', 'a' => 'queries')); @@ -261,7 +261,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { $this->view->query_get = array(); $cat_dao = new FreshRSS_CategoryDAO(); $feed_dao = FreshRSS_Factory::createFeedDao(); - foreach (FreshRSS_Context::$conf->queries as $key => $query) { + foreach (FreshRSS_Context::$user_conf->queries as $key => $query) { if (!isset($query['get'])) { continue; } @@ -329,7 +329,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController { */ public function addQueryAction() { $whitelist = array('get', 'order', 'name', 'search', 'state'); - $queries = FreshRSS_Context::$conf->queries; + $queries = FreshRSS_Context::$user_conf->queries; $query = Minz_Request::params(); $query['name'] = _t('conf.query.number', count($queries) + 1); foreach ($query as $key => $value) { @@ -338,8 +338,8 @@ class FreshRSS_configure_Controller extends Minz_ActionController { } } $queries[] = $query; - FreshRSS_Context::$conf->_queries($queries); - FreshRSS_Context::$conf->save(); + FreshRSS_Context::$user_conf->_queries($queries); + FreshRSS_Context::$user_conf->save(); Minz_Request::good(_t('feedback.conf.query_created', $query['name']), array('c' => 'configure', 'a' => 'queries')); diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php index aae08c413..1d9989f40 100755 --- a/app/Controllers/entryController.php +++ b/app/Controllers/entryController.php @@ -154,7 +154,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { public function purgeAction() { @set_time_limit(300); - $nb_month_old = max(FreshRSS_Context::$conf->old_entries, 1); + $nb_month_old = max(FreshRSS_Context::$user_conf->old_entries, 1); $date_min = time() - (3600 * 24 * 30 * $nb_month_old); $feedDAO = FreshRSS_Factory::createFeedDao(); @@ -168,7 +168,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController { if ($feed_history == -2) { // TODO: -2 must be a constant! // -2 means we take the default value from configuration - $feed_history = FreshRSS_Context::$conf->keep_history_default; + $feed_history = FreshRSS_Context::$user_conf->keep_history_default; } if ($feed_history >= 0) { diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index 121cb8921..92a1e3bf8 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -14,7 +14,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // Token is useful in the case that anonymous refresh is forbidden // and CRON task cannot be used with php command so the user can // set a CRON task to refresh his feeds by using token inside url - $token = FreshRSS_Context::$conf->token; + $token = FreshRSS_Context::$user_conf->token; $token_param = Minz_Request::param('token', ''); $token_is_ok = ($token != '' && $token == $token_param); $action = Minz_Request::actionName(); @@ -161,14 +161,14 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feed->_id($id); $feed->faviconPrepare(); - $is_read = FreshRSS_Context::$conf->mark_when['reception'] ? 1 : 0; + $is_read = FreshRSS_Context::$user_conf->mark_when['reception'] ? 1 : 0; $entryDAO = FreshRSS_Factory::createEntryDao(); // We want chronological order and SimplePie uses reverse order. $entries = array_reverse($feed->entries()); // Calculate date of oldest entries we accept in DB. - $nb_month_old = FreshRSS_Context::$conf->old_entries; + $nb_month_old = FreshRSS_Context::$user_conf->old_entries; $date_min = time() - (3600 * 24 * 30 * $nb_month_old); // Use a shared statement and a transaction to improve a LOT the @@ -272,15 +272,15 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feeds[] = $feed; } } else { - $feeds = $feedDAO->listFeedsOrderUpdate(FreshRSS_Context::$conf->ttl_default); + $feeds = $feedDAO->listFeedsOrderUpdate(FreshRSS_Context::$user_conf->ttl_default); } // Calculate date of oldest entries we accept in DB. - $nb_month_old = max(FreshRSS_Context::$conf->old_entries, 1); + $nb_month_old = max(FreshRSS_Context::$user_conf->old_entries, 1); $date_min = time() - (3600 * 24 * 30 * $nb_month_old); $updated_feeds = 0; - $is_read = FreshRSS_Context::$conf->mark_when['reception'] ? 1 : 0; + $is_read = FreshRSS_Context::$user_conf->mark_when['reception'] ? 1 : 0; foreach ($feeds as $feed) { if (!$feed->lock()) { Minz_Log::notice('Feed already being actualized: ' . $feed->url()); @@ -302,7 +302,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController { if ($feed_history == -2) { // TODO: -2 must be a constant! // -2 means we take the default value from configuration - $feed_history = FreshRSS_Context::$conf->keep_history_default; + $feed_history = FreshRSS_Context::$user_conf->keep_history_default; } // We want chronological order and SimplePie uses reverse order. @@ -476,8 +476,8 @@ class FreshRSS_feed_Controller extends Minz_ActionController { // TODO: Delete old favicon // Remove related queries - FreshRSS_Context::$conf->remove_query_by_get('f_' . $id); - FreshRSS_Context::$conf->save(); + FreshRSS_Context::$user_conf->remove_query_by_get('f_' . $id); + FreshRSS_Context::$user_conf->save(); Minz_Request::good(_t('feedback.sub.feed.deleted'), $redirect_url); } else { diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 6eefa0f6f..334f33d6a 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -315,7 +315,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { return true; } - $is_read = FreshRSS_Context::$conf->mark_when['reception'] ? 1 : 0; + $is_read = FreshRSS_Context::$user_conf->mark_when['reception'] ? 1 : 0; $google_compliant = strpos($article_object['id'], 'com.google') !== false; @@ -532,7 +532,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $this->view->type = 'feed/' . $feed->id(); $this->view->entries = $this->entryDAO->listWhere( 'f', $feed->id(), FreshRSS_Entry::STATE_ALL, 'ASC', - FreshRSS_Context::$conf->posts_per_page + FreshRSS_Context::$user_conf->posts_per_page ); $this->view->feed = $feed; } diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php index 33cd2843c..14f3f4f4b 100755 --- a/app/Controllers/indexController.php +++ b/app/Controllers/indexController.php @@ -9,7 +9,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { * This action only redirect on the default view mode (normal or global) */ public function indexAction() { - $prefered_output = FreshRSS_Context::$conf->view_mode; + $prefered_output = FreshRSS_Context::$user_conf->view_mode; Minz_Request::forward(array( 'c' => 'index', 'a' => $prefered_output @@ -109,7 +109,7 @@ class FreshRSS_index_Controller extends Minz_ActionController { * This action displays the RSS feed of FreshRSS. */ public function rssAction() { - $token = FreshRSS_Context::$conf->token; + $token = FreshRSS_Context::$user_conf->token; $token_param = Minz_Request::param('token', ''); $token_is_ok = ($token != '' && $token === $token_param); @@ -160,10 +160,10 @@ class FreshRSS_index_Controller extends Minz_ActionController { FreshRSS_Context::_get(Minz_Request::param('get', 'a')); FreshRSS_Context::$state = Minz_Request::param( - 'state', FreshRSS_Context::$conf->default_state + 'state', FreshRSS_Context::$user_conf->default_state ); $state_forced_by_user = Minz_Request::param('state', false) !== false; - if (FreshRSS_Context::$conf->default_view === 'adaptive' && + if (FreshRSS_Context::$user_conf->default_view === 'adaptive' && FreshRSS_Context::$get_unread <= 0 && !FreshRSS_Context::isStateEnabled(FreshRSS_Entry::STATE_READ) && !$state_forced_by_user) { @@ -172,10 +172,10 @@ class FreshRSS_index_Controller extends Minz_ActionController { FreshRSS_Context::$search = Minz_Request::param('search', ''); FreshRSS_Context::$order = Minz_Request::param( - 'order', FreshRSS_Context::$conf->sort_order + 'order', FreshRSS_Context::$user_conf->sort_order ); FreshRSS_Context::$number = Minz_Request::param( - 'nb', FreshRSS_Context::$conf->posts_per_page + 'nb', FreshRSS_Context::$user_conf->posts_per_page ); FreshRSS_Context::$first_id = Minz_Request::param('next', ''); } diff --git a/app/Controllers/javascriptController.php b/app/Controllers/javascriptController.php index 113f58ea9..b178801d4 100755 --- a/app/Controllers/javascriptController.php +++ b/app/Controllers/javascriptController.php @@ -8,7 +8,7 @@ class FreshRSS_javascript_Controller extends Minz_ActionController { public function actualizeAction() { header('Content-Type: text/javascript; charset=UTF-8'); $feedDAO = FreshRSS_Factory::createFeedDao(); - $this->view->feeds = $feedDAO->listFeedsOrderUpdate(FreshRSS_Context::$conf->ttl_default); + $this->view->feeds = $feedDAO->listFeedsOrderUpdate(FreshRSS_Context::$user_conf->ttl_default); } public function nbUnreadsPerFeedAction() { diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php index 1b1ccaac9..58181bfb0 100644 --- a/app/Controllers/userController.php +++ b/app/Controllers/userController.php @@ -39,9 +39,9 @@ class FreshRSS_user_Controller extends Minz_ActionController { $passwordPlain = ''; $passwordHash = preg_replace('/^\$2[xy]\$/', '\$2a\$', $passwordHash); //Compatibility with bcrypt.js $ok &= ($passwordHash != ''); - FreshRSS_Context::$conf->_passwordHash($passwordHash); + FreshRSS_Context::$user_conf->_passwordHash($passwordHash); } - Minz_Session::_param('passwordHash', FreshRSS_Context::$conf->passwordHash); + Minz_Session::_param('passwordHash', FreshRSS_Context::$user_conf->passwordHash); $passwordPlain = Minz_Request::param('apiPasswordPlain', '', true); if ($passwordPlain != '') { @@ -52,17 +52,17 @@ class FreshRSS_user_Controller extends Minz_ActionController { $passwordPlain = ''; $passwordHash = preg_replace('/^\$2[xy]\$/', '\$2a\$', $passwordHash); //Compatibility with bcrypt.js $ok &= ($passwordHash != ''); - FreshRSS_Context::$conf->_apiPasswordHash($passwordHash); + FreshRSS_Context::$user_conf->_apiPasswordHash($passwordHash); } // TODO: why do we need of hasAccess here? if (FreshRSS_Auth::hasAccess('admin')) { - FreshRSS_Context::$conf->_mail_login(Minz_Request::param('mail_login', '', true)); + FreshRSS_Context::$user_conf->_mail_login(Minz_Request::param('mail_login', '', true)); } - $email = FreshRSS_Context::$conf->mail_login; + $email = FreshRSS_Context::$user_conf->mail_login; Minz_Session::_param('mail', $email); - $ok &= FreshRSS_Context::$conf->save(); + $ok &= FreshRSS_Context::$user_conf->save(); if ($email != '') { $personaFile = DATA_PATH . '/persona/' . $email . '.txt'; @@ -108,10 +108,10 @@ class FreshRSS_user_Controller extends Minz_ActionController { $db = Minz_Configuration::dataBase(); require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php'); - $new_user_language = Minz_Request::param('new_user_language', FreshRSS_Context::$conf->language); - $languages = FreshRSS_Context::$conf->availableLanguages(); + $new_user_language = Minz_Request::param('new_user_language', FreshRSS_Context::$user_conf->language); + $languages = FreshRSS_Context::$user_conf->availableLanguages(); if (!isset($languages[$new_user_language])) { - $new_user_language = FreshRSS_Context::$conf->language; + $new_user_language = FreshRSS_Context::$user_conf->language; } $new_user_name = Minz_Request::param('new_user_name'); diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 455f2fefd..b22bfdb4b 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -32,7 +32,7 @@ class FreshRSS extends Minz_FrontController { FreshRSS_Context::init(); // Init i18n. - Minz_Session::_param('language', FreshRSS_Context::$conf->language); + Minz_Session::_param('language', FreshRSS_Context::$user_conf->language); Minz_Translate::init(); $this->loadStylesAndScripts(); @@ -41,7 +41,7 @@ class FreshRSS extends Minz_FrontController { } private function loadStylesAndScripts() { - $theme = FreshRSS_Themes::load(FreshRSS_Context::$conf->theme); + $theme = FreshRSS_Themes::load(FreshRSS_Context::$user_conf->theme); if ($theme) { foreach($theme['files'] as $file) { if ($file[0] === '_') { @@ -62,8 +62,7 @@ class FreshRSS extends Minz_FrontController { Minz_View::appendScript(Minz_Url::display('/scripts/shortcut.js?' . @filemtime(PUBLIC_PATH . '/scripts/shortcut.js'))); Minz_View::appendScript(Minz_Url::display('/scripts/main.js?' . @filemtime(PUBLIC_PATH . '/scripts/main.js'))); - $conf = Minz_Configuration::get('system'); - if ($conf->general['auth_type'] === 'persona') { + if (FreshRSS_Context::$system_conf->general['auth_type'] === 'persona') { // TODO move it in a plugin // Needed for login AND logout with Persona. Minz_View::appendScript('https://login.persona.org/include.js'); diff --git a/app/Models/Configuration.php b/app/Models/Configuration.php deleted file mode 100644 index 8bba8f777..000000000 --- a/app/Models/Configuration.php +++ /dev/null @@ -1,345 +0,0 @@ - 'en', - 'old_entries' => 3, - 'keep_history_default' => 0, - 'ttl_default' => 3600, - 'mail_login' => '', - 'token' => '', - 'passwordHash' => '', //CRYPT_BLOWFISH - 'apiPasswordHash' => '', //CRYPT_BLOWFISH - 'posts_per_page' => 20, - 'view_mode' => 'normal', - 'default_view' => 'adaptive', - 'default_state' => FreshRSS_Entry::STATE_NOT_READ, - 'auto_load_more' => true, - 'display_posts' => false, - 'display_categories' => false, - 'hide_read_feeds' => true, - 'onread_jump_next' => true, - 'lazyload' => true, - 'sticky_post' => true, - 'reading_confirm' => false, - 'auto_remove_article' => false, - 'sort_order' => 'DESC', - 'anon_access' => false, - 'mark_when' => array( - 'article' => true, - 'site' => true, - 'scroll' => false, - 'reception' => false, - ), - 'theme' => 'Origine', - 'content_width' => 'thin', - 'shortcuts' => array( - 'mark_read' => 'r', - 'mark_favorite' => 'f', - 'go_website' => 'space', - 'next_entry' => 'j', - 'prev_entry' => 'k', - 'first_entry' => 'home', - 'last_entry' => 'end', - 'collapse_entry' => 'c', - 'load_more' => 'm', - 'auto_share' => 's', - 'focus_search' => 'a', - 'user_filter' => 'u', - 'help' => 'f1', - 'close_dropdown' => 'escape', - ), - 'topline_read' => true, - 'topline_favorite' => true, - 'topline_date' => true, - 'topline_link' => true, - 'bottomline_read' => true, - 'bottomline_favorite' => true, - 'bottomline_sharing' => true, - 'bottomline_tags' => true, - 'bottomline_date' => true, - 'bottomline_link' => true, - 'sharing' => array(), - 'queries' => array(), - 'html5_notif_timeout' => 0, - ); - - private $available_languages = array( - 'en' => 'English', - 'fr' => 'Français', - ); - - private $shares; - - public function __construct($user) { - $this->filename = join_path(DATA_PATH, 'users', $user, 'config.php'); - - $data = @include($this->filename); - if (!is_array($data)) { - throw new Minz_PermissionDeniedException($this->filename); - } - - foreach ($data as $key => $value) { - if (isset($this->data[$key])) { - $function = '_' . $key; - $this->$function($value); - } - } - $this->data['user'] = $user; - - $this->shares = join_path(DATA_PATH, 'shares.php'); - - $shares = @include($this->shares); - if (!is_array($shares)) { - throw new Minz_PermissionDeniedException($this->shares); - } - - $this->data['shares'] = $shares; - } - - public function save() { - @rename($this->filename, $this->filename . '.bak.php'); - unset($this->data['shares']); // Remove shares because it is not intended to be stored in user configuration - if (file_put_contents($this->filename, "data, true) . ';', LOCK_EX) === false) { - throw new Minz_PermissionDeniedException($this->filename); - } - if (function_exists('opcache_invalidate')) { - opcache_invalidate($this->filename); //Clear PHP 5.5+ cache for include - } - invalidateHttpCache(); - return true; - } - - public function __get($name) { - if (array_key_exists($name, $this->data)) { - return $this->data[$name]; - } else { - $trace = debug_backtrace(); - trigger_error('Undefined FreshRSS_Configuration->' . $name . 'in ' . $trace[0]['file'] . ' line ' . $trace[0]['line'], E_USER_NOTICE); //TODO: Use Minz exceptions - return null; - } - } - - public function availableLanguages() { - 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'; - } - $this->data['language'] = $value; - } - public function _posts_per_page($value) { - $value = intval($value); - $this->data['posts_per_page'] = $value > 0 ? $value : 10; - } - public function _view_mode($value) { - if ($value === 'global' || $value === 'reader') { - $this->data['view_mode'] = $value; - } else { - $this->data['view_mode'] = 'normal'; - } - } - public function _default_view($value) { - switch ($value) { - case 'all': - $this->data['default_view'] = $value; - $this->data['default_state'] = (FreshRSS_Entry::STATE_READ + - FreshRSS_Entry::STATE_NOT_READ); - break; - case 'adaptive': - case 'unread': - default: - $this->data['default_view'] = $value; - $this->data['default_state'] = FreshRSS_Entry::STATE_NOT_READ; - } - } - public function _default_state($value) { - $this->data['default_state'] = (int)$value; - } - - public function _display_posts($value) { - $this->data['display_posts'] = ((bool)$value) && $value !== 'no'; - } - public function _display_categories($value) { - $this->data['display_categories'] = ((bool)$value) && $value !== 'no'; - } - public function _hide_read_feeds($value) { - $this->data['hide_read_feeds'] = (bool)$value; - } - public function _onread_jump_next($value) { - $this->data['onread_jump_next'] = ((bool)$value) && $value !== 'no'; - } - public function _lazyload($value) { - $this->data['lazyload'] = ((bool)$value) && $value !== 'no'; - } - public function _sticky_post($value) { - $this->data['sticky_post'] = ((bool)$value) && $value !== 'no'; - } - public function _reading_confirm($value) { - $this->data['reading_confirm'] = ((bool)$value) && $value !== 'no'; - } - public function _auto_remove_article($value) { - $this->data['auto_remove_article'] = ((bool)$value) && $value !== 'no'; - } - public function _sort_order($value) { - $this->data['sort_order'] = $value === 'ASC' ? 'ASC' : 'DESC'; - } - public function _old_entries($value) { - $value = intval($value); - $this->data['old_entries'] = $value > 0 ? $value : 3; - } - public function _keep_history_default($value) { - $value = intval($value); - $this->data['keep_history_default'] = $value >= -1 ? $value : 0; - } - public function _ttl_default($value) { - $value = intval($value); - $this->data['ttl_default'] = $value >= -1 ? $value : 3600; - } - public function _shortcuts($values) { - foreach ($values as $key => $value) { - if (isset($this->data['shortcuts'][$key])) { - $this->data['shortcuts'][$key] = $value; - } - } - } - public function _passwordHash($value) { - $this->data['passwordHash'] = ctype_graph($value) && (strlen($value) >= 60) ? $value : ''; - } - public function _apiPasswordHash($value) { - $this->data['apiPasswordHash'] = ctype_graph($value) && (strlen($value) >= 60) ? $value : ''; - } - public function _mail_login($value) { - $value = filter_var($value, FILTER_VALIDATE_EMAIL); - if ($value) { - $this->data['mail_login'] = $value; - } else { - $this->data['mail_login'] = ''; - } - } - public function _anon_access($value) { - $this->data['anon_access'] = ((bool)$value) && $value !== 'no'; - } - public function _mark_when($values) { - foreach ($values as $key => $value) { - if (isset($this->data['mark_when'][$key])) { - $this->data['mark_when'][$key] = ((bool)$value) && $value !== 'no'; - } - } - } - public function _sharing($values) { - $this->data['sharing'] = array(); - $unique = array(); - foreach ($values as $value) { - if (!is_array($value)) { - continue; - } - - // Verify URL and add default value when needed - if (isset($value['url'])) { - $is_url = ( - filter_var($value['url'], FILTER_VALIDATE_URL) || - (version_compare(PHP_VERSION, '5.3.3', '<') && - (strpos($value, '-') > 0) && - ($value === filter_var($value, FILTER_SANITIZE_URL))) - ); //PHP bug #51192 - if (!$is_url) { - continue; - } - } else { - $value['url'] = null; - } - - // Add a default name - if (empty($value['name'])) { - $value['name'] = $value['type']; - } - - $json_value = json_encode($value); - if (!in_array($json_value, $unique)) { - $unique[] = $json_value; - $this->data['sharing'][] = $value; - } - } - } - public function _queries($values) { - $this->data['queries'] = array(); - foreach ($values as $value) { - $value = array_filter($value); - $params = $value; - unset($params['name']); - unset($params['url']); - $value['url'] = Minz_Url::display(array('params' => $params)); - - $this->data['queries'][] = $value; - } - } - public function _theme($value) { - $this->data['theme'] = $value; - } - public function _content_width($value) { - if ($value === 'medium' || - $value === 'large' || - $value === 'no_limit') { - $this->data['content_width'] = $value; - } else { - $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; - } - public function _auto_load_more($value) { - $this->data['auto_load_more'] = ((bool)$value) && $value !== 'no'; - } - public function _topline_read($value) { - $this->data['topline_read'] = ((bool)$value) && $value !== 'no'; - } - public function _topline_favorite($value) { - $this->data['topline_favorite'] = ((bool)$value) && $value !== 'no'; - } - public function _topline_date($value) { - $this->data['topline_date'] = ((bool)$value) && $value !== 'no'; - } - public function _topline_link($value) { - $this->data['topline_link'] = ((bool)$value) && $value !== 'no'; - } - public function _bottomline_read($value) { - $this->data['bottomline_read'] = ((bool)$value) && $value !== 'no'; - } - public function _bottomline_favorite($value) { - $this->data['bottomline_favorite'] = ((bool)$value) && $value !== 'no'; - } - public function _bottomline_sharing($value) { - $this->data['bottomline_sharing'] = ((bool)$value) && $value !== 'no'; - } - public function _bottomline_tags($value) { - $this->data['bottomline_tags'] = ((bool)$value) && $value !== 'no'; - } - public function _bottomline_date($value) { - $this->data['bottomline_date'] = ((bool)$value) && $value !== 'no'; - } - public function _bottomline_link($value) { - $this->data['bottomline_link'] = ((bool)$value) && $value !== 'no'; - } -} diff --git a/app/Models/Context.php b/app/Models/Context.php index 9bbad9857..1c770c756 100644 --- a/app/Models/Context.php +++ b/app/Models/Context.php @@ -5,7 +5,8 @@ * useful functions associated to the current view state. */ class FreshRSS_Context { - public static $conf = null; + public static $user_conf = null; + public static $system_conf = null; public static $categories = array(); public static $name = ''; @@ -37,17 +38,12 @@ class FreshRSS_Context { /** * Initialize the context. * - * Set the correct $conf and $categories variables. + * Set the correct configurations and $categories variables. */ public static function init() { // Init configuration. - try { - self::$conf = Minz_Configuration::get('user'); - } catch(Minz_Exception $e) { - $current_user = Minz_Session::param('currentUser', '_'); - Minz_Log::error('Cannot load configuration file of user `' . $current_user . '`'); - die($e->getMessage()); - } + self::$system_conf = Minz_Configuration::get('system'); + self::$user_conf = Minz_Configuration::get('user'); $catDAO = new FreshRSS_CategoryDAO(); self::$categories = $catDAO->listCategories(); @@ -198,7 +194,7 @@ class FreshRSS_Context { // By default, $next_get == $get self::$next_get = $get; - if (self::$conf->onread_jump_next && strlen($get) > 2) { + if (self::$user_conf->onread_jump_next && strlen($get) > 2) { $another_unread_id = ''; $found_current_get = false; switch ($get[0]) { @@ -276,7 +272,7 @@ class FreshRSS_Context { * @return boolean */ public static function isAutoRemoveAvailable() { - if (!self::$conf->auto_remove_article) { + if (!self::$user_conf->auto_remove_article) { return false; } if (self::isStateEnabled(FreshRSS_Entry::STATE_READ)) { @@ -297,7 +293,7 @@ class FreshRSS_Context { * @return boolean */ public static function isStickyPostEnabled() { - if (self::$conf->sticky_post) { + if (self::$user_conf->sticky_post) { return true; } if (self::isAutoRemoveAvailable()) { diff --git a/app/layout/aside_feed.phtml b/app/layout/aside_feed.phtml index a39aea327..a384455b4 100644 --- a/app/layout/aside_feed.phtml +++ b/app/layout/aside_feed.phtml @@ -1,6 +1,6 @@ hide_read_feeds && + if (FreshRSS_Context::$user_conf->hide_read_feeds && FreshRSS_Context::isStateEnabled(FreshRSS_Entry::STATE_NOT_READ) && !FreshRSS_Context::isStateEnabled(FreshRSS_Entry::STATE_READ)) { $class = ' state_unread'; @@ -39,7 +39,7 @@ $feeds = $cat->feeds(); if (!empty($feeds)) { $c_active = FreshRSS_Context::isCurrentGet('c_' . $cat->id()); - $c_show = $c_active && (!FreshRSS_Context::$conf->display_categories || + $c_show = $c_active && (!FreshRSS_Context::$user_conf->display_categories || FreshRSS_Context::$current_get['feed']); ?>
    • @@ -84,7 +84,7 @@
    • - reading_confirm ? 'confirm' : ''; ?> + reading_confirm ? 'confirm' : ''; ?>
    • - queries as $query) { ?> + queries as $query) { ?>
    • - queries) > 0) { ?> + queries) > 0) { ?>
    • @@ -82,7 +82,7 @@ @@ -28,9 +28,9 @@
    @@ -39,9 +39,9 @@
    @@ -49,7 +49,7 @@
    @@ -58,7 +58,7 @@
    @@ -68,7 +68,7 @@
    @@ -78,7 +78,7 @@
    @@ -88,7 +88,7 @@
    @@ -98,7 +98,7 @@
    @@ -108,7 +108,7 @@
    @@ -118,7 +118,7 @@
    @@ -129,19 +129,19 @@
    @@ -151,7 +151,7 @@
    diff --git a/app/views/configure/sharing.phtml b/app/views/configure/sharing.phtml index ffe3c039b..f5c133f07 100644 --- a/app/views/configure/sharing.phtml +++ b/app/views/configure/sharing.phtml @@ -15,8 +15,8 @@
    '> - sharing as $key => $sharing) { ?> - shares[$sharing['type']]; ?> + sharing as $key => $sharing) { ?> + shares[$sharing['type']]; ?>