aboutsummaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/.htaccess14
-rw-r--r--app/Controllers/authController.php14
-rwxr-xr-xapp/Controllers/configureController.php59
-rwxr-xr-xapp/Controllers/entryController.php22
-rw-r--r--app/Controllers/extensionController.php4
-rwxr-xr-xapp/Controllers/feedController.php28
-rw-r--r--app/Controllers/importExportController.php22
-rwxr-xr-xapp/Controllers/indexController.php21
-rwxr-xr-xapp/Controllers/javascriptController.php2
-rw-r--r--app/Controllers/subscriptionController.php67
-rw-r--r--app/Controllers/tagController.php4
-rw-r--r--app/Controllers/updateController.php2
-rw-r--r--app/Controllers/userController.php276
-rw-r--r--app/FreshRSS.php22
-rw-r--r--app/Mailers/UserMailer.php31
-rw-r--r--app/Models/Auth.php7
-rw-r--r--app/Models/Category.php31
-rw-r--r--app/Models/CategoryDAO.php251
-rw-r--r--app/Models/CategoryDAOSQLite.php17
-rw-r--r--app/Models/ConfigurationSetter.php17
-rw-r--r--app/Models/Context.php18
-rw-r--r--app/Models/DatabaseDAO.php250
-rw-r--r--app/Models/DatabaseDAOPGSQL.php49
-rw-r--r--app/Models/DatabaseDAOSQLite.php36
-rw-r--r--app/Models/Entry.php12
-rw-r--r--app/Models/EntryDAO.php467
-rw-r--r--app/Models/EntryDAOPGSQL.php28
-rw-r--r--app/Models/EntryDAOSQLite.php92
-rw-r--r--app/Models/Factory.php12
-rw-r--r--app/Models/Feed.php55
-rw-r--r--app/Models/FeedDAO.php208
-rw-r--r--app/Models/FeedDAOSQLite.php4
-rw-r--r--app/Models/StatsDAO.php47
-rw-r--r--app/Models/StatsDAOPGSQL.php5
-rw-r--r--app/Models/StatsDAOSQLite.php5
-rw-r--r--app/Models/Tag.php2
-rw-r--r--app/Models/TagDAO.php139
-rw-r--r--app/Models/TagDAOSQLite.php2
-rw-r--r--app/Models/UserDAO.php89
-rw-r--r--app/SQL/install.sql.mysql.php104
-rw-r--r--app/SQL/install.sql.pgsql.php101
-rw-r--r--app/SQL/install.sql.sqlite.php87
-rw-r--r--app/i18n/cz/admin.php1
-rw-r--r--app/i18n/cz/conf.php15
-rw-r--r--app/i18n/cz/gen.php11
-rw-r--r--app/i18n/cz/index.php5
-rw-r--r--app/i18n/cz/sub.php6
-rw-r--r--app/i18n/cz/user.php37
-rw-r--r--app/i18n/de/admin.php1
-rw-r--r--app/i18n/de/conf.php15
-rw-r--r--app/i18n/de/gen.php11
-rw-r--r--app/i18n/de/index.php5
-rw-r--r--app/i18n/de/sub.php6
-rw-r--r--app/i18n/de/user.php37
-rw-r--r--app/i18n/en/admin.php1
-rw-r--r--app/i18n/en/conf.php15
-rw-r--r--app/i18n/en/gen.php12
-rw-r--r--app/i18n/en/index.php5
-rw-r--r--app/i18n/en/sub.php6
-rw-r--r--app/i18n/en/user.php37
-rwxr-xr-xapp/i18n/es/admin.php1
-rwxr-xr-xapp/i18n/es/conf.php15
-rwxr-xr-xapp/i18n/es/gen.php11
-rwxr-xr-xapp/i18n/es/index.php5
-rwxr-xr-xapp/i18n/es/sub.php6
-rw-r--r--app/i18n/es/user.php37
-rw-r--r--app/i18n/fr/admin.php1
-rw-r--r--app/i18n/fr/conf.php15
-rw-r--r--app/i18n/fr/gen.php11
-rw-r--r--app/i18n/fr/index.php5
-rw-r--r--app/i18n/fr/sub.php6
-rw-r--r--app/i18n/fr/user.php37
-rw-r--r--app/i18n/he/admin.php1
-rw-r--r--app/i18n/he/conf.php15
-rw-r--r--app/i18n/he/gen.php11
-rw-r--r--app/i18n/he/index.php5
-rw-r--r--app/i18n/he/sub.php6
-rw-r--r--app/i18n/he/user.php37
-rw-r--r--app/i18n/it/admin.php1
-rw-r--r--app/i18n/it/conf.php15
-rw-r--r--app/i18n/it/gen.php11
-rw-r--r--app/i18n/it/index.php5
-rw-r--r--app/i18n/it/sub.php6
-rw-r--r--app/i18n/it/user.php37
-rw-r--r--app/i18n/kr/admin.php1
-rw-r--r--app/i18n/kr/conf.php15
-rw-r--r--app/i18n/kr/gen.php11
-rw-r--r--app/i18n/kr/index.php5
-rw-r--r--app/i18n/kr/sub.php6
-rw-r--r--app/i18n/kr/user.php37
-rw-r--r--app/i18n/nl/admin.php1
-rw-r--r--app/i18n/nl/conf.php19
-rw-r--r--app/i18n/nl/feedback.php2
-rw-r--r--app/i18n/nl/gen.php27
-rw-r--r--app/i18n/nl/index.php15
-rw-r--r--app/i18n/nl/sub.php24
-rw-r--r--app/i18n/nl/user.php37
-rw-r--r--app/i18n/oc/admin.php1
-rw-r--r--app/i18n/oc/conf.php18
-rw-r--r--app/i18n/oc/gen.php13
-rw-r--r--app/i18n/oc/index.php5
-rw-r--r--app/i18n/oc/sub.php6
-rw-r--r--app/i18n/oc/user.php37
-rw-r--r--app/i18n/pt-br/admin.php1
-rw-r--r--app/i18n/pt-br/conf.php15
-rw-r--r--app/i18n/pt-br/gen.php11
-rw-r--r--app/i18n/pt-br/index.php5
-rw-r--r--app/i18n/pt-br/sub.php10
-rw-r--r--app/i18n/pt-br/user.php37
-rw-r--r--app/i18n/ru/admin.php1
-rw-r--r--app/i18n/ru/conf.php17
-rw-r--r--app/i18n/ru/gen.php11
-rw-r--r--app/i18n/ru/index.php5
-rw-r--r--app/i18n/ru/sub.php6
-rw-r--r--app/i18n/ru/user.php37
-rw-r--r--app/i18n/sk/admin.php199
-rw-r--r--app/i18n/sk/conf.php188
-rw-r--r--app/i18n/sk/feedback.php116
-rw-r--r--app/i18n/sk/gen.php181
-rw-r--r--app/i18n/sk/index.php66
-rw-r--r--app/i18n/sk/install.php123
-rw-r--r--app/i18n/sk/sub.php103
-rw-r--r--app/i18n/sk/user.php37
-rw-r--r--app/i18n/tr/admin.php1
-rw-r--r--app/i18n/tr/conf.php15
-rw-r--r--app/i18n/tr/gen.php11
-rw-r--r--app/i18n/tr/index.php5
-rw-r--r--app/i18n/tr/sub.php6
-rw-r--r--app/i18n/tr/user.php37
-rw-r--r--app/i18n/zh-cn/admin.php1
-rw-r--r--app/i18n/zh-cn/conf.php15
-rw-r--r--app/i18n/zh-cn/gen.php11
-rw-r--r--app/i18n/zh-cn/index.php5
-rw-r--r--app/i18n/zh-cn/sub.php6
-rw-r--r--app/i18n/zh-cn/user.php37
-rw-r--r--app/install.php538
-rw-r--r--app/layout/aside_configure.phtml51
-rw-r--r--app/layout/aside_feed.phtml69
-rw-r--r--app/layout/aside_stats.phtml14
-rw-r--r--app/layout/aside_subscription.phtml14
-rw-r--r--app/layout/header.phtml72
-rw-r--r--app/layout/layout.phtml28
-rw-r--r--app/layout/nav_entries.phtml6
-rw-r--r--app/layout/nav_menu.phtml80
-rw-r--r--app/layout/simple.phtml69
-rw-r--r--app/shares.php12
-rw-r--r--app/views/auth/formLogin.phtml22
-rw-r--r--app/views/auth/index.phtml40
-rw-r--r--app/views/auth/register.phtml42
-rw-r--r--app/views/configure/archiving.phtml140
-rw-r--r--app/views/configure/display.phtml103
-rw-r--r--app/views/configure/queries.phtml60
-rw-r--r--app/views/configure/reading.phtml126
-rw-r--r--app/views/configure/sharing.phtml50
-rw-r--r--app/views/configure/shortcut.phtml114
-rw-r--r--app/views/configure/system.phtml60
-rw-r--r--app/views/error/index.phtml6
-rw-r--r--app/views/extension/index.phtml38
-rw-r--r--app/views/feed/add.phtml58
-rw-r--r--app/views/helpers/category/update.phtml154
-rw-r--r--app/views/helpers/export/articles.phtml5
-rw-r--r--app/views/helpers/extension/configure.phtml8
-rw-r--r--app/views/helpers/extension/details.phtml12
-rw-r--r--app/views/helpers/feed/update.phtml267
-rw-r--r--app/views/helpers/index/normal/entry_bottom.phtml38
-rw-r--r--app/views/helpers/index/normal/entry_header.phtml26
-rwxr-xr-xapp/views/helpers/logs_pagination.phtml12
-rwxr-xr-xapp/views/helpers/pagination.phtml16
-rw-r--r--app/views/importExport/index.phtml36
-rw-r--r--app/views/index/about.phtml26
-rw-r--r--app/views/index/global.phtml16
-rw-r--r--app/views/index/logs.phtml14
-rw-r--r--app/views/index/normal.phtml24
-rw-r--r--app/views/index/reader.phtml28
-rwxr-xr-xapp/views/index/rss.phtml24
-rw-r--r--app/views/index/tos.phtml13
-rw-r--r--app/views/stats/idle.phtml18
-rw-r--r--app/views/stats/index.phtml60
-rw-r--r--app/views/stats/repartition.phtml34
-rw-r--r--app/views/subscription/bookmarklet.phtml23
-rw-r--r--app/views/subscription/feed.phtml4
-rw-r--r--app/views/subscription/index.phtml70
-rw-r--r--app/views/update/apply.phtml4
-rw-r--r--app/views/update/checkInstall.phtml20
-rw-r--r--app/views/update/index.phtml18
-rw-r--r--app/views/user/manage.phtml75
-rw-r--r--app/views/user/profile.phtml90
-rw-r--r--app/views/user/validateEmail.phtml22
-rw-r--r--app/views/user_mailer/email_need_validation.txt5
189 files changed, 5407 insertions, 2415 deletions
diff --git a/app/.htaccess b/app/.htaccess
index 9e768397d..32eca30f7 100644
--- a/app/.htaccess
+++ b/app/.htaccess
@@ -1,3 +1,11 @@
-Order Allow,Deny
-Deny from all
-Satisfy all
+# Apache 2.2
+<IfModule !mod_authz_core.c>
+ Order Allow,Deny
+ Deny from all
+ Satisfy all
+</IfModule>
+
+# Apache 2.4
+<IfModule mod_authz_core.c>
+ Require all denied
+</IfModule>
diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php
index ca44b1a96..e2e1aaa22 100644
--- a/app/Controllers/authController.php
+++ b/app/Controllers/authController.php
@@ -169,10 +169,6 @@ class FreshRSS_auth_Controller extends Minz_ActionController {
return;
}
- if (!function_exists('password_verify')) {
- include_once(LIB_PATH . '/password_compat.php');
- }
-
$s = $conf->passwordHash;
$ok = password_verify($password, $s);
unset($password);
@@ -203,12 +199,22 @@ class FreshRSS_auth_Controller extends Minz_ActionController {
/**
* This action gives possibility to a user to create an account.
+ *
+ * The user is redirected to the home if he's connected.
+ *
+ * A 403 is sent if max number of registrations is reached.
*/
public function registerAction() {
+ if (FreshRSS_Auth::hasAccess()) {
+ Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true);
+ }
+
if (max_registrations_reached()) {
Minz_Error::error(403);
}
+ $this->view->show_tos_checkbox = file_exists(join_path(DATA_PATH, 'tos.html'));
+ $this->view->show_email_field = FreshRSS_Context::$system_conf->force_email_validation;
Minz_View::prependTitle(_t('gen.auth.registration.title') . ' · ');
}
}
diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php
index 6d3c4dcce..b38d3289a 100755
--- a/app/Controllers/configureController.php
+++ b/app/Controllers/configureController.php
@@ -48,6 +48,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
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->topline_display_authors = Minz_Request::param('topline_display_authors', 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);
@@ -166,8 +167,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
* tab and up.
*/
public function shortcutAction() {
- global $SHORTCUT_KEYS;
- $this->view->list_keys = $SHORTCUT_KEYS;
+ $this->view->list_keys = SHORTCUT_KEYS;
if (Minz_Request::isPost()) {
FreshRSS_Context::$user_conf->shortcuts = validateShortcutList(Minz_Request::param('shortcuts'));
@@ -196,9 +196,31 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
*/
public function archivingAction() {
if (Minz_Request::isPost()) {
- 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);
+ if (!Minz_Request::paramBoolean('enable_keep_max')) {
+ $keepMax = false;
+ } elseif (!$keepMax = Minz_Request::param('keep_max')) {
+ $keepMax = FreshRSS_Feed::ARCHIVING_RETENTION_COUNT_LIMIT;
+ }
+ if ($enableRetentionPeriod = Minz_Request::paramBoolean('enable_keep_period')) {
+ $keepPeriod = FreshRSS_Feed::ARCHIVING_RETENTION_PERIOD;
+ if (is_numeric(Minz_Request::param('keep_period_count')) && preg_match('/^PT?1[YMWDH]$/', Minz_Request::param('keep_period_unit'))) {
+ $keepPeriod = str_replace('1', Minz_Request::param('keep_period_count'), Minz_Request::param('keep_period_unit'));
+ }
+ } else {
+ $keepPeriod = false;
+ }
+
FreshRSS_Context::$user_conf->ttl_default = Minz_Request::param('ttl_default', FreshRSS_Feed::TTL_DEFAULT);
+ FreshRSS_Context::$user_conf->archiving = [
+ 'keep_period' => $keepPeriod,
+ 'keep_max' => $keepMax,
+ 'keep_min' => Minz_Request::param('keep_min_default', 0),
+ 'keep_favourites' => Minz_Request::paramBoolean('keep_favourites'),
+ 'keep_labels' => Minz_Request::paramBoolean('keep_labels'),
+ 'keep_unreads' => Minz_Request::paramBoolean('keep_unreads'),
+ ];
+ FreshRSS_Context::$user_conf->keep_history_default = null; //Legacy < FreshRSS 1.15
+ FreshRSS_Context::$user_conf->old_entries = null; //Legacy < FreshRSS 1.15
FreshRSS_Context::$user_conf->save();
invalidateHttpCache();
@@ -206,7 +228,20 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
array('c' => 'configure', 'a' => 'archiving'));
}
- Minz_View::prependTitle(_t('conf.archiving.title') . ' · ');
+ $volatile = [
+ 'enable_keep_period' => false,
+ 'keep_period_count' => '3',
+ 'keep_period_unit' => 'P1M',
+ ];
+ $keepPeriod = FreshRSS_Context::$user_conf->archiving['keep_period'];
+ if (preg_match('/^PT?(?P<count>\d+)[YMWDH]$/', $keepPeriod, $matches)) {
+ $volatile = [
+ 'enable_keep_period' => true,
+ 'keep_period_count' => $matches['count'],
+ 'keep_period_unit' => str_replace($matches['count'], 1, $keepPeriod),
+ ];
+ }
+ FreshRSS_Context::$user_conf->volatile = $volatile;
$entryDAO = FreshRSS_Factory::createEntryDao();
$this->view->nb_total = $entryDAO->count();
@@ -217,6 +252,8 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
if (FreshRSS_Auth::hasAccess('admin')) {
$this->view->size_total = $databaseDAO->size(true);
}
+
+ Minz_View::prependTitle(_t('conf.archiving.title') . ' · ');
}
/**
@@ -292,15 +329,24 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
* configuration values then sends a notification to the user.
*
* The options available on the page are:
+ * - instance name (default: FreshRSS)
+ * - auto update URL (default: false)
+ * - force emails validation (default: false)
* - user limit (default: 1)
* - user category limit (default: 16384)
* - user feed limit (default: 16384)
* - user login duration for form auth (default: 2592000)
+ *
+ * The `force-email-validation` is ignored with PHP < 5.5
*/
public function systemAction() {
if (!FreshRSS_Auth::hasAccess('admin')) {
Minz_Error::error(403);
}
+
+ $can_enable_email_validation = version_compare(PHP_VERSION, '5.5') >= 0;
+ $this->view->can_enable_email_validation = $can_enable_email_validation;
+
if (Minz_Request::isPost()) {
$limits = FreshRSS_Context::$system_conf->limits;
$limits['max_registrations'] = Minz_Request::param('max-registrations', 1);
@@ -310,6 +356,9 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
FreshRSS_Context::$system_conf->limits = $limits;
FreshRSS_Context::$system_conf->title = Minz_Request::param('instance-name', 'FreshRSS');
FreshRSS_Context::$system_conf->auto_update_url = Minz_Request::param('auto-update-url', false);
+ if ($can_enable_email_validation) {
+ FreshRSS_Context::$system_conf->force_email_validation = Minz_Request::param('force-email-validation', false);
+ }
FreshRSS_Context::$system_conf->save();
invalidateHttpCache();
diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php
index 9c5ee2616..7881cb3ec 100755
--- a/app/Controllers/entryController.php
+++ b/app/Controllers/entryController.php
@@ -17,7 +17,7 @@ class FreshRSS_entry_Controller extends Minz_ActionController {
// If ajax request, we do not print layout
$this->ajax = Minz_Request::param('ajax');
if ($this->ajax) {
- $this->view->_useLayout(false);
+ $this->view->_layout(false);
Minz_Request::_param('ajax');
}
}
@@ -181,32 +181,20 @@ class FreshRSS_entry_Controller extends Minz_ActionController {
public function purgeAction() {
@set_time_limit(300);
- $nb_month_old = max(FreshRSS_Context::$user_conf->old_entries, 1);
- $date_min = time() - (3600 * 24 * 30 * $nb_month_old);
-
- $entryDAO = FreshRSS_Factory::createEntryDao();
$feedDAO = FreshRSS_Factory::createFeedDao();
$feeds = $feedDAO->listFeeds();
$nb_total = 0;
invalidateHttpCache();
- foreach ($feeds as $feed) {
- $feed_history = $feed->keepHistory();
- if (FreshRSS_Feed::KEEP_HISTORY_DEFAULT === $feed_history) {
- $feed_history = FreshRSS_Context::$user_conf->keep_history_default;
- }
+ $feedDAO->beginTransaction();
- if ($feed_history >= 0) {
- $nb = $entryDAO->cleanOldEntries($feed->id(), $date_min, $feed_history);
- if ($nb > 0) {
- $nb_total += $nb;
- Minz_Log::debug($nb . ' old entries cleaned in feed [' . $feed->url(false) . ']');
- }
- }
+ foreach ($feeds as $feed) {
+ $nb_total += $feed->cleanOldEntries();
}
$feedDAO->updateCachedValues();
+ $feedDAO->commit();
$databaseDAO = FreshRSS_Factory::createDatabaseDAO();
$databaseDAO->minorDbMaintenance();
diff --git a/app/Controllers/extensionController.php b/app/Controllers/extensionController.php
index 806e5a696..68bd90f4c 100644
--- a/app/Controllers/extensionController.php
+++ b/app/Controllers/extensionController.php
@@ -80,10 +80,10 @@ class FreshRSS_extension_Controller extends Minz_ActionController {
*/
public function configureAction() {
if (Minz_Request::param('ajax')) {
- $this->view->_useLayout(false);
+ $this->view->_layout(false);
} else {
$this->indexAction();
- $this->view->change_view('extension', 'index');
+ $this->view->_path('extension/index.phtml');
}
$ext_name = urldecode(Minz_Request::param('e'));
diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php
index 862bb10fb..aabeb80ff 100755
--- a/app/Controllers/feedController.php
+++ b/app/Controllers/feedController.php
@@ -267,10 +267,6 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
$maxFeeds = 10;
}
- // Calculate date of oldest entries we accept in DB.
- $nb_month_old = max(FreshRSS_Context::$user_conf->old_entries, 1);
- $date_min = time() - (3600 * 24 * 30 * $nb_month_old);
-
// WebSub (PubSubHubbub) support
$pubsubhubbubEnabledGeneral = FreshRSS_Context::$system_conf->pubsubhubbub_enabled;
$pshbMinAge = time() - (3600 * 24); //TODO: Make a configuration.
@@ -323,12 +319,6 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
continue;
}
- $feed_history = $feed->keepHistory();
- if ($isNewFeed) {
- $feed_history = FreshRSS_Feed::KEEP_HISTORY_INFINITE;
- } elseif (FreshRSS_Feed::KEEP_HISTORY_DEFAULT === $feed_history) {
- $feed_history = FreshRSS_Context::$user_conf->keep_history_default;
- }
$needFeedCacheRefresh = false;
// We want chronological order and SimplePie uses reverse order.
@@ -376,15 +366,9 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
}
$entryDAO->updateEntry($entry->toArray());
}
- } elseif ($feed_history == 0 && $entry_date < $date_min) {
- // This entry should not be added considering configuration and date.
- $oldGuids[] = $entry->guid();
} else {
$id = uTimeString();
$entry->_id($id);
- if ($entry_date < $date_min) {
- $entry->_isRead(true); //Old article that was not in database. Probably an error, so mark as read
- }
$entry->applyFilterActions();
@@ -413,23 +397,19 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
$entryDAO->updateLastSeen($feed->id(), $oldGuids, $mtime);
}
- if ($feed_history >= 0 && mt_rand(0, 30) === 1) {
- // TODO: move this function in web cron when available (see entry::purge)
- // Remove old entries once in 30.
+ if (mt_rand(0, 30) === 1) { // Remove old entries once in 30.
if (!$entryDAO->inTransaction()) {
$entryDAO->beginTransaction();
}
-
- $nb = $entryDAO->cleanOldEntries($feed->id(), $date_min, max($feed_history, count($entries) + 10));
+ $nb = $feed->cleanOldEntries();
if ($nb > 0) {
$needFeedCacheRefresh = true;
- Minz_Log::debug($nb . ' old entries cleaned in feed [' . $feed->url(false) . ']');
}
}
$feedDAO->updateLastUpdate($feed->id(), false, $mtime);
if ($needFeedCacheRefresh) {
- $feedDAO->updateCachedValue($feed->id());
+ $feedDAO->updateCachedValues($feed->id());
}
if ($entryDAO->inTransaction()) {
$entryDAO->commit();
@@ -530,7 +510,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
);
Minz_Session::_param('notification', $notif);
// No layout in ajax request.
- $this->view->_useLayout(false);
+ $this->view->_layout(false);
} else {
// Redirect to the main page with correct notification.
if ($updated_feeds === 1) {
diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php
index 1d7176929..f2ae8238e 100644
--- a/app/Controllers/importExportController.php
+++ b/app/Controllers/importExportController.php
@@ -29,7 +29,25 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
Minz_View::prependTitle(_t('sub.import_export.title') . ' · ');
}
+ private static function megabytes($size_str) {
+ switch (substr($size_str, -1)) {
+ case 'M': case 'm': return (int)$size_str;
+ case 'K': case 'k': return (int)$size_str / 1024;
+ case 'G': case 'g': return (int)$size_str * 1024;
+ }
+ return $size_str;
+ }
+
+ private static function minimumMemory($mb) {
+ $mb = (int)$mb;
+ $ini = self::megabytes(ini_get('memory_limit'));
+ if ($ini < $mb) {
+ ini_set('memory_limit', $mb . 'M');
+ }
+ }
+
public function importFile($name, $path, $username = null) {
+ self::minimumMemory(256);
require_once(LIB_PATH . '/lib_opml.php');
$this->catDAO = new FreshRSS_CategoryDAO($username);
@@ -709,8 +727,6 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
$this->entryDAO = FreshRSS_Factory::createEntryDao($username);
$this->feedDAO = FreshRSS_Factory::createFeedDao($username);
- $this->entryDAO->disableBuffering();
-
if ($export_feeds === true) {
//All feeds
$export_feeds = $this->feedDAO->listFeedsIds();
@@ -773,7 +789,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
if (!Minz_Request::isPost()) {
Minz_Request::forward(array('c' => 'importExport', 'a' => 'index'), true);
}
- $this->view->_useLayout(false);
+ $this->view->_layout(false);
$nb_files = 0;
try {
diff --git a/app/Controllers/indexController.php b/app/Controllers/indexController.php
index f536113dd..967029fd1 100755
--- a/app/Controllers/indexController.php
+++ b/app/Controllers/indexController.php
@@ -155,7 +155,7 @@ class FreshRSS_index_Controller extends Minz_ActionController {
// No layout for RSS output.
$this->view->url = PUBLIC_TO_INDEX_PATH . '/' . (empty($_SERVER['QUERY_STRING']) ? '' : '?' . $_SERVER['QUERY_STRING']);
$this->view->rss_title = FreshRSS_Context::$name . ' | ' . Minz_View::title();
- $this->view->_useLayout(false);
+ $this->view->_layout(false);
header('Content-Type: application/rss+xml; charset=utf-8');
}
@@ -173,7 +173,7 @@ class FreshRSS_index_Controller extends Minz_ActionController {
private function updateContext() {
if (empty(FreshRSS_Context::$categories)) {
$catDAO = FreshRSS_Factory::createCategoryDao();
- FreshRSS_Context::$categories = $catDAO->listCategories();
+ FreshRSS_Context::$categories = $catDAO->listSortedCategories();
}
// Update number of read / unread variables.
@@ -260,6 +260,23 @@ class FreshRSS_index_Controller extends Minz_ActionController {
}
/**
+ * This action displays the EULA page of FreshRSS.
+ * This page is enabled only if admin created a data/tos.html file.
+ * The content of the page is the content of data/tos.html.
+ * It returns 404 if there is no EULA.
+ */
+ public function tosAction() {
+ $terms_of_service = file_get_contents(join_path(DATA_PATH, 'tos.html'));
+ if (!$terms_of_service) {
+ Minz_Error::error(404);
+ }
+
+ $this->view->terms_of_service = $terms_of_service;
+ $this->view->can_register = !max_registrations_reached();
+ Minz_View::prependTitle(_t('index.tos.title') . ' · ');
+ }
+
+ /**
* This action displays logs of FreshRSS for the current user.
*/
public function logsAction() {
diff --git a/app/Controllers/javascriptController.php b/app/Controllers/javascriptController.php
index d56da9cbb..c84e5483b 100755
--- a/app/Controllers/javascriptController.php
+++ b/app/Controllers/javascriptController.php
@@ -2,7 +2,7 @@
class FreshRSS_javascript_Controller extends Minz_ActionController {
public function firstAction() {
- $this->view->_useLayout(false);
+ $this->view->_layout(false);
}
public function actualizeAction() {
diff --git a/app/Controllers/subscriptionController.php b/app/Controllers/subscriptionController.php
index 79da39751..b4520c8e6 100644
--- a/app/Controllers/subscriptionController.php
+++ b/app/Controllers/subscriptionController.php
@@ -19,7 +19,7 @@ class FreshRSS_subscription_Controller extends Minz_ActionController {
$catDAO->checkDefault();
$feedDAO->updateTTL();
- $this->view->categories = $catDAO->listCategories(false);
+ $this->view->categories = $catDAO->listSortedCategories(false);
$this->view->default_category = $catDAO->getDefault();
}
@@ -74,7 +74,7 @@ class FreshRSS_subscription_Controller extends Minz_ActionController {
*/
public function feedAction() {
if (Minz_Request::param('ajax')) {
- $this->view->_useLayout(false);
+ $this->view->_layout(false);
}
$feedDAO = FreshRSS_Factory::createFeedDao();
@@ -121,6 +121,32 @@ class FreshRSS_subscription_Controller extends Minz_ActionController {
$feed->_attributes('timeout', null);
}
+ if (Minz_Request::paramBoolean('use_default_purge_options')) {
+ $feed->_attributes('archiving', null);
+ } else {
+ if (!Minz_Request::paramBoolean('enable_keep_max')) {
+ $keepMax = false;
+ } elseif (!$keepMax = Minz_Request::param('keep_max')) {
+ $keepMax = FreshRSS_Feed::ARCHIVING_RETENTION_COUNT_LIMIT;
+ }
+ if ($enableRetentionPeriod = Minz_Request::paramBoolean('enable_keep_period')) {
+ $keepPeriod = FreshRSS_Feed::ARCHIVING_RETENTION_PERIOD;
+ if (is_numeric(Minz_Request::param('keep_period_count')) && preg_match('/^PT?1[YMWDH]$/', Minz_Request::param('keep_period_unit'))) {
+ $keepPeriod = str_replace(1, Minz_Request::param('keep_period_count'), Minz_Request::param('keep_period_unit'));
+ }
+ } else {
+ $keepPeriod = false;
+ }
+ $feed->_attributes('archiving', [
+ 'keep_period' => $keepPeriod,
+ 'keep_max' => $keepMax,
+ 'keep_min' => intval(Minz_Request::param('keep_min', 0)),
+ 'keep_favourites' => Minz_Request::paramBoolean('keep_favourites'),
+ 'keep_labels' => Minz_Request::paramBoolean('keep_labels'),
+ 'keep_unreads' => Minz_Request::paramBoolean('keep_unreads'),
+ ]);
+ }
+
$feed->_filtersAction('read', preg_split('/[\n\r]+/', Minz_Request::param('filteractions_read', '')));
$values = array(
@@ -132,7 +158,6 @@ class FreshRSS_subscription_Controller extends Minz_ActionController {
'pathEntries' => Minz_Request::param('path_entries', ''),
'priority' => intval(Minz_Request::param('priority', FreshRSS_Feed::PRIORITY_MAIN_STREAM)),
'httpAuth' => $httpAuth,
- 'keep_history' => intval(Minz_Request::param('keep_history', FreshRSS_Feed::KEEP_HISTORY_DEFAULT)),
'ttl' => $ttl * ($mute ? -1 : 1),
'attributes' => $feed->attributes(),
);
@@ -152,7 +177,7 @@ class FreshRSS_subscription_Controller extends Minz_ActionController {
}
public function categoryAction() {
- $this->view->_useLayout(false);
+ $this->view->_layout(false);
$categoryDAO = FreshRSS_Factory::createCategoryDao();
@@ -165,9 +190,39 @@ class FreshRSS_subscription_Controller extends Minz_ActionController {
$this->view->category = $category;
if (Minz_Request::isPost()) {
- $values = array(
+ if (Minz_Request::paramBoolean('use_default_purge_options')) {
+ $category->_attributes('archiving', null);
+ } else {
+ if (!Minz_Request::paramBoolean('enable_keep_max')) {
+ $keepMax = false;
+ } elseif (!$keepMax = Minz_Request::param('keep_max')) {
+ $keepMax = FreshRSS_Feed::ARCHIVING_RETENTION_COUNT_LIMIT;
+ }
+ if ($enableRetentionPeriod = Minz_Request::paramBoolean('enable_keep_period')) {
+ $keepPeriod = FreshRSS_Feed::ARCHIVING_RETENTION_PERIOD;
+ if (is_numeric(Minz_Request::param('keep_period_count')) && preg_match('/^PT?1[YMWDH]$/', Minz_Request::param('keep_period_unit'))) {
+ $keepPeriod = str_replace(1, Minz_Request::param('keep_period_count'), Minz_Request::param('keep_period_unit'));
+ }
+ } else {
+ $keepPeriod = false;
+ }
+ $category->_attributes('archiving', [
+ 'keep_period' => $keepPeriod,
+ 'keep_max' => $keepMax,
+ 'keep_min' => intval(Minz_Request::param('keep_min', 0)),
+ 'keep_favourites' => Minz_Request::paramBoolean('keep_favourites'),
+ 'keep_labels' => Minz_Request::paramBoolean('keep_labels'),
+ 'keep_unreads' => Minz_Request::paramBoolean('keep_unreads'),
+ ]);
+ }
+
+ $position = Minz_Request::param('position');
+ $category->_attributes('position', '' === $position ? null : (int) $position);
+
+ $values = [
'name' => Minz_Request::param('name', ''),
- );
+ 'attributes' => $category->attributes(),
+ ];
invalidateHttpCache();
diff --git a/app/Controllers/tagController.php b/app/Controllers/tagController.php
index 106e0afa8..ba9efe2fc 100644
--- a/app/Controllers/tagController.php
+++ b/app/Controllers/tagController.php
@@ -16,7 +16,7 @@ class FreshRSS_tag_Controller extends Minz_ActionController {
// If ajax request, we do not print layout
$this->ajax = Minz_Request::param('ajax');
if ($this->ajax) {
- $this->view->_useLayout(false);
+ $this->view->_layout(false);
Minz_Request::_param('ajax');
}
}
@@ -70,7 +70,7 @@ class FreshRSS_tag_Controller extends Minz_ActionController {
}
public function getTagsForEntryAction() {
- $this->view->_useLayout(false);
+ $this->view->_layout(false);
header('Content-Type: application/json; charset=UTF-8');
header('Cache-Control: private, no-cache, no-store, must-revalidate');
$id_entry = Minz_Request::param('id_entry', 0);
diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php
index 2be644c85..ebe5e4cc8 100644
--- a/app/Controllers/updateController.php
+++ b/app/Controllers/updateController.php
@@ -89,7 +89,7 @@ class FreshRSS_update_Controller extends Minz_ActionController {
}
public function checkAction() {
- $this->view->change_view('update', 'index');
+ $this->view->_path('update/index.phtml');
if (file_exists(UPDATE_FILENAME)) {
// There is already an update file to apply: we don't need to check
diff --git a/app/Controllers/userController.php b/app/Controllers/userController.php
index 6d0fced5b..6afc91b4e 100644
--- a/app/Controllers/userController.php
+++ b/app/Controllers/userController.php
@@ -8,26 +8,7 @@ class FreshRSS_user_Controller extends Minz_ActionController {
// so do not use a too high cost
const BCRYPT_COST = 9;
- /**
- * 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 clean up the access condition.
- */
- public function firstAction() {
- if (!FreshRSS_Auth::hasAccess() && !(
- Minz_Request::actionName() === 'create' &&
- !max_registrations_reached()
- )) {
- Minz_Error::error(403);
- }
- }
-
public static function hashPassword($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
@@ -52,12 +33,23 @@ class FreshRSS_user_Controller extends Minz_ActionController {
return false;
}
- public static function updateUser($user, $passwordPlain, $apiPasswordPlain, $userConfigUpdated = array()) {
+ public static function updateUser($user, $email, $passwordPlain, $apiPasswordPlain, $userConfigUpdated = array()) {
$userConfig = get_user_configuration($user);
if ($userConfig === null) {
return false;
}
+ if ($email !== null && $userConfig->mail_login !== $email) {
+ $userConfig->mail_login = $email;
+
+ if (FreshRSS_Context::$system_conf->force_email_validation) {
+ $salt = FreshRSS_Context::$system_conf->salt;
+ $userConfig->email_validation_token = sha1($salt . uniqid(mt_rand(), true));
+ $mailer = new FreshRSS_User_Mailer();
+ $mailer->send_email_need_validation($user, $userConfig);
+ }
+ }
+
if ($passwordPlain != '') {
$passwordHash = self::hashPassword($passwordPlain);
$userConfig->passwordHash = $passwordHash;
@@ -103,7 +95,7 @@ class FreshRSS_user_Controller extends Minz_ActionController {
$apiPasswordPlain = Minz_Request::param('apiPasswordPlain', '', true);
$username = Minz_Request::param('username');
- $ok = self::updateUser($username, $passwordPlain, $apiPasswordPlain, array(
+ $ok = self::updateUser($username, null, $passwordPlain, $apiPasswordPlain, array(
'token' => Minz_Request::param('token', null),
));
@@ -126,25 +118,63 @@ class FreshRSS_user_Controller extends Minz_ActionController {
* This action displays the user profile page.
*/
public function profileAction() {
+ if (!FreshRSS_Auth::hasAccess()) {
+ Minz_Error::error(403);
+ }
+
+ $email_not_verified = FreshRSS_Context::$user_conf->email_validation_token !== '';
+ $this->view->disable_aside = false;
+ if ($email_not_verified) {
+ $this->view->_layout('simple');
+ $this->view->disable_aside = true;
+ }
+
Minz_View::prependTitle(_t('conf.profile.title') . ' · ');
Minz_View::appendScript(Minz_Url::display('/scripts/bcrypt.min.js?' . @filemtime(PUBLIC_PATH . '/scripts/bcrypt.min.js')));
if (Minz_Request::isPost()) {
+ $system_conf = FreshRSS_Context::$system_conf;
+ $user_config = FreshRSS_Context::$user_conf;
+ $old_email = $user_config->mail_login;
+
+ $email = trim(Minz_Request::param('email', ''));
$passwordPlain = Minz_Request::param('newPasswordPlain', '', true);
Minz_Request::_param('newPasswordPlain'); //Discard plain-text password ASAP
$_POST['newPasswordPlain'] = '';
$apiPasswordPlain = Minz_Request::param('apiPasswordPlain', '', true);
- $ok = self::updateUser(Minz_Session::param('currentUser'), $passwordPlain, $apiPasswordPlain, array(
+ if ($system_conf->force_email_validation && empty($email)) {
+ Minz_Request::bad(
+ _t('user.email.feedback.required'),
+ array('c' => 'user', 'a' => 'profile')
+ );
+ }
+
+ if (!empty($email) && !validateEmailAddress($email)) {
+ Minz_Request::bad(
+ _t('user.email.feedback.invalid'),
+ array('c' => 'user', 'a' => 'profile')
+ );
+ }
+
+ $ok = self::updateUser(
+ Minz_Session::param('currentUser'),
+ $email,
+ $passwordPlain,
+ $apiPasswordPlain,
+ array(
'token' => Minz_Request::param('token', null),
- ));
+ )
+ );
Minz_Session::_param('passwordHash', FreshRSS_Context::$user_conf->passwordHash);
if ($ok) {
- if ($passwordPlain == '') {
+ if ($system_conf->force_email_validation && $email !== $old_email) {
+ Minz_Request::good(_t('feedback.profile.updated'), array('c' => 'user', 'a' => 'validateEmail'));
+ } elseif ($passwordPlain == '') {
Minz_Request::good(_t('feedback.profile.updated'), array('c' => 'user', 'a' => 'profile'));
} else {
Minz_Request::good(_t('feedback.profile.updated'), array('c' => 'index', 'a' => 'index'));
@@ -166,6 +196,7 @@ class FreshRSS_user_Controller extends Minz_ActionController {
Minz_View::prependTitle(_t('admin.user.title') . ' · ');
+ $this->view->show_email_field = FreshRSS_Context::$system_conf->force_email_validation;
$this->view->current_user = Minz_Request::param('u');
$this->view->nb_articles = 0;
@@ -180,9 +211,19 @@ class FreshRSS_user_Controller extends Minz_ActionController {
}
}
- public static function createUser($new_user_name, $passwordPlain, $apiPasswordPlain, $userConfig = array(), $insertDefaultFeeds = true) {
- if (!is_array($userConfig)) {
- $userConfig = array();
+ public static function createUser($new_user_name, $email, $passwordPlain, $apiPasswordPlain = '', $userConfigOverride = [], $insertDefaultFeeds = true) {
+ $userConfig = [];
+
+ $customUserConfigPath = join_path(DATA_PATH, 'config-user.custom.php');
+ if (file_exists($customUserConfigPath)) {
+ $customUserConfig = include($customUserConfigPath);
+ if (is_array($customUserConfig)) {
+ $userConfig = $customUserConfig;
+ }
+ }
+
+ if (is_array($userConfigOverride)) {
+ $userConfig = array_merge($userConfig, $userConfigOverride);
}
$ok = self::checkUsername($new_user_name);
@@ -206,9 +247,9 @@ class FreshRSS_user_Controller extends Minz_ActionController {
$ok &= (file_put_contents($configPath, "<?php\n return " . var_export($userConfig, true) . ';') !== false);
}
if ($ok) {
- $userDAO = new FreshRSS_UserDAO();
- $ok &= $userDAO->createUser($new_user_name, $userConfig['language'], $insertDefaultFeeds);
- $ok &= self::updateUser($new_user_name, $passwordPlain, $apiPasswordPlain);
+ $newUserDAO = FreshRSS_Factory::createUserDao($new_user_name);
+ $ok &= $newUserDAO->createUser($insertDefaultFeeds);
+ $ok &= self::updateUser($new_user_name, $email, $passwordPlain, $apiPasswordPlain);
}
return $ok;
}
@@ -219,6 +260,7 @@ class FreshRSS_user_Controller extends Minz_ActionController {
* Request parameters are:
* - new_user_language
* - new_user_name
+ * - new_user_email
* - new_user_passwordPlain
* - r (i.e. a redirection url, optional)
*
@@ -226,15 +268,43 @@ class FreshRSS_user_Controller extends Minz_ActionController {
* @todo handle r redirection in Minz_Request::forward directly?
*/
public function createAction() {
- if (Minz_Request::isPost() && (
- FreshRSS_Auth::hasAccess('admin') ||
- !max_registrations_reached()
- )) {
+ if (!FreshRSS_Auth::hasAccess('admin') && max_registrations_reached()) {
+ Minz_Error::error(403);
+ }
+
+ if (Minz_Request::isPost()) {
+ $system_conf = FreshRSS_Context::$system_conf;
+
$new_user_name = Minz_Request::param('new_user_name');
+ $email = Minz_Request::param('new_user_email', '');
$passwordPlain = Minz_Request::param('new_user_passwordPlain', '', true);
$new_user_language = Minz_Request::param('new_user_language', FreshRSS_Context::$user_conf->language);
- $ok = self::createUser($new_user_name, $passwordPlain, '', array('language' => $new_user_language));
+ $tos_enabled = file_exists(join_path(DATA_PATH, 'tos.html'));
+ $accept_tos = Minz_Request::param('accept_tos', false);
+
+ if ($system_conf->force_email_validation && empty($email)) {
+ Minz_Request::bad(
+ _t('user.email.feedback.required'),
+ array('c' => 'auth', 'a' => 'register')
+ );
+ }
+
+ if (!empty($email) && !validateEmailAddress($email)) {
+ Minz_Request::bad(
+ _t('user.email.feedback.invalid'),
+ array('c' => 'auth', 'a' => 'register')
+ );
+ }
+
+ if ($tos_enabled && !$accept_tos) {
+ Minz_Request::bad(
+ _t('user.tos.feedback.invalid'),
+ array('c' => 'auth', 'a' => 'register')
+ );
+ }
+
+ $ok = self::createUser($new_user_name, $email, $passwordPlain, '', array('language' => $new_user_language));
Minz_Request::_param('new_user_passwordPlain'); //Discard plain-text password ASAP
$_POST['new_user_passwordPlain'] = '';
invalidateHttpCache();
@@ -266,9 +336,6 @@ class FreshRSS_user_Controller extends Minz_ActionController {
}
public static function deleteUser($username) {
- $db = FreshRSS_Context::$system_conf->db;
- require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php');
-
$ok = self::checkUsername($username);
if ($ok) {
$default_user = FreshRSS_Context::$system_conf->default_user;
@@ -278,8 +345,8 @@ class FreshRSS_user_Controller extends Minz_ActionController {
$ok &= is_dir($user_data);
if ($ok) {
self::deleteFeverKey($username);
- $userDAO = new FreshRSS_UserDAO();
- $ok &= $userDAO->deleteUser($username);
+ $oldUserDAO = FreshRSS_Factory::createUserDao($username);
+ $ok &= $oldUserDAO->deleteUser();
$ok &= recursive_unlink($user_data);
array_map('unlink', glob(PSHB_PATH . '/feeds/*/' . $username . '.txt'));
}
@@ -287,6 +354,122 @@ class FreshRSS_user_Controller extends Minz_ActionController {
}
/**
+ * This action validates an email address, based on the token sent by email.
+ * It also serves the main page when user is blocked.
+ *
+ * Request parameters are:
+ * - username
+ * - token
+ *
+ * This route works with GET requests since the URL is provided by email.
+ * The security risks (e.g. forged URL by an attacker) are not very high so
+ * it's ok.
+ *
+ * It returns 404 error if `force_email_validation` is disabled or if the
+ * user doesn't exist.
+ *
+ * It returns 403 if user isn't logged in and `username` param isn't passed.
+ */
+ public function validateEmailAction() {
+ if (!FreshRSS_Context::$system_conf->force_email_validation) {
+ Minz_Error::error(404);
+ }
+
+ Minz_View::prependTitle(_t('user.email.validation.title') . ' · ');
+ $this->view->_layout('simple');
+
+ $username = Minz_Request::param('username');
+ $token = Minz_Request::param('token');
+
+ if ($username) {
+ $user_config = get_user_configuration($username);
+ } elseif (FreshRSS_Auth::hasAccess()) {
+ $user_config = FreshRSS_Context::$user_conf;
+ } else {
+ Minz_Error::error(403);
+ }
+
+ if (!FreshRSS_UserDAO::exists($username) || $user_config === null) {
+ Minz_Error::error(404);
+ }
+
+ if ($user_config->email_validation_token === '') {
+ Minz_Request::good(
+ _t('user.email.validation.feedback.unnecessary'),
+ array('c' => 'index', 'a' => 'index')
+ );
+ }
+
+ if ($token) {
+ if ($user_config->email_validation_token !== $token) {
+ Minz_Request::bad(
+ _t('user.email.validation.feedback.wrong_token'),
+ array('c' => 'user', 'a' => 'validateEmail')
+ );
+ }
+
+ $user_config->email_validation_token = '';
+ if ($user_config->save()) {
+ Minz_Request::good(
+ _t('user.email.validation.feedback.ok'),
+ array('c' => 'index', 'a' => 'index')
+ );
+ } else {
+ Minz_Request::bad(
+ _t('user.email.validation.feedback.error'),
+ array('c' => 'user', 'a' => 'validateEmail')
+ );
+ }
+ }
+ }
+
+ /**
+ * This action resends a validation email to the current user.
+ *
+ * It only acts on POST requests but doesn't require any param (except the
+ * CSRF token).
+ *
+ * It returns 403 error if the user is not logged in or 404 if request is
+ * not POST. Else it redirects silently to the index if user has already
+ * validated its email, or to the user#validateEmail route.
+ */
+ public function sendValidationEmailAction() {
+ if (!FreshRSS_Auth::hasAccess()) {
+ Minz_Error::error(403);
+ }
+
+ if (!Minz_Request::isPost()) {
+ Minz_Error::error(404);
+ }
+
+ $username = Minz_Session::param('currentUser', '_');
+ $user_config = FreshRSS_Context::$user_conf;
+
+ if ($user_config->email_validation_token === '') {
+ Minz_Request::forward(array(
+ 'c' => 'index',
+ 'a' => 'index',
+ ), true);
+ }
+
+ $mailer = new FreshRSS_User_Mailer();
+ $ok = $mailer->send_email_need_validation($username, $user_config);
+
+ $redirect_url = array('c' => 'user', 'a' => 'validateEmail');
+ if ($ok) {
+ Minz_Request::good(
+ _t('user.email.validation.feedback.email_sent'),
+ $redirect_url
+ );
+ } else {
+ Minz_Request::bad(
+ _t('user.email.validation.feedback.email_failed'),
+ $redirect_url
+ );
+ }
+ }
+
+ /**
* This action delete an existing user.
*
* Request parameter is:
@@ -296,17 +479,18 @@ class FreshRSS_user_Controller extends Minz_ActionController {
*/
public function deleteAction() {
$username = Minz_Request::param('username');
+ $self_deletion = Minz_Session::param('currentUser', '_') === $username;
+
+ if (!FreshRSS_Auth::hasAccess('admin') && !$self_deletion) {
+ Minz_Error::error(403);
+ }
+
$redirect_url = urldecode(Minz_Request::param('r', false, true));
if (!$redirect_url) {
$redirect_url = array('c' => 'user', 'a' => 'manage');
}
- $self_deletion = Minz_Session::param('currentUser', '_') === $username;
-
- if (Minz_Request::isPost() && (
- FreshRSS_Auth::hasAccess('admin') ||
- $self_deletion
- )) {
+ if (Minz_Request::isPost()) {
$ok = true;
if ($ok && $self_deletion) {
// We check the password if it's a self-destruction
diff --git a/app/FreshRSS.php b/app/FreshRSS.php
index 8f614c538..d472a2147 100644
--- a/app/FreshRSS.php
+++ b/app/FreshRSS.php
@@ -53,6 +53,10 @@ class FreshRSS extends Minz_FrontController {
$ext_list = FreshRSS_Context::$user_conf->extensions_enabled;
Minz_ExtensionManager::enableByList($ext_list);
}
+
+ self::checkEmailValidated();
+
+ Minz_ExtensionManager::callHook('freshrss_init');
}
private static function initAuth() {
@@ -142,4 +146,22 @@ class FreshRSS extends Minz_FrontController {
FreshRSS_Share::load(join_path(APP_PATH, 'shares.php'));
self::loadStylesAndScripts();
}
+
+ private static function checkEmailValidated() {
+ $email_not_verified = FreshRSS_Auth::hasAccess() && FreshRSS_Context::$user_conf->email_validation_token !== '';
+ $action_is_allowed = (
+ Minz_Request::is('user', 'validateEmail') ||
+ Minz_Request::is('user', 'sendValidationEmail') ||
+ Minz_Request::is('user', 'profile') ||
+ Minz_Request::is('user', 'delete') ||
+ Minz_Request::is('auth', 'logout') ||
+ Minz_Request::is('javascript', 'nonce')
+ );
+ if ($email_not_verified && !$action_is_allowed) {
+ Minz_Request::forward(array(
+ 'c' => 'user',
+ 'a' => 'validateEmail',
+ ), true);
+ }
+ }
}
diff --git a/app/Mailers/UserMailer.php b/app/Mailers/UserMailer.php
new file mode 100644
index 000000000..5a2d39f1a
--- /dev/null
+++ b/app/Mailers/UserMailer.php
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * Manage the emails sent to the users.
+ */
+class FreshRSS_User_Mailer extends Minz_Mailer {
+ public function send_email_need_validation($username, $user_config) {
+ $this->view->_path('user_mailer/email_need_validation.txt');
+
+ $this->view->username = $username;
+ $this->view->site_title = FreshRSS_Context::$system_conf->title;
+ $this->view->validation_url = Minz_Url::display(
+ array(
+ 'c' => 'user',
+ 'a' => 'validateEmail',
+ 'params' => array(
+ 'username' => $username,
+ 'token' => $user_config->email_validation_token
+ )
+ ),
+ 'txt',
+ true
+ );
+
+ $subject_prefix = '[' . FreshRSS_Context::$system_conf->title . ']';
+ return $this->mail(
+ $user_config->mail_login,
+ $subject_prefix . ' ' ._t('user.mailer.email_need_validation.title')
+ );
+ }
+}
diff --git a/app/Models/Auth.php b/app/Models/Auth.php
index 6d079a01f..b7fb0e6d6 100644
--- a/app/Models/Auth.php
+++ b/app/Models/Auth.php
@@ -219,10 +219,6 @@ class FreshRSS_FormAuth {
return false;
}
- if (!function_exists('password_verify')) {
- include_once(LIB_PATH . '/password_compat.php');
- }
-
return password_verify($nonce . $hash, $challenge);
}
@@ -283,8 +279,7 @@ class FreshRSS_FormAuth {
$cookie_duration = empty($limits['cookie_duration']) ? 2592000 : $limits['cookie_duration'];
$oldest = time() - $cookie_duration;
foreach (new DirectoryIterator(DATA_PATH . '/tokens/') as $file_info) {
- // $extension = $file_info->getExtension(); doesn't work in PHP < 5.3.7
- $extension = pathinfo($file_info->getFilename(), PATHINFO_EXTENSION);
+ $extension = $file_info->getExtension();
if ($extension === 'txt' && $file_info->getMTime() < $oldest) {
@unlink($file_info->getPathname());
}
diff --git a/app/Models/Category.php b/app/Models/Category.php
index fa711aa66..a195c88b3 100644
--- a/app/Models/Category.php
+++ b/app/Models/Category.php
@@ -8,6 +8,7 @@ class FreshRSS_Category extends Minz_Model {
private $feeds = null;
private $hasFeedsWithError = false;
private $isDefault = false;
+ private $attributes = [];
public function __construct($name = '', $feeds = null) {
$this->_name($name);
@@ -68,8 +69,19 @@ class FreshRSS_Category extends Minz_Model {
return $this->hasFeedsWithError;
}
- public function _id($value) {
- $this->id = $value;
+ public function attributes($key = '') {
+ if ($key == '') {
+ return $this->attributes;
+ } else {
+ return isset($this->attributes[$key]) ? $this->attributes[$key] : null;
+ }
+ }
+
+ public function _id($id) {
+ $this->id = $id;
+ if ($id == FreshRSS_CategoryDAO::DEFAULTCATEGORYID) {
+ $this->_name(_t('gen.short.default_category'));
+ }
}
public function _name($value) {
$this->name = trim($value);
@@ -84,4 +96,19 @@ class FreshRSS_Category extends Minz_Model {
$this->feeds = $values;
}
+
+ public function _attributes($key, $value) {
+ if ('' == $key) {
+ if (is_string($value)) {
+ $value = json_decode($value, true);
+ }
+ if (is_array($value)) {
+ $this->attributes = $value;
+ }
+ } elseif (null === $value) {
+ unset($this->attributes[$key]);
+ } else {
+ $this->attributes[$key] = $value;
+ }
+ }
}
diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php
index 6535adae7..c1277751c 100644
--- a/app/Models/CategoryDAO.php
+++ b/app/Models/CategoryDAO.php
@@ -4,23 +4,92 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable
const DEFAULTCATEGORYID = 1;
+ protected function addColumn($name) {
+ Minz_Log::warning(__method__ . ': ' . $name);
+ try {
+ if ('attributes' === $name) { //v1.15.0
+ $ok = $this->pdo->exec('ALTER TABLE `_category` ADD COLUMN attributes TEXT') !== false;
+
+ $stm = $this->pdo->query('SELECT * FROM `_feed`');
+ $feeds = $stm->fetchAll(PDO::FETCH_ASSOC);
+
+ $stm = $this->pdo->prepare('UPDATE `_feed` SET attributes = :attributes WHERE id = :id');
+ foreach ($feeds as $feed) {
+ if (empty($feed['keep_history']) || empty($feed['id'])) {
+ continue;
+ }
+ $keepHistory = $feed['keep_history'];
+ $attributes = empty($feed['attributes']) ? [] : json_decode($feed['attributes'], true);
+ if (is_string($attributes)) { //Legacy risk of double-encoding
+ $attributes = json_decode($attributes, true);
+ }
+ if (!is_array($attributes)) {
+ $attributes = [];
+ }
+ if ($keepHistory > 0) {
+ $attributes['archiving']['keep_min'] = intval($keepHistory);
+ } elseif ($keepHistory == -1) { //Infinite
+ $attributes['archiving']['keep_period'] = false;
+ $attributes['archiving']['keep_max'] = false;
+ $attributes['archiving']['keep_min'] = false;
+ } else {
+ continue;
+ }
+ $stm->bindValue(':id', $feed['id'], PDO::PARAM_INT);
+ $stm->bindValue(':attributes', json_encode($attributes, JSON_UNESCAPED_SLASHES));
+ $stm->execute();
+ }
+
+ if ($this->pdo->dbType() !== 'sqlite') { //SQLite does not support DROP COLUMN
+ $this->pdo->exec('ALTER TABLE `_feed` DROP COLUMN keep_history');
+ } else {
+ $this->pdo->exec('DROP INDEX IF EXISTS feed_keep_history_index'); //SQLite at least drop index
+ }
+ return $ok;
+ }
+ } catch (Exception $e) {
+ Minz_Log::error(__method__ . ': ' . $e->getMessage());
+ }
+ return false;
+ }
+
+ protected function autoUpdateDb($errorInfo) {
+ if (isset($errorInfo[0])) {
+ if ($errorInfo[0] === FreshRSS_DatabaseDAO::ER_BAD_FIELD_ERROR || $errorInfo[0] === FreshRSS_DatabaseDAOPGSQL::UNDEFINED_COLUMN) {
+ foreach (['attributes'] as $column) {
+ if (stripos($errorInfo[2], $column) !== false) {
+ return $this->addColumn($column);
+ }
+ }
+ }
+ }
+ return false;
+ }
+
public function addCategory($valuesTmp) {
- $sql = 'INSERT INTO `' . $this->prefix . 'category`(name) '
- . 'SELECT * FROM (SELECT TRIM(?)) c2 ' //TRIM() to provide a type hint as text for PostgreSQL
- . 'WHERE NOT EXISTS (SELECT 1 FROM `' . $this->prefix . 'tag` WHERE name = TRIM(?))'; //No tag of the same name
- $stm = $this->bd->prepare($sql);
+ $sql = 'INSERT INTO `_category`(name, attributes) '
+ . 'SELECT * FROM (SELECT TRIM(?), ?) c2 ' //TRIM() to provide a type hint as text for PostgreSQL
+ . 'WHERE NOT EXISTS (SELECT 1 FROM `_tag` WHERE name = TRIM(?))'; //No tag of the same name
+ $stm = $this->pdo->prepare($sql);
$valuesTmp['name'] = mb_strcut(trim($valuesTmp['name']), 0, FreshRSS_DatabaseDAO::LENGTH_INDEX_UNICODE, 'UTF-8');
+ if (!isset($valuesTmp['attributes'])) {
+ $valuesTmp['attributes'] = [];
+ }
$values = array(
$valuesTmp['name'],
+ is_string($valuesTmp['attributes']) ? $valuesTmp['attributes'] : json_encode($valuesTmp['attributes'], JSON_UNESCAPED_SLASHES),
$valuesTmp['name'],
);
if ($stm && $stm->execute($values)) {
- return $this->bd->lastInsertId('"' . $this->prefix . 'category_id_seq"');
+ return $this->pdo->lastInsertId('`_category_id_seq`');
} else {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
- Minz_Log::error('SQL error addCategory: ' . $info[2]);
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
+ if ($this->autoUpdateDb($info)) {
+ return $this->addCategory($valuesTmp);
+ }
+ Minz_Log::error('SQL error addCategory: ' . json_encode($info));
return false;
}
}
@@ -39,13 +108,17 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable
}
public function updateCategory($id, $valuesTmp) {
- $sql = 'UPDATE `' . $this->prefix . 'category` SET name=? WHERE id=? '
- . 'AND NOT EXISTS (SELECT 1 FROM `' . $this->prefix . 'tag` WHERE name = ?)'; //No tag of the same name
- $stm = $this->bd->prepare($sql);
+ $sql = 'UPDATE `_category` SET name=?, attributes=? WHERE id=? '
+ . 'AND NOT EXISTS (SELECT 1 FROM `_tag` WHERE name = ?)'; //No tag of the same name
+ $stm = $this->pdo->prepare($sql);
$valuesTmp['name'] = mb_strcut(trim($valuesTmp['name']), 0, FreshRSS_DatabaseDAO::LENGTH_INDEX_UNICODE, 'UTF-8');
+ if (!isset($valuesTmp['attributes'])) {
+ $valuesTmp['attributes'] = [];
+ }
$values = array(
$valuesTmp['name'],
+ is_string($valuesTmp['attributes']) ? $valuesTmp['attributes'] : json_encode($valuesTmp['attributes'], JSON_UNESCAPED_SLASHES),
$id,
$valuesTmp['name'],
);
@@ -53,8 +126,11 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable
if ($stm && $stm->execute($values)) {
return $stm->rowCount();
} else {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
- Minz_Log::error('SQL error updateCategory: ' . $info[2]);
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
+ if ($this->autoUpdateDb($info)) {
+ return $this->updateCategory($valuesTmp);
+ }
+ Minz_Log::error('SQL error updateCategory: ' . json_encode($info));
return false;
}
}
@@ -63,27 +139,42 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable
if ($id <= self::DEFAULTCATEGORYID) {
return false;
}
- $sql = 'DELETE FROM `' . $this->prefix . 'category` WHERE id=?';
- $stm = $this->bd->prepare($sql);
-
- $values = array($id);
-
- if ($stm && $stm->execute($values)) {
+ $sql = 'DELETE FROM `_category` WHERE id=:id';
+ $stm = $this->pdo->prepare($sql);
+ $stm->bindParam(':id', $id, PDO::PARAM_INT);
+ if ($stm && $stm->execute()) {
return $stm->rowCount();
} else {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
- Minz_Log::error('SQL error deleteCategory: ' . $info[2]);
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
+ Minz_Log::error('SQL error deleteCategory: ' . json_encode($info));
return false;
}
}
- public function searchById($id) {
- $sql = 'SELECT * FROM `' . $this->prefix . 'category` WHERE id=?';
- $stm = $this->bd->prepare($sql);
-
- $values = array($id);
+ public function selectAll() {
+ $sql = 'SELECT id, name, attributes FROM `_category`';
+ $stm = $this->pdo->query($sql);
+ if ($stm != false) {
+ while ($row = $stm->fetch(PDO::FETCH_ASSOC)) {
+ yield $row;
+ }
+ } else {
+ $info = $this->pdo->errorInfo();
+ if ($this->autoUpdateDb($info)) {
+ foreach ($this->selectAll() as $category) { // `yield from` requires PHP 7+
+ yield $category;
+ }
+ }
+ Minz_Log::error(__method__ . ' error: ' . json_encode($info));
+ yield false;
+ }
+ }
- $stm->execute($values);
+ public function searchById($id) {
+ $sql = 'SELECT * FROM `_category` WHERE id=:id';
+ $stm = $this->pdo->prepare($sql);
+ $stm->bindParam(':id', $id, PDO::PARAM_INT);
+ $stm->execute();
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
$cat = self::daoToCategory($res);
@@ -94,15 +185,15 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable
}
}
public function searchByName($name) {
- $sql = 'SELECT * FROM `' . $this->prefix . 'category` WHERE name=?';
- $stm = $this->bd->prepare($sql);
-
- $values = array($name);
-
- $stm->execute($values);
+ $sql = 'SELECT * FROM `_category` WHERE name=:name';
+ $stm = $this->pdo->prepare($sql);
+ if ($stm == false) {
+ return false;
+ }
+ $stm->bindParam(':name', $name);
+ $stm->execute();
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
$cat = self::daoToCategory($res);
-
if (isset($cat[0])) {
return $cat[0];
} else {
@@ -110,30 +201,61 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable
}
}
+ public function listSortedCategories($prePopulateFeeds = true, $details = false) {
+ $categories = $this->listCategories($prePopulateFeeds, $details);
+
+ if (!is_array($categories)) {
+ return $categories;
+ }
+
+ uasort($categories, function ($a, $b) {
+ $aPosition = $a->attributes('position');
+ $bPosition = $b->attributes('position');
+ if ($aPosition === $bPosition) {
+ return ($a->name() < $b->name()) ? -1 : 1;
+ } elseif (null === $aPosition) {
+ return 1;
+ } elseif (null === $bPosition) {
+ return -1;
+ }
+ return ($aPosition < $bPosition) ? -1 : 1;
+ });
+
+ return $categories;
+ }
+
public function listCategories($prePopulateFeeds = true, $details = false) {
if ($prePopulateFeeds) {
- $sql = 'SELECT c.id AS c_id, c.name AS c_name, '
+ $sql = 'SELECT c.id AS c_id, c.name AS c_name, c.attributes AS c_attributes, '
. ($details ? 'f.* ' : 'f.id, f.name, f.url, f.website, f.priority, f.error, f.`cache_nbEntries`, f.`cache_nbUnreads`, f.ttl ')
- . 'FROM `' . $this->prefix . 'category` c '
- . 'LEFT OUTER JOIN `' . $this->prefix . 'feed` f ON f.category=c.id '
+ . 'FROM `_category` c '
+ . 'LEFT OUTER JOIN `_feed` f ON f.category=c.id '
. 'WHERE f.priority >= :priority_normal '
. 'GROUP BY f.id, c_id '
. 'ORDER BY c.name, f.name';
- $stm = $this->bd->prepare($sql);
- $stm->execute(array(':priority_normal' => FreshRSS_Feed::PRIORITY_NORMAL));
- return self::daoToCategoryPrepopulated($stm->fetchAll(PDO::FETCH_ASSOC));
+ $stm = $this->pdo->prepare($sql);
+ $values = [ ':priority_normal' => FreshRSS_Feed::PRIORITY_NORMAL ];
+ if ($stm && $stm->execute($values)) {
+ return self::daoToCategoryPrepopulated($stm->fetchAll(PDO::FETCH_ASSOC));
+ } else {
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
+ if ($this->autoUpdateDb($info)) {
+ return $this->listCategories($prePopulateFeeds, $details);
+ }
+ Minz_Log::error('SQL error listCategories: ' . json_encode($info));
+ return false;
+ }
} else {
- $sql = 'SELECT * FROM `' . $this->prefix . 'category` ORDER BY name';
- $stm = $this->bd->prepare($sql);
- $stm->execute();
+ $sql = 'SELECT * FROM `_category` ORDER BY name';
+ $stm = $this->pdo->query($sql);
return self::daoToCategory($stm->fetchAll(PDO::FETCH_ASSOC));
}
}
public function getDefault() {
- $sql = 'SELECT * FROM `' . $this->prefix . 'category` WHERE id=' . self::DEFAULTCATEGORYID;
- $stm = $this->bd->prepare($sql);
-
+ $sql = 'SELECT * FROM `_category` WHERE id=:id';
+ $stm = $this->pdo->prepare($sql);
+ $stm->bindValue(':id', self::DEFAULTCATEGORYID, PDO::PARAM_INT);
$stm->execute();
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
$cat = self::daoToCategory($res);
@@ -155,12 +277,12 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable
$cat = new FreshRSS_Category(_t('gen.short.default_category'));
$cat->_id(self::DEFAULTCATEGORYID);
- $sql = 'INSERT INTO `' . $this->prefix . 'category`(id, name) VALUES(?, ?)';
- if (parent::$sharedDbType === 'pgsql') {
+ $sql = 'INSERT INTO `_category`(id, name) VALUES(?, ?)';
+ if ($this->pdo->dbType() === 'pgsql') {
//Force call to nextval()
- $sql .= ' RETURNING nextval(\'"' . $this->prefix . 'category_id_seq"\');';
+ $sql .= " RETURNING nextval('`_category_id_seq`');";
}
- $stm = $this->bd->prepare($sql);
+ $stm = $this->pdo->prepare($sql);
$values = array(
$cat->id(),
@@ -168,9 +290,9 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable
);
if ($stm && $stm->execute($values)) {
- return $this->bd->lastInsertId('"' . $this->prefix . 'category_id_seq"');
+ return $this->pdo->lastInsertId('`_category_id_seq`');
} else {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error check default category: ' . json_encode($info));
return false;
}
@@ -179,31 +301,27 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable
}
public function count() {
- $sql = 'SELECT COUNT(*) AS count FROM `' . $this->prefix . 'category`';
- $stm = $this->bd->prepare($sql);
- $stm->execute();
+ $sql = 'SELECT COUNT(*) AS count FROM `_category`';
+ $stm = $this->pdo->query($sql);
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
-
return $res[0]['count'];
}
public function countFeed($id) {
- $sql = 'SELECT COUNT(*) AS count FROM `' . $this->prefix . 'feed` WHERE category=?';
- $stm = $this->bd->prepare($sql);
- $values = array($id);
- $stm->execute($values);
+ $sql = 'SELECT COUNT(*) AS count FROM `_feed` WHERE category=:id';
+ $stm = $this->pdo->prepare($sql);
+ $stm->bindParam(':id', $id, PDO::PARAM_INT);
+ $stm->execute();
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
-
return $res[0]['count'];
}
public function countNotRead($id) {
- $sql = 'SELECT COUNT(*) AS count FROM `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed=f.id WHERE category=? AND e.is_read=0';
- $stm = $this->bd->prepare($sql);
- $values = array($id);
- $stm->execute($values);
+ $sql = 'SELECT COUNT(*) AS count FROM `_entry` e INNER JOIN `_feed` f ON e.id_feed=f.id WHERE category=:id AND e.is_read=0';
+ $stm = $this->pdo->prepare($sql);
+ $stm->bindParam(':id', $id, PDO::PARAM_INT);
+ $stm->execute();
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
-
return $res[0]['count'];
}
@@ -248,6 +366,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable
$feedDao->daoToFeed($feedsDao, $previousLine['c_id'])
);
$cat->_id($previousLine['c_id']);
+ $cat->_attributes('', $previousLine['c_attributes']);
$list[$previousLine['c_id']] = $cat;
$feedsDao = array(); //Prepare for next category
@@ -264,6 +383,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable
$feedDao->daoToFeed($feedsDao, $previousLine['c_id'])
);
$cat->_id($previousLine['c_id']);
+ $cat->_attributes('', $previousLine['c_attributes']);
$list[$previousLine['c_id']] = $cat;
}
@@ -282,6 +402,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable
$dao['name']
);
$cat->_id($dao['id']);
+ $cat->_attributes('', isset($dao['attributes']) ? $dao['attributes'] : '');
$cat->_isDefault(static::DEFAULTCATEGORYID === intval($dao['id']));
$list[$key] = $cat;
}
diff --git a/app/Models/CategoryDAOSQLite.php b/app/Models/CategoryDAOSQLite.php
new file mode 100644
index 000000000..e32545c90
--- /dev/null
+++ b/app/Models/CategoryDAOSQLite.php
@@ -0,0 +1,17 @@
+<?php
+
+class FreshRSS_CategoryDAOSQLite extends FreshRSS_CategoryDAO {
+
+ protected function autoUpdateDb($errorInfo) {
+ if ($tableInfo = $this->pdo->query("PRAGMA table_info('category')")) {
+ $columns = $tableInfo->fetchAll(PDO::FETCH_COLUMN, 1);
+ foreach (['attributes'] as $column) {
+ if (!in_array($column, $columns)) {
+ return $this->addColumn($column);
+ }
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/app/Models/ConfigurationSetter.php b/app/Models/ConfigurationSetter.php
index ec6380df4..b1d271f41 100644
--- a/app/Models/ConfigurationSetter.php
+++ b/app/Models/ConfigurationSetter.php
@@ -79,11 +79,6 @@ class FreshRSS_ConfigurationSetter {
$data['html5_notif_timeout'] = $value >= 0 ? $value : 0;
}
- private function _keep_history_default(&$data, $value) {
- $value = intval($value);
- $data['keep_history_default'] = $value >= FreshRSS_Feed::KEEP_HISTORY_INFINITE ? $value : 0;
- }
-
// It works for system config too!
private function _language(&$data, $value) {
$value = strtolower($value);
@@ -94,11 +89,6 @@ class FreshRSS_ConfigurationSetter {
$data['language'] = $value;
}
- private function _old_entries(&$data, $value) {
- $value = intval($value);
- $data['old_entries'] = $value > 0 ? $value : 3;
- }
-
private function _passwordHash(&$data, $value) {
$data['passwordHash'] = ctype_graph($value) && (strlen($value) >= 60) ? $value : '';
}
@@ -257,6 +247,9 @@ class FreshRSS_ConfigurationSetter {
private function _topline_read(&$data, $value) {
$data['topline_read'] = $this->handleBool($value);
}
+ private function _topline_display_authors(&$data, $value) {
+ $data['topline_display_authors'] = $this->handleBool($value);
+ }
/**
* The (not so long) list of setters for system configuration.
@@ -386,4 +379,8 @@ class FreshRSS_ConfigurationSetter {
$data['auto_update_url'] = $value;
}
+
+ private function _force_email_validation(&$data, $value) {
+ $data['force_email_validation'] = $this->handleBool($value);
+ }
}
diff --git a/app/Models/Context.php b/app/Models/Context.php
index 95dc47c8c..e27330665 100644
--- a/app/Models/Context.php
+++ b/app/Models/Context.php
@@ -51,6 +51,24 @@ class FreshRSS_Context {
// Init configuration.
self::$system_conf = Minz_Configuration::get('system');
self::$user_conf = Minz_Configuration::get('user');
+
+ //Legacy
+ $oldEntries = (int)FreshRSS_Context::$user_conf->param('old_entries', 0);
+ $keepMin = (int)FreshRSS_Context::$user_conf->param('keep_history_default', -5);
+ if ($oldEntries > 0 || $keepMin > -5) { //Freshrss < 1.15
+ $archiving = FreshRSS_Context::$user_conf->archiving;
+ $archiving['keep_max'] = false;
+ if ($oldEntries > 0) {
+ $archiving['keep_period'] = 'P' . $oldEntries . 'M';
+ }
+ if ($keepMin > 0) {
+ $archiving['keep_min'] = $keepMin;
+ } elseif ($keepMin == -1) { //Infinite
+ $archiving['keep_period'] = false;
+ $archiving['keep_min'] = false;
+ }
+ FreshRSS_Context::$user_conf->archiving = $archiving;
+ }
}
/**
diff --git a/app/Models/DatabaseDAO.php b/app/Models/DatabaseDAO.php
index b331eccc3..a36b469b1 100644
--- a/app/Models/DatabaseDAO.php
+++ b/app/Models/DatabaseDAO.php
@@ -8,25 +8,50 @@ class FreshRSS_DatabaseDAO extends Minz_ModelPdo {
//MySQL error codes
const ER_BAD_FIELD_ERROR = '42S22';
const ER_BAD_TABLE_ERROR = '42S02';
- const ER_TRUNCATED_WRONG_VALUE_FOR_FIELD = '1366';
+ const ER_DATA_TOO_LONG = '1406';
//MySQL InnoDB maximum index length for UTF8MB4
//https://dev.mysql.com/doc/refman/8.0/en/innodb-restrictions.html
const LENGTH_INDEX_UNICODE = 191;
+ public function create() {
+ require(APP_PATH . '/SQL/install.sql.' . $this->pdo->dbType() . '.php');
+ $db = FreshRSS_Context::$system_conf->db;
+
+ try {
+ $sql = sprintf($SQL_CREATE_DB, empty($db['base']) ? '' : $db['base']);
+ return $this->pdo->exec($sql) !== false;
+ } catch (PDOException $e) {
+ $_SESSION['bd_error'] = $e->getMessage();
+ syslog(LOG_DEBUG, __method__ . ' warning: ' . $e->getMessage());
+ return false;
+ }
+ }
+
+ public function testConnection() {
+ try {
+ $sql = 'SELECT 1';
+ $stm = $this->pdo->query($sql);
+ $res = $stm->fetchAll(PDO::FETCH_COLUMN, 0);
+ return $res != false;
+ } catch (PDOException $e) {
+ $_SESSION['bd_error'] = $e->getMessage();
+ syslog(LOG_DEBUG, __method__ . ' warning: ' . $e->getMessage());
+ return false;
+ }
+ }
+
public function tablesAreCorrect() {
- $sql = 'SHOW TABLES';
- $stm = $this->bd->prepare($sql);
- $stm->execute();
+ $stm = $this->pdo->query('SHOW TABLES');
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
$tables = array(
- $this->prefix . 'category' => false,
- $this->prefix . 'feed' => false,
- $this->prefix . 'entry' => false,
- $this->prefix . 'entrytmp' => false,
- $this->prefix . 'tag' => false,
- $this->prefix . 'entrytag' => false,
+ $this->pdo->prefix() . 'category' => false,
+ $this->pdo->prefix() . 'feed' => false,
+ $this->pdo->prefix() . 'entry' => false,
+ $this->pdo->prefix() . 'entrytmp' => false,
+ $this->pdo->prefix() . 'tag' => false,
+ $this->pdo->prefix() . 'entrytag' => false,
);
foreach ($res as $value) {
$tables[array_pop($value)] = true;
@@ -36,10 +61,8 @@ class FreshRSS_DatabaseDAO extends Minz_ModelPdo {
}
public function getSchema($table) {
- $sql = 'DESC ' . $this->prefix . $table;
- $stm = $this->bd->prepare($sql);
- $stm->execute();
-
+ $sql = 'DESC `_' . $table . '`';
+ $stm = $this->pdo->query($sql);
return $this->listDaoToSchema($stm->fetchAll(PDO::FETCH_ASSOC));
}
@@ -63,7 +86,7 @@ class FreshRSS_DatabaseDAO extends Minz_ModelPdo {
public function feedIsCorrect() {
return $this->checkTable('feed', array(
'id', 'url', 'category', 'name', 'website', 'description', 'lastUpdate',
- 'priority', 'pathEntries', 'httpAuth', 'error', 'keep_history', 'ttl', 'attributes',
+ 'priority', 'pathEntries', 'httpAuth', 'error', 'ttl', 'attributes',
'cache_nbEntries', 'cache_nbUnreads',
));
}
@@ -119,9 +142,9 @@ class FreshRSS_DatabaseDAO extends Minz_ModelPdo {
$values = array($db['base']);
if (!$all) {
$sql .= ' AND table_name LIKE ?';
- $values[] = $this->prefix . '%';
+ $values[] = $this->pdo->prefix() . '%';
}
- $stm = $this->bd->prepare($sql);
+ $stm = $this->pdo->prepare($sql);
$stm->execute($values);
$res = $stm->fetchAll(PDO::FETCH_COLUMN, 0);
return $res[0];
@@ -132,30 +155,23 @@ class FreshRSS_DatabaseDAO extends Minz_ModelPdo {
$tables = array('category', 'feed', 'entry', 'entrytmp', 'tag', 'entrytag');
foreach ($tables as $table) {
- $sql = 'OPTIMIZE TABLE `' . $this->prefix . $table . '`'; //MySQL
- $stm = $this->bd->prepare($sql);
- $ok &= $stm != false;
- if ($stm) {
- $ok &= $stm->execute();
- }
+ $sql = 'OPTIMIZE TABLE `_' . $table . '`'; //MySQL
+ $ok &= ($this->pdo->exec($sql) !== false);
}
return $ok;
}
public function ensureCaseInsensitiveGuids() {
$ok = true;
- $db = FreshRSS_Context::$system_conf->db;
- if ($db['type'] === 'mysql') {
- include_once(APP_PATH . '/SQL/install.sql.mysql.php');
- if (defined('SQL_UPDATE_GUID_LATIN1_BIN')) { //FreshRSS 1.12
- try {
- $sql = sprintf(SQL_UPDATE_GUID_LATIN1_BIN, $this->prefix);
- $stm = $this->bd->prepare($sql);
- $ok = $stm->execute();
- } catch (Exception $e) {
- $ok = false;
- Minz_Log::error('FreshRSS_DatabaseDAO::ensureCaseInsensitiveGuids error: ' . $e->getMessage());
- }
+ if ($this->pdo->dbType() === 'mysql') {
+ include(APP_PATH . '/SQL/install.sql.mysql.php');
+
+ $ok = false;
+ try {
+ $ok = $this->pdo->exec($SQL_UPDATE_GUID_LATIN1_BIN) !== false; //FreshRSS 1.12
+ } catch (Exception $e) {
+ $ok = false;
+ Minz_Log::error(__METHOD__ . ' error: ' . $e->getMessage());
}
}
return $ok;
@@ -164,4 +180,168 @@ class FreshRSS_DatabaseDAO extends Minz_ModelPdo {
public function minorDbMaintenance() {
$this->ensureCaseInsensitiveGuids();
}
+
+ private static function stdError($error) {
+ if (defined('STDERR')) {
+ fwrite(STDERR, $error . "\n");
+ }
+ Minz_Log::error($error);
+ return false;
+ }
+
+ const SQLITE_EXPORT = 1;
+ const SQLITE_IMPORT = 2;
+
+ public function dbCopy($filename, $mode, $clearFirst = false) {
+ $error = '';
+
+ $userDAO = FreshRSS_Factory::createUserDao();
+ $catDAO = FreshRSS_Factory::createCategoryDao();
+ $feedDAO = FreshRSS_Factory::createFeedDao();
+ $entryDAO = FreshRSS_Factory::createEntryDao();
+ $tagDAO = FreshRSS_Factory::createTagDao();
+
+ switch ($mode) {
+ case self::SQLITE_EXPORT:
+ if (@filesize($filename) > 0) {
+ $error = 'Error: SQLite export file already exists: ' . $filename;
+ }
+ break;
+ case self::SQLITE_IMPORT:
+ if (!is_readable($filename)) {
+ $error = 'Error: SQLite import file is not readable: ' . $filename;
+ } elseif ($clearFirst) {
+ $userDAO->deleteUser();
+ if ($this->pdo->dbType() === 'sqlite') {
+ //We cannot just delete the .sqlite file otherwise PDO gets buggy.
+ //SQLite is the only one with database-level optimization, instead of at table level.
+ $this->optimize();
+ }
+ } else {
+ $nbEntries = $entryDAO->countUnreadRead();
+ if (!empty($nbEntries['all'])) {
+ $error = 'Error: Destination database already contains some entries!';
+ }
+ }
+ break;
+ default:
+ $error = 'Invalid copy mode!';
+ break;
+ }
+ if ($error != '') {
+ return self::stdError($error);
+ }
+
+ $sqlite = null;
+
+ try {
+ $sqlite = new MinzPDOSQLite('sqlite:' . $filename);
+ } catch (Exception $e) {
+ $error = 'Error while initialising SQLite copy: ' . $e->getMessage();
+ return self::stdError($error);
+ }
+
+ Minz_ModelPdo::clean();
+ $userDAOSQLite = new FreshRSS_UserDAO('', $sqlite);
+ $categoryDAOSQLite = new FreshRSS_CategoryDAOSQLite('', $sqlite);
+ $feedDAOSQLite = new FreshRSS_FeedDAOSQLite('', $sqlite);
+ $entryDAOSQLite = new FreshRSS_EntryDAOSQLite('', $sqlite);
+ $tagDAOSQLite = new FreshRSS_TagDAOSQLite('', $sqlite);
+
+ switch ($mode) {
+ case self::SQLITE_EXPORT:
+ $userFrom = $userDAO; $userTo = $userDAOSQLite;
+ $catFrom = $catDAO; $catTo = $categoryDAOSQLite;
+ $feedFrom = $feedDAO; $feedTo = $feedDAOSQLite;
+ $entryFrom = $entryDAO; $entryTo = $entryDAOSQLite;
+ $tagFrom = $tagDAO; $tagTo = $tagDAOSQLite;
+ break;
+ case self::SQLITE_IMPORT:
+ $userFrom = $userDAOSQLite; $userTo = $userDAO;
+ $catFrom = $categoryDAOSQLite; $catTo = $catDAO;
+ $feedFrom = $feedDAOSQLite; $feedTo = $feedDAO;
+ $entryFrom = $entryDAOSQLite; $entryTo = $entryDAO;
+ $tagFrom = $tagDAOSQLite; $tagTo = $tagDAO;
+ break;
+ }
+
+ $idMaps = [];
+
+ if (defined('STDERR')) {
+ fwrite(STDERR, "Start SQL copy…\n");
+ }
+
+ $userTo->createUser();
+
+ $catTo->beginTransaction();
+ foreach ($catFrom->selectAll() as $category) {
+ $cat = $catTo->searchByName($category['name']); //Useful for the default category
+ if ($cat != null) {
+ $catId = $cat->id();
+ } else {
+ $catId = $catTo->addCategory($category);
+ if ($catId == false) {
+ $error = 'Error during SQLite copy of categories!';
+ return self::stdError($error);
+ }
+ }
+ $idMaps['c' . $category['id']] = $catId;
+ }
+ foreach ($feedFrom->selectAll() as $feed) {
+ $feed['category'] = empty($idMaps['c' . $feed['category']]) ? FreshRSS_CategoryDAO::DEFAULTCATEGORYID : $idMaps['c' . $feed['category']];
+ $feedId = $feedTo->addFeed($feed);
+ if ($feedId == false) {
+ $error = 'Error during SQLite copy of feeds!';
+ return self::stdError($error);
+ }
+ $idMaps['f' . $feed['id']] = $feedId;
+ }
+ $catTo->commit();
+
+ $nbEntries = $entryFrom->count();
+ $n = 0;
+ $entryTo->beginTransaction();
+ foreach ($entryFrom->selectAll() as $entry) {
+ $n++;
+ if (!empty($idMaps['f' . $entry['id_feed']])) {
+ $entry['id_feed'] = $idMaps['f' . $entry['id_feed']];
+ if (!$entryTo->addEntry($entry, false)) {
+ $error = 'Error during SQLite copy of entries!';
+ return self::stdError($error);
+ }
+ }
+ if ($n % 100 === 1 && defined('STDERR')) { //Display progression
+ fwrite(STDERR, "\033[0G" . $n . '/' . $nbEntries);
+ }
+ }
+ if (defined('STDERR')) {
+ fwrite(STDERR, "\033[0G" . $n . '/' . $nbEntries . "\n");
+ }
+ $entryTo->commit();
+ $feedTo->updateCachedValues();
+
+ $idMaps = [];
+
+ $tagTo->beginTransaction();
+ foreach ($tagFrom->selectAll() as $tag) {
+ $tagId = $tagTo->addTag($tag);
+ if ($tagId == false) {
+ $error = 'Error during SQLite copy of tags!';
+ return self::stdError($error);
+ }
+ $idMaps['t' . $tag['id']] = $tagId;
+ }
+ foreach ($tagFrom->selectEntryTag() as $entryTag) {
+ if (!empty($idMaps['t' . $entryTag['id_tag']])) {
+ $entryTag['id_tag'] = $idMaps['t' . $entryTag['id_tag']];
+ if (!$tagTo->tagEntry($entryTag['id_tag'], $entryTag['id_entry'])) {
+ $error = 'Error during SQLite copy of entry-tags!';
+ return self::stdError($error);
+ }
+ }
+ }
+ $tagTo->commit();
+
+ return true;
+ }
}
diff --git a/app/Models/DatabaseDAOPGSQL.php b/app/Models/DatabaseDAOPGSQL.php
index 8582b5719..1a6b3599e 100644
--- a/app/Models/DatabaseDAOPGSQL.php
+++ b/app/Models/DatabaseDAOPGSQL.php
@@ -13,18 +13,18 @@ class FreshRSS_DatabaseDAOPGSQL extends FreshRSS_DatabaseDAOSQLite {
$db = FreshRSS_Context::$system_conf->db;
$dbowner = $db['user'];
$sql = 'SELECT * FROM pg_catalog.pg_tables where tableowner=?';
- $stm = $this->bd->prepare($sql);
+ $stm = $this->pdo->prepare($sql);
$values = array($dbowner);
$stm->execute($values);
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
$tables = array(
- $this->prefix . 'category' => false,
- $this->prefix . 'feed' => false,
- $this->prefix . 'entry' => false,
- $this->prefix . 'entrytmp' => false,
- $this->prefix . 'tag' => false,
- $this->prefix . 'entrytag' => false,
+ $this->pdo->prefix() . 'category' => false,
+ $this->pdo->prefix() . 'feed' => false,
+ $this->pdo->prefix() . 'entry' => false,
+ $this->pdo->prefix() . 'entrytmp' => false,
+ $this->pdo->prefix() . 'tag' => false,
+ $this->pdo->prefix() . 'entrytag' => false,
);
foreach ($res as $value) {
$tables[array_pop($value)] = true;
@@ -35,8 +35,8 @@ class FreshRSS_DatabaseDAOPGSQL extends FreshRSS_DatabaseDAOSQLite {
public function getSchema($table) {
$sql = 'select column_name as field, data_type as type, column_default as default, is_nullable as null from INFORMATION_SCHEMA.COLUMNS where table_name = ?';
- $stm = $this->bd->prepare($sql);
- $stm->execute(array($this->prefix . $table));
+ $stm = $this->pdo->prepare($sql);
+ $stm->execute(array($this->pdo->prefix() . $table));
return $this->listDaoToSchema($stm->fetchAll(PDO::FETCH_ASSOC));
}
@@ -49,12 +49,23 @@ class FreshRSS_DatabaseDAOPGSQL extends FreshRSS_DatabaseDAOSQLite {
);
}
- public function size($all = true) {
- $db = FreshRSS_Context::$system_conf->db;
- $sql = 'SELECT pg_size_pretty(pg_database_size(?))';
- $values = array($db['base']);
- $stm = $this->bd->prepare($sql);
- $stm->execute($values);
+ public function size($all = false) {
+ if ($all) {
+ $db = FreshRSS_Context::$system_conf->db;
+ $sql = 'SELECT pg_database_size(:base)';
+ $stm = $this->pdo->prepare($sql);
+ $stm->bindParam(':base', $db['base']);
+ $stm->execute();
+ } else {
+ $sql = "SELECT "
+ . "pg_total_relation_size('{$this->pdo->prefix()}category') + "
+ . "pg_total_relation_size('{$this->pdo->prefix()}feed') + "
+ . "pg_total_relation_size('{$this->pdo->prefix()}entry') + "
+ . "pg_total_relation_size('{$this->pdo->prefix()}entrytmp') + "
+ . "pg_total_relation_size('{$this->pdo->prefix()}tag') + "
+ . "pg_total_relation_size('{$this->pdo->prefix()}entrytag')";
+ $stm = $this->pdo->query($sql);
+ }
$res = $stm->fetchAll(PDO::FETCH_COLUMN, 0);
return $res[0];
}
@@ -64,12 +75,8 @@ class FreshRSS_DatabaseDAOPGSQL extends FreshRSS_DatabaseDAOSQLite {
$tables = array('category', 'feed', 'entry', 'entrytmp', 'tag', 'entrytag');
foreach ($tables as $table) {
- $sql = 'VACUUM `' . $this->prefix . $table . '`';
- $stm = $this->bd->prepare($sql);
- $ok &= $stm != false;
- if ($stm) {
- $ok &= $stm->execute();
- }
+ $sql = 'VACUUM `_' . $table . '`';
+ $ok &= ($this->pdo->exec($sql) !== false);
}
return $ok;
}
diff --git a/app/Models/DatabaseDAOSQLite.php b/app/Models/DatabaseDAOSQLite.php
index a93a209b2..413e7ee09 100644
--- a/app/Models/DatabaseDAOSQLite.php
+++ b/app/Models/DatabaseDAOSQLite.php
@@ -6,17 +6,16 @@
class FreshRSS_DatabaseDAOSQLite extends FreshRSS_DatabaseDAO {
public function tablesAreCorrect() {
$sql = 'SELECT name FROM sqlite_master WHERE type="table"';
- $stm = $this->bd->prepare($sql);
- $stm->execute();
+ $stm = $this->pdo->query($sql);
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
$tables = array(
- 'category' => false,
- 'feed' => false,
- 'entry' => false,
- 'entrytmp' => false,
- 'tag' => false,
- 'entrytag' => false,
+ $this->pdo->prefix() . 'category' => false,
+ $this->pdo->prefix() . 'feed' => false,
+ $this->pdo->prefix() . 'entry' => false,
+ $this->pdo->prefix() . 'entrytmp' => false,
+ $this->pdo->prefix() . 'tag' => false,
+ $this->pdo->prefix() . 'entrytag' => false,
);
foreach ($res as $value) {
$tables[$value['name']] = true;
@@ -27,9 +26,7 @@ class FreshRSS_DatabaseDAOSQLite extends FreshRSS_DatabaseDAO {
public function getSchema($table) {
$sql = 'PRAGMA table_info(' . $table . ')';
- $stm = $this->bd->prepare($sql);
- $stm->execute();
-
+ $stm = $this->pdo->query($sql);
return $this->listDaoToSchema($stm->fetchAll(PDO::FETCH_ASSOC));
}
@@ -57,15 +54,18 @@ class FreshRSS_DatabaseDAOSQLite extends FreshRSS_DatabaseDAO {
}
public function size($all = false) {
- return @filesize(join_path(DATA_PATH, 'users', $this->current_user, 'db.sqlite'));
+ $sum = 0;
+ if ($all) {
+ foreach (glob(DATA_PATH . '/users/*/db.sqlite') as $filename) {
+ $sum += @filesize($filename);
+ }
+ } else {
+ $sum = @filesize(DATA_PATH . '/users/' . $this->current_user . '/db.sqlite');
+ }
+ return $sum;
}
public function optimize() {
- $sql = 'VACUUM';
- $stm = $this->bd->prepare($sql);
- if ($stm) {
- return $stm->execute();
- }
- return false;
+ return $this->pdo->exec('VACUUM') !== false;
}
}
diff --git a/app/Models/Entry.php b/app/Models/Entry.php
index 3bb977283..d90f828bc 100644
--- a/app/Models/Entry.php
+++ b/app/Models/Entry.php
@@ -327,7 +327,7 @@ class FreshRSS_Entry extends Minz_Model {
}
$ch = curl_init();
- curl_setopt_array($ch, array(
+ curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_REFERER => SimplePie_Misc::url_remove_credentials($url),
CURLOPT_HTTPHEADER => array('Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'),
@@ -337,13 +337,9 @@ class FreshRSS_Entry extends Minz_Model {
//CURLOPT_FAILONERROR => true;
CURLOPT_MAXREDIRS => 4,
CURLOPT_RETURNTRANSFER => true,
- ));
- if (version_compare(PHP_VERSION, '5.6.0') >= 0 || ini_get('open_basedir') == '') {
- curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); //Keep option separated for open_basedir PHP bug 65646
- }
- if (defined('CURLOPT_ENCODING')) {
- curl_setopt($ch, CURLOPT_ENCODING, ''); //Enable all encodings
- }
+ CURLOPT_FOLLOWLOCATION => true,
+ CURLOPT_ENCODING => '', //Enable all encodings
+ ]);
curl_setopt_array($ch, $system_conf->curl_options);
if (isset($attributes['ssl_verify'])) {
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $attributes['ssl_verify'] ? 2 : 0);
diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php
index b47cd55ad..99e99f463 100644
--- a/app/Models/EntryDAO.php
+++ b/app/Models/EntryDAO.php
@@ -3,11 +3,11 @@
class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
public function isCompressed() {
- return parent::$sharedDbType === 'mysql';
+ return true;
}
public function hasNativeHex() {
- return parent::$sharedDbType !== 'sqlite';
+ return true;
}
public function sqlHexDecode($x) {
@@ -19,106 +19,40 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
}
//TODO: Move the database auto-updates to DatabaseDAO
- protected function addColumn($name) {
- Minz_Log::warning('FreshRSS_EntryDAO::addColumn: ' . $name);
- $hasTransaction = false;
+ protected function createEntryTempTable() {
+ $ok = false;
+ $hadTransaction = $this->pdo->inTransaction();
+ if ($hadTransaction) {
+ $this->pdo->commit();
+ }
try {
- $stm = null;
- if ($name === 'lastSeen') { //v1.1.1
- if (!$this->bd->inTransaction()) {
- $this->bd->beginTransaction();
- $hasTransaction = true;
- }
- $stm = $this->bd->prepare('ALTER TABLE `' . $this->prefix . 'entry` ADD COLUMN `lastSeen` INT(11) DEFAULT 0');
- if ($stm && $stm->execute()) {
- $stm = $this->bd->prepare('CREATE INDEX entry_lastSeen_index ON `' . $this->prefix . 'entry`(`lastSeen`);'); //"IF NOT EXISTS" does not exist in MySQL 5.7
- if ($stm && $stm->execute()) {
- if ($hasTransaction) {
- $this->bd->commit();
- }
- return true;
- }
- }
- if ($hasTransaction) {
- $this->bd->rollBack();
- }
- } elseif ($name === 'hash') { //v1.1.1
- $stm = $this->bd->prepare('ALTER TABLE `' . $this->prefix . 'entry` ADD COLUMN hash BINARY(16)');
- return $stm && $stm->execute();
- }
- } catch (Exception $e) {
- Minz_Log::error('FreshRSS_EntryDAO::addColumn error: ' . $e->getMessage());
- if ($hasTransaction) {
- $this->bd->rollBack();
- }
+ require(APP_PATH . '/SQL/install.sql.' . $this->pdo->dbType() . '.php');
+ Minz_Log::warning('SQL CREATE TABLE entrytmp...');
+ $ok = $this->pdo->exec($SQL_CREATE_TABLE_ENTRYTMP . $SQL_CREATE_INDEX_ENTRY_1) !== false;
+ } catch (Exception $ex) {
+ Minz_Log::error(__method__ . ' error: ' . $ex->getMessage());
}
- return false;
+ if ($hadTransaction) {
+ $this->pdo->beginTransaction();
+ }
+ return $ok;
}
- private $triedUpdateToUtf8mb4 = false;
-
- //TODO: Move the database auto-updates to DatabaseDAO
- protected function updateToUtf8mb4() {
- if ($this->triedUpdateToUtf8mb4) {
+ private function updateToMediumBlob() {
+ if ($this->pdo->dbType() !== 'mysql') {
return false;
}
- $this->triedUpdateToUtf8mb4 = true;
- $db = FreshRSS_Context::$system_conf->db;
- if ($db['type'] === 'mysql') {
- include_once(APP_PATH . '/SQL/install.sql.mysql.php');
- if (defined('SQL_UPDATE_UTF8MB4')) {
- Minz_Log::warning('Updating MySQL to UTF8MB4...'); //v1.5.0
- $hadTransaction = $this->bd->inTransaction();
- if ($hadTransaction) {
- $this->bd->commit();
- }
- $ok = false;
- try {
- $sql = sprintf(SQL_UPDATE_UTF8MB4, $this->prefix, $db['base']);
- $stm = $this->bd->prepare($sql);
- $ok = $stm->execute();
- } catch (Exception $e) {
- Minz_Log::error('FreshRSS_EntryDAO::updateToUtf8mb4 error: ' . $e->getMessage());
- }
- if ($hadTransaction) {
- $this->bd->beginTransaction();
- //NB: Transaction not starting. Why? (tested on PHP 7.0.8-0ubuntu and MySQL 5.7.13-0ubuntu)
- }
- return $ok;
- }
- }
- return false;
- }
+ Minz_Log::warning('Update MySQL table to use MEDIUMBLOB...');
- //TODO: Move the database auto-updates to DatabaseDAO
- protected function createEntryTempTable() {
- $ok = false;
- $hadTransaction = $this->bd->inTransaction();
- if ($hadTransaction) {
- $this->bd->commit();
- }
+ $sql = <<<'SQL'
+ALTER TABLE `_entry` MODIFY `content_bin` MEDIUMBLOB;
+ALTER TABLE `_entrytmp` MODIFY `content_bin` MEDIUMBLOB;
+SQL;
try {
- $db = FreshRSS_Context::$system_conf->db;
- require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php');
- Minz_Log::warning('SQL CREATE TABLE entrytmp...');
- if (defined('SQL_CREATE_TABLE_ENTRYTMP')) {
- $sql = sprintf(SQL_CREATE_TABLE_ENTRYTMP, $this->prefix);
- $stm = $this->bd->prepare($sql);
- $ok = $stm && $stm->execute();
- } else {
- global $SQL_CREATE_TABLE_ENTRYTMP;
- $ok = !empty($SQL_CREATE_TABLE_ENTRYTMP);
- foreach ($SQL_CREATE_TABLE_ENTRYTMP as $instruction) {
- $sql = sprintf($instruction, $this->prefix);
- $stm = $this->bd->prepare($sql);
- $ok &= $stm && $stm->execute();
- }
- }
+ $ok = $this->pdo->exec($sql) !== false;
} catch (Exception $e) {
- Minz_Log::error('FreshRSS_EntryDAO::createEntryTempTable error: ' . $e->getMessage());
- }
- if ($hadTransaction) {
- $this->bd->beginTransaction();
+ $ok = false;
+ Minz_Log::error(__method__ . ' error: ' . $e->getMessage());
}
return $ok;
}
@@ -126,14 +60,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
//TODO: Move the database auto-updates to DatabaseDAO
protected function autoUpdateDb($errorInfo) {
if (isset($errorInfo[0])) {
- if ($errorInfo[0] === FreshRSS_DatabaseDAO::ER_BAD_FIELD_ERROR) {
- //autoAddColumn
- foreach (array('lastSeen', 'hash') as $column) {
- if (stripos($errorInfo[2], $column) !== false) {
- return $this->addColumn($column);
- }
- }
- } elseif ($errorInfo[0] === FreshRSS_DatabaseDAO::ER_BAD_TABLE_ERROR) {
+ if ($errorInfo[0] === FreshRSS_DatabaseDAO::ER_BAD_TABLE_ERROR) {
if (stripos($errorInfo[2], 'tag') !== false) {
$tagDAO = FreshRSS_Factory::createTagDao();
return $tagDAO->createTagTable(); //v1.12.0
@@ -143,8 +70,10 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
}
}
if (isset($errorInfo[1])) {
- if ($errorInfo[1] == FreshRSS_DatabaseDAO::ER_TRUNCATED_WRONG_VALUE_FOR_FIELD) {
- return $this->updateToUtf8mb4(); //v1.5.0
+ if ($errorInfo[1] == FreshRSS_DatabaseDAO::ER_DATA_TOO_LONG) {
+ if (stripos($errorInfo[2], 'content_bin') !== false) {
+ return $this->updateToMediumBlob(); //v1.15.0
+ }
}
}
return false;
@@ -152,9 +81,9 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
private $addEntryPrepared = null;
- public function addEntry($valuesTmp) {
+ public function addEntry($valuesTmp, $useTmpTable = true) {
if ($this->addEntryPrepared == null) {
- $sql = 'INSERT INTO `' . $this->prefix . 'entrytmp` (id, guid, title, author, '
+ $sql = 'INSERT INTO `_' . ($useTmpTable ? 'entrytmp' : 'entry') . '` (id, guid, title, author, '
. ($this->isCompressed() ? 'content_bin' : 'content')
. ', link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags) '
. 'VALUES(:id, :guid, :title, :author, '
@@ -162,7 +91,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
. ', :link, :date, :last_seen, '
. $this->sqlHexDecode(':hash')
. ', :is_read, :is_favorite, :id_feed, :tags)';
- $this->addEntryPrepared = $this->bd->prepare($sql);
+ $this->addEntryPrepared = $this->pdo->prepare($sql);
}
if ($this->addEntryPrepared) {
$this->addEntryPrepared->bindParam(':id', $valuesTmp['id']);
@@ -178,7 +107,9 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
$valuesTmp['link'] = safe_ascii($valuesTmp['link']);
$this->addEntryPrepared->bindParam(':link', $valuesTmp['link']);
$this->addEntryPrepared->bindParam(':date', $valuesTmp['date'], PDO::PARAM_INT);
- $valuesTmp['lastSeen'] = time();
+ if (empty($valuesTmp['lastSeen'])) {
+ $valuesTmp['lastSeen'] = time();
+ }
$this->addEntryPrepared->bindParam(':last_seen', $valuesTmp['lastSeen'], PDO::PARAM_INT);
$valuesTmp['is_read'] = $valuesTmp['is_read'] ? 1 : 0;
$this->addEntryPrepared->bindParam(':is_read', $valuesTmp['is_read'], PDO::PARAM_INT);
@@ -191,14 +122,14 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
if ($this->hasNativeHex()) {
$this->addEntryPrepared->bindParam(':hash', $valuesTmp['hash']);
} else {
- $valuesTmp['hashBin'] = pack('H*', $valuesTmp['hash']); //hex2bin() is PHP5.4+
+ $valuesTmp['hashBin'] = hex2bin($valuesTmp['hash']);
$this->addEntryPrepared->bindParam(':hash', $valuesTmp['hashBin']);
}
}
if ($this->addEntryPrepared && $this->addEntryPrepared->execute()) {
return true;
} else {
- $info = $this->addEntryPrepared == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $this->addEntryPrepared->errorInfo();
+ $info = $this->addEntryPrepared == null ? $this->pdo->errorInfo() : $this->addEntryPrepared->errorInfo();
if ($this->autoUpdateDb($info)) {
$this->addEntryPrepared = null;
return $this->addEntry($valuesTmp);
@@ -211,22 +142,26 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
}
public function commitNewEntries() {
- $sql = 'SET @rank=(SELECT MAX(id) - COUNT(*) FROM `' . $this->prefix . 'entrytmp`); ' . //MySQL-specific
- 'INSERT IGNORE INTO `' . $this->prefix . 'entry`
- (
- id, guid, title, author, content_bin, link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags
- ) ' .
- 'SELECT @rank:=@rank+1 AS id, guid, title, author, content_bin, link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags
- FROM `' . $this->prefix . 'entrytmp`
- ORDER BY date; ' .
- 'DELETE FROM `' . $this->prefix . 'entrytmp` WHERE id <= @rank;';
- $hadTransaction = $this->bd->inTransaction();
+ $sql = <<<'SQL'
+SET @rank=(SELECT MAX(id) - COUNT(*) FROM `_entrytmp`);
+
+INSERT IGNORE INTO `_entry` (
+ id, guid, title, author, content_bin, link, date, `lastSeen`,
+ hash, is_read, is_favorite, id_feed, tags
+)
+SELECT @rank:=@rank+1 AS id, guid, title, author, content_bin, link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags
+FROM `_entrytmp`
+ORDER BY date;
+
+DELETE FROM `_entrytmp` WHERE id <= @rank;';
+SQL;
+ $hadTransaction = $this->pdo->inTransaction();
if (!$hadTransaction) {
- $this->bd->beginTransaction();
+ $this->pdo->beginTransaction();
}
- $result = $this->bd->exec($sql) !== false;
+ $result = $this->pdo->exec($sql) !== false;
if (!$hadTransaction) {
- $this->bd->commit();
+ $this->pdo->commit();
}
return $result;
}
@@ -239,7 +174,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
}
if ($this->updateEntryPrepared === null) {
- $sql = 'UPDATE `' . $this->prefix . 'entry` '
+ $sql = 'UPDATE `_entry` '
. 'SET title=:title, author=:author, '
. ($this->isCompressed() ? 'content_bin=COMPRESS(:content)' : 'content=:content')
. ', link=:link, date=:date, `lastSeen`=:last_seen, '
@@ -247,7 +182,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
. ', ' . ($valuesTmp['is_read'] === null ? '' : 'is_read=:is_read, ')
. 'tags=:tags '
. 'WHERE id_feed=:id_feed AND guid=:guid';
- $this->updateEntryPrepared = $this->bd->prepare($sql);
+ $this->updateEntryPrepared = $this->pdo->prepare($sql);
}
$valuesTmp['guid'] = substr($valuesTmp['guid'], 0, 760);
@@ -273,14 +208,14 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
if ($this->hasNativeHex()) {
$this->updateEntryPrepared->bindParam(':hash', $valuesTmp['hash']);
} else {
- $valuesTmp['hashBin'] = pack('H*', $valuesTmp['hash']); //hex2bin() is PHP5.4+
+ $valuesTmp['hashBin'] = hex2bin($valuesTmp['hash']);
$this->updateEntryPrepared->bindParam(':hash', $valuesTmp['hashBin']);
}
if ($this->updateEntryPrepared && $this->updateEntryPrepared->execute()) {
return true;
} else {
- $info = $this->updateEntryPrepared == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $this->updateEntryPrepared->errorInfo();
+ $info = $this->updateEntryPrepared == null ? $this->pdo->errorInfo() : $this->updateEntryPrepared->errorInfo();
if ($this->autoUpdateDb($info)) {
return $this->updateEntry($valuesTmp);
}
@@ -308,16 +243,16 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
return 0;
}
FreshRSS_UserDAO::touch();
- $sql = 'UPDATE `' . $this->prefix . 'entry` '
+ $sql = 'UPDATE `_entry` '
. 'SET is_favorite=? '
. 'WHERE id IN (' . str_repeat('?,', count($ids) - 1). '?)';
$values = array($is_favorite ? 1 : 0);
$values = array_merge($values, $ids);
- $stm = $this->bd->prepare($sql);
+ $stm = $this->pdo->prepare($sql);
if ($stm && $stm->execute($values)) {
return $stm->rowCount();
} else {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error markFavorite: ' . $info[2]);
return false;
}
@@ -335,11 +270,11 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
* @return boolean
*/
protected function updateCacheUnreads($catId = false, $feedId = false) {
- $sql = 'UPDATE `' . $this->prefix . 'feed` f '
+ $sql = 'UPDATE `_feed` f '
. 'LEFT OUTER JOIN ('
. 'SELECT e.id_feed, '
. 'COUNT(*) AS nbUnreads '
- . 'FROM `' . $this->prefix . 'entry` e '
+ . 'FROM `_entry` e '
. 'WHERE e.is_read=0 '
. 'GROUP BY e.id_feed'
. ') x ON x.id_feed=f.id '
@@ -358,11 +293,11 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
$sql .= ' f.category=?';
$values[] = $catId;
}
- $stm = $this->bd->prepare($sql);
+ $stm = $this->pdo->prepare($sql);
if ($stm && $stm->execute($values)) {
return true;
} else {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error updateCacheUnreads: ' . $info[2]);
return false;
}
@@ -392,14 +327,14 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
return $affected;
}
- $sql = 'UPDATE `' . $this->prefix . 'entry` '
+ $sql = 'UPDATE `_entry` '
. 'SET is_read=? '
. 'WHERE id IN (' . str_repeat('?,', count($ids) - 1). '?)';
$values = array($is_read ? 1 : 0);
$values = array_merge($values, $ids);
- $stm = $this->bd->prepare($sql);
+ $stm = $this->pdo->prepare($sql);
if (!($stm && $stm->execute($values))) {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error markRead: ' . $info[2]);
return false;
}
@@ -409,16 +344,16 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
}
return $affected;
} else {
- $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed=f.id '
+ $sql = 'UPDATE `_entry` e INNER JOIN `_feed` f ON e.id_feed=f.id '
. 'SET e.is_read=?,'
. 'f.`cache_nbUnreads`=f.`cache_nbUnreads`' . ($is_read ? '-' : '+') . '1 '
. 'WHERE e.id=? AND e.is_read=?';
$values = array($is_read ? 1 : 0, $ids, $is_read ? 0 : 1);
- $stm = $this->bd->prepare($sql);
+ $stm = $this->pdo->prepare($sql);
if ($stm && $stm->execute($values)) {
return $stm->rowCount();
} else {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error markRead: ' . $info[2]);
return false;
}
@@ -453,7 +388,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
Minz_Log::debug('Calling markReadEntries(0) is deprecated!');
}
- $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed=f.id '
+ $sql = 'UPDATE `_entry` e INNER JOIN `_feed` f ON e.id_feed=f.id '
. 'SET e.is_read=? '
. 'WHERE e.is_read <> ? AND e.id <= ?';
if ($onlyFavorites) {
@@ -465,9 +400,9 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
list($searchValues, $search) = $this->sqlListEntriesWhere('e.', $filters, $state);
- $stm = $this->bd->prepare($sql . $search);
+ $stm = $this->pdo->prepare($sql . $search);
if (!($stm && $stm->execute(array_merge($values, $searchValues)))) {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error markReadEntries: ' . $info[2]);
return false;
}
@@ -496,16 +431,16 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
Minz_Log::debug('Calling markReadCat(0) is deprecated!');
}
- $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed=f.id '
+ $sql = 'UPDATE `_entry` e INNER JOIN `_feed` f ON e.id_feed=f.id '
. 'SET e.is_read=? '
. 'WHERE f.category=? AND e.is_read <> ? AND e.id <= ?';
$values = array($is_read ? 1 : 0, $id, $is_read ? 1 : 0, $idMax);
list($searchValues, $search) = $this->sqlListEntriesWhere('e.', $filters, $state);
- $stm = $this->bd->prepare($sql . $search);
+ $stm = $this->pdo->prepare($sql . $search);
if (!($stm && $stm->execute(array_merge($values, $searchValues)))) {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error markReadCat: ' . $info[2]);
return false;
}
@@ -533,39 +468,39 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
$idMax = time() . '000000';
Minz_Log::debug('Calling markReadFeed(0) is deprecated!');
}
- $this->bd->beginTransaction();
+ $this->pdo->beginTransaction();
- $sql = 'UPDATE `' . $this->prefix . 'entry` '
+ $sql = 'UPDATE `_entry` '
. 'SET is_read=? '
. 'WHERE id_feed=? AND is_read <> ? AND id <= ?';
$values = array($is_read ? 1 : 0, $id_feed, $is_read ? 1 : 0, $idMax);
list($searchValues, $search) = $this->sqlListEntriesWhere('', $filters, $state);
- $stm = $this->bd->prepare($sql . $search);
+ $stm = $this->pdo->prepare($sql . $search);
if (!($stm && $stm->execute(array_merge($values, $searchValues)))) {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error markReadFeed: ' . $info[2] . ' with SQL: ' . $sql . $search);
- $this->bd->rollBack();
+ $this->pdo->rollBack();
return false;
}
$affected = $stm->rowCount();
if ($affected > 0) {
- $sql = 'UPDATE `' . $this->prefix . 'feed` '
+ $sql = 'UPDATE `_feed` '
. 'SET `cache_nbUnreads`=`cache_nbUnreads`-' . $affected
- . ' WHERE id=?';
- $values = array($id_feed);
- $stm = $this->bd->prepare($sql);
- if (!($stm && $stm->execute($values))) {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ . ' WHERE id=:id';
+ $stm = $this->pdo->prepare($sql);
+ $stm->bindParam(':id', $id_feed, PDO::PARAM_INT);
+ if (!($stm && $stm->execute())) {
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error markReadFeed cache: ' . $info[2]);
- $this->bd->rollBack();
+ $this->pdo->rollBack();
return false;
}
}
- $this->bd->commit();
+ $this->pdo->commit();
return $affected;
}
@@ -582,7 +517,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
Minz_Log::debug('Calling markReadTag(0) is deprecated!');
}
- $sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'entrytag` et ON et.id_entry = e.id '
+ $sql = 'UPDATE `_entry` e INNER JOIN `_entrytag` et ON et.id_entry = e.id '
. 'SET e.is_read = ? '
. 'WHERE '
. ($id == '' ? '' : 'et.id_tag = ? AND ')
@@ -596,9 +531,9 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
list($searchValues, $search) = $this->sqlListEntriesWhere('e.', $filters, $state);
- $stm = $this->bd->prepare($sql . $search);
+ $stm = $this->pdo->prepare($sql . $search);
if (!($stm && $stm->execute(array_merge($values, $searchValues)))) {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error markReadTag: ' . $info[2]);
return false;
}
@@ -609,48 +544,86 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
return $affected;
}
- public function cleanOldEntries($id_feed, $date_min, $keep = 15) { //Remember to call updateCachedValue($id_feed) or updateCachedValues() just after
- $sql = 'DELETE FROM `' . $this->prefix . 'entry` '
- . 'WHERE id_feed=:id_feed AND id<=:id_max '
- . 'AND is_favorite=0 ' //Do not remove favourites
- . 'AND `lastSeen` < (SELECT maxLastSeen FROM (SELECT (MAX(e3.`lastSeen`)-99) AS maxLastSeen FROM `' . $this->prefix . 'entry` e3 WHERE e3.id_feed=:id_feed) recent) ' //Do not remove the most newly seen articles, plus a few seconds of tolerance
- . 'AND id NOT IN (SELECT id_entry FROM `' . $this->prefix . 'entrytag`) ' //Do not purge tagged entries
- . 'AND id NOT IN (SELECT id FROM (SELECT e2.id FROM `' . $this->prefix . 'entry` e2 WHERE e2.id_feed=:id_feed ORDER BY id DESC LIMIT :keep) keep)'; //Double select: MySQL doesn't support 'LIMIT & IN/ALL/ANY/SOME subquery'
- $stm = $this->bd->prepare($sql);
+ public function cleanOldEntries($id_feed, $options = []) { //Remember to call updateCachedValue($id_feed) or updateCachedValues() just after
+ $sql = 'DELETE FROM `_entry` WHERE id_feed = :id_feed1'; //No alias for MySQL / MariaDB
+ $params = [];
+ $params[':id_feed1'] = $id_feed;
- if ($stm) {
- $id_max = intval($date_min) . '000000';
- $stm->bindParam(':id_feed', $id_feed, PDO::PARAM_INT);
- $stm->bindParam(':id_max', $id_max, PDO::PARAM_STR);
- $stm->bindParam(':keep', $keep, PDO::PARAM_INT);
+ //==Exclusions==
+ if (!empty($options['keep_favourites'])) {
+ $sql .= ' AND is_favorite = 0';
+ }
+ if (!empty($options['keep_unreads'])) {
+ $sql .= ' AND is_read = 1';
+ }
+ if (!empty($options['keep_labels'])) {
+ $sql .= ' AND NOT EXISTS (SELECT 1 FROM `_entrytag` WHERE id_entry = id)';
+ }
+ if (!empty($options['keep_min']) && $options['keep_min'] > 0) {
+ //Double SELECT for MySQL workaround ERROR 1093 (HY000)
+ $sql .= ' AND `lastSeen` < (SELECT `lastSeen`'
+ . ' FROM (SELECT e2.`lastSeen` FROM `_entry` e2 WHERE e2.id_feed = :id_feed2'
+ . ' ORDER BY e2.`lastSeen` DESC LIMIT 1 OFFSET :keep_min) last_seen2)';
+ $params[':id_feed2'] = $id_feed;
+ $params[':keep_min'] = (int)$options['keep_min'];
+ }
+ //Keep at least the articles seen at the last refresh
+ $sql .= ' AND `lastSeen` < (SELECT maxlastseen'
+ . ' FROM (SELECT MAX(e3.`lastSeen`) AS maxlastseen FROM `_entry` e3 WHERE e3.id_feed = :id_feed3) last_seen3)';
+ $params[':id_feed3'] = $id_feed;
+
+ //==Inclusions==
+ $sql .= ' AND (1=0';
+ if (!empty($options['keep_period'])) {
+ $sql .= ' OR `lastSeen` < :max_last_seen';
+ $now = new DateTime('now');
+ $now->sub(new DateInterval($options['keep_period']));
+ $params[':max_last_seen'] = $now->format('U');
}
+ if (!empty($options['keep_max']) && $options['keep_max'] > 0) {
+ $sql .= ' OR `lastSeen` <= (SELECT `lastSeen`'
+ . ' FROM (SELECT e4.`lastSeen` FROM `_entry` e4 WHERE e4.id_feed = :id_feed4'
+ . ' ORDER BY e4.`lastSeen` DESC LIMIT 1 OFFSET :keep_max) last_seen4)';
+ $params[':id_feed4'] = $id_feed;
+ $params[':keep_max'] = (int)$options['keep_max'];
+ }
+ $sql .= ')';
+
+ $stm = $this->pdo->prepare($sql);
- if ($stm && $stm->execute()) {
+ if ($stm && $stm->execute($params)) {
return $stm->rowCount();
} else {
- $info = $stm == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
if ($this->autoUpdateDb($info)) {
- return $this->cleanOldEntries($id_feed, $date_min, $keep);
+ return $this->cleanOldEntries($id_feed, $options);
}
- Minz_Log::error('SQL error cleanOldEntries: ' . $info[2]);
+ Minz_Log::error(__method__ . ' error:' . json_encode($info));
return false;
}
}
+ public function selectAll() {
+ $sql = 'SELECT id, guid, title, author, '
+ . ($this->isCompressed() ? 'UNCOMPRESS(content_bin) AS content' : 'content')
+ . ', link, date, `lastSeen`, ' . $this->sqlHexEncode('hash') . ' AS hash, is_read, is_favorite, id_feed, tags '
+ . 'FROM `_entry`';
+ $stm = $this->pdo->query($sql);
+ while ($row = $stm->fetch(PDO::FETCH_ASSOC)) {
+ yield $row;
+ }
+ }
+
public function searchByGuid($id_feed, $guid) {
// un guid est unique pour un flux donné
$sql = 'SELECT id, guid, title, author, '
. ($this->isCompressed() ? 'UNCOMPRESS(content_bin) AS content' : 'content')
. ', link, date, is_read, is_favorite, id_feed, tags '
- . 'FROM `' . $this->prefix . 'entry` WHERE id_feed=? AND guid=?';
- $stm = $this->bd->prepare($sql);
-
- $values = array(
- $id_feed,
- $guid,
- );
-
- $stm->execute($values);
+ . 'FROM `_entry` WHERE id_feed=:id_feed AND guid=:guid';
+ $stm = $this->pdo->prepare($sql);
+ $stm->bindParam(':id_feed', $id_feed, PDO::PARAM_INT);
+ $stm->bindParam(':guid', $guid);
+ $stm->execute();
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
$entries = self::daoToEntries($res);
return isset($entries[0]) ? $entries[0] : null;
@@ -660,22 +633,21 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
$sql = 'SELECT id, guid, title, author, '
. ($this->isCompressed() ? 'UNCOMPRESS(content_bin) AS content' : 'content')
. ', link, date, is_read, is_favorite, id_feed, tags '
- . 'FROM `' . $this->prefix . 'entry` WHERE id=?';
- $stm = $this->bd->prepare($sql);
-
- $values = array($id);
-
- $stm->execute($values);
+ . 'FROM `_entry` WHERE id=:id';
+ $stm = $this->pdo->prepare($sql);
+ $stm->bindParam(':id', $id, PDO::PARAM_INT);
+ $stm->execute();
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
$entries = self::daoToEntries($res);
return isset($entries[0]) ? $entries[0] : null;
}
public function searchIdByGuid($id_feed, $guid) {
- $sql = 'SELECT id FROM `' . $this->prefix . 'entry` WHERE id_feed=? AND guid=?';
- $stm = $this->bd->prepare($sql);
- $values = array($id_feed, $guid);
- $stm->execute($values);
+ $sql = 'SELECT id FROM `_entry` WHERE id_feed=:id_feed AND guid=:guid';
+ $stm = $this->pdo->prepare($sql);
+ $stm->bindParam(':id_feed', $id_feed, PDO::PARAM_INT);
+ $stm->bindParam(':guid', $guid);
+ $stm->execute();
$res = $stm->fetchAll(PDO::FETCH_COLUMN, 0);
return isset($res[0]) ? $res[0] : null;
}
@@ -859,7 +831,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
$where .= '1=1 ';
break;
case 'ST': //Starred or tagged
- $where .= 'e.is_favorite=1 OR EXISTS (SELECT et2.id_tag FROM `' . $this->prefix . 'entrytag` et2 WHERE et2.id_entry = e.id) ';
+ $where .= 'e.is_favorite=1 OR EXISTS (SELECT et2.id_tag FROM `_entrytag` et2 WHERE et2.id_entry = e.id) ';
break;
default:
throw new FreshRSS_EntriesGetter_Exception('Bad type in Entry->listByType: [' . $type . ']!');
@@ -870,9 +842,9 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
return array(array_merge($values, $searchValues),
'SELECT '
. ($type === 'T' ? 'DISTINCT ' : '')
- . 'e.id FROM `' . $this->prefix . 'entry` e '
- . 'INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
- . ($type === 't' || $type === 'T' ? 'INNER JOIN `' . $this->prefix . 'entrytag` et ON et.id_entry = e.id ' : '')
+ . 'e.id FROM `_entry` e '
+ . 'INNER JOIN `_feed` f ON e.id_feed = f.id '
+ . ($type === 't' || $type === 'T' ? 'INNER JOIN `_entrytag` et ON et.id_entry = e.id ' : '')
. 'WHERE ' . $where
. $search
. 'ORDER BY e.id ' . $order
@@ -885,17 +857,17 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
$sql = 'SELECT e0.id, e0.guid, e0.title, e0.author, '
. ($this->isCompressed() ? 'UNCOMPRESS(content_bin) AS content' : 'content')
. ', e0.link, e0.date, e0.is_read, e0.is_favorite, e0.id_feed, e0.tags '
- . 'FROM `' . $this->prefix . 'entry` e0 '
+ . 'FROM `_entry` e0 '
. 'INNER JOIN ('
. $sql
. ') e2 ON e2.id=e0.id '
. 'ORDER BY e0.id ' . $order;
- $stm = $this->bd->prepare($sql);
+ $stm = $this->pdo->prepare($sql);
if ($stm && $stm->execute($values)) {
return $stm;
} else {
- $info = $stm == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error listWhereRaw: ' . $info[2]);
return false;
}
@@ -918,11 +890,11 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
$sql = 'SELECT id, guid, title, author, '
. ($this->isCompressed() ? 'UNCOMPRESS(content_bin) AS content' : 'content')
. ', link, date, is_read, is_favorite, id_feed, tags '
- . 'FROM `' . $this->prefix . 'entry` '
+ . 'FROM `_entry` '
. 'WHERE id IN (' . str_repeat('?,', count($ids) - 1). '?) '
. 'ORDER BY id ' . $order;
- $stm = $this->bd->prepare($sql);
+ $stm = $this->pdo->prepare($sql);
$stm->execute($ids);
return self::daoToEntries($stm->fetchAll(PDO::FETCH_ASSOC));
}
@@ -930,7 +902,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
public function listIdsWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filters = null) { //For API
list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filters);
- $stm = $this->bd->prepare($sql);
+ $stm = $this->pdo->prepare($sql);
$stm->execute($values);
return $stm->fetchAll(PDO::FETCH_COLUMN, 0);
@@ -941,8 +913,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
return array();
}
$guids = array_unique($guids);
- $sql = 'SELECT guid, ' . $this->sqlHexEncode('hash') . ' AS hex_hash FROM `' . $this->prefix . 'entry` WHERE id_feed=? AND guid IN (' . str_repeat('?,', count($guids) - 1). '?)';
- $stm = $this->bd->prepare($sql);
+ $sql = 'SELECT guid, ' . $this->sqlHexEncode('hash') . ' AS hex_hash FROM `_entry` WHERE id_feed=? AND guid IN (' . str_repeat('?,', count($guids) - 1). '?)';
+ $stm = $this->pdo->prepare($sql);
$values = array($id_feed);
$values = array_merge($values, $guids);
if ($stm && $stm->execute($values)) {
@@ -953,7 +925,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
}
return $result;
} else {
- $info = $stm == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
if ($this->autoUpdateDb($info)) {
return $this->listHashForFeedGuids($id_feed, $guids);
}
@@ -967,8 +939,8 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
if (count($guids) < 1) {
return 0;
}
- $sql = 'UPDATE `' . $this->prefix . 'entry` SET `lastSeen`=? WHERE id_feed=? AND guid IN (' . str_repeat('?,', count($guids) - 1). '?)';
- $stm = $this->bd->prepare($sql);
+ $sql = 'UPDATE `_entry` SET `lastSeen`=? WHERE id_feed=? AND guid IN (' . str_repeat('?,', count($guids) - 1). '?)';
+ $stm = $this->pdo->prepare($sql);
if ($mtime <= 0) {
$mtime = time();
}
@@ -977,7 +949,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
if ($stm && $stm->execute($values)) {
return $stm->rowCount();
} else {
- $info = $stm == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
if ($this->autoUpdateDb($info)) {
return $this->updateLastSeen($id_feed, $guids);
}
@@ -988,65 +960,70 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
}
public function countUnreadRead() {
- $sql = 'SELECT COUNT(e.id) AS count FROM `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed=f.id WHERE f.priority > 0'
- . ' UNION SELECT COUNT(e.id) AS count FROM `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed=f.id WHERE f.priority > 0 AND e.is_read=0';
- $stm = $this->bd->prepare($sql);
- $stm->execute();
+ $sql = 'SELECT COUNT(e.id) AS count FROM `_entry` e INNER JOIN `_feed` f ON e.id_feed=f.id WHERE f.priority > 0'
+ . ' UNION SELECT COUNT(e.id) AS count FROM `_entry` e INNER JOIN `_feed` f ON e.id_feed=f.id WHERE f.priority > 0 AND e.is_read=0';
+ $stm = $this->pdo->query($sql);
+ if ($stm === false) {
+ return false;
+ }
$res = $stm->fetchAll(PDO::FETCH_COLUMN, 0);
rsort($res);
$all = empty($res[0]) ? 0 : $res[0];
$unread = empty($res[1]) ? 0 : $res[1];
return array('all' => $all, 'unread' => $unread, 'read' => $all - $unread);
}
+
public function count($minPriority = null) {
- $sql = 'SELECT COUNT(e.id) AS count FROM `' . $this->prefix . 'entry` e';
+ $sql = 'SELECT COUNT(e.id) AS count FROM `_entry` e';
if ($minPriority !== null) {
- $sql .= ' INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed=f.id';
+ $sql .= ' INNER JOIN `_feed` f ON e.id_feed=f.id';
$sql .= ' WHERE f.priority > ' . intval($minPriority);
}
- $stm = $this->bd->prepare($sql);
- $stm->execute();
+ $stm = $this->pdo->query($sql);
+ if ($stm == false) {
+ return false;
+ }
$res = $stm->fetchAll(PDO::FETCH_COLUMN, 0);
return isset($res[0]) ? $res[0] : 0;
}
+
public function countNotRead($minPriority = null) {
- $sql = 'SELECT COUNT(e.id) AS count FROM `' . $this->prefix . 'entry` e';
+ $sql = 'SELECT COUNT(e.id) AS count FROM `_entry` e';
if ($minPriority !== null) {
- $sql .= ' INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed=f.id';
+ $sql .= ' INNER JOIN `_feed` f ON e.id_feed=f.id';
}
$sql .= ' WHERE e.is_read=0';
if ($minPriority !== null) {
$sql .= ' AND f.priority > ' . intval($minPriority);
}
- $stm = $this->bd->prepare($sql);
- $stm->execute();
+ $stm = $this->pdo->query($sql);
$res = $stm->fetchAll(PDO::FETCH_COLUMN, 0);
return $res[0];
}
public function countUnreadReadFavorites() {
- $sql = <<<SQL
- SELECT c
- FROM (
- SELECT COUNT(e1.id) AS c
- , 1 AS o
- FROM `{$this->prefix}entry` AS e1
- JOIN `{$this->prefix}feed` AS f1 ON e1.id_feed = f1.id
- WHERE e1.is_favorite = 1
- AND f1.priority >= :priority_normal
- UNION
- SELECT COUNT(e2.id) AS c
- , 2 AS o
- FROM `{$this->prefix}entry` AS e2
- JOIN `{$this->prefix}feed` AS f2 ON e2.id_feed = f2.id
- WHERE e2.is_favorite = 1
- AND e2.is_read = 0
- AND f2.priority >= :priority_normal
- ) u
+ $sql = <<<'SQL'
+SELECT c FROM (
+ SELECT COUNT(e1.id) AS c, 1 AS o
+ FROM `_entry` AS e1
+ JOIN `_feed` AS f1 ON e1.id_feed = f1.id
+ WHERE e1.is_favorite = 1
+ AND f1.priority >= :priority_normal1
+ UNION
+ SELECT COUNT(e2.id) AS c, 2 AS o
+ FROM `_entry` AS e2
+ JOIN `_feed` AS f2 ON e2.id_feed = f2.id
+ WHERE e2.is_favorite = 1
+ AND e2.is_read = 0
+ AND f2.priority >= :priority_normal2
+ ) u
ORDER BY o
SQL;
- $stm = $this->bd->prepare($sql);
- $stm->execute(array(':priority_normal' => FreshRSS_Feed::PRIORITY_NORMAL));
+ $stm = $this->pdo->prepare($sql);
+ //Binding a value more than once is not standard and does not work with native prepared statements (e.g. MySQL) https://bugs.php.net/bug.php?id=40417
+ $stm->bindValue(':priority_normal1', FreshRSS_Feed::PRIORITY_NORMAL, PDO::PARAM_INT);
+ $stm->bindValue(':priority_normal2', FreshRSS_Feed::PRIORITY_NORMAL, PDO::PARAM_INT);
+ $stm->execute();
$res = $stm->fetchAll(PDO::FETCH_COLUMN, 0);
rsort($res);
$all = empty($res[0]) ? 0 : $res[0];
diff --git a/app/Models/EntryDAOPGSQL.php b/app/Models/EntryDAOPGSQL.php
index e571e457f..9afea279f 100644
--- a/app/Models/EntryDAOPGSQL.php
+++ b/app/Models/EntryDAOPGSQL.php
@@ -2,6 +2,10 @@
class FreshRSS_EntryDAOPGSQL extends FreshRSS_EntryDAOSQLite {
+ public function hasNativeHex() {
+ return true;
+ }
+
public function sqlHexDecode($x) {
return 'decode(' . $x . ", 'hex')";
}
@@ -31,25 +35,27 @@ class FreshRSS_EntryDAOPGSQL extends FreshRSS_EntryDAOSQLite {
public function commitNewEntries() {
$sql = 'DO $$
DECLARE
-maxrank bigint := (SELECT MAX(id) FROM `' . $this->prefix . 'entrytmp`);
-rank bigint := (SELECT maxrank - COUNT(*) FROM `' . $this->prefix . 'entrytmp`);
+maxrank bigint := (SELECT MAX(id) FROM `_entrytmp`);
+rank bigint := (SELECT maxrank - COUNT(*) FROM `_entrytmp`);
BEGIN
- INSERT INTO `' . $this->prefix . 'entry` (id, guid, title, author, content, link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags)
- (SELECT rank + row_number() OVER(ORDER BY date) AS id, guid, title, author, content, link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags
- FROM `' . $this->prefix . 'entrytmp` AS etmp
+ INSERT INTO `_entry`
+ (id, guid, title, author, content, link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags)
+ (SELECT rank + row_number() OVER(ORDER BY date) AS id, guid, title, author, content,
+ link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags
+ FROM `_entrytmp` AS etmp
WHERE NOT EXISTS (
- SELECT 1 FROM `' . $this->prefix . 'entry` AS ereal
+ SELECT 1 FROM `_entry` AS ereal
WHERE (etmp.id = ereal.id) OR (etmp.id_feed = ereal.id_feed AND etmp.guid = ereal.guid))
ORDER BY date);
- DELETE FROM `' . $this->prefix . 'entrytmp` WHERE id <= maxrank;
+ DELETE FROM `_entrytmp` WHERE id <= maxrank;
END $$;';
- $hadTransaction = $this->bd->inTransaction();
+ $hadTransaction = $this->pdo->inTransaction();
if (!$hadTransaction) {
- $this->bd->beginTransaction();
+ $this->pdo->beginTransaction();
}
- $result = $this->bd->exec($sql) !== false;
+ $result = $this->pdo->exec($sql) !== false;
if (!$hadTransaction) {
- $this->bd->commit();
+ $this->pdo->commit();
}
return $result;
}
diff --git a/app/Models/EntryDAOSQLite.php b/app/Models/EntryDAOSQLite.php
index f8cd14fe6..12e8f27e1 100644
--- a/app/Models/EntryDAOSQLite.php
+++ b/app/Models/EntryDAOSQLite.php
@@ -2,32 +2,32 @@
class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO {
+ public function isCompressed() {
+ return false;
+ }
+
+ public function hasNativeHex() {
+ return false;
+ }
+
public function sqlHexDecode($x) {
return $x;
}
protected function autoUpdateDb($errorInfo) {
- if ($tableInfo = $this->bd->query("SELECT sql FROM sqlite_master where name='tag'")) {
+ if ($tableInfo = $this->pdo->query("SELECT sql FROM sqlite_master where name='tag'")) {
$showCreate = $tableInfo->fetchColumn();
if (stripos($showCreate, 'tag') === false) {
$tagDAO = FreshRSS_Factory::createTagDao();
return $tagDAO->createTagTable(); //v1.12.0
}
}
- if ($tableInfo = $this->bd->query("SELECT sql FROM sqlite_master where name='entrytmp'")) {
+ if ($tableInfo = $this->pdo->query("SELECT sql FROM sqlite_master where name='entrytmp'")) {
$showCreate = $tableInfo->fetchColumn();
if (stripos($showCreate, 'entrytmp') === false) {
return $this->createEntryTempTable(); //v1.7.0
}
}
- if ($tableInfo = $this->bd->query("SELECT sql FROM sqlite_master where name='entry'")) {
- $showCreate = $tableInfo->fetchColumn();
- foreach (array('lastSeen', 'hash') as $column) {
- if (stripos($showCreate, $column) === false) {
- return $this->addColumn($column);
- }
- }
- }
return false;
}
@@ -36,27 +36,27 @@ class FreshRSS_EntryDAOSQLite extends FreshRSS_EntryDAO {
DROP TABLE IF EXISTS `tmp`;
CREATE TEMP TABLE `tmp` AS
SELECT id, guid, title, author, content, link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags
- FROM `' . $this->prefix . 'entrytmp`
+ FROM `_entrytmp`
ORDER BY date;
-INSERT OR IGNORE INTO `' . $this->prefix . 'entry`
+INSERT OR IGNORE INTO `_entry`
(id, guid, title, author, content, link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags)
SELECT rowid + (SELECT MAX(id) - COUNT(*) FROM `tmp`) AS id,
guid, title, author, content, link, date, `lastSeen`, hash, is_read, is_favorite, id_feed, tags
FROM `tmp`
ORDER BY date;
-DELETE FROM `' . $this->prefix . 'entrytmp` WHERE id <= (SELECT MAX(id) FROM `tmp`);
+DELETE FROM `_entrytmp` WHERE id <= (SELECT MAX(id) FROM `tmp`);
DROP TABLE IF EXISTS `tmp`;
';
- $hadTransaction = $this->bd->inTransaction();
+ $hadTransaction = $this->pdo->inTransaction();
if (!$hadTransaction) {
- $this->bd->beginTransaction();
+ $this->pdo->beginTransaction();
}
- $result = $this->bd->exec($sql) !== false;
+ $result = $this->pdo->exec($sql) !== false;
if (!$result) {
- Minz_Log::error('SQL error commitNewEntries: ' . json_encode($this->bd->errorInfo()));
+ Minz_Log::error('SQL error commitNewEntries: ' . json_encode($this->pdo->errorInfo()));
}
if (!$hadTransaction) {
- $this->bd->commit();
+ $this->pdo->commit();
}
return $result;
}
@@ -66,10 +66,10 @@ DROP TABLE IF EXISTS `tmp`;
}
protected function updateCacheUnreads($catId = false, $feedId = false) {
- $sql = 'UPDATE `' . $this->prefix . 'feed` '
+ $sql = 'UPDATE `_feed` '
. 'SET `cache_nbUnreads`=('
- . 'SELECT COUNT(*) AS nbUnreads FROM `' . $this->prefix . 'entry` e '
- . 'WHERE e.id_feed=`' . $this->prefix . 'feed`.id AND e.is_read=0)';
+ . 'SELECT COUNT(*) AS nbUnreads FROM `_entry` e '
+ . 'WHERE e.id_feed=`_feed`.id AND e.is_read=0)';
$hasWhere = false;
$values = array();
if ($feedId !== false) {
@@ -84,11 +84,11 @@ DROP TABLE IF EXISTS `tmp`;
$sql .= ' category=?';
$values[] = $catId;
}
- $stm = $this->bd->prepare($sql);
+ $stm = $this->pdo->prepare($sql);
if ($stm && $stm->execute($values)) {
return true;
} else {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error updateCacheUnreads: ' . $info[2]);
return false;
}
@@ -118,30 +118,30 @@ DROP TABLE IF EXISTS `tmp`;
return $affected;
}
} else {
- $this->bd->beginTransaction();
- $sql = 'UPDATE `' . $this->prefix . 'entry` SET is_read=? WHERE id=? AND is_read=?';
+ $this->pdo->beginTransaction();
+ $sql = 'UPDATE `_entry` SET is_read=? WHERE id=? AND is_read=?';
$values = array($is_read ? 1 : 0, $ids, $is_read ? 0 : 1);
- $stm = $this->bd->prepare($sql);
+ $stm = $this->pdo->prepare($sql);
if (!($stm && $stm->execute($values))) {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error markRead 1: ' . $info[2]);
- $this->bd->rollBack();
+ $this->pdo->rollBack();
return false;
}
$affected = $stm->rowCount();
if ($affected > 0) {
- $sql = 'UPDATE `' . $this->prefix . 'feed` SET `cache_nbUnreads`=`cache_nbUnreads`' . ($is_read ? '-' : '+') . '1 '
- . 'WHERE id=(SELECT e.id_feed FROM `' . $this->prefix . 'entry` e WHERE e.id=?)';
+ $sql = 'UPDATE `_feed` SET `cache_nbUnreads`=`cache_nbUnreads`' . ($is_read ? '-' : '+') . '1 '
+ . 'WHERE id=(SELECT e.id_feed FROM `_entry` e WHERE e.id=?)';
$values = array($ids);
- $stm = $this->bd->prepare($sql);
+ $stm = $this->pdo->prepare($sql);
if (!($stm && $stm->execute($values))) {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error markRead 2: ' . $info[2]);
- $this->bd->rollBack();
+ $this->pdo->rollBack();
return false;
}
}
- $this->bd->commit();
+ $this->pdo->commit();
return $affected;
}
}
@@ -174,19 +174,19 @@ DROP TABLE IF EXISTS `tmp`;
Minz_Log::debug('Calling markReadEntries(0) is deprecated!');
}
- $sql = 'UPDATE `' . $this->prefix . 'entry` SET is_read = ? WHERE is_read <> ? AND id <= ?';
+ $sql = 'UPDATE `_entry` SET is_read = ? WHERE is_read <> ? AND id <= ?';
if ($onlyFavorites) {
$sql .= ' AND is_favorite=1';
} elseif ($priorityMin >= 0) {
- $sql .= ' AND id_feed IN (SELECT f.id FROM `' . $this->prefix . 'feed` f WHERE f.priority > ' . intval($priorityMin) . ')';
+ $sql .= ' AND id_feed IN (SELECT f.id FROM `_feed` f WHERE f.priority > ' . intval($priorityMin) . ')';
}
$values = array($is_read ? 1 : 0, $is_read ? 1 : 0, $idMax);
list($searchValues, $search) = $this->sqlListEntriesWhere('', $filters, $state);
- $stm = $this->bd->prepare($sql . $search);
+ $stm = $this->pdo->prepare($sql . $search);
if (!($stm && $stm->execute(array_merge($values, $searchValues)))) {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error markReadEntries: ' . $info[2]);
return false;
}
@@ -215,17 +215,17 @@ DROP TABLE IF EXISTS `tmp`;
Minz_Log::debug('Calling markReadCat(0) is deprecated!');
}
- $sql = 'UPDATE `' . $this->prefix . 'entry` '
+ $sql = 'UPDATE `_entry` '
. 'SET is_read = ? '
. 'WHERE is_read <> ? AND id <= ? AND '
- . 'id_feed IN (SELECT f.id FROM `' . $this->prefix . 'feed` f WHERE f.category=?)';
+ . 'id_feed IN (SELECT f.id FROM `_feed` f WHERE f.category=?)';
$values = array($is_read ? 1 : 0, $is_read ? 1 : 0, $idMax, $id);
list($searchValues, $search) = $this->sqlListEntriesWhere('', $filters, $state);
- $stm = $this->bd->prepare($sql . $search);
+ $stm = $this->pdo->prepare($sql . $search);
if (!($stm && $stm->execute(array_merge($values, $searchValues)))) {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error markReadCat: ' . $info[2]);
return false;
}
@@ -249,10 +249,10 @@ DROP TABLE IF EXISTS `tmp`;
Minz_Log::debug('Calling markReadTag(0) is deprecated!');
}
- $sql = 'UPDATE `' . $this->prefix . 'entry` e '
+ $sql = 'UPDATE `_entry` e '
. 'SET e.is_read = ? '
. 'WHERE e.is_read <> ? AND e.id <= ? AND '
- . 'e.id IN (SELECT et.id_entry FROM `' . $this->prefix . 'entrytag` et '
+ . 'e.id IN (SELECT et.id_entry FROM `_entrytag` et '
. ($id == '' ? '' : 'WHERE et.id = ?')
. ')';
$values = array($is_read ? 1 : 0, $is_read ? 1 : 0, $idMax);
@@ -262,9 +262,9 @@ DROP TABLE IF EXISTS `tmp`;
list($searchValues, $search) = $this->sqlListEntriesWhere('e.', $filters, $state);
- $stm = $this->bd->prepare($sql . $search);
+ $stm = $this->pdo->prepare($sql . $search);
if (!($stm && $stm->execute(array_merge($values, $searchValues)))) {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error markReadTag: ' . $info[2]);
return false;
}
diff --git a/app/Models/Factory.php b/app/Models/Factory.php
index 1accb491c..69885c205 100644
--- a/app/Models/Factory.php
+++ b/app/Models/Factory.php
@@ -2,8 +2,18 @@
class FreshRSS_Factory {
+ public static function createUserDao($username = null) {
+ return new FreshRSS_UserDAO($username);
+ }
+
public static function createCategoryDao($username = null) {
- return new FreshRSS_CategoryDAO($username);
+ $conf = Minz_Configuration::get('system');
+ switch ($conf->db['type']) {
+ case 'sqlite':
+ return new FreshRSS_CategoryDAOSQLite($username);
+ default:
+ return new FreshRSS_CategoryDAO($username);
+ }
}
public static function createFeedDao($username = null) {
diff --git a/app/Models/Feed.php b/app/Models/Feed.php
index 89989236c..0a45a1f4c 100644
--- a/app/Models/Feed.php
+++ b/app/Models/Feed.php
@@ -7,8 +7,8 @@ class FreshRSS_Feed extends Minz_Model {
const TTL_DEFAULT = 0;
- const KEEP_HISTORY_DEFAULT = -2;
- const KEEP_HISTORY_INFINITE = -1;
+ const ARCHIVING_RETENTION_COUNT_LIMIT = 10000;
+ const ARCHIVING_RETENTION_PERIOD = 'P3M';
private $id = 0;
private $url;
@@ -24,9 +24,8 @@ class FreshRSS_Feed extends Minz_Model {
private $pathEntries = '';
private $httpAuth = '';
private $error = false;
- private $keep_history = self::KEEP_HISTORY_DEFAULT;
private $ttl = self::TTL_DEFAULT;
- private $attributes = array();
+ private $attributes = [];
private $mute = false;
private $hash = null;
private $lockPath = '';
@@ -110,9 +109,6 @@ class FreshRSS_Feed extends Minz_Model {
public function inError() {
return $this->error;
}
- public function keepHistory() {
- return $this->keep_history;
- }
public function ttl() {
return $this->ttl;
}
@@ -153,18 +149,17 @@ class FreshRSS_Feed extends Minz_Model {
return $this->nbNotRead;
}
public function faviconPrepare() {
- global $favicons_dir;
require_once(LIB_PATH . '/favicons.php');
$url = $this->website;
if ($url == '') {
$url = $this->url;
}
- $txt = $favicons_dir . $this->hash() . '.txt';
+ $txt = FAVICONS_DIR . $this->hash() . '.txt';
if (!file_exists($txt)) {
file_put_contents($txt, $url);
}
if (FreshRSS_Context::$isCli) {
- $ico = $favicons_dir . $this->hash() . '.ico';
+ $ico = FAVICONS_DIR . $this->hash() . '.ico';
$ico_mtime = @filemtime($ico);
$txt_mtime = @filemtime($txt);
if ($txt_mtime != false &&
@@ -231,12 +226,6 @@ class FreshRSS_Feed extends Minz_Model {
public function _error($value) {
$this->error = (bool)$value;
}
- public function _keepHistory($value) {
- $value = intval($value);
- $value = min($value, 1000000);
- $value = max($value, self::KEEP_HISTORY_DEFAULT);
- $this->keep_history = $value;
- }
public function _ttl($value) {
$value = intval($value);
$value = min($value, 100000000);
@@ -470,6 +459,28 @@ class FreshRSS_Feed extends Minz_Model {
$this->entries = $entries;
}
+ public function cleanOldEntries() { //Remember to call updateCachedValue($id_feed) or updateCachedValues() just after
+ $archiving = $this->attributes('archiving');
+ if ($archiving == null) {
+ $catDAO = FreshRSS_Factory::createCategoryDao();
+ $category = $catDAO->searchById($this->category());
+ $archiving = $category == null ? null : $category->attributes('archiving');
+ if ($archiving == null) {
+ $archiving = FreshRSS_Context::$user_conf->archiving;
+ }
+ }
+ if (is_array($archiving)) {
+ $entryDAO = FreshRSS_Factory::createEntryDao();
+ $nb = $entryDAO->cleanOldEntries($this->id(), $archiving);
+ if ($nb > 0) {
+ $needFeedCacheRefresh = true;
+ Minz_Log::debug($nb . ' entries cleaned in feed [' . $this->url(false) . '] with: ' . json_encode($archiving));
+ }
+ return $nb;
+ }
+ return false;
+ }
+
protected function cacheFilename() {
return CACHE_PATH . '/' . md5($this->url) . '.spc';
}
@@ -701,7 +712,7 @@ class FreshRSS_Feed extends Minz_Model {
file_put_contents($hubFilename, json_encode($hubJson));
}
$ch = curl_init();
- curl_setopt_array($ch, array(
+ curl_setopt_array($ch, [
CURLOPT_URL => $hubJson['hub'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POSTFIELDS => http_build_query(array(
@@ -712,13 +723,9 @@ class FreshRSS_Feed extends Minz_Model {
)),
CURLOPT_USERAGENT => FRESHRSS_USERAGENT,
CURLOPT_MAXREDIRS => 10,
- ));
- if (version_compare(PHP_VERSION, '5.6.0') >= 0 || ini_get('open_basedir') == '') {
- curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); //Keep option separated for open_basedir PHP bug 65646
- }
- if (defined('CURLOPT_ENCODING')) {
- curl_setopt($ch, CURLOPT_ENCODING, ''); //Enable all encodings
- }
+ CURLOPT_FOLLOWLOCATION => true,
+ CURLOPT_ENCODING => '', //Enable all encodings
+ ]);
$response = curl_exec($ch);
$info = curl_getinfo($ch);
diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php
index c9c9f6301..fa0001df7 100644
--- a/app/Models/FeedDAO.php
+++ b/app/Models/FeedDAO.php
@@ -3,14 +3,13 @@
class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
protected function addColumn($name) {
- Minz_Log::warning('FreshRSS_FeedDAO::addColumn: ' . $name);
+ Minz_Log::warning(__method__ . ': ' . $name);
try {
if ($name === 'attributes') { //v1.11.0
- $stm = $this->bd->prepare('ALTER TABLE `' . $this->prefix . 'feed` ADD COLUMN attributes TEXT');
- return $stm && $stm->execute();
+ return $this->pdo->exec('ALTER TABLE `_feed` ADD COLUMN attributes TEXT') !== false;
}
} catch (Exception $e) {
- Minz_Log::error('FreshRSS_FeedDAO::addColumn error: ' . $e->getMessage());
+ Minz_Log::error(__method__ . ' error: ' . $e->getMessage());
}
return false;
}
@@ -18,7 +17,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
protected function autoUpdateDb($errorInfo) {
if (isset($errorInfo[0])) {
if ($errorInfo[0] === FreshRSS_DatabaseDAO::ER_BAD_FIELD_ERROR || $errorInfo[0] === FreshRSS_DatabaseDAOPGSQL::UNDEFINED_COLUMN) {
- foreach (array('attributes') as $column) {
+ foreach (['attributes'] as $column) {
if (stripos($errorInfo[2], $column) !== false) {
return $this->addColumn($column);
}
@@ -30,7 +29,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
public function addFeed($valuesTmp) {
$sql = '
- INSERT INTO `' . $this->prefix . 'feed`
+ INSERT INTO `_feed`
(
url,
category,
@@ -39,18 +38,24 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
description,
`lastUpdate`,
priority,
+ `pathEntries`,
`httpAuth`,
error,
- keep_history,
ttl,
attributes
)
VALUES
- (?, ?, ?, ?, ?, ?, 10, ?, 0, ?, ?, ?)';
- $stm = $this->bd->prepare($sql);
+ (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
+ $stm = $this->pdo->prepare($sql);
$valuesTmp['url'] = safe_ascii($valuesTmp['url']);
$valuesTmp['website'] = safe_ascii($valuesTmp['website']);
+ if (!isset($valuesTmp['pathEntries'])) {
+ $valuesTmp['pathEntries'] = '';
+ }
+ if (!isset($valuesTmp['attributes'])) {
+ $valuesTmp['attributes'] = [];
+ }
$values = array(
substr($valuesTmp['url'], 0, 511),
@@ -59,16 +64,18 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
substr($valuesTmp['website'], 0, 255),
mb_strcut($valuesTmp['description'], 0, 1023, 'UTF-8'),
$valuesTmp['lastUpdate'],
+ isset($valuesTmp['priority']) ? intval($valuesTmp['priority']) : FreshRSS_Feed::PRIORITY_MAIN_STREAM,
+ mb_strcut($valuesTmp['pathEntries'], 0, 511, 'UTF-8'),
base64_encode($valuesTmp['httpAuth']),
- FreshRSS_Feed::KEEP_HISTORY_DEFAULT,
+ isset($valuesTmp['error']) ? intval($valuesTmp['error']) : 0,
isset($valuesTmp['ttl']) ? intval($valuesTmp['ttl']) : FreshRSS_Feed::TTL_DEFAULT,
- isset($valuesTmp['attributes']) ? json_encode($valuesTmp['attributes']) : '',
+ is_string($valuesTmp['attributes']) ? $valuesTmp['attributes'] : json_encode($valuesTmp['attributes'], JSON_UNESCAPED_SLASHES),
);
if ($stm && $stm->execute($values)) {
- return $this->bd->lastInsertId('"' . $this->prefix . 'feed_id_seq"');
+ return $this->pdo->lastInsertId('`_feed_id_seq`');
} else {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
if ($this->autoUpdateDb($info)) {
return $this->addFeed($valuesTmp);
}
@@ -129,13 +136,13 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
if ($key === 'httpAuth') {
$valuesTmp[$key] = base64_encode($v);
} elseif ($key === 'attributes') {
- $valuesTmp[$key] = json_encode($v);
+ $valuesTmp[$key] = is_string($valuesTmp[$key]) ? $valuesTmp[$key] : json_encode($valuesTmp[$key], JSON_UNESCAPED_SLASHES);
}
}
$set = substr($set, 0, -2);
- $sql = 'UPDATE `' . $this->prefix . 'feed` SET ' . $set . ' WHERE id=?';
- $stm = $this->bd->prepare($sql);
+ $sql = 'UPDATE `_feed` SET ' . $set . ' WHERE id=?';
+ $stm = $this->pdo->prepare($sql);
foreach ($valuesTmp as $v) {
$values[] = $v;
@@ -145,7 +152,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
if ($stm && $stm->execute($values)) {
return $stm->rowCount();
} else {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
if ($this->autoUpdateDb($info)) {
return $this->updateFeed($id, $valuesTmp);
}
@@ -166,7 +173,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
}
public function updateLastUpdate($id, $inError = false, $mtime = 0) { //See also updateCachedValue()
- $sql = 'UPDATE `' . $this->prefix . 'feed` '
+ $sql = 'UPDATE `_feed` '
. 'SET `lastUpdate`=?, error=? '
. 'WHERE id=?';
$values = array(
@@ -174,12 +181,12 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
$inError ? 1 : 0,
$id,
);
- $stm = $this->bd->prepare($sql);
+ $stm = $this->pdo->prepare($sql);
if ($stm && $stm->execute($values)) {
return $stm->rowCount();
} else {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error updateLastUpdate: ' . $info[2]);
return false;
}
@@ -192,8 +199,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
$newCat = $catDAO->getDefault();
}
- $sql = 'UPDATE `' . $this->prefix . 'feed` SET category=? WHERE category=?';
- $stm = $this->bd->prepare($sql);
+ $sql = 'UPDATE `_feed` SET category=? WHERE category=?';
+ $stm = $this->pdo->prepare($sql);
$values = array(
$newCat->id(),
@@ -203,44 +210,54 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
if ($stm && $stm->execute($values)) {
return $stm->rowCount();
} else {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error changeCategory: ' . $info[2]);
return false;
}
}
public function deleteFeed($id) {
- $sql = 'DELETE FROM `' . $this->prefix . 'feed` WHERE id=?';
- $stm = $this->bd->prepare($sql);
+ $sql = 'DELETE FROM `_feed` WHERE id=?';
+ $stm = $this->pdo->prepare($sql);
$values = array($id);
if ($stm && $stm->execute($values)) {
return $stm->rowCount();
} else {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error deleteFeed: ' . $info[2]);
return false;
}
}
public function deleteFeedByCategory($id) {
- $sql = 'DELETE FROM `' . $this->prefix . 'feed` WHERE category=?';
- $stm = $this->bd->prepare($sql);
+ $sql = 'DELETE FROM `_feed` WHERE category=?';
+ $stm = $this->pdo->prepare($sql);
$values = array($id);
if ($stm && $stm->execute($values)) {
return $stm->rowCount();
} else {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error deleteFeedByCategory: ' . $info[2]);
return false;
}
}
+ public function selectAll() {
+ $sql = 'SELECT id, url, category, name, website, description, `lastUpdate`, priority, '
+ . '`pathEntries`, `httpAuth`, error, ttl, attributes '
+ . 'FROM `_feed`';
+ $stm = $this->pdo->query($sql);
+ while ($row = $stm->fetch(PDO::FETCH_ASSOC)) {
+ yield $row;
+ }
+ }
+
public function searchById($id) {
- $sql = 'SELECT * FROM `' . $this->prefix . 'feed` WHERE id=?';
- $stm = $this->bd->prepare($sql);
+ $sql = 'SELECT * FROM `_feed` WHERE id=?';
+ $stm = $this->pdo->prepare($sql);
$values = array($id);
@@ -255,8 +272,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
}
}
public function searchByUrl($url) {
- $sql = 'SELECT * FROM `' . $this->prefix . 'feed` WHERE url=?';
- $stm = $this->bd->prepare($sql);
+ $sql = 'SELECT * FROM `_feed` WHERE url=?';
+ $stm = $this->pdo->prepare($sql);
$values = array($url);
@@ -272,25 +289,21 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
}
public function listFeedsIds() {
- $sql = 'SELECT id FROM `' . $this->prefix . 'feed`';
- $stm = $this->bd->prepare($sql);
- $stm->execute();
+ $sql = 'SELECT id FROM `_feed`';
+ $stm = $this->pdo->query($sql);
return $stm->fetchAll(PDO::FETCH_COLUMN, 0);
}
public function listFeeds() {
- $sql = 'SELECT * FROM `' . $this->prefix . 'feed` ORDER BY name';
- $stm = $this->bd->prepare($sql);
- $stm->execute();
-
+ $sql = 'SELECT * FROM `_feed` ORDER BY name';
+ $stm = $this->pdo->query($sql);
return self::daoToFeed($stm->fetchAll(PDO::FETCH_ASSOC));
}
public function arrayFeedCategoryNames() { //For API
- $sql = 'SELECT f.id, f.name, c.name as c_name FROM `' . $this->prefix . 'feed` f '
- . 'INNER JOIN `' . $this->prefix . 'category` c ON c.id = f.category';
- $stm = $this->bd->prepare($sql);
- $stm->execute();
+ $sql = 'SELECT f.id, f.name, c.name as c_name FROM `_feed` f '
+ . 'INNER JOIN `_category` c ON c.id = f.category';
+ $stm = $this->pdo->query($sql);
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
$feedCategoryNames = array();
foreach ($res as $line) {
@@ -307,17 +320,18 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
*/
public function listFeedsOrderUpdate($defaultCacheDuration = 3600, $limit = 0) {
$this->updateTTL();
- $sql = 'SELECT id, url, name, website, `lastUpdate`, `pathEntries`, `httpAuth`, keep_history, ttl, attributes '
- . 'FROM `' . $this->prefix . 'feed` '
+ $sql = 'SELECT id, url, name, website, `lastUpdate`, `pathEntries`, `httpAuth`, ttl, attributes '
+ . 'FROM `_feed` '
. ($defaultCacheDuration < 0 ? '' : 'WHERE ttl >= ' . FreshRSS_Feed::TTL_DEFAULT
- . ' AND `lastUpdate` < (' . (time() + 60) . '-(CASE WHEN ttl=' . FreshRSS_Feed::TTL_DEFAULT . ' THEN ' . intval($defaultCacheDuration) . ' ELSE ttl END)) ')
+ . ' AND `lastUpdate` < (' . (time() + 60)
+ . '-(CASE WHEN ttl=' . FreshRSS_Feed::TTL_DEFAULT . ' THEN ' . intval($defaultCacheDuration) . ' ELSE ttl END)) ')
. 'ORDER BY `lastUpdate` '
. ($limit < 1 ? '' : 'LIMIT ' . intval($limit));
- $stm = $this->bd->prepare($sql);
- if ($stm && $stm->execute()) {
+ $stm = $this->pdo->query($sql);
+ if ($stm !== false) {
return self::daoToFeed($stm->fetchAll(PDO::FETCH_ASSOC));
} else {
- $info = $stm == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
if ($this->autoUpdateDb($info)) {
return $this->listFeedsOrderUpdate($defaultCacheDuration);
}
@@ -327,8 +341,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
}
public function listByCategory($cat) {
- $sql = 'SELECT * FROM `' . $this->prefix . 'feed` WHERE category=? ORDER BY name';
- $stm = $this->bd->prepare($sql);
+ $sql = 'SELECT * FROM `_feed` WHERE category=? ORDER BY name';
+ $stm = $this->pdo->prepare($sql);
$values = array($cat);
@@ -338,8 +352,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
}
public function countEntries($id) {
- $sql = 'SELECT COUNT(*) AS count FROM `' . $this->prefix . 'entry` WHERE id_feed=?';
- $stm = $this->bd->prepare($sql);
+ $sql = 'SELECT COUNT(*) AS count FROM `_entry` WHERE id_feed=?';
+ $stm = $this->pdo->prepare($sql);
$values = array($id);
$stm->execute($values);
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
@@ -348,8 +362,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
}
public function countNotRead($id) {
- $sql = 'SELECT COUNT(*) AS count FROM `' . $this->prefix . 'entry` WHERE id_feed=? AND is_read=0';
- $stm = $this->bd->prepare($sql);
+ $sql = 'SELECT COUNT(*) AS count FROM `_entry` WHERE id_feed=? AND is_read=0';
+ $stm = $this->pdo->prepare($sql);
$values = array($id);
$stm->execute($values);
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
@@ -357,62 +371,51 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
return $res[0]['count'];
}
- public function updateCachedValue($id) { //For multiple feeds, call updateCachedValues()
- $sql = 'UPDATE `' . $this->prefix . 'feed` ' //2 sub-requests with FOREIGN KEY(e.id_feed), INDEX(e.is_read) faster than 1 request with GROUP BY or CASE
- . 'SET `cache_nbEntries`=(SELECT COUNT(e1.id) FROM `' . $this->prefix . 'entry` e1 WHERE e1.id_feed=`' . $this->prefix . 'feed`.id),'
- . '`cache_nbUnreads`=(SELECT COUNT(e2.id) FROM `' . $this->prefix . 'entry` e2 WHERE e2.id_feed=`' . $this->prefix . 'feed`.id AND e2.is_read=0) '
- . 'WHERE id=?';
- $values = array($id);
- $stm = $this->bd->prepare($sql);
-
- if ($stm && $stm->execute($values)) {
- return $stm->rowCount();
- } else {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
- Minz_Log::error('SQL error updateCachedValue: ' . $info[2]);
- return false;
+ public function updateCachedValues($id = null) {
+ //2 sub-requests with FOREIGN KEY(e.id_feed), INDEX(e.is_read) faster than 1 request with GROUP BY or CASE
+ $sql = 'UPDATE `_feed` '
+ . 'SET `cache_nbEntries`=(SELECT COUNT(e1.id) FROM `_entry` e1 WHERE e1.id_feed=`_feed`.id),'
+ . '`cache_nbUnreads`=(SELECT COUNT(e2.id) FROM `_entry` e2 WHERE e2.id_feed=`_feed`.id AND e2.is_read=0)'
+ . ($id != null ? ' WHERE id=:id' : '');
+ $stm = $this->pdo->prepare($sql);
+ if ($id != null) {
+ $stm->bindParam(':id', $id, PDO::PARAM_INT);
}
- }
- public function updateCachedValues() { //For one single feed, call updateCachedValue($id)
- $sql = 'UPDATE `' . $this->prefix . 'feed` '
- . 'SET `cache_nbEntries`=(SELECT COUNT(e1.id) FROM `' . $this->prefix . 'entry` e1 WHERE e1.id_feed=`' . $this->prefix . 'feed`.id),'
- . '`cache_nbUnreads`=(SELECT COUNT(e2.id) FROM `' . $this->prefix . 'entry` e2 WHERE e2.id_feed=`' . $this->prefix . 'feed`.id AND e2.is_read=0)';
- $stm = $this->bd->prepare($sql);
if ($stm && $stm->execute()) {
return $stm->rowCount();
} else {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
- Minz_Log::error('SQL error updateCachedValues: ' . $info[2]);
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
+ Minz_Log::error('SQL error updateCachedValue: ' . $info[2]);
return false;
}
}
public function truncate($id) {
- $sql = 'DELETE FROM `' . $this->prefix . 'entry` WHERE id_feed=?';
- $stm = $this->bd->prepare($sql);
- $values = array($id);
- $this->bd->beginTransaction();
- if (!($stm && $stm->execute($values))) {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $sql = 'DELETE FROM `_entry` WHERE id_feed=:id';
+ $stm = $this->pdo->prepare($sql);
+ $stm->bindParam(':id', $id, PDO::PARAM_INT);
+ $this->pdo->beginTransaction();
+ if (!($stm && $stm->execute())) {
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error truncate: ' . $info[2]);
- $this->bd->rollBack();
+ $this->pdo->rollBack();
return false;
}
$affected = $stm->rowCount();
- $sql = 'UPDATE `' . $this->prefix . 'feed` '
- . 'SET `cache_nbEntries`=0, `cache_nbUnreads`=0 WHERE id=?';
- $values = array($id);
- $stm = $this->bd->prepare($sql);
- if (!($stm && $stm->execute($values))) {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $sql = 'UPDATE `_feed` '
+ . 'SET `cache_nbEntries`=0, `cache_nbUnreads`=0 WHERE id=:id';
+ $stm = $this->pdo->prepare($sql);
+ $stm->bindParam(':id', $id, PDO::PARAM_INT);
+ if (!($stm && $stm->execute())) {
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error truncate: ' . $info[2]);
- $this->bd->rollBack();
+ $this->pdo->rollBack();
return false;
}
- $this->bd->commit();
+ $this->pdo->commit();
return $affected;
}
@@ -446,7 +449,6 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
$myFeed->_pathEntries(isset($dao['pathEntries']) ? $dao['pathEntries'] : '');
$myFeed->_httpAuth(isset($dao['httpAuth']) ? base64_decode($dao['httpAuth']) : '');
$myFeed->_error(isset($dao['error']) ? $dao['error'] : 0);
- $myFeed->_keepHistory(isset($dao['keep_history']) ? $dao['keep_history'] : FreshRSS_Feed::KEEP_HISTORY_DEFAULT);
$myFeed->_ttl(isset($dao['ttl']) ? $dao['ttl'] : FreshRSS_Feed::TTL_DEFAULT);
$myFeed->_attributes('', isset($dao['attributes']) ? $dao['attributes'] : '');
$myFeed->_nbNotRead(isset($dao['cache_nbUnreads']) ? $dao['cache_nbUnreads'] : 0);
@@ -461,20 +463,16 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
}
public function updateTTL() {
- $sql = <<<SQL
-UPDATE `{$this->prefix}feed`
- SET ttl = :new_value
- WHERE ttl = :old_value
-SQL;
- $stm = $this->bd->prepare($sql);
+ $sql = 'UPDATE `_feed` SET ttl=:new_value WHERE ttl=:old_value';
+ $stm = $this->pdo->prepare($sql);
if (!($stm && $stm->execute(array(':new_value' => FreshRSS_Feed::TTL_DEFAULT, ':old_value' => -2)))) {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL warning updateTTL 1: ' . $info[2] . ' ' . $sql);
- $sql2 = 'ALTER TABLE `' . $this->prefix . 'feed` ADD COLUMN ttl INT NOT NULL DEFAULT ' . FreshRSS_Feed::TTL_DEFAULT; //v0.7.3
- $stm = $this->bd->prepare($sql2);
- if (!($stm && $stm->execute())) {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $sql2 = 'ALTER TABLE `_feed` ADD COLUMN ttl INT NOT NULL DEFAULT ' . FreshRSS_Feed::TTL_DEFAULT; //v0.7.3
+ $stm = $this->pdo->query($sql2);
+ if ($stm === false) {
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error updateTTL 2: ' . $info[2] . ' ' . $sql2);
}
} else {
diff --git a/app/Models/FeedDAOSQLite.php b/app/Models/FeedDAOSQLite.php
index 3c203b378..0f685867a 100644
--- a/app/Models/FeedDAOSQLite.php
+++ b/app/Models/FeedDAOSQLite.php
@@ -3,9 +3,9 @@
class FreshRSS_FeedDAOSQLite extends FreshRSS_FeedDAO {
protected function autoUpdateDb($errorInfo) {
- if ($tableInfo = $this->bd->query("PRAGMA table_info('feed')")) {
+ if ($tableInfo = $this->pdo->query("PRAGMA table_info('feed')")) {
$columns = $tableInfo->fetchAll(PDO::FETCH_COLUMN, 1);
- foreach (array('attributes') as $column) {
+ foreach (['attributes'] as $column) {
if (!in_array($column, $columns)) {
return $this->addColumn($column);
}
diff --git a/app/Models/StatsDAO.php b/app/Models/StatsDAO.php
index 67ada73f7..cbfa79c61 100644
--- a/app/Models/StatsDAO.php
+++ b/app/Models/StatsDAO.php
@@ -45,13 +45,11 @@ SELECT COUNT(1) AS total,
COUNT(1) - SUM(e.is_read) AS count_unreads,
SUM(e.is_read) AS count_reads,
SUM(e.is_favorite) AS count_favorites
-FROM `{$this->prefix}entry` AS e
-, `{$this->prefix}feed` AS f
+FROM `_entry` AS e, `_feed` AS f
WHERE e.id_feed = f.id
{$filter}
SQL;
- $stm = $this->bd->prepare($sql);
- $stm->execute();
+ $stm = $this->pdo->query($sql);
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
return $res[0];
@@ -73,13 +71,12 @@ SQL;
$sql = <<<SQL
SELECT {$sqlDay} AS day,
COUNT(*) as count
-FROM `{$this->prefix}entry`
+FROM `_entry`
WHERE date >= {$oldest} AND date < {$midnight}
GROUP BY day
ORDER BY day ASC
SQL;
- $stm = $this->bd->prepare($sql);
- $stm->execute();
+ $stm = $this->pdo->query($sql);
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
foreach ($res as $value) {
@@ -143,14 +140,13 @@ SQL;
$sql = <<<SQL
SELECT DATE_FORMAT(FROM_UNIXTIME(e.date), '{$period}') AS period
, COUNT(1) AS count
-FROM `{$this->prefix}entry` AS e
+FROM `_entry` AS e
{$restrict}
GROUP BY period
ORDER BY period ASC
SQL;
- $stm = $this->bd->prepare($sql);
- $stm->execute();
+ $stm = $this->pdo->query($sql);
$res = $stm->fetchAll(PDO::FETCH_NAMED);
$repartition = array();
@@ -207,11 +203,10 @@ SQL;
SELECT COUNT(1) AS count
, MIN(date) AS date_min
, MAX(date) AS date_max
-FROM `{$this->prefix}entry` AS e
+FROM `_entry` AS e
{$restrict}
SQL;
- $stm = $this->bd->prepare($sql);
- $stm->execute();
+ $stm = $this->pdo->query($sql);
$res = $stm->fetch(PDO::FETCH_NAMED);
$date_min = new \DateTime();
$date_min->setTimestamp($res['date_min']);
@@ -251,14 +246,12 @@ SQL;
$sql = <<<SQL
SELECT c.name AS label
, COUNT(f.id) AS data
-FROM `{$this->prefix}category` AS c,
-`{$this->prefix}feed` AS f
+FROM `_category` AS c, `_feed` AS f
WHERE c.id = f.category
GROUP BY label
ORDER BY data DESC
SQL;
- $stm = $this->bd->prepare($sql);
- $stm->execute();
+ $stm = $this->pdo->query($sql);
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
return $res;
@@ -274,16 +267,13 @@ SQL;
$sql = <<<SQL
SELECT c.name AS label
, COUNT(e.id) AS data
-FROM `{$this->prefix}category` AS c,
-`{$this->prefix}feed` AS f,
-`{$this->prefix}entry` AS e
+FROM `_category` AS c, `_feed` AS f, `_entry` AS e
WHERE c.id = f.category
AND f.id = e.id_feed
GROUP BY label
ORDER BY data DESC
SQL;
- $stm = $this->bd->prepare($sql);
- $stm->execute();
+ $stm = $this->pdo->query($sql);
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
return $res;
@@ -300,17 +290,14 @@ SELECT f.id AS id
, MAX(f.name) AS name
, MAX(c.name) AS category
, COUNT(e.id) AS count
-FROM `{$this->prefix}category` AS c,
-`{$this->prefix}feed` AS f,
-`{$this->prefix}entry` AS e
+FROM `_category` AS c, `_feed` AS f, `_entry` AS e
WHERE c.id = f.category
AND f.id = e.id_feed
GROUP BY f.id
ORDER BY count DESC
LIMIT 10
SQL;
- $stm = $this->bd->prepare($sql);
- $stm->execute();
+ $stm = $this->pdo->query($sql);
return $stm->fetchAll(PDO::FETCH_ASSOC);
}
@@ -325,14 +312,12 @@ SELECT MAX(f.id) as id
, MAX(f.name) AS name
, MAX(date) AS last_date
, COUNT(*) AS nb_articles
-FROM `{$this->prefix}feed` AS f,
-`{$this->prefix}entry` AS e
+FROM `_feed` AS f, `_entry` AS e
WHERE f.id = e.id_feed
GROUP BY f.id
ORDER BY name
SQL;
- $stm = $this->bd->prepare($sql);
- $stm->execute();
+ $stm = $this->pdo->query($sql);
return $stm->fetchAll(PDO::FETCH_ASSOC);
}
diff --git a/app/Models/StatsDAOPGSQL.php b/app/Models/StatsDAOPGSQL.php
index 1effbb64b..4a66068cb 100644
--- a/app/Models/StatsDAOPGSQL.php
+++ b/app/Models/StatsDAOPGSQL.php
@@ -47,14 +47,13 @@ class FreshRSS_StatsDAOPGSQL extends FreshRSS_StatsDAO {
$sql = <<<SQL
SELECT extract( {$period} from to_timestamp(e.date)) AS period
, COUNT(1) AS count
-FROM "{$this->prefix}entry" AS e
+FROM `_entry` AS e
{$restrict}
GROUP BY period
ORDER BY period ASC
SQL;
- $stm = $this->bd->prepare($sql);
- $stm->execute();
+ $stm = $this->pdo->query($sql);
$res = $stm->fetchAll(PDO::FETCH_NAMED);
foreach ($res as $value) {
diff --git a/app/Models/StatsDAOSQLite.php b/app/Models/StatsDAOSQLite.php
index 6cfc20463..f96f8f479 100644
--- a/app/Models/StatsDAOSQLite.php
+++ b/app/Models/StatsDAOSQLite.php
@@ -15,14 +15,13 @@ class FreshRSS_StatsDAOSQLite extends FreshRSS_StatsDAO {
$sql = <<<SQL
SELECT strftime('{$period}', e.date, 'unixepoch') AS period
, COUNT(1) AS count
-FROM `{$this->prefix}entry` AS e
+FROM `_entry` AS e
{$restrict}
GROUP BY period
ORDER BY period ASC
SQL;
- $stm = $this->bd->prepare($sql);
- $stm->execute();
+ $stm = $this->pdo->query($sql);
$res = $stm->fetchAll(PDO::FETCH_NAMED);
$repartition = array();
diff --git a/app/Models/Tag.php b/app/Models/Tag.php
index 3eb989cc1..0d50e356c 100644
--- a/app/Models/Tag.php
+++ b/app/Models/Tag.php
@@ -3,7 +3,7 @@
class FreshRSS_Tag extends Minz_Model {
private $id = 0;
private $name;
- private $attributes = array();
+ private $attributes = [];
private $nbEntries = -1;
private $nbUnread = -1;
diff --git a/app/Models/TagDAO.php b/app/Models/TagDAO.php
index 297d24c96..5882eee76 100644
--- a/app/Models/TagDAO.php
+++ b/app/Models/TagDAO.php
@@ -8,37 +8,24 @@ class FreshRSS_TagDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
public function createTagTable() {
$ok = false;
- $hadTransaction = $this->bd->inTransaction();
+ $hadTransaction = $this->pdo->inTransaction();
if ($hadTransaction) {
- $this->bd->commit();
+ $this->pdo->commit();
}
try {
- $db = FreshRSS_Context::$system_conf->db;
- require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php');
+ require(APP_PATH . '/SQL/install.sql.' . $this->pdo->dbType() . '.php');
Minz_Log::warning('SQL ALTER GUID case sensitivity...');
$databaseDAO = FreshRSS_Factory::createDatabaseDAO();
$databaseDAO->ensureCaseInsensitiveGuids();
Minz_Log::warning('SQL CREATE TABLE tag...');
- if (defined('SQL_CREATE_TABLE_TAGS')) {
- $sql = sprintf(SQL_CREATE_TABLE_TAGS, $this->prefix);
- $stm = $this->bd->prepare($sql);
- $ok = $stm && $stm->execute();
- } else {
- global $SQL_CREATE_TABLE_TAGS;
- $ok = !empty($SQL_CREATE_TABLE_TAGS);
- foreach ($SQL_CREATE_TABLE_TAGS as $instruction) {
- $sql = sprintf($instruction, $this->prefix);
- $stm = $this->bd->prepare($sql);
- $ok &= $stm && $stm->execute();
- }
- }
+ $ok = $this->pdo->exec($SQL_CREATE_TABLE_TAGS) !== false;
} catch (Exception $e) {
Minz_Log::error('FreshRSS_EntryDAO::createTagTable error: ' . $e->getMessage());
}
if ($hadTransaction) {
- $this->bd->beginTransaction();
+ $this->pdo->beginTransaction();
}
return $ok;
}
@@ -55,22 +42,25 @@ class FreshRSS_TagDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
}
public function addTag($valuesTmp) {
- $sql = 'INSERT INTO `' . $this->prefix . 'tag`(name, attributes) '
- . 'SELECT * FROM (SELECT TRIM(?), TRIM(?)) t2 ' //TRIM() to provide a type hint as text for PostgreSQL
- . 'WHERE NOT EXISTS (SELECT 1 FROM `' . $this->prefix . 'category` WHERE name = TRIM(?))'; //No category of the same name
- $stm = $this->bd->prepare($sql);
+ $sql = 'INSERT INTO `_tag`(name, attributes) '
+ . 'SELECT * FROM (SELECT TRIM(?) as name, TRIM(?) as attributes) t2 ' //TRIM() gives a text type hint to PostgreSQL
+ . 'WHERE NOT EXISTS (SELECT 1 FROM `_category` WHERE name = TRIM(?))'; //No category of the same name
+ $stm = $this->pdo->prepare($sql);
$valuesTmp['name'] = mb_strcut(trim($valuesTmp['name']), 0, 63, 'UTF-8');
+ if (!isset($valuesTmp['attributes'])) {
+ $valuesTmp['attributes'] = [];
+ }
$values = array(
$valuesTmp['name'],
- isset($valuesTmp['attributes']) ? json_encode($valuesTmp['attributes']) : '',
+ is_string($valuesTmp['attributes']) ? $valuesTmp['attributes'] : json_encode($valuesTmp['attributes'], JSON_UNESCAPED_SLASHES),
$valuesTmp['name'],
);
if ($stm && $stm->execute($values)) {
- return $this->bd->lastInsertId('"' . $this->prefix . 'tag_id_seq"');
+ return $this->pdo->lastInsertId('`_tag_id_seq`');
} else {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error addTag: ' . $info[2]);
return false;
}
@@ -89,14 +79,17 @@ class FreshRSS_TagDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
}
public function updateTag($id, $valuesTmp) {
- $sql = 'UPDATE `' . $this->prefix . 'tag` SET name=?, attributes=? WHERE id=? '
- . 'AND NOT EXISTS (SELECT 1 FROM `' . $this->prefix . 'category` WHERE name = ?)'; //No category of the same name
- $stm = $this->bd->prepare($sql);
+ $sql = 'UPDATE `_tag` SET name=?, attributes=? WHERE id=? '
+ . 'AND NOT EXISTS (SELECT 1 FROM `_category` WHERE name = ?)'; //No category of the same name
+ $stm = $this->pdo->prepare($sql);
$valuesTmp['name'] = mb_strcut(trim($valuesTmp['name']), 0, 63, 'UTF-8');
+ if (!isset($valuesTmp['attributes'])) {
+ $valuesTmp['attributes'] = [];
+ }
$values = array(
$valuesTmp['name'],
- isset($valuesTmp['attributes']) ? json_encode($valuesTmp['attributes']) : '',
+ is_string($valuesTmp['attributes']) ? $valuesTmp['attributes'] : json_encode($valuesTmp['attributes'], JSON_UNESCAPED_SLASHES),
$id,
$valuesTmp['name'],
);
@@ -104,7 +97,7 @@ class FreshRSS_TagDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
if ($stm && $stm->execute($values)) {
return $stm->rowCount();
} else {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error updateTag: ' . $info[2]);
return false;
}
@@ -125,23 +118,39 @@ class FreshRSS_TagDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
if ($id <= 0) {
return false;
}
- $sql = 'DELETE FROM `' . $this->prefix . 'tag` WHERE id=?';
- $stm = $this->bd->prepare($sql);
+ $sql = 'DELETE FROM `_tag` WHERE id=?';
+ $stm = $this->pdo->prepare($sql);
$values = array($id);
if ($stm && $stm->execute($values)) {
return $stm->rowCount();
} else {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error deleteTag: ' . $info[2]);
return false;
}
}
+ public function selectAll() {
+ $sql = 'SELECT id, name, attributes FROM `_tag`';
+ $stm = $this->pdo->query($sql);
+ while ($row = $stm->fetch(PDO::FETCH_ASSOC)) {
+ yield $row;
+ }
+ }
+
+ public function selectEntryTag() {
+ $sql = 'SELECT id_tag, id_entry FROM `_entrytag`';
+ $stm = $this->pdo->query($sql);
+ while ($row = $stm->fetch(PDO::FETCH_ASSOC)) {
+ yield $row;
+ }
+ }
+
public function searchById($id) {
- $sql = 'SELECT * FROM `' . $this->prefix . 'tag` WHERE id=?';
- $stm = $this->bd->prepare($sql);
+ $sql = 'SELECT * FROM `_tag` WHERE id=?';
+ $stm = $this->pdo->prepare($sql);
$values = array($id);
$stm->execute($values);
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
@@ -150,8 +159,8 @@ class FreshRSS_TagDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
}
public function searchByName($name) {
- $sql = 'SELECT * FROM `' . $this->prefix . 'tag` WHERE name=?';
- $stm = $this->bd->prepare($sql);
+ $sql = 'SELECT * FROM `_tag` WHERE name=?';
+ $stm = $this->pdo->prepare($sql);
$values = array($name);
$stm->execute($values);
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
@@ -162,20 +171,20 @@ class FreshRSS_TagDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
public function listTags($precounts = false) {
if ($precounts) {
$sql = 'SELECT t.id, t.name, count(e.id) AS unreads '
- . 'FROM `' . $this->prefix . 'tag` t '
- . 'LEFT OUTER JOIN `' . $this->prefix . 'entrytag` et ON et.id_tag = t.id '
- . 'LEFT OUTER JOIN `' . $this->prefix . 'entry` e ON et.id_entry = e.id AND e.is_read = 0 '
+ . 'FROM `_tag` t '
+ . 'LEFT OUTER JOIN `_entrytag` et ON et.id_tag = t.id '
+ . 'LEFT OUTER JOIN `_entry` e ON et.id_entry = e.id AND e.is_read = 0 '
. 'GROUP BY t.id '
. 'ORDER BY t.name';
} else {
- $sql = 'SELECT * FROM `' . $this->prefix . 'tag` ORDER BY name';
+ $sql = 'SELECT * FROM `_tag` ORDER BY name';
}
- $stm = $this->bd->prepare($sql);
- if ($stm && $stm->execute()) {
+ $stm = $this->pdo->query($sql);
+ if ($stm !== false) {
return self::daoToTag($stm->fetchAll(PDO::FETCH_ASSOC));
} else {
- $info = $stm == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
if ($this->autoUpdateDb($info)) {
return $this->listTags($precounts);
}
@@ -185,13 +194,13 @@ class FreshRSS_TagDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
}
public function count() {
- $sql = 'SELECT COUNT(*) AS count FROM `' . $this->prefix . 'tag`';
- $stm = $this->bd->prepare($sql);
- if ($stm && $stm->execute()) {
+ $sql = 'SELECT COUNT(*) AS count FROM `_tag`';
+ $stm = $this->pdo->query($sql);
+ if ($stm !== false) {
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
return $res[0]['count'];
} else {
- $info = $stm == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
if ($this->autoUpdateDb($info)) {
return $this->count();
}
@@ -201,8 +210,8 @@ class FreshRSS_TagDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
}
public function countEntries($id) {
- $sql = 'SELECT COUNT(*) AS count FROM `' . $this->prefix . 'entrytag` WHERE id_tag=?';
- $stm = $this->bd->prepare($sql);
+ $sql = 'SELECT COUNT(*) AS count FROM `_entrytag` WHERE id_tag=?';
+ $stm = $this->pdo->prepare($sql);
$values = array($id);
$stm->execute($values);
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
@@ -210,10 +219,10 @@ class FreshRSS_TagDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
}
public function countNotRead($id) {
- $sql = 'SELECT COUNT(*) AS count FROM `' . $this->prefix . 'entrytag` et '
- . 'INNER JOIN `' . $this->prefix . 'entry` e ON et.id_entry=e.id '
+ $sql = 'SELECT COUNT(*) AS count FROM `_entrytag` et '
+ . 'INNER JOIN `_entry` e ON et.id_entry=e.id '
. 'WHERE et.id_tag=? AND e.is_read=0';
- $stm = $this->bd->prepare($sql);
+ $stm = $this->pdo->prepare($sql);
$values = array($id);
$stm->execute($values);
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
@@ -222,17 +231,17 @@ class FreshRSS_TagDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
public function tagEntry($id_tag, $id_entry, $checked = true) {
if ($checked) {
- $sql = 'INSERT ' . $this->sqlIgnore() . ' INTO `' . $this->prefix . 'entrytag`(id_tag, id_entry) VALUES(?, ?)';
+ $sql = 'INSERT ' . $this->sqlIgnore() . ' INTO `_entrytag`(id_tag, id_entry) VALUES(?, ?)';
} else {
- $sql = 'DELETE FROM `' . $this->prefix . 'entrytag` WHERE id_tag=? AND id_entry=?';
+ $sql = 'DELETE FROM `_entrytag` WHERE id_tag=? AND id_entry=?';
}
- $stm = $this->bd->prepare($sql);
+ $stm = $this->pdo->prepare($sql);
$values = array($id_tag, $id_entry);
if ($stm && $stm->execute($values)) {
return true;
} else {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error tagEntry: ' . $info[2]);
return false;
}
@@ -240,11 +249,11 @@ class FreshRSS_TagDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
public function getTagsForEntry($id_entry) {
$sql = 'SELECT t.id, t.name, et.id_entry IS NOT NULL as checked '
- . 'FROM `' . $this->prefix . 'tag` t '
- . 'LEFT OUTER JOIN `' . $this->prefix . 'entrytag` et ON et.id_tag = t.id AND et.id_entry=? '
+ . 'FROM `_tag` t '
+ . 'LEFT OUTER JOIN `_entrytag` et ON et.id_tag = t.id AND et.id_entry=? '
. 'ORDER BY t.name';
- $stm = $this->bd->prepare($sql);
+ $stm = $this->pdo->prepare($sql);
$values = array($id_entry);
if ($stm && $stm->execute($values)) {
@@ -255,7 +264,7 @@ class FreshRSS_TagDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
}
return $lines;
} else {
- $info = $stm == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
if ($this->autoUpdateDb($info)) {
return $this->getTagsForEntry($id_entry);
}
@@ -266,8 +275,8 @@ class FreshRSS_TagDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
public function getTagsForEntries($entries) {
$sql = 'SELECT et.id_entry, et.id_tag, t.name '
- . 'FROM `' . $this->prefix . 'tag` t '
- . 'INNER JOIN `' . $this->prefix . 'entrytag` et ON et.id_tag = t.id';
+ . 'FROM `_tag` t '
+ . 'INNER JOIN `_entrytag` et ON et.id_tag = t.id';
$values = array();
if (is_array($entries) && count($entries) > 0) {
@@ -286,12 +295,12 @@ class FreshRSS_TagDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
}
}
}
- $stm = $this->bd->prepare($sql);
+ $stm = $this->pdo->prepare($sql);
if ($stm && $stm->execute($values)) {
return $stm->fetchAll(PDO::FETCH_ASSOC);
} else {
- $info = $stm == null ? array(0 => '', 1 => '', 2 => 'syntax error') : $stm->errorInfo();
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
if ($this->autoUpdateDb($info)) {
return $this->getTagsForEntries($entries);
}
diff --git a/app/Models/TagDAOSQLite.php b/app/Models/TagDAOSQLite.php
index b1deb6c65..ca0fce7ca 100644
--- a/app/Models/TagDAOSQLite.php
+++ b/app/Models/TagDAOSQLite.php
@@ -7,7 +7,7 @@ class FreshRSS_TagDAOSQLite extends FreshRSS_TagDAO {
}
protected function autoUpdateDb($errorInfo) {
- if ($tableInfo = $this->bd->query("SELECT sql FROM sqlite_master where name='tag'")) {
+ if ($tableInfo = $this->pdo->query("SELECT sql FROM sqlite_master where name='tag'")) {
$showCreate = $tableInfo->fetchColumn();
if (stripos($showCreate, 'tag') === false) {
return $this->createTagTable(); //v1.12.0
diff --git a/app/Models/UserDAO.php b/app/Models/UserDAO.php
index e9d3a7329..4e824cf01 100644
--- a/app/Models/UserDAO.php
+++ b/app/Models/UserDAO.php
@@ -1,83 +1,52 @@
<?php
class FreshRSS_UserDAO extends Minz_ModelPdo {
- public function createUser($username, $new_user_language, $insertDefaultFeeds = true) {
- $db = FreshRSS_Context::$system_conf->db;
- require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php');
-
- $userPDO = new Minz_ModelPdo($username);
-
- $currentLanguage = Minz_Translate::language();
+ public function createUser($insertDefaultFeeds = false) {
+ require(APP_PATH . '/SQL/install.sql.' . $this->pdo->dbType() . '.php');
try {
- Minz_Translate::reset($new_user_language);
- $ok = false;
- $bd_prefix_user = $db['prefix'] . $username . '_';
- if (defined('SQL_CREATE_TABLES')) { //E.g. MySQL
- $sql = sprintf(SQL_CREATE_TABLES . SQL_CREATE_TABLE_ENTRYTMP . SQL_CREATE_TABLE_TAGS, $bd_prefix_user, _t('gen.short.default_category'));
- $stm = $userPDO->bd->prepare($sql);
- $ok = $stm && $stm->execute();
- } else { //E.g. SQLite
- global $SQL_CREATE_TABLES, $SQL_CREATE_TABLE_ENTRYTMP, $SQL_CREATE_TABLE_TAGS;
- if (is_array($SQL_CREATE_TABLES)) {
- $instructions = array_merge($SQL_CREATE_TABLES, $SQL_CREATE_TABLE_ENTRYTMP, $SQL_CREATE_TABLE_TAGS);
- $ok = !empty($instructions);
- foreach ($instructions as $instruction) {
- $sql = sprintf($instruction, $bd_prefix_user, _t('gen.short.default_category'));
- $stm = $userPDO->bd->prepare($sql);
- $ok &= ($stm && $stm->execute());
- }
- }
- }
+ $sql = $SQL_CREATE_TABLES . $SQL_CREATE_TABLE_ENTRYTMP . $SQL_CREATE_TABLE_TAGS;
+ $ok = $this->pdo->exec($sql) !== false; //Note: Only exec() can take multiple statements safely.
if ($ok && $insertDefaultFeeds) {
- if (defined('SQL_INSERT_FEEDS')) { //E.g. MySQL
- $sql = sprintf(SQL_INSERT_FEEDS, $bd_prefix_user);
- $stm = $userPDO->bd->prepare($sql);
- $ok &= $stm && $stm->execute();
- } else { //E.g. SQLite
- global $SQL_INSERT_FEEDS;
- if (is_array($SQL_INSERT_FEEDS)) {
- foreach ($SQL_INSERT_FEEDS as $instruction) {
- $sql = sprintf($instruction, $bd_prefix_user);
- $stm = $userPDO->bd->prepare($sql);
- $ok &= ($stm && $stm->execute());
- }
- }
+ $default_feeds = FreshRSS_Context::$system_conf->default_feeds;
+ $stm = $this->pdo->prepare($SQL_INSERT_FEED);
+ foreach ($default_feeds as $feed) {
+ $parameters = [
+ ':url' => $feed['url'],
+ ':name' => $feed['name'],
+ ':website' => $feed['website'],
+ ':description' => $feed['description'],
+ ];
+ $ok &= ($stm && $stm->execute($parameters));
}
}
} catch (Exception $e) {
- Minz_Log::error('Error while creating user: ' . $e->getMessage());
+ Minz_Log::error('Error while creating database for user: ' . $e->getMessage());
}
- Minz_Translate::reset($currentLanguage);
-
if ($ok) {
return true;
} else {
- $info = empty($stm) ? array(2 => 'syntax error') : $stm->errorInfo();
- Minz_Log::error('SQL error: ' . $info[2]);
+ $info = empty($stm) ? $this->pdo->errorInfo() : $stm->errorInfo();
+ Minz_Log::error(__METHOD__ . ' error: ' . $info[2]);
return false;
}
}
- public function deleteUser($username) {
- $db = FreshRSS_Context::$system_conf->db;
- require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php');
+ public function deleteUser() {
+ if (defined('STDERR')) {
+ fwrite(STDERR, 'Deleting SQL data for user “' . $this->current_user . "”…\n");
+ }
+
+ require(APP_PATH . '/SQL/install.sql.' . $this->pdo->dbType() . '.php');
+ $ok = $this->pdo->exec($SQL_DROP_TABLES) !== false;
- if ($db['type'] === 'sqlite') {
- return unlink(USERS_PATH . '/' . $username . '/db.sqlite');
+ if ($ok) {
+ return true;
} else {
- $userPDO = new Minz_ModelPdo($username);
-
- $sql = sprintf(SQL_DROP_TABLES, $db['prefix'] . $username . '_');
- $stm = $userPDO->bd->prepare($sql);
- if ($stm && $stm->execute()) {
- return true;
- } else {
- $info = $stm == null ? array(2 => 'syntax error') : $stm->errorInfo();
- Minz_Log::error('SQL error : ' . $info[2]);
- return false;
- }
+ $info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
+ Minz_Log::error(__METHOD__ . ' error: ' . $info[2]);
+ return false;
}
}
diff --git a/app/SQL/install.sql.mysql.php b/app/SQL/install.sql.mysql.php
index b3353ac95..1eabfae8b 100644
--- a/app/SQL/install.sql.mysql.php
+++ b/app/SQL/install.sql.mysql.php
@@ -1,20 +1,23 @@
<?php
-define('SQL_CREATE_DB', 'CREATE DATABASE IF NOT EXISTS `%1$s` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;');
+$SQL_CREATE_DB = <<<'SQL'
+CREATE DATABASE IF NOT EXISTS `%1$s` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
+SQL;
-define('SQL_CREATE_TABLES', '
-CREATE TABLE IF NOT EXISTS `%1$scategory` (
+$SQL_CREATE_TABLES = <<<'SQL'
+CREATE TABLE IF NOT EXISTS `_category` (
`id` SMALLINT NOT NULL AUTO_INCREMENT, -- v0.7
- `name` VARCHAR(' . FreshRSS_DatabaseDAO::LENGTH_INDEX_UNICODE . ') NOT NULL, -- Max index length for Unicode is 191 characters (767 bytes)
+ `name` VARCHAR(191) NOT NULL, -- Max index length for Unicode is 191 characters (767 bytes) FreshRSS_DatabaseDAO::LENGTH_INDEX_UNICODE
+ `attributes` TEXT, -- v1.15.0
PRIMARY KEY (`id`),
UNIQUE KEY (`name`) -- v0.7
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
ENGINE = INNODB;
-CREATE TABLE IF NOT EXISTS `%1$sfeed` (
+CREATE TABLE IF NOT EXISTS `_feed` (
`id` SMALLINT NOT NULL AUTO_INCREMENT, -- v0.7
`url` VARCHAR(511) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL,
`category` SMALLINT DEFAULT 0, -- v0.7
- `name` VARCHAR(' . FreshRSS_DatabaseDAO::LENGTH_INDEX_UNICODE . ') NOT NULL,
+ `name` VARCHAR(191) NOT NULL,
`website` VARCHAR(255) CHARACTER SET latin1 COLLATE latin1_bin,
`description` TEXT,
`lastUpdate` INT(11) DEFAULT 0, -- Until year 2038
@@ -22,26 +25,24 @@ CREATE TABLE IF NOT EXISTS `%1$sfeed` (
`pathEntries` VARCHAR(511) DEFAULT NULL,
`httpAuth` VARCHAR(511) DEFAULT NULL,
`error` BOOLEAN DEFAULT 0,
- `keep_history` MEDIUMINT NOT NULL DEFAULT -2, -- v0.7
`ttl` INT NOT NULL DEFAULT 0, -- v0.7.3
`attributes` TEXT, -- v1.11.0
`cache_nbEntries` INT DEFAULT 0, -- v0.7
`cache_nbUnreads` INT DEFAULT 0, -- v0.7
PRIMARY KEY (`id`),
- FOREIGN KEY (`category`) REFERENCES `%1$scategory`(`id`) ON DELETE SET NULL ON UPDATE CASCADE,
+ FOREIGN KEY (`category`) REFERENCES `_category`(`id`) ON DELETE SET NULL ON UPDATE CASCADE,
UNIQUE KEY (`url`), -- v0.7
INDEX (`name`), -- v0.7
- INDEX (`priority`), -- v0.7
- INDEX (`keep_history`) -- v0.7
+ INDEX (`priority`) -- v0.7
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
ENGINE = INNODB;
-CREATE TABLE IF NOT EXISTS `%1$sentry` (
+CREATE TABLE IF NOT EXISTS `_entry` (
`id` BIGINT NOT NULL, -- v0.7
`guid` VARCHAR(760) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL, -- Maximum for UNIQUE is 767B
`title` VARCHAR(255) NOT NULL,
`author` VARCHAR(255),
- `content_bin` BLOB, -- v0.7
+ `content_bin` MEDIUMBLOB, -- v0.7
`link` VARCHAR(1023) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL,
`date` INT(11), -- Until year 2038
`lastSeen` INT(11) DEFAULT 0, -- v1.1.1, Until year 2038
@@ -51,25 +52,29 @@ CREATE TABLE IF NOT EXISTS `%1$sentry` (
`id_feed` SMALLINT, -- v0.7
`tags` VARCHAR(1023),
PRIMARY KEY (`id`),
- FOREIGN KEY (`id_feed`) REFERENCES `%1$sfeed`(`id`) ON DELETE CASCADE ON UPDATE CASCADE,
+ FOREIGN KEY (`id_feed`) REFERENCES `_feed`(`id`) ON DELETE CASCADE ON UPDATE CASCADE,
UNIQUE KEY (`id_feed`,`guid`), -- v0.7
INDEX (`is_favorite`), -- v0.7
INDEX (`is_read`), -- v0.7
- INDEX `entry_lastSeen_index` (`lastSeen`) -- v1.1.1
- -- INDEX `entry_feed_read_index` (`id_feed`,`is_read`) -- v1.7 Located futher down
+ INDEX `entry_lastSeen_index` (`lastSeen`), -- v1.1.1
+ INDEX `entry_feed_read_index` (`id_feed`,`is_read`) -- v1.7
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
ENGINE = INNODB;
-INSERT IGNORE INTO `%1$scategory` (id, name) VALUES(1, "%2$s");
-');
+INSERT IGNORE INTO `_category` (id, name) VALUES(1, "Uncategorized");
+SQL;
-define('SQL_CREATE_TABLE_ENTRYTMP', '
-CREATE TABLE IF NOT EXISTS `%1$sentrytmp` ( -- v1.7
+$SQL_CREATE_INDEX_ENTRY_1 = <<<'SQL'
+CREATE INDEX `entry_feed_read_index` ON `_entry` (`id_feed`,`is_read`); -- v1.7
+SQL;
+
+$SQL_CREATE_TABLE_ENTRYTMP = <<<'SQL'
+CREATE TABLE IF NOT EXISTS `_entrytmp` ( -- v1.7
`id` BIGINT NOT NULL,
`guid` VARCHAR(760) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL,
`title` VARCHAR(255) NOT NULL,
`author` VARCHAR(255),
- `content_bin` BLOB,
+ `content_bin` MEDIUMBLOB,
`link` VARCHAR(1023) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL,
`date` INT(11),
`lastSeen` INT(11) DEFAULT 0,
@@ -79,17 +84,15 @@ CREATE TABLE IF NOT EXISTS `%1$sentrytmp` ( -- v1.7
`id_feed` SMALLINT,
`tags` VARCHAR(1023),
PRIMARY KEY (`id`),
- FOREIGN KEY (`id_feed`) REFERENCES `%1$sfeed`(`id`) ON DELETE CASCADE ON UPDATE CASCADE,
+ FOREIGN KEY (`id_feed`) REFERENCES `_feed`(`id`) ON DELETE CASCADE ON UPDATE CASCADE,
UNIQUE KEY (`id_feed`,`guid`),
INDEX (`date`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
ENGINE = INNODB;
+SQL;
-CREATE INDEX `entry_feed_read_index` ON `%1$sentry`(`id_feed`,`is_read`); -- v1.7 Located here to be auto-added
-');
-
-define('SQL_CREATE_TABLE_TAGS', '
-CREATE TABLE IF NOT EXISTS `%1$stag` ( -- v1.12
+$SQL_CREATE_TABLE_TAGS = <<<'SQL'
+CREATE TABLE IF NOT EXISTS `_tag` ( -- v1.12
`id` SMALLINT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(63) NOT NULL,
`attributes` TEXT,
@@ -98,46 +101,27 @@ CREATE TABLE IF NOT EXISTS `%1$stag` ( -- v1.12
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
ENGINE = INNODB;
-CREATE TABLE IF NOT EXISTS `%1$sentrytag` ( -- v1.12
+CREATE TABLE IF NOT EXISTS `_entrytag` ( -- v1.12
`id_tag` SMALLINT,
`id_entry` BIGINT,
PRIMARY KEY (`id_tag`,`id_entry`),
- FOREIGN KEY (`id_tag`) REFERENCES `%1$stag`(`id`) ON DELETE CASCADE ON UPDATE CASCADE,
- FOREIGN KEY (`id_entry`) REFERENCES `%1$sentry`(`id`) ON DELETE CASCADE ON UPDATE CASCADE,
+ FOREIGN KEY (`id_tag`) REFERENCES `_tag`(`id`) ON DELETE CASCADE ON UPDATE CASCADE,
+ FOREIGN KEY (`id_entry`) REFERENCES `_entry`(`id`) ON DELETE CASCADE ON UPDATE CASCADE,
INDEX (`id_entry`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
ENGINE = INNODB;
-');
-
-define('SQL_INSERT_FEEDS', '
-INSERT IGNORE INTO `%1$sfeed` (url, category, name, website, description, ttl) VALUES("https://freshrss.org/feeds/all.atom.xml", 1, "FreshRSS.org", "https://freshrss.org/", "FreshRSS, a free, self-hostable aggregator…", 86400);
-INSERT IGNORE INTO `%1$sfeed` (url, category, name, website, description, ttl) VALUES("https://github.com/FreshRSS/FreshRSS/releases.atom", 1, "FreshRSS @ GitHub", "https://github.com/FreshRSS/FreshRSS/", "FreshRSS releases @ GitHub", 86400);
-');
-
-define('SQL_DROP_TABLES', 'DROP TABLE IF EXISTS `%1$sentrytag`, `%1$stag`, `%1$sentrytmp`, `%1$sentry`, `%1$sfeed`, `%1$scategory`');
-
-define('SQL_UPDATE_UTF8MB4', '
-ALTER DATABASE `%2$s` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- v1.5.0
-
-ALTER TABLE `%1$scategory` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-UPDATE `%1$scategory` SET name=SUBSTRING(name,1,' . FreshRSS_DatabaseDAO::LENGTH_INDEX_UNICODE . ') WHERE LENGTH(name) > ' . FreshRSS_DatabaseDAO::LENGTH_INDEX_UNICODE . ';
-ALTER TABLE `%1$scategory` MODIFY `name` VARCHAR(' . FreshRSS_DatabaseDAO::LENGTH_INDEX_UNICODE . ') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL;
-OPTIMIZE TABLE `%1$scategory`;
+SQL;
-ALTER TABLE `%1$sfeed` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-UPDATE `%1$sfeed` SET name=SUBSTRING(name,1,' . FreshRSS_DatabaseDAO::LENGTH_INDEX_UNICODE . ') WHERE LENGTH(name) > ' . FreshRSS_DatabaseDAO::LENGTH_INDEX_UNICODE . ';
-ALTER TABLE `%1$sfeed` MODIFY `name` VARCHAR(' . FreshRSS_DatabaseDAO::LENGTH_INDEX_UNICODE . ') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL;
-ALTER TABLE `%1$sfeed` MODIFY `description` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-OPTIMIZE TABLE `%1$sfeed`;
+$SQL_INSERT_FEED = <<<'SQL'
+INSERT IGNORE INTO `_feed` (url, category, name, website, description, ttl)
+ VALUES(:url, 1, :name, :website, :description, 86400);
+SQL;
-ALTER TABLE `%1$sentry` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-ALTER TABLE `%1$sentry` MODIFY `title` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL;
-ALTER TABLE `%1$sentry` MODIFY `author` VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-ALTER TABLE `%1$sentry` MODIFY `tags` VARCHAR(1023) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-OPTIMIZE TABLE `%1$sentry`;
-');
+$SQL_DROP_TABLES = <<<'SQL'
+DROP TABLE IF EXISTS `_entrytag`, `_tag`, `_entrytmp`, `_entry`, `_feed`, `_category`;
+SQL;
-define('SQL_UPDATE_GUID_LATIN1_BIN', ' -- v1.12
-ALTER TABLE `%1$sentrytmp` MODIFY `guid` VARCHAR(760) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL;
-ALTER TABLE `%1$sentry` MODIFY `guid` VARCHAR(760) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL;
-');
+$SQL_UPDATE_GUID_LATIN1_BIN = <<<'SQL'
+ALTER TABLE `_entrytmp` MODIFY `guid` VARCHAR(760) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL; -- v1.12
+ALTER TABLE `_entry` MODIFY `guid` VARCHAR(760) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL;
+SQL;
diff --git a/app/SQL/install.sql.pgsql.php b/app/SQL/install.sql.pgsql.php
index e68e6f3be..53afc8a17 100644
--- a/app/SQL/install.sql.pgsql.php
+++ b/app/SQL/install.sql.pgsql.php
@@ -1,14 +1,16 @@
<?php
-define('SQL_CREATE_DB', 'CREATE DATABASE "%1$s" ENCODING \'UTF8\';');
+$SQL_CREATE_DB = <<<'SQL'
+CREATE DATABASE "%1$s" ENCODING 'UTF8';
+SQL;
-global $SQL_CREATE_TABLES;
-$SQL_CREATE_TABLES = array(
-'CREATE TABLE IF NOT EXISTS "%1$scategory" (
+$SQL_CREATE_TABLES = <<<'SQL'
+CREATE TABLE IF NOT EXISTS `_category` (
"id" SERIAL PRIMARY KEY,
- "name" VARCHAR(255) UNIQUE NOT NULL
-);',
+ "name" VARCHAR(255) UNIQUE NOT NULL,
+ "attributes" TEXT -- v1.15.0
+);
-'CREATE TABLE IF NOT EXISTS "%1$sfeed" (
+CREATE TABLE IF NOT EXISTS `_feed` (
"id" SERIAL PRIMARY KEY,
"url" VARCHAR(511) UNIQUE NOT NULL,
"category" SMALLINT DEFAULT 0,
@@ -20,18 +22,16 @@ $SQL_CREATE_TABLES = array(
"pathEntries" VARCHAR(511) DEFAULT NULL,
"httpAuth" VARCHAR(511) DEFAULT NULL,
"error" SMALLINT DEFAULT 0,
- "keep_history" INT NOT NULL DEFAULT -2,
"ttl" INT NOT NULL DEFAULT 0,
"attributes" TEXT, -- v1.11.0
"cache_nbEntries" INT DEFAULT 0,
"cache_nbUnreads" INT DEFAULT 0,
- FOREIGN KEY ("category") REFERENCES "%1$scategory" ("id") ON DELETE SET NULL ON UPDATE CASCADE
-);',
-'CREATE INDEX "%1$sname_index" ON "%1$sfeed" ("name");',
-'CREATE INDEX "%1$spriority_index" ON "%1$sfeed" ("priority");',
-'CREATE INDEX "%1$skeep_history_index" ON "%1$sfeed" ("keep_history");',
+ FOREIGN KEY ("category") REFERENCES `_category` ("id") ON DELETE SET NULL ON UPDATE CASCADE
+);
+CREATE INDEX IF NOT EXISTS `_name_index` ON `_feed` ("name");
+CREATE INDEX IF NOT EXISTS `_priority_index` ON `_feed` ("priority");
-'CREATE TABLE IF NOT EXISTS "%1$sentry" (
+CREATE TABLE IF NOT EXISTS `_entry` (
"id" BIGINT NOT NULL PRIMARY KEY,
"guid" VARCHAR(760) NOT NULL,
"title" VARCHAR(255) NOT NULL,
@@ -45,22 +45,26 @@ $SQL_CREATE_TABLES = array(
"is_favorite" SMALLINT NOT NULL DEFAULT 0,
"id_feed" SMALLINT,
"tags" VARCHAR(1023),
- FOREIGN KEY ("id_feed") REFERENCES "%1$sfeed" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ FOREIGN KEY ("id_feed") REFERENCES `_feed` ("id") ON DELETE CASCADE ON UPDATE CASCADE,
UNIQUE ("id_feed","guid")
-);',
-'CREATE INDEX "%1$sis_favorite_index" ON "%1$sentry" ("is_favorite");',
-'CREATE INDEX "%1$sis_read_index" ON "%1$sentry" ("is_read");',
-'CREATE INDEX "%1$sentry_lastSeen_index" ON "%1$sentry" ("lastSeen");',
-
-'INSERT INTO "%1$scategory" (id, name)
- SELECT 1, \'%2$s\'
- WHERE NOT EXISTS (SELECT id FROM "%1$scategory" WHERE id = 1)
- RETURNING nextval(\'"%1$scategory_id_seq"\');',
);
+CREATE INDEX IF NOT EXISTS `_is_favorite_index` ON `_entry` ("is_favorite");
+CREATE INDEX IF NOT EXISTS `_is_read_index` ON `_entry` ("is_read");
+CREATE INDEX IF NOT EXISTS `_entry_lastSeen_index` ON `_entry` ("lastSeen");
+CREATE INDEX IF NOT EXISTS `_entry_feed_read_index` ON `_entry` ("id_feed","is_read"); -- v1.7
+
+INSERT INTO `_category` (id, name)
+ SELECT 1, 'Uncategorized'
+ WHERE NOT EXISTS (SELECT id FROM `_category` WHERE id = 1)
+ RETURNING nextval('`_category_id_seq`');
+SQL;
-global $SQL_CREATE_TABLE_ENTRYTMP;
-$SQL_CREATE_TABLE_ENTRYTMP = array(
-'CREATE TABLE IF NOT EXISTS "%1$sentrytmp" ( -- v1.7
+$SQL_CREATE_INDEX_ENTRY_1 = <<<'SQL'
+CREATE INDEX IF NOT EXISTS `_entry_feed_read_index` ON `_entry` ("id_feed","is_read"); -- v1.7
+SQL;
+
+$SQL_CREATE_TABLE_ENTRYTMP = <<<'SQL'
+CREATE TABLE IF NOT EXISTS `_entrytmp` ( -- v1.7
"id" BIGINT NOT NULL PRIMARY KEY,
"guid" VARCHAR(760) NOT NULL,
"title" VARCHAR(255) NOT NULL,
@@ -74,39 +78,34 @@ $SQL_CREATE_TABLE_ENTRYTMP = array(
"is_favorite" SMALLINT NOT NULL DEFAULT 0,
"id_feed" SMALLINT,
"tags" VARCHAR(1023),
- FOREIGN KEY ("id_feed") REFERENCES "%1$sfeed" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ FOREIGN KEY ("id_feed") REFERENCES `_feed` ("id") ON DELETE CASCADE ON UPDATE CASCADE,
UNIQUE ("id_feed","guid")
-);',
-'CREATE INDEX "%1$sentrytmp_date_index" ON "%1$sentrytmp" ("date");',
-
-'CREATE INDEX "%1$sentry_feed_read_index" ON "%1$sentry" ("id_feed","is_read");', //v1.7
);
+CREATE INDEX IF NOT EXISTS `_entrytmp_date_index` ON `_entrytmp` ("date");
+SQL;
-global $SQL_CREATE_TABLE_TAGS;
-$SQL_CREATE_TABLE_TAGS = array(
-'CREATE TABLE IF NOT EXISTS "%1$stag" ( -- v1.12
+$SQL_CREATE_TABLE_TAGS = <<<'SQL'
+CREATE TABLE IF NOT EXISTS `_tag` ( -- v1.12
"id" SERIAL PRIMARY KEY,
"name" VARCHAR(63) UNIQUE NOT NULL,
"attributes" TEXT
-);',
-'CREATE TABLE IF NOT EXISTS "%1$sentrytag" (
+);
+CREATE TABLE IF NOT EXISTS `_entrytag` (
"id_tag" SMALLINT,
"id_entry" BIGINT,
PRIMARY KEY ("id_tag","id_entry"),
- FOREIGN KEY ("id_tag") REFERENCES "%1$stag" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
- FOREIGN KEY ("id_entry") REFERENCES "%1$sentry" ("id") ON DELETE CASCADE ON UPDATE CASCADE
-);',
-'CREATE INDEX "%1$sentrytag_id_entry_index" ON "%1$sentrytag" ("id_entry");',
+ FOREIGN KEY ("id_tag") REFERENCES `_tag` ("id") ON DELETE CASCADE ON UPDATE CASCADE,
+ FOREIGN KEY ("id_entry") REFERENCES `_entry` ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
+CREATE INDEX IF NOT EXISTS `_entrytag_id_entry_index` ON `_entrytag` ("id_entry");
+SQL;
-global $SQL_INSERT_FEEDS;
-$SQL_INSERT_FEEDS = array(
-'INSERT INTO "%1$sfeed" (url, category, name, website, description, ttl)
- SELECT \'https://freshrss.org/feeds/all.atom.xml\', 1, \'FreshRSS.org\', \'https://freshrss.org/\', \'FreshRSS, a free, self-hostable aggregator…\', 86400
- WHERE NOT EXISTS (SELECT id FROM "%1$sfeed" WHERE url = \'https://freshrss.org/feeds/all.atom.xml\');',
-'INSERT INTO "%1$sfeed" (url, category, name, website, description, ttl)
- SELECT \'https://github.com/FreshRSS/FreshRSS/releases.atom\', 1, \'FreshRSS @ GitHub\', \'https://github.com/FreshRSS/FreshRSS/\', \'FreshRSS releases @ GitHub\', 86400
- WHERE NOT EXISTS (SELECT id FROM "%1$sfeed" WHERE url = \'https://github.com/FreshRSS/FreshRSS/releases.atom\');',
-);
+$SQL_INSERT_FEED = <<<'SQL'
+INSERT INTO `_feed` (url, category, name, website, description, ttl)
+ SELECT :url::VARCHAR, 1, :name, :website, :description, 86400
+ WHERE NOT EXISTS (SELECT id FROM `_feed` WHERE url = :url);
+SQL;
-define('SQL_DROP_TABLES', 'DROP TABLE IF EXISTS "%1$sentrytag", "%1$stag", "%1$sentrytmp", "%1$sentry", "%1$sfeed", "%1$scategory"');
+$SQL_DROP_TABLES = <<<'SQL'
+DROP TABLE IF EXISTS `_entrytag`, `_tag`, `_entrytmp`, `_entry`, `_feed`, `_category`;
+SQL;
diff --git a/app/SQL/install.sql.sqlite.php b/app/SQL/install.sql.sqlite.php
index 1dd5f2647..2a4763637 100644
--- a/app/SQL/install.sql.sqlite.php
+++ b/app/SQL/install.sql.sqlite.php
@@ -1,13 +1,17 @@
<?php
-global $SQL_CREATE_TABLES;
-$SQL_CREATE_TABLES = array(
-'CREATE TABLE IF NOT EXISTS `category` (
+$SQL_CREATE_DB = <<<'SQL'
+SELECT 1; -- Do nothing for SQLite
+SQL;
+
+$SQL_CREATE_TABLES = <<<'SQL'
+CREATE TABLE IF NOT EXISTS `category` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
`name` VARCHAR(255) NOT NULL,
+ `attributes` TEXT, -- v1.15.0
UNIQUE (`name`)
-);',
+);
-'CREATE TABLE IF NOT EXISTS `feed` (
+CREATE TABLE IF NOT EXISTS `feed` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
`url` VARCHAR(511) NOT NULL,
`category` SMALLINT DEFAULT 0,
@@ -19,19 +23,17 @@ $SQL_CREATE_TABLES = array(
`pathEntries` VARCHAR(511) DEFAULT NULL,
`httpAuth` VARCHAR(511) DEFAULT NULL,
`error` BOOLEAN DEFAULT 0,
- `keep_history` MEDIUMINT NOT NULL DEFAULT -2,
`ttl` INT NOT NULL DEFAULT 0,
`attributes` TEXT, -- v1.11.0
`cache_nbEntries` INT DEFAULT 0,
`cache_nbUnreads` INT DEFAULT 0,
FOREIGN KEY (`category`) REFERENCES `category`(`id`) ON DELETE SET NULL ON UPDATE CASCADE,
UNIQUE (`url`)
-);',
-'CREATE INDEX IF NOT EXISTS feed_name_index ON `feed`(`name`);',
-'CREATE INDEX IF NOT EXISTS feed_priority_index ON `feed`(`priority`);',
-'CREATE INDEX IF NOT EXISTS feed_keep_history_index ON `feed`(`keep_history`);',
+);
+CREATE INDEX IF NOT EXISTS feed_name_index ON `feed`(`name`);
+CREATE INDEX IF NOT EXISTS feed_priority_index ON `feed`(`priority`);
-'CREATE TABLE IF NOT EXISTS `entry` (
+CREATE TABLE IF NOT EXISTS `entry` (
`id` BIGINT NOT NULL,
`guid` VARCHAR(760) NOT NULL,
`title` VARCHAR(255) NOT NULL,
@@ -48,17 +50,21 @@ $SQL_CREATE_TABLES = array(
PRIMARY KEY (`id`),
FOREIGN KEY (`id_feed`) REFERENCES `feed`(`id`) ON DELETE CASCADE ON UPDATE CASCADE,
UNIQUE (`id_feed`,`guid`)
-);',
-'CREATE INDEX IF NOT EXISTS entry_is_favorite_index ON `entry`(`is_favorite`);',
-'CREATE INDEX IF NOT EXISTS entry_is_read_index ON `entry`(`is_read`);',
-'CREATE INDEX IF NOT EXISTS entry_lastSeen_index ON `entry`(`lastSeen`);', //v1.1.1
-
-'INSERT OR IGNORE INTO `category` (id, name) VALUES(1, "%2$s");',
);
+CREATE INDEX IF NOT EXISTS entry_is_favorite_index ON `entry`(`is_favorite`);
+CREATE INDEX IF NOT EXISTS entry_is_read_index ON `entry`(`is_read`);
+CREATE INDEX IF NOT EXISTS entry_lastSeen_index ON `entry`(`lastSeen`); -- //v1.1.1
+CREATE INDEX IF NOT EXISTS entry_feed_read_index ON `entry`(`id_feed`,`is_read`); -- v1.7
+
+INSERT OR IGNORE INTO `category` (id, name) VALUES(1, "Uncategorized");
+SQL;
-global $SQL_CREATE_TABLE_ENTRYTMP;
-$SQL_CREATE_TABLE_ENTRYTMP = array(
-'CREATE TABLE IF NOT EXISTS `entrytmp` ( -- v1.7
+$SQL_CREATE_INDEX_ENTRY_1 = <<<'SQL'
+CREATE INDEX IF NOT EXISTS entry_feed_read_index ON `entry`(`id_feed`,`is_read`); -- v1.7
+SQL;
+
+$SQL_CREATE_TABLE_ENTRYTMP = <<<'SQL'
+CREATE TABLE IF NOT EXISTS `entrytmp` ( -- v1.7
`id` BIGINT NOT NULL,
`guid` VARCHAR(760) NOT NULL,
`title` VARCHAR(255) NOT NULL,
@@ -75,36 +81,37 @@ $SQL_CREATE_TABLE_ENTRYTMP = array(
PRIMARY KEY (`id`),
FOREIGN KEY (`id_feed`) REFERENCES `feed`(`id`) ON DELETE CASCADE ON UPDATE CASCADE,
UNIQUE (`id_feed`,`guid`)
-);',
-'CREATE INDEX IF NOT EXISTS entrytmp_date_index ON `entrytmp`(`date`);',
-
-'CREATE INDEX IF NOT EXISTS `entry_feed_read_index` ON `entry`(`id_feed`,`is_read`);', //v1.7
);
+CREATE INDEX IF NOT EXISTS entrytmp_date_index ON `entrytmp`(`date`);
+SQL;
-global $SQL_CREATE_TABLE_TAGS;
-$SQL_CREATE_TABLE_TAGS = array(
-'CREATE TABLE IF NOT EXISTS `tag` ( -- v1.12
+$SQL_CREATE_TABLE_TAGS = <<<'SQL'
+CREATE TABLE IF NOT EXISTS `tag` ( -- v1.12
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
`name` VARCHAR(63) NOT NULL,
`attributes` TEXT,
UNIQUE (`name`)
-);',
-'CREATE TABLE IF NOT EXISTS `entrytag` (
+);
+CREATE TABLE IF NOT EXISTS `entrytag` (
`id_tag` SMALLINT,
- `id_entry` SMALLINT,
+ `id_entry` BIGINT,
PRIMARY KEY (`id_tag`,`id_entry`),
FOREIGN KEY (`id_tag`) REFERENCES `tag` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (`id_entry`) REFERENCES `entry` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
-);',
-'CREATE INDEX entrytag_id_entry_index ON `entrytag` (`id_entry`);',
);
+CREATE INDEX IF NOT EXISTS entrytag_id_entry_index ON `entrytag` (`id_entry`);
+SQL;
-global $SQL_INSERT_FEEDS;
-$SQL_INSERT_FEEDS = array(
-'INSERT OR IGNORE INTO `feed` (url, category, name, website, description, ttl)
- VALUES ("https://freshrss.org/feeds/all.atom.xml", 1, "FreshRSS.org", "https://freshrss.org/", "FreshRSS, a free, self-hostable aggregator…", 86400);',
-'INSERT OR IGNORE INTO `feed` (url, category, name, website, description, ttl)
- VALUES ("https://github.com/FreshRSS/FreshRSS/releases.atom", 1, "FreshRSS releases", "https://github.com/FreshRSS/FreshRSS/", "FreshRSS releases @ GitHub", 86400);',
-);
+$SQL_INSERT_FEED = <<<'SQL'
+INSERT OR IGNORE INTO `feed` (url, category, name, website, description, ttl)
+ VALUES(:url, 1, :name, :website, :description, 86400);
+SQL;
-define('SQL_DROP_TABLES', 'DROP TABLE IF EXISTS `entrytag`, `tag`, `entrytmp`, `entry`, `feed`, `category`');
+$SQL_DROP_TABLES = <<<'SQL'
+DROP TABLE IF EXISTS `entrytag`;
+DROP TABLE IF EXISTS `tag`;
+DROP TABLE IF EXISTS `entrytmp`;
+DROP TABLE IF EXISTS `entry`;
+DROP TABLE IF EXISTS `feed`;
+DROP TABLE IF EXISTS `category`;
+SQL;
diff --git a/app/i18n/cz/admin.php b/app/i18n/cz/admin.php
index 68127f571..a2a509560 100644
--- a/app/i18n/cz/admin.php
+++ b/app/i18n/cz/admin.php
@@ -163,6 +163,7 @@ return array(
'help' => 'in seconds', //TODO - Translation
'number' => 'Duration to keep logged in', //TODO - Translation
),
+ 'force_email_validation' => 'Force email addresses validation', //TODO - Translation
'instance-name' => 'Instance name', //TODO - Translation
'max-categories' => 'Categories per user limit', //TODO - Translation
'max-feeds' => 'Feeds per user limit', //TODO - Translation
diff --git a/app/i18n/cz/conf.php b/app/i18n/cz/conf.php
index a2618e310..056e895a7 100644
--- a/app/i18n/cz/conf.php
+++ b/app/i18n/cz/conf.php
@@ -3,13 +3,21 @@
return array(
'archiving' => array(
'_' => 'Archivace',
- 'advanced' => 'Pokročilé',
'delete_after' => 'Smazat články starší než',
+ 'exception' => 'Purge exception', //TODO - Translation
'help' => 'Více možností je dostupných v nastavení jednotlivých kanálů',
- 'keep_history_by_feed' => 'Zachovat tento minimální počet článků v každém kanálu',
+ 'keep_favourites' => 'Never delete favourites', //TODO - Translation
+ 'keep_min_by_feed' => 'Zachovat tento minimální počet článků v každém kanálu',
+ 'keep_labels' => 'Never delete labels', //TODO - Translation
+ 'keep_unreads' => 'Never delete unreads', //TODO - Translation
+ 'maintenance' => 'Maintenance', //TODO - Translation
'optimize' => 'Optimalizovat databázi',
'optimize_help' => 'Občasná údržba zmenší velikost databáze',
+ 'policy' => 'Purge policy', //TODO - Translation
+ 'policy_warning' => 'If no purge policy is selected, every article will be kept.', //TODO - Translation
'purge_now' => 'Vyčistit nyní',
+ 'keep_max' => 'Maximum number of articles to keep', //TODO - Translation
+ 'keep_period' => 'Maximum age of articles to keep', //TODO - Translation
'title' => 'Archivace',
'ttl' => 'Neaktualizovat častěji než',
),
@@ -21,6 +29,7 @@ return array(
'publication_date' => 'Datum vydání',
'related_tags' => 'Související tagy', //TODO - Translation
'sharing' => 'Sdílení',
+ 'display_authors' => 'Authors', //TODO - Translation
'top_line' => 'Horní řádek',
),
'language' => 'Jazyk',
@@ -45,6 +54,7 @@ return array(
'_' => 'Smazání účtu',
'warn' => 'Váš účet bude smazán spolu se všemi souvisejícími daty',
),
+ 'email' => 'Email',
'password_api' => 'Password API<br /><small>(tzn. pro mobilní aplikace)</small>',
'password_form' => 'Heslo<br /><small>(pro přihlášení webovým formulářem)</small>',
'password_format' => 'Alespoň 7 znaků',
@@ -133,7 +143,6 @@ return array(
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'more_information' => 'Více informací',
'print' => 'Tisk',
'remove' => 'Remove sharing method', //TODO - Translation
diff --git a/app/i18n/cz/gen.php b/app/i18n/cz/gen.php
index 08fce0280..de1456187 100644
--- a/app/i18n/cz/gen.php
+++ b/app/i18n/cz/gen.php
@@ -3,6 +3,7 @@
return array(
'action' => array(
'actualize' => 'Aktualizovat',
+ 'back' => '← Go back', //TODO - Translation
'back_to_rss_feeds' => '← Zpět na seznam RSS kanálů',
'cancel' => 'Zrušit',
'create' => 'Vytvořit',
@@ -22,6 +23,7 @@ return array(
'update' => 'Update', //TODO - Translation
),
'auth' => array(
+ 'accept_tos' => 'I accept the <a href="%s">Terms of Service</a>.', // TODO - Translation
'email' => 'Email',
'keep_logged_in' => 'Zapamatovat přihlášení <small>(%s dny)</small>',
'login' => 'Login',
@@ -160,15 +162,22 @@ return array(
'nothing_to_load' => 'Žádné nové články',
'previous' => 'Předchozí',
),
+ 'period' => array(
+ 'days' => 'days', //TODO - Translation
+ 'hours' => 'hours', //TODO - Translation
+ 'months' => 'months', //TODO - Translation
+ 'weeks' => 'weeks', //TODO - Translation
+ 'years' => 'years', //TODO - Translation
+ ),
'share' => array(
'blogotext' => 'Blogotext',
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'gnusocial' => 'GNU social',
'jdh' => 'Journal du hacker',
'Known' => 'Known based sites',
+ 'lemmy' => 'Lemmy',
'linkedin' => 'LinkedIn',
'mastodon' => 'Mastodon',
'movim' => 'Movim',
diff --git a/app/i18n/cz/index.php b/app/i18n/cz/index.php
index 00f424fe8..078ca5ca1 100644
--- a/app/i18n/cz/index.php
+++ b/app/i18n/cz/index.php
@@ -7,7 +7,7 @@ return array(
'bugs_reports' => 'Hlášení chyb',
'credits' => 'Poděkování',
'credits_content' => 'Některé designové prvky pocházejí z <a href="http://twitter.github.io/bootstrap/">Bootstrap</a>, FreshRSS ale tuto platformu nevyužívá. <a href="https://git.gnome.org/browse/gnome-icon-theme-symbolic">Ikony</a> pocházejí z <a href="https://www.gnome.org/">GNOME projektu</a>. Font <em>Open Sans</em> vytvořil <a href="https://fonts.google.com/specimen/Open+Sans">Steve Matteson</a>. FreshRSS je založen na PHP framework <a href="https://github.com/marienfressinaud/MINZ">Minz</a>.',
- 'freshrss_description' => 'FreshRSS je čtečka RSS kanálů určená k provozu na vlastním serveru, podobná <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> nebo <a href="http://leed.idleman.fr/">Leed</a>. Je to nenáročný a jednoduchý, zároveň ale mocný a konfigurovatelný nástroj.',
+ 'freshrss_description' => 'FreshRSS je čtečka RSS kanálů určená k provozu na vlastním serveru, podobná <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> nebo <a href="https://github.com/LeedRSS/Leed">Leed</a>. Je to nenáročný a jednoduchý, zároveň ale mocný a konfigurovatelný nástroj.',
'github' => '<a href="https://github.com/FreshRSS/FreshRSS/issues">na Github</a>',
'license' => 'Licence',
'project_website' => 'Stránka projektu',
@@ -15,6 +15,9 @@ return array(
'version' => 'Verze',
'website' => 'Webové stránka',
),
+ 'tos' => array(
+ 'title' => 'Terms of Service', // TODO - Translation
+ ),
'feed' => array(
'add' => 'Můžete přidat kanály.',
'empty' => 'Žádné články k zobrazení.',
diff --git a/app/i18n/cz/sub.php b/app/i18n/cz/sub.php
index b2bdf416b..f2c259d15 100644
--- a/app/i18n/cz/sub.php
+++ b/app/i18n/cz/sub.php
@@ -13,9 +13,12 @@ return array(
'category' => array(
'_' => 'Kategorie',
'add' => 'Přidat kategorii',
+ 'archiving' => 'Archivace',
'empty' => 'Vyprázdit kategorii',
'information' => 'Informace',
'new' => 'Nová kategorie',
+ 'position' => 'Display position', //TODO - Translation
+ 'position_help' => 'To control category sort order', //TODO - Translation
'title' => 'Název',
),
'feed' => array(
@@ -40,7 +43,7 @@ return array(
'help' => 'Write one search filter per line.', //TODO - Translation
),
'information' => 'Informace',
- 'keep_history' => 'Zachovat tento minimální počet článků',
+ 'keep_min' => 'Zachovat tento minimální počet článků',
'moved_category_deleted' => 'Po smazání kategorie budou v ní obsažené kanály automaticky přesunuty do <em>%s</em>.',
'mute' => 'mute', //TODO - Translation
'no_selected' => 'Nejsou označeny žádné kanály.',
@@ -72,6 +75,7 @@ return array(
),
'firefox' => array(
'documentation' => 'Follow the steps described <a href="https://developer.mozilla.org/en-US/Firefox/Releases/2/Adding_feed_readers_to_Firefox#Adding_a_new_feed_reader_manually">here</a> to add FreshRSS to Firefox feed reader list.',// TODO
+ 'obsolete_63' => 'From version 63 and onwards, Firefox has removed the ability to add your own subscription services that are not standalone programs.', //TODO - Translation
'title' => 'Firefox feed reader', //TODO - Translation
),
'import_export' => array(
diff --git a/app/i18n/cz/user.php b/app/i18n/cz/user.php
new file mode 100644
index 000000000..3a8343c11
--- /dev/null
+++ b/app/i18n/cz/user.php
@@ -0,0 +1,37 @@
+<?php
+
+return array(
+ 'email' => array(
+ 'feedback' => array(
+ 'invalid' => 'The email address is invalid.', //TODO - Translation
+ 'required' => 'The email address is required.', //TODO - Translation
+ ),
+ 'validation' => array(
+ 'change_email' => 'You can change your email address <a href="%s">on the profile page</a>.', //TODO - Translation
+ 'email_sent_to' => 'We sent you an email at <strong>%s</strong>, please follow its indications to validate your address.', //TODO - Translation
+ 'feedback' => array(
+ 'email_failed' => 'We couldn’t send you an email because of a misconfiguration of the server.', //TODO - Translation
+ 'email_sent' => 'An email has been sent to your address.', //TODO - Translation
+ 'error' => 'The email address failed to be validated.', //TODO - Translation
+ 'ok' => 'The email address has been validated.', //TODO - Translation
+ 'unneccessary' => 'The email address was already validated.', //TODO - Translation
+ 'wrong_token' => 'The email address failed to be validated due to a wrong token.', //TODO - Translation
+ ),
+ 'need_to' => 'You need to validate your email address before being able to use %s.', //TODO - Translation
+ 'resend_email' => 'Resend the email', //TODO - Translation
+ 'title' => 'Email address validation', //TODO - Translation
+ ),
+ ),
+ 'tos' => array(
+ 'feedback' => array(
+ 'invalid' => 'You must accept the Terms of Service to be able to register.', // TODO - Translation
+ ),
+ ),
+ 'mailer' => array(
+ 'email_need_validation' => array(
+ 'title' => 'You need to validate your account', //TODO - Translation
+ 'welcome' => 'Welcome %s,', //TODO - Translation
+ 'body' => 'You’ve just registered on %s but you still need to validate your email. For that, just follow the link:', //TODO - Translation
+ ),
+ ),
+);
diff --git a/app/i18n/de/admin.php b/app/i18n/de/admin.php
index f0307dcab..d075bf28f 100644
--- a/app/i18n/de/admin.php
+++ b/app/i18n/de/admin.php
@@ -159,6 +159,7 @@ return array(
'system' => array(
'_' => 'Systemeinstellungen',
'auto-update-url' => 'Auto-update URL',
+ 'force_email_validation' => 'Force email addresses validation', //TODO - Translation
'instance-name' => 'Dein Reader Name',
'max-categories' => 'Anzahl erlaubter Kategorien pro Benutzer',
'max-feeds' => 'Anzahl erlaubter Feeds pro Benutzer',
diff --git a/app/i18n/de/conf.php b/app/i18n/de/conf.php
index 40209576e..89bbfc10e 100644
--- a/app/i18n/de/conf.php
+++ b/app/i18n/de/conf.php
@@ -3,13 +3,21 @@
return array(
'archiving' => array(
'_' => 'Archivierung',
- 'advanced' => 'Erweitert',
'delete_after' => 'Entferne Artikel nach',
+ 'exception' => 'Purge exception', //TODO - Translation
'help' => 'Weitere Optionen sind in den Einstellungen der individuellen Feeds verfügbar.',
- 'keep_history_by_feed' => 'Minimale Anzahl an Artikeln, die pro Feed behalten werden',
+ 'keep_favourites' => 'Never delete favourites', //TODO - Translation
+ 'keep_min_by_feed' => 'Minimale Anzahl an Artikeln, die pro Feed behalten werden',
+ 'keep_labels' => 'Never delete labels', //TODO - Translation
+ 'keep_unreads' => 'Never delete unreads', //TODO - Translation
+ 'maintenance' => 'Maintenance', //TODO - Translation
'optimize' => 'Datenbank optimieren',
'optimize_help' => 'Sollte gelegentlich durchgeführt werden, um die Größe der Datenbank zu reduzieren.',
+ 'policy' => 'Purge policy', //TODO - Translation
+ 'policy_warning' => 'If no purge policy is selected, every article will be kept.', //TODO - Translation
'purge_now' => 'Jetzt bereinigen',
+ 'keep_max' => 'Maximum number of articles to keep', //TODO - Translation
+ 'keep_period' => 'Maximum age of articles to keep', //TODO - Translation
'title' => 'Archivierung',
'ttl' => 'Aktualisiere automatisch nicht öfter als',
),
@@ -21,6 +29,7 @@ return array(
'publication_date' => 'Datum der Veröffentlichung',
'related_tags' => 'Verwandte Tags',
'sharing' => 'Teilen',
+ 'display_authors' => 'Authors', //TODO - Translation
'top_line' => 'Kopfzeile',
),
'language' => 'Sprache',
@@ -45,6 +54,7 @@ return array(
'_' => 'Accountlöschung',
'warn' => 'Dein Account und alle damit bezogenen Daten werden gelöscht.',
),
+ 'email' => 'E-Mail-Adresse',
'password_api' => 'Passwort-API<br /><small>(z. B. für mobile Anwendungen)</small>',
'password_form' => 'Passwort<br /><small>(für die Anmeldemethode per Webformular)</small>',
'password_format' => 'mindestens 7 Zeichen',
@@ -133,7 +143,6 @@ return array(
'diaspora' => 'Diaspora*',
'email' => 'E-Mail',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'more_information' => 'Weitere Informationen',
'print' => 'Drucken',
'remove' => 'Entferne Teilen-Dienst',
diff --git a/app/i18n/de/gen.php b/app/i18n/de/gen.php
index c02a55b2c..e2dd2a251 100644
--- a/app/i18n/de/gen.php
+++ b/app/i18n/de/gen.php
@@ -3,6 +3,7 @@
return array(
'action' => array(
'actualize' => 'Aktualisieren',
+ 'back' => '← Go back', //TODO - Translation
'back_to_rss_feeds' => '← Zurück zu Ihren RSS-Feeds gehen',
'cancel' => 'Abbrechen',
'create' => 'Erstellen',
@@ -22,6 +23,7 @@ return array(
'update' => 'Aktualisieren',
),
'auth' => array(
+ 'accept_tos' => 'I accept the <a href="%s">Terms of Service</a>.', // TODO - Translation
'email' => 'E-Mail-Adresse',
'keep_logged_in' => 'Eingeloggt bleiben <small>(%s Tage)</small>',
'login' => 'Anmelden',
@@ -160,15 +162,22 @@ return array(
'nothing_to_load' => 'Es gibt keine weiteren Artikel',
'previous' => 'Vorherige',
),
+ 'period' => array(
+ 'days' => 'days', //TODO - Translation
+ 'hours' => 'hours', //TODO - Translation
+ 'months' => 'months', //TODO - Translation
+ 'weeks' => 'weeks', //TODO - Translation
+ 'years' => 'years', //TODO - Translation
+ ),
'share' => array(
'blogotext' => 'Blogotext',
'diaspora' => 'Diaspora*',
'email' => 'E-Mail',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'gnusocial' => 'GNU social',
'jdh' => 'Journal du hacker',
'Known' => 'Known-Seite (https://withknown.com)',
+ 'lemmy' => 'Lemmy',
'linkedin' => 'LinkedIn',
'mastodon' => 'Mastodon',
'movim' => 'Movim',
diff --git a/app/i18n/de/index.php b/app/i18n/de/index.php
index 10172e6f5..85ab3bb26 100644
--- a/app/i18n/de/index.php
+++ b/app/i18n/de/index.php
@@ -7,7 +7,7 @@ return array(
'bugs_reports' => 'Fehlerberichte',
'credits' => 'Credits',
'credits_content' => 'Einige Designelemente stammen von <a href="http://twitter.github.io/bootstrap/">Bootstrap</a>, obwohl FreshRSS dieses Framework nicht nutzt. <a href="https://git.gnome.org/browse/gnome-icon-theme-symbolic">Icons</a> stammen vom <a href="https://www.gnome.org/">GNOME project</a>. <em>Open Sans</em> Font wurde von <a href="https://fonts.google.com/specimen/Open+Sans">Steve Matteson</a> erstellt. FreshRSS basiert auf <a href="https://github.com/marienfressinaud/MINZ">Minz</a>, einem PHP-Framework.',
- 'freshrss_description' => 'FreshRSS ist ein RSS-Feedsaggregator zum selbst hosten wie zum Beispiel <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> oder <a href="http://leed.idleman.fr/">Leed</a>. Er ist leicht und einfach zu handhaben und gleichzeitig ein leistungsstarkes und konfigurierbares Werkzeug.',
+ 'freshrss_description' => 'FreshRSS ist ein RSS-Feedsaggregator zum selbst hosten wie zum Beispiel <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> oder <a href="https://github.com/LeedRSS/Leed">Leed</a>. Er ist leicht und einfach zu handhaben und gleichzeitig ein leistungsstarkes und konfigurierbares Werkzeug.',
'github' => '<a href="https://github.com/FreshRSS/FreshRSS/issues">on Github</a>',
'license' => 'Lizenz',
'project_website' => 'Projekt-Webseite',
@@ -15,6 +15,9 @@ return array(
'version' => 'Version',
'website' => 'Webseite',
),
+ 'tos' => array(
+ 'title' => 'Terms of Service', // TODO - Translation
+ ),
'feed' => array(
'add' => 'Sie können Feeds hinzufügen.',
'empty' => 'Es gibt keinen Artikel zum Anzeigen.',
diff --git a/app/i18n/de/sub.php b/app/i18n/de/sub.php
index abc01b954..754ac0866 100644
--- a/app/i18n/de/sub.php
+++ b/app/i18n/de/sub.php
@@ -13,9 +13,12 @@ return array(
'category' => array(
'_' => 'Kategorie',
'add' => 'Eine Kategorie hinzufügen',
+ 'archiving' => 'Archivierung',
'empty' => 'Leere Kategorie',
'information' => 'Information',
'new' => 'Neue Kategorie',
+ 'position' => 'Display position', //TODO - Translation
+ 'position_help' => 'To control category sort order', //TODO - Translation
'title' => 'Titel',
),
'feed' => array(
@@ -40,7 +43,7 @@ return array(
'help' => 'Write one search filter per line.', //TODO - Translation
),
'information' => 'Information',
- 'keep_history' => 'Minimale Anzahl an Artikeln, die behalten wird',
+ 'keep_min' => 'Minimale Anzahl an Artikeln, die behalten wird',
'moved_category_deleted' => 'Wenn Sie eine Kategorie entfernen, werden deren Feeds automatisch in die Kategorie <em>%s</em> eingefügt.',
'mute' => 'Stumm schalten',
'no_selected' => 'Kein Feed ausgewählt.',
@@ -72,6 +75,7 @@ return array(
),
'firefox' => array(
'documentation' => 'Folge den <a href="https://developer.mozilla.org/en-US/Firefox/Releases/2/Adding_feed_readers_to_Firefox#Adding_a_new_feed_reader_manually">hier</a> beschriebenen Schritten um FreshRSS zu Deiner Firefox RSS-Reader Liste hinzuzufügen.',
+ 'obsolete_63' => 'From version 63 and onwards, Firefox has removed the ability to add your own subscription services that are not standalone programs.', //TODO - Translation
'title' => 'Firefox RSS-Reader',
),
'import_export' => array(
diff --git a/app/i18n/de/user.php b/app/i18n/de/user.php
new file mode 100644
index 000000000..3a8343c11
--- /dev/null
+++ b/app/i18n/de/user.php
@@ -0,0 +1,37 @@
+<?php
+
+return array(
+ 'email' => array(
+ 'feedback' => array(
+ 'invalid' => 'The email address is invalid.', //TODO - Translation
+ 'required' => 'The email address is required.', //TODO - Translation
+ ),
+ 'validation' => array(
+ 'change_email' => 'You can change your email address <a href="%s">on the profile page</a>.', //TODO - Translation
+ 'email_sent_to' => 'We sent you an email at <strong>%s</strong>, please follow its indications to validate your address.', //TODO - Translation
+ 'feedback' => array(
+ 'email_failed' => 'We couldn’t send you an email because of a misconfiguration of the server.', //TODO - Translation
+ 'email_sent' => 'An email has been sent to your address.', //TODO - Translation
+ 'error' => 'The email address failed to be validated.', //TODO - Translation
+ 'ok' => 'The email address has been validated.', //TODO - Translation
+ 'unneccessary' => 'The email address was already validated.', //TODO - Translation
+ 'wrong_token' => 'The email address failed to be validated due to a wrong token.', //TODO - Translation
+ ),
+ 'need_to' => 'You need to validate your email address before being able to use %s.', //TODO - Translation
+ 'resend_email' => 'Resend the email', //TODO - Translation
+ 'title' => 'Email address validation', //TODO - Translation
+ ),
+ ),
+ 'tos' => array(
+ 'feedback' => array(
+ 'invalid' => 'You must accept the Terms of Service to be able to register.', // TODO - Translation
+ ),
+ ),
+ 'mailer' => array(
+ 'email_need_validation' => array(
+ 'title' => 'You need to validate your account', //TODO - Translation
+ 'welcome' => 'Welcome %s,', //TODO - Translation
+ 'body' => 'You’ve just registered on %s but you still need to validate your email. For that, just follow the link:', //TODO - Translation
+ ),
+ ),
+);
diff --git a/app/i18n/en/admin.php b/app/i18n/en/admin.php
index 004089ffc..c5ab183e8 100644
--- a/app/i18n/en/admin.php
+++ b/app/i18n/en/admin.php
@@ -159,6 +159,7 @@ return array(
'system' => array(
'_' => 'System configuration',
'auto-update-url' => 'Auto-update server URL',
+ 'force_email_validation' => 'Force email addresses validation',
'instance-name' => 'Instance name',
'max-categories' => 'Categories per user limit',
'max-feeds' => 'Feeds per user limit',
diff --git a/app/i18n/en/conf.php b/app/i18n/en/conf.php
index fde78f5b5..2d4e06550 100644
--- a/app/i18n/en/conf.php
+++ b/app/i18n/en/conf.php
@@ -3,13 +3,21 @@
return array(
'archiving' => array(
'_' => 'Archiving',
- 'advanced' => 'Advanced',
'delete_after' => 'Remove articles after',
+ 'exception' => 'Purge exception',
'help' => 'More options are available in the individual feed settings',
- 'keep_history_by_feed' => 'Minimum number of articles to keep by feed',
+ 'keep_favourites' => 'Never delete favourites',
+ 'keep_min_by_feed' => 'Minimum number of articles to keep by feed',
+ 'keep_labels' => 'Never delete labels',
+ 'keep_unreads' => 'Never delete unreads',
+ 'maintenance' => 'Maintenance',
'optimize' => 'Optimise database',
'optimize_help' => 'Do occasionally to reduce the size of the database',
+ 'policy' => 'Purge policy',
+ 'policy_warning' => 'If no purge policy is selected, every article will be kept.',
'purge_now' => 'Purge now',
+ 'keep_max' => 'Maximum number of articles to keep',
+ 'keep_period' => 'Maximum age of articles to keep',
'title' => 'Archiving',
'ttl' => 'Do not automatically refresh more often than',
),
@@ -21,6 +29,7 @@ return array(
'publication_date' => 'Date of publication',
'related_tags' => 'Article tags',
'sharing' => 'Sharing',
+ 'display_authors' => 'Authors',
'top_line' => 'Top line',
),
'language' => 'Language',
@@ -45,6 +54,7 @@ return array(
'_' => 'Account deletion',
'warn' => 'Your account and all related data will be deleted.',
),
+ 'email' => 'Email address',
'password_api' => 'API password<br /><small>(e.g., for mobile apps)</small>',
'password_form' => 'Password<br /><small>(for the Web-form login method)</small>',
'password_format' => 'At least 7 characters',
@@ -133,7 +143,6 @@ return array(
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'more_information' => 'More information',
'print' => 'Print',
'remove' => 'Remove sharing method',
diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php
index 32f5ee02e..fc1bd587a 100644
--- a/app/i18n/en/gen.php
+++ b/app/i18n/en/gen.php
@@ -3,6 +3,7 @@
return array(
'action' => array(
'actualize' => 'Actualize',
+ 'back' => '← Go back',
'back_to_rss_feeds' => '← Go back to your RSS feeds',
'cancel' => 'Cancel',
'create' => 'Create',
@@ -22,6 +23,7 @@ return array(
'update' => 'Update',
),
'auth' => array(
+ 'accept_tos' => 'I accept the <a href="%s">Terms of Service</a>.',
'email' => 'Email address',
'keep_logged_in' => 'Keep me logged in <small>(%s days)</small>',
'login' => 'Login',
@@ -127,6 +129,7 @@ return array(
'oc' => 'Occitan',
'pt-br' => 'Português (Brasil)',
'ru' => 'Русский',
+ 'sk' => 'Slovenčina',
'tr' => 'Türkçe',
'zh-cn' => '简体中文',
),
@@ -160,15 +163,22 @@ return array(
'nothing_to_load' => 'There are no more articles',
'previous' => 'Previous',
),
+ 'period' => array(
+ 'days' => 'days',
+ 'hours' => 'hours',
+ 'months' => 'months',
+ 'weeks' => 'weeks',
+ 'years' => 'years',
+ ),
'share' => array(
'blogotext' => 'Blogotext',
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'gnusocial' => 'GNU social',
'jdh' => 'Journal du hacker',
'Known' => 'Known based sites',
+ 'lemmy' => 'Lemmy',
'linkedin' => 'LinkedIn',
'mastodon' => 'Mastodon',
'movim' => 'Movim',
diff --git a/app/i18n/en/index.php b/app/i18n/en/index.php
index 46c415816..71bf8b53e 100644
--- a/app/i18n/en/index.php
+++ b/app/i18n/en/index.php
@@ -7,7 +7,7 @@ return array(
'bugs_reports' => 'Bugs reports',
'credits' => 'Credits',
'credits_content' => 'Some design elements come from <a href="http://twitter.github.io/bootstrap/">Bootstrap</a> although FreshRSS doesn’t use this framework. <a href="https://git.gnome.org/browse/gnome-icon-theme-symbolic">Icons</a> come from <a href="https://www.gnome.org/">GNOME project</a>. <em>Open Sans</em> font police has been created by <a href="https://fonts.google.com/specimen/Open+Sans">Steve Matteson</a>. FreshRSS is based on <a href="https://github.com/marienfressinaud/MINZ">Minz</a>, a PHP framework.',
- 'freshrss_description' => 'FreshRSS is a RSS feeds aggregator to self-host like <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> or <a href="http://leed.idleman.fr/">Leed</a>. It is light and easy to take in hand while being powerful and configurable tool.',
+ 'freshrss_description' => 'FreshRSS is a RSS feeds aggregator to self-host like <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> or <a href="https://github.com/LeedRSS/Leed">Leed</a>. It is light and easy to take in hand while being powerful and configurable tool.',
'github' => '<a href="https://github.com/FreshRSS/FreshRSS/issues">on Github</a>',
'license' => 'License',
'project_website' => 'Project website',
@@ -15,6 +15,9 @@ return array(
'version' => 'Version',
'website' => 'Website',
),
+ 'tos' => array(
+ 'title' => 'Terms of Service',
+ ),
'feed' => array(
'add' => 'You may add some feeds.',
'empty' => 'There is no article to show.',
diff --git a/app/i18n/en/sub.php b/app/i18n/en/sub.php
index fde01f9df..252177940 100644
--- a/app/i18n/en/sub.php
+++ b/app/i18n/en/sub.php
@@ -13,9 +13,12 @@ return array(
'category' => array(
'_' => 'Category',
'add' => 'Add a category',
+ 'archiving' => 'Archiving',
'empty' => 'Empty category',
'information' => 'Information',
'new' => 'New category',
+ 'position' => 'Display position',
+ 'position_help' => 'To control category sort order',
'title' => 'Title',
),
'feed' => array(
@@ -40,7 +43,7 @@ return array(
'help' => 'Write one search filter per line.',
),
'information' => 'Information',
- 'keep_history' => 'Minimum number of articles to keep',
+ 'keep_min' => 'Minimum number of articles to keep',
'moved_category_deleted' => 'When you delete a category, its feeds are automatically classified under <em>%s</em>.',
'mute' => 'mute',
'no_selected' => 'No feed selected.',
@@ -72,6 +75,7 @@ return array(
),
'firefox' => array(
'documentation' => 'Follow the steps described <a href="https://developer.mozilla.org/en-US/Firefox/Releases/2/Adding_feed_readers_to_Firefox#Adding_a_new_feed_reader_manually">here</a> to add FreshRSS to Firefox feed reader list.',
+ 'obsolete_63' => 'From version 63 and onwards, Firefox has removed the ability to add your own subscription services that are not standalone programs.',
'title' => 'Firefox feed reader',
),
'import_export' => array(
diff --git a/app/i18n/en/user.php b/app/i18n/en/user.php
new file mode 100644
index 000000000..54d8dfa4d
--- /dev/null
+++ b/app/i18n/en/user.php
@@ -0,0 +1,37 @@
+<?php
+
+return array(
+ 'email' => array(
+ 'feedback' => array(
+ 'invalid' => 'The email address is invalid.',
+ 'required' => 'The email address is required.',
+ ),
+ 'validation' => array(
+ 'change_email' => 'You can change your email address <a href="%s">on the profile page</a>.',
+ 'email_sent_to' => 'We sent you an email at <strong>%s</strong>, please follow its indications to validate your address.',
+ 'feedback' => array(
+ 'email_failed' => 'We couldn’t send you an email because of a misconfiguration of the server.',
+ 'email_sent' => 'An email has been sent to your address.',
+ 'error' => 'The email address failed to be validated.',
+ 'ok' => 'The email address has been validated.',
+ 'unneccessary' => 'The email address was already validated.',
+ 'wrong_token' => 'The email address failed to be validated due to a wrong token.',
+ ),
+ 'need_to' => 'You need to validate your email address before being able to use %s.',
+ 'resend_email' => 'Resend the email',
+ 'title' => 'Email address validation',
+ ),
+ ),
+ 'tos' => array(
+ 'feedback' => array(
+ 'invalid' => 'You must accept the Terms of Service to be able to register.',
+ ),
+ ),
+ 'mailer' => array(
+ 'email_need_validation' => array(
+ 'title' => 'You need to validate your account',
+ 'welcome' => 'Welcome %s,',
+ 'body' => 'You’ve just registered on %s but you still need to validate your email. For that, just follow the link:',
+ ),
+ ),
+);
diff --git a/app/i18n/es/admin.php b/app/i18n/es/admin.php
index 0ec8549bd..1af3bdcb2 100755
--- a/app/i18n/es/admin.php
+++ b/app/i18n/es/admin.php
@@ -159,6 +159,7 @@ return array(
'system' => array(
'_' => 'Configuración del sistema',
'auto-update-url' => 'URL de auto-actualización',
+ 'force_email_validation' => 'Force email addresses validation', //TODO - Translation
'instance-name' => 'Nombre de la fuente',
'max-categories' => 'Límite de categorías por usuario',
'max-feeds' => 'Límite de fuentes por usuario',
diff --git a/app/i18n/es/conf.php b/app/i18n/es/conf.php
index b7d87f375..7a93a87de 100755
--- a/app/i18n/es/conf.php
+++ b/app/i18n/es/conf.php
@@ -3,13 +3,21 @@
return array(
'archiving' => array(
'_' => 'Archivo',
- 'advanced' => 'Avanzado',
'delete_after' => 'Eliminar artículos tras',
+ 'exception' => 'Purge exception', //TODO - Translation
'help' => 'Hay más opciones disponibles en los ajustes de la fuente',
- 'keep_history_by_feed' => 'Número mínimo de artículos a conservar por fuente',
+ 'keep_favourites' => 'Never delete favourites', //TODO - Translation
+ 'keep_min_by_feed' => 'Número mínimo de artículos a conservar por fuente',
+ 'keep_labels' => 'Never delete labels', //TODO - Translation
+ 'keep_unreads' => 'Never delete unreads', //TODO - Translation
+ 'maintenance' => 'Maintenance', //TODO - Translation
'optimize' => 'Optimizar la base de datos',
'optimize_help' => 'Ejecuta la optimización de vez en cuando para reducir el tamaño de la base de datos',
+ 'policy' => 'Purge policy', //TODO - Translation
+ 'policy_warning' => 'If no purge policy is selected, every article will be kept.', //TODO - Translation
'purge_now' => 'Limpiar ahora',
+ 'keep_max' => 'Maximum number of articles to keep', //TODO - Translation
+ 'keep_period' => 'Maximum age of articles to keep', //TODO - Translation
'title' => 'Archivo',
'ttl' => 'No actualizar automáticamente más de',
),
@@ -21,6 +29,7 @@ return array(
'publication_date' => 'Fecha de publicación',
'related_tags' => 'Etiquetas relacionadas',
'sharing' => 'Compartir',
+ 'display_authors' => 'Authors', //TODO - Translation
'top_line' => 'Línea superior',
),
'language' => 'Idioma',
@@ -45,6 +54,7 @@ return array(
'_' => 'Borrar cuenta',
'warn' => 'Tu cuenta y todos los datos asociados serán eliminados.',
),
+ 'email' => 'Correo electrónico',
'password_api' => 'Contraseña API <br /><small>(para apps móviles, por ej.)</small>',
'password_form' => 'Contraseña<br /><small>(para el método de identificación por formulario web)</small>',
'password_format' => 'Mínimo de 7 caracteres',
@@ -133,7 +143,6 @@ return array(
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'more_information' => 'Más información',
'print' => 'Print',
'remove' => 'Remove sharing method', //TODO - Translation
diff --git a/app/i18n/es/gen.php b/app/i18n/es/gen.php
index db36e5f5b..538ddc8fe 100755
--- a/app/i18n/es/gen.php
+++ b/app/i18n/es/gen.php
@@ -3,6 +3,7 @@
return array(
'action' => array(
'actualize' => 'Actualizar',
+ 'back' => '← Go back', //TODO - Translation
'back_to_rss_feeds' => '← regresar a tus fuentes RSS',
'cancel' => 'Cancelar',
'create' => 'Crear',
@@ -22,6 +23,7 @@ return array(
'update' => 'Update', //TODO - Translation
),
'auth' => array(
+ 'accept_tos' => 'I accept the <a href="%s">Terms of Service</a>.', // TODO - Translation
'email' => 'Correo electrónico',
'keep_logged_in' => 'Mantenerme identificado <small>(%s días)</small>',
'login' => 'Conectar',
@@ -160,15 +162,22 @@ return array(
'nothing_to_load' => 'No hay más artículos',
'previous' => 'Anterior',
),
+ 'period' => array(
+ 'days' => 'days', //TODO - Translation
+ 'hours' => 'hours', //TODO - Translation
+ 'months' => 'months', //TODO - Translation
+ 'weeks' => 'weeks', //TODO - Translation
+ 'years' => 'years', //TODO - Translation
+ ),
'share' => array(
'blogotext' => 'Blogotext',
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'gnusocial' => 'GNU social',
'jdh' => 'Journal du hacker',
'Known' => 'Known based sites',
+ 'lemmy' => 'Lemmy',
'linkedin' => 'LinkedIn',
'mastodon' => 'Mastodon',
'movim' => 'Movim',
diff --git a/app/i18n/es/index.php b/app/i18n/es/index.php
index d7a42537b..8977ee70b 100755
--- a/app/i18n/es/index.php
+++ b/app/i18n/es/index.php
@@ -7,7 +7,7 @@ return array(
'bugs_reports' => 'Informe de fallos',
'credits' => 'Créditos',
'credits_content' => 'Aunque FreshRSS no usa ese entorno, algunos elementos del diseño están obtenidos de <a href="http://twitter.github.io/bootstrap/">Bootstrap</a>. Los <a href="https://git.gnome.org/browse/gnome-icon-theme-symbolic">Iconos</a> han sido obtenidos del <a href="https://www.gnome.org/">proyecto GNOME</a>. La fuente <em>Open Sans</em> es una creación de <a href="https://fonts.google.com/specimen/Open+Sans">Steve Matteson</a>. FreshRSS usa el entorno PHP <a href="https://github.com/marienfressinaud/MINZ">Minz</a>.',
- 'freshrss_description' => 'FreshRSS es un agregador de fuentes RSS de alojamiento privado al estilo de <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> o <a href="http://leed.idleman.fr/">Leed</a>. Es una herramienta potente, pero ligera y fácil de usar y configurar.',
+ 'freshrss_description' => 'FreshRSS es un agregador de fuentes RSS de alojamiento privado al estilo de <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> o <a href="https://github.com/LeedRSS/Leed">Leed</a>. Es una herramienta potente, pero ligera y fácil de usar y configurar.',
'github' => '<a href="https://github.com/FreshRSS/FreshRSS/issues">en Github</a>',
'license' => 'Licencia',
'project_website' => 'Web del proyecto',
@@ -15,6 +15,9 @@ return array(
'version' => 'Versión',
'website' => 'Web',
),
+ 'tos' => array(
+ 'title' => 'Terms of Service', // TODO - Translation
+ ),
'feed' => array(
'add' => 'Puedes añadir fuentes.',
'empty' => 'No hay artículos a mostrar.',
diff --git a/app/i18n/es/sub.php b/app/i18n/es/sub.php
index 7d33c59fa..f1640b76b 100755
--- a/app/i18n/es/sub.php
+++ b/app/i18n/es/sub.php
@@ -13,9 +13,12 @@ return array(
'category' => array(
'_' => 'Categoría',
'add' => 'Añadir a la categoría',
+ 'archiving' => 'Archivo',
'empty' => 'Vaciar categoría',
'information' => 'Información',
'new' => 'Nueva categoría',
+ 'position' => 'Display position', //TODO - Translation
+ 'position_help' => 'To control category sort order', //TODO - Translation
'title' => 'Título',
),
'feed' => array(
@@ -40,7 +43,7 @@ return array(
'help' => 'Write one search filter per line.', //TODO - Translation
),
'information' => 'Información',
- 'keep_history' => 'Número mínimo de artículos a conservar',
+ 'keep_min' => 'Número mínimo de artículos a conservar',
'moved_category_deleted' => 'Al borrar una categoría todas sus fuentes pasan automáticamente a la categoría <em>%s</em>.',
'mute' => 'mute', //TODO - Translation
'no_selected' => 'No hay funentes seleccionadas.',
@@ -72,6 +75,7 @@ return array(
),
'firefox' => array(
'documentation' => 'Follow the steps described <a href="https://developer.mozilla.org/en-US/Firefox/Releases/2/Adding_feed_readers_to_Firefox#Adding_a_new_feed_reader_manually">here</a> to add FreshRSS to Firefox feed reader list.', //TODO - Translation
+ 'obsolete_63' => 'From version 63 and onwards, Firefox has removed the ability to add your own subscription services that are not standalone programs.', //TODO - Translation
'title' => 'Firefox feed reader', //TODO - Translation
),
'import_export' => array(
diff --git a/app/i18n/es/user.php b/app/i18n/es/user.php
new file mode 100644
index 000000000..3a8343c11
--- /dev/null
+++ b/app/i18n/es/user.php
@@ -0,0 +1,37 @@
+<?php
+
+return array(
+ 'email' => array(
+ 'feedback' => array(
+ 'invalid' => 'The email address is invalid.', //TODO - Translation
+ 'required' => 'The email address is required.', //TODO - Translation
+ ),
+ 'validation' => array(
+ 'change_email' => 'You can change your email address <a href="%s">on the profile page</a>.', //TODO - Translation
+ 'email_sent_to' => 'We sent you an email at <strong>%s</strong>, please follow its indications to validate your address.', //TODO - Translation
+ 'feedback' => array(
+ 'email_failed' => 'We couldn’t send you an email because of a misconfiguration of the server.', //TODO - Translation
+ 'email_sent' => 'An email has been sent to your address.', //TODO - Translation
+ 'error' => 'The email address failed to be validated.', //TODO - Translation
+ 'ok' => 'The email address has been validated.', //TODO - Translation
+ 'unneccessary' => 'The email address was already validated.', //TODO - Translation
+ 'wrong_token' => 'The email address failed to be validated due to a wrong token.', //TODO - Translation
+ ),
+ 'need_to' => 'You need to validate your email address before being able to use %s.', //TODO - Translation
+ 'resend_email' => 'Resend the email', //TODO - Translation
+ 'title' => 'Email address validation', //TODO - Translation
+ ),
+ ),
+ 'tos' => array(
+ 'feedback' => array(
+ 'invalid' => 'You must accept the Terms of Service to be able to register.', // TODO - Translation
+ ),
+ ),
+ 'mailer' => array(
+ 'email_need_validation' => array(
+ 'title' => 'You need to validate your account', //TODO - Translation
+ 'welcome' => 'Welcome %s,', //TODO - Translation
+ 'body' => 'You’ve just registered on %s but you still need to validate your email. For that, just follow the link:', //TODO - Translation
+ ),
+ ),
+);
diff --git a/app/i18n/fr/admin.php b/app/i18n/fr/admin.php
index 74605b5ee..6002617fc 100644
--- a/app/i18n/fr/admin.php
+++ b/app/i18n/fr/admin.php
@@ -159,6 +159,7 @@ return array(
'system' => array(
'_' => 'Configuration du système',
'auto-update-url' => 'URL du service de mise à jour',
+ 'force_email_validation' => 'Forcer la validation des adresses email',
'instance-name' => 'Nom de l’instance',
'max-categories' => 'Limite de catégories par utilisateur',
'max-feeds' => 'Limite de flux par utilisateur',
diff --git a/app/i18n/fr/conf.php b/app/i18n/fr/conf.php
index ef29a360e..020c94085 100644
--- a/app/i18n/fr/conf.php
+++ b/app/i18n/fr/conf.php
@@ -3,13 +3,21 @@
return array(
'archiving' => array(
'_' => 'Archivage',
- 'advanced' => 'Avancé',
'delete_after' => 'Supprimer les articles après',
+ 'exception' => 'Exception de nettoyage',
'help' => 'D’autres options sont disponibles dans la configuration individuelle des flux.',
- 'keep_history_by_feed' => 'Nombre minimum d’articles à conserver par flux',
+ 'keep_favourites' => 'Ne jamais supprimer les articles favoris',
+ 'keep_min_by_feed' => 'Nombre minimum d’articles à conserver par flux',
+ 'keep_labels' => 'Ne jamais supprimer les articles étiquetés',
+ 'keep_unreads' => 'Ne jamais supprimer les articles non lus',
+ 'maintenance' => 'Maintenance',
'optimize' => 'Optimiser la base de données',
'optimize_help' => 'À faire de temps en temps pour réduire la taille de la BDD',
+ 'policy' => 'Politique de nettoyage',
+ 'policy_warning' => 'Si aucune politique de nettoyage n’est sélectionnée, tous les articles seront conservés.',
'purge_now' => 'Purger maintenant',
+ 'keep_max' => 'Nombre maximum d’articles à conserver',
+ 'keep_period' => 'Âge maximum des articles à conserver',
'title' => 'Archivage',
'ttl' => 'Ne pas automatiquement rafraîchir plus souvent que',
),
@@ -21,6 +29,7 @@ return array(
'publication_date' => 'Date de publication',
'related_tags' => 'Tags de l’article',
'sharing' => 'Partage',
+ 'display_authors' => 'Authors', //TODO - Translation
'top_line' => 'Ligne du haut',
),
'language' => 'Langue',
@@ -45,6 +54,7 @@ return array(
'_' => 'Suppression du compte',
'warn' => 'Le compte et toutes les données associées vont être supprimées.',
),
+ 'email' => 'Adresse email',
'password_api' => 'Mot de passe API<br /><small>(ex. : pour applis mobiles)</small>',
'password_form' => 'Mot de passe<br /><small>(pour connexion par formulaire)</small>',
'password_format' => '7 caractères minimum',
@@ -133,7 +143,6 @@ return array(
'diaspora' => 'Diaspora*',
'email' => 'Courriel',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'more_information' => 'Plus d’informations',
'print' => 'Print',
'remove' => 'Supprimer la méthode de partage',
diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php
index 86d8461e6..a6875dd05 100644
--- a/app/i18n/fr/gen.php
+++ b/app/i18n/fr/gen.php
@@ -3,6 +3,7 @@
return array(
'action' => array(
'actualize' => 'Actualiser',
+ 'back' => '← Retour',
'back_to_rss_feeds' => '← Retour à vos flux RSS',
'cancel' => 'Annuler',
'create' => 'Créer',
@@ -22,6 +23,7 @@ return array(
'update' => 'Mettre à jour',
),
'auth' => array(
+ 'accept_tos' => 'Accepter les <a href="%s">Conditions Générales d’Utilisation</a>.',
'email' => 'Adresse courriel',
'keep_logged_in' => 'Rester connecté <small>(%s jours)</small>',
'login' => 'Connexion',
@@ -160,15 +162,22 @@ return array(
'nothing_to_load' => 'Fin des articles',
'previous' => 'Précédent',
),
+ 'period' => array(
+ 'days' => 'jours',
+ 'hours' => 'heures',
+ 'months' => 'mois',
+ 'weeks' => 'semaines',
+ 'years' => 'années',
+ ),
'share' => array(
'blogotext' => 'Blogotext',
'diaspora' => 'Diaspora*',
'email' => 'Courriel',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'gnusocial' => 'GNU social',
'jdh' => 'Journal du hacker',
'Known' => 'Sites basés sur Known',
+ 'lemmy' => 'Lemmy',
'linkedin' => 'LinkedIn',
'mastodon' => 'Mastodon',
'movim' => 'Movim',
diff --git a/app/i18n/fr/index.php b/app/i18n/fr/index.php
index c9595e449..489de3849 100644
--- a/app/i18n/fr/index.php
+++ b/app/i18n/fr/index.php
@@ -7,7 +7,7 @@ return array(
'bugs_reports' => 'Rapports de bugs',
'credits' => 'Crédits',
'credits_content' => 'Des éléments de design sont issus du <a href="http://twitter.github.io/bootstrap/">projet Bootstrap</a> bien que FreshRSS n’utilise pas ce framework. Les <a href="https://git.gnome.org/browse/gnome-icon-theme-symbolic">icônes</a> sont issues du <a href="https://www.gnome.org/">projet GNOME</a>. La police <em>Open Sans</em> utilisée a été créée par <a href="https://fonts.google.com/specimen/Open+Sans">Steve Matteson</a>. FreshRSS repose sur <a href="https://github.com/marienfressinaud/MINZ">Minz</a>, un framework PHP.',
- 'freshrss_description' => 'FreshRSS est un agrégateur de flux RSS à auto-héberger à l’image de <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> ou <a href="http://leed.idleman.fr/">Leed</a>. Il se veut léger et facile à prendre en main tout en étant un outil puissant et paramétrable.',
+ 'freshrss_description' => 'FreshRSS est un agrégateur de flux RSS à auto-héberger à l’image de <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> ou <a href="https://github.com/LeedRSS/Leed">Leed</a>. Il se veut léger et facile à prendre en main tout en étant un outil puissant et paramétrable.',
'github' => '<a href="https://github.com/FreshRSS/FreshRSS/issues">sur Github</a>',
'license' => 'Licence',
'project_website' => 'Site du projet',
@@ -15,6 +15,9 @@ return array(
'version' => 'Version',
'website' => 'Site Internet',
),
+ 'tos' => array(
+ 'title' => 'Conditions Générales d’Utilisation',
+ ),
'feed' => array(
'add' => 'Vous pouvez ajouter des flux.',
'empty' => 'Il n’y a aucun article à afficher.',
diff --git a/app/i18n/fr/sub.php b/app/i18n/fr/sub.php
index df44150c2..e12444315 100644
--- a/app/i18n/fr/sub.php
+++ b/app/i18n/fr/sub.php
@@ -13,9 +13,12 @@ return array(
'category' => array(
'_' => 'Catégorie',
'add' => 'Ajouter une catégorie',
+ 'archiving' => 'Archivage',
'empty' => 'Catégorie vide',
'information' => 'Informations',
'new' => 'Nouvelle catégorie',
+ 'position' => 'Position d’affichage',
+ 'position_help' => 'Pour contrôler l’ordre de tri des catégories',
'title' => 'Titre',
),
'feed' => array(
@@ -40,7 +43,7 @@ return array(
'help' => 'Écrivez une recherche par ligne.',
),
'information' => 'Informations',
- 'keep_history' => 'Nombre minimum d’articles à conserver',
+ 'keep_min' => 'Nombre minimum d’articles à conserver',
'moved_category_deleted' => 'Lors de la suppression d’une catégorie, ses flux seront automatiquement classés dans <em>%s</em>.',
'mute' => 'muet',
'no_selected' => 'Aucun flux sélectionné.',
@@ -72,6 +75,7 @@ return array(
),
'firefox' => array(
'documentation' => 'Suivre les étapes décrites <a href="https://developer.mozilla.org/en-US/Firefox/Releases/2/Adding_feed_readers_to_Firefox#Adding_a_new_feed_reader_manually">ici</a> pour ajouter FreshRSS à la liste des lecteurs de flux dans Firefox.',
+ 'obsolete_63' => 'À partir de la version 63, Firefox ne supporte plus l’ajout de services d’abonnements.',
'title' => 'Lecteur de flux dans Firefox',
),
'import_export' => array(
diff --git a/app/i18n/fr/user.php b/app/i18n/fr/user.php
new file mode 100644
index 000000000..7b531c749
--- /dev/null
+++ b/app/i18n/fr/user.php
@@ -0,0 +1,37 @@
+<?php
+
+return array(
+ 'email' => array(
+ 'feedback' => array(
+ 'invalid' => 'L’adresse email est invalide.',
+ 'required' => 'L’adresse email est requise.',
+ ),
+ 'validation' => array(
+ 'change_email' => 'Vous pouvez changer votre adresse email <a href="%s">dans votre profil</a>.',
+ 'email_sent_to' => 'Nous venons d’envoyer un email à <strong>%s</strong>, veuillez suivre ses indications pour valider votre adresse.',
+ 'feedback' => array(
+ 'email_failed' => 'Nous n’avons pas pu vous envoyer d’email à cause d’une mauvaise configuration du serveur.',
+ 'email_sent' => 'Un email a été envoyé à votre adresse.',
+ 'error' => 'L’adresse email n’a pas pu être validée.',
+ 'ok' => 'L’adresse email a été validée.',
+ 'unnecessary' => 'L’adresse email a déjà été validée.',
+ 'wrong_token' => 'L’adresse email n’a pas pu être validée à cause d’un mauvais token.',
+ ),
+ 'need_to' => 'Vous devez valider votre adresse email avant de pouvoir utiliser %s.',
+ 'resend_email' => 'Renvoyer l’email',
+ 'title' => 'Validation de l’adresse email',
+ ),
+ ),
+ 'tos' => array(
+ 'feedback' => array(
+ 'invalid' => 'Vous devez accepter les conditions générales d’utilisation pour pouvoir vous inscrire.',
+ ),
+ ),
+ 'mailer' => array(
+ 'email_need_validation' => array(
+ 'title' => 'Vous devez valider votre compte',
+ 'welcome' => 'Bienvenue %s,',
+ 'body' => 'Vous venez de vous inscrire sur %s mais vous devez encore valider votre adresse email. Pour cela, veuillez cliquer sur ce lien :',
+ ),
+ ),
+);
diff --git a/app/i18n/he/admin.php b/app/i18n/he/admin.php
index e0dfc405d..759b74e2a 100644
--- a/app/i18n/he/admin.php
+++ b/app/i18n/he/admin.php
@@ -163,6 +163,7 @@ return array(
'help' => 'in seconds', //TODO - Translation
'number' => 'Duration to keep logged in', //TODO - Translation
),
+ 'force_email_validation' => 'Force email addresses validation', //TODO - Translation
'instance-name' => 'Instance name', //TODO - Translation
'max-categories' => 'Categories per user limit', //TODO - Translation
'max-feeds' => 'Feeds per user limit', //TODO - Translation
diff --git a/app/i18n/he/conf.php b/app/i18n/he/conf.php
index 1eb447911..b987f21f4 100644
--- a/app/i18n/he/conf.php
+++ b/app/i18n/he/conf.php
@@ -3,13 +3,21 @@
return array(
'archiving' => array(
'_' => 'ארכוב',
- 'advanced' => 'מתקדם',
'delete_after' => 'מחיקת מאמרים לאחר',
+ 'exception' => 'Purge exception', //TODO - Translation
'help' => 'אפשרויות נוספות זמינות בזרמים ספציפיים',
- 'keep_history_by_feed' => 'Minimum number of articles to keep by feed', //TODO - Translation
+ 'keep_favourites' => 'Never delete favourites', //TODO - Translation
+ 'keep_min_by_feed' => 'Minimum number of articles to keep by feed',
+ 'keep_labels' => 'Never delete labels', //TODO - Translation
+ 'keep_unreads' => 'Never delete unreads', //TODO - Translation
+ 'maintenance' => 'Maintenance', //TODO - Translation
'optimize' => 'מיטוב בסיס הנתונים',
'optimize_help' => 'ביצוע לעיתים קרובות על מנת למטב את בסיס הנתונים',
+ 'policy' => 'Purge policy', //TODO - Translation
+ 'policy_warning' => 'If no purge policy is selected, every article will be kept.', //TODO - Translation
'purge_now' => 'ניקוי עכשיו',
+ 'keep_max' => 'Maximum number of articles to keep', //TODO - Translation
+ 'keep_period' => 'Maximum age of articles to keep', //TODO - Translation
'title' => 'ארכוב',
'ttl' => 'אין לרענן אוטומטית יותר מ',
),
@@ -21,6 +29,7 @@ return array(
'publication_date' => 'תאריך הפרסום',
'related_tags' => 'תגיות קשורות', //TODO - Translation
'sharing' => 'שיתוף',
+ 'display_authors' => 'Authors', //TODO - Translation
'top_line' => 'שורה עליונה',
),
'language' => 'שפה',
@@ -45,6 +54,7 @@ return array(
'_' => 'Account deletion', //TODO - Translation
'warn' => 'Your account and all related data will be deleted.', //TODO - Translation
),
+ 'email' => 'Email address', //TODO - Translation
'password_api' => 'סיסמת API<br /><small>(לדוגמה ליישומים סלולריים)</small>',
'password_form' => 'סיסמה<br /><small>(לשימוש בטפוס ההרשמה)</small>',
'password_format' => 'At least 7 characters', //TODO - Translation
@@ -133,7 +143,6 @@ return array(
'diaspora' => 'Diaspora*',
'email' => 'דואר אלקטרוני',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'more_information' => 'מידע נוסף',
'print' => 'הדפסה',
'remove' => 'Remove sharing method', //TODO - Translation
diff --git a/app/i18n/he/gen.php b/app/i18n/he/gen.php
index cf4a1fcda..34e6d77de 100644
--- a/app/i18n/he/gen.php
+++ b/app/i18n/he/gen.php
@@ -3,6 +3,7 @@
return array(
'action' => array(
'actualize' => 'מימוש',
+ 'back' => '← Go back', //TODO - Translation
'back_to_rss_feeds' => '← חזרה להזנות הRSS שלך',
'cancel' => 'ביטול',
'create' => 'יצירה',
@@ -22,6 +23,7 @@ return array(
'update' => 'Update', //TODO - Translation
),
'auth' => array(
+ 'accept_tos' => 'I accept the <a href="%s">Terms of Service</a>.', // TODO - Translation
'email' => 'Email address', //TODO - Translation
'keep_logged_in' => 'השאר מחובר <small>חודש</small>',
'login' => 'כניסה לחשבון',
@@ -160,15 +162,22 @@ return array(
'nothing_to_load' => 'אין מאמרים נוספים',
'previous' => 'הקודם',
),
+ 'period' => array(
+ 'days' => 'days', //TODO - Translation
+ 'hours' => 'hours', //TODO - Translation
+ 'months' => 'months', //TODO - Translation
+ 'weeks' => 'weeks', //TODO - Translation
+ 'years' => 'years', //TODO - Translation
+ ),
'share' => array(
'blogotext' => 'Blogotext',
'diaspora' => 'Diaspora*',
'email' => 'דואר אלקטרוני',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'gnusocial' => 'GNU social',
'jdh' => 'Journal du hacker',
'Known' => 'Known based sites',
+ 'lemmy' => 'Lemmy',
'linkedin' => 'LinkedIn',
'mastodon' => 'Mastodon',
'movim' => 'Movim',
diff --git a/app/i18n/he/index.php b/app/i18n/he/index.php
index e01a02773..7cd1945e7 100644
--- a/app/i18n/he/index.php
+++ b/app/i18n/he/index.php
@@ -7,7 +7,7 @@ return array(
'bugs_reports' => 'דיווח באגים',
'credits' => 'קרדיטים',
'credits_content' => 'מאפייני עיצוב מסויימים הגיעו מ <a href="http://twitter.github.io/bootstrap/">Bootstrap</a> אף על פי ש FreshRSS אינו משתמש בתשתית הזו. <a href="https://git.gnome.org/browse/gnome-icon-theme-symbolic">סמלילים</a> הגיעו מ <a href="https://www.gnome.org/"> פרוייקט GNOME </a>. <em>Open Sans</em> הגופן police נוצר על ידי <a href="https://www.google.com/webfonts/specimen/Open+Sans">Steve Matteson</a>. Favicons נאספים בעזרת <a href="https://getfavicon.appspot.com/">getFavicon API</a>. FreshRSS מבוסס על <a href="https://github.com/marienfressinaud/MINZ">Minz</a>, תשתית PHP.',
- 'freshrss_description' => 'FreshRSS הוא קורא RSS לאחסון עצמי בדומה ל <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> או <a href="http://leed.idleman.fr/">Leed</a>. אינו צורך משאבים רבים, וקל לתפעול אך בו בזמן חזק וניתן להתאמה.',
+ 'freshrss_description' => 'FreshRSS הוא קורא RSS לאחסון עצמי בדומה ל <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> או <a href="https://github.com/LeedRSS/Leed">Leed</a>. אינו צורך משאבים רבים, וקל לתפעול אך בו בזמן חזק וניתן להתאמה.',
'github' => '<a href="https://github.com/FreshRSS/FreshRSS/issues">בגיטהאב</a>',
'license' => 'רישיון',
'project_website' => 'אתר',
@@ -15,6 +15,9 @@ return array(
'version' => 'גרסה',
'website' => 'אתר',
),
+ 'tos' => array(
+ 'title' => 'Terms of Service', // TODO - Translation
+ ),
'feed' => array(
'add' => 'ניתן להוסיף הזנות חדשות.',
'empty' => 'אין מאמר להצגה.',
diff --git a/app/i18n/he/sub.php b/app/i18n/he/sub.php
index 8a629defb..3fd0f267a 100644
--- a/app/i18n/he/sub.php
+++ b/app/i18n/he/sub.php
@@ -13,9 +13,12 @@ return array(
'category' => array(
'_' => 'קטגוריה',
'add' => 'הוספת קטגוריה',
+ 'archiving' => 'ארכוב',
'empty' => 'Empty category', //TODO - Translation
'information' => 'מידע',
'new' => 'קטגוריה חדשה',
+ 'position' => 'Display position', //TODO - Translation
+ 'position_help' => 'To control category sort order', //TODO - Translation
'title' => 'כותרת',
),
'feed' => array(
@@ -40,7 +43,7 @@ return array(
'help' => 'Write one search filter per line.', //TODO - Translation
),
'information' => 'מידע',
- 'keep_history' => 'מסםר מינימלי של מאמרים לשמור',
+ 'keep_min' => 'מסםר מינימלי של מאמרים לשמור',
'moved_category_deleted' => 'כאשר הקטגוריה נמחקת ההזנות שבתוכה אוטומטית מקוטלגות תחת <em>%s</em>.',
'mute' => 'mute', //TODO - Translation
'no_selected' => 'אף הזנה לא נבחרה.',
@@ -72,6 +75,7 @@ return array(
),
'firefox' => array(
'documentation' => 'Follow the steps described <a href="https://developer.mozilla.org/en-US/Firefox/Releases/2/Adding_feed_readers_to_Firefox#Adding_a_new_feed_reader_manually">here</a> to add FreshRSS to Firefox feed reader list.', //TODO - Translation
+ 'obsolete_63' => 'From version 63 and onwards, Firefox has removed the ability to add your own subscription services that are not standalone programs.', //TODO - Translation
'title' => 'Firefox feed reader', //TODO - Translation
),
'import_export' => array(
diff --git a/app/i18n/he/user.php b/app/i18n/he/user.php
new file mode 100644
index 000000000..3a8343c11
--- /dev/null
+++ b/app/i18n/he/user.php
@@ -0,0 +1,37 @@
+<?php
+
+return array(
+ 'email' => array(
+ 'feedback' => array(
+ 'invalid' => 'The email address is invalid.', //TODO - Translation
+ 'required' => 'The email address is required.', //TODO - Translation
+ ),
+ 'validation' => array(
+ 'change_email' => 'You can change your email address <a href="%s">on the profile page</a>.', //TODO - Translation
+ 'email_sent_to' => 'We sent you an email at <strong>%s</strong>, please follow its indications to validate your address.', //TODO - Translation
+ 'feedback' => array(
+ 'email_failed' => 'We couldn’t send you an email because of a misconfiguration of the server.', //TODO - Translation
+ 'email_sent' => 'An email has been sent to your address.', //TODO - Translation
+ 'error' => 'The email address failed to be validated.', //TODO - Translation
+ 'ok' => 'The email address has been validated.', //TODO - Translation
+ 'unneccessary' => 'The email address was already validated.', //TODO - Translation
+ 'wrong_token' => 'The email address failed to be validated due to a wrong token.', //TODO - Translation
+ ),
+ 'need_to' => 'You need to validate your email address before being able to use %s.', //TODO - Translation
+ 'resend_email' => 'Resend the email', //TODO - Translation
+ 'title' => 'Email address validation', //TODO - Translation
+ ),
+ ),
+ 'tos' => array(
+ 'feedback' => array(
+ 'invalid' => 'You must accept the Terms of Service to be able to register.', // TODO - Translation
+ ),
+ ),
+ 'mailer' => array(
+ 'email_need_validation' => array(
+ 'title' => 'You need to validate your account', //TODO - Translation
+ 'welcome' => 'Welcome %s,', //TODO - Translation
+ 'body' => 'You’ve just registered on %s but you still need to validate your email. For that, just follow the link:', //TODO - Translation
+ ),
+ ),
+);
diff --git a/app/i18n/it/admin.php b/app/i18n/it/admin.php
index d4253e9ba..8bb6c7bfe 100644
--- a/app/i18n/it/admin.php
+++ b/app/i18n/it/admin.php
@@ -159,6 +159,7 @@ return array(
'system' => array(
'_' => 'Configurazione di sistema',
'auto-update-url' => 'Auto-update server URL', //TODO - Translation
+ 'force_email_validation' => 'Force email addresses validation', //TODO - Translation
'instance-name' => 'Nome istanza',
'max-categories' => 'Limite categorie per utente',
'max-feeds' => 'Limite feeds per utente',
diff --git a/app/i18n/it/conf.php b/app/i18n/it/conf.php
index df4a5ebeb..4bdaad33d 100644
--- a/app/i18n/it/conf.php
+++ b/app/i18n/it/conf.php
@@ -3,13 +3,21 @@
return array(
'archiving' => array(
'_' => 'Archiviazione',
- 'advanced' => 'Avanzate',
'delete_after' => 'Rimuovi articoli dopo',
+ 'exception' => 'Purge exception', //TODO - Translation
'help' => 'Altre opzioni sono disponibili nelle impostazioni dei singoli feed',
- 'keep_history_by_feed' => 'Numero minimo di articoli da mantenere per feed',
+ 'keep_favourites' => 'Never delete favourites', //TODO - Translation
+ 'keep_min_by_feed' => 'Numero minimo di articoli da mantenere per feed',
+ 'keep_labels' => 'Never delete labels', //TODO - Translation
+ 'keep_unreads' => 'Never delete unreads', //TODO - Translation
+ 'maintenance' => 'Maintenance', //TODO - Translation
'optimize' => 'Ottimizza database',
'optimize_help' => 'Da fare occasionalmente per ridurre le dimensioni del database',
+ 'policy' => 'Purge policy', //TODO - Translation
+ 'policy_warning' => 'If no purge policy is selected, every article will be kept.', //TODO - Translation
'purge_now' => 'Cancella ora',
+ 'keep_max' => 'Maximum number of articles to keep', //TODO - Translation
+ 'keep_period' => 'Maximum age of articles to keep', //TODO - Translation
'title' => 'Archiviazione',
'ttl' => 'Non effettuare aggiornamenti per più di',
),
@@ -21,6 +29,7 @@ return array(
'publication_date' => 'Data di pubblicazione',
'related_tags' => 'Tags correlati', //TODO - Translation
'sharing' => 'Condivisione',
+ 'display_authors' => 'Authors', //TODO - Translation
'top_line' => 'Barra in alto',
),
'language' => 'Lingua',
@@ -45,6 +54,7 @@ return array(
'_' => 'Cancellazione account',
'warn' => 'Il tuo account e tutti i dati associati saranno cancellati.',
),
+ 'email' => 'Indirizzo email',
'password_api' => 'Password API<br /><small>(e.g., per applicazioni mobili)</small>',
'password_form' => 'Password<br /><small>(per il login classico)</small>',
'password_format' => 'Almeno 7 caratteri',
@@ -133,7 +143,6 @@ return array(
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'more_information' => 'Ulteriori informazioni',
'print' => 'Stampa',
'remove' => 'Remove sharing method', //TODO - Translation
diff --git a/app/i18n/it/gen.php b/app/i18n/it/gen.php
index 9cc40ffe3..50d4b4e6c 100644
--- a/app/i18n/it/gen.php
+++ b/app/i18n/it/gen.php
@@ -3,6 +3,7 @@
return array(
'action' => array(
'actualize' => 'Aggiorna',
+ 'back' => '← Go back', //TODO - Translation
'back_to_rss_feeds' => '← Indietro',
'cancel' => 'Annulla',
'create' => 'Crea',
@@ -22,6 +23,7 @@ return array(
'update' => 'Update', // TODO
),
'auth' => array(
+ 'accept_tos' => 'I accept the <a href="%s">Terms of Service</a>.', // TODO - Translation
'email' => 'Indirizzo email',
'keep_logged_in' => 'Ricorda i dati <small>(%s giorni)</small>',
'login' => 'Accedi',
@@ -160,15 +162,22 @@ return array(
'nothing_to_load' => 'Non ci sono altri articoli',
'previous' => 'Precedente',
),
+ 'period' => array(
+ 'days' => 'days', //TODO - Translation
+ 'hours' => 'hours', //TODO - Translation
+ 'months' => 'months', //TODO - Translation
+ 'weeks' => 'weeks', //TODO - Translation
+ 'years' => 'years', //TODO - Translation
+ ),
'share' => array(
'blogotext' => 'Blogotext',
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'gnusocial' => 'GNU social',
'jdh' => 'Journal du hacker',
'Known' => 'Siti basati su Known',
+ 'lemmy' => 'Lemmy',
'linkedin' => 'LinkedIn',
'mastodon' => 'Mastodon',
'movim' => 'Movim',
diff --git a/app/i18n/it/index.php b/app/i18n/it/index.php
index 8162b1639..16c695a12 100644
--- a/app/i18n/it/index.php
+++ b/app/i18n/it/index.php
@@ -7,7 +7,7 @@ return array(
'bugs_reports' => 'Bugs',
'credits' => 'Crediti',
'credits_content' => 'Alcuni elementi di design provengono da <a href="http://twitter.github.io/bootstrap/">Bootstrap</a> sebbene FreshRSS non usi questo framework. Le <a href="https://git.gnome.org/browse/gnome-icon-theme-symbolic">icone</a> provengono dal progetto <a href="https://www.gnome.org/">GNOME</a>. Il carattere <em>Open Sans</em> è stato creato da <a href="https://fonts.google.com/specimen/Open+Sans">Steve Matteson</a>. FreshRSS è basato su <a href="https://github.com/marienfressinaud/MINZ">Minz</a>, un framework PHP.',
- 'freshrss_description' => 'FreshRSS è un aggregatore di feeds RSS da installare sul proprio host come <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> o <a href="http://leed.idleman.fr/">Leed</a>. Leggero e facile da mantenere pur essendo molto configurabile e potente.',
+ 'freshrss_description' => 'FreshRSS è un aggregatore di feeds RSS da installare sul proprio host come <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> o <a href="https://github.com/LeedRSS/Leed">Leed</a>. Leggero e facile da mantenere pur essendo molto configurabile e potente.',
'github' => '<a href="https://github.com/FreshRSS/FreshRSS/issues">su Github</a>',
'license' => 'Licenza',
'project_website' => 'Sito del progetto',
@@ -15,6 +15,9 @@ return array(
'version' => 'Versione',
'website' => 'Sito',
),
+ 'tos' => array(
+ 'title' => 'Terms of Service', // TODO - Translation
+ ),
'feed' => array(
'add' => 'Aggiungi un Feed RSS',
'empty' => 'Non ci sono articoli da mostrare.',
diff --git a/app/i18n/it/sub.php b/app/i18n/it/sub.php
index 50738d9e3..78db7b0a6 100644
--- a/app/i18n/it/sub.php
+++ b/app/i18n/it/sub.php
@@ -13,9 +13,12 @@ return array(
'category' => array(
'_' => 'Categoria',
'add' => 'Aggiungi una categoria',
+ 'archiving' => 'Archiviazione',
'empty' => 'Categoria vuota',
'information' => 'Informazioni',
'new' => 'Nuova categoria',
+ 'position' => 'Display position', //TODO - Translation
+ 'position_help' => 'To control category sort order', //TODO - Translation
'title' => 'Titolo',
),
'feed' => array(
@@ -40,7 +43,7 @@ return array(
'help' => 'Write one search filter per line.', //TODO - Translation
),
'information' => 'Informazioni',
- 'keep_history' => 'Numero minimo di articoli da mantenere',
+ 'keep_min' => 'Numero minimo di articoli da mantenere',
'moved_category_deleted' => 'Cancellando una categoria i feed al suo interno verranno classificati automaticamente come <em>%s</em>.',
'mute' => 'mute', //TODO - Translation
'no_selected' => 'Nessun feed selezionato.',
@@ -72,6 +75,7 @@ return array(
),
'firefox' => array(
'documentation' => 'Follow the steps described <a href="https://developer.mozilla.org/en-US/Firefox/Releases/2/Adding_feed_readers_to_Firefox#Adding_a_new_feed_reader_manually">here</a> to add FreshRSS to Firefox feed reader list.', //TODO - Translation
+ 'obsolete_63' => 'From version 63 and onwards, Firefox has removed the ability to add your own subscription services that are not standalone programs.', //TODO - Translation
'title' => 'Firefox feed reader', //TODO - Translation
),
'import_export' => array(
diff --git a/app/i18n/it/user.php b/app/i18n/it/user.php
new file mode 100644
index 000000000..3a8343c11
--- /dev/null
+++ b/app/i18n/it/user.php
@@ -0,0 +1,37 @@
+<?php
+
+return array(
+ 'email' => array(
+ 'feedback' => array(
+ 'invalid' => 'The email address is invalid.', //TODO - Translation
+ 'required' => 'The email address is required.', //TODO - Translation
+ ),
+ 'validation' => array(
+ 'change_email' => 'You can change your email address <a href="%s">on the profile page</a>.', //TODO - Translation
+ 'email_sent_to' => 'We sent you an email at <strong>%s</strong>, please follow its indications to validate your address.', //TODO - Translation
+ 'feedback' => array(
+ 'email_failed' => 'We couldn’t send you an email because of a misconfiguration of the server.', //TODO - Translation
+ 'email_sent' => 'An email has been sent to your address.', //TODO - Translation
+ 'error' => 'The email address failed to be validated.', //TODO - Translation
+ 'ok' => 'The email address has been validated.', //TODO - Translation
+ 'unneccessary' => 'The email address was already validated.', //TODO - Translation
+ 'wrong_token' => 'The email address failed to be validated due to a wrong token.', //TODO - Translation
+ ),
+ 'need_to' => 'You need to validate your email address before being able to use %s.', //TODO - Translation
+ 'resend_email' => 'Resend the email', //TODO - Translation
+ 'title' => 'Email address validation', //TODO - Translation
+ ),
+ ),
+ 'tos' => array(
+ 'feedback' => array(
+ 'invalid' => 'You must accept the Terms of Service to be able to register.', // TODO - Translation
+ ),
+ ),
+ 'mailer' => array(
+ 'email_need_validation' => array(
+ 'title' => 'You need to validate your account', //TODO - Translation
+ 'welcome' => 'Welcome %s,', //TODO - Translation
+ 'body' => 'You’ve just registered on %s but you still need to validate your email. For that, just follow the link:', //TODO - Translation
+ ),
+ ),
+);
diff --git a/app/i18n/kr/admin.php b/app/i18n/kr/admin.php
index 6312bd3fe..4a8e425d5 100644
--- a/app/i18n/kr/admin.php
+++ b/app/i18n/kr/admin.php
@@ -159,6 +159,7 @@ return array(
'system' => array(
'_' => '시스템 설정',
'auto-update-url' => '자동 업데이트 서버 URL',
+ 'force_email_validation' => 'Force email addresses validation', //TODO - Translation
'instance-name' => '인스턴스 이름',
'max-categories' => '사용자별 카테고리 개수 제한',
'max-feeds' => '사용자별 피드 개수 제한',
diff --git a/app/i18n/kr/conf.php b/app/i18n/kr/conf.php
index acd4c40c1..1e77d0098 100644
--- a/app/i18n/kr/conf.php
+++ b/app/i18n/kr/conf.php
@@ -3,13 +3,21 @@
return array(
'archiving' => array(
'_' => '보관',
- 'advanced' => '고급 설정',
'delete_after' => '다음 기간보다 오래된 글 삭제',
+ 'exception' => 'Purge exception', //TODO - Translation
'help' => '더 자세한 옵션은 개별 피드 설정에 있습니다',
- 'keep_history_by_feed' => '피드별 최소 유지 글 개수',
+ 'keep_favourites' => 'Never delete favourites', //TODO - Translation
+ 'keep_min_by_feed' => '피드별 최소 유지 글 개수',
+ 'keep_labels' => 'Never delete labels', //TODO - Translation
+ 'keep_unreads' => 'Never delete unreads', //TODO - Translation
+ 'maintenance' => 'Maintenance', //TODO - Translation
'optimize' => '데이터베이스 최적화',
'optimize_help' => '데이터베이스 크기를 줄이기 위해 가끔씩 수행해주세요',
+ 'policy' => 'Purge policy', //TODO - Translation
+ 'policy_warning' => 'If no purge policy is selected, every article will be kept.', //TODO - Translation
'purge_now' => '지금 삭제',
+ 'keep_max' => 'Maximum number of articles to keep', //TODO - Translation
+ 'keep_period' => 'Maximum age of articles to keep', //TODO - Translation
'title' => '보관',
'ttl' => '다음 시간이 지나기 전에 새로고침 금지',
),
@@ -21,6 +29,7 @@ return array(
'publication_date' => '발행일',
'related_tags' => '관련 태그',
'sharing' => '공유',
+ 'display_authors' => 'Authors', //TODO - Translation
'top_line' => '상단',
),
'language' => '언어',
@@ -45,6 +54,7 @@ return array(
'_' => '계정 삭제',
'warn' => '당신의 계정과 관련된 모든 데이터가 삭제됩니다.',
),
+ 'email' => '메일 주소',
'password_api' => 'API 암호<br /><small>(예: 모바일 애플리케이션)</small>',
'password_form' => '암호<br /><small>(웹폼 로그인 방식 사용시)</small>',
'password_format' => '7 글자 이상이어야 합니다',
@@ -133,7 +143,6 @@ return array(
'diaspora' => 'Diaspora*',
'email' => '메일',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'more_information' => '자세한 정보',
'print' => '인쇄',
'remove' => '공유 방법 삭제',
diff --git a/app/i18n/kr/gen.php b/app/i18n/kr/gen.php
index f7855c499..fdc95d431 100644
--- a/app/i18n/kr/gen.php
+++ b/app/i18n/kr/gen.php
@@ -3,6 +3,7 @@
return array(
'action' => array(
'actualize' => '새 글 가져오기',
+ 'back' => '← Go back', //TODO - Translation
'back_to_rss_feeds' => '← RSS 피드로 돌아가기',
'cancel' => '취소',
'create' => '생성',
@@ -22,6 +23,7 @@ return array(
'update' => '변경',
),
'auth' => array(
+ 'accept_tos' => 'I accept the <a href="%s">Terms of Service</a>.', // TODO - Translation
'email' => '메일 주소',
'keep_logged_in' => '로그인 유지 <small>(%s 일)</small>',
'login' => '로그인',
@@ -160,15 +162,22 @@ return array(
'nothing_to_load' => '더 이상 글이 없습니다',
'previous' => '이전',
),
+ 'period' => array(
+ 'days' => 'days', //TODO - Translation
+ 'hours' => 'hours', //TODO - Translation
+ 'months' => 'months', //TODO - Translation
+ 'weeks' => 'weeks', //TODO - Translation
+ 'years' => 'years', //TODO - Translation
+ ),
'share' => array(
'blogotext' => 'Blogotext',
'diaspora' => 'Diaspora*',
'email' => '메일',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'gnusocial' => 'GNU social',
'jdh' => 'Journal du hacker',
'Known' => 'Known based sites',
+ 'lemmy' => 'Lemmy',
'linkedin' => 'LinkedIn',
'mastodon' => 'Mastodon',
'movim' => 'Movim',
diff --git a/app/i18n/kr/index.php b/app/i18n/kr/index.php
index bebc8bdec..6e582d906 100644
--- a/app/i18n/kr/index.php
+++ b/app/i18n/kr/index.php
@@ -7,7 +7,7 @@ return array(
'bugs_reports' => '버그 제보하기',
'credits' => '크레딧',
'credits_content' => 'FreshRSS는 <a href="http://twitter.github.io/bootstrap/">Bootstrap</a> 프레임워크를 사용하진 않지만, 일부 디자인 요소를 가져왔습니다. <a href="https://git.gnome.org/browse/gnome-icon-theme-symbolic">아이콘들</a>은 <a href="https://www.gnome.org/">GNOME 프로젝트</a>에서 가져왔습니다. <em>Open Sans</em> 글꼴은 <a href="https://fonts.google.com/specimen/Open+Sans">Steve Matteson</a>가 제작하였습니다. FreshRSS는 PHP 프레임워크인 <a href="https://github.com/marienfressinaud/MINZ">Minz</a>에 기반하고 있습니다.',
- 'freshrss_description' => 'FreshRSS는 <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> 또는 <a href="http://leed.idleman.fr/">Leed</a>와 같은 셀프 호스팅 기반의 RSS 피드 수집기입니다. FreshRSS는 강력하고 다양한 설정을 할 수 있으면서 도 가볍고 사용하기 쉽습니다.',
+ 'freshrss_description' => 'FreshRSS는 <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> 또는 <a href="https://github.com/LeedRSS/Leed">Leed</a>와 같은 셀프 호스팅 기반의 RSS 피드 수집기입니다. FreshRSS는 강력하고 다양한 설정을 할 수 있으면서 도 가볍고 사용하기 쉽습니다.',
'github' => '<a href="https://github.com/FreshRSS/FreshRSS/issues">Github 저장소에 제보</a>',
'license' => '라이센스',
'project_website' => '프로젝트 웹사이트',
@@ -15,6 +15,9 @@ return array(
'version' => '버전',
'website' => '웹사이트',
),
+ 'tos' => array(
+ 'title' => 'Terms of Service', // TODO - Translation
+ ),
'feed' => array(
'add' => '피드를 추가하세요.',
'empty' => '글이 없습니다.',
diff --git a/app/i18n/kr/sub.php b/app/i18n/kr/sub.php
index f8eccfa27..ac45e4e73 100644
--- a/app/i18n/kr/sub.php
+++ b/app/i18n/kr/sub.php
@@ -13,9 +13,12 @@ return array(
'category' => array(
'_' => '카테고리',
'add' => '카테고리 추가',
+ 'archiving' => '보관',
'empty' => '빈 카테고리',
'information' => '정보',
'new' => '새 카테고리',
+ 'position' => 'Display position', //TODO - Translation
+ 'position_help' => 'To control category sort order', //TODO - Translation
'title' => '제목',
),
'feed' => array(
@@ -40,7 +43,7 @@ return array(
'help' => 'Write one search filter per line.', //TODO - Translation
),
'information' => '정보',
- 'keep_history' => '최소 유지 글 개수',
+ 'keep_min' => '최소 유지 글 개수',
'moved_category_deleted' => '카테고리를 삭제하면, 해당 카테고리 아래에 있던 피드들은 자동적으로 <em>%s</em> 아래로 분류됩니다.',
'mute' => '무기한 새로고침 금지',
'no_selected' => '선택된 피드가 없습니다.',
@@ -72,6 +75,7 @@ return array(
),
'firefox' => array(
'documentation' => 'FreshRSS를 Firefox 피드 리더에 추가하기 위해서는 <a href="https://developer.mozilla.org/en-US/Firefox/Releases/2/Adding_feed_readers_to_Firefox#Adding_a_new_feed_reader_manually">여기</a>의 설명을 따르세요.',
+ 'obsolete_63' => 'From version 63 and onwards, Firefox has removed the ability to add your own subscription services that are not standalone programs.', //TODO - Translation
'title' => 'Firefox 피드 리더',
),
'import_export' => array(
diff --git a/app/i18n/kr/user.php b/app/i18n/kr/user.php
new file mode 100644
index 000000000..3a8343c11
--- /dev/null
+++ b/app/i18n/kr/user.php
@@ -0,0 +1,37 @@
+<?php
+
+return array(
+ 'email' => array(
+ 'feedback' => array(
+ 'invalid' => 'The email address is invalid.', //TODO - Translation
+ 'required' => 'The email address is required.', //TODO - Translation
+ ),
+ 'validation' => array(
+ 'change_email' => 'You can change your email address <a href="%s">on the profile page</a>.', //TODO - Translation
+ 'email_sent_to' => 'We sent you an email at <strong>%s</strong>, please follow its indications to validate your address.', //TODO - Translation
+ 'feedback' => array(
+ 'email_failed' => 'We couldn’t send you an email because of a misconfiguration of the server.', //TODO - Translation
+ 'email_sent' => 'An email has been sent to your address.', //TODO - Translation
+ 'error' => 'The email address failed to be validated.', //TODO - Translation
+ 'ok' => 'The email address has been validated.', //TODO - Translation
+ 'unneccessary' => 'The email address was already validated.', //TODO - Translation
+ 'wrong_token' => 'The email address failed to be validated due to a wrong token.', //TODO - Translation
+ ),
+ 'need_to' => 'You need to validate your email address before being able to use %s.', //TODO - Translation
+ 'resend_email' => 'Resend the email', //TODO - Translation
+ 'title' => 'Email address validation', //TODO - Translation
+ ),
+ ),
+ 'tos' => array(
+ 'feedback' => array(
+ 'invalid' => 'You must accept the Terms of Service to be able to register.', // TODO - Translation
+ ),
+ ),
+ 'mailer' => array(
+ 'email_need_validation' => array(
+ 'title' => 'You need to validate your account', //TODO - Translation
+ 'welcome' => 'Welcome %s,', //TODO - Translation
+ 'body' => 'You’ve just registered on %s but you still need to validate your email. For that, just follow the link:', //TODO - Translation
+ ),
+ ),
+);
diff --git a/app/i18n/nl/admin.php b/app/i18n/nl/admin.php
index e5d126eb8..1083c630b 100644
--- a/app/i18n/nl/admin.php
+++ b/app/i18n/nl/admin.php
@@ -159,6 +159,7 @@ return array(
'system' => array(
'_' => 'Systeem configuratie',
'auto-update-url' => 'Automatische update server URL',
+ 'force_email_validation' => 'Emailadresvalidatie forceren',
'instance-name' => 'Voorbeeld naam',
'max-categories' => 'Categorielimiet per gebruiker',
'max-feeds' => 'Feedlimiet per gebruiker',
diff --git a/app/i18n/nl/conf.php b/app/i18n/nl/conf.php
index fa84ae184..ca6627cbb 100644
--- a/app/i18n/nl/conf.php
+++ b/app/i18n/nl/conf.php
@@ -1,15 +1,23 @@
<?php
-/* Dutch translation by Wanabo. http://www.nieuwskop.be */
+
return array(
'archiving' => array(
'_' => 'Archivering',
- 'advanced' => 'Geavanceerd',
'delete_after' => 'Verwijder artikelen na',
+ 'exception' => 'Zuiveringsuitzondering',
'help' => 'Meer opties zijn beschikbaar in de persoonlijke stroom instellingen',
- 'keep_history_by_feed' => 'Minimum aantal te behouden artikelen in de feed',
- 'optimize' => 'Optimaliseer database',
+ 'keep_favourites' => 'Favorieten nooit verwijderen',
+ 'keep_min_by_feed' => 'Minimum aantal te behouden artikelen in de feed',
+ 'keep_labels' => 'Labels nooit verwijderen',
+ 'keep_unreads' => 'Ongelezen artikels nooit verwijderen',
+ 'maintenance' => 'Onderhoud',
+ 'optimize' => 'Database optimaliseren',
'optimize_help' => 'Doe dit zo af en toe om de omvang van de database te verkleinen',
+ 'policy' => 'Zuiveringsbeleid',
+ 'policy_warning' => 'Zonder zuiveringsbeleid wordt elk artikel bewaard.',
'purge_now' => 'Schoon nu op',
+ 'keep_max' => 'Maximaal aantal artikelen om te behouden',
+ 'keep_period' => 'Maximumleeftijd artikelen om te behouden',
'title' => 'Archivering',
'ttl' => 'Vernieuw niet automatisch meer dan',
),
@@ -21,6 +29,7 @@ return array(
'publication_date' => 'Publicatie datum',
'related_tags' => 'Gerelateerde labels',
'sharing' => 'Delen',
+ 'display_authors' => 'Auteurs',
'top_line' => 'Bovenaan',
),
'language' => 'Taal',
@@ -45,6 +54,7 @@ return array(
'_' => 'Account verwijderen',
'warn' => 'Uw account en alle gerelateerde gegvens worden verwijderd.',
),
+ 'email' => 'Email adres',
'password_api' => 'Wachtwoord API<br /><small>(e.g., voor mobiele apps)</small>',
'password_form' => 'Wachtwoord<br /><small>(voor de Web-formulier log in methode)</small>',
'password_format' => 'Ten minste 7 tekens',
@@ -133,7 +143,6 @@ return array(
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'more_information' => 'Meer informatie',
'print' => 'Afdrukken',
'remove' => 'Deelmethode verwijderen',
diff --git a/app/i18n/nl/feedback.php b/app/i18n/nl/feedback.php
index 25378360b..97e1a71b8 100644
--- a/app/i18n/nl/feedback.php
+++ b/app/i18n/nl/feedback.php
@@ -75,7 +75,7 @@ return array(
),
'feed' => array(
'actualized' => '<em>%s</em> vernieuwd',
- 'actualizeds' => 'RSS feeds vernieuwd',
+ 'actualizeds' => 'RSS-feeds vernieuwd',
'added' => 'RSS feed <em>%s</em> toegevoegd',
'already_subscribed' => 'Al geabonneerd op <em>%s</em>',
'deleted' => 'Feed verwijderd',
diff --git a/app/i18n/nl/gen.php b/app/i18n/nl/gen.php
index bdf2e0abd..fdbb866fc 100644
--- a/app/i18n/nl/gen.php
+++ b/app/i18n/nl/gen.php
@@ -3,6 +3,7 @@
return array(
'action' => array(
'actualize' => 'Actualiseren',
+ 'back' => '← Terug',
'back_to_rss_feeds' => '← Ga terug naar je RSS feeds',
'cancel' => 'Annuleren',
'create' => 'Opslaan',
@@ -22,6 +23,7 @@ return array(
'update' => 'Updaten',
),
'auth' => array(
+ 'accept_tos' => 'Ik accepteer de <a href="%s">gebruiksvoorwaarden</a>.',
'email' => 'Email adres',
'keep_logged_in' => 'Ingelogd blijven voor <small>(%s dagen)</small>',
'login' => 'Log in',
@@ -160,25 +162,16 @@ return array(
'nothing_to_load' => 'Er zijn geen artikelen meer',
'previous' => 'Vorige',
),
+ 'period' => array(
+ 'days' => 'dagen',
+ 'hours' => 'uren',
+ 'months' => 'maanden',
+ 'weeks' => 'weken',
+ 'years' => 'jaren',
+ ),
'share' => array(
- 'blogotext' => 'Blogotext',
- 'diaspora' => 'Diaspora*',
'email' => 'Email',
- 'facebook' => 'Facebook',
- 'g+' => 'Google+',
- 'gnusocial' => 'GNU social',
- 'jdh' => 'Journal du hacker',
- 'Known' => 'Known based sites',
- 'linkedin' => 'LinkedIn',
- 'mastodon' => 'Mastodon',
- 'movim' => 'Movim',
- 'pinboard' => 'Pinboard',
- 'pocket' => 'Pocket',
- 'print' => 'Print',
- 'shaarli' => 'Shaarli',
- 'twitter' => 'Twitter',
- 'wallabag' => 'wallabag v1',
- 'wallabagv2' => 'wallabag v2',
+ 'Known' => 'Known-gebaseerde sites',
),
'short' => array(
'attention' => 'Attentie!',
diff --git a/app/i18n/nl/index.php b/app/i18n/nl/index.php
index d202b812a..22720f927 100644
--- a/app/i18n/nl/index.php
+++ b/app/i18n/nl/index.php
@@ -7,19 +7,22 @@ return array(
'bugs_reports' => 'Rapporteer fouten',
'credits' => 'Waarderingen',
'credits_content' => 'Sommige ontwerp elementen komen van <a href="http://twitter.github.io/bootstrap/">Bootstrap</a> alhoewel FreshRSS dit raamwerk niet gebruikt. <a href="https://git.gnome.org/browse/gnome-icon-theme-symbolic">Pictogrammen</a> komen van het <a href="https://www.gnome.org/">GNOME project</a>. <em>De Open Sans</em> font police is gemaakt door <a href="https://fonts.google.com/specimen/Open+Sans">Steve Matteson</a>. FreshRSS is gebaseerd op <a href="https://github.com/marienfressinaud/MINZ">Minz</a>, een PHP raamwerk. Nederlandse vertaling door Wanabo, <a href="http://www.nieuwskop.be" title="NieuwsKop">NieuwsKop.be</a>. Link naar de Nederlandse vertaling, <a href="https://github.com/Wanabo/FreshRSS-Dutch-translation/tree/master">FreshRSS-Dutch-translation</a>.',
- 'freshrss_description' => 'FreshRSS is een RSS feed aggregator om zelf te hosten zoals <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> of <a href="http://leed.idleman.fr/">Leed</a>. Het gebruikt weinig systeembronnen en is makkelijk te administreren terwijl het een krachtig en makkelijk te configureren programma is.',
+ 'freshrss_description' => 'FreshRSS is een RSS-feed aggregator om zelf te hosten, net als <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> of <a href="https://github.com/LeedRSS/Leed">Leed</a>. Het gebruikt weinig systeembronnen en is makkelijk te beheren terwijl het een krachtig en makkelijk te configureren programma is.',
'github' => '<a href="https://github.com/FreshRSS/FreshRSS/issues">op Github</a>',
- 'license' => 'License',
- 'project_website' => 'Project website',
+ 'license' => 'Licentie',
+ 'project_website' => 'Projectwebsite',
'title' => 'Over',
'version' => 'Versie',
'website' => 'Website',
),
+ 'tos' => array(
+ 'title' => 'Gebruiksvoorwaarden',
+ ),
'feed' => array(
'add' => 'U kunt wat feeds toevoegen.',
'empty' => 'Er is geen artikel om te laten zien.',
- 'rss_of' => 'RSS feed van %s',
- 'title' => 'Overzicht RSS feeds',
+ 'rss_of' => 'RSS-feed van %s',
+ 'title' => 'Overzicht RSS-feeds',
'title_global' => 'Globale weergave',
'title_fav' => 'Uw favorieten',
),
@@ -48,7 +51,7 @@ return array(
'queries' => 'Gebruikers queries',
'read' => 'Laat alleen gelezen zien',
'reader_view' => 'Lees modus',
- 'rss_view' => 'RSS feed',
+ 'rss_view' => 'RSS-feed',
'search_short' => 'Zoeken',
'starred' => 'Laat alleen favorieten zien',
'stats' => 'Statistieken',
diff --git a/app/i18n/nl/sub.php b/app/i18n/nl/sub.php
index b59515f42..8a3af6064 100644
--- a/app/i18n/nl/sub.php
+++ b/app/i18n/nl/sub.php
@@ -13,34 +13,37 @@ return array(
'category' => array(
'_' => 'Categorie',
'add' => 'Voeg categorie toe',
+ 'archiving' => 'Archiveren',
'empty' => 'Lege categorie',
'information' => 'Informatie',
'new' => 'Nieuwe categorie',
+ 'position' => 'Weergavepositie',
+ 'position_help' => 'Om de categorieweergave-sorteervolgorde te controleren',
'title' => 'Titel',
),
'feed' => array(
- 'add' => 'Voeg een RSS feed toe',
+ 'add' => 'Voeg een RSS-feed toe',
'advanced' => 'Geavanceerd',
'archiving' => 'Archiveren',
'auth' => array(
'configuration' => 'Log in',
- 'help' => 'Verbinding toestaan toegang te krijgen tot HTTP beveiligde RSS feeds',
+ 'help' => 'Verbinding toestaan toegang te krijgen tot HTTP beveiligde RSS-feeds',
'http' => 'HTTP Authenticatie',
'password' => 'HTTP wachtwoord',
'username' => 'HTTP gebruikers naam',
),
'clear_cache' => 'Cache altijd leegmaken',
- 'css_help' => 'Haalt verstoorde RSS feeds op (attentie, heeft meer tijd nodig!)',
- 'css_path' => 'Artikelen CSS pad op originele website',
+ 'css_help' => 'Haalt onvolledige RSS-feeds op (attentie, heeft meer tijd nodig!)',
+ 'css_path' => 'CSS-pad van artikelen op originele website',
'description' => 'Omschrijving',
'empty' => 'Deze feed is leeg. Controleer of deze nog actueel is.',
'error' => 'Deze feed heeft problemen. Verifieer a.u.b het doeladres en actualiseer het.',
'filteractions' => array(
- '_' => 'Filter actions', //TODO - Translation
- 'help' => 'Write one search filter per line.', //TODO - Translation
+ '_' => 'Filteracties',
+ 'help' => 'Voer één zoekfilter per lijn in.',
),
'information' => 'Informatie',
- 'keep_history' => 'Minimum aantal artikelen om te houden',
+ 'keep_min' => 'Minimum aantal artikelen om te houden',
'moved_category_deleted' => 'Als u een categorie verwijderd, worden de feeds automatisch geclassificeerd onder <em>%s</em>.',
'mute' => 'demp',
'no_selected' => 'Geen feed geselecteerd.',
@@ -64,14 +67,15 @@ return array(
'think_to_add' => 'Voeg wat feeds toe.',
'timeout' => 'Time-out in seconden',
'title' => 'Titel',
- 'title_add' => 'Voeg een RSS feed toe',
+ 'title_add' => 'Voeg een RSS-feed toe',
'ttl' => 'Vernieuw automatisch niet vaker dan',
- 'url' => 'Feed URL',
+ 'url' => 'Feed-url',
'validator' => 'Controleer de geldigheid van de feed',
- 'website' => 'Website URL',
+ 'website' => 'Website-url',
),
'firefox' => array(
'documentation' => 'Volg de stappen die <a href="https://developer.mozilla.org/en-US/Firefox/Releases/2/Adding_feed_readers_to_Firefox#Adding_a_new_feed_reader_manually">hier</a> beschreven worden om FreshRSS aan de Firefox-nieuwslezerlijst toe te voegen.',
+ 'obsolete_63' => 'Vanaf versie 63 en nieuwer, heeft Firefox de mogelijkheid om zelf niewslezers toe te voegen verwijderd voor online diensten.',
'title' => 'Firefox-nieuwslezer',
),
'import_export' => array(
diff --git a/app/i18n/nl/user.php b/app/i18n/nl/user.php
new file mode 100644
index 000000000..f98a6b2fd
--- /dev/null
+++ b/app/i18n/nl/user.php
@@ -0,0 +1,37 @@
+<?php
+
+return array(
+ 'email' => array(
+ 'feedback' => array(
+ 'invalid' => 'Het emailadres is niet geldig.',
+ 'required' => 'Het emailadres is vereist.',
+ ),
+ 'validation' => array(
+ 'change_email' => 'Het emailadres kan worden gewijzigd <a href="%s">op de profielpagina</a>.',
+ 'email_sent_to' => 'Er is een email verzonden naar <strong>%s</strong>. Volg de instructies om het emailadres te valideren.',
+ 'feedback' => array(
+ 'email_failed' => 'Er kon geen email worden verzonden vanwege een incorrecte configuratie van de server.',
+ 'email_sent' => 'Er is een email naar het adres verzonden.',
+ 'error' => 'Het emailadres kon niet worden gevalideerd.',
+ 'ok' => 'Het emailadres is gevalideerd.',
+ 'unneccessary' => 'Het emailadres is al eerder gevalideerd.',
+ 'wrong_token' => 'Het emailadres kon niet worden gevalideerd vanwege een fout token.',
+ ),
+ 'need_to' => 'Het emailadres %1 moet worden gevalideerd voordat het kan worden gebruikt.',
+ 'resend_email' => 'Email opnieuw sturen',
+ 'title' => 'Emailadresvalidatie',
+ ),
+ ),
+ 'tos' => array(
+ 'feedback' => array(
+ 'invalid' => 'De gebruiksvoorwaarden moeten worden geaccepteerd om te kunnen registeren.',
+ ),
+ ),
+ 'mailer' => array(
+ 'email_need_validation' => array(
+ 'title' => 'Je account moet worden gevalideerd',
+ 'welcome' => 'Welkom %s,',
+ 'body' => 'Je hebt je net geregistreerd op %s, maar je moet je email nog valideren. Volg daarvoor de link:',
+ ),
+ ),
+);
diff --git a/app/i18n/oc/admin.php b/app/i18n/oc/admin.php
index 2f8ede873..1fb8d5c3a 100644
--- a/app/i18n/oc/admin.php
+++ b/app/i18n/oc/admin.php
@@ -163,6 +163,7 @@ return array(
'help' => 'en segondas',
'number' => 'Durada de téner d’ésser connectat',
),
+ 'force_email_validation' => 'Forçar la validacion de las adreças electronicas',
'instance-name' => 'Nom de l’instància',
'max-categories' => 'Limita de categoria per utilizaire',
'max-feeds' => 'Limita de fluxes per utilizaire',
diff --git a/app/i18n/oc/conf.php b/app/i18n/oc/conf.php
index 1596950ea..e123c03c5 100644
--- a/app/i18n/oc/conf.php
+++ b/app/i18n/oc/conf.php
@@ -2,15 +2,24 @@
return array(
'archiving' => array(
- '_' => 'Archivar',
+ '_' => 'Archius',
'advanced' => 'Avançat',
'delete_after' => 'Levar los articles aprèp',
+ 'exception' => 'Excepcion de purga',
'help' => 'Mai d’opcions son disponiblas dins la configuracion individuala dels fluxes',
- 'keep_history_by_feed' => 'Nombre minimum d’articles de servar per flux',
+ 'keep_favourites' => 'Jamai suprimir los favorits',
+ 'keep_min_by_feed' => 'Nombre minimum d’articles de servar per flux',
+ 'keep_labels' => 'Jamai suprimir las etiquetas',
+ 'keep_unreads' => 'Jamai suprimir los pas legits',
+ 'maintenance' => 'Entreten',
'optimize' => 'Optimizar la basa de donada',
'optimize_help' => 'De far de temps en temps per redusir la talha de la basa de donadas',
+ 'policy' => 'Politica de purga',
+ 'policy_warning' => 'Se cap de politica de purga es pas seleccionada, totes los articles seràn gardats',
'purge_now' => 'Purgar ara',
- 'title' => 'Archivar',
+ 'keep_max' => 'Nombre maximum d’articles de gardar',
+ 'keep_period' => 'Atge maximum dels articles de gardar',
+ 'title' => 'Archius',
'ttl' => 'Actualizar pas automaticament mai sovent que',
),
'display' => array(
@@ -21,6 +30,7 @@ return array(
'publication_date' => 'Data de publicacion',
'related_tags' => 'Etiquetas ligadas',
'sharing' => 'Partatge',
+ 'display_authors' => 'Autors',
'top_line' => 'Linha amont',
),
'language' => 'Lenga',
@@ -45,6 +55,7 @@ return array(
'_' => 'Supression del compte',
'warn' => 'Lo compte e totas las donadas ligadas seràn suprimits.',
),
+ 'email' => 'Adreça de corrièl',
'password_api' => 'Senhal API<br /><small>(ex. : per las aplicacions mobil)</small>',
'password_form' => 'Senhal API<br /><small>(ex. : per la connexion via formulari)</small>',
'password_format' => 'Almens 7 caractèrs',
@@ -133,7 +144,6 @@ return array(
'diaspora' => 'Diaspora*',
'email' => 'Corrièl',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'more_information' => 'Mai d’informacions',
'print' => 'Imprimir',
'remove' => 'Suprimir lo metòde de partatge',
diff --git a/app/i18n/oc/gen.php b/app/i18n/oc/gen.php
index 7f9793283..a5bd003c2 100644
--- a/app/i18n/oc/gen.php
+++ b/app/i18n/oc/gen.php
@@ -3,6 +3,7 @@
return array(
'action' => array(
'actualize' => 'Actualizar',
+ 'back' => '← Tornar',
'back_to_rss_feeds' => '← Tornar a vòstres fluxes RSS',
'cancel' => 'Anullar',
'create' => 'Crear',
@@ -22,6 +23,7 @@ return array(
'update' => 'Actualizar',
),
'auth' => array(
+ 'accept_tos' => 'Accepti las <a href="%s">condicions d’utilizacion</a>.',
'email' => 'Adreça de corrièl',
'keep_logged_in' => 'Demorar connectat <small>(%s jorns) </small>',
'login' => 'Connexion',
@@ -49,7 +51,7 @@ return array(
'Aug' => '\\a\\g\\o\\s\\t',
'aug' => 'agost',
'august' => 'agost',
- 'before_yesterday' => 'Abans ièr',
+ 'before_yesterday' => 'Anterior a ièr',
'Dec' => '\\d\\e\\c\\e\\m\\b\\r\\e',
'dec' => 'dec.',
'december' => 'decembre',
@@ -160,15 +162,22 @@ return array(
'nothing_to_load' => 'I a pas mai d’articles',
'previous' => 'Precedent',
),
+ 'period' => array(
+ 'days' => 'jorns',
+ 'hours' => 'oras',
+ 'months' => 'meses',
+ 'weeks' => 'setmanas',
+ 'years' => 'ans',
+ ),
'share' => array(
'blogotext' => 'Blogotext',
'diaspora' => 'Diaspora*',
'email' => 'Corrièl',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'gnusocial' => 'GNU social',
'jdh' => 'Journal du hacker',
'Known' => 'Sites basats sus Known',
+ 'lemmy' => 'Lemmy',
'linkedin' => 'LinkedIn',
'mastodon' => 'Mastodon',
'movim' => 'Movim',
diff --git a/app/i18n/oc/index.php b/app/i18n/oc/index.php
index 5cc71c9a9..763d24139 100644
--- a/app/i18n/oc/index.php
+++ b/app/i18n/oc/index.php
@@ -7,7 +7,7 @@ return array(
'bugs_reports' => 'Senhalament de problèmas',
'credits' => 'Crèdits',
'credits_content' => 'Unes elements de l’estil venon del <a href="http://twitter.github.io/bootstrap/">projècte Bootstrap</a> encara que FreshRSS utilize pas aqueste framework. Las <a href="https://git.gnome.org/browse/gnome-icon-theme-symbolic">icònas</a> venon del <a href="https://www.gnome.org/">projècte GNOME</a>. La polissa <em>Open Sans</em> utilizada foguèt creada per en <a href="https://fonts.google.com/specimen/Open+Sans">Steve Matteson</a>. FreshRSS es basat sus <a href="https://github.com/marienfressinaud/MINZ">Minz</a>, un framework PHP.',
- 'freshrss_description' => 'FreshRSS es un agregador de fluxes RSS per l’auto-albergar tal coma <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> o <a href="http://projet.idleman.fr/leed/">Leed</a>. Sa tòca es d’èsser leugièr e de bon utilizar de prima abòrd mas tanben d’èsser potent e parametrable.',
+ 'freshrss_description' => 'FreshRSS es un agregador de fluxes RSS per l’auto-albergar tal coma <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> o <a href="https://github.com/LeedRSS/Leed">Leed</a>. Sa tòca es d’èsser leugièr e de bon utilizar de prima abòrd mas tanben d’èsser potent e parametrable.',
'github' => '<a href="https://github.com/FreshRSS/FreshRSS/issues">on Github</a>',
'license' => 'Licéncia',
'project_website' => 'Site del projècte',
@@ -15,6 +15,9 @@ return array(
'website' => 'Site internet',
'version' => 'Version',
),
+ 'tos' => array(
+ 'title' => 'Condicions d’utilizacion',
+ ),
'feed' => array(
'add' => 'Podètz ajustar de fluxes.',
'empty' => 'I a pas cap de flux de mostrar.',
diff --git a/app/i18n/oc/sub.php b/app/i18n/oc/sub.php
index eae9dff29..98a7521eb 100644
--- a/app/i18n/oc/sub.php
+++ b/app/i18n/oc/sub.php
@@ -12,9 +12,12 @@ return array(
'category' => array(
'_' => 'Categoria',
'add' => 'Ajustar una categoria',
+ 'archiving' => 'Archivar',
'empty' => 'Categoria voida',
'information' => 'Informacions',
'new' => 'Nòva categoria',
+ 'position' => 'Mostrar la posicion',
+ 'position_help' => 'Per contrarotlar l’òrdre de tria de la categoria',
'title' => 'Títol',
),
'feed' => array(
@@ -39,7 +42,7 @@ return array(
'help' => 'Escrivètz una recèrca per linha.',
),
'information' => 'Informacions',
- 'keep_history' => 'Nombre minimum d’articles de servar',
+ 'keep_min' => 'Nombre minimum d’articles de servar',
'moved_category_deleted' => 'Quand escafatz una categoria, sos fluxes son automaticament classats dins <em>%s</em>.',
'mute' => 'mut',
'no_selected' => 'Cap de flux pas seleccionat.',
@@ -71,6 +74,7 @@ return array(
),
'firefox' => array(
'documentation' => 'Seguissètz las etapas descrichas <a href="https://developer.mozilla.org/en-US/Firefox/Releases/2/Adding_feed_readers_to_Firefox#Adding_a_new_feed_reader_manually">aquí</a> per ajustar FreshRSS a la lista dels lectors de flux de Firefox.',
+ 'obsolete_63' => 'A partir de la version 63 e las seguentas, Firefox permet pas mai d’ajustar vòstres pròpris servicis d’abonament.',
'title' => 'Lector de flux de Firefox',
),
'import_export' => array(
diff --git a/app/i18n/oc/user.php b/app/i18n/oc/user.php
new file mode 100644
index 000000000..655aa052c
--- /dev/null
+++ b/app/i18n/oc/user.php
@@ -0,0 +1,37 @@
+<?php
+
+return array(
+ 'email' => array(
+ 'feedback' => array(
+ 'invalid' => 'L’adreça electronica es invalida.',
+ 'required' => 'L’adreça electronica es requesida.',
+ ),
+ 'validation' => array(
+ 'change_email' => 'Podètz cambiar l’adreça electronica <a href="%s">sus la pagina de perfil</a>.',
+ 'email_sent_to' => 'Vos avèm enviat un corrièl a <strong>%s</strong>, mercés de seguir las consignas per validar l’adreça electronica.',
+ 'feedback' => array(
+ 'email_failed' => 'Avèm pas pogut vos enviar un corrièl a causa d’una marrida configuracion del servidor.',
+ 'email_sent' => 'Avèm enviat un corrièl a vòstra adreça.',
+ 'error' => 'Fracàs de la validacion de l’adreça electronica.',
+ 'ok' => 'L’adreça electronica es estada validada.',
+ 'unneccessary' => 'L’adreça es ja estada validada.',
+ 'wrong_token' => 'Fracàs de la validacion de l’adreça a causa d’un marrit geton.',
+ ),
+ 'need_to' => 'Devèètz validar vòstra adreça electronica abans de poder utilizar %s.',
+ 'resend_email' => 'Tornar enviar lo corrièl',
+ 'title' => 'Validacion de l’adreça electronica',
+ ),
+ ),
+ 'tos' => array(
+ 'feedback' => array(
+ 'invalid' => 'Vos cal acceptar las condicions d’utilizacion per poder vos inscriure.',
+ ),
+ ),
+ 'mailer' => array(
+ 'email_need_validation' => array(
+ 'title' => 'Vos cal validar vòstra adreça electronica',
+ 'welcome' => 'La benvenguda %s,',
+ 'body' => 'Venètz de vos marcar sus %s mas vos cal encara validar l’adreça electronica. Per aquò far, seguissètz lo ligam :',
+ ),
+ ),
+);
diff --git a/app/i18n/pt-br/admin.php b/app/i18n/pt-br/admin.php
index 82559c67b..cef6694c2 100644
--- a/app/i18n/pt-br/admin.php
+++ b/app/i18n/pt-br/admin.php
@@ -159,6 +159,7 @@ return array(
'system' => array(
'_' => 'Configuração do sistema',
'auto-update-url' => 'URL do servidor para atualização automática',
+ 'force_email_validation' => 'Force email addresses validation', //TODO - Translation
'instance-name' => 'Nome da instância',
'max-categories' => 'Limite de categorias por usuário',
'max-feeds' => 'Limite de Feeds por usuário',
diff --git a/app/i18n/pt-br/conf.php b/app/i18n/pt-br/conf.php
index 8f5eb7746..5e43cc373 100644
--- a/app/i18n/pt-br/conf.php
+++ b/app/i18n/pt-br/conf.php
@@ -3,13 +3,21 @@
return array(
'archiving' => array(
'_' => 'Arquivar',
- 'advanced' => 'Avançado',
'delete_after' => 'Remover artigos depois',
+ 'exception' => 'Purge exception', //TODO - Translation
'help' => 'Mais opções estão disponíveis nas configurações individuais do feed',
- 'keep_history_by_feed' => 'Número mínimo de artigos para deixar no feed',
+ 'keep_favourites' => 'Never delete favourites', //TODO - Translation
+ 'keep_min_by_feed' => 'Número mínimo de artigos para deixar no feed',
+ 'keep_labels' => 'Never delete labels', //TODO - Translation
+ 'keep_unreads' => 'Never delete unreads', //TODO - Translation
+ 'maintenance' => 'Maintenance', //TODO - Translation
'optimize' => 'Otimizar banco de dados',
'optimize_help' => 'Faça ocasionalmente para reduzir o tamanho do banco de dados',
+ 'policy' => 'Purge policy', //TODO - Translation
+ 'policy_warning' => 'If no purge policy is selected, every article will be kept.', //TODO - Translation
'purge_now' => 'Purge agora',
+ 'keep_max' => 'Maximum number of articles to keep', //TODO - Translation
+ 'keep_period' => 'Maximum age of articles to keep', //TODO - Translation
'title' => 'Arquivar',
'ttl' => 'Não atualize automaticamente mais frequente que',
),
@@ -21,6 +29,7 @@ return array(
'publication_date' => 'Data da publicação',
'related_tags' => 'Tags relacionadas', //TODO - Translation
'sharing' => 'Compartilhar',
+ 'display_authors' => 'Authors', //TODO - Translation
'top_line' => 'Linha superior',
),
'language' => 'Ídioma',
@@ -45,6 +54,7 @@ return array(
'_' => 'Remover conta',
'warn' => 'Sua conta e todos os dados relacionados serão removidos.',
),
+ 'email' => 'Endereço de e-mail',
'password_api' => 'Senha da API<br /><small>(p.s., para aplicativos móveis)</small>',
'password_form' => 'Senha<br /><small>(para o método de formulário web)</small>',
'password_format' => 'Ao menos 7 caracteres',
@@ -133,7 +143,6 @@ return array(
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'more_information' => 'Mais informação',
'print' => 'Imprimir',
'remove' => 'Remove sharing method', //TODO - Translation
diff --git a/app/i18n/pt-br/gen.php b/app/i18n/pt-br/gen.php
index 46ae53eb4..0e7f367ee 100644
--- a/app/i18n/pt-br/gen.php
+++ b/app/i18n/pt-br/gen.php
@@ -3,6 +3,7 @@
return array(
'action' => array(
'actualize' => 'Atualizar',
+ 'back' => '← Go back', //TODO - Translation
'back_to_rss_feeds' => '← Volte para o seu feeds RSS',
'cancel' => 'Cancelar',
'create' => 'Criar',
@@ -22,6 +23,7 @@ return array(
'update' => 'Update', //TODO - Translation
),
'auth' => array(
+ 'accept_tos' => 'I accept the <a href="%s">Terms of Service</a>.', // TODO - Translation
'email' => 'Endereço de e-mail',
'keep_logged_in' => 'Mantenha logado por <small>(%s days)</small>',
'login' => 'Login',
@@ -160,15 +162,22 @@ return array(
'nothing_to_load' => 'Não há mais artigos',
'previous' => 'Anterior',
),
+ 'period' => array(
+ 'days' => 'days', //TODO - Translation
+ 'hours' => 'hours', //TODO - Translation
+ 'months' => 'months', //TODO - Translation
+ 'weeks' => 'weeks', //TODO - Translation
+ 'years' => 'years', //TODO - Translation
+ ),
'share' => array(
'blogotext' => 'Blogotext',
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'gnusocial' => 'GNU social',
'jdh' => 'Journal du hacker',
'Known' => 'Known based sites',
+ 'lemmy' => 'Lemmy',
'linkedin' => 'LinkedIn',
'mastodon' => 'Mastodon',
'movim' => 'Movim',
diff --git a/app/i18n/pt-br/index.php b/app/i18n/pt-br/index.php
index e5807ed95..fac17e171 100644
--- a/app/i18n/pt-br/index.php
+++ b/app/i18n/pt-br/index.php
@@ -7,7 +7,7 @@ return array(
'bugs_reports' => 'Reportar Bugs',
'credits' => 'Créditos',
'credits_content' => 'Alguns elementos de design vieram do <a href="http://twitter.github.io/bootstrap/">Bootstrap</a> Embora FreshRRS não utiliza este framework. <a href="https://git.gnome.org/browse/gnome-icon-theme-symbolic">Ícones</a> vieram do <a href="https://www.gnome.org/">GNOME project</a>. <em>Open Sans</em> font police foi criada por <a href="https://fonts.google.com/specimen/Open+Sans">Steve Matteson</a>. FreshRSS é baseado no <a href="https://github.com/marienfressinaud/MINZ">Minz</a>, um framework PHP.',
- 'freshrss_description' => 'FreshRSS é um RSS feeds aggregator para um host próprio como o <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> ou <a href="http://leed.idleman.fr/">Leed</a>. É leve e fácil de utilizar enquanto é uma ferramenta poderosa e configurável. ',
+ 'freshrss_description' => 'FreshRSS é um RSS feeds aggregator para um host próprio como o <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> ou <a href="https://github.com/LeedRSS/Leed">Leed</a>. É leve e fácil de utilizar enquanto é uma ferramenta poderosa e configurável. ',
'github' => '<a href="https://github.com/FreshRSS/FreshRSS/issues">no Github</a>',
'license' => 'licença',
'project_website' => 'Site do projeto',
@@ -15,6 +15,9 @@ return array(
'version' => 'Versão',
'website' => 'Site',
),
+ 'tos' => array(
+ 'title' => 'Terms of Service', // TODO - Translation
+ ),
'feed' => array(
'add' => 'Você pode adicionar alguns feeds.',
'empty' => 'Não há nenhum artigo para mostrar.',
diff --git a/app/i18n/pt-br/sub.php b/app/i18n/pt-br/sub.php
index d4bea33c4..04e0c85ab 100644
--- a/app/i18n/pt-br/sub.php
+++ b/app/i18n/pt-br/sub.php
@@ -13,9 +13,12 @@ return array(
'category' => array(
'_' => 'Categoria',
'add' => 'Adicionar uma categoria',
+ 'archiving' => 'Arquivar',
'empty' => 'Categoria vazia',
'information' => 'Informações',
'new' => 'Nova categoria',
+ 'position' => 'Display position', //TODO - Translation
+ 'position_help' => 'To control category sort order', //TODO - Translation
'title' => 'Título',
),
'feed' => array(
@@ -40,7 +43,7 @@ return array(
'help' => 'Write one search filter per line.', //TODO - Translation
),
'information' => 'Informações',
- 'keep_history' => 'Número mínimo de artigos para manter',
+ 'keep_min' => 'Número mínimo de artigos para manter',
'moved_category_deleted' => 'Quando você deleta uma categoria, seus feeds são automaticamente classificados como <em>%s</em>.',
'mute' => 'mute', //TODO - Translation
'no_selected' => 'Nenhum feed selecionado.',
@@ -70,6 +73,11 @@ return array(
'validator' => 'Verifique a validade do feed',
'website' => 'URL do site',
),
+ 'firefox' => array(
+ 'documentation' => 'Follow the steps described <a href="https://developer.mozilla.org/en-US/Firefox/Releases/2/Adding_feed_readers_to_Firefox#Adding_a_new_feed_reader_manually">here</a> to add FreshRSS to Firefox feed reader list.',// TODO
+ 'obsolete_63' => 'From version 63 and onwards, Firefox has removed the ability to add your own subscription services that are not standalone programs.', //TODO - Translation
+ 'title' => 'Firefox feed reader', //TODO - Translation
+ ),
'import_export' => array(
'export' => 'Exportar',
'export_opml' => 'Exporta a lista dos feeds (OPML)',
diff --git a/app/i18n/pt-br/user.php b/app/i18n/pt-br/user.php
new file mode 100644
index 000000000..3a8343c11
--- /dev/null
+++ b/app/i18n/pt-br/user.php
@@ -0,0 +1,37 @@
+<?php
+
+return array(
+ 'email' => array(
+ 'feedback' => array(
+ 'invalid' => 'The email address is invalid.', //TODO - Translation
+ 'required' => 'The email address is required.', //TODO - Translation
+ ),
+ 'validation' => array(
+ 'change_email' => 'You can change your email address <a href="%s">on the profile page</a>.', //TODO - Translation
+ 'email_sent_to' => 'We sent you an email at <strong>%s</strong>, please follow its indications to validate your address.', //TODO - Translation
+ 'feedback' => array(
+ 'email_failed' => 'We couldn’t send you an email because of a misconfiguration of the server.', //TODO - Translation
+ 'email_sent' => 'An email has been sent to your address.', //TODO - Translation
+ 'error' => 'The email address failed to be validated.', //TODO - Translation
+ 'ok' => 'The email address has been validated.', //TODO - Translation
+ 'unneccessary' => 'The email address was already validated.', //TODO - Translation
+ 'wrong_token' => 'The email address failed to be validated due to a wrong token.', //TODO - Translation
+ ),
+ 'need_to' => 'You need to validate your email address before being able to use %s.', //TODO - Translation
+ 'resend_email' => 'Resend the email', //TODO - Translation
+ 'title' => 'Email address validation', //TODO - Translation
+ ),
+ ),
+ 'tos' => array(
+ 'feedback' => array(
+ 'invalid' => 'You must accept the Terms of Service to be able to register.', // TODO - Translation
+ ),
+ ),
+ 'mailer' => array(
+ 'email_need_validation' => array(
+ 'title' => 'You need to validate your account', //TODO - Translation
+ 'welcome' => 'Welcome %s,', //TODO - Translation
+ 'body' => 'You’ve just registered on %s but you still need to validate your email. For that, just follow the link:', //TODO - Translation
+ ),
+ ),
+);
diff --git a/app/i18n/ru/admin.php b/app/i18n/ru/admin.php
index c9a7d6683..adf091df9 100644
--- a/app/i18n/ru/admin.php
+++ b/app/i18n/ru/admin.php
@@ -159,6 +159,7 @@ return array(
'system' => array(
'_' => 'Системные настройки',
'auto-update-url' => 'Адрес сервера для автоматического обновления',
+ 'force_email_validation' => 'Force email addresses validation', //TODO - Translation
'instance-name' => 'Название этого сервера',
'max-categories' => 'Количество категорий на пользователя',
'max-feeds' => 'Количество статей на пользователя',
diff --git a/app/i18n/ru/conf.php b/app/i18n/ru/conf.php
index 841477964..7a80587f8 100644
--- a/app/i18n/ru/conf.php
+++ b/app/i18n/ru/conf.php
@@ -3,13 +3,21 @@
return array(
'archiving' => array(
'_' => 'Архивация',
- 'advanced' => 'Продвинутые настройки',
'delete_after' => 'Удалять статьи после',
+ 'exception' => 'Purge exception', //TODO - Translation
'help' => 'Каждую подписку можно настроить более гибко',
- 'keep_history_by_feed' => 'Minimum number of articles to keep by feed', //TODO - Translation
+ 'keep_favourites' => 'Never delete favourites', //TODO - Translation
+ 'keep_min_by_feed' => 'Minimum number of articles to keep by feed', //TODO - Translation
+ 'keep_labels' => 'Never delete labels', //TODO - Translation
+ 'keep_unreads' => 'Never delete unreads', //TODO - Translation
+ 'maintenance' => 'Maintenance', //TODO - Translation
'optimize' => 'Оптимизировать базу данных',
- 'optimize_help' => 'To do occasionally to reduce the size of the database', //TODO - Translation
+ 'optimize_help' => 'To do occasionally to reduce the size of the database', //TODO - Translation
+ 'policy' => 'Purge policy', //TODO - Translation
+ 'policy_warning' => 'If no purge policy is selected, every article will be kept.', //TODO - Translation
'purge_now' => 'Очистить сейчас',
+ 'keep_max' => 'Maximum number of articles to keep', //TODO - Translation
+ 'keep_period' => 'Maximum age of articles to keep', //TODO - Translation
'title' => 'Архивация',
'ttl' => 'Не обновлять чаще чем',
),
@@ -21,6 +29,7 @@ return array(
'publication_date' => 'Date of publication', //TODO - Translation
'related_tags' => 'Related tags', //TODO - Translation
'sharing' => 'Sharing', //TODO - Translation
+ 'display_authors' => 'Authors', //TODO - Translation
'top_line' => 'Top line', //TODO - Translation
),
'language' => 'Язык',
@@ -45,6 +54,7 @@ return array(
'_' => 'Account deletion', //TODO - Translation
'warn' => 'Your account and all the related data will be deleted.', //TODO - Translation
),
+ 'email' => 'Email address', //TODO - Translation
'password_api' => 'Password API<br /><small>(e.g., for mobile apps)</small>', //TODO - Translation
'password_form' => 'Password<br /><small>(for the Web-form login method)</small>', //TODO - Translation
'password_format' => 'At least 7 characters', //TODO - Translation
@@ -133,7 +143,6 @@ return array(
'diaspora' => 'Diaspora*',
'email' => 'Email', //TODO - Translation
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'more_information' => 'More information', //TODO - Translation
'print' => 'Print', //TODO - Translation
'remove' => 'Remove sharing method', //TODO - Translation
diff --git a/app/i18n/ru/gen.php b/app/i18n/ru/gen.php
index b55c6b667..5200a7005 100644
--- a/app/i18n/ru/gen.php
+++ b/app/i18n/ru/gen.php
@@ -3,6 +3,7 @@
return array(
'action' => array(
'actualize' => 'Actualize', //TODO - Translation
+ 'back' => '← Go back', //TODO - Translation
'back_to_rss_feeds' => '← Go back to your RSS feeds', //TODO - Translation
'cancel' => 'Cancel', //TODO - Translation
'create' => 'Create', //TODO - Translation
@@ -22,6 +23,7 @@ return array(
'update' => 'Update', //TODO - Translation
),
'auth' => array(
+ 'accept_tos' => 'I accept the <a href="%s">Terms of Service</a>.', // TODO - Translation
'email' => 'Email address', //TODO - Translation
'keep_logged_in' => 'Keep me logged in <small>(%s дней)</small>', //TODO - Translation
'login' => 'Login', //TODO - Translation
@@ -160,15 +162,22 @@ return array(
'nothing_to_load' => 'There are no more articles', //TODO - Translation
'previous' => 'Previous', //TODO - Translation
),
+ 'period' => array(
+ 'days' => 'days', //TODO - Translation
+ 'hours' => 'hours', //TODO - Translation
+ 'months' => 'months', //TODO - Translation
+ 'weeks' => 'weeks', //TODO - Translation
+ 'years' => 'years', //TODO - Translation
+ ),
'share' => array(
'blogotext' => 'Blogotext',
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'gnusocial' => 'GNU social',
'jdh' => 'Journal du hacker',
'Known' => 'Known based sites',
+ 'lemmy' => 'Lemmy',
'linkedin' => 'LinkedIn',
'mastodon' => 'Mastodon',
'movim' => 'Movim',
diff --git a/app/i18n/ru/index.php b/app/i18n/ru/index.php
index 977777178..b5f022cd2 100644
--- a/app/i18n/ru/index.php
+++ b/app/i18n/ru/index.php
@@ -7,7 +7,7 @@ return array(
'bugs_reports' => 'Bugs reports', //TODO - Translation
'credits' => 'Credits', //TODO - Translation
'credits_content' => 'Some design elements come from <a href="http://twitter.github.io/bootstrap/">Bootstrap</a> although FreshRSS doesn’t use this framework. <a href="https://git.gnome.org/browse/gnome-icon-theme-symbolic">Icons</a> come from <a href="https://www.gnome.org/">GNOME project</a>. <em>Open Sans</em> font police has been created by <a href="https://fonts.google.com/specimen/Open+Sans">Steve Matteson</a>. FreshRSS is based on <a href="https://github.com/marienfressinaud/MINZ">Minz</a>, a PHP framework.', //TODO - Translation
- 'freshrss_description' => 'FreshRSS is a RSS feeds aggregator to self-host like <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> or <a href="http://leed.idleman.fr/">Leed</a>. It is light and easy to take in hand while being powerful and configurable tool.', //TODO - Translation
+ 'freshrss_description' => 'FreshRSS is a RSS feeds aggregator to self-host like <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> or <a href="https://github.com/LeedRSS/Leed">Leed</a>. It is light and easy to take in hand while being powerful and configurable tool.', //TODO - Translation
'github' => '<a href="https://github.com/FreshRSS/FreshRSS/issues">on Github</a>', //TODO - Translation
'license' => 'License', //TODO - Translation
'project_website' => 'Project website', //TODO - Translation
@@ -15,6 +15,9 @@ return array(
'version' => 'Version', //TODO - Translation
'website' => 'Website', //TODO - Translation
),
+ 'tos' => array(
+ 'title' => 'Terms of Service', // TODO - Translation
+ ),
'feed' => array(
'add' => 'You may add some feeds.', //TODO - Translation
'empty' => 'There is no article to show.', //TODO - Translation
diff --git a/app/i18n/ru/sub.php b/app/i18n/ru/sub.php
index a2c4e4690..e8cdeb89d 100644
--- a/app/i18n/ru/sub.php
+++ b/app/i18n/ru/sub.php
@@ -13,9 +13,12 @@ return array(
'category' => array(
'_' => 'Category', //TODO - Translation
'add' => 'Add a category', //TODO - Translation
+ 'archiving' => 'Archivage', //TODO - Translation
'empty' => 'Empty category', //TODO - Translation
'information' => 'Information', //TODO - Translation
'new' => 'New category', //TODO - Translation
+ 'position' => 'Display position', //TODO - Translation
+ 'position_help' => 'To control category sort order', //TODO - Translation
'title' => 'Title', //TODO - Translation
),
'feed' => array(
@@ -40,7 +43,7 @@ return array(
'help' => 'Write one search filter per line.', //TODO - Translation
),
'information' => 'Information', //TODO - Translation
- 'keep_history' => 'Minimum number of articles to keep', //TODO - Translation
+ 'keep_min' => 'Minimum number of articles to keep', //TODO - Translation
'moved_category_deleted' => 'When you delete a category, its feeds are automatically classified under <em>%s</em>.', //TODO - Translation
'mute' => 'mute', //TODO - Translation
'no_selected' => 'No feed selected.', //TODO - Translation
@@ -72,6 +75,7 @@ return array(
),
'firefox' => array(
'documentation' => 'Follow the steps described <a href="https://developer.mozilla.org/en-US/Firefox/Releases/2/Adding_feed_readers_to_Firefox#Adding_a_new_feed_reader_manually">here</a> to add FreshRSS to Firefox feed reader list.', //TODO - Translation
+ 'obsolete_63' => 'From version 63 and onwards, Firefox has removed the ability to add your own subscription services that are not standalone programs.', //TODO - Translation
'title' => 'Firefox feed reader', //TODO - Translation
),
'import_export' => array(
diff --git a/app/i18n/ru/user.php b/app/i18n/ru/user.php
new file mode 100644
index 000000000..3a8343c11
--- /dev/null
+++ b/app/i18n/ru/user.php
@@ -0,0 +1,37 @@
+<?php
+
+return array(
+ 'email' => array(
+ 'feedback' => array(
+ 'invalid' => 'The email address is invalid.', //TODO - Translation
+ 'required' => 'The email address is required.', //TODO - Translation
+ ),
+ 'validation' => array(
+ 'change_email' => 'You can change your email address <a href="%s">on the profile page</a>.', //TODO - Translation
+ 'email_sent_to' => 'We sent you an email at <strong>%s</strong>, please follow its indications to validate your address.', //TODO - Translation
+ 'feedback' => array(
+ 'email_failed' => 'We couldn’t send you an email because of a misconfiguration of the server.', //TODO - Translation
+ 'email_sent' => 'An email has been sent to your address.', //TODO - Translation
+ 'error' => 'The email address failed to be validated.', //TODO - Translation
+ 'ok' => 'The email address has been validated.', //TODO - Translation
+ 'unneccessary' => 'The email address was already validated.', //TODO - Translation
+ 'wrong_token' => 'The email address failed to be validated due to a wrong token.', //TODO - Translation
+ ),
+ 'need_to' => 'You need to validate your email address before being able to use %s.', //TODO - Translation
+ 'resend_email' => 'Resend the email', //TODO - Translation
+ 'title' => 'Email address validation', //TODO - Translation
+ ),
+ ),
+ 'tos' => array(
+ 'feedback' => array(
+ 'invalid' => 'You must accept the Terms of Service to be able to register.', // TODO - Translation
+ ),
+ ),
+ 'mailer' => array(
+ 'email_need_validation' => array(
+ 'title' => 'You need to validate your account', //TODO - Translation
+ 'welcome' => 'Welcome %s,', //TODO - Translation
+ 'body' => 'You’ve just registered on %s but you still need to validate your email. For that, just follow the link:', //TODO - Translation
+ ),
+ ),
+);
diff --git a/app/i18n/sk/admin.php b/app/i18n/sk/admin.php
new file mode 100644
index 000000000..347204f37
--- /dev/null
+++ b/app/i18n/sk/admin.php
@@ -0,0 +1,199 @@
+<?php
+
+return array(
+ 'auth' => array(
+ 'allow_anonymous' => 'Povoliť čítanie článkov prednastaveného používateľa (%s) bez prihlásenia.',
+ 'allow_anonymous_refresh' => 'Povoliť obnovenie článkov bez prihlásenia',
+ 'api_enabled' => 'Povoliť prístup cez <abbr>API</abbr> <small>(vyžadujú mobilné aplikácie)</small>',
+ 'form' => 'Webový formulár (traditičný, vyžaduje JavaScript)',
+ 'http' => 'HTTP (pre pokročilých používateľov s HTTPS)',
+ 'none' => 'Žiadny (nebezpečné)',
+ 'title' => 'Prihlásenie',
+ 'title_reset' => 'Reset prihlásenia',
+ 'token' => 'Token prihlásenia',
+ 'token_help' => 'Povoliť prístup k výstupu RSS prednastaveného používateľa bez prihlásenia:',
+ 'type' => 'Spôsob prihlásenia',
+ 'unsafe_autologin' => 'Povoliť nebezpečné automatické prihlásenie pomocou webového formulára: ',
+ ),
+ 'check_install' => array(
+ 'cache' => array(
+ 'nok' => 'Overte prístupové práva priečinka <em>./data/cache</em>. HTTP server musí mať právo doň zapisovať.',
+ 'ok' => 'Prístupové práva priečinka pre vyrovnávaciu pamäť sú OK.',
+ ),
+ 'categories' => array(
+ 'nok' => 'Tabuľka kategórií je nesprávne nastavená.',
+ 'ok' => 'Tabuľka kategórií je OK.',
+ ),
+ 'connection' => array(
+ 'nok' => 'Nepodarilo sa vytvoriť pripojenie k databáze.',
+ 'ok' => 'Pripojenie k databáze je OK.',
+ ),
+ 'ctype' => array(
+ 'nok' => 'Nepodarilo sa nájsť požadovanú knižnicu na kontrolu typu znakov (php-ctype).',
+ 'ok' => 'Našla sa požadovaná knižnica na kontrolu typu znakov (ctype).',
+ ),
+ 'curl' => array(
+ 'nok' => 'Nepodarilo sa nájsť knižnicu cURL (balík php-curl).',
+ 'ok' => 'Našla sa knižnica cURL.',
+ ),
+ 'data' => array(
+ 'nok' => 'Skontrolujte oprávnenia prístupu do priečinku <em>./data</em>. HTTP server musí mať právo doň zapisovať.',
+ 'ok' => 'Oprávnenia prístupu do priečinku údajov sú OK.',
+ ),
+ 'database' => 'Inštalácia databázy',
+ 'dom' => array(
+ 'nok' => 'Nepodarilo sa nájsť požadovanú knižnicu na prehliadanie DOM.',
+ 'ok' => 'Našla sa požadovaná knižnica na prehliadanie DOM.',
+ ),
+ 'entries' => array(
+ 'nok' => 'Tabuľka článkov je nesprávne nastavená.',
+ 'ok' => 'Tabuľka článkov je OK.',
+ ),
+ 'favicons' => array(
+ 'nok' => 'Skontrolujte oprávnenia prístupu do priečinku <em>./data/favicons</em>. HTTP server musí mať právo doň zapisovať.',
+ 'ok' => 'Oprávnenia prístupu do priečinku ikôn obľúbených sú OK.',
+ ),
+ 'feeds' => array(
+ 'nok' => 'Tabuľka kanálov je nesprávne nastavená.',
+ 'ok' => 'Tabuľka kanálov je OK.',
+ ),
+ 'fileinfo' => array(
+ 'nok' => 'Nepodarilo sa nájsť knižniuc PHP fileinfo (balík fileinfo).',
+ 'ok' => 'Našla sa knižnica fileinfo.',
+ ),
+ 'files' => 'Inštalácia súborov',
+ 'json' => array(
+ 'nok' => 'Nepodarilo sa nájsť požadovanú knižnicu na spracovanie formátu JSON.',
+ 'ok' => 'Našla sa požadovaná knižnica na spracovanie formátu JSON.',
+ ),
+ 'mbstring' => array(
+ 'nok' => 'Nepodarilo sa nájsť požadovanú knižnicu mbstring pre Unicode.',
+ 'ok' => 'Našla sa požadovaná knižnica mbstring pre Unicode.',
+ ),
+ 'minz' => array(
+ 'nok' => 'Nepodarilo sa nájsť framework Minz.',
+ 'ok' => 'Našiel sa framework Minz.',
+ ),
+ 'pcre' => array(
+ 'nok' => 'Nepodarilo sa nájsť požadovanú knižnicu pre regulárne výrazy (php-pcre).',
+ 'ok' => 'Našla sa požadovaná knižnica pre regulárne výrazy (PCRE).',
+ ),
+ 'pdo' => array(
+ 'nok' => 'Nepodarilo sa nájsť PDO alebo niektorý z podporovaných ovládačov (pdo_mysql, pdo_sqlite, pdo_pgsql).',
+ 'ok' => 'Našiel sa PDO a aspoň jeden z podporovaných ovládačov (pdo_mysql, pdo_sqlite, pdo_pgsql).',
+ ),
+ 'php' => array(
+ '_' => 'Inštalácia PHP',
+ 'nok' => 'Vaša verzia PHP je %s, ale FreshRSS vyžaduje minimálne verziu %s.',
+ 'ok' => 'Vaša verzia PHP %s je kompatibilná s FreshRSS.',
+ ),
+ 'tables' => array(
+ 'nok' => 'V databáze chýba jedna alebo viacero tabuliek.',
+ 'ok' => 'V databáze sa nachádzajú všetky potrebné tabuľky.',
+ ),
+ 'title' => 'Kontrola inštalácie',
+ 'tokens' => array(
+ 'nok' => 'Skontrolujte oprávnenia prístupu do priečinku <em>./data/tokens</em>. HTTP server musí mať právo doň zapisovať.',
+ 'ok' => 'Oprávnenia prístupu do priečinku tokens sú OK.',
+ ),
+ 'users' => array(
+ 'nok' => 'Skontrolujte oprávnenia prístupu do priečinku <em>./data/users</em>. HTTP server musí mať právo doň zapisovať.',
+ 'ok' => 'Oprávnenia prístupu do priečinku používateľov sú OK.',
+ ),
+ 'zip' => array(
+ 'nok' => 'Nepodarilo sa nájsť rozšírenie ZIP (balík php-zip).',
+ 'ok' => 'Rozšírenie ZIP sa našlo.',
+ ),
+ ),
+ 'extensions' => array(
+ 'author' => 'Autor',
+ 'community' => 'Rozšírenia od komunity',
+ 'description' => 'Popis',
+ 'disabled' => 'Zakázané',
+ 'empty_list' => 'Žiadne nainštalované rozšírenia',
+ 'enabled' => 'Povolené',
+ 'latest' => 'Nainštalované',
+ 'name' => 'Názov',
+ 'no_configure_view' => 'Toto rozšírenie nemá nastavenia.',
+ 'system' => array(
+ '_' => 'Systémové rozšírenia',
+ 'no_rights' => 'Systémové rozšírenie (nemáte oprávnenia)',
+ ),
+ 'title' => 'Rozšírenia',
+ 'update' => 'Sú dostupné aktualizácie',
+ 'user' => 'Používateľské rozšírenia',
+ 'version' => 'Verzia',
+ ),
+ 'stats' => array(
+ '_' => 'Štatistiky',
+ 'all_feeds' => 'Všetky kanály',
+ 'category' => 'Kategória',
+ 'entry_count' => 'Počet položiek',
+ 'entry_per_category' => 'Položiek v kategórii',
+ 'entry_per_day' => 'Položiek za deň (posledných 30 dní)',
+ 'entry_per_day_of_week' => 'Za deň v týždni (priemer: %.2f správy)',
+ 'entry_per_hour' => 'Za hodinu (priemer: %.2f správy)',
+ 'entry_per_month' => 'Za mesiac (priemer: %.2f správy)',
+ 'entry_repartition' => 'Rozdelenie článkov',
+ 'feed' => 'Kanál',
+ 'feed_per_category' => 'Kanálov v kategórii',
+ 'idle' => 'Neaktívne kanály',
+ 'main' => 'Hlavné štatistiky',
+ 'main_stream' => 'Všetky kanály',
+ 'menu' => array(
+ 'idle' => 'Neaktívne kanály',
+ 'main' => 'Hlavné štatistiky',
+ 'repartition' => 'Rozdelenie článkov',
+ ),
+ 'no_idle' => 'Žiadne neaktívne kanály!',
+ 'number_entries' => 'Počet článkov: %d',
+ 'percent_of_total' => 'Z celkového počtu: %%',
+ 'repartition' => 'Rozdelenie článkov',
+ 'status_favorites' => 'Obľúbené',
+ 'status_read' => 'Prečítané',
+ 'status_total' => 'Spolu',
+ 'status_unread' => 'Neprečítané',
+ 'title' => 'Štatistiky',
+ 'top_feed' => 'Top 10 kanálov',
+ ),
+ 'system' => array(
+ '_' => 'Nastavenia systému',
+ 'auto-update-url' => 'Odkaz na aktualizačný server',
+ 'instance-name' => 'Názov inštancie',
+ 'max-categories' => 'Limit počtu kategórií pre používateľa',
+ 'max-feeds' => 'Limit počtu kanálov pre používateľov',
+ 'cookie-duration' => array(
+ 'help' => 'v sekundách',
+ 'number' => 'Dobra, počas ktorej ste prihlásený',
+ ),
+ 'registration' => array(
+ 'help' => '0 znamená žiadny limit počtu účtov',
+ 'number' => 'Maximálny počt účtov',
+ ),
+ ),
+ 'update' => array(
+ '_' => 'Aktualizácia systému',
+ 'apply' => 'Použiť',
+ 'check' => 'Skontrolovať aktualizácie',
+ 'current_version' => 'Vaša aktuálna verzia FreshRSS: %s',
+ 'last' => 'Posledná kontrola: %s',
+ 'none' => 'Žiadna nová aktualizácia',
+ 'title' => 'Aktualizácia systému',
+ ),
+ 'user' => array(
+ 'articles_and_size' => '%s článkov (%s)',
+ 'create' => 'Vytvoriť nového používateľa',
+ 'delete_users' => 'Zmazať používateľa',
+ 'language' => 'Jazyk',
+ 'number' => 'Je vytvorený používateľ: %d',
+ 'numbers' => 'Je vytvorených používateľov: %d',
+ 'password_form' => 'Heslo<br /><small>(pre spôsob prihlásenia cez webový formulár)</small>',
+ 'password_format' => 'Minimálne 7 znakov',
+ 'selected' => 'Označený používateľ',
+ 'title' => 'Správa používateľov',
+ 'update_users' => 'Sktualizovať používateľov',
+ 'user_list' => 'Zoznam používateľov',
+ 'username' => 'Používateľské meno',
+ 'users' => 'Používatelia',
+ ),
+);
diff --git a/app/i18n/sk/conf.php b/app/i18n/sk/conf.php
new file mode 100644
index 000000000..2e2289b79
--- /dev/null
+++ b/app/i18n/sk/conf.php
@@ -0,0 +1,188 @@
+<?php
+
+return array(
+ 'archiving' => array(
+ '_' => 'Archivovanie',
+ 'advanced' => 'Pokročilé',
+ 'delete_after' => 'Vymazať články po',
+ 'help' => 'Viac možností nájdete v nastaveniach kanála',
+ 'keep_min_by_feed' => 'Minimálny počet článkov kanála na zachovanie',
+ 'optimize' => 'Optimalizovať databázu',
+ 'optimize_help' => 'Občas vykonajte na zmenšenie veľkosti databázy',
+ 'purge_now' => 'Vyčistiť teraz',
+ 'title' => 'Archivovanie',
+ 'ttl' => 'Neaktualizovať častejšie ako',
+ ),
+ 'display' => array(
+ '_' => 'Zobrazenie',
+ 'icon' => array(
+ 'bottom_line' => 'Spodný riadok',
+ 'display_authors' => 'Autori',
+ 'entry' => 'Ikony článku',
+ 'publication_date' => 'Dátum zverejnenia',
+ 'related_tags' => 'Značky článku',
+ 'sharing' => 'Zdieľanie',
+ 'top_line' => 'Horný riadok',
+ ),
+ 'language' => 'Jazyk',
+ 'notif_html5' => array(
+ 'seconds' => 'sekundy (0 znamená bez limitu)',
+ 'timeout' => 'Limit HTML5 oznámenia',
+ ),
+ 'show_nav_buttons' => 'Zobraziť tlačidlá oznámenia',
+ 'theme' => 'Vzhľad',
+ 'title' => 'Zobraziť',
+ 'width' => array(
+ 'content' => 'Šírka obsahu',
+ 'large' => 'Veľká',
+ 'medium' => 'Stredná',
+ 'no_limit' => 'Bez obmedzenia',
+ 'thin' => 'Úzka',
+ ),
+ ),
+ 'profile' => array(
+ '_' => 'Správca profilu',
+ 'delete' => array(
+ '_' => 'Vymazanie účtu',
+ 'warn' => 'Váš účet a všetky údaje v ňom budú vymazané.',
+ ),
+ 'password_api' => 'Heslo API<br /><small>(pre mobilné aplikácie)</small>',
+ 'password_form' => 'Heslo<br /><small>(pre spôsob prihlásenia cez webový formulár)</small>',
+ 'password_format' => 'Najmenej 7 znakov',
+ 'title' => 'Profil',
+ ),
+ 'query' => array(
+ '_' => 'Dopyty používateľa',
+ 'deprecated' => 'Tento dopyt už nie je platný. Kategória alebo kanál boli vymazané.',
+ 'display' => 'Zobraziť výsledky dopytu používateľa',
+ 'filter' => 'Použitý filter:',
+ 'get_all' => 'Zobraziť všetky články',
+ 'get_category' => 'Zobraziť kategóriu "%s"',
+ 'get_favorite' => 'Zobraziť obľúbené články',
+ 'get_feed' => 'Zobraziť kanál "%s"',
+ 'no_filter' => 'Žiadny filter',
+ 'none' => 'Zatiaľ ste nevytvorili používateľský dopyt.',
+ 'number' => 'Dopyt číslo %d',
+ 'order_asc' => 'Zobraziť staršie články hore',
+ 'order_desc' => 'Zobraziť novšie články hore',
+ 'remove' => 'Vymazať dopyt používateľa',
+ 'search' => 'Vyhľadáva sa: "%s"',
+ 'state_0' => 'Zobraziť všetky články',
+ 'state_1' => 'Zobraziť prečítané články',
+ 'state_2' => 'Zobraziť neprečítané články',
+ 'state_3' => 'Zobraziť všetky články',
+ 'state_4' => 'Zobraziť obľúbené články',
+ 'state_5' => 'Zobraziť prečítané obľúbené články',
+ 'state_6' => 'Zobraziť neprečítané obľúbené články',
+ 'state_7' => 'Zobraziť obľúbené články',
+ 'state_8' => 'Zobraziť neobľúbené články',
+ 'state_9' => 'Zobraziť prečítané neobľúbené články',
+ 'state_10' => 'Zobraziť neprečítané neobľúbené články',
+ 'state_11' => 'Zobraziť neobľúbené články',
+ 'state_12' => 'Zobraziť všetky články',
+ 'state_13' => 'Zobraziť prečítané články',
+ 'state_14' => 'Zobraziť neprečítané články',
+ 'state_15' => 'Zobraziť všetky články',
+ 'title' => 'Používateľské dopyty',
+ ),
+ 'reading' => array(
+ '_' => 'Čítanie',
+ 'after_onread' => 'Po “Označiť všetko ako prečítané”,',
+ 'articles_per_page' => 'Počet článkov na jednu stranu',
+ 'auto_load_more' => 'Načítať ďalšie články dolu na stránke',
+ 'auto_remove_article' => 'Skryť články po prečítaní',
+ 'confirm_enabled' => 'Zobraziť potvrdzovací dialóg po kliknutí na “Označiť všetko ako prečítané”',
+ 'display_articles_unfolded' => 'Zobraziť články otvorené',
+ 'display_categories_unfolded' => 'Zobraziť kategórie otvorené',
+ 'hide_read_feeds' => 'Skryť kategórie a kanály s nulovým počtom neprečítaných článkov (nefunguje s nastaveným “Zobraziť všetky články”)',
+ 'img_with_lazyload' => 'Pre načítanie obrázkov použiť "lazy load"',
+ 'jump_next' => 'skočiť na ďalší neprečítaný (kanál ale kategóriu)',
+ 'mark_updated_article_unread' => 'Označiť aktualizované články ako neprečítané',
+ 'number_divided_when_reader' => 'V režime čítania predeliť na dve časti.',
+ 'read' => array(
+ 'article_open_on_website' => 'keď je článok otvorený na svojej webovej stránke',
+ 'article_viewed' => 'keď je článok zobrazený',
+ 'scroll' => 'počas skrolovania',
+ 'upon_reception' => 'po načítaní článku',
+ 'when' => 'Označiť článok ako prečítaný…',
+ ),
+ 'show' => array(
+ '_' => 'Článkov na zobrazenie',
+ 'adaptive' => 'Vyberte zobrazenie',
+ 'all_articles' => 'Zobraziť všetky články',
+ 'unread' => 'Zobraziť iba neprečítané',
+ ),
+ 'sides_close_article' => 'Po kliknutí mimo textu článku sa článok zatvorí',
+ 'sort' => array(
+ '_' => 'Poradie',
+ 'newer_first' => 'Novšie hore',
+ 'older_first' => 'Staršie hore',
+ ),
+ 'sticky_post' => 'Po otvorení posunúť článok hore',
+ 'title' => 'Čítanie',
+ 'view' => array(
+ 'default' => 'Prednastavené zobrazenie',
+ 'global' => 'Prehľadné zobrazenie',
+ 'normal' => 'Základné zobrazenie',
+ 'reader' => 'Zobrazenie na čítanie',
+ ),
+ ),
+ 'sharing' => array(
+ '_' => 'Zdieľanie',
+ 'add' => 'Pridať spôsob zdieľania',
+ 'blogotext' => 'Blogotext',
+ 'diaspora' => 'Diaspora*',
+ 'email' => 'E-mail',
+ 'facebook' => 'Facebook',
+ 'g+' => 'Google+',
+ 'more_information' => 'Viac informácií',
+ 'print' => 'Tlač',
+ 'remove' => 'Odstrániť spôsob zdieľania',
+ 'shaarli' => 'Shaarli',
+ 'share_name' => 'Meno pre zobrazenie',
+ 'share_url' => 'Zdieľaný odkaz',
+ 'title' => 'Zdieľanie',
+ 'twitter' => 'Twitter',
+ 'wallabag' => 'wallabag',
+ ),
+ 'shortcut' => array(
+ '_' => 'Skratky',
+ 'article_action' => 'Akcie článku',
+ 'auto_share' => 'Zdieľať',
+ 'auto_share_help' => 'Ak je nastavený iba jeden spôsob zdieľania, použije sa. Inak si spôsoby zdieľania vyberá používateľ podľa čísla.',
+ 'close_dropdown' => 'Zavrie menu',
+ 'collapse_article' => 'Zroluje článok',
+ 'first_article' => 'Otvorí prvý článok',
+ 'focus_search' => 'Vyhľadávanie',
+ 'global_view' => 'Prepne do prehľadného zobrazenia',
+ 'help' => 'Zobrazí dokumentáciu',
+ 'javascript' => 'JavaScript musí byť povolený, ak chcete používať skratky',
+ 'last_article' => 'Otvorí posledný článok',
+ 'load_more' => 'Načíta viac článkov',
+ 'mark_favorite' => 'O(d)značí ako obľúbené',
+ 'mark_read' => 'O(d)značí ako prečítané',
+ 'navigation' => 'Navigácia',
+ 'navigation_help' => 'Po stlačení skratky s klávesou "Shift", sa skratky navigácie vzťahujú na kanály.<br/>Po stlačení skratky s klávesou "Alt", sa skratky navigácie vzťahujú na kategórie.',
+ 'navigation_no_mod_help' => 'Tieto skratky navigácie nepodporujú klávesy "Shift" a "Alt".',
+ 'next_article' => 'Otvorí ďalší článok',
+ 'normal_view' => 'Prepne do základného zobrazenia',
+ 'other_action' => 'Ostatné akcie',
+ 'previous_article' => 'Otvorí predošlý článok',
+ 'reading_view' => 'Prepne do zobrazenia na čítanie',
+ 'rss_view' => 'Otvorí zobrazenie RSS v novej záložke',
+ 'see_on_website' => 'Zobrazí na webovej stránke',
+ 'shift_for_all_read' => '+ <code>shift</code> na označenie všetkých článkov ako prečítaných',
+ 'skip_next_article' => 'Prejde na ďalší bez otvorenia',
+ 'skip_previous_article' => 'Prejde na predošlý bez otvorenia',
+ 'title' => 'Skratky',
+ 'user_filter' => 'Použiť používateľské filtre',
+ 'user_filter_help' => 'Ak je nastavený iba jeden spôsob zdieľania, použije sa. Inak si spôsoby zdieľania vyberá používateľ podľa čísla.',
+ 'views' => 'Zobrazenia',
+ ),
+ 'user' => array(
+ 'articles_and_size' => '%s článkov (%s)',
+ 'current' => 'Aktuálny používateľ',
+ 'is_admin' => 'je administrátor',
+ 'users' => 'Používatelia',
+ ),
+);
diff --git a/app/i18n/sk/feedback.php b/app/i18n/sk/feedback.php
new file mode 100644
index 000000000..9aee79068
--- /dev/null
+++ b/app/i18n/sk/feedback.php
@@ -0,0 +1,116 @@
+<?php
+
+return array(
+ 'admin' => array(
+ 'optimization_complete' => 'Optimalizácia dokončená',
+ ),
+ 'access' => array(
+ 'denied' => 'Na prístup k tejto stránke nemáte oprávnenie',
+ 'not_found' => 'Hľadáte stránku, ktorá neexistuje',
+ ),
+ 'auth' => array(
+ 'form' => array(
+ 'not_set' => 'Nastavl problém pri nastavovaní prihlasovacieho systému. Prosím, skúste to znova neskôr.',
+ 'set' => 'Webový formulár je teraz váš prednastavený prihlasovací spôsob.',
+ ),
+ 'login' => array(
+ 'invalid' => 'Nesprávne prihlasovacie údaje',
+ 'success' => 'Úspešne ste sa prihlásili',
+ ),
+ 'logout' => array(
+ 'success' => 'Boli ste odhlásený',
+ ),
+ 'no_password_set' => 'Heslo administrátora nebolo nastavené. Táto funkcia nie je dostupná.',
+ ),
+ 'conf' => array(
+ 'error' => 'Vyskytla sa chyba počas ukladania nastavaní',
+ 'query_created' => 'Dopyt "%s" bol vytvorený.',
+ 'shortcuts_updated' => 'Skratky boli aktualizované',
+ 'updated' => 'Nastavenia boli aktualizované',
+ ),
+ 'extensions' => array(
+ 'already_enabled' => '%s už je povolené',
+ 'disable' => array(
+ 'ko' => '%s sa nepodarilo nainštalovať. <a href="%s">Prečítajte si záznamy FreshRSS</a>, ak chcete poznať podrobnosti.',
+ 'ok' => '%s je teraz zakázaný',
+ ),
+ 'enable' => array(
+ 'ko' => '%s sa nepodarilo povoliť. <a href="%s">Prečítajte si záznamy FreshRSS</a>, ak chcete poznať podrobnosti.',
+ 'ok' => '%s je teraz povolený',
+ ),
+ 'no_access' => 'Nemáte prístup k %s',
+ 'not_enabled' => '%s nie je povolený',
+ 'not_found' => '%s neexistuje',
+ ),
+ 'import_export' => array(
+ 'export_no_zip_extension' => 'ZIP rozšírenie sa na vašom serveri nenachádza. Prosím, skúste exportovať súbory pojednom.',
+ 'feeds_imported' => 'Váš kanál bol importovaný a bude aktualizovaný',
+ 'feeds_imported_with_errors' => 'Vaše kanály boli importované, ale vyskytli sa chyby',
+ 'file_cannot_be_uploaded' => 'Súbor sa nepodarilo nahrať!',
+ 'no_zip_extension' => 'ZIP rozšírenie sa na vašom serveri nenachádza.',
+ 'zip_error' => 'Počas importovania ZIP sa vyskytla chyba.',
+ ),
+ 'profile' => array(
+ 'error' => 'Váš profil nie je možné upraviť',
+ 'updated' => 'Váš profil bol upravený',
+ ),
+ 'sub' => array(
+ 'actualize' => 'Aktualizácia',
+ 'articles' => array(
+ 'marked_read' => 'Vybraté články boli označené ako prečítané.',
+ 'marked_unread' => 'Články boli označené ako neprečítané.',
+ ),
+ 'category' => array(
+ 'created' => 'Kategória %s bola vytvorená.',
+ 'deleted' => 'Kategória bola odstránená.',
+ 'emptied' => 'Kategória bola vyprázdnená',
+ 'error' => 'Nepodarilo sa aktualizovať kategóriu',
+ 'name_exists' => 'Názov kategórie už existuje.',
+ 'no_id' => 'Musíte zadať ID kategórie.',
+ 'no_name' => 'Názov kategórie nemôže byť prázdny.',
+ 'not_delete_default' => 'Nemôžete odstrániť prednastavenú kategóriu!',
+ 'not_exist' => 'Kategória neexistuje!',
+ 'over_max' => 'Dosiahli ste limit počtu kategórií (%d)',
+ 'updated' => 'Kategória bola aktualizovaná.',
+ ),
+ 'feed' => array(
+ 'actualized' => '<em>%s</em> bol aktualizovaný',
+ 'actualizeds' => 'RSS kanál bol aktualizovaný',
+ 'added' => 'RSS kanál <em>%s</em> bol pridaný',
+ 'already_subscribed' => 'Tento RSS kanál už odoberáte: <em>%s</em>',
+ 'deleted' => 'Kanál bol vymazaný',
+ 'error' => 'Kanál sa nepodarilo aktualizovať',
+ 'internal_problem' => 'Kanál sa nepodarilo pridať. <a href="%s">Prečítajte si záznamy FreshRSS</a>, ak chcete poznať podrobnosti. Skúste pridať kanál pomocou <code>#force_feed</code> v odkaze (URL).',
+ 'invalid_url' => 'Odkaz <em>%s</em> je neplatný',
+ 'n_actualized' => 'Počet aktualizovaných kanálov: %d',
+ 'n_entries_deleted' => 'Počet vymazaných článkov: %d',
+ 'no_refresh' => 'Žiadny kanál sa neaktualizoval…',
+ 'not_added' => 'Kanál <em>%s</em> sa nepodarilo pridať',
+ 'over_max' => 'Dosiahli ste limit počtu kanálov (%d)',
+ 'updated' => 'Kanál bol aktualizovaný',
+ ),
+ 'purge_completed' => 'Čistenie ukončené. Počet vymazaných článkov: %d',
+ ),
+ 'update' => array(
+ 'can_apply' => 'FreshRSS sa teraz aktualizuje <strong>na verziu %s</strong>.',
+ 'error' => 'Počas aktualizácie sa vyskytla chyba: %s',
+ 'file_is_nok' => 'Je dostupná nová <strong>verzia %s</strong>, ale skontrolujte prístupové práva priečinka <em>%s</em>. HTTP server musí mať právo doň zapisovať.',
+ 'finished' => 'Aktualizácia prebehla úspešne!',
+ 'none' => 'Žiadne aktualizácie',
+ 'server_not_found' => 'Nepodarilo sa nájsť server s aktualizáciami. [%s]',
+ ),
+ 'user' => array(
+ 'created' => array(
+ '_' => 'Používateľ %s bol vytvorený',
+ 'error' => 'Používateľ %s nebol vytvorený',
+ ),
+ 'deleted' => array(
+ '_' => 'Používateľ %s bol vymazaný',
+ 'error' => 'Používateľ %s nebol vymazaný',
+ ),
+ 'updated' => array(
+ '_' => 'Používateľ %s bol aktualizovaný',
+ 'error' => 'Používateľ %s nebol aktualizovaný',
+ ),
+ ),
+);
diff --git a/app/i18n/sk/gen.php b/app/i18n/sk/gen.php
new file mode 100644
index 000000000..7303ffa9f
--- /dev/null
+++ b/app/i18n/sk/gen.php
@@ -0,0 +1,181 @@
+<?php
+
+return array(
+ 'action' => array(
+ 'actualize' => 'Aktualizovať',
+ 'back_to_rss_feeds' => '← Späť na vaše RSS kanály',
+ 'cancel' => 'Zrušiť',
+ 'create' => 'Vytvoriť',
+ 'disable' => 'Zakázať',
+ 'empty' => 'Vyprázdniť',
+ 'enable' => 'Povoliť',
+ 'export' => 'Exportovať',
+ 'filter' => 'Filtrovať',
+ 'import' => 'Importovať',
+ 'manage' => 'Spravovať',
+ 'mark_favorite' => 'Označiť ako obľúbené',
+ 'mark_read' => 'Označiť ako prečítané',
+ 'remove' => 'Odstrániť',
+ 'see_website' => 'Zobraziť webovú stránku',
+ 'submit' => 'Poslať',
+ 'truncate' => 'Vymazať všetky články',
+ 'update' => 'Aktualizovať',
+ ),
+ 'auth' => array(
+ 'accept_tos' => 'I accept the <a href="%s">Terms of Service</a>.', // TODO - Translation
+ 'email' => 'E-mailová adresa',
+ 'keep_logged_in' => 'Zostať prihlásený <small>(počet dní: %s)</small>',
+ 'login' => 'Prihlásiť',
+ 'logout' => 'Odhlásiť',
+ 'password' => array(
+ '_' => 'Heslo',
+ 'format' => '<small>Najmenej 7 znakov</small>',
+ ),
+ 'registration' => array(
+ '_' => 'Nový účet',
+ 'ask' => 'Vytvoriť účet?',
+ 'title' => 'Vytvorenie účtu',
+ ),
+ 'reset' => 'Reset prihlásenia',
+ 'username' => array(
+ '_' => 'Používateľské meno',
+ 'admin' => 'Administrátorské používateľské meno',
+ 'format' => '<small>maximálne 16 alfanumerických znakov</small>',
+ ),
+ ),
+ 'date' => array(
+ 'Apr' => '\\A\\p\\r\\í\\l',
+ 'apr' => 'Apr.',
+ 'april' => 'Apríl',
+ 'Aug' => '\\A\\u\\g\\u\\s\\t',
+ 'aug' => 'Aug.',
+ 'august' => 'August',
+ 'before_yesterday' => 'Predvčerom',
+ 'Dec' => '\\D\\e\\c\\e\\m\\b\\e\\r',
+ 'dec' => 'Dec.',
+ 'december' => 'December',
+ 'Feb' => '\\F\\e\\b\\r\\u\\á\\r',
+ 'feb' => 'Feb.',
+ 'february' => 'Február',
+ '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',
+ 'fri' => 'Pi',
+ 'Jan' => '\\J\\a\\n\\u\\á\\r',
+ 'jan' => 'Jan.',
+ 'january' => 'Január',
+ 'Jul' => '\\J\\ú\\l',
+ 'jul' => 'Júl',
+ 'july' => 'Júl',
+ 'Jun' => '\\J\\ú\\n',
+ 'jun' => 'Jún',
+ 'june' => 'Jún',
+ 'last_3_month' => 'Posledné 3 mesiace',
+ 'last_6_month' => 'Posledných 6 mesiacov',
+ 'last_month' => 'Posledný mesiac',
+ 'last_week' => 'Posledný týždeň',
+ 'last_year' => 'Posledný rok',
+ 'Mar' => '\\M\\a\\r\\e\\c',
+ 'mar' => 'Mar.',
+ 'march' => 'Marec',
+ 'May' => '\\M\\á\\j',
+ 'may' => 'Máj',
+ 'may_' => 'Máj',
+ 'mon' => 'Po',
+ 'month' => 'mesiace',
+ 'Nov' => '\\N\\o\\v\\e\\m\\b\\e\\r',
+ 'nov' => 'Nov.',
+ 'november' => 'November',
+ 'Oct' => '\\O\\k\\t\\ó\\b\\e\\r',
+ 'oct' => 'Okt.',
+ 'october' => 'Október',
+ 'Sep' => '\\S\\e\\p\\t\\e\\m\\b\\e\\r',
+ 'sat' => 'So',
+ 'sep' => 'Sept.',
+ 'september' => 'September',
+ 'sun' => 'Ne',
+ 'thu' => 'Št',
+ 'today' => 'Dnes',
+ 'tue' => 'Ut',
+ 'wed' => 'St',
+ 'yesterday' => 'Včera',
+ ),
+ 'freshrss' => array(
+ '_' => 'FreshRSS',
+ 'about' => 'O FreshRSS',
+ ),
+ 'js' => array(
+ 'category_empty' => 'Prázdna kategória',
+ 'confirm_action' => 'Určite chcete vykonať túto akciu? Zmeny budú nezvratné!',
+ 'confirm_action_feed_cat' => 'Určite chcete vykonať túto akciu? Prídete o súvisiace obľúbené a používateľské dopyty. Zmeny budú nezvratné!',
+ 'feedback' => array(
+ 'body_new_articles' => 'Počet nových článkov v čítačke FreshRSS: %%d',
+ 'request_failed' => 'Nepodarilo sa spracovať váš dopyt, pravdepodobne kvôli problému s pripojením do internetu.',
+ 'title_new_articles' => 'FreshRSS: nové články!',
+ ),
+ 'new_article' => 'Našli sa nové články. Kliknite na obnovenie stránky.',
+ 'should_be_activated' => 'Musíte povoliť JavaScript',
+ ),
+ 'menu' => array(
+ 'about' => 'O FreshRSS',
+ 'admin' => 'Administrácia',
+ 'archiving' => 'Archivácia',
+ 'authentication' => 'Prihlásenie',
+ 'check_install' => 'Kontroloa inštalácie',
+ 'configuration' => 'Nastavenia',
+ 'display' => 'Zobrazenie',
+ 'extensions' => 'Rozšírenia',
+ 'logs' => 'Záznamy',
+ 'queries' => 'Používateľské dopyty',
+ 'reading' => 'Čítanie',
+ 'search' => 'Hľadajte slová alebo #značky',
+ 'sharing' => 'Zdieľanie',
+ 'shortcuts' => 'Skratky',
+ 'stats' => 'Štatistiky',
+ 'system' => 'Nastavenie systému',
+ 'update' => 'Aktualizácia',
+ 'user_management' => 'Spravovať používateľov',
+ 'user_profile' => 'Profil',
+ ),
+ 'pagination' => array(
+ 'first' => 'Prvý',
+ 'last' => 'Posledný',
+ 'load_more' => 'Načítať viac článkov',
+ 'mark_all_read' => 'Označiť všetko prečítané',
+ 'next' => 'Ďalší',
+ 'nothing_to_load' => 'Žiadne nové články',
+ 'previous' => 'Predošlý',
+ ),
+ 'share' => array(
+ 'blogotext' => 'Blogotext',
+ 'diaspora' => 'Diaspora*',
+ 'email' => 'E-mail',
+ 'facebook' => 'Facebook',
+ 'g+' => 'Google+',
+ 'gnusocial' => 'GNU social',
+ 'jdh' => 'Journal du hacker',
+ 'Known' => 'Stránky založené na Known',
+ 'linkedin' => 'LinkedIn',
+ 'mastodon' => 'Mastodon',
+ 'movim' => 'Movim',
+ 'pinboard' => 'Pinboard',
+ 'pocket' => 'Pocket',
+ 'print' => 'Print',
+ 'shaarli' => 'Shaarli',
+ 'twitter' => 'Twitter',
+ 'wallabag' => 'wallabag v1',
+ 'wallabagv2' => 'wallabag v2',
+ ),
+ 'short' => array(
+ 'attention' => 'Upozornenie!',
+ 'blank_to_disable' => 'Ak chcete zakázať, ponechajte prázdne',
+ 'by_author' => 'Od:',
+ 'by_default' => 'Prednastavené',
+ 'damn' => 'Sakra!',
+ 'default_category' => 'Bez kategórie',
+ 'no' => 'Nie',
+ 'not_applicable' => 'Nie je k dispozícii',
+ 'ok' => 'OK',
+ 'or' => 'alebo',
+ 'yes' => 'Áno',
+ ),
+);
diff --git a/app/i18n/sk/index.php b/app/i18n/sk/index.php
new file mode 100644
index 000000000..ae5a077b0
--- /dev/null
+++ b/app/i18n/sk/index.php
@@ -0,0 +1,66 @@
+<?php
+
+return array(
+ 'about' => array(
+ '_' => 'O FreshRSS',
+ 'agpl3' => '<a href="https://www.gnu.org/licenses/agpl-3.0.html">AGPL 3</a>',
+ 'bugs_reports' => 'Nahlásiť chybu',
+ 'credits' => 'Poďakovanie',
+ 'credits_content' => 'Niektoré časti vzhľadu pochádzajú z <a href="http://twitter.github.io/bootstrap/">Bootstrap</a>u, aj keď FreshRSS tento framework nepoužíva. <a href="https://git.gnome.org/browse/gnome-icon-theme-symbolic">Ikony</a> sú z <a href="https://www.gnome.org/">GNOME project</a>. Font <em>Open Sans</em> zabezpečil <a href="https://fonts.google.com/specimen/Open+Sans">Steve Matteson</a>. FreshRSS je založený na PHP frameworku <a href="https://github.com/marienfressinaud/MINZ">Minz</a>.',
+ 'freshrss_description' => 'FreshRSS je čítačka RSS kanálov, ktorú môžete nasadiť na vlastný server podobne ako <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> alebo <a href="https://github.com/LeedRSS/Leed">Leed</a>. Ide o jednoduchý a zároveň dobre nastaviteľný nástroj.',
+ 'github' => '<a href="https://github.com/FreshRSS/FreshRSS/issues">na Github</a>e',
+ 'license' => 'Licencia',
+ 'project_website' => 'Webová stránka projektu',
+ 'title' => 'O FreshRSS',
+ 'version' => 'Verzia',
+ 'website' => 'Webová stránka',
+ ),
+ 'tos' => array(
+ 'title' => 'Terms of Service', // TODO - Translation
+ ),
+ 'feed' => array(
+ 'add' => 'Môžete pridať kanály.',
+ 'empty' => 'Žiadne články.',
+ 'rss_of' => 'RSS kanál pre %s',
+ 'title' => 'Vaše RSS kanály',
+ 'title_global' => 'Prehľad',
+ 'title_fav' => 'Vaše obľúbené',
+ ),
+ 'log' => array(
+ '_' => 'Záznamy',
+ 'clear' => 'Vymazať záznamy',
+ 'empty' => 'Súbor záznamu je prázdny',
+ 'title' => 'Záznamy',
+ ),
+ 'menu' => array(
+ 'about' => 'O FreshRSS',
+ 'add_query' => 'Vytvoriť dopyt',
+ 'before_one_day' => 'Pred 1 dňom',
+ 'before_one_week' => 'Pred 1 týždňom',
+ 'favorites' => 'Obľúbené (%s)',
+ 'global_view' => 'Prehľad',
+ 'main_stream' => 'Všetky kanály',
+ 'mark_all_read' => 'Označiť všetko ako prečítané',
+ 'mark_cat_read' => 'Označiť kategóriu ako prečítanú',
+ 'mark_feed_read' => 'Označiť kanál ako prečítaný',
+ 'mark_selection_unread' => 'Označiť označené ako prečítané',
+ 'newer_first' => 'Novšie hore',
+ 'non-starred' => 'Zobraziť všetko okrem obľúbených',
+ 'normal_view' => 'Základné zobrazenie',
+ 'older_first' => 'Staršie hore',
+ 'queries' => 'Používateľské dopyty',
+ 'read' => 'Zobraziť prečítané',
+ 'reader_view' => 'Zobrazenie na čítanie',
+ 'rss_view' => 'RSS kanál',
+ 'search_short' => 'Hľadať',
+ 'starred' => 'Zobraziť obľúbené',
+ 'stats' => 'Štatistiky',
+ 'subscription' => 'Správca odberov',
+ 'tags' => 'Moje nálepky',
+ 'unread' => 'Zobraziť neprečítané',
+ ),
+ 'share' => 'Zdieľať',
+ 'tag' => array(
+ 'related' => 'Značky článku',
+ ),
+);
diff --git a/app/i18n/sk/install.php b/app/i18n/sk/install.php
new file mode 100644
index 000000000..08fbfeef9
--- /dev/null
+++ b/app/i18n/sk/install.php
@@ -0,0 +1,123 @@
+<?php
+
+return array(
+ 'action' => array(
+ 'finish' => 'Dokončiť inštaláciu',
+ 'fix_errors_before' => 'Prosím, pred pokračovaním opravte chyby.',
+ 'keep_install' => 'Použiť predošlé nastavenia',
+ 'next_step' => 'Ďalší krok',
+ 'reinstall' => 'Preinštalovať FreshRSS',
+ ),
+ 'auth' => array(
+ 'form' => 'Webový formulár (tradičný, vyžaduje JavaScript)',
+ 'http' => 'HTTP (pre pokročilých používateľov s HTTPS)',
+ 'none' => 'Žiadny (nebezpečné)',
+ 'password_form' => 'Heslo<br /><small>(pre prihlásenie cez webový formulár)</small>',
+ 'password_format' => 'Najmenej 7 znakov',
+ 'type' => 'Spôsob prihlásenia',
+ ),
+ 'bdd' => array(
+ '_' => 'Databáza',
+ 'conf' => array(
+ '_' => 'Nastavenia databázy',
+ 'ko' => 'Skontrolovať vaše informácie o databáze.',
+ 'ok' => 'Nastavenia databázy boli uložené.',
+ ),
+ 'host' => 'Server',
+ 'password' => 'Heslo databázy',
+ 'prefix' => 'Predpona názvu tabuľky',
+ 'type' => 'Druh databázy',
+ 'username' => 'Používateľské meno databázy',
+ ),
+ 'check' => array(
+ '_' => 'Kontrola',
+ 'already_installed' => 'Zistilo sa, že FreshRSS je už nainštalovaný!',
+ 'cache' => array(
+ 'nok' => 'Skontrolujte oprávnenia prístupu do priečinku <em>./data/cache</em>. HTTP server musí mať právo doň zapisovať.',
+ 'ok' => 'Oprávnenia prístupu do priečinku vyrovnávacej pamäte sú OK.',
+ ),
+ 'ctype' => array(
+ 'nok' => 'Nepodarilo sa nájsť požadovanú knižnicu na kontrolu typu znakov (php-ctype).',
+ 'ok' => 'Našla sa požadovaná knižnica na kontrolu typu znakov (ctype).',
+ ),
+ 'curl' => array(
+ 'nok' => 'Nepodarilo sa nájsť knižnicu cURL (balík php-curl).',
+ 'ok' => 'Našla sa knižnica cURL.',
+ ),
+ 'data' => array(
+ 'nok' => 'Skontrolujte oprávnenia prístupu do priečinku <em>./data</em>. HTTP server musí mať právo doň zapisovať.',
+ 'ok' => 'Oprávnenia prístupu do priečinku údajov sú OK.',
+ ),
+ 'dom' => array(
+ 'nok' => 'Nepodarilo sa nájsť požadovanú knižnicu na prehliadanie DOM.',
+ 'ok' => 'Našla sa požadovaná knižnica na prehliadanie DOM.',
+ ),
+ 'favicons' => array(
+ 'nok' => 'Skontrolujte oprávnenia prístupu do priečinku <em>./data/favicons</em>. HTTP server musí mať právo doň zapisovať.',
+ 'ok' => 'Oprávnenia prístupu do priečinku ikôn obľúbených sú OK.',
+ ),
+ 'fileinfo' => array(
+ 'nok' => 'Nepodarilo sa nájsť knižniuc PHP fileinfo (balík fileinfo).',
+ 'ok' => 'Našla sa knižnica fileinfo.',
+ ),
+ 'http_referer' => array(
+ 'nok' => 'Prosím, skontrolujte, či ste nezmenili váš HTTP REFERER.',
+ 'ok' => 'Váš HTTP REFERER je OK.',
+ ),
+ 'json' => array(
+ 'nok' => 'Nepodarilo sa nájsť požadovanú knižnicu na spracovanie formátu JSON.',
+ 'ok' => 'Našla sa požadovaná knižnica na spracovanie formátu JSON.',
+ ),
+ 'mbstring' => array(
+ 'nok' => 'Nepodarilo sa nájsť požadovanú knižnicu mbstring pre Unicode.',
+ 'ok' => 'Našla sa požadovaná knižnica mbstring pre Unicode.',
+ ),
+ 'minz' => array(
+ 'nok' => 'Nepodarilo sa nájsť framework Minz.',
+ 'ok' => 'Našiel sa framework Minz.',
+ ),
+ 'pcre' => array(
+ 'nok' => 'Nepodarilo sa nájsť požadovanú knižnicu pre regulárne výrazy (php-pcre).',
+ 'ok' => 'Našla sa požadovaná knižnica pre regulárne výrazy (PCRE).',
+ ),
+ 'pdo' => array(
+ 'nok' => 'Nepodarilo sa nájsť PDO alebo niektorý z podporovaných ovládačov (pdo_mysql, pdo_sqlite, pdo_pgsql).',
+ 'ok' => 'Našiel sa PDO a aspoň jeden z podporovaných ovládačov (pdo_mysql, pdo_sqlite, pdo_pgsql).',
+ ),
+ 'php' => array(
+ 'nok' => 'Vaša verzia PHP je %s, ale FreshRSS vyžaduje minimálne verziu %s.',
+ 'ok' => 'Vaša verzia PHP %s je kompatibilná s FreshRSS.',
+ ),
+ 'users' => array(
+ 'nok' => 'Skontrolujte oprávnenia prístupu do priečinku <em>./data/users</em>. HTTP server musí mať právo doň zapisovať.',
+ 'ok' => 'Oprávnenia prístupu do priečinku používateľov sú OK.',
+ ),
+ 'xml' => array(
+ 'nok' => 'Nepodarilo sa nájsť požadovanú knižnicu na spracovanie formátu XML.',
+ 'ok' => 'Našla sa požadovaná knižnica na spracovanie formátu XML.',
+ ),
+ ),
+ 'conf' => array(
+ '_' => 'Hlavné nastavenia',
+ 'ok' => 'Hlavné nastavenia boli uložené.',
+ ),
+ 'congratulations' => 'Nastavenia!',
+ 'default_user' => 'Hlavné používateľské meno <small>(najviac 16 alfanumerických znakov)</small>',
+ 'delete_articles_after' => 'Vymazať články po',
+ 'fix_errors_before' => 'Prosím, pred pokračovaním opravte chyby.',
+ 'javascript_is_better' => 'FreshRSS si užijete viac, keď povolíte JavaScript',
+ 'js' => array(
+ 'confirm_reinstall' => 'Ak budete pokračovať v preinštalovaní FreshRSS, stratíte vaše predošlé nastavenia. Naozaj chcete pokračovať?',
+ ),
+ 'language' => array(
+ '_' => 'Jazyk',
+ 'choose' => 'Vyberte jazyk pre FreshRSS',
+ 'defined' => 'Jazyk bol nastavený.',
+ ),
+ 'not_deleted' => 'Niečo sa nepodarilo. Musíte ručne zmazať súbor <em>%s</em>.',
+ 'ok' => 'Inštalácia bola úspešná.',
+ 'step' => 'krok %d',
+ 'steps' => 'Kroky',
+ 'title' => 'Inštalácia · FreshRSS',
+ 'this_is_the_end' => 'Toto je koniec',
+);
diff --git a/app/i18n/sk/sub.php b/app/i18n/sk/sub.php
new file mode 100644
index 000000000..3149c370b
--- /dev/null
+++ b/app/i18n/sk/sub.php
@@ -0,0 +1,103 @@
+<?php
+
+return array(
+ 'api' => array(
+ 'documentation' => 'Skopírujte tento odkaz a použite ho v inom programe.',
+ 'title' => 'API',
+ ),
+ 'bookmarklet' => array(
+ 'documentation' => 'Presunte toto tlačidlo do vašich záložiek, alebo kliknite pravým a zvoľte "Uložiť odkaz do záložiek". Potom kliknite na tlačidlo "Odoberať" na ktorejkoľvek stránke, ktorú chcete odoberať.',
+ 'label' => 'Odoberať',
+ 'title' => 'Záložka',
+ ),
+ 'category' => array(
+ '_' => 'Kategória',
+ 'add' => 'Pridať kategóriu',
+ 'empty' => 'Prázdna kategória',
+ 'information' => 'Informácia',
+ 'new' => 'Nová kategória',
+ 'position' => 'Display position', //TODO - Translation
+ 'position_help' => 'To control category sort order', //TODO - Translation
+ 'title' => 'Názov',
+ ),
+ 'feed' => array(
+ 'add' => 'Pridať RSS kanál',
+ 'advanced' => 'Pokročilé',
+ 'archiving' => 'Archivovanie',
+ 'auth' => array(
+ 'configuration' => 'Prihlásenie',
+ 'help' => 'Povoliť prístup do kanálov chránených cez HTTP.',
+ 'http' => 'Prihlásenie cez HTTP',
+ 'password' => 'Heslo pre HTTP',
+ 'username' => 'Používateľské meno pre HTTP',
+ ),
+ 'clear_cache' => 'Vždy vymazať vyrovnávaciu pamäť',
+ 'css_help' => 'Stiahnuť skrátenú verziu RSS kanála (pozor, vyžaduje viac času!)',
+ 'css_path' => 'Pôvodný CSS súbor článku z webovej stránky',
+ 'description' => 'Popis',
+ 'empty' => 'Tento kanál je prázdny. Overte, prosím, či je ešte spravovaný autorom.',
+ 'error' => 'Vyskytol sa problém s týmto kanálom. Overte, prosím, či kanál stále existuje, potom ho obnovte.',
+ 'filteractions' => array(
+ '_' => 'Filtrovať akcie',
+ 'help' => 'Napíšte jeden výraz hľadania na riadok.',
+ ),
+ 'information' => 'Informácia',
+ 'keep_min' => 'Minimálny počet článkov na uchovanie',
+ 'moved_category_deleted' => 'Keď vymažete kategóriu, jej kanály sa automaticky zaradia pod <em>%s</em>.',
+ 'mute' => 'stíšiť',
+ 'no_selected' => 'Nevybrali ste kanál.',
+ 'number_entries' => 'Počet článkov: %d',
+ 'priority' => array(
+ '_' => 'Viditeľnosť',
+ 'archived' => 'Nezobrazovať (archivované)',
+ 'main_stream' => 'Zobraziť v prehľade kanálov',
+ 'normal' => 'Zobraziť vo svojej kategórii',
+ ),
+ 'websub' => 'Okamžité oznámenia cez WebSub',
+ 'show' => array(
+ 'all' => 'Zobraziť všetky kanály',
+ 'error' => 'Zobraziť iba kanály s chybou',
+ ),
+ 'showing' => array(
+ 'error' => 'Zobraziť iba kanály s chybou',
+ ),
+ 'ssl_verify' => 'Overiť bezpečnosť SSL',
+ 'stats' => 'Štatistiky',
+ 'think_to_add' => 'Mali by ste pridať kanály.',
+ 'timeout' => 'Doba platnosti dá v sekundách',
+ 'title' => 'Nadpis',
+ 'title_add' => 'Pridať kanál RSS',
+ 'ttl' => 'Automaticky neaktualizovať častejšie ako',
+ 'url' => 'Odkaz kanála',
+ 'validator' => 'Skontrolovať platnosť kanála',
+ 'website' => 'Odkaz webovej stránky',
+ ),
+ 'firefox' => array(
+ 'documentation' => 'Pridajte RSS kanály do Firefoxu <a href="https://developer.mozilla.org/en-US/Firefox/Releases/2/Adding_feed_readers_to_Firefox#Adding_a_new_feed_reader_manually">pomocou tohto návodu</a>.',
+ 'obsolete_63' => 'From version 63 and onwards, Firefox has removed the ability to add your own subscription services that are not standalone programs.', //TODO - Translation
+ 'title' => 'RSS čítačka vo Firefoxe',
+ ),
+ 'import_export' => array(
+ 'export' => 'Exportovať',
+ 'export_opml' => 'Exportovať zoznam kanálov (OPML)',
+ 'export_starred' => 'Exportovať vaše obľúbené',
+ 'export_labelled' => 'Exportovať vaše označené články',
+ 'feed_list' => 'Zoznam článkov %s',
+ 'file_to_import' => 'Súbor na import<br />(OPML, JSON alebo ZIP)',
+ 'file_to_import_no_zip' => 'Súbor na import<br />(OPML alebo JSON)',
+ 'import' => 'Importovať',
+ 'starred_list' => 'Zoznam obľúbených článkov',
+ 'title' => 'Import / export',
+ ),
+ 'menu' => array(
+ 'bookmark' => 'Odoberať (záložka FreshRSS)',
+ 'import_export' => 'Import / export',
+ 'subscription_management' => 'Správa odoberaných kanálov',
+ 'subscription_tools' => 'Nástroje na odoberanie kanálov',
+ ),
+ 'title' => array(
+ '_' => 'Správa odoberaných kanálov',
+ 'feed_management' => 'Správa RSS kanálov',
+ 'subscription_tools' => 'Nástroje na odoberanie kanálov',
+ ),
+);
diff --git a/app/i18n/sk/user.php b/app/i18n/sk/user.php
new file mode 100644
index 000000000..3a8343c11
--- /dev/null
+++ b/app/i18n/sk/user.php
@@ -0,0 +1,37 @@
+<?php
+
+return array(
+ 'email' => array(
+ 'feedback' => array(
+ 'invalid' => 'The email address is invalid.', //TODO - Translation
+ 'required' => 'The email address is required.', //TODO - Translation
+ ),
+ 'validation' => array(
+ 'change_email' => 'You can change your email address <a href="%s">on the profile page</a>.', //TODO - Translation
+ 'email_sent_to' => 'We sent you an email at <strong>%s</strong>, please follow its indications to validate your address.', //TODO - Translation
+ 'feedback' => array(
+ 'email_failed' => 'We couldn’t send you an email because of a misconfiguration of the server.', //TODO - Translation
+ 'email_sent' => 'An email has been sent to your address.', //TODO - Translation
+ 'error' => 'The email address failed to be validated.', //TODO - Translation
+ 'ok' => 'The email address has been validated.', //TODO - Translation
+ 'unneccessary' => 'The email address was already validated.', //TODO - Translation
+ 'wrong_token' => 'The email address failed to be validated due to a wrong token.', //TODO - Translation
+ ),
+ 'need_to' => 'You need to validate your email address before being able to use %s.', //TODO - Translation
+ 'resend_email' => 'Resend the email', //TODO - Translation
+ 'title' => 'Email address validation', //TODO - Translation
+ ),
+ ),
+ 'tos' => array(
+ 'feedback' => array(
+ 'invalid' => 'You must accept the Terms of Service to be able to register.', // TODO - Translation
+ ),
+ ),
+ 'mailer' => array(
+ 'email_need_validation' => array(
+ 'title' => 'You need to validate your account', //TODO - Translation
+ 'welcome' => 'Welcome %s,', //TODO - Translation
+ 'body' => 'You’ve just registered on %s but you still need to validate your email. For that, just follow the link:', //TODO - Translation
+ ),
+ ),
+);
diff --git a/app/i18n/tr/admin.php b/app/i18n/tr/admin.php
index b1d6671ca..2c7d0fd6d 100644
--- a/app/i18n/tr/admin.php
+++ b/app/i18n/tr/admin.php
@@ -159,6 +159,7 @@ return array(
'system' => array(
'_' => 'Sistem yapılandırması',
'auto-update-url' => 'Otomatik güncelleme sunucu URL',
+ 'force_email_validation' => 'Force email addresses validation', //TODO - Translation
'instance-name' => 'Örnek isim',
'max-categories' => 'Kullanıcı başına kategori limiti',
'max-feeds' => 'Kullanıcı başına akış limiti',
diff --git a/app/i18n/tr/conf.php b/app/i18n/tr/conf.php
index 6c57d39da..c8ea78efa 100644
--- a/app/i18n/tr/conf.php
+++ b/app/i18n/tr/conf.php
@@ -3,13 +3,21 @@
return array(
'archiving' => array(
'_' => 'Arşiv',
- 'advanced' => 'Gelişmiş',
'delete_after' => 'Makelelerin tutulacağı süre',
+ 'exception' => 'Purge exception', //TODO - Translation
'help' => 'Akış ayarlarında daha çok ayar bulabilirsiniz',
- 'keep_history_by_feed' => 'Akışta en az tutulacak makale sayısı',
+ 'keep_favourites' => 'Never delete favourites', //TODO - Translation
+ 'keep_min_by_feed' => 'Akışta en az tutulacak makale sayısı',
+ 'keep_labels' => 'Never delete labels', //TODO - Translation
+ 'keep_unreads' => 'Never delete unreads', //TODO - Translation
+ 'maintenance' => 'Maintenance', //TODO - Translation
'optimize' => 'Veritabanı optimize et',
'optimize_help' => 'Bu işlem bazen veritabanı boyutunu düşürmeye yardımcı olur',
+ 'policy' => 'Purge policy', //TODO - Translation
+ 'policy_warning' => 'If no purge policy is selected, every article will be kept.', //TODO - Translation
'purge_now' => 'Şimdi temizle',
+ 'keep_max' => 'Maximum number of articles to keep', //TODO - Translation
+ 'keep_period' => 'Maximum age of articles to keep', //TODO - Translation
'title' => 'Arşiv',
'ttl' => 'Şu süreden sık otomatik yenileme yapma',
),
@@ -21,6 +29,7 @@ return array(
'publication_date' => 'Yayınlama Tarihi',
'related_tags' => 'İlgili etiketler', //TODO - Translation
'sharing' => 'Paylaşım',
+ 'display_authors' => 'Authors', //TODO - Translation
'top_line' => 'Üst çizgi',
),
'language' => 'Dil',
@@ -45,6 +54,7 @@ return array(
'_' => 'Hesap silme',
'warn' => 'Hesabınız ve tüm verileriniz silinecek.',
),
+ 'email' => 'Email adresleri',
'password_api' => 'API Şifresi<br /><small>(ör. mobil uygulamalar için)</small>',
'password_form' => 'Şifre<br /><small>(Tarayıcı girişi için)</small>',
'password_format' => 'En az 7 karakter',
@@ -133,7 +143,6 @@ return array(
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'more_information' => 'Daha fazla bilgi',
'print' => 'Yazdır',
'remove' => 'Remove sharing method', //TODO - Translation
diff --git a/app/i18n/tr/gen.php b/app/i18n/tr/gen.php
index a84c39f20..ccc5b9ee6 100644
--- a/app/i18n/tr/gen.php
+++ b/app/i18n/tr/gen.php
@@ -3,6 +3,7 @@
return array(
'action' => array(
'actualize' => 'Yenile',
+ 'back' => '← Go back', //TODO - Translation
'back_to_rss_feeds' => '← RSS akışlarınız için geri gidin',
'cancel' => 'İptal',
'create' => 'Oluştur',
@@ -22,6 +23,7 @@ return array(
'update' => 'Update', //TODO - Translation
),
'auth' => array(
+ 'accept_tos' => 'I accept the <a href="%s">Terms of Service</a>.', // TODO - Translation
'email' => 'Email adresleri',
'keep_logged_in' => '<small>(%s günler)</small> oturumu açık tut',
'login' => 'Giriş',
@@ -160,15 +162,22 @@ return array(
'nothing_to_load' => 'Başka makale yok',
'previous' => 'Önceki',
),
+ 'period' => array(
+ 'days' => 'days', //TODO - Translation
+ 'hours' => 'hours', //TODO - Translation
+ 'months' => 'months', //TODO - Translation
+ 'weeks' => 'weeks', //TODO - Translation
+ 'years' => 'years', //TODO - Translation
+ ),
'share' => array(
'blogotext' => 'Blogotext',
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'gnusocial' => 'GNU social',
'jdh' => 'Journal du hacker',
'Known' => 'Known based sites',
+ 'lemmy' => 'Lemmy',
'linkedin' => 'LinkedIn',
'mastodon' => 'Mastodon',
'movim' => 'Movim',
diff --git a/app/i18n/tr/index.php b/app/i18n/tr/index.php
index d6db514dd..e284d78db 100644
--- a/app/i18n/tr/index.php
+++ b/app/i18n/tr/index.php
@@ -7,7 +7,7 @@ return array(
'bugs_reports' => 'Hata raporu',
'credits' => 'Tanıtım',
'credits_content' => 'Bu frameworkü kullanmamasına rağmen FreshRSS bazı tasarım ögelerini <a href="http://twitter.github.io/bootstrap/">Bootstrap</a> dan almıştır. <a href="https://git.gnome.org/browse/gnome-icon-theme-symbolic">İkonlar</a> <a href="https://www.gnome.org/">GNOME projesinden</a> alınmıştır. <em>Open Sans</em> yazı tipi <a href="https://fonts.google.com/specimen/Open+Sans">Steve Matteson</a> tarafından oluşturulmuştur. FreshRSS bir PHP framework olan <a href="https://github.com/marienfressinaud/MINZ">Minz</a> i temel alır.',
- 'freshrss_description' => 'FreshRSS <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> veya <a href="http://leed.idleman.fr/">Leed</a> gibi kendi hostunuzda çalışan bir RSS akış toplayıcısıdır. Güçlü ve yapılandırılabilir araçlarıyla basit ve kullanımı kolay bir uygulamadır.',
+ 'freshrss_description' => 'FreshRSS <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> veya <a href="https://github.com/LeedRSS/Leed">Leed</a> gibi kendi hostunuzda çalışan bir RSS akış toplayıcısıdır. Güçlü ve yapılandırılabilir araçlarıyla basit ve kullanımı kolay bir uygulamadır.',
'github' => '<a href="https://github.com/FreshRSS/FreshRSS/issues">Github sayfası</a>',
'license' => 'Lisans',
'project_website' => 'Proje sayfası',
@@ -15,6 +15,9 @@ return array(
'version' => 'Versiyon',
'website' => 'Website',
),
+ 'tos' => array(
+ 'title' => 'Terms of Service', // TODO - Translation
+ ),
'feed' => array(
'add' => 'Akış ekleyebilirsin.',
'empty' => 'Gösterilecek makale yok.',
diff --git a/app/i18n/tr/sub.php b/app/i18n/tr/sub.php
index 858d15758..ed2a7ce76 100644
--- a/app/i18n/tr/sub.php
+++ b/app/i18n/tr/sub.php
@@ -13,9 +13,12 @@ return array(
'category' => array(
'_' => 'Kategori',
'add' => 'Kategori ekle',
+ 'archiving' => 'Arşiv',
'empty' => 'Boş kategori',
'information' => 'Bilgi',
'new' => 'Yeni kategori',
+ 'position' => 'Display position', //TODO - Translation
+ 'position_help' => 'To control category sort order', //TODO - Translation
'title' => 'Başlık',
),
'feed' => array(
@@ -40,7 +43,7 @@ return array(
'help' => 'Write one search filter per line.', //TODO - Translation
),
'information' => 'Bilgi',
- 'keep_history' => 'En az tutulacak makale sayısı',
+ 'keep_min' => 'En az tutulacak makale sayısı',
'moved_category_deleted' => 'Bir kategoriyi silerseniz, içerisindeki akışlar <em>%s</em> içerisine yerleşir.',
'mute' => 'mute', //TODO - Translation
'no_selected' => 'Hiçbir akış seçilmedi.',
@@ -72,6 +75,7 @@ return array(
),
'firefox' => array(
'documentation' => 'Follow the steps described <a href="https://developer.mozilla.org/en-US/Firefox/Releases/2/Adding_feed_readers_to_Firefox#Adding_a_new_feed_reader_manually">here</a> to add FreshRSS to Firefox feed reader list.', //TODO - Translation
+ 'obsolete_63' => 'From version 63 and onwards, Firefox has removed the ability to add your own subscription services that are not standalone programs.', //TODO - Translation
'title' => 'Firefox feed reader', //TODO - Translation
),
'import_export' => array(
diff --git a/app/i18n/tr/user.php b/app/i18n/tr/user.php
new file mode 100644
index 000000000..3a8343c11
--- /dev/null
+++ b/app/i18n/tr/user.php
@@ -0,0 +1,37 @@
+<?php
+
+return array(
+ 'email' => array(
+ 'feedback' => array(
+ 'invalid' => 'The email address is invalid.', //TODO - Translation
+ 'required' => 'The email address is required.', //TODO - Translation
+ ),
+ 'validation' => array(
+ 'change_email' => 'You can change your email address <a href="%s">on the profile page</a>.', //TODO - Translation
+ 'email_sent_to' => 'We sent you an email at <strong>%s</strong>, please follow its indications to validate your address.', //TODO - Translation
+ 'feedback' => array(
+ 'email_failed' => 'We couldn’t send you an email because of a misconfiguration of the server.', //TODO - Translation
+ 'email_sent' => 'An email has been sent to your address.', //TODO - Translation
+ 'error' => 'The email address failed to be validated.', //TODO - Translation
+ 'ok' => 'The email address has been validated.', //TODO - Translation
+ 'unneccessary' => 'The email address was already validated.', //TODO - Translation
+ 'wrong_token' => 'The email address failed to be validated due to a wrong token.', //TODO - Translation
+ ),
+ 'need_to' => 'You need to validate your email address before being able to use %s.', //TODO - Translation
+ 'resend_email' => 'Resend the email', //TODO - Translation
+ 'title' => 'Email address validation', //TODO - Translation
+ ),
+ ),
+ 'tos' => array(
+ 'feedback' => array(
+ 'invalid' => 'You must accept the Terms of Service to be able to register.', // TODO - Translation
+ ),
+ ),
+ 'mailer' => array(
+ 'email_need_validation' => array(
+ 'title' => 'You need to validate your account', //TODO - Translation
+ 'welcome' => 'Welcome %s,', //TODO - Translation
+ 'body' => 'You’ve just registered on %s but you still need to validate your email. For that, just follow the link:', //TODO - Translation
+ ),
+ ),
+);
diff --git a/app/i18n/zh-cn/admin.php b/app/i18n/zh-cn/admin.php
index 74f57b6e8..cdc8449a3 100644
--- a/app/i18n/zh-cn/admin.php
+++ b/app/i18n/zh-cn/admin.php
@@ -159,6 +159,7 @@ return array(
'system' => array(
'_' => '系统配置',
'auto-update-url' => '自动升级服务器 URL',
+ 'force_email_validation' => 'Force email addresses validation', //TODO - Translation
'instance-name' => '实例名称',
'max-categories' => '每用户分类限制',
'max-feeds' => '每用户 RSS 源限制',
diff --git a/app/i18n/zh-cn/conf.php b/app/i18n/zh-cn/conf.php
index 216e4590a..a7404bc58 100644
--- a/app/i18n/zh-cn/conf.php
+++ b/app/i18n/zh-cn/conf.php
@@ -3,13 +3,21 @@
return array(
'archiving' => array(
'_' => '存档',
- 'advanced' => '高级',
'delete_after' => '文章保留',
+ 'exception' => 'Purge exception', //TODO - Translation
'help' => '详细选项位于单独的 RSS 源设置',
- 'keep_history_by_feed' => '至少保存的文章数',
+ 'keep_favourites' => 'Never delete favourites', //TODO - Translation
+ 'keep_min_by_feed' => '至少保存的文章数',
+ 'keep_labels' => 'Never delete labels', //TODO - Translation
+ 'keep_unreads' => 'Never delete unreads', //TODO - Translation
+ 'maintenance' => 'Maintenance', //TODO - Translation
'optimize' => '优化数据库',
'optimize_help' => '偶尔执行优化可以减少数据库大小',
+ 'policy' => 'Purge policy', //TODO - Translation
+ 'policy_warning' => 'If no purge policy is selected, every article will be kept.', //TODO - Translation
'purge_now' => '立即清除',
+ 'keep_max' => 'Maximum number of articles to keep', //TODO - Translation
+ 'keep_period' => 'Maximum age of articles to keep', //TODO - Translation
'title' => '存档',
'ttl' => '最小自动更新时间',
),
@@ -21,6 +29,7 @@ return array(
'publication_date' => '更新日期',
'related_tags' => '相关标签',
'sharing' => '分享',
+ 'display_authors' => 'Authors', //TODO - Translation
'top_line' => '顶栏',
),
'language' => '语言',
@@ -45,6 +54,7 @@ return array(
'_' => '账户删除',
'warn' => '你的帐户和所有相关数据都将被删除。',
),
+ 'email' => 'Email 地址',
'password_api' => 'API 密码<br /><small>(例如,用于手机 APP)</small>',
'password_form' => '密码<br /><small>(用于 Web-form 登录方式)</small>',
'password_format' => '至少 7 个字符',
@@ -133,7 +143,6 @@ return array(
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'more_information' => '更多信息',
'print' => '打印',
'remove' => '删除分享方式',
diff --git a/app/i18n/zh-cn/gen.php b/app/i18n/zh-cn/gen.php
index 11d4efdb3..31817260e 100644
--- a/app/i18n/zh-cn/gen.php
+++ b/app/i18n/zh-cn/gen.php
@@ -3,6 +3,7 @@
return array(
'action' => array(
'actualize' => '获取',
+ 'back' => '← Go back', //TODO - Translation
'back_to_rss_feeds' => '← 返回',
'cancel' => '取消',
'create' => '创建',
@@ -22,6 +23,7 @@ return array(
'update' => '更新', //TODO - Translation
),
'auth' => array(
+ 'accept_tos' => 'I accept the <a href="%s">Terms of Service</a>.', // TODO - Translation
'email' => 'Email 地址',
'keep_logged_in' => '自动登录<small>(%s 天)</small>',
'login' => '登录',
@@ -160,15 +162,22 @@ return array(
'nothing_to_load' => '没有更多文章了',
'previous' => '上一页',
),
+ 'period' => array(
+ 'days' => 'days', //TODO - Translation
+ 'hours' => 'hours', //TODO - Translation
+ 'months' => 'months', //TODO - Translation
+ 'weeks' => 'weeks', //TODO - Translation
+ 'years' => 'years', //TODO - Translation
+ ),
'share' => array(
'blogotext' => 'Blogotext',
'diaspora' => 'Diaspora*',
'email' => 'Email',
'facebook' => 'Facebook',
- 'g+' => 'Google+',
'gnusocial' => 'GNU social',
'jdh' => 'Journal du hacker',
'Known' => '基于 Known 的站点',
+ 'lemmy' => 'Lemmy',
'linkedin' => 'LinkedIn',
'mastodon' => 'Mastodon',
'movim' => 'Movim',
diff --git a/app/i18n/zh-cn/index.php b/app/i18n/zh-cn/index.php
index 018813c3e..3e448608e 100644
--- a/app/i18n/zh-cn/index.php
+++ b/app/i18n/zh-cn/index.php
@@ -7,7 +7,7 @@ return array(
'bugs_reports' => 'Bug 报告',
'credits' => '致谢',
'credits_content' => '某些设计元素来自于 <a href="http://twitter.github.io/bootstrap/">Bootstrap</a> ,尽管 FreshRSS 并没有使用此框架。<a href="https://git.gnome.org/browse/gnome-icon-theme-symbolic">图标</a> 来自于 <a href="https://www.gnome.org/">GNOME 项目</a>。<em>Open Sans</em> 字体出自 <a href="https://fonts.google.com/specimen/Open+Sans">Steve Matteson</a> 之手。FreshRSS 基于 PHP 框架 <a href="https://github.com/marienfressinaud/MINZ">Minz</a>。',
- 'freshrss_description' => 'FreshRSS 是一个自托管的 RSS 聚合服务,类似于 <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> 或 <a href="http://leed.idleman.fr/">Leed</a>。 它不仅轻快又易用,而且强大又易于配置。',
+ 'freshrss_description' => 'FreshRSS 是一个自托管的 RSS 聚合服务,类似于 <a href="http://tontof.net/kriss/feed/">Kriss Feed</a> 或 <a href="https://github.com/LeedRSS/Leed">Leed</a>。 它不仅轻快又易用,而且强大又易于配置。',
'github' => '<a href="https://github.com/FreshRSS/FreshRSS/issues">Github Issues</a>',
'license' => '授权',
'project_website' => '项目网站',
@@ -15,6 +15,9 @@ return array(
'version' => '版本',
'website' => '网站',
),
+ 'tos' => array(
+ 'title' => 'Terms of Service', // TODO - Translation
+ ),
'feed' => array(
'add' => '你可以添加一些 RSS 源。',
'empty' => '暂时没有文章可显示。',
diff --git a/app/i18n/zh-cn/sub.php b/app/i18n/zh-cn/sub.php
index bf517756b..944d6986f 100644
--- a/app/i18n/zh-cn/sub.php
+++ b/app/i18n/zh-cn/sub.php
@@ -13,9 +13,12 @@ return array(
'category' => array(
'_' => '分类',
'add' => '添加分类',
+ 'archiving' => '存档',
'empty' => '空分类',
'information' => '信息',
'new' => '新分类',
+ 'position' => 'Display position', //TODO - Translation
+ 'position_help' => 'To control category sort order', //TODO - Translation
'title' => '标题',
),
'feed' => array(
@@ -40,7 +43,7 @@ return array(
'help' => 'Write one search filter per line.', //TODO - Translation
),
'information' => '信息',
- 'keep_history' => '至少保存的文章数',
+ 'keep_min' => '至少保存的文章数',
'moved_category_deleted' => '删除分类时,其中的 RSS 源会自动归类到 <em>%s</em>',
'mute' => '暂停',
'no_selected' => '未选择 RSS 源。',
@@ -72,6 +75,7 @@ return array(
),
'firefox' => array(
'documentation' => '按照 <a href="https://developer.mozilla.org/en-US/Firefox/Releases/2/Adding_feed_readers_to_Firefox#Adding_a_new_feed_reader_manually">这里</a> 描述的步骤可将 FreshRSS 添加到 Firefox 阅读器列表',
+ 'obsolete_63' => 'From version 63 and onwards, Firefox has removed the ability to add your own subscription services that are not standalone programs.', //TODO - Translation
'title' => 'Firefox RSS 阅读器',
),
'import_export' => array(
diff --git a/app/i18n/zh-cn/user.php b/app/i18n/zh-cn/user.php
new file mode 100644
index 000000000..3a8343c11
--- /dev/null
+++ b/app/i18n/zh-cn/user.php
@@ -0,0 +1,37 @@
+<?php
+
+return array(
+ 'email' => array(
+ 'feedback' => array(
+ 'invalid' => 'The email address is invalid.', //TODO - Translation
+ 'required' => 'The email address is required.', //TODO - Translation
+ ),
+ 'validation' => array(
+ 'change_email' => 'You can change your email address <a href="%s">on the profile page</a>.', //TODO - Translation
+ 'email_sent_to' => 'We sent you an email at <strong>%s</strong>, please follow its indications to validate your address.', //TODO - Translation
+ 'feedback' => array(
+ 'email_failed' => 'We couldn’t send you an email because of a misconfiguration of the server.', //TODO - Translation
+ 'email_sent' => 'An email has been sent to your address.', //TODO - Translation
+ 'error' => 'The email address failed to be validated.', //TODO - Translation
+ 'ok' => 'The email address has been validated.', //TODO - Translation
+ 'unneccessary' => 'The email address was already validated.', //TODO - Translation
+ 'wrong_token' => 'The email address failed to be validated due to a wrong token.', //TODO - Translation
+ ),
+ 'need_to' => 'You need to validate your email address before being able to use %s.', //TODO - Translation
+ 'resend_email' => 'Resend the email', //TODO - Translation
+ 'title' => 'Email address validation', //TODO - Translation
+ ),
+ ),
+ 'tos' => array(
+ 'feedback' => array(
+ 'invalid' => 'You must accept the Terms of Service to be able to register.', // TODO - Translation
+ ),
+ ),
+ 'mailer' => array(
+ 'email_need_validation' => array(
+ 'title' => 'You need to validate your account', //TODO - Translation
+ 'welcome' => 'Welcome %s,', //TODO - Translation
+ 'body' => 'You’ve just registered on %s but you still need to validate your email. For that, just follow the link:', //TODO - Translation
+ ),
+ ),
+);
diff --git a/app/install.php b/app/install.php
index 961a7c171..96bee34a1 100644
--- a/app/install.php
+++ b/app/install.php
@@ -17,24 +17,10 @@ if (isset($_GET['step'])) {
define('STEP', 0);
}
-if (STEP === 3 && isset($_POST['type'])) {
+if (STEP === 2 && isset($_POST['type'])) {
$_SESSION['bd_type'] = $_POST['type'];
}
-if (isset($_SESSION['bd_type'])) {
- switch ($_SESSION['bd_type']) {
- case 'mysql':
- include_once(APP_PATH . '/SQL/install.sql.mysql.php');
- break;
- case 'sqlite':
- include_once(APP_PATH . '/SQL/install.sql.sqlite.php');
- break;
- case 'pgsql':
- include_once(APP_PATH . '/SQL/install.sql.pgsql.php');
- break;
- }
-}
-
function param($key, $default = false) {
if (isset($_POST[$key])) {
return $_POST[$key];
@@ -43,7 +29,6 @@ function param($key, $default = false) {
}
}
-
// gestion internationalisation
function initTranslate() {
Minz_Translate::init();
@@ -61,7 +46,7 @@ function initTranslate() {
}
function get_best_language() {
- $accept = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
+ $accept = empty($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? '' : $_SERVER['HTTP_ACCEPT_LANGUAGE'];
return strtolower(substr($accept, 0, 2));
}
@@ -101,7 +86,6 @@ function saveStep1() {
// Then, we set $_SESSION vars
$_SESSION['title'] = $system_conf->title;
$_SESSION['auth_type'] = $system_conf->auth_type;
- $_SESSION['old_entries'] = $user_conf->old_entries;
$_SESSION['default_user'] = $current_user;
$_SESSION['passwordHash'] = $user_conf->passwordHash;
@@ -119,68 +103,13 @@ function saveStep1() {
}
function saveStep2() {
- $user_default_config = Minz_Configuration::get('default_user');
- if (!empty($_POST)) {
- $system_default_config = Minz_Configuration::get('default_system');
- $_SESSION['title'] = $system_default_config->title;
- $_SESSION['old_entries'] = param('old_entries', $user_default_config->old_entries);
- $_SESSION['auth_type'] = param('auth_type', 'form');
- if (FreshRSS_user_Controller::checkUsername(param('default_user', ''))) {
- $_SESSION['default_user'] = param('default_user', '');
- }
-
- $password_plain = param('passwordPlain', false);
- if ($password_plain !== false && cryptAvailable()) {
- $_SESSION['passwordHash'] = FreshRSS_user_Controller::hashPassword($password_plain);
- }
-
- if (empty($_SESSION['old_entries']) ||
- empty($_SESSION['auth_type']) ||
- empty($_SESSION['default_user'])) {
- return false;
- }
-
- if ($_SESSION['auth_type'] === 'form' && empty($_SESSION['passwordHash'])) {
- return false;
- }
-
- $_SESSION['salt'] = generateSalt();
- if ((!ctype_digit($_SESSION['old_entries'])) ||($_SESSION['old_entries'] < 1)) {
- $_SESSION['old_entries'] = $user_default_config->old_entries;
- }
-
- $token = '';
-
- $config_array = array(
- 'language' => $_SESSION['language'],
- 'theme' => $user_default_config->theme,
- 'old_entries' => $_SESSION['old_entries'],
- 'passwordHash' => $_SESSION['passwordHash'],
- 'token' => $token,
- );
-
- // Create default user files but first, we delete previous data to
- // avoid access right problems.
- $user_dir = join_path(USERS_PATH, $_SESSION['default_user']);
- $user_config_path = join_path($user_dir, 'config.php');
-
- recursive_unlink($user_dir);
- mkdir($user_dir);
- file_put_contents($user_config_path, "<?php\n return " . var_export($config_array, true) . ";\n");
-
- header('Location: index.php?step=3');
- }
-}
-
-function saveStep3() {
if (!empty($_POST)) {
if ($_SESSION['bd_type'] === 'sqlite') {
- $_SESSION['bd_base'] = $_SESSION['default_user'];
+ $_SESSION['bd_base'] = '';
$_SESSION['bd_host'] = '';
$_SESSION['bd_user'] = '';
$_SESSION['bd_password'] = '';
$_SESSION['bd_prefix'] = '';
- $_SESSION['bd_prefix_user'] = ''; //No prefix for SQLite
} else {
if (empty($_POST['type']) ||
empty($_POST['host']) ||
@@ -193,7 +122,6 @@ function saveStep3() {
$_SESSION['bd_user'] = $_POST['user'];
$_SESSION['bd_password'] = $_POST['pass'];
$_SESSION['bd_prefix'] = substr($_POST['prefix'], 0, 16);
- $_SESSION['bd_prefix_user'] = $_SESSION['bd_prefix'] . (empty($_SESSION['default_user']) ? '' : ($_SESSION['default_user'] . '_'));
}
if ($_SESSION['bd_type'] === 'pgsql') {
$_SESSION['bd_base'] = strtolower($_SESSION['bd_base']);
@@ -201,44 +129,108 @@ function saveStep3() {
// We use dirname to remove the /i part
$base_url = dirname(Minz_Request::guessBaseUrl());
- $config_array = array(
- 'salt' => $_SESSION['salt'],
+ $config_array = [
+ 'salt' => generateSalt(),
'base_url' => $base_url,
- 'title' => $_SESSION['title'],
- 'default_user' => $_SESSION['default_user'],
- 'auth_type' => $_SESSION['auth_type'],
- 'db' => array(
+ 'default_user' => 'admin',
+ 'db' => [
'type' => $_SESSION['bd_type'],
'host' => $_SESSION['bd_host'],
'user' => $_SESSION['bd_user'],
'password' => $_SESSION['bd_password'],
'base' => $_SESSION['bd_base'],
'prefix' => $_SESSION['bd_prefix'],
- 'pdo_options' => array(),
- ),
+ 'pdo_options' => [],
+ ],
'pubsubhubbub_enabled' => server_is_public($base_url),
- );
+ ];
+ if (!empty($_SESSION['title'])) {
+ $config_array['title'] = $_SESSION['title'];
+ }
+ if (!empty($_SESSION['auth_type'])) {
+ $config_array['auth_type'] = $_SESSION['auth_type'];
+ }
+
+ @unlink(DATA_PATH . '/config.php'); //To avoid access-rights problems
+ file_put_contents(DATA_PATH . '/config.php', "<?php\n return " . var_export($config_array, true) . ";\n");
- @unlink(join_path(DATA_PATH, 'config.php')); //To avoid access-rights problems
- file_put_contents(join_path(DATA_PATH, 'config.php'), "<?php\n return " . var_export($config_array, true) . ";\n");
+ Minz_Configuration::register('system', DATA_PATH . '/config.php', FRESHRSS_PATH . '/config.default.php');
+ FreshRSS_Context::$system_conf = Minz_Configuration::get('system');
- $config_array['db']['default_user'] = $config_array['default_user'];
- $config_array['db']['prefix_user'] = $_SESSION['bd_prefix_user'];
- $ok = checkDb($config_array['db']) && checkDbUser($config_array['db']);
+ $ok = false;
+ try {
+ $ok = checkDb();
+ } catch (Exception $ex) {
+ $_SESSION['bd_error'] = $ex->getMessage();
+ $ok = false;
+ }
if (!$ok) {
@unlink(join_path(DATA_PATH, 'config.php'));
}
if ($ok) {
$_SESSION['bd_error'] = '';
- header('Location: index.php?step=4');
- } else {
- $_SESSION['bd_error'] = empty($config_array['db']['error']) ? 'Unknown error!' : $config_array['db']['error'];
+ header('Location: index.php?step=3');
+ } elseif (empty($_SESSION['bd_error'])) {
+ $_SESSION['bd_error'] = 'Unknown error!';
}
}
invalidateHttpCache();
}
+function saveStep3() {
+ $user_default_config = Minz_Configuration::get('default_user');
+ if (!empty($_POST)) {
+ $system_default_config = Minz_Configuration::get('default_system');
+ $_SESSION['title'] = $system_default_config->title;
+ $_SESSION['auth_type'] = param('auth_type', 'form');
+ if (FreshRSS_user_Controller::checkUsername(param('default_user', ''))) {
+ $_SESSION['default_user'] = param('default_user', '');
+ }
+
+ if (empty($_SESSION['auth_type']) ||
+ empty($_SESSION['default_user'])) {
+ return false;
+ }
+
+ $password_plain = param('passwordPlain', false);
+ if ($_SESSION['auth_type'] === 'form' && $password_plain == '') {
+ return false;
+ }
+
+ Minz_Configuration::register('system', DATA_PATH . '/config.php', FRESHRSS_PATH . '/config.default.php');
+ FreshRSS_Context::$system_conf = Minz_Configuration::get('system');
+ Minz_Translate::init($_SESSION['language']);
+
+ FreshRSS_Context::$system_conf->default_user = $_SESSION['default_user'];
+ FreshRSS_Context::$system_conf->save();
+
+ // Create default user files but first, we delete previous data to
+ // avoid access right problems.
+ recursive_unlink(USERS_PATH . '/' . $_SESSION['default_user']);
+
+ $ok = false;
+ try {
+ $ok = FreshRSS_user_Controller::createUser(
+ $_SESSION['default_user'],
+ '', //TODO: Add e-mail
+ $password_plain,
+ '',
+ [
+ 'language' => $_SESSION['language'],
+ ]
+ );
+ } catch (Exception $e) {
+ $_SESSION['bd_error'] = $e->getMessage();
+ $ok = false;
+ }
+ if (!$ok) {
+ return false;
+ }
+
+ header('Location: index.php?step=4');
+ }
+}
/*** VÉRIFICATIONS ***/
function checkStep() {
@@ -297,29 +289,6 @@ function freshrss_already_installed() {
}
function checkStep2() {
- $conf = !empty($_SESSION['old_entries']) &&
- !empty($_SESSION['default_user']);
-
- $form = (
- isset($_SESSION['auth_type']) &&
- ($_SESSION['auth_type'] != 'form' || !empty($_SESSION['passwordHash']))
- );
-
- $defaultUser = empty($_POST['default_user']) ? null : $_POST['default_user'];
- if ($defaultUser === null) {
- $defaultUser = empty($_SESSION['default_user']) ? '' : $_SESSION['default_user'];
- }
- $data = is_writable(join_path(USERS_PATH, $defaultUser, 'config.php'));
-
- return array(
- 'conf' => $conf ? 'ok' : 'ko',
- 'form' => $form ? 'ok' : 'ko',
- 'data' => $data ? 'ok' : 'ko',
- 'all' => $conf && $form && $data ? 'ok' : 'ko'
- );
-}
-
-function checkStep3() {
$conf = is_writable(join_path(DATA_PATH, 'config.php'));
$bd = isset($_SESSION['bd_type']) &&
@@ -331,60 +300,52 @@ function checkStep3() {
isset($_SESSION['bd_error']);
$conn = empty($_SESSION['bd_error']);
- return array(
+ return [
'bd' => $bd ? 'ok' : 'ko',
'conn' => $conn ? 'ok' : 'ko',
'conf' => $conf ? 'ok' : 'ko',
- 'all' => $bd && $conn && $conf ? 'ok' : 'ko'
- );
+ 'all' => $bd && $conn && $conf ? 'ok' : 'ko',
+ ];
}
-function checkDbUser(&$dbOptions) {
- $ok = false;
- $str = $dbOptions['dsn'];
- $driver_options = $dbOptions['options'];
- try {
- $c = new PDO($str, $dbOptions['user'], $dbOptions['password'], $driver_options);
- if (defined('SQL_CREATE_TABLES')) {
- $sql = sprintf(SQL_CREATE_TABLES . SQL_CREATE_TABLE_ENTRYTMP . SQL_CREATE_TABLE_TAGS . SQL_INSERT_FEEDS,
- $dbOptions['prefix_user'], _t('gen.short.default_category'));
- $stm = $c->prepare($sql);
- $ok = $stm && $stm->execute();
- } else {
- global $SQL_CREATE_TABLES, $SQL_CREATE_TABLE_ENTRYTMP, $SQL_CREATE_TABLE_TAGS, $SQL_INSERT_FEEDS;
- $instructions = array_merge($SQL_CREATE_TABLES, $SQL_CREATE_TABLE_ENTRYTMP, $SQL_CREATE_TABLE_TAGS, $SQL_INSERT_FEEDS);
- $ok = !empty($instructions);
- foreach ($instructions as $instruction) {
- $sql = sprintf($instruction, $dbOptions['prefix_user'], _t('gen.short.default_category'));
- $stm = $c->prepare($sql);
- $ok &= $stm && $stm->execute();
- }
- }
- } catch (PDOException $e) {
- $ok = false;
- $dbOptions['error'] = $e->getMessage();
+function checkStep3() {
+ $conf = !empty($_SESSION['default_user']);
+
+ $form = isset($_SESSION['auth_type']);
+
+ $defaultUser = empty($_POST['default_user']) ? null : $_POST['default_user'];
+ if ($defaultUser === null) {
+ $defaultUser = empty($_SESSION['default_user']) ? '' : $_SESSION['default_user'];
}
- return $ok;
+ $data = is_writable(join_path(USERS_PATH, $defaultUser, 'config.php'));
+
+ return [
+ 'conf' => $conf ? 'ok' : 'ko',
+ 'form' => $form ? 'ok' : 'ko',
+ 'data' => $data ? 'ok' : 'ko',
+ 'all' => $conf && $form && $data ? 'ok' : 'ko',
+ ];
}
+
/*** AFFICHAGE ***/
function printStep0() {
$actual = Minz_Translate::language();
$languages = Minz_Translate::availableLanguages();
?>
<?php $s0 = checkStep0(); if ($s0['all'] == 'ok') { ?>
- <p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.language.defined'); ?></p>
+ <p class="alert alert-success"><span class="alert-head"><?= _t('gen.short.ok') ?></span> <?= _t('install.language.defined') ?></p>
<?php } ?>
<form action="index.php?step=0" method="post">
- <legend><?php echo _t('install.language.choose'); ?></legend>
+ <legend><?= _t('install.language.choose') ?></legend>
<div class="form-group">
- <label class="group-name" for="language"><?php echo _t('install.language'); ?></label>
+ <label class="group-name" for="language"><?= _t('install.language') ?></label>
<div class="group-controls">
<select name="language" id="language" tabindex="1" >
<?php foreach ($languages as $lang) { ?>
- <option value="<?php echo $lang; ?>"<?php echo $actual == $lang ? ' selected="selected"' : ''; ?>>
- <?php echo _t('gen.lang.' . $lang); ?>
+ <option value="<?= $lang ?>"<?= $actual == $lang ? ' selected="selected"' : '' ?>>
+ <?= _t('gen.lang.' . $lang) ?>
</option>
<?php } ?>
</select>
@@ -393,10 +354,10 @@ function printStep0() {
<div class="form-group form-actions">
<div class="group-controls">
- <button type="submit" class="btn btn-important" tabindex="2" ><?php echo _t('gen.action.submit'); ?></button>
- <button type="reset" class="btn" tabindex="3" ><?php echo _t('gen.action.cancel'); ?></button>
+ <button type="submit" class="btn btn-important" tabindex="2" ><?= _t('gen.action.submit') ?></button>
+ <button type="reset" class="btn" tabindex="3" ><?= _t('gen.action.cancel') ?></button>
<?php if ($s0['all'] == 'ok') { ?>
- <a class="btn btn-important next-step" href="?step=1" tabindex="4" ><?php echo _t('install.action.next_step'); ?></a>
+ <a class="btn btn-important next-step" href="?step=1" tabindex="4" ><?= _t('install.action.next_step') ?></a>
<?php } ?>
</div>
</div>
@@ -408,203 +369,135 @@ function printStep0() {
function printStep1() {
$res = checkRequirements();
?>
- <noscript><p class="alert alert-warn"><span class="alert-head"><?php echo _t('gen.short.attention'); ?></span> <?php echo _t('install.javascript_is_better'); ?></p></noscript>
+ <noscript><p class="alert alert-warn"><span class="alert-head"><?= _t('gen.short.attention') ?></span> <?= _t('install.javascript_is_better') ?></p></noscript>
<?php if ($res['php'] == 'ok') { ?>
- <p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.check.php.ok', PHP_VERSION); ?></p>
+ <p class="alert alert-success"><span class="alert-head"><?= _t('gen.short.ok') ?></span> <?= _t('install.check.php.ok', PHP_VERSION) ?></p>
<?php } else { ?>
- <p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.php.nok', PHP_VERSION, '5.3.8'); ?></p>
+ <p class="alert alert-error"><span class="alert-head"><?= _t('gen.short.damn') ?></span> <?= _t('install.check.php.nok', PHP_VERSION, '5.6.0') ?></p>
<?php } ?>
<?php if ($res['minz'] == 'ok') { ?>
- <p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.check.minz.ok'); ?></p>
+ <p class="alert alert-success"><span class="alert-head"><?= _t('gen.short.ok') ?></span> <?= _t('install.check.minz.ok') ?></p>
<?php } else { ?>
- <p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.minz.nok', join_path(LIB_PATH, 'Minz')); ?></p>
+ <p class="alert alert-error"><span class="alert-head"><?= _t('gen.short.damn') ?></span> <?= _t('install.check.minz.nok', join_path(LIB_PATH, 'Minz')) ?></p>
<?php } ?>
<?php if ($res['pdo'] == 'ok') { ?>
- <p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.check.pdo.ok'); ?></p>
+ <p class="alert alert-success"><span class="alert-head"><?= _t('gen.short.ok') ?></span> <?= _t('install.check.pdo.ok') ?></p>
<?php } else { ?>
- <p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.pdo.nok'); ?></p>
+ <p class="alert alert-error"><span class="alert-head"><?= _t('gen.short.damn') ?></span> <?= _t('install.check.pdo.nok') ?></p>
<?php } ?>
<?php if ($res['curl'] == 'ok') { ?>
<?php $version = curl_version(); ?>
- <p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.check.curl.ok', $version['version']); ?></p>
+ <p class="alert alert-success"><span class="alert-head"><?= _t('gen.short.ok') ?></span> <?= _t('install.check.curl.ok', $version['version']) ?></p>
<?php } else { ?>
- <p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.curl.nok'); ?></p>
+ <p class="alert alert-error"><span class="alert-head"><?= _t('gen.short.damn') ?></span> <?= _t('install.check.curl.nok') ?></p>
<?php } ?>
<?php if ($res['json'] == 'ok') { ?>
- <p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.check.json.ok'); ?></p>
+ <p class="alert alert-success"><span class="alert-head"><?= _t('gen.short.ok') ?></span> <?= _t('install.check.json.ok') ?></p>
<?php } else { ?>
- <p class="alert alert-warn"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.json.nok'); ?></p>
+ <p class="alert alert-error"><span class="alert-head"><?= _t('gen.short.damn') ?></span> <?= _t('install.check.json.nok') ?></p>
<?php } ?>
<?php if ($res['pcre'] == 'ok') { ?>
- <p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.check.pcre.ok'); ?></p>
+ <p class="alert alert-success"><span class="alert-head"><?= _t('gen.short.ok') ?></span> <?= _t('install.check.pcre.ok') ?></p>
<?php } else { ?>
- <p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.pcre.nok'); ?></p>
+ <p class="alert alert-error"><span class="alert-head"><?= _t('gen.short.damn') ?></span> <?= _t('install.check.pcre.nok') ?></p>
<?php } ?>
<?php if ($res['ctype'] == 'ok') { ?>
- <p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.check.ctype.ok'); ?></p>
+ <p class="alert alert-success"><span class="alert-head"><?= _t('gen.short.ok') ?></span> <?= _t('install.check.ctype.ok') ?></p>
<?php } else { ?>
- <p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.ctype.nok'); ?></p>
+ <p class="alert alert-error"><span class="alert-head"><?= _t('gen.short.damn') ?></span> <?= _t('install.check.ctype.nok') ?></p>
<?php } ?>
<?php if ($res['dom'] == 'ok') { ?>
- <p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.check.dom.ok'); ?></p>
+ <p class="alert alert-success"><span class="alert-head"><?= _t('gen.short.ok') ?></span> <?= _t('install.check.dom.ok') ?></p>
<?php } else { ?>
- <p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.dom.nok'); ?></p>
+ <p class="alert alert-error"><span class="alert-head"><?= _t('gen.short.damn') ?></span> <?= _t('install.check.dom.nok') ?></p>
<?php } ?>
<?php if ($res['xml'] == 'ok') { ?>
- <p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.check.xml.ok'); ?></p>
+ <p class="alert alert-success"><span class="alert-head"><?= _t('gen.short.ok') ?></span> <?= _t('install.check.xml.ok') ?></p>
<?php } else { ?>
- <p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.xml.nok'); ?></p>
+ <p class="alert alert-error"><span class="alert-head"><?= _t('gen.short.damn') ?></span> <?= _t('install.check.xml.nok') ?></p>
<?php } ?>
<?php if ($res['mbstring'] == 'ok') { ?>
- <p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.check.mbstring.ok'); ?></p>
+ <p class="alert alert-success"><span class="alert-head"><?= _t('gen.short.ok') ?></span> <?= _t('install.check.mbstring.ok') ?></p>
<?php } else { ?>
- <p class="alert alert-warn"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.mbstring.nok'); ?></p>
+ <p class="alert alert-warn"><span class="alert-head"><?= _t('gen.short.damn') ?></span> <?= _t('install.check.mbstring.nok') ?></p>
<?php } ?>
<?php if ($res['fileinfo'] == 'ok') { ?>
- <p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.check.fileinfo.ok'); ?></p>
+ <p class="alert alert-success"><span class="alert-head"><?= _t('gen.short.ok') ?></span> <?= _t('install.check.fileinfo.ok') ?></p>
<?php } else { ?>
- <p class="alert alert-warn"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.fileinfo.nok'); ?></p>
+ <p class="alert alert-warn"><span class="alert-head"><?= _t('gen.short.damn') ?></span> <?= _t('install.check.fileinfo.nok') ?></p>
<?php } ?>
<?php if ($res['data'] == 'ok') { ?>
- <p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.check.data.ok'); ?></p>
+ <p class="alert alert-success"><span class="alert-head"><?= _t('gen.short.ok') ?></span> <?= _t('install.check.data.ok') ?></p>
<?php } else { ?>
- <p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.data.nok', DATA_PATH); ?></p>
+ <p class="alert alert-error"><span class="alert-head"><?= _t('gen.short.damn') ?></span> <?= _t('install.check.data.nok', DATA_PATH) ?></p>
<?php } ?>
<?php if ($res['cache'] == 'ok') { ?>
- <p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.check.cache.ok'); ?></p>
+ <p class="alert alert-success"><span class="alert-head"><?= _t('gen.short.ok') ?></span> <?= _t('install.check.cache.ok') ?></p>
<?php } else { ?>
- <p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.cache.nok', CACHE_PATH); ?></p>
+ <p class="alert alert-error"><span class="alert-head"><?= _t('gen.short.damn') ?></span> <?= _t('install.check.cache.nok', CACHE_PATH) ?></p>
<?php } ?>
<?php if ($res['users'] == 'ok') { ?>
- <p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.check.users.ok'); ?></p>
+ <p class="alert alert-success"><span class="alert-head"><?= _t('gen.short.ok') ?></span> <?= _t('install.check.users.ok') ?></p>
<?php } else { ?>
- <p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.users.nok', USERS_PATH); ?></p>
+ <p class="alert alert-error"><span class="alert-head"><?= _t('gen.short.damn') ?></span> <?= _t('install.check.users.nok', USERS_PATH) ?></p>
<?php } ?>
<?php if ($res['favicons'] == 'ok') { ?>
- <p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.check.favicons.ok'); ?></p>
+ <p class="alert alert-success"><span class="alert-head"><?= _t('gen.short.ok') ?></span> <?= _t('install.check.favicons.ok') ?></p>
<?php } else { ?>
- <p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.favicons.nok', DATA_PATH . '/favicons'); ?></p>
+ <p class="alert alert-error"><span class="alert-head"><?= _t('gen.short.damn') ?></span> <?= _t('install.check.favicons.nok', DATA_PATH . '/favicons') ?></p>
<?php } ?>
<?php if ($res['http_referer'] == 'ok') { ?>
- <p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.check.http_referer.ok'); ?></p>
+ <p class="alert alert-success"><span class="alert-head"><?= _t('gen.short.ok') ?></span> <?= _t('install.check.http_referer.ok') ?></p>
<?php } else { ?>
- <p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.check.http_referer.nok'); ?></p>
+ <p class="alert alert-error"><span class="alert-head"><?= _t('gen.short.damn') ?></span> <?= _t('install.check.http_referer.nok') ?></p>
<?php } ?>
<?php if (freshrss_already_installed() && $res['all'] == 'ok') { ?>
- <p class="alert alert-warn"><span class="alert-head"><?php echo _t('gen.short.attention'); ?></span> <?php echo _t('install.check.already_installed'); ?></p>
+ <p class="alert alert-warn"><span class="alert-head"><?= _t('gen.short.attention') ?></span> <?= _t('install.check.already_installed') ?></p>
<form action="index.php?step=1" method="post">
<input type="hidden" name="freshrss-keep-install" value="1" />
- <button type="submit" class="btn btn-important next-step" tabindex="1" ><?php echo _t('install.action.keep_install'); ?></button>
- <a class="btn btn-attention next-step confirm" data-str-confirm="<?php echo _t('install.js.confirm_reinstall'); ?>" href="?step=2" tabindex="2" ><?php echo _t('install.action.reinstall'); ?></a>
+ <button type="submit" class="btn btn-important next-step" tabindex="1" ><?= _t('install.action.keep_install') ?></button>
+ <a class="btn btn-attention next-step confirm" data-str-confirm="<?= _t('install.js.confirm_reinstall') ?>" href="?step=2" tabindex="2" ><?= _t('install.action.reinstall') ?></a>
</form>
<?php } elseif ($res['all'] == 'ok') { ?>
- <a class="btn btn-important next-step" href="?step=2" tabindex="1" ><?php echo _t('install.action.next_step'); ?></a>
+ <a class="btn btn-important next-step" href="?step=2" tabindex="1" ><?= _t('install.action.next_step') ?></a>
<?php } else { ?>
- <p class="alert alert-error"><?php echo _t('install.action.fix_errors_before'); ?></p>
+ <p class="alert alert-error"><?= _t('install.action.fix_errors_before') ?></p>
<?php } ?>
<?php
}
function printStep2() {
- $user_default_config = Minz_Configuration::get('default_user');
-?>
- <?php $s2 = checkStep2(); if ($s2['all'] == 'ok') { ?>
- <p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.conf.ok'); ?></p>
- <?php } elseif (!empty($_POST)) { ?>
- <p class="alert alert-error"><?php echo _t('install.fix_errors_before'); ?></p>
- <?php } ?>
-
- <form action="index.php?step=2" method="post">
- <legend><?php echo _t('install.conf'); ?></legend>
-
- <div class="form-group">
- <label class="group-name" for="old_entries"><?php echo _t('install.delete_articles_after'); ?></label>
- <div class="group-controls">
- <input type="number" id="old_entries" name="old_entries" required="required" min="1" max="1200" value="<?php echo isset($_SESSION['old_entries']) ? $_SESSION['old_entries'] : $user_default_config->old_entries; ?>" tabindex="2" /> <?php echo _t('gen.date.month'); ?>
- </div>
- </div>
-
- <div class="form-group">
- <label class="group-name" for="default_user"><?php echo _t('install.default_user'); ?></label>
- <div class="group-controls">
- <input type="text" id="default_user" name="default_user" autocomplete="username" required="required" size="16" pattern="<?php echo FreshRSS_user_Controller::USERNAME_PATTERN; ?>" value="<?php echo isset($_SESSION['default_user']) ? $_SESSION['default_user'] : ''; ?>" placeholder="<?php echo httpAuthUser() == '' ? 'alice' : httpAuthUser(); ?>" tabindex="3" />
- </div>
- </div>
-
- <div class="form-group">
- <label class="group-name" for="auth_type"><?php echo _t('install.auth.type'); ?></label>
- <div class="group-controls">
- <select id="auth_type" name="auth_type" required="required" tabindex="4">
- <?php
- function no_auth($auth_type) {
- return !in_array($auth_type, array('form', 'http_auth', 'none'));
- }
- $auth_type = isset($_SESSION['auth_type']) ? $_SESSION['auth_type'] : '';
- ?>
- <option value="form"<?php echo $auth_type === 'form' || (no_auth($auth_type) && cryptAvailable()) ? ' selected="selected"' : '', cryptAvailable() ? '' : ' disabled="disabled"'; ?>><?php echo _t('install.auth.form'); ?></option>
- <option value="http_auth"<?php echo $auth_type === 'http_auth' ? ' selected="selected"' : '', httpAuthUser() == '' ? ' disabled="disabled"' : ''; ?>><?php echo _t('install.auth.http'); ?>(REMOTE_USER = '<?php echo httpAuthUser(); ?>')</option>
- <option value="none"<?php echo $auth_type === 'none' || (no_auth($auth_type) && !cryptAvailable()) ? ' selected="selected"' : ''; ?>><?php echo _t('install.auth.none'); ?></option>
- </select>
- </div>
- </div>
-
- <div class="form-group">
- <label class="group-name" for="passwordPlain"><?php echo _t('install.auth.password_form'); ?></label>
- <div class="group-controls">
- <div class="stick">
- <input type="password" id="passwordPlain" name="passwordPlain" pattern=".{7,}" autocomplete="off" <?php echo $auth_type === 'form' ? ' required="required"' : ''; ?> tabindex="5" />
- <a class="btn toggle-password" data-toggle="passwordPlain"><?php echo FreshRSS_Themes::icon('key'); ?></a>
- </div>
- <?php echo _i('help'); ?> <?php echo _t('install.auth.password_format'); ?>
- <noscript><b><?php echo _t('gen.js.should_be_activated'); ?></b></noscript>
- </div>
- </div>
-
- <div class="form-group form-actions">
- <div class="group-controls">
- <button type="submit" class="btn btn-important" tabindex="7" ><?php echo _t('gen.action.submit'); ?></button>
- <button type="reset" class="btn" tabindex="8" ><?php echo _t('gen.action.cancel'); ?></button>
- <?php if ($s2['all'] == 'ok') { ?>
- <a class="btn btn-important next-step" href="?step=3" tabindex="9" ><?php echo _t('install.action.next_step'); ?></a>
- <?php } ?>
- </div>
- </div>
- </form>
-<?php
-}
-
-function printStep3() {
$system_default_config = Minz_Configuration::get('default_system');
?>
- <?php $s3 = checkStep3(); if ($s3['all'] == 'ok') { ?>
- <p class="alert alert-success"><span class="alert-head"><?php echo _t('gen.short.ok'); ?></span> <?php echo _t('install.bdd.conf.ok'); ?></p>
- <?php } elseif ($s3['conn'] == 'ko') { ?>
- <p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.bdd.conf.ko'),(empty($_SESSION['bd_error']) ? '' : ' : ' . $_SESSION['bd_error']); ?></p>
+ <?php $s2 = checkStep2(); if ($s2['all'] == 'ok') { ?>
+ <p class="alert alert-success"><span class="alert-head"><?= _t('gen.short.ok') ?></span> <?= _t('install.bdd.conf.ok') ?></p>
+ <?php } elseif ($s2['conn'] == 'ko') { ?>
+ <p class="alert alert-error"><span class="alert-head"><?= _t('gen.short.damn') ?></span> <?= _t('install.bdd.conf.ko'),(empty($_SESSION['bd_error']) ? '' : ' : ' . $_SESSION['bd_error']) ?></p>
<?php } ?>
- <form action="index.php?step=3" method="post" autocomplete="off">
- <legend><?php echo _t('install.bdd.conf'); ?></legend>
+ <form action="index.php?step=2" method="post" autocomplete="off">
+ <legend><?= _t('install.bdd.conf') ?></legend>
<div class="form-group">
- <label class="group-name" for="type"><?php echo _t('install.bdd.type'); ?></label>
+ <label class="group-name" for="type"><?= _t('install.bdd.type') ?></label>
<div class="group-controls">
<select name="type" id="type" tabindex="1">
<?php if (extension_loaded('pdo_sqlite')) {?>
@@ -631,47 +524,108 @@ function printStep3() {
<div id="mysql">
<div class="form-group">
- <label class="group-name" for="host"><?php echo _t('install.bdd.host'); ?></label>
+ <label class="group-name" for="host"><?= _t('install.bdd.host') ?></label>
<div class="group-controls">
- <input type="text" id="host" name="host" pattern="[0-9A-Z/a-z_.-]{1,64}(:[0-9]{2,5})?" value="<?php echo isset($_SESSION['bd_host']) ? $_SESSION['bd_host'] : $system_default_config->db['host']; ?>" tabindex="2" />
+ <input type="text" id="host" name="host" pattern="[0-9A-Z/a-z_.-]{1,64}(:[0-9]{2,5})?" value="<?= isset($_SESSION['bd_host']) ? $_SESSION['bd_host'] : $system_default_config->db['host'] ?>" tabindex="2" />
</div>
</div>
<div class="form-group">
- <label class="group-name" for="user"><?php echo _t('install.bdd.username'); ?></label>
+ <label class="group-name" for="user"><?= _t('install.bdd.username') ?></label>
<div class="group-controls">
- <input type="text" id="user" name="user" maxlength="64" pattern="[0-9A-Za-z_.-]{1,64}" value="<?php echo isset($_SESSION['bd_user']) ? $_SESSION['bd_user'] : ''; ?>" tabindex="3" />
+ <input type="text" id="user" name="user" maxlength="64" pattern="[0-9A-Za-z_.-]{1,64}" value="<?= isset($_SESSION['bd_user']) ? $_SESSION['bd_user'] : '' ?>" tabindex="3" />
</div>
</div>
<div class="form-group">
- <label class="group-name" for="pass"><?php echo _t('install.bdd.password'); ?></label>
+ <label class="group-name" for="pass"><?= _t('install.bdd.password') ?></label>
<div class="group-controls">
- <input type="password" id="pass" name="pass" value="<?php echo isset($_SESSION['bd_password']) ? $_SESSION['bd_password'] : ''; ?>" tabindex="4" autocomplete="off" />
+ <input type="password" id="pass" name="pass" value="<?= isset($_SESSION['bd_password']) ? $_SESSION['bd_password'] : '' ?>" tabindex="4" autocomplete="off" />
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label class="group-name" for="base"><?= _t('install.bdd') ?></label>
+ <div class="group-controls">
+ <input type="text" id="base" name="base" maxlength="64" pattern="[0-9A-Za-z_-]{1,64}" value="<?= isset($_SESSION['bd_base']) ? $_SESSION['bd_base'] : '' ?>" tabindex="5" />
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label class="group-name" for="prefix"><?= _t('install.bdd.prefix') ?></label>
+ <div class="group-controls">
+ <input type="text" id="prefix" name="prefix" maxlength="16" pattern="[0-9A-Za-z_]{1,16}" value="<?= isset($_SESSION['bd_prefix']) ? $_SESSION['bd_prefix'] : $system_default_config->db['prefix'] ?>" tabindex="6" />
+ </div>
+ </div>
+ </div>
+
+ <div class="form-group form-actions">
+ <div class="group-controls">
+ <button type="submit" class="btn btn-important" tabindex="7" ><?= _t('gen.action.submit') ?></button>
+ <button type="reset" class="btn" tabindex="8" ><?= _t('gen.action.cancel') ?></button>
+ <?php if ($s2['all'] == 'ok') { ?>
+ <a class="btn btn-important next-step" href="?step=3" tabindex="9" ><?= _t('install.action.next_step') ?></a>
+ <?php } ?>
</div>
</div>
+ </form>
+<?php
+}
+
+function printStep3() {
+ $user_default_config = Minz_Configuration::get('default_user');
+?>
+ <?php $s3 = checkStep3(); if ($s3['all'] == 'ok') { ?>
+ <p class="alert alert-success"><span class="alert-head"><?= _t('gen.short.ok') ?></span> <?= _t('install.conf.ok') ?></p>
+ <?php } elseif (!empty($_POST)) { ?>
+ <p class="alert alert-error"><?= _t('install.fix_errors_before') ?></p>
+ <?php } ?>
+
+ <form action="index.php?step=3" method="post">
+ <legend><?= _t('install.conf') ?></legend>
<div class="form-group">
- <label class="group-name" for="base"><?php echo _t('install.bdd'); ?></label>
+ <label class="group-name" for="default_user"><?= _t('install.default_user') ?></label>
<div class="group-controls">
- <input type="text" id="base" name="base" maxlength="64" pattern="[0-9A-Za-z_-]{1,64}" value="<?php echo isset($_SESSION['bd_base']) ? $_SESSION['bd_base'] : ''; ?>" tabindex="5" />
+ <input type="text" id="default_user" name="default_user" autocomplete="username" required="required" size="16" pattern="<?= FreshRSS_user_Controller::USERNAME_PATTERN ?>" value="<?= isset($_SESSION['default_user']) ? $_SESSION['default_user'] : '' ?>" placeholder="<?= httpAuthUser() == '' ? 'alice' : httpAuthUser() ?>" tabindex="3" />
</div>
</div>
<div class="form-group">
- <label class="group-name" for="prefix"><?php echo _t('install.bdd.prefix'); ?></label>
+ <label class="group-name" for="auth_type"><?= _t('install.auth.type') ?></label>
<div class="group-controls">
- <input type="text" id="prefix" name="prefix" maxlength="16" pattern="[0-9A-Za-z_]{1,16}" value="<?php echo isset($_SESSION['bd_prefix']) ? $_SESSION['bd_prefix'] : $system_default_config->db['prefix']; ?>" tabindex="6" />
+ <select id="auth_type" name="auth_type" required="required" tabindex="4">
+ <?php
+ function no_auth($auth_type) {
+ return !in_array($auth_type, array('form', 'http_auth', 'none'));
+ }
+ $auth_type = isset($_SESSION['auth_type']) ? $_SESSION['auth_type'] : '';
+ ?>
+ <option value="form"<?= $auth_type === 'form' || (no_auth($auth_type) && cryptAvailable()) ? ' selected="selected"' : '', cryptAvailable() ? '' : ' disabled="disabled"' ?>><?= _t('install.auth.form') ?></option>
+ <option value="http_auth"<?= $auth_type === 'http_auth' ? ' selected="selected"' : '', httpAuthUser() == '' ? ' disabled="disabled"' : '' ?>><?= _t('install.auth.http') ?>(REMOTE_USER = '<?= httpAuthUser() ?>')</option>
+ <option value="none"<?= $auth_type === 'none' || (no_auth($auth_type) && !cryptAvailable()) ? ' selected="selected"' : '' ?>><?= _t('install.auth.none') ?></option>
+ </select>
</div>
</div>
+
+ <div class="form-group">
+ <label class="group-name" for="passwordPlain"><?= _t('install.auth.password_form') ?></label>
+ <div class="group-controls">
+ <div class="stick">
+ <input type="password" id="passwordPlain" name="passwordPlain" pattern=".{7,}" autocomplete="off" <?= $auth_type === 'form' ? ' required="required"' : '' ?> tabindex="5" />
+ <a class="btn toggle-password" data-toggle="passwordPlain"><?= FreshRSS_Themes::icon('key') ?></a>
+ </div>
+ <?= _i('help') ?> <?= _t('install.auth.password_format') ?>
+ <noscript><b><?= _t('gen.js.should_be_activated') ?></b></noscript>
+ </div>
</div>
<div class="form-group form-actions">
<div class="group-controls">
- <button type="submit" class="btn btn-important" tabindex="7" ><?php echo _t('gen.action.submit'); ?></button>
- <button type="reset" class="btn" tabindex="8" ><?php echo _t('gen.action.cancel'); ?></button>
+ <button type="submit" class="btn btn-important" tabindex="7" ><?= _t('gen.action.submit') ?></button>
+ <button type="reset" class="btn" tabindex="8" ><?= _t('gen.action.cancel') ?></button>
<?php if ($s3['all'] == 'ok') { ?>
- <a class="btn btn-important next-step" href="?step=4" tabindex="9" ><?php echo _t('install.action.next_step'); ?></a>
+ <a class="btn btn-important next-step" href="?step=4" tabindex="9" ><?= _t('install.action.next_step') ?></a>
<?php } ?>
</div>
</div>
@@ -681,14 +635,14 @@ function printStep3() {
function printStep4() {
?>
- <p class="alert alert-success"><span class="alert-head"><?php echo _t('install.congratulations'); ?></span> <?php echo _t('install.ok'); ?></p>
- <a class="btn btn-important next-step" href="?step=5" tabindex="1"><?php echo _t('install.action.finish'); ?></a>
+ <p class="alert alert-success"><span class="alert-head"><?= _t('install.congratulations') ?></span> <?= _t('install.ok') ?></p>
+ <a class="btn btn-important next-step" href="?step=5" tabindex="1"><?= _t('install.action.finish') ?></a>
<?php
}
function printStep5() {
?>
- <p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('install.not_deleted', DATA_PATH . '/do-install.txt'); ?></p>
+ <p class="alert alert-error"><span class="alert-head"><?= _t('gen.short.damn') ?></span> <?= _t('install.not_deleted', DATA_PATH . '/do-install.txt') ?></p>
<?php
}
@@ -725,28 +679,28 @@ case 5:
<meta charset="UTF-8" />
<meta name="viewport" content="initial-scale=1.0" />
<script id="jsonVars" type="application/json">{}</script>
- <title><?php echo _t('install.title'); ?></title>
- <link rel="stylesheet" href="../themes/base-theme/template.css?<?php echo @filemtime(PUBLIC_PATH . '/themes/base-theme/template.css'); ?>" />
- <link rel="stylesheet" href="../themes/Origine/origine.css?<?php echo @filemtime(PUBLIC_PATH . '/themes/Origine/origine.css'); ?>" />
+ <title><?= _t('install.title') ?></title>
+ <link rel="stylesheet" href="../themes/base-theme/template.css?<?= @filemtime(PUBLIC_PATH . '/themes/base-theme/template.css') ?>" />
+ <link rel="stylesheet" href="../themes/Origine/origine.css?<?= @filemtime(PUBLIC_PATH . '/themes/Origine/origine.css') ?>" />
<meta name="robots" content="noindex,nofollow" />
</head>
<body>
<div class="header">
<div class="item title">
- <h1><a href="index.php"><?php echo _t('install.title'); ?></a></h1>
- <h2><?php echo _t('install.step', STEP); ?></h2>
+ <h1><a href="index.php"><?= _t('install.title') ?></a></h1>
+ <h2><?= _t('install.step', STEP) ?></h2>
</div>
</div>
<div id="global">
<ul class="nav nav-list aside">
- <li class="nav-header"><?php echo _t('install.steps'); ?></li>
- <li class="item<?php echo STEP == 0 ? ' active' : ''; ?>"><a href="?step=0"><?php echo _t('install.language'); ?></a></li>
- <li class="item<?php echo STEP == 1 ? ' active' : ''; ?>"><a href="?step=1"><?php echo _t('install.check'); ?></a></li>
- <li class="item<?php echo STEP == 2 ? ' active' : ''; ?>"><a href="?step=2"><?php echo _t('install.conf'); ?></a></li>
- <li class="item<?php echo STEP == 3 ? ' active' : ''; ?>"><a href="?step=3"><?php echo _t('install.bdd.conf'); ?></a></li>
- <li class="item<?php echo STEP == 4 ? ' active' : ''; ?>"><a href="?step=4"><?php echo _t('install.this_is_the_end'); ?></a></li>
+ <li class="nav-header"><?= _t('install.steps') ?></li>
+ <li class="item<?= STEP == 0 ? ' active' : '' ?>"><a href="?step=0"><?= _t('install.language') ?></a></li>
+ <li class="item<?= STEP == 1 ? ' active' : '' ?>"><a href="?step=1"><?= _t('install.check') ?></a></li>
+ <li class="item<?= STEP == 2 ? ' active' : '' ?>"><a href="?step=2"><?= _t('install.bdd.conf') ?></a></li>
+ <li class="item<?= STEP == 3 ? ' active' : '' ?>"><a href="?step=3"><?= _t('install.conf') ?></a></li>
+ <li class="item<?= STEP == 4 ? ' active' : '' ?>"><a href="?step=4"><?= _t('install.this_is_the_end') ?></a></li>
</ul>
<div class="post">
@@ -775,6 +729,6 @@ case 5:
?>
</div>
</div>
- <script src="../scripts/install.js?<?php echo @filemtime(PUBLIC_PATH . '/scripts/install.js'); ?>"></script>
+ <script src="../scripts/install.js?<?= @filemtime(PUBLIC_PATH . '/scripts/install.js') ?>"></script>
</body>
</html>
diff --git a/app/layout/aside_configure.phtml b/app/layout/aside_configure.phtml
index 94f5b1f6c..1267f747c 100644
--- a/app/layout/aside_configure.phtml
+++ b/app/layout/aside_configure.phtml
@@ -1,51 +1,54 @@
<ul class="nav nav-list aside">
- <li class="nav-header"><?php echo _t('gen.menu.configuration'); ?></li>
- <li class="item<?php echo Minz_Request::actionName() === 'display' ? ' active' : ''; ?>">
- <a href="<?php echo _url('configure', 'display'); ?>"><?php echo _t('gen.menu.display'); ?></a>
+ <li class="nav-header"><?= _t('gen.menu.configuration') ?></li>
+ <li class="item<?= Minz_Request::actionName() === 'display' ? ' active' : '' ?>">
+ <a href="<?= _url('configure', 'display') ?>"><?= _t('gen.menu.display') ?></a>
</li>
- <li class="item<?php echo Minz_Request::actionName() === 'reading' ? ' active' : ''; ?>">
- <a href="<?php echo _url('configure', 'reading'); ?>"><?php echo _t('gen.menu.reading'); ?></a>
+ <li class="item<?= Minz_Request::actionName() === 'reading' ? ' active' : '' ?>">
+ <a href="<?= _url('configure', 'reading') ?>"><?= _t('gen.menu.reading') ?></a>
</li>
- <li class="item<?php echo Minz_Request::actionName() === 'archiving' ? ' active' : ''; ?>">
- <a href="<?php echo _url('configure', 'archiving'); ?>"><?php echo _t('gen.menu.archiving'); ?></a>
+ <li class="item<?= Minz_Request::actionName() === 'archiving' ? ' active' : '' ?>">
+ <a href="<?= _url('configure', 'archiving') ?>"><?= _t('gen.menu.archiving') ?></a>
</li>
- <li class="item<?php echo Minz_Request::actionName() === 'sharing' ? ' active' : ''; ?>">
- <a href="<?php echo _url('configure', 'sharing'); ?>"><?php echo _t('gen.menu.sharing'); ?></a>
+ <li class="item<?= Minz_Request::actionName() === 'sharing' ? ' active' : '' ?>">
+ <a href="<?= _url('configure', 'sharing') ?>"><?= _t('gen.menu.sharing') ?></a>
</li>
- <li class="item<?php echo Minz_Request::actionName() === 'shortcut' ? ' active' : ''; ?>">
- <a href="<?php echo _url('configure', 'shortcut'); ?>"><?php echo _t('gen.menu.shortcuts'); ?></a>
+ <li class="item<?= Minz_Request::actionName() === 'shortcut' ? ' active' : '' ?>">
+ <a href="<?= _url('configure', 'shortcut') ?>"><?= _t('gen.menu.shortcuts') ?></a>
</li>
- <li class="item<?php echo Minz_Request::actionName() === 'queries' ? ' active' : ''; ?>">
- <a href="<?php echo _url('configure', 'queries'); ?>"><?php echo _t('gen.menu.queries'); ?></a>
+ <li class="item<?= Minz_Request::actionName() === 'queries' ? ' active' : '' ?>">
+ <a href="<?= _url('configure', 'queries') ?>"><?= _t('gen.menu.queries') ?></a>
</li>
<li class="item<?php echo Minz_Request::controllerName() === 'user' &&
Minz_Request::actionName() === 'profile'? ' active' : ''; ?>">
- <a href="<?php echo _url('user', 'profile'); ?>"><?php echo _t('gen.menu.user_profile'); ?></a>
+ <a href="<?= _url('user', 'profile') ?>"><?= _t('gen.menu.user_profile') ?></a>
</li>
- <li class="item<?php echo Minz_Request::controllerName() === 'extension' ? ' active' : ''; ?>">
- <a href="<?php echo _url('extension', 'index'); ?>"><?php echo _t('gen.menu.extensions'); ?></a>
+ <li class="item<?= Minz_Request::controllerName() === 'extension' ? ' active' : '' ?>">
+ <a href="<?= _url('extension', 'index') ?>"><?= _t('gen.menu.extensions') ?></a>
</li>
+ <?= Minz_ExtensionManager::callHook('menu_configuration_entry') ?>
+
<?php if (FreshRSS_Auth::hasAccess('admin')) { ?>
- <li class="nav-header"><?php echo _t('gen.menu.admin'); ?></li>
- <li class="item<?php echo Minz_Request::actionName() === 'system' ? ' active' : ''; ?>">
- <a href="<?php echo _url('configure', 'system')?>"><?php echo _t('gen.menu.system'); ?></a>
+ <li class="nav-header"><?= _t('gen.menu.admin') ?></li>
+ <li class="item<?= Minz_Request::actionName() === 'system' ? ' active' : '' ?>">
+ <a href="<?= _url('configure', 'system') ?>"><?= _t('gen.menu.system') ?></a>
</li>
<li class="item<?php echo Minz_Request::controllerName() === 'user' &&
Minz_Request::actionName() === 'manage' ? ' active' : ''; ?>">
- <a href="<?php echo _url('user', 'manage'); ?>"><?php echo _t('gen.menu.user_management'); ?></a>
+ <a href="<?= _url('user', 'manage') ?>"><?= _t('gen.menu.user_management') ?></a>
</li>
- <li class="item<?php echo Minz_Request::controllerName() === 'auth' ? ' active' : ''; ?>">
- <a href="<?php echo _url('auth', 'index'); ?>"><?php echo _t('gen.menu.authentication'); ?></a>
+ <li class="item<?= Minz_Request::controllerName() === 'auth' ? ' active' : '' ?>">
+ <a href="<?= _url('auth', 'index') ?>"><?= _t('gen.menu.authentication') ?></a>
</li>
<li class="item<?php echo Minz_Request::controllerName() === 'update' &&
Minz_Request::actionName() === 'checkInstall' ? ' active' : ''; ?>">
- <a href="<?php echo _url('update', 'checkInstall'); ?>"><?php echo _t('gen.menu.check_install'); ?></a>
+ <a href="<?= _url('update', 'checkInstall') ?>"><?= _t('gen.menu.check_install') ?></a>
</li>
<?php if (!Minz_Configuration::get('system')->disable_update) { ?>
<li class="item<?php echo Minz_Request::controllerName() === 'update' &&
Minz_Request::actionName() === 'index' ? ' active' : ''; ?>">
- <a href="<?php echo _url('update', 'index'); ?>"><?php echo _t('gen.menu.update'); ?></a>
+ <a href="<?= _url('update', 'index') ?>"><?= _t('gen.menu.update') ?></a>
</li>
<?php } ?>
+ <?= Minz_ExtensionManager::callHook('menu_admin_entry') ?>
<?php } ?>
</ul>
diff --git a/app/layout/aside_feed.phtml b/app/layout/aside_feed.phtml
index 637acf4a4..e0c90282f 100644
--- a/app/layout/aside_feed.phtml
+++ b/app/layout/aside_feed.phtml
@@ -8,30 +8,30 @@
}
?>
-<div class="aside aside_feed<?php echo $class; ?>" id="aside_feed">
- <a class="toggle_aside" href="#close"><?php echo _i('close'); ?></a>
+<div class="aside aside_feed<?= $class ?>" id="aside_feed">
+ <a class="toggle_aside" href="#close"><?= _i('close') ?></a>
<?php if (FreshRSS_Auth::hasAccess()) { ?>
<div class="stick configure-feeds no-mobile">
- <a id="btn-subscription" class="btn btn-important" href="<?php echo _url('subscription', 'index'); ?>"><?php echo _t('index.menu.subscription'); ?></a>
- <a id="btn-importExport" class="btn btn-important" href="<?php echo _url('importExport', 'index'); ?>"><?php echo _i('import'); ?></a>
+ <a id="btn-subscription" class="btn btn-important" href="<?= _url('subscription', 'index') ?>"><?= _t('index.menu.subscription') ?></a>
+ <a id="btn-importExport" class="btn btn-important" href="<?= _url('importExport', 'index') ?>"><?= _i('import') ?></a>
</div>
<?php } elseif (FreshRSS_Auth::accessNeedsLogin()) { ?>
- <a href="<?php echo _url('index', 'about'); ?>"><?php echo _t('index.menu.about'); ?></a>
+ <a href="<?= _url('index', 'about') ?>"><?= _t('index.menu.about') ?></a>
<?php } ?>
<form id="mark-read-aside" method="post">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
<ul id="sidebar" class="tree">
- <li class="tree-folder category all<?php echo FreshRSS_Context::isCurrentGet('a') ? ' active' : ''; ?>">
+ <li class="tree-folder category all<?= FreshRSS_Context::isCurrentGet('a') ? ' active' : '' ?>">
<div class="tree-folder-title">
- <?php echo _i('all'); ?> <a class="title" data-unread="<?php echo format_number(FreshRSS_Context::$total_unread); ?>" href="<?php echo _url('index', $actual_view); ?>"><?php echo _t('index.menu.main_stream'); ?></a>
+ <?= _i('all') ?> <a class="title" data-unread="<?= format_number(FreshRSS_Context::$total_unread) ?>" href="<?= _url('index', $actual_view) ?>"><?= _t('index.menu.main_stream') ?></a>
</div>
</li>
- <li class="tree-folder category favorites<?php echo FreshRSS_Context::isCurrentGet('s') ? ' active' : ''; ?>">
+ <li class="tree-folder category favorites<?= FreshRSS_Context::isCurrentGet('s') ? ' active' : '' ?>">
<div class="tree-folder-title">
- <?php echo _i('bookmark'); ?> <a class="title" data-unread="<?php echo format_number(FreshRSS_Context::$total_starred['unread']); ?>" href="<?php echo _url('index', $actual_view, 'get', 's'); ?>"><?php echo _t('index.menu.favorites', format_number(FreshRSS_Context::$total_starred['all'])); ?></a>
+ <?= _i('bookmark') ?> <a class="title" data-unread="<?= format_number(FreshRSS_Context::$total_starred['unread']) ?>" href="<?= _url('index', $actual_view, 'get', 's') ?>"><?= _t('index.menu.favorites', format_number(FreshRSS_Context::$total_starred['all'])) ?></a>
</div>
</li>
@@ -39,22 +39,22 @@
$t_active = FreshRSS_Context::isCurrentGet('T');
$t_show = $t_active || FreshRSS_Context::$user_conf->display_categories;
?>
- <li class="tree-folder category tags<?php echo $t_active ? ' active' : ''; ?>">
+ <li class="tree-folder category tags<?= $t_active ? ' active' : '' ?>">
<div class="tree-folder-title">
- <a class="dropdown-toggle" href="#"><?php echo _i($t_active ? 'up' : 'down'); ?></a>
- <a class="title" data-unread="<?php echo format_number($this->nbUnreadTags); ?>" href="<?php echo _url('index', $actual_view, 'get', 'T'); ?>"><?php echo _t('index.menu.tags'); ?></a>
+ <a class="dropdown-toggle" href="#"><?= _i($t_active ? 'up' : 'down') ?></a>
+ <a class="title" data-unread="<?= format_number($this->nbUnreadTags) ?>" href="<?= _url('index', $actual_view, 'get', 'T') ?>"><?= _t('index.menu.tags') ?></a>
</div>
- <ul class="tree-folder-items<?php echo $t_show ? ' active' : ''; ?>">
+ <ul class="tree-folder-items<?= $t_show ? ' active' : '' ?>">
<?php
foreach ($this->tags as $tag):
?>
- <li id="t_<?php echo $tag->id(); ?>" class="item feed<?php echo FreshRSS_Context::isCurrentGet('t_' . $tag->id()) ? ' active' : ''; ?>" data-unread="<?php echo $tag->nbUnread(); ?>">
+ <li id="t_<?= $tag->id() ?>" class="item feed<?= FreshRSS_Context::isCurrentGet('t_' . $tag->id()) ? ' active' : '' ?>" data-unread="<?= $tag->nbUnread() ?>">
<div class="dropdown no-mobile">
<div class="dropdown-target"></div>
- <a class="dropdown-toggle"><?php echo _i('configure'); ?></a>
+ <a class="dropdown-toggle"><?= _i('configure') ?></a>
<?php /* tag_config_template */ ?>
</div>
- <?php echo FreshRSS_Themes::alt('label'); ?> <a class="item-title" data-unread="<?php echo format_number($tag->nbUnread()); ?>" href="<?php echo _url('index', $actual_view, 'get', 't_' . $tag->id()); ?>"><?php echo $tag->name(); ?></a>
+ <?= FreshRSS_Themes::alt('label') ?> <a class="item-title" data-unread="<?= format_number($tag->nbUnread()) ?>" href="<?= _url('index', $actual_view, 'get', 't_' . $tag->id()) ?>"><?= $tag->name() ?></a>
</li>
<?php endforeach; ?>
</ul>
@@ -63,28 +63,29 @@
<?php
foreach ($this->categories as $cat) {
$feeds = $cat->feeds();
+ $position = $cat->attributes('position');
if (!empty($feeds)) {
$c_active = FreshRSS_Context::isCurrentGet('c_' . $cat->id());
$c_show = $c_active || FreshRSS_Context::$user_conf->display_categories;
?>
- <li class="tree-folder category<?php echo $c_active ? ' active' : ''; ?>" data-unread="<?php echo $cat->nbNotRead(); ?>">
+ <li class="tree-folder category<?= $c_active ? ' active' : '' ?>"<?= null === $position ? '' : "data-position='$position'" ?> data-unread="<?= $cat->nbNotRead() ?>">
<div class="tree-folder-title">
- <a class="dropdown-toggle" href="#"><?php echo _i($c_show ? 'up' : 'down'); ?></a>
- <a class="title<?php echo $cat->hasFeedsWithError() ? ' error' : ''; ?>" data-unread="<?php echo format_number($cat->nbNotRead()); ?>" href="<?php echo _url('index', $actual_view, 'get', 'c_' . $cat->id()); ?>"><?php echo $cat->name(); ?></a>
+ <a class="dropdown-toggle" href="#"><?= _i($c_show ? 'up' : 'down') ?></a>
+ <a class="title<?= $cat->hasFeedsWithError() ? ' error' : '' ?>" data-unread="<?= format_number($cat->nbNotRead()) ?>" href="<?= _url('index', $actual_view, 'get', 'c_' . $cat->id()) ?>"><?= $cat->name() ?></a>
</div>
- <ul class="tree-folder-items<?php echo $c_show ? ' active' : ''; ?>">
+ <ul class="tree-folder-items<?= $c_show ? ' active' : '' ?>">
<?php
foreach ($feeds as $feed) {
$f_active = FreshRSS_Context::isCurrentGet('f_' . $feed->id());
?>
- <li id="f_<?php echo $feed->id(); ?>" class="item feed<?php echo $f_active ? ' active' : '', $feed->mute() ? ' mute' : ''; ?><?php echo $feed->inError() ? ' error' : ''; ?><?php echo $feed->nbEntries() <= 0 ? ' empty' : ''; ?>" data-unread="<?php echo $feed->nbNotRead(); ?>" data-priority="<?php echo $feed->priority(); ?>">
+ <li id="f_<?= $feed->id() ?>" class="item feed<?= $f_active ? ' active' : '', $feed->mute() ? ' mute' : '' ?><?= $feed->inError() ? ' error' : '' ?><?= $feed->nbEntries() <= 0 ? ' empty' : '' ?>" data-unread="<?= $feed->nbNotRead() ?>" data-priority="<?= $feed->priority() ?>">
<div class="dropdown no-mobile">
<div class="dropdown-target"></div>
- <a class="dropdown-toggle" data-fweb="<?php echo $feed->website(); ?>"><?php echo _i('configure'); ?></a>
+ <a class="dropdown-toggle" data-fweb="<?= $feed->website() ?>"><?= _i('configure') ?></a>
<?php /* feed_config_template */ ?>
</div>
- <img class="favicon" src="<?php echo $feed->favicon(); ?>" alt="✇" /> <a class="item-title" data-unread="<?php echo format_number($feed->nbNotRead()); ?>" href="<?php echo _url('index', $actual_view, 'get', 'f_' . $feed->id()); ?>"><?php echo $feed->name(); ?></a>
+ <img class="favicon" src="<?= $feed->favicon() ?>" alt="✇" /> <a class="item-title" data-unread="<?= format_number($feed->nbNotRead()) ?>" href="<?= _url('index', $actual_view, 'get', 'f_' . $feed->id()) ?>"><?= $feed->name() ?></a>
</li>
<?php } ?>
</ul>
@@ -103,8 +104,8 @@
<li class="dropdown-close"><a href="#close">❌</a></li>
<li class="item">
<button class="as-link confirm" disabled="disabled"
- form="mark-read-aside" formaction="<?php echo _url('tag', 'delete', 'id_tag', '------'); ?>"
- type="submit"><?php echo _t('gen.action.remove'); ?></button>
+ form="mark-read-aside" formaction="<?= _url('tag', 'delete', 'id_tag', '------') ?>"
+ type="submit"><?= _t('gen.action.remove') ?></button>
</li>
</ul>
</script>
@@ -112,21 +113,21 @@
<script id="feed_config_template" type="text/html">
<ul class="dropdown-menu">
<li class="dropdown-close"><a href="#close">❌</a></li>
- <li class="item"><a href="<?php echo _url('index', $actual_view, 'get', 'f_------'); ?>"><?php echo _t('gen.action.filter'); ?></a></li>
+ <li class="item"><a href="<?= _url('index', $actual_view, 'get', 'f_------') ?>"><?= _t('gen.action.filter') ?></a></li>
<?php if (FreshRSS_Auth::hasAccess()) { ?>
- <li class="item"><a href="<?php echo _url('stats', 'repartition', 'id', '------'); ?>"><?php echo _t('index.menu.stats'); ?></a></li>
+ <li class="item"><a href="<?= _url('stats', 'repartition', 'id', '------') ?>"><?= _t('index.menu.stats') ?></a></li>
<?php } ?>
- <li class="item"><a target="_blank" rel="noreferrer" href="http://example.net/"><?php echo _t('gen.action.see_website'); ?></a></li>
+ <li class="item"><a target="_blank" rel="noreferrer" href="http://example.net/"><?= _t('gen.action.see_website') ?></a></li>
<?php if (FreshRSS_Auth::hasAccess()) { ?>
<li class="separator"></li>
- <li class="item"><a href="<?php echo _url('subscription', 'index', 'id', '------'); ?>"><?php echo _t('gen.action.manage'); ?></a></li>
- <li class="item"><a href="<?php echo _url('feed', 'actualize', 'id', '------'); ?>"><?php echo _t('gen.action.actualize'); ?></a></li>
+ <li class="item"><a href="<?= _url('subscription', 'index', 'id', '------') ?>"><?= _t('gen.action.manage') ?></a></li>
+ <li class="item"><a href="<?= _url('feed', 'actualize', 'id', '------') ?>"><?= _t('gen.action.actualize') ?></a></li>
<li class="item">
<?php $confirm = FreshRSS_Context::$user_conf->reading_confirm ? 'confirm" disabled="disabled' : ''; ?>
- <button class="read_all as-link <?php echo $confirm; ?>"
+ <button class="read_all as-link <?= $confirm ?>"
form="mark-read-aside"
- formaction="<?php echo _url('entry', 'read', 'get', 'f_------'); ?>"
- type="submit"><?php echo _t('gen.action.mark_read'); ?></button>
+ formaction="<?= _url('entry', 'read', 'get', 'f_------') ?>"
+ type="submit"><?= _t('gen.action.mark_read') ?></button>
</li>
<?php } ?>
</ul>
diff --git a/app/layout/aside_stats.phtml b/app/layout/aside_stats.phtml
index 4bdaf7165..705e6ce86 100644
--- a/app/layout/aside_stats.phtml
+++ b/app/layout/aside_stats.phtml
@@ -1,12 +1,12 @@
<ul class="nav nav-list aside">
- <li class="nav-header"><?php echo _t('admin.stats'); ?></li>
- <li class="item<?php echo Minz_Request::actionName() == 'index' ? ' active' : ''; ?>">
- <a href="<?php echo _url('stats', 'index'); ?>"><?php echo _t('admin.stats.menu.main'); ?></a>
+ <li class="nav-header"><?= _t('admin.stats') ?></li>
+ <li class="item<?= Minz_Request::actionName() == 'index' ? ' active' : '' ?>">
+ <a href="<?= _url('stats', 'index') ?>"><?= _t('admin.stats.menu.main') ?></a>
</li>
- <li class="item<?php echo Minz_Request::actionName() == 'idle' ? ' active' : ''; ?>">
- <a href="<?php echo _url('stats', 'idle'); ?>"><?php echo _t('admin.stats.menu.idle'); ?></a>
+ <li class="item<?= Minz_Request::actionName() == 'idle' ? ' active' : '' ?>">
+ <a href="<?= _url('stats', 'idle') ?>"><?= _t('admin.stats.menu.idle') ?></a>
</li>
- <li class="item<?php echo Minz_Request::actionName() == 'repartition' ? ' active' : ''; ?>">
- <a href="<?php echo _url('stats', 'repartition'); ?>"><?php echo _t('admin.stats.menu.repartition'); ?></a>
+ <li class="item<?= Minz_Request::actionName() == 'repartition' ? ' active' : '' ?>">
+ <a href="<?= _url('stats', 'repartition') ?>"><?= _t('admin.stats.menu.repartition') ?></a>
</li>
</ul>
diff --git a/app/layout/aside_subscription.phtml b/app/layout/aside_subscription.phtml
index e6a378837..fa1c1aa2d 100644
--- a/app/layout/aside_subscription.phtml
+++ b/app/layout/aside_subscription.phtml
@@ -1,15 +1,15 @@
<ul class="nav nav-list aside">
- <li class="nav-header"><?php echo _t('sub.menu.subscription_management'); ?></li>
+ <li class="nav-header"><?= _t('sub.menu.subscription_management') ?></li>
- <li class="item<?php echo Minz_Request::controllerName() === 'subscription' && Minz_Request::actionName() !== 'bookmarklet' ? ' active' : ''; ?>">
- <a href="<?php echo _url('subscription', 'index'); ?>"><?php echo _t('sub.menu.subscription_management'); ?></a>
+ <li class="item<?= Minz_Request::controllerName() === 'subscription' && Minz_Request::actionName() !== 'bookmarklet' ? ' active' : '' ?>">
+ <a href="<?= _url('subscription', 'index') ?>"><?= _t('sub.menu.subscription_management') ?></a>
</li>
- <li class="item<?php echo Minz_Request::controllerName() === 'importExport' ? ' active' : ''; ?>">
- <a href="<?php echo _url('importExport', 'index'); ?>"><?php echo _t('sub.menu.import_export'); ?></a>
+ <li class="item<?= Minz_Request::controllerName() === 'importExport' ? ' active' : '' ?>">
+ <a href="<?= _url('importExport', 'index') ?>"><?= _t('sub.menu.import_export') ?></a>
</li>
- <li class="item<?php echo Minz_Request::controllerName() === 'subscription' && Minz_Request::actionName() === 'bookmarklet' ? ' active' : ''; ?>">
- <a href="<?php echo _url('subscription', 'bookmarklet'); ?>"><?php echo _t('sub.menu.subscription_tools'); ?></a>
+ <li class="item<?= Minz_Request::controllerName() === 'subscription' && Minz_Request::actionName() === 'bookmarklet' ? ' active' : '' ?>">
+ <a href="<?= _url('subscription', 'bookmarklet') ?>"><?= _t('sub.menu.subscription_tools') ?></a>
</li>
</ul>
diff --git a/app/layout/header.phtml b/app/layout/header.phtml
index 410ac1ff0..3f7bd80e3 100644
--- a/app/layout/header.phtml
+++ b/app/layout/header.phtml
@@ -3,10 +3,10 @@
if (FreshRSS_Auth::accessNeedsAction()) {
?><ul class="nav nav-head nav-login"><?php
if (FreshRSS_Auth::hasAccess()) {
- ?><li class="item"><?php echo _i('logout'); ?> <a class="signout" href="<?php echo _url('auth', 'logout'); ?>"><?php
+ ?><li class="item"><?= _i('logout') ?> <a class="signout" href="<?= _url('auth', 'logout') ?>"><?php
echo _t('gen.auth.logout') . ' (' . htmlspecialchars(Minz_Session::param('currentUser', '_'), ENT_NOQUOTES, 'UTF-8') . ')'; ?></a></li><?php
} else {
- ?><li class="item"><?php echo _i('login'); ?> <a class="signin" href="<?php echo _url('auth', 'login'); ?>"><?php echo _t('gen.auth.login'); ?></a></li><?php
+ ?><li class="item"><?= _i('login') ?> <a class="signin" href="<?= _url('auth', 'login') ?>"><?= _t('gen.auth.login') ?></a></li><?php
}
?></ul><?php
}
@@ -15,36 +15,36 @@ if (FreshRSS_Auth::accessNeedsAction()) {
<div class="header">
<div class="item title">
<h1>
- <a href="<?php echo _url('index', 'index'); ?>">
- <img class="logo" src="<?php echo _i('icon', true); ?>" alt="" />
- <?php echo FreshRSS_Context::$system_conf->title; ?>
+ <a href="<?= _url('index', 'index') ?>">
+ <img class="logo" src="<?= _i('icon', true) ?>" alt="" />
+ <?= FreshRSS_Context::$system_conf->title ?>
</a>
</h1>
</div>
<div class="item search">
<?php if (FreshRSS_Auth::hasAccess() || FreshRSS_Context::$system_conf->allow_anonymous) { ?>
- <form action="<?php echo _url('index', 'index'); ?>" method="get">
+ <form action="<?= _url('index', 'index') ?>" method="get">
<div class="stick">
<input type="search" name="search" id="search" class="extend" value="<?php
- echo htmlspecialchars(htmlspecialchars_decode(FreshRSS_Context::$search, ENT_QUOTES), ENT_COMPAT, 'UTF-8'); ?>" placeholder="<?php echo _t('gen.menu.search'); ?>" />
+ echo htmlspecialchars(htmlspecialchars_decode(FreshRSS_Context::$search, ENT_QUOTES), ENT_COMPAT, 'UTF-8'); ?>" placeholder="<?= _t('gen.menu.search') ?>" />
<?php $get = Minz_Request::param('get', ''); ?>
<?php if ($get != '') { ?>
- <input type="hidden" name="get" value="<?php echo $get; ?>" />
+ <input type="hidden" name="get" value="<?= $get ?>" />
<?php } ?>
<?php $order = Minz_Request::param('order', ''); ?>
<?php if ($order != '') { ?>
- <input type="hidden" name="order" value="<?php echo $order; ?>" />
+ <input type="hidden" name="order" value="<?= $order ?>" />
<?php } ?>
<?php $state = Minz_Request::param('state', ''); ?>
<?php if ($state != '') { ?>
- <input type="hidden" name="state" value="<?php echo $state; ?>" />
+ <input type="hidden" name="state" value="<?= $state ?>" />
<?php } ?>
- <button class="btn" type="submit"><?php echo _i('search'); ?></button>
+ <button class="btn" type="submit"><?= _i('search') ?></button>
</div>
</form>
<?php } ?>
@@ -54,46 +54,52 @@ if (FreshRSS_Auth::accessNeedsAction()) {
<div class="item configure">
<div class="dropdown">
<div id="dropdown-configure" class="dropdown-target"></div>
- <a class="btn dropdown-toggle" href="#dropdown-configure"><?php echo _i('configure'); ?></a>
+ <a class="btn dropdown-toggle" href="#dropdown-configure"><?= _i('configure') ?></a>
<ul class="dropdown-menu">
<li class="dropdown-close"><a href="#close">❌</a></li>
- <li class="dropdown-header"><?php echo _t('gen.menu.configuration'); ?></li>
- <li class="item"><a href="<?php echo _url('configure', 'display'); ?>"><?php echo _t('gen.menu.display'); ?></a></li>
- <li class="item"><a href="<?php echo _url('configure', 'reading'); ?>"><?php echo _t('gen.menu.reading'); ?></a></li>
- <li class="item"><a href="<?php echo _url('configure', 'archiving'); ?>"><?php echo _t('gen.menu.archiving'); ?></a></li>
- <li class="item"><a href="<?php echo _url('configure', 'sharing'); ?>"><?php echo _t('gen.menu.sharing'); ?></a></li>
- <li class="item"><a href="<?php echo _url('configure', 'shortcut'); ?>"><?php echo _t('gen.menu.shortcuts'); ?></a></li>
- <li class="item"><a href="<?php echo _url('configure', 'queries'); ?>"><?php echo _t('gen.menu.queries'); ?></a></li>
- <li class="item"><a href="<?php echo _url('user', 'profile'); ?>"><?php echo _t('gen.menu.user_profile'); ?></a></li>
- <li class="item"><a href="<?php echo _url('extension', 'index'); ?>"><?php echo _t('gen.menu.extensions'); ?></a></li>
+ <li class="dropdown-header"><?= _t('gen.menu.configuration') ?></li>
+ <li class="item"><a href="<?= _url('configure', 'display') ?>"><?= _t('gen.menu.display') ?></a></li>
+ <li class="item"><a href="<?= _url('configure', 'reading') ?>"><?= _t('gen.menu.reading') ?></a></li>
+ <li class="item"><a href="<?= _url('configure', 'archiving') ?>"><?= _t('gen.menu.archiving') ?></a></li>
+ <li class="item"><a href="<?= _url('configure', 'sharing') ?>"><?= _t('gen.menu.sharing') ?></a></li>
+ <li class="item"><a href="<?= _url('configure', 'shortcut') ?>"><?= _t('gen.menu.shortcuts') ?></a></li>
+ <li class="item"><a href="<?= _url('configure', 'queries') ?>"><?= _t('gen.menu.queries') ?></a></li>
+ <li class="item"><a href="<?= _url('user', 'profile') ?>"><?= _t('gen.menu.user_profile') ?></a></li>
+ <li class="item"><a href="<?= _url('extension', 'index') ?>"><?= _t('gen.menu.extensions') ?></a></li>
+ <?= Minz_ExtensionManager::callHook('menu_configuration_entry') ?>
+
<?php if (FreshRSS_Auth::hasAccess('admin')) { ?>
<li class="separator"></li>
- <li class="dropdown-header"><?php echo _t('gen.menu.admin'); ?></li>
- <li class="item"><a href="<?php echo _url('configure', 'system'); ?>"><?php echo _t('gen.menu.system'); ?></a></li>
- <li class="item"><a href="<?php echo _url('user', 'manage'); ?>"><?php echo _t('gen.menu.user_management'); ?></a></li>
- <li class="item"><a href="<?php echo _url('auth', 'index'); ?>"><?php echo _t('gen.menu.authentication'); ?></a></li>
- <li class="item"><a href="<?php echo _url('update', 'checkInstall'); ?>"><?php echo _t('gen.menu.check_install'); ?></a></li>
+ <li class="dropdown-header"><?= _t('gen.menu.admin') ?></li>
+ <li class="item"><a href="<?= _url('configure', 'system') ?>"><?= _t('gen.menu.system') ?></a></li>
+ <li class="item"><a href="<?= _url('user', 'manage') ?>"><?= _t('gen.menu.user_management') ?></a></li>
+ <li class="item"><a href="<?= _url('auth', 'index') ?>"><?= _t('gen.menu.authentication') ?></a></li>
+ <li class="item"><a href="<?= _url('update', 'checkInstall') ?>"><?= _t('gen.menu.check_install') ?></a></li>
<?php if (!Minz_Configuration::get('system')->disable_update) { ?>
- <li class="item"><a href="<?php echo _url('update', 'index'); ?>"><?php echo _t('gen.menu.update'); ?></a></li>
+ <li class="item"><a href="<?= _url('update', 'index') ?>"><?= _t('gen.menu.update') ?></a></li>
<?php } ?>
+ <?= Minz_ExtensionManager::callHook('menu_admin_entry') ?>
<?php } ?>
+
<li class="separator"></li>
- <li class="item"><a href="<?php echo _url('stats', 'index'); ?>"><?php echo _t('gen.menu.stats'); ?></a></li>
- <li class="item"><a href="<?php echo _url('index', 'logs'); ?>"><?php echo _t('gen.menu.logs'); ?></a></li>
- <li class="item"><a href="<?php echo _url('index', 'about'); ?>"><?php echo _t('gen.menu.about'); ?></a></li>
+ <li class="item"><a href="<?= _url('stats', 'index') ?>"><?= _t('gen.menu.stats') ?></a></li>
+ <li class="item"><a href="<?= _url('index', 'logs') ?>"><?= _t('gen.menu.logs') ?></a></li>
+ <li class="item"><a href="<?= _url('index', 'about') ?>"><?= _t('gen.menu.about') ?></a></li>
+ <?= Minz_ExtensionManager::callHook('menu_other_entry') ?>
+
<li class="separator"></li>
<?php if (FreshRSS_Auth::accessNeedsAction()): ?>
- <li class="item"><a class="signout" href="<?php echo _url('auth', 'logout'); ?>"><?php
+ <li class="item"><a class="signout" href="<?= _url('auth', 'logout') ?>"><?php
echo _i('logout') . ' ' . _t('gen.auth.logout') . ' (' . htmlspecialchars(Minz_Session::param('currentUser', '_'), ENT_NOQUOTES, 'UTF-8') . ')'; ?></a></li>
<?php else: ?>
- <li class="item"><span class="signout">(<?php echo htmlspecialchars(Minz_Session::param('currentUser', '_'), ENT_NOQUOTES, 'UTF-8'); ?>)</span></li>
+ <li class="item"><span class="signout">(<?= htmlspecialchars(Minz_Session::param('currentUser', '_'), ENT_NOQUOTES, 'UTF-8') ?>)</span></li>
<?php endif; ?>
</ul>
</div>
</div>
<?php } elseif (FreshRSS_Auth::accessNeedsAction()) { ?>
<div class="item configure">
- <?php echo _i('login'); ?><a class="signin" href="<?php echo _url('auth', 'login'); ?>"><?php echo _t('gen.auth.login'); ?></a>
+ <?= _i('login') ?><a class="signin" href="<?= _url('auth', 'login') ?>"><?= _t('gen.auth.login') ?></a>
</div>
<?php } ?>
</div>
diff --git a/app/layout/layout.phtml b/app/layout/layout.phtml
index 2e16672e6..498cc4470 100644
--- a/app/layout/layout.phtml
+++ b/app/layout/layout.phtml
@@ -1,25 +1,25 @@
<?php FreshRSS::preLayout(); ?>
<!DOCTYPE html>
-<html lang="<?php echo FreshRSS_Context::$user_conf->language; ?>" xml:lang="<?php echo FreshRSS_Context::$user_conf->language; ?>">
+<html lang="<?= FreshRSS_Context::$user_conf->language ?>" xml:lang="<?= FreshRSS_Context::$user_conf->language ?>">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="initial-scale=1.0" />
- <?php echo self::headStyle(); ?>
+ <?= self::headStyle() ?>
<script id="jsonVars" type="application/json">
<?php $this->renderHelper('javascript_vars'); ?>
</script>
- <?php echo self::headScript(); ?>
- <link rel="shortcut icon" id="favicon" type="image/x-icon" sizes="16x16 64x64" href="<?php echo Minz_Url::display('/favicon.ico'); ?>" />
- <link rel="icon msapplication-TileImage apple-touch-icon" type="image/png" sizes="256x256" href="<?php echo Minz_Url::display('/themes/icons/favicon-256.png'); ?>" />
- <link rel="apple-touch-icon" href="<?php echo Minz_Url::display('/themes/icons/apple-touch-icon.png'); ?>" />
+ <?= self::headScript() ?>
+ <link rel="shortcut icon" id="favicon" type="image/x-icon" sizes="16x16 64x64" href="<?= Minz_Url::display('/favicon.ico') ?>" />
+ <link rel="icon msapplication-TileImage apple-touch-icon" type="image/png" sizes="256x256" href="<?= Minz_Url::display('/themes/icons/favicon-256.png') ?>" />
+ <link rel="apple-touch-icon" href="<?= Minz_Url::display('/themes/icons/apple-touch-icon.png') ?>" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
- <meta name="apple-mobile-web-app-title" content="<?php echo FreshRSS_Context::$system_conf->title; ?>">
+ <meta name="apple-mobile-web-app-title" content="<?= FreshRSS_Context::$system_conf->title ?>">
<meta name="msapplication-TileColor" content="#FFF" />
<?php if (!FreshRSS_Context::$system_conf->allow_referrer) { ?>
<meta name="referrer" content="never" />
<?php } ?>
- <?php echo self::headTitle(); ?>
+ <?= self::headTitle() ?>
<?php
$url_base = Minz_Request::currentRequest();
if (isset($this->rss_title)) {
@@ -29,14 +29,14 @@
$url_rss['params']['hours'] = FreshRSS_Context::$user_conf->since_hours_posts_per_rss;
}
?>
- <link rel="alternate" type="application/rss+xml" title="<?php echo $this->rss_title; ?>" href="<?php echo Minz_Url::display($url_rss); ?>" />
+ <link rel="alternate" type="application/rss+xml" title="<?= $this->rss_title ?>" href="<?= Minz_Url::display($url_rss) ?>" />
<?php } if (FreshRSS_Context::$system_conf->allow_robots) { ?>
- <meta name="description" content="<?php echo htmlspecialchars(FreshRSS_Context::$name . ' | ' . FreshRSS_Context::$description, ENT_COMPAT, 'UTF-8'); ?>" />
+ <meta name="description" content="<?= htmlspecialchars(FreshRSS_Context::$name . ' | ' . FreshRSS_Context::$description, ENT_COMPAT, 'UTF-8') ?>" />
<?php } else { ?>
<meta name="robots" content="noindex,nofollow" />
<?php } ?>
</head>
- <body class="<?php echo Minz_Request::actionName(); ?>">
+ <body class="<?= Minz_Request::actionName() ?>">
<?php
flush();
$this->partial('header');
@@ -62,9 +62,9 @@
invalidateHttpCache();
}
?>
-<div id="notification" class="notification <?php echo $status; ?>">
- <span class="msg"><?php echo $msg; ?></span>
- <a class="close" href=""><?php echo _i('close'); ?></a>
+<div id="notification" class="notification <?= $status ?>">
+ <span class="msg"><?= $msg ?></span>
+ <a class="close" href=""><?= _i('close') ?></a>
</div>
</body>
</html>
diff --git a/app/layout/nav_entries.phtml b/app/layout/nav_entries.phtml
index ca6849193..cbc514737 100644
--- a/app/layout/nav_entries.phtml
+++ b/app/layout/nav_entries.phtml
@@ -1,5 +1,5 @@
<ul id="nav_entries">
- <li class="item"><a class="previous_entry" href="#"><?php echo _i('prev'); ?></a></li>
- <li class="item"><a class="up" href="#"><?php echo _i('up'); ?></a></li>
- <li class="item"><a class="next_entry" href="#"><?php echo _i('next'); ?></a></li>
+ <li class="item"><a class="previous_entry" href="#"><?= _i('prev') ?></a></li>
+ <li class="item"><a class="up" href="#"><?= _i('up') ?></a></li>
+ <li class="item"><a class="next_entry" href="#"><?= _i('next') ?></a></li>
</ul> \ No newline at end of file
diff --git a/app/layout/nav_menu.phtml b/app/layout/nav_menu.phtml
index af7267bac..da33d3e20 100644
--- a/app/layout/nav_menu.phtml
+++ b/app/layout/nav_menu.phtml
@@ -9,7 +9,7 @@
<div class="nav_menu">
<?php if ($actual_view === 'normal' || $actual_view === 'reader' ) { ?>
- <a class="btn toggle_aside" href="#aside_feed"><?php echo _i('category'); ?></a>
+ <a class="btn toggle_aside" href="#aside_feed"><?= _i('category') ?></a>
<?php } ?>
<?php if (FreshRSS_Auth::hasAccess()) { ?>
@@ -27,28 +27,28 @@
$url_state = Minz_Request::currentRequest();
$url_state['params']['state'] = FreshRSS_Context::getRevertState($state);
?>
- <a id="toggle-<?php echo $state_str; ?>"
- class="btn <?php echo $state_enabled ? 'active' : ''; ?>"
- role="checkbox" aria-checked="<?php echo $state_enabled ? 'true' : 'false'; ?>"
- title="<?php echo _t('index.menu.' . $state_str); ?>"
- href="<?php echo Minz_Url::display($url_state); ?>"><?php echo _i($state_str); ?></a>
+ <a id="toggle-<?= $state_str ?>"
+ class="btn <?= $state_enabled ? 'active' : '' ?>"
+ role="checkbox" aria-checked="<?= $state_enabled ? 'true' : 'false' ?>"
+ title="<?= _t('index.menu.' . $state_str) ?>"
+ href="<?= Minz_Url::display($url_state) ?>"><?= _i($state_str) ?></a>
<?php } ?>
<div class="dropdown">
<div id="dropdown-query" class="dropdown-target"></div>
- <a class="dropdown-toggle btn" href="#dropdown-query"><?php echo _i('down'); ?></a>
+ <a class="dropdown-toggle btn" href="#dropdown-query"><?= _i('down') ?></a>
<ul class="dropdown-menu">
<li class="dropdown-close"><a href="#close">❌</a></li>
<li class="dropdown-header">
- <?php echo _t('index.menu.queries'); ?>
- <a class="no-mobile" href="<?php echo _url('configure', 'queries'); ?>"><?php echo _i('configure'); ?></a>
+ <?= _t('index.menu.queries') ?>
+ <a class="no-mobile" href="<?= _url('configure', 'queries') ?>"><?= _i('configure') ?></a>
</li>
<?php foreach (FreshRSS_Context::$user_conf->queries as $query) { ?>
<li class="item query">
- <a href="<?php echo $query['url']; ?>"><?php echo $query['name']; ?></a>
+ <a href="<?= $query['url'] ?>"><?= $query['name'] ?></a>
</li>
<?php } ?>
@@ -61,7 +61,7 @@
$url_query['c'] = 'configure';
$url_query['a'] = 'addQuery';
?>
- <li class="item no-mobile"><a href="<?php echo Minz_Url::display($url_query); ?>"><?php echo _i('bookmark-add'); ?> <?php echo _t('index.menu.add_query'); ?></a></li>
+ <li class="item no-mobile"><a href="<?= Minz_Url::display($url_query) ?>"><?= _i('bookmark-add') ?> <?= _t('index.menu.add_query') ?></a></li>
</ul>
</div>
</div>
@@ -96,24 +96,24 @@
<div class="stick" id="nav_menu_read_all">
<form id="mark-read-menu" method="post">
<?php $confirm = FreshRSS_Context::$user_conf->reading_confirm ? 'confirm" disabled="disabled' : ''; ?>
- <button class="read_all btn <?php echo $confirm; ?>"
+ <button class="read_all btn <?= $confirm ?>"
form="mark-read-menu"
- formaction="<?php echo Minz_Url::display($mark_read_url); ?>"
- type="submit"><?php echo _t('gen.action.mark_read'); ?></button>
+ formaction="<?= Minz_Url::display($mark_read_url) ?>"
+ type="submit"><?= _t('gen.action.mark_read') ?></button>
<div class="dropdown">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
<div id="dropdown-read" class="dropdown-target"></div>
- <a class="dropdown-toggle btn" href="#dropdown-read"><?php echo _i('down'); ?></a>
+ <a class="dropdown-toggle btn" href="#dropdown-read"><?= _i('down') ?></a>
<ul class="dropdown-menu">
<li class="dropdown-close"><a href="#close">❌</a></li>
<li class="item">
- <button class="as-link <?php echo $confirm; ?>"
+ <button class="as-link <?= $confirm ?>"
form="mark-read-menu"
- formaction="<?php echo Minz_Url::display($mark_read_url); ?>"
- type="submit"><?php echo $string_mark; ?></button>
+ formaction="<?= Minz_Url::display($mark_read_url) ?>"
+ type="submit"><?= $string_mark ?></button>
</li>
<li class="separator"></li>
<?php
@@ -125,23 +125,23 @@
$mark_unread_enabled = FreshRSS_Context::isStateEnabled(FreshRSS_Entry::STATE_READ) or !FreshRSS_Context::isStateEnabled(FreshRSS_Entry::STATE_NOT_READ);
?>
<li class="item">
- <button class="as-link <?php echo $confirm; ?>"
+ <button class="as-link <?= $confirm ?>"
form="mark-read-menu"
- formaction="<?php echo Minz_Url::display($mark_before_today); ?>"
- type="submit"><?php echo _t('index.menu.before_one_day'); ?></button>
+ formaction="<?= Minz_Url::display($mark_before_today) ?>"
+ type="submit"><?= _t('index.menu.before_one_day') ?></button>
</li>
<li class="item">
- <button class="as-link <?php echo $confirm; ?>"
+ <button class="as-link <?= $confirm ?>"
form="mark-read-menu"
- formaction="<?php echo Minz_Url::display($mark_before_one_week); ?>"
- type="submit"><?php echo _t('index.menu.before_one_week'); ?></button>
+ formaction="<?= Minz_Url::display($mark_before_one_week) ?>"
+ type="submit"><?= _t('index.menu.before_one_week') ?></button>
</li>
<li class="separator"></li>
<li class="item">
- <button class="as-link <?php echo $mark_unread_enabled ? $confirm : '" disabled="disabled'; ?>"
+ <button class="as-link <?= $mark_unread_enabled ? $confirm : '" disabled="disabled' ?>"
form="mark-read-menu"
- formaction="<?php echo Minz_Url::display($mark_unread_url); ?>"
- type="submit"><?php echo $string_unmark; ?></button>
+ formaction="<?= Minz_Url::display($mark_unread_url) ?>"
+ type="submit"><?= $string_unmark ?></button>
</li>
</ul>
</div>
@@ -158,8 +158,8 @@
/** @var FreshRSS_ReadingMode $mode */
foreach ($readingModes as $mode) {
?>
- <a class="<?php echo $mode->getId(); ?> btn <?php if ($mode->isActive()) { echo 'active'; } ?>" title="<?php echo $mode->getTitle(); ?>" href="<?php echo Minz_Url::display($mode->getUrlParams()); ?>">
- <?php echo $mode->getName(); ?>
+ <a class="<?= $mode->getId() ?> btn <?php if ($mode->isActive()) { echo 'active'; } ?>" title="<?= $mode->getTitle() ?>" href="<?= Minz_Url::display($mode->getUrlParams()) ?>">
+ <?= $mode->getName() ?>
</a>
<?php
}
@@ -175,29 +175,29 @@
$url_output['params']['hours'] = FreshRSS_Context::$user_conf->since_hours_posts_per_rss;
}
?>
- <a class="view-rss btn" target="_blank" rel="noreferrer" title="<?php echo _t('index.menu.rss_view'); ?>" href="<?php echo Minz_Url::display($url_output); ?>">
- <?php echo _i('rss'); ?>
+ <a class="view-rss btn" target="_blank" rel="noreferrer" title="<?= _t('index.menu.rss_view') ?>" href="<?= Minz_Url::display($url_output) ?>">
+ <?= _i('rss') ?>
</a>
</div>
<div class="item search">
- <form action="<?php echo _url('index', 'index'); ?>" method="get">
+ <form action="<?= _url('index', 'index') ?>" method="get">
<input type="search" name="search" class="extend" value="<?php
- echo htmlspecialchars(htmlspecialchars_decode(FreshRSS_Context::$search, ENT_QUOTES), ENT_COMPAT, 'UTF-8'); ?>" placeholder="<?php echo _t('index.menu.search_short'); ?>" />
+ echo htmlspecialchars(htmlspecialchars_decode(FreshRSS_Context::$search, ENT_QUOTES), ENT_COMPAT, 'UTF-8'); ?>" placeholder="<?= _t('index.menu.search_short') ?>" />
<?php $get = Minz_Request::param('get', ''); ?>
<?php if($get != '') { ?>
- <input type="hidden" name="get" value="<?php echo $get; ?>" />
+ <input type="hidden" name="get" value="<?= $get ?>" />
<?php } ?>
<?php $order = Minz_Request::param('order', ''); ?>
<?php if($order != '') { ?>
- <input type="hidden" name="order" value="<?php echo $order; ?>" />
+ <input type="hidden" name="order" value="<?= $order ?>" />
<?php } ?>
<?php $state = Minz_Request::param('state', ''); ?>
<?php if($state != '') { ?>
- <input type="hidden" name="state" value="<?php echo $state; ?>" />
+ <input type="hidden" name="state" value="<?= $state ?>" />
<?php } ?>
</form>
</div>
@@ -215,11 +215,11 @@
$url_order = Minz_Request::currentRequest();
$url_order['params']['order'] = $order;
?>
- <a id="toggle-order" class="btn" href="<?php echo Minz_Url::display($url_order); ?>" title="<?php echo $title; ?>">
- <?php echo _i($icon); ?>
+ <a id="toggle-order" class="btn" href="<?= Minz_Url::display($url_order) ?>" title="<?= $title ?>">
+ <?= _i($icon) ?>
</a>
<?php if (FreshRSS_Auth::hasAccess() || FreshRSS_Context::$system_conf->allow_anonymous_refresh) { ?>
- <a id="actualize" class="btn" href="<?php echo _url('feed', 'actualize'); ?>" title="<?php echo _t('gen.action.actualize'); ?>"><?php echo _i('refresh'); ?></a>
+ <a id="actualize" class="btn" href="<?= _url('feed', 'actualize') ?>" title="<?= _t('gen.action.actualize') ?>"><?= _i('refresh') ?></a>
<?php } ?>
</div>
diff --git a/app/layout/simple.phtml b/app/layout/simple.phtml
new file mode 100644
index 000000000..89fe69005
--- /dev/null
+++ b/app/layout/simple.phtml
@@ -0,0 +1,69 @@
+<?php FreshRSS::preLayout(); ?>
+<!DOCTYPE html>
+<html lang="<?= FreshRSS_Context::$user_conf->language ?>" xml:lang="<?= FreshRSS_Context::$user_conf->language ?>">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="initial-scale=1.0" />
+ <?= self::headStyle() ?>
+ <script id="jsonVars" type="application/json">
+<?php $this->renderHelper('javascript_vars'); ?>
+ </script>
+ <?= self::headScript() ?>
+ <link rel="shortcut icon" id="favicon" type="image/x-icon" sizes="16x16 64x64" href="<?= Minz_Url::display('/favicon.ico') ?>" />
+ <link rel="icon msapplication-TileImage apple-touch-icon" type="image/png" sizes="256x256" href="<?= Minz_Url::display('/themes/icons/favicon-256.png') ?>" />
+ <link rel="apple-touch-icon" href="<?= Minz_Url::display('/themes/icons/apple-touch-icon.png') ?>" />
+ <meta name="apple-mobile-web-app-capable" content="yes" />
+ <meta name="apple-mobile-web-app-status-bar-style" content="black" />
+ <meta name="apple-mobile-web-app-title" content="<?= FreshRSS_Context::$system_conf->title ?>">
+ <meta name="msapplication-TileColor" content="#FFF" />
+ <meta name="referrer" content="never" />
+ <meta name="robots" content="noindex,nofollow" />
+ <?= self::headTitle() ?>
+ </head>
+ <body>
+
+<?php flush(); ?>
+<div class="app-layout app-layout-simple">
+ <div class="header">
+ <div class="item title">
+ <h1>
+ <a href="<?= _url('index', 'index') ?>">
+ <img class="logo" src="<?= _i('icon', true) ?>" alt="" />
+ <?= FreshRSS_Context::$system_conf->title ?>
+ </a>
+ </h1>
+ </div>
+
+ <div class="item"></div>
+
+ <div class="item">
+ <?php if (FreshRSS_Auth::accessNeedsAction()) { ?>
+ <a class="signout" href="<?= _url('auth', 'logout') ?>">
+ <?= _i('logout') . _t('gen.auth.logout') ?>
+
+ (<?= htmlspecialchars(Minz_Session::param('currentUser', '_'), ENT_NOQUOTES, 'UTF-8') ?>)
+ </a>
+ <?php } ?>
+ </div>
+ </div>
+
+ <?php $this->render(); ?>
+</div>
+
+<?php
+ $msg = '';
+ $status = 'closed';
+ if (isset($this->notification)) {
+ $msg = $this->notification['content'];
+ $status = $this->notification['type'];
+
+ invalidateHttpCache();
+ }
+?>
+<div id="notification" class="notification <?= $status ?>">
+ <span class="msg"><?= $msg ?></span>
+ <a class="close" href=""><?= _i('close') ?></a>
+</div>
+
+ </body>
+</html>
diff --git a/app/shares.php b/app/shares.php
index 4f7fde3ed..9df83617a 100644
--- a/app/shares.php
+++ b/app/shares.php
@@ -75,12 +75,6 @@ return array(
'form' => 'simple',
'method' => 'GET',
),
- 'g+' => array(
- 'url' => 'https://plus.google.com/share?url=~LINK~',
- 'transform' => array('rawurlencode'),
- 'form' => 'simple',
- 'method' => 'GET',
- ),
'facebook' => array(
'url' => 'https://www.facebook.com/sharer.php?u=~LINK~&amp;t=~TITLE~',
'transform' => array('rawurlencode'),
@@ -144,4 +138,10 @@ return array(
'form' => 'simple',
'method' => 'GET',
),
+ 'lemmy' => array(
+ 'url' => '~URL~/create_post?url=~LINK~&name=~TITLE~',
+ 'transform' => array('rawurlencode'),
+ 'form' => 'advanced',
+ 'method' => 'GET',
+ ),
);
diff --git a/app/views/auth/formLogin.phtml b/app/views/auth/formLogin.phtml
index 01d1d4736..ecac7aced 100644
--- a/app/views/auth/formLogin.phtml
+++ b/app/views/auth/formLogin.phtml
@@ -1,33 +1,33 @@
<div class="prompt">
- <h1><?php echo _t('gen.auth.login'); ?></h1>
+ <h1><?= _t('gen.auth.login') ?></h1>
<?php if (!max_registrations_reached()) { ?>
- <a href="<?php echo _url('auth', 'register'); ?>"><?php echo _t('gen.auth.registration.ask'); ?></a>
+ <a href="<?= _url('auth', 'register') ?>"><?= _t('gen.auth.registration.ask') ?></a>
<?php } ?>
- <form id="crypto-form" method="post" action="<?php echo _url('auth', 'login'); ?>">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
+ <form id="crypto-form" method="post" action="<?= _url('auth', 'login') ?>">
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
<div>
- <label for="username"><?php echo _t('gen.auth.username'); ?></label>
- <input type="text" id="username" name="username" autocomplete="username" size="16" required="required" pattern="<?php echo FreshRSS_user_Controller::USERNAME_PATTERN; ?>" autofocus="autofocus" />
+ <label for="username"><?= _t('gen.auth.username') ?></label>
+ <input type="text" id="username" name="username" autocomplete="username" size="16" required="required" pattern="<?= FreshRSS_user_Controller::USERNAME_PATTERN ?>" autofocus="autofocus" />
</div>
<div>
- <label for="passwordPlain"><?php echo _t('gen.auth.password'); ?></label>
+ <label for="passwordPlain"><?= _t('gen.auth.password') ?></label>
<input type="password" id="passwordPlain" required="required" />
<input type="hidden" id="challenge" name="challenge" /><br />
- <noscript><strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript>
+ <noscript><strong><?= _t('gen.js.should_be_activated') ?></strong></noscript>
</div>
<div>
<label class="checkbox" for="keep_logged_in">
<input type="checkbox" name="keep_logged_in" id="keep_logged_in" value="1" />
- <?php echo _t('gen.auth.keep_logged_in', $this->cookie_days); ?>
+ <?= _t('gen.auth.keep_logged_in', $this->cookie_days) ?>
</label>
<br />
</div>
<div>
- <button id="loginButton" type="submit" class="btn btn-important"><?php echo _t('gen.auth.login'); ?></button>
+ <button id="loginButton" type="submit" class="btn btn-important"><?= _t('gen.auth.login') ?></button>
</div>
</form>
- <p><a href="<?php echo _url('index', 'about'); ?>"><?php echo _t('gen.freshrss.about'); ?></a></p>
+ <p><a href="<?= _url('index', 'about') ?>"><?= _t('gen.freshrss.about') ?></a></p>
</div>
diff --git a/app/views/auth/index.phtml b/app/views/auth/index.phtml
index 20966f24e..c1cf95b2b 100644
--- a/app/views/auth/index.phtml
+++ b/app/views/auth/index.phtml
@@ -1,22 +1,22 @@
<?php $this->partial('aside_configure'); ?>
<div class="post">
- <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
+ <a href="<?= _url('index', 'index') ?>"><?= _t('gen.action.back_to_rss_feeds') ?></a>
- <form method="post" action="<?php echo _url('auth', 'index'); ?>">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
- <legend><?php echo _t('admin.auth.type'); ?></legend>
+ <form method="post" action="<?= _url('auth', 'index') ?>">
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
+ <legend><?= _t('admin.auth.type') ?></legend>
<div class="form-group">
- <label class="group-name" for="auth_type"><?php echo _t('admin.auth.type'); ?></label>
+ <label class="group-name" for="auth_type"><?= _t('admin.auth.type') ?></label>
<div class="group-controls">
- <select id="auth_type" name="auth_type" required="required" data-leave-validation="<?php echo FreshRSS_Context::$system_conf->auth_type; ?>">
+ <select id="auth_type" name="auth_type" required="required" data-leave-validation="<?= FreshRSS_Context::$system_conf->auth_type ?>">
<?php if (!in_array(FreshRSS_Context::$system_conf->auth_type, array('form', 'http_auth', 'none'))) { ?>
<option selected="selected"></option>
<?php } ?>
- <option value="form"<?php echo FreshRSS_Context::$system_conf->auth_type === 'form' ? ' selected="selected"' : '', cryptAvailable() ? '' : ' disabled="disabled"'; ?>><?php echo _t('admin.auth.form'); ?></option>
- <option value="http_auth"<?php echo FreshRSS_Context::$system_conf->auth_type === 'http_auth' ? ' selected="selected"' : '', httpAuthUser() == '' ? ' disabled="disabled"' : ''; ?>><?php echo _t('admin.auth.http'); ?> (REMOTE_USER = '<?php echo httpAuthUser(); ?>')</option>
- <option value="none"<?php echo FreshRSS_Context::$system_conf->auth_type === 'none' ? ' selected="selected"' : ''; ?>><?php echo _t('admin.auth.none'); ?></option>
+ <option value="form"<?= FreshRSS_Context::$system_conf->auth_type === 'form' ? ' selected="selected"' : '', cryptAvailable() ? '' : ' disabled="disabled"' ?>><?= _t('admin.auth.form') ?></option>
+ <option value="http_auth"<?= FreshRSS_Context::$system_conf->auth_type === 'http_auth' ? ' selected="selected"' : '', httpAuthUser() == '' ? ' disabled="disabled"' : '' ?>><?= _t('admin.auth.http') ?> (REMOTE_USER = '<?= httpAuthUser() ?>')</option>
+ <option value="none"<?= FreshRSS_Context::$system_conf->auth_type === 'none' ? ' selected="selected"' : '' ?>><?= _t('admin.auth.none') ?></option>
</select>
</div>
</div>
@@ -25,8 +25,8 @@
<div class="group-controls">
<label class="checkbox" for="anon_access">
<input type="checkbox" name="anon_access" id="anon_access" value="1"<?php echo FreshRSS_Context::$system_conf->allow_anonymous ? ' checked="checked"' : '',
- FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"'; ?> data-leave-validation="<?php echo FreshRSS_Context::$system_conf->allow_anonymous; ?>"/>
- <?php echo _t('admin.auth.allow_anonymous', FreshRSS_Context::$system_conf->default_user); ?>
+ FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"'; ?> data-leave-validation="<?= FreshRSS_Context::$system_conf->allow_anonymous ?>"/>
+ <?= _t('admin.auth.allow_anonymous', FreshRSS_Context::$system_conf->default_user) ?>
</label>
</div>
</div>
@@ -35,8 +35,8 @@
<div class="group-controls">
<label class="checkbox" for="anon_refresh">
<input type="checkbox" name="anon_refresh" id="anon_refresh" value="1"<?php echo FreshRSS_Context::$system_conf->allow_anonymous_refresh ? ' checked="checked"' : '',
- FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"'; ?> data-leave-validation="<?php echo FreshRSS_Context::$system_conf->allow_anonymous_refresh; ?>"/>
- <?php echo _t('admin.auth.allow_anonymous_refresh'); ?>
+ FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"'; ?> data-leave-validation="<?= FreshRSS_Context::$system_conf->allow_anonymous_refresh ?>"/>
+ <?= _t('admin.auth.allow_anonymous_refresh') ?>
</label>
</div>
</div>
@@ -45,9 +45,9 @@
<div class="group-controls">
<label class="checkbox" for="unsafe_autologin">
<input type="checkbox" name="unsafe_autologin" id="unsafe_autologin" value="1"<?php echo FreshRSS_Context::$system_conf->unsafe_autologin_enabled ? ' checked="checked"' : '',
- FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"'; ?> data-leave-validation="<?php echo FreshRSS_Context::$system_conf->unsafe_autologin_enabled; ?>"/>
- <?php echo _t('admin.auth.unsafe_autologin'); ?>
- <kbd><?php echo Minz_Url::display(array('c' => 'auth', 'a' => 'login', 'params' => array('u' => 'alice', 'p' => '1234')), 'html', true); ?></kbd>
+ FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"'; ?> data-leave-validation="<?= FreshRSS_Context::$system_conf->unsafe_autologin_enabled ?>"/>
+ <?= _t('admin.auth.unsafe_autologin') ?>
+ <kbd><?= Minz_Url::display(array('c' => 'auth', 'a' => 'login', 'params' => array('u' => 'alice', 'p' => '1234')), 'html', true) ?></kbd>
</label>
</div>
</div>
@@ -56,16 +56,16 @@
<div class="group-controls">
<label class="checkbox" for="api_enabled">
<input type="checkbox" name="api_enabled" id="api_enabled" value="1"<?php echo FreshRSS_Context::$system_conf->api_enabled ? ' checked="checked"' : '',
- FreshRSS_Auth::accessNeedsLogin() ? '' : ' disabled="disabled"'; ?> data-leave-validation="<?php echo FreshRSS_Context::$system_conf->api_enabled; ?>"/>
- <?php echo _t('admin.auth.api_enabled'); ?>
+ FreshRSS_Auth::accessNeedsLogin() ? '' : ' disabled="disabled"'; ?> data-leave-validation="<?= FreshRSS_Context::$system_conf->api_enabled ?>"/>
+ <?= _t('admin.auth.api_enabled') ?>
</label>
</div>
</div>
<div class="form-group form-actions">
<div class="group-controls">
- <button type="submit" class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button>
- <button type="reset" class="btn"><?php echo _t('gen.action.cancel'); ?></button>
+ <button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button>
+ <button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button>
</div>
</div>
</form>
diff --git a/app/views/auth/register.phtml b/app/views/auth/register.phtml
index 19e11ef76..4233f7fd4 100644
--- a/app/views/auth/register.phtml
+++ b/app/views/auth/register.phtml
@@ -1,22 +1,40 @@
<div class="prompt">
- <h1><?php echo _t('gen.auth.registration'); ?></h1>
+ <h1><?= _t('gen.auth.registration') ?></h1>
- <form method="post" action="<?php echo _url('user', 'create'); ?>">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
+ <form method="post" action="<?= _url('user', 'create') ?>">
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
<div>
- <label class="group-name" for="new_user_name"><?php echo _t('gen.auth.username'), '<br />', _i('help'), ' ', _t('gen.auth.username.format'); ?></label>
- <input id="new_user_name" name="new_user_name" type="text" size="16" required="required" autocomplete="off" pattern="<?php echo FreshRSS_user_Controller::USERNAME_PATTERN; ?>" />
+ <label class="group-name" for="new_user_name"><?= _t('gen.auth.username'), '<br />', _i('help'), ' ', _t('gen.auth.username.format') ?></label>
+ <input id="new_user_name" name="new_user_name" type="text" size="16" required="required" autocomplete="off" pattern="<?= FreshRSS_user_Controller::USERNAME_PATTERN ?>" />
</div>
+ <?php if ($this->show_email_field) { ?>
+ <div>
+ <label class="group-name" for="new_user_email">
+ <?= _t('gen.auth.email') ?>
+ </label>
+ <input id="new_user_email" name="new_user_email" type="email" required />
+ </div>
+ <?php } ?>
+
<div>
- <label class="group-name" for="new_user_passwordPlain"><?php echo _t('gen.auth.password'), '<br />', _i('help'), ' ', _t('gen.auth.password.format'); ?></label>
+ <label class="group-name" for="new_user_passwordPlain"><?= _t('gen.auth.password'), '<br />', _i('help'), ' ', _t('gen.auth.password.format') ?></label>
<div class="stick">
<input type="password" id="new_user_passwordPlain" name="new_user_passwordPlain" required="required" autocomplete="new-password" pattern=".{7,}" />
- <a class="btn toggle-password" data-toggle="new_user_passwordPlain"><?php echo _i('key'); ?></a>
+ <a class="btn toggle-password" data-toggle="new_user_passwordPlain"><?= _i('key') ?></a>
</div>
- <noscript><b><?php echo _t('gen.js.should_be_activated'); ?></b></noscript>
+ <noscript><b><?= _t('gen.js.should_be_activated') ?></b></noscript>
</div>
+ <?php if ($this->show_tos_checkbox) { ?>
+ <div>
+ <label class="checkbox" for="accept-tos">
+ <input type="checkbox" name="accept_tos" id="accept-tos" value="1" required />
+ <?= _t('gen.auth.accept_tos', _url('index', 'tos')) ?>
+ </label>
+ </div>
+ <?php } ?>
+
<div>
<?php
$redirect_url = urlencode(Minz_Url::display(
@@ -24,11 +42,11 @@
'php', true
));
?>
- <input type="hidden" name="r" value="<?php echo $redirect_url; ?>" />
- <button type="submit" class="btn btn-important"><?php echo _t('gen.action.create'); ?></button>
- <a class="btn" href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.cancel'); ?></a>
+ <input type="hidden" name="r" value="<?= $redirect_url ?>" />
+ <button type="submit" class="btn btn-important"><?= _t('gen.action.create') ?></button>
+ <a class="btn" href="<?= _url('index', 'index') ?>"><?= _t('gen.action.cancel') ?></a>
</div>
</form>
- <p><a href="<?php echo _url('index', 'about'); ?>"><?php echo _t('gen.freshrss.about'); ?></a></p>
+ <p><a href="<?= _url('index', 'about') ?>"><?= _t('gen.freshrss.about') ?></a></p>
</div>
diff --git a/app/views/configure/archiving.phtml b/app/views/configure/archiving.phtml
index 09be55fd9..7d76e4dcc 100644
--- a/app/views/configure/archiving.phtml
+++ b/app/views/configure/archiving.phtml
@@ -1,34 +1,17 @@
<?php $this->partial('aside_configure'); ?>
<div class="post">
- <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
+ <a href="<?= _url('index', 'index') ?>"><?= _t('gen.action.back_to_rss_feeds') ?></a>
- <form method="post" action="<?php echo _url('configure', 'archiving'); ?>">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
- <legend><?php echo _t('conf.archiving'); ?></legend>
- <p><?php echo _i('help'); ?> <?php echo _t('conf.archiving.help'); ?></p>
+ <form method="post" action="<?= _url('configure', 'archiving') ?>">
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
+ <legend><?= _t('conf.archiving') ?></legend>
+ <p><?= _i('help') ?> <?= _t('conf.archiving.help') ?></p>
<div class="form-group">
- <label class="group-name" for="old_entries"><?php echo _t('conf.archiving.delete_after'); ?></label>
+ <label class="group-name" for="ttl_default"><?= _t('conf.archiving.ttl') ?></label>
<div class="group-controls">
- <input type="number" id="old_entries" name="old_entries" min="1" max="1200" value="<?php echo FreshRSS_Context::$user_conf->old_entries; ?>" data-leave-validation="<?php echo FreshRSS_Context::$user_conf->old_entries; ?>"/> <?php echo _t('gen.date.month'); ?>
-   <a class="btn confirm" href="<?php echo _url('entry', 'purge'); ?>"><?php echo _t('conf.archiving.purge_now'); ?></a>
- </div>
- </div>
- <div class="form-group">
- <label class="group-name" for="keep_history_default"><?php echo _t('conf.archiving.keep_history_by_feed'); ?></label>
- <div class="group-controls">
- <select class="number" name="keep_history_default" id="keep_history_default" required="required" data-leave-validation="<?php echo FreshRSS_Context::$user_conf->keep_history_default; ?>"><?php
- foreach (array('' => '', 0 => '0', 10 => '10', 50 => '50', 100 => '100', 500 => '500', 1000 => '1 000', 5000 => '5 000', 10000 => '10 000', FreshRSS_Feed::KEEP_HISTORY_INFINITE => '∞') as $v => $t) {
- echo '<option value="' . $v . (FreshRSS_Context::$user_conf->keep_history_default == $v ? '" selected="selected' : '') . '">' . $t . ' </option>';
- }
- ?></select> (<?php echo _t('gen.short.by_default'); ?>)
- </div>
- </div>
- <div class="form-group">
- <label class="group-name" for="ttl_default"><?php echo _t('conf.archiving.ttl'); ?></label>
- <div class="group-controls">
- <select class="number" name="ttl_default" id="ttl_default" required="required" data-leave-validation="<?php echo FreshRSS_Context::$user_conf->ttl_default; ?>"><?php
+ <select class="number" name="ttl_default" id="ttl_default" required="required" data-leave-validation="<?= FreshRSS_Context::$user_conf->ttl_default ?>"><?php
$found = false;
foreach (array(1200 => '20min', 1500 => '25min', 1800 => '30min', 2700 => '45min',
3600 => '1h', 5400 => '1.5h', 7200 => '2h', 10800 => '3h', 14400 => '4h', 18800 => '5h', 21600 => '6h', 25200 => '7h', 28800 => '8h',
@@ -43,44 +26,123 @@
if (!$found) {
echo '<option value="' . intval(FreshRSS_Context::$user_conf->ttl_default) . '" selected="selected">' . intval(FreshRSS_Context::$user_conf->ttl_default) . 's</option>';
}
- ?></select> (<?php echo _t('gen.short.by_default'); ?>)
+ ?></select> (<?= _t('gen.short.by_default') ?>)
+ </div>
+ </div>
+
+ <p class="alert alert-warn">
+ <?= _t('conf.archiving.policy_warning') ?>
+ </p>
+
+ <div class="form-group">
+ <label class="group-name"><?= _t('conf.archiving.policy') ?><br /><small>(<?= _t('gen.short.by_default') ?>)</small></label>
+ <div class="group-controls">
+ <label class="checkbox" for="enable_keep_max">
+ <input type="checkbox" name="enable_keep_max" id="enable_keep_max" value="1"<?= empty(FreshRSS_Context::$user_conf->archiving['keep_max']) ? '' : ' checked="checked"' ?> data-leave-validation="<?= empty(FreshRSS_Context::$user_conf->archiving['keep_max']) ? 0 : 1 ?>"/>
+ <?= _t('conf.archiving.keep_max') ?>
+ <?php $keepMax = empty(FreshRSS_Context::$user_conf->archiving['keep_max']) ? 200 : FreshRSS_Context::$user_conf->archiving['keep_max']; ?>
+ <input type="number" id="keep_max" name="keep_max" min="0" value="<?= $keepMax ?>" data-leave-validation="<?= $keepMax ?>"/>
+ </label>
+ </div>
+ </div>
+
+ <div class="form-group">
+ <div class="group-controls">
+ <label class="checkbox" for="enable_keep_period">
+ <input type="checkbox" name="enable_keep_period" id="enable_keep_period" value="1"<?= FreshRSS_Context::$user_conf->volatile['enable_keep_period'] ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->volatile['enable_keep_period'] ? 1 : 0 ?>"/>
+ <?= _t('conf.archiving.keep_period') ?>
+ <input type="number" id="keep_period_count" name="keep_period_count" min="0" value="<?= FreshRSS_Context::$user_conf->volatile['keep_period_count'] ?>" data-leave-validation="<?= FreshRSS_Context::$user_conf->volatile['keep_period_count'] ?>"/>
+ <select class="number" name="keep_period_unit" id="keep_period_unit" data-leave-validation="<?= FreshRSS_Context::$user_conf->volatile['keep_period_unit'] ?>">
+ <option></option>
+ <option value="P1Y" <?= 'P1Y' === FreshRSS_Context::$user_conf->volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.years') ?></option>
+ <option value="P1M" <?= 'P1M' === FreshRSS_Context::$user_conf->volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.months') ?></option>
+ <option value="P1W" <?= 'P1W' === FreshRSS_Context::$user_conf->volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.weeks') ?></option>
+ <option value="P1D" <?= 'P1D' === FreshRSS_Context::$user_conf->volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.days') ?></option>
+ <option value="PT1H" <?= 'PT1H' === FreshRSS_Context::$user_conf->volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.hours') ?></option>
+ </select>
+ </label>
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label class="group-name"><?= _t('conf.archiving.exception') ?><br /><small>(<?= _t('gen.short.by_default') ?>)</small></label>
+ <div class="group-controls">
+ <label class="checkbox" for="keep_favourites">
+ <input type="checkbox" name="keep_favourites" id="keep_favourites" value="1"<?= FreshRSS_Context::$user_conf->archiving['keep_favourites'] !== false ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->archiving['keep_favourites'] !== false ? 1 : 0 ?>"/>
+ <?= _t('conf.archiving.keep_favourites') ?>
+ </label>
+ </div>
+ </div>
+
+ <div class="form-group">
+ <div class="group-controls">
+ <label class="checkbox" for="keep_labels">
+ <input type="checkbox" name="keep_labels" id="keep_labels" value="1"<?= FreshRSS_Context::$user_conf->archiving['keep_labels'] !== false ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->archiving['keep_labels'] !== false ? 1 : 0 ?>"/>
+ <?= _t('conf.archiving.keep_labels') ?>
+ </label>
+ </div>
+ </div>
+
+ <div class="form-group">
+ <div class="group-controls">
+ <label class="checkbox" for="keep_unreads">
+ <input type="checkbox" name="keep_unreads" id="keep_unreads" value="1"<?= FreshRSS_Context::$user_conf->archiving['keep_unreads'] ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->archiving['keep_unreads'] ? 1 : 0 ?>"/>
+ <?= _t('conf.archiving.keep_unreads') ?>
+ </label>
+ </div>
+ </div>
+
+ <div class="form-group">
+ <div class="group-controls">
+ <label for="keep_min_default"><?= _t('conf.archiving.keep_min_by_feed') ?>
+ <input type="number" id="keep_min_default" name="keep_min_default" min="0" value="<?= FreshRSS_Context::$user_conf->archiving['keep_min'] ?>" data-leave-validation="<?= FreshRSS_Context::$user_conf->archiving['keep_min'] ?>">
+ </label>
</div>
</div>
<div class="form-group form-actions">
<div class="group-controls">
- <button type="submit" class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button>
- <button type="reset" class="btn"><?php echo _t('gen.action.cancel'); ?></button>
+ <button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button>
+ <button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button>
</div>
</div>
</form>
- <form method="post" action="<?php echo _url('entry', 'optimize'); ?>">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
- <legend><?php echo _t('conf.archiving.advanced'); ?></legend>
+ <legend><?= _t('conf.archiving.maintenance') ?></legend>
+ <form method="post" action="<?= _url('entry', 'purge') ?>">
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
<div class="form-group">
- <label class="group-name"><?php echo _t('conf.user.current'); ?></label>
+ <label class="group-name"><?= _t('conf.user.current') ?></label>
<div class="group-controls">
- <?php echo _t('conf.user.articles_and_size', format_number($this->nb_total), format_bytes($this->size_user)); ?>
+ <?= _t('conf.user.articles_and_size', format_number($this->nb_total), format_bytes($this->size_user)) ?>
</div>
</div>
- <?php if (FreshRSS_Auth::hasAccess('admin')) { ?>
<div class="form-group">
- <label class="group-name"><?php echo _t('conf.user.users'); ?></label>
<div class="group-controls">
- <?php echo format_bytes($this->size_total); ?>
+ <button type="submit" class="btn btn-important confirm"><?= _t('conf.archiving.purge_now') ?></button>
</div>
</div>
+ </form>
- <div class="form-group form-actions">
+ <form method="post" action="<?= _url('entry', 'optimize') ?>">
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
+ <div class="form-group">
<div class="group-controls">
<input type="hidden" name="optimiseDatabase" value="1" />
- <button type="submit" class="btn btn-important"><?php echo _t('conf.archiving.optimize'); ?></button>
- <?php echo _i('help'); ?> <?php echo _t('conf.archiving.optimize_help'); ?>
+ <button type="submit" class="btn btn-important"><?= _t('conf.archiving.optimize') ?></button>
+ <?= _i('help') ?> <?= _t('conf.archiving.optimize_help') ?>
</div>
</div>
- <?php } ?>
</form>
+
+ <?php if (FreshRSS_Auth::hasAccess('admin')): ?>
+ <div class="form-group">
+ <label class="group-name"><?= _t('conf.user.users') ?></label>
+ <div class="group-controls">
+ <?= format_bytes($this->size_total) ?>
+ </div>
+ </div>
+ <?php endif; ?>
</div>
diff --git a/app/views/configure/display.phtml b/app/views/configure/display.phtml
index 58c4e219a..c1cfecc2a 100644
--- a/app/views/configure/display.phtml
+++ b/app/views/configure/display.phtml
@@ -1,47 +1,47 @@
<?php $this->partial('aside_configure'); ?>
<div class="post">
- <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
+ <a href="<?= _url('index', 'index') ?>"><?= _t('gen.action.back_to_rss_feeds') ?></a>
- <form method="post" action="<?php echo _url('configure', 'display'); ?>">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
- <legend><?php echo _t('conf.display'); ?></legend>
+ <form method="post" action="<?= _url('configure', 'display') ?>">
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
+ <legend><?= _t('conf.display') ?></legend>
<div class="form-group">
- <label class="group-name" for="language"><?php echo _t('conf.display.language'); ?></label>
+ <label class="group-name" for="language"><?= _t('conf.display.language') ?></label>
<div class="group-controls">
- <select name="language" id="language" data-leave-validation="<?php echo FreshRSS_Context::$user_conf->language; ?>">
+ <select name="language" id="language" data-leave-validation="<?= FreshRSS_Context::$user_conf->language ?>">
<?php $languages = Minz_Translate::availableLanguages(); ?>
<?php foreach ($languages as $lang) { ?>
- <option value="<?php echo $lang; ?>"<?php echo FreshRSS_Context::$user_conf->language === $lang ? ' selected="selected"' : ''; ?>><?php echo _t('gen.lang.' . $lang); ?></option>
+ <option value="<?= $lang ?>"<?= FreshRSS_Context::$user_conf->language === $lang ? ' selected="selected"' : '' ?>><?= _t('gen.lang.' . $lang) ?></option>
<?php } ?>
</select>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="theme"><?php echo _t('conf.display.theme'); ?></label>
+ <label class="group-name" for="theme"><?= _t('conf.display.theme') ?></label>
<div class="group-controls">
<ul class="slides">
<?php $slides = count($this->themes); $i = 1; ?>
<?php foreach($this->themes as $theme) { ?>
- <input type="radio" name="theme" id="img-<?php echo $i ?>" <?php if (FreshRSS_Context::$user_conf->theme === $theme['id']) {echo "checked";}?> value="<?php echo $theme['id'] ?>" data-leave-validation="<?php echo (FreshRSS_Context::$user_conf->theme === $theme['id']) ? 1 : 0; ?>"/>
+ <input type="radio" name="theme" id="img-<?= $i ?>" <?php if (FreshRSS_Context::$user_conf->theme === $theme['id']) {echo "checked";}?> value="<?= $theme['id'] ?>" data-leave-validation="<?= (FreshRSS_Context::$user_conf->theme === $theme['id']) ? 1 : 0 ?>"/>
<li class="slide-container">
<div class="slide">
- <img src="<?php echo Minz_Url::display('/themes/' . $theme['id'] . '/thumbs/original.png')?>"/>
+ <img src="<?= Minz_Url::display('/themes/' . $theme['id'] . '/thumbs/original.png') ?>"/>
</div>
<div class="nav">
<?php if ($i !== 1) {?>
- <label for="img-<?php echo $i - 1 ?>" class="prev">&#x2039;</label>
+ <label for="img-<?= $i - 1 ?>" class="prev">&#x2039;</label>
<?php } ?>
<?php if ($i !== $slides) {?>
- <label for="img-<?php echo $i + 1 ?>" class="next">&#x203a;</label>
+ <label for="img-<?= $i + 1 ?>" class="next">&#x203a;</label>
<?php } ?>
</div>
<div class="properties">
- <div><?php echo sprintf('%s — %s %s', $theme['name'], _t('gen.short.by_author'), $theme['author']); ?></div>
- <div><?php echo $theme['description'] ?></div>
- <div class="page-number"><?php echo sprintf('%d/%d', $i, $slides) ?></div>
+ <div><?= sprintf('%s — %s %s', $theme['name'], _t('gen.short.by_author'), $theme['author']) ?></div>
+ <div><?= $theme['description'] ?></div>
+ <div class="page-number"><?= sprintf('%d/%d', $i, $slides) ?></div>
</div>
</li>
<?php $i++ ?>
@@ -52,81 +52,84 @@
<?php $width = FreshRSS_Context::$user_conf->content_width; ?>
<div class="form-group">
- <label class="group-name" for="content_width"><?php echo _t('conf.display.width.content'); ?></label>
+ <label class="group-name" for="content_width"><?= _t('conf.display.width.content') ?></label>
<div class="group-controls">
- <select name="content_width" id="content_width" required="" data-leave-validation="<?php echo $width; ?>">
- <option value="thin" <?php echo $width === 'thin'? 'selected="selected"' : ''; ?>>
- <?php echo _t('conf.display.width.thin'); ?>
+ <select name="content_width" id="content_width" required="" data-leave-validation="<?= $width ?>">
+ <option value="thin" <?= $width === 'thin'? 'selected="selected"' : '' ?>>
+ <?= _t('conf.display.width.thin') ?>
</option>
- <option value="medium" <?php echo $width === 'medium'? 'selected="selected"' : ''; ?>>
- <?php echo _t('conf.display.width.medium'); ?>
+ <option value="medium" <?= $width === 'medium'? 'selected="selected"' : '' ?>>
+ <?= _t('conf.display.width.medium') ?>
</option>
- <option value="large" <?php echo $width === 'large'? 'selected="selected"' : ''; ?>>
- <?php echo _t('conf.display.width.large'); ?>
+ <option value="large" <?= $width === 'large'? 'selected="selected"' : '' ?>>
+ <?= _t('conf.display.width.large') ?>
</option>
- <option value="no_limit" <?php echo $width === 'no_limit'? 'selected="selected"' : ''; ?>>
- <?php echo _t('conf.display.width.no_limit'); ?>
+ <option value="no_limit" <?= $width === 'no_limit'? 'selected="selected"' : '' ?>>
+ <?= _t('conf.display.width.no_limit') ?>
</option>
</select>
</div>
</div>
<div class="form-group">
- <label class="group-name"><?php echo _t('conf.display.icon.entry'); ?></label>
+ <label class="group-name"><?= _t('conf.display.icon.entry') ?></label>
<table>
<thead>
<tr>
<th> </th>
- <th title="<?php echo _t('gen.action.mark_read'); ?>"><?php echo _i('read'); ?></th>
- <th title="<?php echo _t('gen.action.mark_favorite'); ?>"><?php echo _i('bookmark'); ?></th>
- <th><?php echo _t('conf.display.icon.related_tags'); ?></th>
- <th><?php echo _t('conf.display.icon.sharing'); ?></th>
- <th><?php echo _t('conf.display.icon.publication_date'); ?></th>
- <th><?php echo _i('link'); ?></th>
+ <th title="<?= _t('gen.action.mark_read') ?>"><?= _i('read') ?></th>
+ <th title="<?= _t('gen.action.mark_favorite') ?>"><?= _i('bookmark') ?></th>
+ <th><?= _t('conf.display.icon.related_tags') ?></th>
+ <th><?= _t('conf.display.icon.sharing') ?></th>
+ <th><?= _t('conf.display.icon.display_authors') ?></th>
+ <th><?= _t('conf.display.icon.publication_date') ?></th>
+ <th><?= _i('link') ?></th>
</tr>
</thead>
<tbody>
<tr>
- <th><?php echo _t('conf.display.icon.top_line'); ?></th>
- <td><input type="checkbox" name="topline_read" value="1"<?php echo FreshRSS_Context::$user_conf->topline_read ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->topline_read; ?>"/></td>
- <td><input type="checkbox" name="topline_favorite" value="1"<?php echo FreshRSS_Context::$user_conf->topline_favorite ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->topline_favorite; ?>"/></td>
+ <th><?= _t('conf.display.icon.top_line') ?></th>
+ <td><input type="checkbox" name="topline_read" value="1"<?= FreshRSS_Context::$user_conf->topline_read ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->topline_read ?>"/></td>
+ <td><input type="checkbox" name="topline_favorite" value="1"<?= FreshRSS_Context::$user_conf->topline_favorite ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->topline_favorite ?>"/></td>
<td><input type="checkbox" disabled="disabled" /></td>
<td><input type="checkbox" disabled="disabled" /></td>
- <td><input type="checkbox" name="topline_date" value="1"<?php echo FreshRSS_Context::$user_conf->topline_date ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->topline_date; ?>"/></td>
- <td><input type="checkbox" name="topline_link" value="1"<?php echo FreshRSS_Context::$user_conf->topline_link ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->topline_link; ?>"/></td>
+ <td><input type="checkbox" name="topline_display_authors" value="1"<?= FreshRSS_Context::$user_conf->topline_display_authors ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->topline_display_authors ?>"/></td>
+ <td><input type="checkbox" name="topline_date" value="1"<?= FreshRSS_Context::$user_conf->topline_date ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->topline_date ?>"/></td>
+ <td><input type="checkbox" name="topline_link" value="1"<?= FreshRSS_Context::$user_conf->topline_link ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->topline_link ?>"/></td>
</tr><tr>
- <th><?php echo _t('conf.display.icon.bottom_line'); ?></th>
- <td><input type="checkbox" name="bottomline_read" value="1"<?php echo FreshRSS_Context::$user_conf->bottomline_read ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->bottomline_read; ?>"/></td>
- <td><input type="checkbox" name="bottomline_favorite" value="1"<?php echo FreshRSS_Context::$user_conf->bottomline_favorite ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->bottomline_favorite; ?>"/></td>
- <td><input type="checkbox" name="bottomline_tags" value="1"<?php echo FreshRSS_Context::$user_conf->bottomline_tags ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->bottomline_tags; ?>"/></td>
- <td><input type="checkbox" name="bottomline_sharing" value="1"<?php echo FreshRSS_Context::$user_conf->bottomline_sharing ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->bottomline_sharing; ?>"/></td>
- <td><input type="checkbox" name="bottomline_date" value="1"<?php echo FreshRSS_Context::$user_conf->bottomline_date ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->bottomline_date; ?>"/></td>
- <td><input type="checkbox" name="bottomline_link" value="1"<?php echo FreshRSS_Context::$user_conf->bottomline_link ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->bottomline_link; ?>"/></td>
+ <th><?= _t('conf.display.icon.bottom_line') ?></th>
+ <td><input type="checkbox" name="bottomline_read" value="1"<?= FreshRSS_Context::$user_conf->bottomline_read ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->bottomline_read ?>"/></td>
+ <td><input type="checkbox" name="bottomline_favorite" value="1"<?= FreshRSS_Context::$user_conf->bottomline_favorite ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->bottomline_favorite ?>"/></td>
+ <td><input type="checkbox" name="bottomline_tags" value="1"<?= FreshRSS_Context::$user_conf->bottomline_tags ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->bottomline_tags ?>"/></td>
+ <td><input type="checkbox" name="bottomline_sharing" value="1"<?= FreshRSS_Context::$user_conf->bottomline_sharing ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->bottomline_sharing ?>"/></td>
+ <td><input type="checkbox" disabled="disabled" /></td>
+ <td><input type="checkbox" name="bottomline_date" value="1"<?= FreshRSS_Context::$user_conf->bottomline_date ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->bottomline_date ?>"/></td>
+ <td><input type="checkbox" name="bottomline_link" value="1"<?= FreshRSS_Context::$user_conf->bottomline_link ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->bottomline_link ?>"/></td>
</tr>
</tbody>
</table><br />
</div>
<div class="form-group">
- <label class="group-name" for="html5_notif_timeout"><?php echo _t('conf.display.notif_html5.timeout'); ?></label>
+ <label class="group-name" for="html5_notif_timeout"><?= _t('conf.display.notif_html5.timeout') ?></label>
<div class="group-controls">
- <input type="number" id="html5_notif_timeout" name="html5_notif_timeout" value="<?php echo FreshRSS_Context::$user_conf->html5_notif_timeout; ?>" data-leave-validation="<?php echo FreshRSS_Context::$user_conf->html5_notif_timeout; ?>"/> <?php echo _t('conf.display.notif_html5.seconds'); ?>
+ <input type="number" id="html5_notif_timeout" name="html5_notif_timeout" value="<?= FreshRSS_Context::$user_conf->html5_notif_timeout ?>" data-leave-validation="<?= FreshRSS_Context::$user_conf->html5_notif_timeout ?>"/> <?= _t('conf.display.notif_html5.seconds') ?>
</div>
</div>
<div class="form-group">
<div class="group-controls">
<label class="checkbox" for="show_nav_buttons">
- <input type="checkbox" name="show_nav_buttons" id="show_nav_buttons" value="1"<?php echo FreshRSS_Context::$user_conf->show_nav_buttons ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->show_nav_buttons; ?>"/>
- <?php echo _t('conf.display.show_nav_buttons'); ?>
+ <input type="checkbox" name="show_nav_buttons" id="show_nav_buttons" value="1"<?= FreshRSS_Context::$user_conf->show_nav_buttons ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->show_nav_buttons ?>"/>
+ <?= _t('conf.display.show_nav_buttons') ?>
</label>
</div>
</div>
<div class="form-group form-actions">
<div class="group-controls">
- <button type="submit" class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button>
- <button type="reset" class="btn"><?php echo _t('gen.action.cancel'); ?></button>
+ <button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button>
+ <button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button>
</div>
</div>
</form>
diff --git a/app/views/configure/queries.phtml b/app/views/configure/queries.phtml
index baaf74954..a0f600b5d 100644
--- a/app/views/configure/queries.phtml
+++ b/app/views/configure/queries.phtml
@@ -1,70 +1,70 @@
<?php $this->partial('aside_configure'); ?>
<div class="post">
- <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
+ <a href="<?= _url('index', 'index') ?>"><?= _t('gen.action.back_to_rss_feeds') ?></a>
- <form method="post" action="<?php echo _url('configure', 'queries'); ?>">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
- <legend><?php echo _t('conf.query'); ?></legend>
+ <form method="post" action="<?= _url('configure', 'queries') ?>">
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
+ <legend><?= _t('conf.query') ?></legend>
<?php foreach ($this->queries as $key => $query) { ?>
- <div class="form-group" id="query-group-<?php echo $key; ?>">
- <label class="group-name" for="queries_<?php echo $key; ?>_name">
- <?php echo _t('conf.query.number', $key + 1); ?>
+ <div class="form-group" id="query-group-<?= $key ?>">
+ <label class="group-name" for="queries_<?= $key ?>_name">
+ <?= _t('conf.query.number', $key + 1) ?>
</label>
<div class="group-controls">
- <input type="hidden" id="queries_<?php echo $key; ?>_url" name="queries[<?php echo $key; ?>][url]" value="<?php echo $query->getUrl(); ?>"/>
- <input type="hidden" id="queries_<?php echo $key; ?>_search" name="queries[<?php echo $key; ?>][search]" value="<?php echo $query->getSearch(); ?>"/>
- <input type="hidden" id="queries_<?php echo $key; ?>_state" name="queries[<?php echo $key; ?>][state]" value="<?php echo $query->getState(); ?>"/>
- <input type="hidden" id="queries_<?php echo $key; ?>_order" name="queries[<?php echo $key; ?>][order]" value="<?php echo $query->getOrder(); ?>"/>
- <input type="hidden" id="queries_<?php echo $key; ?>_get" name="queries[<?php echo $key; ?>][get]" value="<?php echo $query->getGet(); ?>"/>
+ <input type="hidden" id="queries_<?= $key ?>_url" name="queries[<?= $key ?>][url]" value="<?= $query->getUrl() ?>"/>
+ <input type="hidden" id="queries_<?= $key ?>_search" name="queries[<?= $key ?>][search]" value="<?= $query->getSearch() ?>"/>
+ <input type="hidden" id="queries_<?= $key ?>_state" name="queries[<?= $key ?>][state]" value="<?= $query->getState() ?>"/>
+ <input type="hidden" id="queries_<?= $key ?>_order" name="queries[<?= $key ?>][order]" value="<?= $query->getOrder() ?>"/>
+ <input type="hidden" id="queries_<?= $key ?>_get" name="queries[<?= $key ?>][get]" value="<?= $query->getGet() ?>"/>
<div class="stick">
<input class="extend"
type="text"
- id="queries_<?php echo $key; ?>_name"
- name="queries[<?php echo $key; ?>][name]"
- value="<?php echo $query->getName(); ?>"
- data-leave-validation="<?php echo $query->getName(); ?>"
+ id="queries_<?= $key ?>_name"
+ name="queries[<?= $key ?>][name]"
+ value="<?= $query->getName() ?>"
+ data-leave-validation="<?= $query->getName() ?>"
/>
- <a class="btn" href="<?php echo $query->getUrl(); ?>" title="<?php echo _t('conf.query.display'); ?>">
- <?php echo _i('link'); ?>
+ <a class="btn" href="<?= $query->getUrl() ?>" title="<?= _t('conf.query.display') ?>">
+ <?= _i('link') ?>
</a>
- <a class="btn btn-attention remove" href="#" data-remove="query-group-<?php echo $key; ?>" title="<?php echo _t('conf.query.remove'); ?>">
- <?php echo _i('close'); ?>
+ <a class="btn btn-attention remove" href="#" data-remove="query-group-<?= $key ?>" title="<?= _t('conf.query.remove') ?>">
+ <?= _i('close') ?>
</a>
</div>
<?php if (!$query->hasParameters()) { ?>
<div class="alert alert-warn">
- <div class="alert-head"><?php echo _t('conf.query.no_filter'); ?></div>
+ <div class="alert-head"><?= _t('conf.query.no_filter') ?></div>
</div>
<?php } elseif ($query->isDeprecated()) { ?>
<div class="alert alert-error">
- <div class="alert-head"><?php echo _t('conf.query.deprecated'); ?></div>
+ <div class="alert-head"><?= _t('conf.query.deprecated') ?></div>
</div>
<?php } else { ?>
<div class="alert alert-success">
- <div class="alert-head"><?php echo _t('conf.query.filter'); ?></div>
+ <div class="alert-head"><?= _t('conf.query.filter') ?></div>
<ul>
<?php if ($query->hasSearch()) { ?>
- <li class="item"><?php echo _t('conf.query.search', $query->getSearch()->getRawInput()); ?></li>
+ <li class="item"><?= _t('conf.query.search', $query->getSearch()->getRawInput()) ?></li>
<?php } ?>
<?php if ($query->getState()) { ?>
- <li class="item"><?php echo _t('conf.query.state_' . $query->getState()); ?></li>
+ <li class="item"><?= _t('conf.query.state_' . $query->getState()) ?></li>
<?php } ?>
<?php if ($query->getOrder()) { ?>
- <li class="item"><?php echo _t('conf.query.order_' . strtolower($query->getOrder())); ?></li>
+ <li class="item"><?= _t('conf.query.order_' . strtolower($query->getOrder())) ?></li>
<?php } ?>
<?php if ($query->getGet()) { ?>
- <li class="item"><?php echo _t('conf.query.get_' . $query->getGetType(), $query->getGetName()); ?></li>
+ <li class="item"><?= _t('conf.query.get_' . $query->getGetType(), $query->getGetName()) ?></li>
<?php } ?>
</ul>
</div>
@@ -76,12 +76,12 @@
<?php if (count(FreshRSS_Context::$user_conf->queries) > 0) { ?>
<div class="form-group form-actions">
<div class="group-controls">
- <button type="submit" class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button>
- <button type="reset" class="btn"><?php echo _t('gen.action.cancel'); ?></button>
+ <button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button>
+ <button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button>
</div>
</div>
<?php } else { ?>
- <p class="alert alert-warn"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('conf.query.none'); ?></p>
+ <p class="alert alert-warn"><span class="alert-head"><?= _t('gen.short.damn') ?></span> <?= _t('conf.query.none') ?></p>
<?php } ?>
</form>
diff --git a/app/views/configure/reading.phtml b/app/views/configure/reading.phtml
index ebb00c97b..7c42b59f1 100644
--- a/app/views/configure/reading.phtml
+++ b/app/views/configure/reading.phtml
@@ -1,48 +1,48 @@
<?php $this->partial('aside_configure'); ?>
<div class="post">
- <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
+ <a href="<?= _url('index', 'index') ?>"><?= _t('gen.action.back_to_rss_feeds') ?></a>
- <form method="post" action="<?php echo _url('configure', 'reading'); ?>">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
- <legend><?php echo _t('conf.reading'); ?></legend>
+ <form method="post" action="<?= _url('configure', 'reading') ?>">
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
+ <legend><?= _t('conf.reading') ?></legend>
<div class="form-group">
- <label class="group-name" for="posts_per_page"><?php echo _t('conf.reading.articles_per_page'); ?></label>
+ <label class="group-name" for="posts_per_page"><?= _t('conf.reading.articles_per_page') ?></label>
<div class="group-controls">
- <input type="number" id="posts_per_page" name="posts_per_page" value="<?php echo FreshRSS_Context::$user_conf->posts_per_page; ?>" min="5" max="500" data-leave-validation="<?php echo FreshRSS_Context::$user_conf->posts_per_page; ?>"/>
- <?php echo _i('help'); ?> <?php echo _t('conf.reading.number_divided_when_reader'); ?>
+ <input type="number" id="posts_per_page" name="posts_per_page" value="<?= FreshRSS_Context::$user_conf->posts_per_page ?>" min="5" max="500" data-leave-validation="<?= FreshRSS_Context::$user_conf->posts_per_page ?>"/>
+ <?= _i('help') ?> <?= _t('conf.reading.number_divided_when_reader') ?>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="sort_order"><?php echo _t('conf.reading.sort'); ?></label>
+ <label class="group-name" for="sort_order"><?= _t('conf.reading.sort') ?></label>
<div class="group-controls">
- <select name="sort_order" id="sort_order" data-leave-validation="<?php echo FreshRSS_Context::$user_conf->sort_order; ?>">
- <option value="DESC"<?php echo FreshRSS_Context::$user_conf->sort_order === 'DESC' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.sort.newer_first'); ?></option>
- <option value="ASC"<?php echo FreshRSS_Context::$user_conf->sort_order === 'ASC' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.sort.older_first'); ?></option>
+ <select name="sort_order" id="sort_order" data-leave-validation="<?= FreshRSS_Context::$user_conf->sort_order ?>">
+ <option value="DESC"<?= FreshRSS_Context::$user_conf->sort_order === 'DESC' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.sort.newer_first') ?></option>
+ <option value="ASC"<?= FreshRSS_Context::$user_conf->sort_order === 'ASC' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.sort.older_first') ?></option>
</select>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="view_mode"><?php echo _t('conf.reading.view.default'); ?></label>
+ <label class="group-name" for="view_mode"><?= _t('conf.reading.view.default') ?></label>
<div class="group-controls">
- <select name="view_mode" id="view_mode" data-leave-validation="<?php echo FreshRSS_Context::$user_conf->view_mode; ?>">
- <option value="normal"<?php echo FreshRSS_Context::$user_conf->view_mode === 'normal' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.view.normal'); ?></option>
- <option value="reader"<?php echo FreshRSS_Context::$user_conf->view_mode === 'reader' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.view.reader'); ?></option>
- <option value="global"<?php echo FreshRSS_Context::$user_conf->view_mode === 'global' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.view.global'); ?></option>
+ <select name="view_mode" id="view_mode" data-leave-validation="<?= FreshRSS_Context::$user_conf->view_mode ?>">
+ <option value="normal"<?= FreshRSS_Context::$user_conf->view_mode === 'normal' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.view.normal') ?></option>
+ <option value="reader"<?= FreshRSS_Context::$user_conf->view_mode === 'reader' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.view.reader') ?></option>
+ <option value="global"<?= FreshRSS_Context::$user_conf->view_mode === 'global' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.view.global') ?></option>
</select>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="view_mode"><?php echo _t('conf.reading.show'); ?></label>
+ <label class="group-name" for="view_mode"><?= _t('conf.reading.show') ?></label>
<div class="group-controls">
- <select name="default_view" id="default_view" data-leave-validation="<?php echo FreshRSS_Context::$user_conf->default_view; ?>">
- <option value="adaptive"<?php echo FreshRSS_Context::$user_conf->default_view === 'adaptive' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.show.adaptive'); ?></option>
- <option value="all"<?php echo FreshRSS_Context::$user_conf->default_view === 'all' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.show.all_articles'); ?></option>
- <option value="unread"<?php echo FreshRSS_Context::$user_conf->default_view === 'unread' ? ' selected="selected"' : ''; ?>><?php echo _t('conf.reading.show.unread'); ?></option>
+ <select name="default_view" id="default_view" data-leave-validation="<?= FreshRSS_Context::$user_conf->default_view ?>">
+ <option value="adaptive"<?= FreshRSS_Context::$user_conf->default_view === 'adaptive' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.show.adaptive') ?></option>
+ <option value="all"<?= FreshRSS_Context::$user_conf->default_view === 'all' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.show.all_articles') ?></option>
+ <option value="unread"<?= FreshRSS_Context::$user_conf->default_view === 'unread' ? ' selected="selected"' : '' ?>><?= _t('conf.reading.show.unread') ?></option>
</select>
</div>
</div>
@@ -50,8 +50,8 @@
<div class="form-group">
<div class="group-controls">
<label class="checkbox" for="hide_read_feeds">
- <input type="checkbox" name="hide_read_feeds" id="hide_read_feeds" value="1"<?php echo FreshRSS_Context::$user_conf->hide_read_feeds ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->hide_read_feeds; ?>"/>
- <?php echo _t('conf.reading.hide_read_feeds'); ?>
+ <input type="checkbox" name="hide_read_feeds" id="hide_read_feeds" value="1"<?= FreshRSS_Context::$user_conf->hide_read_feeds ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->hide_read_feeds ?>"/>
+ <?= _t('conf.reading.hide_read_feeds') ?>
</label>
</div>
</div>
@@ -59,9 +59,9 @@
<div class="form-group">
<div class="group-controls">
<label class="checkbox" for="display_posts">
- <input type="checkbox" name="display_posts" id="display_posts" value="1"<?php echo FreshRSS_Context::$user_conf->display_posts ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->display_posts; ?>"/>
- <?php echo _t('conf.reading.display_articles_unfolded'); ?>
- <noscript> — <strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript>
+ <input type="checkbox" name="display_posts" id="display_posts" value="1"<?= FreshRSS_Context::$user_conf->display_posts ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->display_posts ?>"/>
+ <?= _t('conf.reading.display_articles_unfolded') ?>
+ <noscript> — <strong><?= _t('gen.js.should_be_activated') ?></strong></noscript>
</label>
</div>
</div>
@@ -69,9 +69,9 @@
<div class="form-group">
<div class="group-controls">
<label class="checkbox" for="display_categories">
- <input type="checkbox" name="display_categories" id="display_categories" value="1"<?php echo FreshRSS_Context::$user_conf->display_categories ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->display_categories; ?>"/>
- <?php echo _t('conf.reading.display_categories_unfolded'); ?>
- <noscript> — <strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript>
+ <input type="checkbox" name="display_categories" id="display_categories" value="1"<?= FreshRSS_Context::$user_conf->display_categories ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->display_categories ?>"/>
+ <?= _t('conf.reading.display_categories_unfolded') ?>
+ <noscript> — <strong><?= _t('gen.js.should_be_activated') ?></strong></noscript>
</label>
</div>
</div>
@@ -79,9 +79,9 @@
<div class="form-group">
<div class="group-controls">
<label class="checkbox" for="sticky_post">
- <input type="checkbox" name="sticky_post" id="sticky_post" value="1"<?php echo FreshRSS_Context::$user_conf->sticky_post ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->sticky_post; ?>"/>
- <?php echo _t('conf.reading.sticky_post'); ?>
- <noscript> — <strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript>
+ <input type="checkbox" name="sticky_post" id="sticky_post" value="1"<?= FreshRSS_Context::$user_conf->sticky_post ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->sticky_post ?>"/>
+ <?= _t('conf.reading.sticky_post') ?>
+ <noscript> — <strong><?= _t('gen.js.should_be_activated') ?></strong></noscript>
</label>
</div>
</div>
@@ -89,9 +89,9 @@
<div class="form-group">
<div class="group-controls">
<label class="checkbox" for="auto_load_more">
- <input type="checkbox" name="auto_load_more" id="auto_load_more" value="1"<?php echo FreshRSS_Context::$user_conf->auto_load_more ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->auto_load_more; ?>"/>
- <?php echo _t('conf.reading.auto_load_more'); ?>
- <noscript> — <strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript>
+ <input type="checkbox" name="auto_load_more" id="auto_load_more" value="1"<?= FreshRSS_Context::$user_conf->auto_load_more ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->auto_load_more ?>"/>
+ <?= _t('conf.reading.auto_load_more') ?>
+ <noscript> — <strong><?= _t('gen.js.should_be_activated') ?></strong></noscript>
</label>
</div>
</div>
@@ -99,9 +99,9 @@
<div class="form-group">
<div class="group-controls">
<label class="checkbox" for="lazyload">
- <input type="checkbox" name="lazyload" id="lazyload" value="1"<?php echo FreshRSS_Context::$user_conf->lazyload ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->lazyload; ?>"/>
- <?php echo _t('conf.reading.img_with_lazyload'); ?>
- <noscript> — <strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript>
+ <input type="checkbox" name="lazyload" id="lazyload" value="1"<?= FreshRSS_Context::$user_conf->lazyload ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->lazyload ?>"/>
+ <?= _t('conf.reading.img_with_lazyload') ?>
+ <noscript> — <strong><?= _t('gen.js.should_be_activated') ?></strong></noscript>
</label>
</div>
</div>
@@ -109,9 +109,9 @@
<div class="form-group">
<div class="group-controls">
<label class="checkbox" for="sides_close_article">
- <input type="checkbox" name="sides_close_article" id="sides_close_article" value="1"<?php echo FreshRSS_Context::$user_conf->sides_close_article ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->sides_close_article; ?>"/>
- <?php echo _t('conf.reading.sides_close_article'); ?>
- <noscript> — <strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript>
+ <input type="checkbox" name="sides_close_article" id="sides_close_article" value="1"<?= FreshRSS_Context::$user_conf->sides_close_article ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->sides_close_article ?>"/>
+ <?= _t('conf.reading.sides_close_article') ?>
+ <noscript> — <strong><?= _t('gen.js.should_be_activated') ?></strong></noscript>
</label>
</div>
</div>
@@ -119,9 +119,9 @@
<div class="form-group">
<div class="group-controls">
<label class="checkbox" for="reading_confirm">
- <input type="checkbox" name="reading_confirm" id="reading_confirm" value="1"<?php echo FreshRSS_Context::$user_conf->reading_confirm ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->reading_confirm; ?>"/>
- <?php echo _t('conf.reading.confirm_enabled'); ?>
- <noscript> — <strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript>
+ <input type="checkbox" name="reading_confirm" id="reading_confirm" value="1"<?= FreshRSS_Context::$user_conf->reading_confirm ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->reading_confirm ?>"/>
+ <?= _t('conf.reading.confirm_enabled') ?>
+ <noscript> — <strong><?= _t('gen.js.should_be_activated') ?></strong></noscript>
</label>
</div>
</div>
@@ -129,9 +129,9 @@
<div class="form-group">
<div class="group-controls">
<label class="checkbox" for="auto_remove_article">
- <input type="checkbox" name="auto_remove_article" id="auto_remove_article" value="1"<?php echo FreshRSS_Context::$user_conf->auto_remove_article ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->auto_remove_article; ?>"/>
- <?php echo _t('conf.reading.auto_remove_article'); ?>
- <noscript> — <strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript>
+ <input type="checkbox" name="auto_remove_article" id="auto_remove_article" value="1"<?= FreshRSS_Context::$user_conf->auto_remove_article ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->auto_remove_article ?>"/>
+ <?= _t('conf.reading.auto_remove_article') ?>
+ <noscript> — <strong><?= _t('gen.js.should_be_activated') ?></strong></noscript>
</label>
</div>
</div>
@@ -139,48 +139,48 @@
<div class="form-group">
<div class="group-controls">
<label class="checkbox" for="mark_updated_article_unread">
- <input type="checkbox" name="mark_updated_article_unread" id="mark_updated_article_unread" value="1"<?php echo FreshRSS_Context::$user_conf->mark_updated_article_unread ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->mark_updated_article_unread; ?>"/>
- <?php echo _t('conf.reading.mark_updated_article_unread'); ?>
+ <input type="checkbox" name="mark_updated_article_unread" id="mark_updated_article_unread" value="1"<?= FreshRSS_Context::$user_conf->mark_updated_article_unread ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->mark_updated_article_unread ?>"/>
+ <?= _t('conf.reading.mark_updated_article_unread') ?>
</label>
</div>
</div>
<div class="form-group">
- <label class="group-name"><?php echo _t('conf.reading.read.when'); ?></label>
+ <label class="group-name"><?= _t('conf.reading.read.when') ?></label>
<div class="group-controls">
<label class="checkbox" for="check_open_article">
- <input type="checkbox" name="mark_open_article" id="check_open_article" value="1"<?php echo FreshRSS_Context::$user_conf->mark_when['article'] ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->mark_when['article']; ?>"/>
- <?php echo _t('conf.reading.read.article_viewed'); ?>
+ <input type="checkbox" name="mark_open_article" id="check_open_article" value="1"<?= FreshRSS_Context::$user_conf->mark_when['article'] ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->mark_when['article'] ?>"/>
+ <?= _t('conf.reading.read.article_viewed') ?>
</label>
<label class="checkbox" for="check_open_site">
- <input type="checkbox" name="mark_open_site" id="check_open_site" value="1"<?php echo FreshRSS_Context::$user_conf->mark_when['site'] ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->mark_when['site']; ?>"/>
- <?php echo _t('conf.reading.read.article_open_on_website'); ?>
+ <input type="checkbox" name="mark_open_site" id="check_open_site" value="1"<?= FreshRSS_Context::$user_conf->mark_when['site'] ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->mark_when['site'] ?>"/>
+ <?= _t('conf.reading.read.article_open_on_website') ?>
</label>
<label class="checkbox" for="check_scroll">
- <input type="checkbox" name="mark_scroll" id="check_scroll" value="1"<?php echo FreshRSS_Context::$user_conf->mark_when['scroll'] ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->mark_when['scroll']; ?>"/>
- <?php echo _t('conf.reading.read.scroll'); ?>
+ <input type="checkbox" name="mark_scroll" id="check_scroll" value="1"<?= FreshRSS_Context::$user_conf->mark_when['scroll'] ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->mark_when['scroll'] ?>"/>
+ <?= _t('conf.reading.read.scroll') ?>
</label>
<label class="checkbox" for="check_reception">
- <input type="checkbox" name="mark_upon_reception" id="check_reception" value="1"<?php echo FreshRSS_Context::$user_conf->mark_when['reception'] ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->mark_when['reception']; ?>"/>
- <?php echo _t('conf.reading.read.upon_reception'); ?>
+ <input type="checkbox" name="mark_upon_reception" id="check_reception" value="1"<?= FreshRSS_Context::$user_conf->mark_when['reception'] ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->mark_when['reception'] ?>"/>
+ <?= _t('conf.reading.read.upon_reception') ?>
</label>
</div>
</div>
<div class="form-group">
- <label class="group-name"><?php echo _t('conf.reading.after_onread'); ?></label>
+ <label class="group-name"><?= _t('conf.reading.after_onread') ?></label>
<div class="group-controls">
<label class="checkbox" for="onread_jump_next">
- <input type="checkbox" name="onread_jump_next" id="onread_jump_next" value="1"<?php echo FreshRSS_Context::$user_conf->onread_jump_next ? ' checked="checked"' : ''; ?> data-leave-validation="<?php echo FreshRSS_Context::$user_conf->onread_jump_next; ?>"/>
- <?php echo _t('conf.reading.jump_next'); ?>
+ <input type="checkbox" name="onread_jump_next" id="onread_jump_next" value="1"<?= FreshRSS_Context::$user_conf->onread_jump_next ? ' checked="checked"' : '' ?> data-leave-validation="<?= FreshRSS_Context::$user_conf->onread_jump_next ?>"/>
+ <?= _t('conf.reading.jump_next') ?>
</label>
</div>
</div>
<div class="form-group form-actions">
<div class="group-controls">
- <button type="submit" class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button>
- <button type="reset" class="btn"><?php echo _t('gen.action.cancel'); ?></button>
+ <button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button>
+ <button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button>
</div>
</div>
diff --git a/app/views/configure/sharing.phtml b/app/views/configure/sharing.phtml
index 026659007..32ef11716 100644
--- a/app/views/configure/sharing.phtml
+++ b/app/views/configure/sharing.phtml
@@ -1,48 +1,48 @@
<?php $this->partial('aside_configure'); ?>
<div class="post">
- <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
+ <a href="<?= _url('index', 'index') ?>"><?= _t('gen.action.back_to_rss_feeds') ?></a>
- <form method="post" action="<?php echo _url('configure', 'sharing'); ?>"
- data-simple='<div class="form-group" id="group-share-##key##"><label class="group-name">##label##</label><div class="group-controls"><div class="stick"><input type="text" id="share_##key##_name" name="share[##key##][name]" class="extend" value="##label##" placeholder="<?php echo _t('conf.sharing.share_name'); ?>" size="64" />
- <input type="url" id="share_##key##_url" name="share[##key##][url]" class="extend" value="" placeholder="<?php echo _t('gen.short.not_applicable'); ?>" size="64" disabled /><a href="#" class="remove btn btn-attention" data-remove="group-share-##key##"><?php echo _i('close'); ?></a></div>
+ <form method="post" action="<?= _url('configure', 'sharing') ?>"
+ data-simple='<div class="form-group" id="group-share-##key##"><label class="group-name">##label##</label><div class="group-controls"><div class="stick"><input type="text" id="share_##key##_name" name="share[##key##][name]" class="extend" value="##label##" placeholder="<?= _t('conf.sharing.share_name') ?>" size="64" />
+ <input type="url" id="share_##key##_url" name="share[##key##][url]" class="extend" value="" placeholder="<?= _t('gen.short.not_applicable') ?>" size="64" disabled /><a href="#" class="remove btn btn-attention" data-remove="group-share-##key##"><?= _i('close') ?></a></div>
<input type="hidden" id="share_##key##_type" name="share[##key##][type]" value="##type##" /></div></div>'
data-advanced='<div class="form-group" id="group-share-##key##"><label class="group-name">##label##</label><div class="group-controls">
<input type="hidden" id="share_##key##_type" name="share[##key##][type]" value="##type##" />
<input type="hidden" id="share_##key##_method" name="share[##key##][method]" value="##method##" />
<input type="hidden" id="share_##key##_field" name="share[##key##][field]" value="##field##" />
<div class="stick">
- <input type="text" id="share_##key##_name" name="share[##key##][name]" class="extend" value="" placeholder="<?php echo _t('conf.sharing.share_name'); ?>" size="64" />
- <input type="url" id="share_##key##_url" name="share[##key##][url]" class="extend" value="" placeholder="<?php echo _t('conf.sharing.share_url'); ?>" size="64" />
- <a href="#" class="remove btn btn-attention" data-remove="group-share-##key##" title="<?php echo _t('conf.sharing.remove'); ?>"><?php echo _i('close'); ?></a></div>
- <a target="_blank" rel="noreferrer" class="btn" title="<?php echo _t('conf.sharing.more_information'); ?>" href="##help##"><?php echo _i('help'); ?></a>
+ <input type="text" id="share_##key##_name" name="share[##key##][name]" class="extend" value="" placeholder="<?= _t('conf.sharing.share_name') ?>" size="64" />
+ <input type="url" id="share_##key##_url" name="share[##key##][url]" class="extend" value="" placeholder="<?= _t('conf.sharing.share_url') ?>" size="64" />
+ <a href="#" class="remove btn btn-attention" data-remove="group-share-##key##" title="<?= _t('conf.sharing.remove') ?>"><?= _i('close') ?></a></div>
+ <a target="_blank" rel="noreferrer" class="btn" title="<?= _t('conf.sharing.more_information') ?>" href="##help##"><?= _i('help') ?></a>
</div></div>'>
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
- <legend><?php echo _t('conf.sharing'); ?></legend>
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
+ <legend><?= _t('conf.sharing') ?></legend>
<?php
foreach (FreshRSS_Context::$user_conf->sharing as $key => $share_options) {
$share = FreshRSS_Share::get($share_options['type']);
$share->update($share_options);
?>
- <div class="form-group group-share" id="group-share-<?php echo $key; ?>">
+ <div class="form-group group-share" id="group-share-<?= $key ?>">
<label class="group-name">
- <?php echo $share->name(true); ?>
+ <?= $share->name(true) ?>
</label>
<div class="group-controls">
- <input type='hidden' id='share_<?php echo $key; ?>_type' name="share[<?php echo $key; ?>][type]" value='<?php echo $share->type(); ?>' />
- <input type='hidden' id='share_<?php echo $key; ?>_method' name="share[<?php echo $key; ?>][method]" value='<?php echo $share->method(); ?>' />
- <input type='hidden' id='share_<?php echo $key; ?>_field' name="share[<?php echo $key; ?>][field]" value='<?php echo $share->field(); ?>' />
+ <input type='hidden' id='share_<?= $key ?>_type' name="share[<?= $key ?>][type]" value='<?= $share->type() ?>' />
+ <input type='hidden' id='share_<?= $key ?>_method' name="share[<?= $key ?>][method]" value='<?= $share->method() ?>' />
+ <input type='hidden' id='share_<?= $key ?>_field' name="share[<?= $key ?>][field]" value='<?= $share->field() ?>' />
<div class="stick">
- <input type="text" id="share_<?php echo $key; ?>_name" name="share[<?php echo $key; ?>][name]" class="extend" value="<?php echo $share->name(); ?>" placeholder="<?php echo _t('conf.sharing.share_name'); ?>" size="64" data-leave-validation="<?php echo $share->name(); ?>"/>
+ <input type="text" id="share_<?= $key ?>_name" name="share[<?= $key ?>][name]" class="extend" value="<?= $share->name() ?>" placeholder="<?= _t('conf.sharing.share_name') ?>" size="64" data-leave-validation="<?= $share->name() ?>"/>
<?php if ($share->formType() === 'advanced') { ?>
- <input type="url" id="share_<?php echo $key; ?>_url" name="share[<?php echo $key; ?>][url]" class="extend" value="<?php echo $share->baseUrl(); ?>" placeholder="<?php echo _t('conf.sharing.share_url'); ?>" size="64" data-leave-validation="<?php echo $share->baseUrl(); ?>"/>
+ <input type="url" id="share_<?= $key ?>_url" name="share[<?= $key ?>][url]" class="extend" value="<?= $share->baseUrl() ?>" placeholder="<?= _t('conf.sharing.share_url') ?>" size="64" data-leave-validation="<?= $share->baseUrl() ?>"/>
<?php } else { ?>
- <input type="url" id="share_<?php echo $key; ?>_url" name="share[<?php echo $key; ?>][url]" class="extend" value="<?php echo $share->baseUrl(); ?>" placeholder="<?php echo _t('gen.short.not_applicable'); ?>" size="64" disabled/>
+ <input type="url" id="share_<?= $key ?>_url" name="share[<?= $key ?>][url]" class="extend" value="<?= $share->baseUrl() ?>" placeholder="<?= _t('gen.short.not_applicable') ?>" size="64" disabled/>
<?php } ?>
- <a href='#' class='remove btn btn-attention' data-remove="group-share-<?php echo $key; ?>" title="<?php echo _t('conf.sharing.remove'); ?>"><?php echo _i('close'); ?></a>
+ <a href='#' class='remove btn btn-attention' data-remove="group-share-<?= $key ?>" title="<?= _t('conf.sharing.remove') ?>"><?= _i('close') ?></a>
</div>
<?php if ($share->formType() === 'advanced') { ?>
- <a target="_blank" rel="noreferrer" class="btn" title="<?php echo _t('conf.sharing.more_information'); ?>" href="<?php echo $share->help(); ?>"><?php echo _i('help'); ?></a>
+ <a target="_blank" rel="noreferrer" class="btn" title="<?= _t('conf.sharing.more_information') ?>" href="<?= $share->help() ?>"><?= _i('help') ?></a>
<?php } ?>
</div>
</div>
@@ -52,19 +52,19 @@
<div class="group-controls">
<select>
<?php foreach (FreshRSS_Share::enum() as $share) { ?>
- <option value='<?php echo $share->type(); ?>' data-form='<?php echo $share->formType(); ?>' data-help='<?php echo $share->help(); ?>' data-method='<?php echo $share->method(); ?>' data-field='<?php echo $share->field(); ?>'>
- <?php echo $share->name(true); ?>
+ <option value='<?= $share->type() ?>' data-form='<?= $share->formType() ?>' data-help='<?= $share->help() ?>' data-method='<?= $share->method() ?>' data-field='<?= $share->field() ?>'>
+ <?= $share->name(true) ?>
</option>
<?php } ?>
</select>
- <a href='#' class='share add btn' title="<?php echo _t('conf.sharing.add'); ?>"><?php echo _i('add'); ?></a>
+ <a href='#' class='share add btn' title="<?= _t('conf.sharing.add') ?>"><?= _i('add') ?></a>
</div>
</div>
<div class="form-group form-actions">
<div class="group-controls">
- <button type="submit" class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button>
- <button type="reset" class="btn"><?php echo _t('gen.action.cancel'); ?></button>
+ <button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button>
+ <button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button>
</div>
</div>
</form>
diff --git a/app/views/configure/shortcut.phtml b/app/views/configure/shortcut.phtml
index 412ea676d..4412266cc 100644
--- a/app/views/configure/shortcut.phtml
+++ b/app/views/configure/shortcut.phtml
@@ -1,181 +1,181 @@
<?php $this->partial('aside_configure'); ?>
<div class="post">
- <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
+ <a href="<?= _url('index', 'index') ?>"><?= _t('gen.action.back_to_rss_feeds') ?></a>
<datalist id="keys">
<?php foreach ($this->list_keys as $key) { ?>
- <option value="<?php echo $key; ?>">
+ <option value="<?= $key ?>">
<?php } ?>
</datalist>
<?php $s = FreshRSS_Context::$user_conf->shortcuts; ?>
- <form method="post" action="<?php echo _url('configure', 'shortcut'); ?>">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
- <legend><?php echo _t('conf.shortcut'); ?></legend>
+ <form method="post" action="<?= _url('configure', 'shortcut') ?>">
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
+ <legend><?= _t('conf.shortcut') ?></legend>
- <noscript><p class="alert alert-error"><?php echo _t('conf.shortcut.javascript'); ?></p></noscript>
+ <noscript><p class="alert alert-error"><?= _t('conf.shortcut.javascript') ?></p></noscript>
- <legend><?php echo _t('conf.shortcut.views'); ?></legend>
+ <legend><?= _t('conf.shortcut.views') ?></legend>
<div class="form-group">
- <label class="group-name" for="normal_view_shortcut"><?php echo _t('conf.shortcut.normal_view'); ?></label>
+ <label class="group-name" for="normal_view_shortcut"><?= _t('conf.shortcut.normal_view') ?></label>
<div class="group-controls">
- <input type="text" id="normal_view_shortcut" name="shortcuts[normal_view]" list="keys" value="<?php echo $s['normal_view']; ?>" data-leave-validation="<?php echo $s['normal_view']; ?>"/>
+ <input type="text" id="normal_view_shortcut" name="shortcuts[normal_view]" list="keys" value="<?= $s['normal_view'] ?>" data-leave-validation="<?= $s['normal_view'] ?>"/>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="global_view_shortcut"><?php echo _t('conf.shortcut.global_view'); ?></label>
+ <label class="group-name" for="global_view_shortcut"><?= _t('conf.shortcut.global_view') ?></label>
<div class="group-controls">
- <input type="text" id="global_view_shortcut" name="shortcuts[global_view]" list="keys" value="<?php echo $s['global_view']; ?>" data-leave-validation="<?php echo $s['global_view']; ?>"/>
+ <input type="text" id="global_view_shortcut" name="shortcuts[global_view]" list="keys" value="<?= $s['global_view'] ?>" data-leave-validation="<?= $s['global_view'] ?>"/>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="reading_view_shortcut"><?php echo _t('conf.shortcut.reading_view'); ?></label>
+ <label class="group-name" for="reading_view_shortcut"><?= _t('conf.shortcut.reading_view') ?></label>
<div class="group-controls">
- <input type="text" id="reading_view_shortcut" name="shortcuts[reading_view]" list="keys" value="<?php echo $s['reading_view']; ?>" data-leave-validation="<?php echo $s['reading_view']; ?>"/>
+ <input type="text" id="reading_view_shortcut" name="shortcuts[reading_view]" list="keys" value="<?= $s['reading_view'] ?>" data-leave-validation="<?= $s['reading_view'] ?>"/>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="rss_view_shortcut"><?php echo _t('conf.shortcut.rss_view'); ?></label>
+ <label class="group-name" for="rss_view_shortcut"><?= _t('conf.shortcut.rss_view') ?></label>
<div class="group-controls">
- <input type="text" id="rss_view_shortcut" name="shortcuts[rss_view]" list="keys" value="<?php echo $s['rss_view']; ?>" data-leave-validation="<?php echo $s['rss_view']; ?>"/>
+ <input type="text" id="rss_view_shortcut" name="shortcuts[rss_view]" list="keys" value="<?= $s['rss_view'] ?>" data-leave-validation="<?= $s['rss_view'] ?>"/>
</div>
</div>
- <legend><?php echo _t('conf.shortcut.navigation'); ?></legend>
+ <legend><?= _t('conf.shortcut.navigation') ?></legend>
- <p class="alert alert-warn"><?php echo _t('conf.shortcut.navigation_help');?></p>
+ <p class="alert alert-warn"><?= _t('conf.shortcut.navigation_help') ?></p>
<div class="form-group">
- <label class="group-name" for="next_entry"><?php echo _t('conf.shortcut.next_article'); ?></label>
+ <label class="group-name" for="next_entry"><?= _t('conf.shortcut.next_article') ?></label>
<div class="group-controls">
- <input type="text" id="next_entry" name="shortcuts[next_entry]" list="keys" value="<?php echo $s['next_entry']; ?>" data-leave-validation="<?php echo $s['next_entry']; ?>"/>
+ <input type="text" id="next_entry" name="shortcuts[next_entry]" list="keys" value="<?= $s['next_entry'] ?>" data-leave-validation="<?= $s['next_entry'] ?>"/>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="prev_entry"><?php echo _t('conf.shortcut.previous_article'); ?></label>
+ <label class="group-name" for="prev_entry"><?= _t('conf.shortcut.previous_article') ?></label>
<div class="group-controls">
- <input type="text" id="prev_entry" name="shortcuts[prev_entry]" list="keys" value="<?php echo $s['prev_entry']; ?>" data-leave-validation="<?php echo $s['prev_entry']; ?>"/>
+ <input type="text" id="prev_entry" name="shortcuts[prev_entry]" list="keys" value="<?= $s['prev_entry'] ?>" data-leave-validation="<?= $s['prev_entry'] ?>"/>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="first_entry"><?php echo _t('conf.shortcut.first_article'); ?></label>
+ <label class="group-name" for="first_entry"><?= _t('conf.shortcut.first_article') ?></label>
<div class="group-controls">
- <input type="text" id="first_entry" name="shortcuts[first_entry]" list="keys" value="<?php echo $s['first_entry']; ?>" data-leave-validation="<?php echo $s['first_entry']; ?>"/>
+ <input type="text" id="first_entry" name="shortcuts[first_entry]" list="keys" value="<?= $s['first_entry'] ?>" data-leave-validation="<?= $s['first_entry'] ?>"/>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="last_entry"><?php echo _t('conf.shortcut.last_article'); ?></label>
+ <label class="group-name" for="last_entry"><?= _t('conf.shortcut.last_article') ?></label>
<div class="group-controls">
- <input type="text" id="last_entry" name="shortcuts[last_entry]" list="keys" value="<?php echo $s['last_entry']; ?>" data-leave-validation="<?php echo $s['last_entry']; ?>"/>
+ <input type="text" id="last_entry" name="shortcuts[last_entry]" list="keys" value="<?= $s['last_entry'] ?>" data-leave-validation="<?= $s['last_entry'] ?>"/>
</div>
</div>
- <p class="alert alert-warn"><?php echo _t('conf.shortcut.navigation_no_mod_help');?></p>
+ <p class="alert alert-warn"><?= _t('conf.shortcut.navigation_no_mod_help') ?></p>
<div class="form-group">
- <label class="group-name" for="skip_next_entry"><?php echo _t('conf.shortcut.skip_next_article'); ?></label>
+ <label class="group-name" for="skip_next_entry"><?= _t('conf.shortcut.skip_next_article') ?></label>
<div class="group-controls">
- <input type="text" id="skip_next_entry" name="shortcuts[skip_next_entry]" list="keys" value="<?php echo $s['skip_next_entry']; ?>" data-leave-validation="<?php echo $s['skip_next_entry']; ?>"/>
+ <input type="text" id="skip_next_entry" name="shortcuts[skip_next_entry]" list="keys" value="<?= $s['skip_next_entry'] ?>" data-leave-validation="<?= $s['skip_next_entry'] ?>"/>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="skip_prev_entry"><?php echo _t('conf.shortcut.skip_previous_article'); ?></label>
+ <label class="group-name" for="skip_prev_entry"><?= _t('conf.shortcut.skip_previous_article') ?></label>
<div class="group-controls">
- <input type="text" id="skip_prev_entry" name="shortcuts[skip_prev_entry]" list="keys" value="<?php echo $s['skip_prev_entry']; ?>" data-leave-validation="<?php echo $s['skip_prev_entry']; ?>"/>
+ <input type="text" id="skip_prev_entry" name="shortcuts[skip_prev_entry]" list="keys" value="<?= $s['skip_prev_entry'] ?>" data-leave-validation="<?= $s['skip_prev_entry'] ?>"/>
</div>
</div>
- <legend><?php echo _t('conf.shortcut.article_action');?></legend>
+ <legend><?= _t('conf.shortcut.article_action') ?></legend>
<div class="form-group">
- <label class="group-name" for="mark_read"><?php echo _t('conf.shortcut.mark_read'); ?></label>
+ <label class="group-name" for="mark_read"><?= _t('conf.shortcut.mark_read') ?></label>
<div class="group-controls">
- <input type="text" id="mark_read" name="shortcuts[mark_read]" list="keys" value="<?php echo $s['mark_read']; ?>" data-leave-validation="<?php echo $s['mark_read']; ?>"/>
- <?php echo _t('conf.shortcut.shift_for_all_read'); ?>
+ <input type="text" id="mark_read" name="shortcuts[mark_read]" list="keys" value="<?= $s['mark_read'] ?>" data-leave-validation="<?= $s['mark_read'] ?>"/>
+ <?= _t('conf.shortcut.shift_for_all_read') ?>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="mark_favorite"><?php echo _t('conf.shortcut.mark_favorite'); ?></label>
+ <label class="group-name" for="mark_favorite"><?= _t('conf.shortcut.mark_favorite') ?></label>
<div class="group-controls">
- <input type="text" id="mark_favorite" name="shortcuts[mark_favorite]" list="keys" value="<?php echo $s['mark_favorite']; ?>" data-leave-validation="<?php echo $s['mark_favorite']; ?>"/>
+ <input type="text" id="mark_favorite" name="shortcuts[mark_favorite]" list="keys" value="<?= $s['mark_favorite'] ?>" data-leave-validation="<?= $s['mark_favorite'] ?>"/>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="go_website"><?php echo _t('conf.shortcut.see_on_website'); ?></label>
+ <label class="group-name" for="go_website"><?= _t('conf.shortcut.see_on_website') ?></label>
<div class="group-controls">
- <input type="text" id="go_website" name="shortcuts[go_website]" list="keys" value="<?php echo $s['go_website']; ?>" data-leave-validation="<?php echo $s['go_website']; ?>"/>
+ <input type="text" id="go_website" name="shortcuts[go_website]" list="keys" value="<?= $s['go_website'] ?>" data-leave-validation="<?= $s['go_website'] ?>"/>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="auto_share_shortcut"><?php echo _t('conf.shortcut.auto_share'); ?></label>
+ <label class="group-name" for="auto_share_shortcut"><?= _t('conf.shortcut.auto_share') ?></label>
<div class="group-controls">
- <input type="text" id="auto_share_shortcut" name="shortcuts[auto_share]" list="keys" value="<?php echo $s['auto_share']; ?>" data-leave-validation="<?php echo $s['auto_share']; ?>"/>
- <?php echo _t('conf.shortcut.auto_share_help'); ?>
+ <input type="text" id="auto_share_shortcut" name="shortcuts[auto_share]" list="keys" value="<?= $s['auto_share'] ?>" data-leave-validation="<?= $s['auto_share'] ?>"/>
+ <?= _t('conf.shortcut.auto_share_help') ?>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="collapse_entry"><?php echo _t('conf.shortcut.collapse_article'); ?></label>
+ <label class="group-name" for="collapse_entry"><?= _t('conf.shortcut.collapse_article') ?></label>
<div class="group-controls">
- <input type="text" id="collapse_entry" name="shortcuts[collapse_entry]" list="keys" value="<?php echo $s['collapse_entry']; ?>" data-leave-validation="<?php echo $s['collapse_entry']; ?>"/>
+ <input type="text" id="collapse_entry" name="shortcuts[collapse_entry]" list="keys" value="<?= $s['collapse_entry'] ?>" data-leave-validation="<?= $s['collapse_entry'] ?>"/>
</div>
</div>
- <legend><?php echo _t('conf.shortcut.other_action');?></legend>
+ <legend><?= _t('conf.shortcut.other_action') ?></legend>
<div class="form-group">
- <label class="group-name" for="load_more_shortcut"><?php echo _t('conf.shortcut.load_more'); ?></label>
+ <label class="group-name" for="load_more_shortcut"><?= _t('conf.shortcut.load_more') ?></label>
<div class="group-controls">
- <input type="text" id="load_more_shortcut" name="shortcuts[load_more]" list="keys" value="<?php echo $s['load_more']; ?>" data-leave-validation="<?php echo $s['load_more']; ?>"/>
+ <input type="text" id="load_more_shortcut" name="shortcuts[load_more]" list="keys" value="<?= $s['load_more'] ?>" data-leave-validation="<?= $s['load_more'] ?>"/>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="focus_search_shortcut"><?php echo _t('conf.shortcut.focus_search'); ?></label>
+ <label class="group-name" for="focus_search_shortcut"><?= _t('conf.shortcut.focus_search') ?></label>
<div class="group-controls">
- <input type="text" id="focus_search_shortcut" name="shortcuts[focus_search]" list="keys" value="<?php echo $s['focus_search']; ?>" data-leave-validation="<?php echo $s['focus_search']; ?>"/>
+ <input type="text" id="focus_search_shortcut" name="shortcuts[focus_search]" list="keys" value="<?= $s['focus_search'] ?>" data-leave-validation="<?= $s['focus_search'] ?>"/>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="user_filter_shortcut"><?php echo _t('conf.shortcut.user_filter'); ?></label>
+ <label class="group-name" for="user_filter_shortcut"><?= _t('conf.shortcut.user_filter') ?></label>
<div class="group-controls">
- <input type="text" id="user_filter_shortcut" name="shortcuts[user_filter]" list="keys" value="<?php echo $s['user_filter']; ?>" data-leave-validation="<?php echo $s['user_filter']; ?>"/>
- <?php echo _t('conf.shortcut.user_filter_help'); ?>
+ <input type="text" id="user_filter_shortcut" name="shortcuts[user_filter]" list="keys" value="<?= $s['user_filter'] ?>" data-leave-validation="<?= $s['user_filter'] ?>"/>
+ <?= _t('conf.shortcut.user_filter_help') ?>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="close_dropdown_shortcut"><?php echo _t('conf.shortcut.close_dropdown'); ?></label>
+ <label class="group-name" for="close_dropdown_shortcut"><?= _t('conf.shortcut.close_dropdown') ?></label>
<div class="group-controls">
- <input type="text" id="close_dropdown" name="shortcuts[close_dropdown]" list="keys" value="<?php echo $s['close_dropdown']; ?>" data-leave-validation="<?php echo $s['close_dropdown']; ?>"/>
+ <input type="text" id="close_dropdown" name="shortcuts[close_dropdown]" list="keys" value="<?= $s['close_dropdown'] ?>" data-leave-validation="<?= $s['close_dropdown'] ?>"/>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="help_shortcut"><?php echo _t('conf.shortcut.help'); ?></label>
+ <label class="group-name" for="help_shortcut"><?= _t('conf.shortcut.help') ?></label>
<div class="group-controls">
- <input type="text" id="help_shortcut" name="shortcuts[help]" list="keys" value="<?php echo $s['help']; ?>" data-leave-validation="<?php echo $s['help']; ?>"/>
+ <input type="text" id="help_shortcut" name="shortcuts[help]" list="keys" value="<?= $s['help'] ?>" data-leave-validation="<?= $s['help'] ?>"/>
</div>
</div>
<div class="form-group form-actions">
<div class="group-controls">
- <button type="submit" class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button>
- <button type="reset" class="btn"><?php echo _t('gen.action.cancel'); ?></button>
+ <button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button>
+ <button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button>
</div>
</div>
</form>
diff --git a/app/views/configure/system.phtml b/app/views/configure/system.phtml
index 9af4cc2c9..1a718e20f 100644
--- a/app/views/configure/system.phtml
+++ b/app/views/configure/system.phtml
@@ -1,31 +1,31 @@
<?php $this->partial('aside_configure'); ?>
<div class="post">
- <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
+ <a href="<?= _url('index', 'index') ?>"><?= _t('gen.action.back_to_rss_feeds') ?></a>
- <form method="post" action="<?php echo _url('configure', 'system'); ?>">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
- <legend><?php echo _t('admin.system'); ?></legend>
+ <form method="post" action="<?= _url('configure', 'system') ?>">
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
+ <legend><?= _t('admin.system') ?></legend>
<div class="form-group">
- <label class="group-name" for="instance-name"><?php echo _t('admin.system.instance-name'); ?></label>
+ <label class="group-name" for="instance-name"><?= _t('admin.system.instance-name') ?></label>
<div class="group-controls">
- <input type="text" class="extend" id="instance-name" name="instance-name" value="<?php echo FreshRSS_Context::$system_conf->title; ?>" data-leave-validation="<?php echo FreshRSS_Context::$system_conf->title; ?>"/>
+ <input type="text" class="extend" id="instance-name" name="instance-name" value="<?= FreshRSS_Context::$system_conf->title ?>" data-leave-validation="<?= FreshRSS_Context::$system_conf->title ?>"/>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="auto-update-url"><?php echo _t('admin.system.auto-update-url'); ?></label>
+ <label class="group-name" for="auto-update-url"><?= _t('admin.system.auto-update-url') ?></label>
<div class="group-controls">
- <input type="text" class="extend" id="auto-update-url" name="auto-update-url" value="<?php echo FreshRSS_Context::$system_conf->auto_update_url; ?>" data-leave-validation="<?php echo FreshRSS_Context::$system_conf->auto_update_url; ?>"/>
+ <input type="text" class="extend" id="auto-update-url" name="auto-update-url" value="<?= FreshRSS_Context::$system_conf->auto_update_url ?>" data-leave-validation="<?= FreshRSS_Context::$system_conf->auto_update_url ?>"/>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="max-registrations"><?php echo _t('admin.system.registration.number'); ?></label>
+ <label class="group-name" for="max-registrations"><?= _t('admin.system.registration.number') ?></label>
<div class="group-controls">
- <input type="number" id="max-registrations" name="max-registrations" value="<?php echo FreshRSS_Context::$system_conf->limits['max_registrations']; ?>" min="0" data-leave-validation="<?php echo FreshRSS_Context::$system_conf->limits['max_registrations']; ?>"/>
- <?php echo _i('help'); ?> <?php echo _t('admin.system.registration.help'); ?>
+ <input type="number" id="max-registrations" name="max-registrations" value="<?= FreshRSS_Context::$system_conf->limits['max_registrations'] ?>" min="0" data-leave-validation="<?= FreshRSS_Context::$system_conf->limits['max_registrations'] ?>"/>
+ <?= _i('help') ?> <?= _t('admin.system.registration.help') ?>
</div>
</div>
@@ -38,32 +38,50 @@
</div>
</div>
+ <?php if ($this->can_enable_email_validation) { ?>
+ <div class="form-group">
+ <div class="group-controls">
+ <label class="checkbox" for="force-email-validation">
+ <input
+ type="checkbox"
+ name="force-email-validation"
+ id="force-email-validation"
+ value="1"
+ <?= FreshRSS_Context::$system_conf->force_email_validation ? 'checked="checked"' : '' ?>
+ data-leave-validation="<?= FreshRSS_Context::$system_conf->force_email_validation ?>"
+ />
+ <?= _t('admin.system.force_email_validation') ?>
+ </label>
+ </div>
+ </div>
+ <?php } ?>
+
<div class="form-group">
- <label class="group-name" for="max-feeds"><?php echo _t('admin.system.max-feeds'); ?></label>
+ <label class="group-name" for="max-feeds"><?= _t('admin.system.max-feeds') ?></label>
<div class="group-controls">
- <input type="number" id="max-feeds" name="max-feeds" value="<?php echo FreshRSS_Context::$system_conf->limits['max_feeds']; ?>" min="1" data-leave-validation="<?php echo FreshRSS_Context::$system_conf->limits['max_feeds']; ?>"/>
+ <input type="number" id="max-feeds" name="max-feeds" value="<?= FreshRSS_Context::$system_conf->limits['max_feeds'] ?>" min="1" data-leave-validation="<?= FreshRSS_Context::$system_conf->limits['max_feeds'] ?>"/>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="max-categories"><?php echo _t('admin.system.max-categories'); ?></label>
+ <label class="group-name" for="max-categories"><?= _t('admin.system.max-categories') ?></label>
<div class="group-controls">
- <input type="number" id="max-categories" name="max-categories" value="<?php echo FreshRSS_Context::$system_conf->limits['max_categories']; ?>" min="1" data-leave-validation="<?php echo FreshRSS_Context::$system_conf->limits['max_categories']; ?>"/>
+ <input type="number" id="max-categories" name="max-categories" value="<?= FreshRSS_Context::$system_conf->limits['max_categories'] ?>" min="1" data-leave-validation="<?= FreshRSS_Context::$system_conf->limits['max_categories'] ?>"/>
</div>
</div>
-
+
<div class="form-group">
- <label class="group-name" for="cookie-duration"><?php echo _t('admin.system.cookie-duration.number'); ?></label>
+ <label class="group-name" for="cookie-duration"><?= _t('admin.system.cookie-duration.number') ?></label>
<div class="group-controls">
- <input type="number" id="cookie-duration" name="cookie-duration" value="<?php echo FreshRSS_Context::$system_conf->limits['cookie_duration']; ?>" min="0" data-leave-validation="<?php echo FreshRSS_Context::$system_conf->limits['cookie_duration']; ?>"/>
- <?php echo _i('help'); ?> <?php echo _t('admin.system.cookie-duration.help'); ?>
+ <input type="number" id="cookie-duration" name="cookie-duration" value="<?= FreshRSS_Context::$system_conf->limits['cookie_duration'] ?>" min="0" data-leave-validation="<?= FreshRSS_Context::$system_conf->limits['cookie_duration'] ?>"/>
+ <?= _i('help') ?> <?= _t('admin.system.cookie-duration.help') ?>
</div>
</div>
<div class="form-group form-actions">
<div class="group-controls">
- <button type="submit" class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button>
- <button type="reset" class="btn"><?php echo _t('gen.action.cancel'); ?></button>
+ <button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button>
+ <button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button>
</div>
</div>
</form>
diff --git a/app/views/error/index.phtml b/app/views/error/index.phtml
index 8fd74e8bf..d5618d54c 100644
--- a/app/views/error/index.phtml
+++ b/app/views/error/index.phtml
@@ -1,9 +1,9 @@
<div class="post">
<div class="alert alert-error">
- <h1 class="alert-head"><?php echo $this->code; ?></h1>
+ <h1 class="alert-head"><?= $this->code ?></h1>
<p>
- <?php echo htmlspecialchars($this->errorMessage, ENT_NOQUOTES, 'UTF-8'); ?><br />
- <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
+ <?= htmlspecialchars($this->errorMessage, ENT_NOQUOTES, 'UTF-8') ?><br />
+ <a href="<?= _url('index', 'index') ?>"><?= _t('gen.action.back_to_rss_feeds') ?></a>
</p>
</div>
</div>
diff --git a/app/views/extension/index.phtml b/app/views/extension/index.phtml
index 6439a0333..f5c5bf032 100644
--- a/app/views/extension/index.phtml
+++ b/app/views/extension/index.phtml
@@ -1,14 +1,14 @@
<?php $this->partial('aside_configure'); ?>
<div class="post">
- <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
+ <a href="<?= _url('index', 'index') ?>"><?= _t('gen.action.back_to_rss_feeds') ?></a>
- <h1><?php echo _t('admin.extensions.title'); ?></h1>
+ <h1><?= _t('admin.extensions.title') ?></h1>
<form id="form-extension" method="post">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
<?php if (!empty($this->extension_list['system'])) { ?>
- <h2><?php echo _t('admin.extensions.system'); ?></h2>
+ <h2><?= _t('admin.extensions.system') ?></h2>
<?php
foreach ($this->extension_list['system'] as $ext) {
$this->ext_details = $ext;
@@ -18,7 +18,7 @@
<?php } ?>
<?php if (!empty($this->extension_list['user'])) { ?>
- <h2><?php echo _t('admin.extensions.user'); ?></h2>
+ <h2><?= _t('admin.extensions.user') ?></h2>
<?php
foreach ($this->extension_list['user'] as $ext) {
$this->ext_details = $ext;
@@ -30,34 +30,34 @@
if (empty($this->extension_list['system']) && empty($this->extension_list['user'])) {
?>
- <p class="alert alert-warn"><?php echo _t('admin.extensions.empty_list'); ?></p>
+ <p class="alert alert-warn"><?= _t('admin.extensions.empty_list') ?></p>
<?php } ?>
</form>
<?php if (!empty($this->available_extensions)) { ?>
- <h2><?php echo _t('admin.extensions.community'); ?></h2>
+ <h2><?= _t('admin.extensions.community') ?></h2>
<table>
<tr>
- <th><?php echo _t('admin.extensions.name'); ?></th>
- <th><?php echo _t('admin.extensions.version'); ?></th>
- <th><?php echo _t('admin.extensions.author'); ?></th>
- <th><?php echo _t('admin.extensions.description'); ?></th>
+ <th><?= _t('admin.extensions.name') ?></th>
+ <th><?= _t('admin.extensions.version') ?></th>
+ <th><?= _t('admin.extensions.author') ?></th>
+ <th><?= _t('admin.extensions.description') ?></th>
</tr>
<?php foreach ($this->available_extensions as $ext) { ?>
<tr>
- <td><a href="<?php echo $ext['url']; ?>" target="_blank"><?php echo $ext['name']; ?></a></td>
- <td><?php echo $ext['version']; ?></td>
- <td><?php echo $ext['author']; ?></td>
+ <td><a href="<?= $ext['url'] ?>" target="_blank"><?= $ext['name'] ?></a></td>
+ <td><?= $ext['version'] ?></td>
+ <td><?= $ext['author'] ?></td>
<td>
- <?php echo $ext['description']; ?>
+ <?= $ext['description'] ?>
<?php if (isset($this->extensions_installed[$ext['name']])) { ?>
<?php if (version_compare($this->extensions_installed[$ext['name']], $ext['version']) >= 0) { ?>
<span class="alert alert-success">
- <?php echo _t('admin.extensions.latest'); ?>
+ <?= _t('admin.extensions.latest') ?>
</span>
<?php } else if ($this->extensions_installed[$ext['name']] != $ext['version']) { ?>
<span class="alert alert-warn">
- <?php echo _t('admin.extensions.update'); ?>
+ <?= _t('admin.extensions.update') ?>
</span>
<?php } ?>
<?php } ?>
@@ -69,8 +69,8 @@
</div>
<?php $class = isset($this->extension) ? ' class="active"' : ''; ?>
-<a href="#" id="close-slider"<?php echo $class; ?>></a>
-<div id="slider"<?php echo $class; ?>>
+<a href="#" id="close-slider"<?= $class ?>></a>
+<div id="slider"<?= $class ?>>
<?php
if (isset($this->extension)) {
$this->renderHelper('extension/configure');
diff --git a/app/views/feed/add.phtml b/app/views/feed/add.phtml
index 340970b25..e39f45a86 100644
--- a/app/views/feed/add.phtml
+++ b/app/views/feed/add.phtml
@@ -1,90 +1,90 @@
<?php if ($this->feed) { ?>
<div class="post">
- <h1><?php echo _t('sub.feed.add'); ?></h1>
+ <h1><?= _t('sub.feed.add') ?></h1>
<?php if (!$this->load_ok) { ?>
- <p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('feedback.sub.feed.internal_problem', _url('index', 'logs')); ?></p>
+ <p class="alert alert-error"><span class="alert-head"><?= _t('gen.short.damn') ?></span> <?= _t('feedback.sub.feed.internal_problem', _url('index', 'logs')) ?></p>
<?php } ?>
- <form method="post" action="<?php echo _url('feed', 'add'); ?>" autocomplete="off">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
- <legend><?php echo _t('sub.feed.information'); ?></legend>
+ <form method="post" action="<?= _url('feed', 'add') ?>" autocomplete="off">
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
+ <legend><?= _t('sub.feed.information') ?></legend>
<?php if ($this->load_ok) { ?>
<div class="form-group">
- <label class="group-name"><?php echo _t('sub.feed.title'); ?></label>
+ <label class="group-name"><?= _t('sub.feed.title') ?></label>
<div class="group-controls">
- <label><?php echo $this->feed->name() ; ?></label>
+ <label><?= $this->feed->name() ?></label>
</div>
</div>
<?php $desc = $this->feed->description(); if ($desc != '') { ?>
<div class="form-group">
- <label class="group-name"><?php echo _t('sub.feed.description'); ?></label>
+ <label class="group-name"><?= _t('sub.feed.description') ?></label>
<div class="group-controls">
- <label><?php echo htmlspecialchars($desc, ENT_NOQUOTES, 'UTF-8'); ?></label>
+ <label><?= htmlspecialchars($desc, ENT_NOQUOTES, 'UTF-8') ?></label>
</div>
</div>
<?php } ?>
<div class="form-group">
- <label class="group-name"><?php echo _t('sub.feed.website'); ?></label>
+ <label class="group-name"><?= _t('sub.feed.website') ?></label>
<div class="group-controls">
- <?php echo $this->feed->website(); ?>
- <a class="btn" target="_blank" rel="noreferrer" href="<?php echo $this->feed->website(); ?>"><?php echo _i('link'); ?></a>
+ <?= $this->feed->website() ?>
+ <a class="btn" target="_blank" rel="noreferrer" href="<?= $this->feed->website() ?>"><?= _i('link') ?></a>
</div>
</div>
<?php } ?>
<div class="form-group">
- <label class="group-name" for="url"><?php echo _t('sub.feed.url'); ?></label>
+ <label class="group-name" for="url"><?= _t('sub.feed.url') ?></label>
<div class="group-controls">
<div class="stick">
- <input type="text" name="url_rss" id="url" class="extend" value="<?php echo $this->feed->url(); ?>" />
- <a class="btn" target="_blank" rel="noreferrer" href="<?php echo $this->feed->url(); ?>"><?php echo _i('link'); ?></a>
+ <input type="text" name="url_rss" id="url" class="extend" value="<?= $this->feed->url() ?>" />
+ <a class="btn" target="_blank" rel="noreferrer" href="<?= $this->feed->url() ?>"><?= _i('link') ?></a>
</div>
- <a class="btn" target="_blank" rel="noreferrer" href="http://validator.w3.org/feed/check.cgi?url=<?php echo $this->feed->url(); ?>"><?php echo _t('sub.feed.validator'); ?></a>
+ <a class="btn" target="_blank" rel="noreferrer" href="http://validator.w3.org/feed/check.cgi?url=<?= $this->feed->url() ?>"><?= _t('sub.feed.validator') ?></a>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="category"><?php echo _t('sub.category'); ?></label>
+ <label class="group-name" for="category"><?= _t('sub.category') ?></label>
<div class="group-controls">
<select name="category" id="category">
<?php foreach ($this->categories as $cat) { ?>
- <option value="<?php echo $cat->id(); ?>"<?php echo $cat->id() == 1 ? ' selected="selected"' : ''; ?>>
- <?php echo $cat->name(); ?>
+ <option value="<?= $cat->id() ?>"<?= $cat->id() == 1 ? ' selected="selected"' : '' ?>>
+ <?= $cat->name() ?>
</option>
<?php } ?>
- <option value="nc"><?php echo _t('sub.category.new'); ?></option>
+ <option value="nc"><?= _t('sub.category.new') ?></option>
</select>
<span aria-hidden="true">
- <input type="text" name="new_category[name]" id="new_category_name" autocomplete="off" placeholder="<?php echo _t('sub.category.new'); ?>" />
+ <input type="text" name="new_category[name]" id="new_category_name" autocomplete="off" placeholder="<?= _t('sub.category.new') ?>" />
</span>
</div>
</div>
- <legend><?php echo _t('sub.feed.auth.http'); ?></legend>
+ <legend><?= _t('sub.feed.auth.http') ?></legend>
<?php $auth = $this->feed->httpAuth(false); ?>
<div class="form-group">
- <label class="group-name" for="http_user"><?php echo _t('sub.feed.auth.username'); ?></label>
+ <label class="group-name" for="http_user"><?= _t('sub.feed.auth.username') ?></label>
<div class="group-controls">
- <input type="text" name="http_user" id="http_user" class="extend" value="<?php echo empty($auth['username']) ? ' ' : $auth['username']; ?>" autocomplete="off" />
+ <input type="text" name="http_user" id="http_user" class="extend" value="<?= empty($auth['username']) ? ' ' : $auth['username'] ?>" autocomplete="off" />
</div>
- <label class="group-name" for="http_pass"><?php echo _t('sub.feed.auth.password'); ?></label>
+ <label class="group-name" for="http_pass"><?= _t('sub.feed.auth.password') ?></label>
<div class="group-controls">
- <input type="password" name="http_pass" id="http_pass" class="extend" value="<?php echo $auth['password']; ?>" autocomplete="new-password" />
+ <input type="password" name="http_pass" id="http_pass" class="extend" value="<?= $auth['password'] ?>" autocomplete="new-password" />
</div>
<div class="group-controls">
- <?php echo _i('help'); ?> <?php echo _t('sub.feed.auth.help'); ?>
+ <?= _i('help') ?> <?= _t('sub.feed.auth.help') ?>
</div>
</div>
<div class="form-group form-actions">
<div class="group-controls">
- <button type="submit" class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button>
- <button type="reset" class="btn"><?php echo _t('gen.action.cancel'); ?></button>
+ <button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button>
+ <button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button>
</div>
</div>
</form>
diff --git a/app/views/helpers/category/update.phtml b/app/views/helpers/category/update.phtml
index a2ee3e2ef..9e55e613d 100644
--- a/app/views/helpers/category/update.phtml
+++ b/app/views/helpers/category/update.phtml
@@ -1,34 +1,160 @@
<div class="post">
- <h1><?php echo $this->category->name(); ?></h1>
+ <h1><?= $this->category->name() ?></h1>
<div>
- <a href="<?php echo _url('index', 'index', 'get', 'c_' . $this->category->id()); ?>"><?php echo _i('link'); ?> <?php echo _t('gen.action.filter'); ?></a>
+ <a href="<?= _url('index', 'index', 'get', 'c_' . $this->category->id()) ?>"><?= _i('link') ?> <?= _t('gen.action.filter') ?></a>
</div>
- <form method="post" action="<?php echo _url('subscription', 'category', 'id', $this->category->id()); ?>" autocomplete="off">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
- <legend><?php echo _t('sub.category.information'); ?></legend>
+ <form method="post" action="<?= _url('subscription', 'category', 'id', $this->category->id()) ?>" autocomplete="off">
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
+ <legend><?= _t('sub.category.information') ?></legend>
<div class="form-group">
- <label class="group-name" for="name"><?php echo _t('sub.category.title'); ?></label>
+ <label class="group-name" for="name"><?= _t('sub.category.title') ?></label>
<div class="group-controls">
- <input type="text" name="name" id="name" class="extend" value="<?php echo $this->category->name() ; ?>" />
+ <input type="text" name="name" id="name" class="extend" value="<?= $this->category->name() ?>" <?php
+ //Disallow changing the name of the default category
+ echo $this->category->id() == FreshRSS_CategoryDAO::DEFAULTCATEGORYID ? 'disabled="disabled"' : '';
+ ?> />
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="group-name" for="position"><?= _t('sub.category.position') ?></label>
+ <div class="group-controls">
+ <input type="number" name="position" id="position" min="1" value="<?= $this->category->attributes('position') ?>" />
+ <?= _i('help') ?> <?= _t('sub.category.position_help') ?>
</div>
</div>
<div class="form-group form-actions">
<div class="group-controls">
- <button class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button>
+ <button class="btn btn-important"><?= _t('gen.action.submit') ?></button>
<button class="btn btn-attention confirm"
- data-str-confirm="<?php echo _t('gen.js.confirm_action_feed_cat'); ?>"
- formaction="<?php echo _url('category', 'empty', 'id', $this->category->id()); ?>"
- formmethod="post"><?php echo _t('gen.action.empty'); ?></button>
+ data-str-confirm="<?= _t('gen.js.confirm_action_feed_cat') ?>"
+ formaction="<?= _url('category', 'empty', 'id', $this->category->id()) ?>"
+ formmethod="post"><?= _t('gen.action.empty') ?></button>
<?php if (!$this->category->isDefault()): ?>
<button class="btn btn-attention confirm"
- data-str-confirm="<?php echo _t('gen.js.confirm_action_feed_cat'); ?>"
- formaction="<?php echo _url('category', 'delete', 'id', $this->category->id()); ?>"
- formmethod="post"><?php echo _t('gen.action.remove'); ?></button>
+ data-str-confirm="<?= _t('gen.js.confirm_action_feed_cat') ?>"
+ formaction="<?= _url('category', 'delete', 'id', $this->category->id()) ?>"
+ formmethod="post"><?= _t('gen.action.remove') ?></button>
<?php endif;?>
</div>
</div>
+
+ <legend><?= _t('sub.category.archiving') ?></legend>
+ <?php
+ $archiving = $this->category->attributes('archiving');
+ if (empty($archiving)) {
+ $archiving = [ 'default' => true ];
+ } else {
+ $archiving['default'] = false;
+ }
+ $volatile = [
+ 'enable_keep_period' => false,
+ 'keep_period_count' => '3',
+ 'keep_period_unit' => 'P1M',
+ ];
+ if (!empty($archiving['keep_period'])) {
+ if (preg_match('/^PT?(?P<count>\d+)[YMWDH]$/', $archiving['keep_period'], $matches)) {
+ $volatile['enable_keep_period'] = true;
+ $volatile['keep_period_count'] = $matches['count'];
+ $volatile['keep_period_unit'] = str_replace($matches['count'], '1', $archiving['keep_period']);
+ }
+ }
+ //Defaults
+ if (!isset($archiving['keep_max'])) {
+ $archiving['keep_max'] = false;
+ }
+ if (!isset($archiving['keep_favourites'])) {
+ $archiving['keep_favourites'] = true;
+ }
+ if (!isset($archiving['keep_labels'])) {
+ $archiving['keep_labels'] = true;
+ }
+ if (!isset($archiving['keep_unreads'])) {
+ $archiving['keep_unreads'] = false;
+ }
+ if (!isset($archiving['keep_min'])) {
+ $archiving['keep_min'] = 50;
+ }
+ ?>
+
+ <p class="alert alert-warn">
+ <?= _t('conf.archiving.policy_warning') ?>
+ </p>
+
+ <div class="form-group">
+ <label class="group-name"><?= _t('conf.archiving.policy') ?></label>
+ <div class="group-controls">
+ <label class="checkbox">
+ <input type="checkbox" name="use_default_purge_options" id="use_default_purge_options" value="1"<?= $archiving['default'] ? ' checked="checked"' : '' ?> data-leave-validation="<?= $archiving['default'] ? 1 : 0 ?>" />
+ <?= _t('gen.short.by_default') ?>
+ </label>
+ </div>
+ </div>
+ <div class="form-group archiving"<?= $archiving['default'] ? ' hidden="hidden"' : '' ?>>
+ <div class="group-controls">
+ <label class="checkbox" for="enable_keep_max">
+ <input type="checkbox" name="enable_keep_max" id="enable_keep_max" value="1"<?= empty($archiving['keep_max']) ? '' : ' checked="checked"' ?> data-leave-validation="<?= empty($archiving['keep_max']) ? 0 : 1 ?>"/>
+ <?= _t('conf.archiving.keep_max') ?>
+ <input type="number" id="keep_max" name="keep_max" min="0" value="<?= empty($archiving['keep_max']) ? 200 : $archiving['keep_max'] ?>" data-leave-validation="<?= empty($archiving['keep_max']) ? 200 : $archiving['keep_max'] ?>"/>
+ </label>
+ </div>
+ </div>
+ <div class="form-group archiving"<?= $archiving['default'] ? ' hidden="hidden"' : '' ?>>
+ <div class="group-controls">
+ <label class="checkbox" for="enable_keep_period">
+ <input type="checkbox" name="enable_keep_period" id="enable_keep_period" value="1"<?= $volatile['enable_keep_period'] ? ' checked="checked"' : '' ?> data-leave-validation="<?= $volatile['enable_keep_period'] ? 1 : 0 ?>"/>
+ <?= _t('conf.archiving.keep_period') ?>
+ <input type="number" id="keep_period_count" name="keep_period_count" min="0" value="<?= $volatile['keep_period_count'] ?>" data-leave-validation="<?= $volatile['keep_period_count'] ?>"/>
+ <select class="number" name="keep_period_unit" id="keep_period_unit" data-leave-validation="<?= $volatile['keep_period_unit'] ?>">
+ <option></option>
+ <option value="P1Y" <?= 'P1Y' === $volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.years') ?></option>
+ <option value="P1M" <?= 'P1M' === $volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.months') ?></option>
+ <option value="P1W" <?= 'P1W' === $volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.weeks') ?></option>
+ <option value="P1D" <?= 'P1D' === $volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.days') ?></option>
+ <option value="PT1H" <?= 'PT1H' === $volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.hours') ?></option>
+ </select>
+ </label>
+ </div>
+ </div>
+ <div class="form-group archiving"<?= $archiving['default'] ? ' hidden="hidden"' : '' ?>>
+ <label class="group-name"><?= _t('conf.archiving.exception') ?></label>
+ <div class="group-controls">
+ <label class="checkbox" for="keep_favourites">
+ <input type="checkbox" name="keep_favourites" id="keep_favourites" value="1"<?= $archiving['keep_favourites'] ? ' checked="checked"' : '' ?> data-leave-validation="<?= $archiving['keep_favourites'] ? 1 : 0 ?>"/>
+ <?= _t('conf.archiving.keep_favourites') ?>
+ </label>
+ </div>
+ </div>
+ <div class="form-group archiving"<?= $archiving['default'] ? ' hidden="hidden"' : '' ?>>
+ <div class="group-controls">
+ <label class="checkbox" for="keep_labels">
+ <input type="checkbox" name="keep_labels" id="keep_labels" value="1"<?= $archiving['keep_labels'] ? ' checked="checked"' : '' ?> data-leave-validation="<?= $archiving['keep_labels'] ? 1 : 0 ?>"/>
+ <?= _t('conf.archiving.keep_labels') ?>
+ </label>
+ </div>
+ </div>
+ <div class="form-group archiving"<?= $archiving['default'] ? ' hidden="hidden"' : '' ?>>
+ <div class="group-controls">
+ <label class="checkbox" for="keep_unreads">
+ <input type="checkbox" name="keep_unreads" id="keep_unreads" value="1"<?= $archiving['keep_unreads'] ? ' checked="checked"' : '' ?> data-leave-validation="<?= $archiving['keep_unreads'] ? 1 : 0 ?>"/>
+ <?= _t('conf.archiving.keep_unreads') ?>
+ </label>
+ </div>
+ </div>
+ <div class="form-group archiving"<?= $archiving['default'] ? ' hidden="hidden"' : '' ?>>
+ <div class="group-controls">
+ <label for="keep_min"><?= _t('sub.feed.keep_min') ?>
+ <input type="number" id="keep_min" name="keep_min" min="0" value="<?= $archiving['keep_min'] ?>" data-leave-validation="<?= $archiving['keep_min'] ?>">
+ </label>
+ </div>
+ </div>
+ <div class="form-group form-actions">
+ <div class="group-controls">
+ <button class="btn btn-important"><?= _t('gen.action.submit') ?></button>
+ <button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button>
+ </div>
+ </div>
</form>
</div>
diff --git a/app/views/helpers/export/articles.phtml b/app/views/helpers/export/articles.phtml
index 2d1fcd133..0bbfb86ec 100644
--- a/app/views/helpers/export/articles.phtml
+++ b/app/views/helpers/export/articles.phtml
@@ -1,10 +1,7 @@
<?php
$username = Minz_Session::param('currentUser', '_');
-$options = 0;
-if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
- $options = JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
-}
+$options = JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
$articles = array(
'id' => 'user/' . str_replace('/', '', $username) . '/state/org.freshrss/' . $this->type,
diff --git a/app/views/helpers/extension/configure.phtml b/app/views/helpers/extension/configure.phtml
index cde872aa0..cb6ebd6bb 100644
--- a/app/views/helpers/extension/configure.phtml
+++ b/app/views/helpers/extension/configure.phtml
@@ -1,19 +1,19 @@
<div class="post">
<h1>
- <?php echo $this->extension->getName(); ?> (<?php echo $this->extension->getVersion(); ?>) —
+ <?= $this->extension->getName() ?> (<?= $this->extension->getVersion() ?>) —
<?php echo $this->extension->isEnabled() ? _t('admin.extensions.enabled')
: _t('admin.extensions.disabled'); ?>
</h1>
- <p class="alert alert-warn"><?php echo $this->extension->getDescription(); ?> — <?php echo _t('gen.short.by_author'), ' ', $this->extension->getAuthor(); ?></p>
+ <p class="alert alert-warn"><?= $this->extension->getDescription() ?> — <?= _t('gen.short.by_author'), ' ', $this->extension->getAuthor() ?></p>
- <h2><?php echo _t('gen.action.manage'); ?></h2>
+ <h2><?= _t('gen.action.manage') ?></h2>
<?php
$configure_view = $this->extension->getConfigureView();
if ($configure_view !== false) {
echo $configure_view;
} else {
?>
- <p class="alert alert-warn"><?php echo _t('admin.extensions.no_configure_view'); ?></p>
+ <p class="alert alert-warn"><?= _t('admin.extensions.no_configure_view') ?></p>
<?php } ?>
</div>
diff --git a/app/views/helpers/extension/details.phtml b/app/views/helpers/extension/details.phtml
index acba4e816..ed9674e3d 100644
--- a/app/views/helpers/extension/details.phtml
+++ b/app/views/helpers/extension/details.phtml
@@ -3,19 +3,19 @@
<?php if ($this->ext_details->getType() === 'user' || FreshRSS_Auth::hasAccess('admin')) { ?>
<?php $name_encoded = urlencode($this->ext_details->getName()); ?>
<div class="stick">
- <a class="btn open-slider" href="<?php echo _url('extension', 'configure', 'e', $name_encoded); ?>"><?php echo _i('configure'); ?> <?php echo _t('gen.action.manage'); ?></a>
+ <a class="btn open-slider" href="<?= _url('extension', 'configure', 'e', $name_encoded) ?>"><?= _i('configure') ?> <?= _t('gen.action.manage') ?></a>
<?php if ($this->ext_details->isEnabled()) { ?>
- <button class="btn active" form="form-extension" formaction="<?php echo _url('extension', 'disable', 'e', $name_encoded); ?>"><?php echo _t('gen.action.disable'); ?></button>
+ <button class="btn active" form="form-extension" formaction="<?= _url('extension', 'disable', 'e', $name_encoded) ?>"><?= _t('gen.action.disable') ?></button>
<?php } else { ?>
- <button class="btn" form="form-extension" formaction="<?php echo _url('extension', 'enable', 'e', $name_encoded); ?>"><?php echo _t('gen.action.enable'); ?></button>
+ <button class="btn" form="form-extension" formaction="<?= _url('extension', 'enable', 'e', $name_encoded) ?>"><?= _t('gen.action.enable') ?></button>
<?php } ?>
<?php if (FreshRSS_Auth::hasAccess('admin')) { ?>
- <button class="btn btn-attention confirm" form="form-extension" formaction="<?php echo _url('extension', 'remove', 'e', $name_encoded); ?>"><?php echo _t('gen.action.remove'); ?></button>
+ <button class="btn btn-attention confirm" form="form-extension" formaction="<?= _url('extension', 'remove', 'e', $name_encoded) ?>"><?= _t('gen.action.remove') ?></button>
<?php } ?>
</div>
<?php } else { ?>
- <?php echo _t('admin.extensions.system.no_rights'); ?>
+ <?= _t('admin.extensions.system.no_rights') ?>
<?php } ?>
</li>
- <li class="item"><?php echo $this->ext_details->getName(); ?></li>
+ <li class="item"><?= $this->ext_details->getName() ?></li>
</ul>
diff --git a/app/views/helpers/feed/update.phtml b/app/views/helpers/feed/update.phtml
index 620806d7b..e5f186956 100644
--- a/app/views/helpers/feed/update.phtml
+++ b/app/views/helpers/feed/update.phtml
@@ -1,114 +1,214 @@
<div class="post">
- <h1><?php echo $this->feed->name(); ?></h1>
+ <h1><?= $this->feed->name() ?></h1>
<div>
- <a href="<?php echo _url('index', 'index', 'get', 'f_' . $this->feed->id()); ?>"><?php echo _i('link'); ?> <?php echo _t('gen.action.filter'); ?></a>
- <?php echo _t('gen.short.or'); ?>
- <a href="<?php echo _url('stats', 'repartition', 'id', $this->feed->id()); ?>"><?php echo _i('stats'); ?> <?php echo _t('sub.feed.stats'); ?></a>
+ <a href="<?= _url('index', 'index', 'get', 'f_' . $this->feed->id()) ?>"><?= _i('link') ?> <?= _t('gen.action.filter') ?></a>
+ <?= _t('gen.short.or') ?>
+ <a href="<?= _url('stats', 'repartition', 'id', $this->feed->id()) ?>"><?= _i('stats') ?> <?= _t('sub.feed.stats') ?></a>
</div>
- <p><?php echo $this->feed->description(); ?></p>
+ <p><?= $this->feed->description() ?></p>
<?php $nbEntries = $this->feed->nbEntries(); ?>
<?php if ($this->feed->inError()) { ?>
- <p class="alert alert-error"><span class="alert-head"><?php echo _t('gen.short.damn'); ?></span> <?php echo _t('sub.feed.error'); ?></p>
+ <p class="alert alert-error"><span class="alert-head"><?= _t('gen.short.damn') ?></span> <?= _t('sub.feed.error') ?></p>
<?php } elseif ($nbEntries === 0) { ?>
- <p class="alert alert-warn"><?php echo _t('sub.feed.empty'); ?></p>
+ <p class="alert alert-warn"><?= _t('sub.feed.empty') ?></p>
<?php } ?>
- <form method="post" action="<?php echo _url('subscription', 'feed', 'id', $this->feed->id()); ?>" autocomplete="off">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
- <legend><?php echo _t('sub.feed.information'); ?></legend>
+ <form method="post" action="<?= _url('subscription', 'feed', 'id', $this->feed->id()) ?>" autocomplete="off">
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
+ <legend><?= _t('sub.feed.information') ?></legend>
<div class="form-group">
- <label class="group-name" for="name"><?php echo _t('sub.feed.title'); ?></label>
+ <label class="group-name" for="name"><?= _t('sub.feed.title') ?></label>
<div class="group-controls">
- <input type="text" name="name" id="name" class="extend" value="<?php echo $this->feed->name() ; ?>" />
+ <input type="text" name="name" id="name" class="extend" value="<?= $this->feed->name() ?>" />
</div>
</div>
<div class="form-group">
- <label class="group-name" for="description"><?php echo _t('sub.feed.description'); ?></label>
+ <label class="group-name" for="description"><?= _t('sub.feed.description') ?></label>
<div class="group-controls">
- <textarea name="description" id="description"><?php echo htmlspecialchars($this->feed->description(), ENT_NOQUOTES, 'UTF-8'); ?></textarea>
+ <textarea name="description" id="description"><?= htmlspecialchars($this->feed->description(), ENT_NOQUOTES, 'UTF-8') ?></textarea>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="website"><?php echo _t('sub.feed.website'); ?></label>
+ <label class="group-name" for="website"><?= _t('sub.feed.website') ?></label>
<div class="group-controls">
<div class="stick">
- <input type="text" name="website" id="website" class="extend" value="<?php echo $this->feed->website(); ?>" />
- <a class="btn" target="_blank" rel="noreferrer" href="<?php echo $this->feed->website(); ?>"><?php echo _i('link'); ?></a>
+ <input type="text" name="website" id="website" class="extend" value="<?= $this->feed->website() ?>" />
+ <a class="btn" target="_blank" rel="noreferrer" href="<?= $this->feed->website() ?>"><?= _i('link') ?></a>
</div>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="url"><?php echo _t('sub.feed.url'); ?></label>
+ <label class="group-name" for="url"><?= _t('sub.feed.url') ?></label>
<div class="group-controls">
<div class="stick">
- <input type="text" name="url" id="url" class="extend" value="<?php echo $this->feed->url(); ?>" />
- <a class="btn" target="_blank" rel="noreferrer" href="<?php echo $this->feed->url(); ?>"><?php echo _i('link'); ?></a>
+ <input type="text" name="url" id="url" class="extend" value="<?= $this->feed->url() ?>" />
+ <a class="btn" target="_blank" rel="noreferrer" href="<?= $this->feed->url() ?>"><?= _i('link') ?></a>
</div>
- <a class="btn" target="_blank" rel="noreferrer" href="http://validator.w3.org/feed/check.cgi?url=<?php echo rawurlencode(htmlspecialchars_decode($this->feed->url(), ENT_QUOTES)); ?>"><?php echo _t('sub.feed.validator'); ?></a>
+ <a class="btn" target="_blank" rel="noreferrer" href="http://validator.w3.org/feed/check.cgi?url=<?= rawurlencode(htmlspecialchars_decode($this->feed->url(), ENT_QUOTES)) ?>"><?= _t('sub.feed.validator') ?></a>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="category"><?php echo _t('sub.category'); ?></label>
+ <label class="group-name" for="category"><?= _t('sub.category') ?></label>
<div class="group-controls">
<select name="category" id="category">
<?php foreach ($this->categories as $cat) { ?>
- <option value="<?php echo $cat->id(); ?>"<?php echo $cat->id()== $this->feed->category() ? ' selected="selected"' : ''; ?>>
- <?php echo $cat->name(); ?>
+ <option value="<?= $cat->id() ?>"<?= $cat->id()== $this->feed->category() ? ' selected="selected"' : '' ?>>
+ <?= $cat->name() ?>
</option>
<?php } ?>
</select>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="priority"><?php echo _t('sub.feed.priority'); ?></label>
+ <label class="group-name" for="priority"><?= _t('sub.feed.priority') ?></label>
<div class="group-controls">
<select name="priority" id="priority">
- <option value='<?php echo FreshRSS_Feed::PRIORITY_MAIN_STREAM;?>' <?php if (FreshRSS_Feed::PRIORITY_MAIN_STREAM === $this->feed->priority()) {echo 'selected="selected"';}?>><?php echo _t('sub.feed.priority.main_stream'); ?></option>
- <option value='<?php echo FreshRSS_Feed::PRIORITY_NORMAL;?>' <?php if (FreshRSS_Feed::PRIORITY_NORMAL === $this->feed->priority()) {echo 'selected="selected"';}?>><?php echo _t('sub.feed.priority.normal'); ?></option>
- <option value='<?php echo FreshRSS_Feed::PRIORITY_ARCHIVED;?>' <?php if (FreshRSS_Feed::PRIORITY_ARCHIVED === $this->feed->priority()) {echo 'selected="selected"';}?>><?php echo _t('sub.feed.priority.archived'); ?></option>
+ <option value='<?= FreshRSS_Feed::PRIORITY_MAIN_STREAM ?>' <?php if (FreshRSS_Feed::PRIORITY_MAIN_STREAM === $this->feed->priority()) {echo 'selected="selected"';}?>><?= _t('sub.feed.priority.main_stream') ?></option>
+ <option value='<?= FreshRSS_Feed::PRIORITY_NORMAL ?>' <?php if (FreshRSS_Feed::PRIORITY_NORMAL === $this->feed->priority()) {echo 'selected="selected"';}?>><?= _t('sub.feed.priority.normal') ?></option>
+ <option value='<?= FreshRSS_Feed::PRIORITY_ARCHIVED ?>' <?php if (FreshRSS_Feed::PRIORITY_ARCHIVED === $this->feed->priority()) {echo 'selected="selected"';}?>><?= _t('sub.feed.priority.archived') ?></option>
</select>
</div>
</div>
<div class="form-group form-actions">
<div class="group-controls">
- <button class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button>
+ <button class="btn btn-important"><?= _t('gen.action.submit') ?></button>
+ <button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button>
<button class="btn btn-attention confirm"
- data-str-confirm="<?php echo _t('gen.js.confirm_action_feed_cat'); ?>"
- formaction="<?php echo _url('feed', 'delete', 'id', $this->feed->id()); ?>"
- formmethod="post"><?php echo _t('gen.action.remove'); ?></button>
+ data-str-confirm="<?= _t('gen.js.confirm_action_feed_cat') ?>"
+ formaction="<?= _url('feed', 'delete', 'id', $this->feed->id()) ?>"
+ formmethod="post"><?= _t('gen.action.remove') ?></button>
</div>
</div>
- <legend><?php echo _t('sub.feed.archiving'); ?></legend>
+ <legend><?= _t('sub.feed.archiving') ?></legend>
<div class="form-group">
<div class="group-controls">
<div class="stick">
- <input type="text" value="<?php echo _t('sub.feed.number_entries', $nbEntries); ?>" disabled="disabled" />
- <a class="btn" href="<?php echo _url('feed', 'actualize', 'id', $this->feed->id()); ?>">
- <?php echo _i('refresh'); ?> <?php echo _t('gen.action.actualize'); ?>
+ <input type="text" value="<?= _t('sub.feed.number_entries', $nbEntries) ?>" disabled="disabled" />
+ <a class="btn" href="<?= _url('feed', 'actualize', 'id', $this->feed->id()) ?>">
+ <?= _i('refresh') ?> <?= _t('gen.action.actualize') ?>
</a>
</div>
</div>
</div>
+ <?php
+ $archiving = $this->feed->attributes('archiving');
+ if (empty($archiving)) {
+ $archiving = [ 'default' => true ];
+ } else {
+ $archiving['default'] = false;
+ }
+ $volatile = [
+ 'enable_keep_period' => false,
+ 'keep_period_count' => '3',
+ 'keep_period_unit' => 'P1M',
+ ];
+ if (!empty($archiving['keep_period'])) {
+ if (preg_match('/^PT?(?P<count>\d+)[YMWDH]$/', $archiving['keep_period'], $matches)) {
+ $volatile['enable_keep_period'] = true;
+ $volatile['keep_period_count'] = $matches['count'];
+ $volatile['keep_period_unit'] = str_replace($matches['count'], '1', $archiving['keep_period']);
+ }
+ }
+ //Defaults
+ if (!isset($archiving['keep_max'])) {
+ $archiving['keep_max'] = false;
+ }
+ if (!isset($archiving['keep_min'])) {
+ $archiving['keep_min'] = 50;
+ }
+ if (!isset($archiving['keep_favourites'])) {
+ $archiving['keep_favourites'] = true;
+ }
+ if (!isset($archiving['keep_labels'])) {
+ $archiving['keep_labels'] = true;
+ }
+ if (!isset($archiving['keep_unreads'])) {
+ $archiving['keep_unreads'] = false;
+ }
+ ?>
+
+ <p class="alert alert-warn">
+ <?= _t('conf.archiving.policy_warning') ?>
+ </p>
+
<div class="form-group">
- <label class="group-name" for="keep_history"><?php echo _t('sub.feed.keep_history'); ?></label>
+ <label class="group-name"><?= _t('conf.archiving.policy') ?></label>
<div class="group-controls">
- <select class="number" name="keep_history" id="keep_history" required="required"><?php
- foreach (array('' => '', FreshRSS_Feed::KEEP_HISTORY_DEFAULT => _t('gen.short.by_default'), 0 => '0', 10 => '10', 50 => '50', 100 => '100', 500 => '500', 1000 => '1 000', 5000 => '5 000', 10000 => '10 000', FreshRSS_Feed::KEEP_HISTORY_INFINITE => '∞') as $v => $t) {
- echo '<option value="' . $v . ($this->feed->keepHistory() === $v ? '" selected="selected' : '') . '">' . $t . '</option>';
- }
- ?></select>
+ <label class="checkbox">
+ <input type="checkbox" name="use_default_purge_options" id="use_default_purge_options" value="1"<?= $archiving['default'] ? ' checked="checked"' : '' ?> data-leave-validation="<?= $archiving['default'] ? 1 : 0 ?>" />
+ <?= _t('gen.short.by_default') ?>
+ </label>
+ </div>
+ </div>
+ <div class="form-group archiving"<?= $archiving['default'] ? ' hidden="hidden"' : '' ?>>
+ <div class="group-controls">
+ <label class="checkbox" for="enable_keep_max">
+ <input type="checkbox" name="enable_keep_max" id="enable_keep_max" value="1"<?= empty($archiving['keep_max']) ? '' : ' checked="checked"' ?> data-leave-validation="<?= empty($archiving['keep_max']) ? 0 : 1 ?>"/>
+ <?= _t('conf.archiving.keep_max') ?>
+ <input type="number" id="keep_max" name="keep_max" min="0" value="<?= empty($archiving['keep_max']) ? 200 : $archiving['keep_max'] ?>" data-leave-validation="<?= empty($archiving['keep_max']) ? 200 : $archiving['keep_max'] ?>"/>
+ </label>
+ </div>
+ </div>
+ <div class="form-group archiving"<?= $archiving['default'] ? ' hidden="hidden"' : '' ?>>
+ <div class="group-controls">
+ <label class="checkbox" for="enable_keep_period">
+ <input type="checkbox" name="enable_keep_period" id="enable_keep_period" value="1"<?= $volatile['enable_keep_period'] ? ' checked="checked"' : '' ?> data-leave-validation="<?= $volatile['enable_keep_period'] ? 1 : 0 ?>"/>
+ <?= _t('conf.archiving.keep_period') ?>
+ <input type="number" id="keep_period_count" name="keep_period_count" min="0" value="<?= $volatile['keep_period_count'] ?>" data-leave-validation="<?= $volatile['keep_period_count'] ?>"/>
+ <select class="number" name="keep_period_unit" id="keep_period_unit" data-leave-validation="<?= $volatile['keep_period_unit'] ?>">
+ <option></option>
+ <option value="P1Y" <?= 'P1Y' === $volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.years') ?></option>
+ <option value="P1M" <?= 'P1M' === $volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.months') ?></option>
+ <option value="P1W" <?= 'P1W' === $volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.weeks') ?></option>
+ <option value="P1D" <?= 'P1D' === $volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.days') ?></option>
+ <option value="PT1H" <?= 'PT1H' === $volatile['keep_period_unit'] ? 'selected="selected"' : '' ?>><?= _t('gen.period.hours') ?></option>
+ </select>
+ </label>
</div>
</div>
+ <div class="form-group archiving"<?= $archiving['default'] ? ' hidden="hidden"' : '' ?>>
+ <label class="group-name"><?= _t('conf.archiving.exception') ?></label>
+ <div class="group-controls">
+ <label class="checkbox" for="keep_favourites">
+ <input type="checkbox" name="keep_favourites" id="keep_favourites" value="1"<?= $archiving['keep_favourites'] ? ' checked="checked"' : '' ?> data-leave-validation="<?= $archiving['keep_favourites'] ? 1 : 0 ?>"/>
+ <?= _t('conf.archiving.keep_favourites') ?>
+ </label>
+ </div>
+ </div>
+ <div class="form-group archiving"<?= $archiving['default'] ? ' hidden="hidden"' : '' ?>>
+ <div class="group-controls">
+ <label class="checkbox" for="keep_labels">
+ <input type="checkbox" name="keep_labels" id="keep_labels" value="1"<?= $archiving['keep_labels'] ? ' checked="checked"' : '' ?> data-leave-validation="<?= $archiving['keep_labels'] ? 1 : 0 ?>"/>
+ <?= _t('conf.archiving.keep_labels') ?>
+ </label>
+ </div>
+ </div>
+ <div class="form-group archiving"<?= $archiving['default'] ? ' hidden="hidden"' : '' ?>>
+ <div class="group-controls">
+ <label class="checkbox" for="keep_unreads">
+ <input type="checkbox" name="keep_unreads" id="keep_unreads" value="1"<?= $archiving['keep_unreads'] ? ' checked="checked"' : '' ?> data-leave-validation="<?= $archiving['keep_unreads'] ?>"/>
+ <?= _t('conf.archiving.keep_unreads') ?>
+ </label>
+ </div>
+ </div>
+ <div class="form-group archiving"<?= $archiving['default'] ? ' hidden="hidden"' : '' ?>>
+ <div class="group-controls">
+ <label for="keep_min"><?= _t('sub.feed.keep_min') ?>
+ <input type="number" id="keep_min" name="keep_min" min="0" value="<?= $archiving['keep_min'] ?>" data-leave-validation="<?= $archiving['keep_min'] ?>">
+ </label>
+ </div>
+ </div>
+
<div class="form-group">
- <label class="group-name" for="ttl"><?php echo _t('sub.feed.ttl'); ?></label>
+ <label class="group-name" for="ttl"><?= _t('sub.feed.ttl') ?></label>
<div class="group-controls">
<select class="number" name="ttl" id="ttl" required="required"><?php
$found = false;
@@ -127,130 +227,131 @@
}
?></select>
<label for="mute">
- <input type="checkbox" name="mute" id="mute" value="1"<?php echo $this->feed->mute() ? ' checked="checked"' : ''; ?> />
- <?php echo _t('sub.feed.mute'); ?>
+ <input type="checkbox" name="mute" id="mute" value="1"<?= $this->feed->mute() ? ' checked="checked"' : '' ?> />
+ <?= _t('sub.feed.mute') ?>
</label>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="pubsubhubbub"><?php echo _t('sub.feed.websub'); ?></label>
+ <label class="group-name" for="pubsubhubbub"><?= _t('sub.feed.websub') ?></label>
<div class="group-controls">
<label class="checkbox" for="pubsubhubbub">
- <input type="checkbox" name="pubsubhubbub" id="pubsubhubbub" disabled="disabled" value="1"<?php echo $this->feed->pubSubHubbubEnabled() ? ' checked="checked"' : ''; ?> />
+ <input type="checkbox" name="pubsubhubbub" id="pubsubhubbub" disabled="disabled" value="1"<?= $this->feed->pubSubHubbubEnabled() ? ' checked="checked"' : '' ?> />
</label>
</div>
</div>
<div class="form-group form-actions">
<div class="group-controls">
- <button class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button>
- <button class="btn btn-attention confirm" formmethod="post" formaction="<?php echo _url('feed', 'truncate', 'id', $this->feed->id()); ?>"><?php echo _t('gen.action.truncate'); ?></button>
+ <button class="btn btn-important"><?= _t('gen.action.submit') ?></button>
+ <button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button>
+ <button class="btn btn-attention confirm" formmethod="post" formaction="<?= _url('feed', 'truncate', 'id', $this->feed->id()) ?>"><?= _t('gen.action.truncate') ?></button>
</div>
</div>
- <legend><?php echo _t('sub.feed.auth.configuration'); ?></legend>
+ <legend><?= _t('sub.feed.auth.configuration') ?></legend>
<?php $auth = $this->feed->httpAuth(false); ?>
<div class="form-group">
- <label class="group-name" for="http_user_feed<?php echo $this->feed->id(); ?>"><?php echo _t('sub.feed.auth.username'); ?></label>
+ <label class="group-name" for="http_user_feed<?= $this->feed->id() ?>"><?= _t('sub.feed.auth.username') ?></label>
<div class="group-controls">
- <input type="text" name="http_user_feed<?php echo $this->feed->id(); ?>" id="http_user_feed<?php echo $this->feed->id(); ?>" class="extend" value="<?php echo empty($auth['username']) ? ' ' : $auth['username']; ?>" autocomplete="off" />
- <?php echo _i('help'); ?> <?php echo _t('sub.feed.auth.help'); ?>
+ <input type="text" name="http_user_feed<?= $this->feed->id() ?>" id="http_user_feed<?= $this->feed->id() ?>" class="extend" value="<?= empty($auth['username']) ? ' ' : $auth['username'] ?>" autocomplete="off" />
+ <?= _i('help') ?> <?= _t('sub.feed.auth.help') ?>
</div>
- <label class="group-name" for="http_pass_feed<?php echo $this->feed->id(); ?>"><?php echo _t('sub.feed.auth.password'); ?></label>
+ <label class="group-name" for="http_pass_feed<?= $this->feed->id() ?>"><?= _t('sub.feed.auth.password') ?></label>
<div class="group-controls">
- <input type="password" name="http_pass_feed<?php echo $this->feed->id(); ?>" id="http_pass_feed<?php echo $this->feed->id(); ?>" class="extend" value="<?php echo $auth['password']; ?>" autocomplete="new-password" />
+ <input type="password" name="http_pass_feed<?= $this->feed->id() ?>" id="http_pass_feed<?= $this->feed->id() ?>" class="extend" value="<?= $auth['password'] ?>" autocomplete="new-password" />
</div>
</div>
<div class="form-group form-actions">
<div class="group-controls">
- <button type="submit" class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button>
- <button type="reset" class="btn"><?php echo _t('gen.action.cancel'); ?></button>
+ <button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button>
+ <button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button>
</div>
</div>
- <legend><?php echo _t('sub.feed.advanced'); ?></legend>
+ <legend><?= _t('sub.feed.advanced') ?></legend>
<div class="form-group">
- <label class="group-name" for="path_entries"><?php echo _t('sub.feed.css_path'); ?></label>
+ <label class="group-name" for="path_entries"><?= _t('sub.feed.css_path') ?></label>
<div class="group-controls">
- <input type="text" name="path_entries" id="path_entries" class="extend" value="<?php echo $this->feed->pathEntries(); ?>" placeholder="<?php echo _t('gen.short.blank_to_disable'); ?>" />
- <?php echo _i('help'); ?> <?php echo _t('sub.feed.css_help'); ?>
+ <input type="text" name="path_entries" id="path_entries" class="extend" value="<?= $this->feed->pathEntries() ?>" placeholder="<?= _t('gen.short.blank_to_disable') ?>" />
+ <?= _i('help') ?> <?= _t('sub.feed.css_help') ?>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="mark_updated_article_unread"><?php echo _t('conf.reading.mark_updated_article_unread'); ?></label>
+ <label class="group-name" for="mark_updated_article_unread"><?= _t('conf.reading.mark_updated_article_unread') ?></label>
<div class="group-controls">
<label class="checkbox" for="mark_updated_article_unread">
<select name="mark_updated_article_unread" id="mark_updated_article_unread">
- <option value=""<?php echo $this->feed->attributes('mark_updated_article_unread') === null ? ' selected="selected"' : ''; ?>><?php echo _t('gen.short.by_default'); ?></option>
- <option value="0"<?php echo $this->feed->attributes('mark_updated_article_unread') === false ? ' selected="selected"' : ''; ?>><?php echo _t('gen.short.no'); ?></option>
- <option value="1"<?php echo $this->feed->attributes('mark_updated_article_unread') === true ? ' selected="selected"' : ''; ?>><?php echo _t('gen.short.yes'); ?></option>
+ <option value=""<?= $this->feed->attributes('mark_updated_article_unread') === null ? ' selected="selected"' : '' ?>><?= _t('gen.short.by_default') ?></option>
+ <option value="0"<?= $this->feed->attributes('mark_updated_article_unread') === false ? ' selected="selected"' : '' ?>><?= _t('gen.short.no') ?></option>
+ <option value="1"<?= $this->feed->attributes('mark_updated_article_unread') === true ? ' selected="selected"' : '' ?>><?= _t('gen.short.yes') ?></option>
</select>
</label>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="read_upon_reception"><?php echo _t('conf.reading.read.when'); ?></label>
+ <label class="group-name" for="read_upon_reception"><?= _t('conf.reading.read.when') ?></label>
<div class="group-controls">
<label class="checkbox" for="read_upon_reception">
<select name="read_upon_reception" id="read_upon_reception">
- <option value=""<?php echo $this->feed->attributes('read_upon_reception') === null ? ' selected="selected"' : ''; ?>><?php echo _t('gen.short.by_default'); ?></option>
- <option value="0"<?php echo $this->feed->attributes('read_upon_reception') === false ? ' selected="selected"' : ''; ?>><?php echo _t('gen.short.no'); ?></option>
- <option value="1"<?php echo $this->feed->attributes('read_upon_reception') === true ? ' selected="selected"' : ''; ?>><?php echo _t('gen.short.yes'); ?></option>
+ <option value=""<?= $this->feed->attributes('read_upon_reception') === null ? ' selected="selected"' : '' ?>><?= _t('gen.short.by_default') ?></option>
+ <option value="0"<?= $this->feed->attributes('read_upon_reception') === false ? ' selected="selected"' : '' ?>><?= _t('gen.short.no') ?></option>
+ <option value="1"<?= $this->feed->attributes('read_upon_reception') === true ? ' selected="selected"' : '' ?>><?= _t('gen.short.yes') ?></option>
</select>
- <?php echo _t('conf.reading.read.upon_reception'); ?>
+ <?= _t('conf.reading.read.upon_reception') ?>
</label>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="clear_cache"><?php echo _t('sub.feed.clear_cache'); ?></label>
+ <label class="group-name" for="clear_cache"><?= _t('sub.feed.clear_cache') ?></label>
<div class="group-controls">
- <input type="checkbox" name="clear_cache" id="clear_cache" value="1"<?php echo $this->feed->attributes('clear_cache') ? ' checked="checked"' : ''; ?> />
+ <input type="checkbox" name="clear_cache" id="clear_cache" value="1"<?= $this->feed->attributes('clear_cache') ? ' checked="checked"' : '' ?> />
</div>
</div>
<?php if (FreshRSS_Auth::hasAccess('admin')) { ?>
<div class="form-group">
- <label class="group-name" for="timeout"><?php echo _t('sub.feed.timeout'); ?></label>
+ <label class="group-name" for="timeout"><?= _t('sub.feed.timeout') ?></label>
<div class="group-controls">
- <input type="number" name="timeout" id="timeout" min="3" max="120" value="<?php echo $this->feed->attributes('timeout'); ?>" placeholder="<?php echo _t('gen.short.by_default'); ?>" />
+ <input type="number" name="timeout" id="timeout" min="3" max="120" value="<?= $this->feed->attributes('timeout') ?>" placeholder="<?= _t('gen.short.by_default') ?>" />
</div>
</div>
<div class="form-group">
- <label class="group-name" for="ssl_verify"><?php echo _t('sub.feed.ssl_verify'); ?></label>
+ <label class="group-name" for="ssl_verify"><?= _t('sub.feed.ssl_verify') ?></label>
<div class="group-controls">
<label class="checkbox" for="ssl_verify">
<select name="ssl_verify" id="ssl_verify">
- <option value=""<?php echo $this->feed->attributes('ssl_verify') === null ? ' selected="selected"' : ''; ?>><?php echo _t('gen.short.by_default'); ?></option>
- <option value="0"<?php echo $this->feed->attributes('ssl_verify') === false ? ' selected="selected"' : ''; ?>><?php echo _t('gen.short.no'); ?></option>
- <option value="1"<?php echo $this->feed->attributes('ssl_verify') === true ? ' selected="selected"' : ''; ?>><?php echo _t('gen.short.yes'); ?></option>
+ <option value=""<?= $this->feed->attributes('ssl_verify') === null ? ' selected="selected"' : '' ?>><?= _t('gen.short.by_default') ?></option>
+ <option value="0"<?= $this->feed->attributes('ssl_verify') === false ? ' selected="selected"' : '' ?>><?= _t('gen.short.no') ?></option>
+ <option value="1"<?= $this->feed->attributes('ssl_verify') === true ? ' selected="selected"' : '' ?>><?= _t('gen.short.yes') ?></option>
</select>
</label>
</div>
</div>
<?php } ?>
- <legend><?php echo _t('sub.feed.filteractions'); ?></legend>
+ <legend><?= _t('sub.feed.filteractions') ?></legend>
<div class="form-group">
- <label class="group-name" for="filteractions_read"><?php echo _t('conf.reading.read.when'); ?></label>
+ <label class="group-name" for="filteractions_read"><?= _t('conf.reading.read.when') ?></label>
<div class="group-controls">
<textarea name="filteractions_read" id="filteractions_read"><?php
foreach ($this->feed->filtersAction('read') as $filterRead) {
echo htmlspecialchars($filterRead->getRawInput(), ENT_NOQUOTES, 'UTF-8'), PHP_EOL;
}
?></textarea>
- <?php echo _i('help'); ?> <?php echo _t('sub.feed.filteractions.help'); ?>
+ <?= _i('help') ?> <?= _t('sub.feed.filteractions.help') ?>
</div>
</div>
<div class="form-group form-actions">
<div class="group-controls">
- <button type="submit" class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button>
- <button type="reset" class="btn"><?php echo _t('gen.action.cancel'); ?></button>
+ <button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button>
+ <button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button>
</div>
</div>
</form>
diff --git a/app/views/helpers/index/normal/entry_bottom.phtml b/app/views/helpers/index/normal/entry_bottom.phtml
index c0edbdf7d..dd84ca346 100644
--- a/app/views/helpers/index/normal/entry_bottom.phtml
+++ b/app/views/helpers/index/normal/entry_bottom.phtml
@@ -19,7 +19,7 @@
if ($this->entry->isRead()) {
$arUrl['params']['is_read'] = 0;
}
- ?><a class="read" href="<?php echo Minz_Url::display($arUrl); ?>"><?php
+ ?><a class="read" href="<?= Minz_Url::display($arUrl) ?>"><?php
echo _i($this->entry->isRead() ? 'read' : 'unread'); ?></a><?php
?></li><?php
}
@@ -29,7 +29,7 @@
if ($this->entry->isFavorite()) {
$arUrl['params']['is_favorite'] = 0;
}
- ?><a class="bookmark" href="<?php echo Minz_Url::display($arUrl); ?>"><?php
+ ?><a class="bookmark" href="<?= Minz_Url::display($arUrl) ?>"><?php
echo _i($this->entry->isFavorite() ? 'starred' : 'non-starred'); ?></a><?php
?></li><?php
}
@@ -37,9 +37,9 @@
if ($bottomline_labels) {
?><li class="item">
<div class="dropdown dynamictags">
- <div id="dropdown-labels-<?php echo $this->entry->id();?>" class="dropdown-target"></div>
- <?php echo FreshRSS_Themes::alt('label'); ?>
- <a class="dropdown-toggle" href="#dropdown-labels-<?php echo $this->entry->id();?>"><?php
+ <div id="dropdown-labels-<?= $this->entry->id() ?>" class="dropdown-target"></div>
+ <?= FreshRSS_Themes::alt('label') ?>
+ <a class="dropdown-toggle" href="#dropdown-labels-<?= $this->entry->id() ?>"><?php
echo _t('index.menu.tags');
?></a>
<ul class="dropdown-menu dropdown-menu-scrollable">
@@ -53,15 +53,15 @@
if (!empty($tags)) {
?><li class="item">
<div class="dropdown">
- <div id="dropdown-tags-<?php echo $this->entry->id();?>" class="dropdown-target"></div>
- <?php echo _i('tag'); ?>
- <a class="dropdown-toggle" href="#dropdown-tags-<?php echo $this->entry->id();?>"><?php
+ <div id="dropdown-tags-<?= $this->entry->id() ?>" class="dropdown-target"></div>
+ <?= _i('tag') ?>
+ <a class="dropdown-toggle" href="#dropdown-tags-<?= $this->entry->id() ?>"><?php
echo _t('index.tag.related');
?></a>
<ul class="dropdown-menu">
<li class="dropdown-close"><a href="#close">❌</a></li><?php
foreach ($tags as $tag) {
- ?><li class="item"><a href="<?php echo _url('index', 'index', 'search', '#' . str_replace(' ', '+', htmlspecialchars_decode($tag, ENT_QUOTES))); ?>"><?php echo $tag; ?></a></li><?php
+ ?><li class="item"><a href="<?= _url('index', 'index', 'search', '#' . str_replace(' ', '+', htmlspecialchars_decode($tag, ENT_QUOTES))) ?>"><?= $tag ?></a></li><?php
} ?>
</ul>
</div>
@@ -70,10 +70,10 @@
?><li class="item"><?php
if ($bottomline_sharing) {
?><div class="dropdown">
- <div id="dropdown-share-<?php echo $this->entry->id();?>" class="dropdown-target"></div>
- <a class="dropdown-toggle" href="#dropdown-share-<?php echo $this->entry->id();?>">
- <?php echo _i('share'); ?>
- <?php echo _t('index.share'); ?>
+ <div id="dropdown-share-<?= $this->entry->id() ?>" class="dropdown-target"></div>
+ <a class="dropdown-toggle" href="#dropdown-share-<?= $this->entry->id() ?>">
+ <?= _i('share') ?>
+ <?= _t('index.share') ?>
</a>
<ul class="dropdown-menu">
@@ -90,11 +90,11 @@
$share->update($share_options);
?><li class="item share">
<?php if ('GET' === $share->method()) {?>
- <a target="_blank" rel="noreferrer" href="<?php echo $share->url(); ?>"><?php echo $share->name(); ?></a>
+ <a target="_blank" rel="noreferrer" href="<?= $share->url() ?>"><?= $share->name() ?></a>
<?php } else {?>
- <a href="POST"><?php echo $share->name(); ?></a>
- <form method="POST" action="<?php echo $share->url(); ?>" disabled="disabled">
- <input type="hidden" value="<?php echo $link; ?>" name="<?php echo $share->field(); ?>"/>
+ <a href="POST"><?= $share->name() ?></a>
+ <form method="POST" action="<?= $share->url() ?>" disabled="disabled">
+ <input type="hidden" value="<?= $link ?>" name="<?= $share->field() ?>"/>
</form>
<?php } ?>
</li><?php
@@ -104,9 +104,9 @@
<?php } ?>
</li><?php
if ($bottomline_date) {
- ?><li class="item date"><?php echo $this->entry->date(); ?></li><?php
+ ?><li class="item date"><?= $this->entry->date() ?></li><?php
}
if ($bottomline_link) {
- ?><li class="item link"><a target="_blank" rel="noreferrer" href="<?php echo $this->entry->link(); ?>"><?php echo _i('link'); ?></a></li><?php
+ ?><li class="item link"><a target="_blank" rel="noreferrer" href="<?= $this->entry->link() ?>"><?= _i('link') ?></a></li><?php
} ?>
</ul>
diff --git a/app/views/helpers/index/normal/entry_header.phtml b/app/views/helpers/index/normal/entry_header.phtml
index 86298e59f..d22cf5036 100644
--- a/app/views/helpers/index/normal/entry_header.phtml
+++ b/app/views/helpers/index/normal/entry_header.phtml
@@ -1,6 +1,7 @@
<?php
$topline_read = FreshRSS_Context::$user_conf->topline_read;
$topline_favorite = FreshRSS_Context::$user_conf->topline_favorite;
+ $topline_display_authors = FreshRSS_Context::$user_conf->topline_display_authors;
$topline_date = FreshRSS_Context::$user_conf->topline_date;
$topline_link = FreshRSS_Context::$user_conf->topline_link;
?><ul class="horizontal-list flux_header"><?php
@@ -11,7 +12,7 @@
if ($this->entry->isRead()) {
$arUrl['params']['is_read'] = 0;
}
- ?><a class="read" href="<?php echo Minz_Url::display($arUrl); ?>"><?php
+ ?><a class="read" href="<?= Minz_Url::display($arUrl) ?>"><?php
echo _i($this->entry->isRead() ? 'read' : 'unread'); ?></a><?php
?></li><?php
}
@@ -21,13 +22,26 @@
if ($this->entry->isFavorite()) {
$arUrl['params']['is_favorite'] = 0;
}
- ?><a class="bookmark" href="<?php echo Minz_Url::display($arUrl); ?>"><?php
+ ?><a class="bookmark" href="<?= Minz_Url::display($arUrl) ?>"><?php
echo _i($this->entry->isFavorite() ? 'starred' : 'non-starred'); ?></a><?php
?></li><?php
}
}
- ?><li class="item website"><a href="<?php echo _url('index', 'index', 'get', 'f_' . $this->feed->id()); ?>"><img class="favicon" src="<?php echo $this->feed->favicon(); ?>" alt="✇" /> <span><?php echo $this->feed->name(); ?></span></a></li>
- <li class="item title"><a target="_blank" rel="noreferrer" href="<?php echo $this->entry->link(); ?>"><?php echo $this->entry->title(); ?></a></li>
- <?php if ($topline_date) { ?><li class="item date"><?php echo $this->entry->date(); ?> </li><?php } ?>
- <?php if ($topline_link) { ?><li class="item link"><a target="_blank" rel="noreferrer" href="<?php echo $this->entry->link(); ?>"><?php echo _i('link'); ?></a></li><?php } ?>
+ ?><li class="item website"><a href="<?= _url('index', 'index', 'get', 'f_' . $this->feed->id()) ?>"><img class="favicon" src="<?= $this->feed->favicon() ?>" alt="✇" /> <span><?= $this->feed->name() ?></span></a></li>
+ <li class="item title"><a target="_blank" rel="noreferrer" href="<?= $this->entry->link() ?>"><?= $this->entry->title() ?></a><?php
+ if ($topline_display_authors):
+ ?><div class="item author"><?php
+ $authors = $this->entry->authors();
+ if (is_array($authors)) {
+ $first = true;
+ foreach ($authors as $author) {
+ echo $first ? $author : ', ' . $author;
+ $first = false;
+ }
+ }
+ ?></div><?php
+ endif;
+ ?></li>
+ <?php if ($topline_date) { ?><li class="item date"><?= $this->entry->date() ?> </li><?php } ?>
+ <?php if ($topline_link) { ?><li class="item link"><a target="_blank" rel="noreferrer" href="<?= $this->entry->link() ?>"><?= _i('link') ?></a></li><?php } ?>
</ul>
diff --git a/app/views/helpers/logs_pagination.phtml b/app/views/helpers/logs_pagination.phtml
index bf9d91f04..e74074173 100755
--- a/app/views/helpers/logs_pagination.phtml
+++ b/app/views/helpers/logs_pagination.phtml
@@ -9,14 +9,14 @@
<?php $params[$getteur] = 1; ?>
<li class="item pager-first">
<?php if ($this->currentPage > 1) { ?>
- <a href="<?php echo Minz_Url::display(array('c' => $c, 'a' => $a, 'params' => $params)); ?>">« <?php echo _t('gen.pagination.first'); ?></a>
+ <a href="<?= Minz_Url::display(array('c' => $c, 'a' => $a, 'params' => $params)) ?>">« <?= _t('gen.pagination.first') ?></a>
<?php } ?>
</li>
<?php $params[$getteur] = $this->currentPage - 1; ?>
<li class="item pager-previous">
<?php if ($this->currentPage > 1) { ?>
- <a href="<?php echo Minz_Url::display(array('c' => $c, 'a' => $a, 'params' => $params)); ?>">‹ <?php echo _t('gen.pagination.previous'); ?></a>
+ <a href="<?= Minz_Url::display(array('c' => $c, 'a' => $a, 'params' => $params)) ?>">‹ <?= _t('gen.pagination.previous') ?></a>
<?php } ?>
</li>
@@ -24,9 +24,9 @@
<?php if($i > 0 && $i <= $this->nbPage) { ?>
<?php if ($i != $this->currentPage) { ?>
<?php $params[$getteur] = $i; ?>
- <li class="item pager-item"><a href="<?php echo Minz_Url::display(array('c' => $c, 'a' => $a, 'params' => $params)); ?>"><?php echo $i; ?></a></li>
+ <li class="item pager-item"><a href="<?= Minz_Url::display(array('c' => $c, 'a' => $a, 'params' => $params)) ?>"><?= $i ?></a></li>
<?php } else { ?>
- <li class="item pager-current"><?php echo $i; ?></li>
+ <li class="item pager-current"><?= $i ?></li>
<?php } ?>
<?php } ?>
<?php } ?>
@@ -34,13 +34,13 @@
<?php $params[$getteur] = $this->currentPage + 1; ?>
<li class="item pager-next">
<?php if ($this->currentPage < $this->nbPage) { ?>
- <a href="<?php echo Minz_Url::display(array('c' => $c, 'a' => $a, 'params' => $params)); ?>"><?php echo _t('gen.pagination.next'); ?> ›</a>
+ <a href="<?= Minz_Url::display(array('c' => $c, 'a' => $a, 'params' => $params)) ?>"><?= _t('gen.pagination.next') ?> ›</a>
<?php } ?>
</li>
<?php $params[$getteur] = $this->nbPage; ?>
<li class="item pager-last">
<?php if ($this->currentPage < $this->nbPage) { ?>
- <a href="<?php echo Minz_Url::display(array('c' => $c, 'a' => $a, 'params' => $params)); ?>"><?php echo _t('gen.pagination.last'); ?> »</a>
+ <a href="<?= Minz_Url::display(array('c' => $c, 'a' => $a, 'params' => $params)) ?>"><?= _t('gen.pagination.last') ?> »</a>
<?php } ?>
</li>
</ul>
diff --git a/app/views/helpers/pagination.phtml b/app/views/helpers/pagination.phtml
index fc37ce3f5..b7d62ceab 100755
--- a/app/views/helpers/pagination.phtml
+++ b/app/views/helpers/pagination.phtml
@@ -18,26 +18,26 @@
?>
<form id="mark-read-pagination" method="post">
-<input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
+<input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
<ul class="pagination">
<li class="item pager-next">
<?php if (FreshRSS_Context::$next_id) { ?>
- <a id="load_more" href="<?php echo Minz_Url::display($url_next); ?>">
- <?php echo _t('gen.pagination.load_more'); ?>
+ <a id="load_more" href="<?= Minz_Url::display($url_next) ?>">
+ <?= _t('gen.pagination.load_more') ?>
</a>
<?php } elseif ($url_mark_read) { ?>
<button id="bigMarkAsRead"
- class="as-link <?php echo FreshRSS_Context::$user_conf->reading_confirm ? 'confirm" disabled="disabled' : ''; ?>"
+ class="as-link <?= FreshRSS_Context::$user_conf->reading_confirm ? 'confirm" disabled="disabled' : '' ?>"
form="mark-read-pagination"
- formaction="<?php echo Minz_Url::display($url_mark_read); ?>"
+ formaction="<?= Minz_Url::display($url_mark_read) ?>"
type="submit">
- <?php echo _t('gen.pagination.nothing_to_load'); ?><br />
+ <?= _t('gen.pagination.nothing_to_load') ?><br />
<span class="bigTick">✓</span><br />
- <?php echo _t('gen.pagination.mark_all_read'); ?>
+ <?= _t('gen.pagination.mark_all_read') ?>
</button>
<?php } else { ?>
<a id="bigMarkAsRead" href=".">
- <?php echo _t('gen.pagination.nothing_to_load'); ?><br />
+ <?= _t('gen.pagination.nothing_to_load') ?><br />
</a>
<?php } ?>
</li>
diff --git a/app/views/importExport/index.phtml b/app/views/importExport/index.phtml
index 139e715c5..e5a24dbc4 100644
--- a/app/views/importExport/index.phtml
+++ b/app/views/importExport/index.phtml
@@ -1,14 +1,14 @@
<?php $this->partial('aside_subscription'); ?>
<div class="post ">
- <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
+ <a href="<?= _url('index', 'index') ?>"><?= _t('gen.action.back_to_rss_feeds') ?></a>
- <form method="post" action="<?php echo _url('importExport', 'import'); ?>" enctype="multipart/form-data">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
- <legend><?php echo _t('sub.import_export.import'); ?></legend>
+ <form method="post" action="<?= _url('importExport', 'import') ?>" enctype="multipart/form-data">
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
+ <legend><?= _t('sub.import_export.import') ?></legend>
<div class="form-group">
<label class="group-name" for="file">
- <?php echo extension_loaded('zip') ? _t('sub.import_export.file_to_import') : _t('sub.import_export.file_to_import_no_zip'); ?>
+ <?= extension_loaded('zip') ? _t('sub.import_export.file_to_import') : _t('sub.import_export.file_to_import_no_zip') ?>
</label>
<div class="group-controls">
<input type="file" name="file" id="file" />
@@ -17,30 +17,30 @@
<div class="form-group form-actions">
<div class="group-controls">
- <button type="submit" class="btn btn-important"><?php echo _t('gen.action.import'); ?></button>
+ <button type="submit" class="btn btn-important"><?= _t('gen.action.import') ?></button>
</div>
</div>
</form>
<?php if (count($this->feeds) > 0) { ?>
- <form method="post" action="<?php echo _url('importExport', 'export'); ?>">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
- <legend><?php echo _t('sub.import_export.export'); ?></legend>
+ <form method="post" action="<?= _url('importExport', 'export') ?>">
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
+ <legend><?= _t('sub.import_export.export') ?></legend>
<div class="form-group">
<div class="group-controls">
<label class="checkbox" for="export_opml">
<input type="checkbox" name="export_opml" id="export_opml" value="1" checked="checked" />
- <?php echo _t('sub.import_export.export_opml'); ?>
+ <?= _t('sub.import_export.export_opml') ?>
</label>
<label class="checkbox" for="export_labelled">
- <input type="checkbox" name="export_labelled" id="export_labelled" value="1" <?php echo extension_loaded('zip') ? 'checked="checked"' : ''; ?> />
- <?php echo _t('sub.import_export.export_labelled'); ?>
+ <input type="checkbox" name="export_labelled" id="export_labelled" value="1" <?= extension_loaded('zip') ? 'checked="checked"' : '' ?> />
+ <?= _t('sub.import_export.export_labelled') ?>
</label>
<label class="checkbox" for="export_starred">
- <input type="checkbox" name="export_starred" id="export_starred" value="1" <?php echo extension_loaded('zip') ? 'checked="checked"' : ''; ?> />
- <?php echo _t('sub.import_export.export_starred'); ?>
+ <input type="checkbox" name="export_starred" id="export_starred" value="1" <?= extension_loaded('zip') ? 'checked="checked"' : '' ?> />
+ <?= _t('sub.import_export.export_starred') ?>
</label>
<?php
@@ -49,10 +49,10 @@
$select_args = ' size="' . min(10, count($this->feeds)) .'" multiple="multiple"';
}
?>
- <select name="export_feeds[]"<?php echo $select_args; ?> size="10">
- <?php echo extension_loaded('zip') ? '' : '<option></option>'; ?>
+ <select name="export_feeds[]"<?= $select_args ?> size="10">
+ <?= extension_loaded('zip') ? '' : '<option></option>' ?>
<?php foreach ($this->feeds as $feed) { ?>
- <option value="<?php echo $feed->id(); ?>"><?php echo $feed->name(); ?></option>
+ <option value="<?= $feed->id() ?>"><?= $feed->name() ?></option>
<?php } ?>
</select>
</div>
@@ -60,7 +60,7 @@
<div class="form-group form-actions">
<div class="group-controls">
- <button type="submit" class="btn btn-important"><?php echo _t('gen.action.export'); ?></button>
+ <button type="submit" class="btn btn-important"><?= _t('gen.action.export') ?></button>
</div>
</div>
</form>
diff --git a/app/views/index/about.phtml b/app/views/index/about.phtml
index 649729952..320847886 100644
--- a/app/views/index/about.phtml
+++ b/app/views/index/about.phtml
@@ -1,26 +1,26 @@
<div class="post content">
- <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
+ <a href="<?= _url('index', 'index') ?>"><?= _t('gen.action.back_to_rss_feeds') ?></a>
- <h1><?php echo _t('index.about'); ?></h1>
+ <h1><?= _t('index.about') ?></h1>
<dl class="infos">
- <dt><?php echo _t('index.about.project_website'); ?></dt>
- <dd><a href="<?php echo FRESHRSS_WEBSITE; ?>"><?php echo FRESHRSS_WEBSITE; ?></a></dd>
+ <dt><?= _t('index.about.project_website') ?></dt>
+ <dd><a href="<?= FRESHRSS_WEBSITE ?>"><?= FRESHRSS_WEBSITE ?></a></dd>
- <dt><?php echo _t('index.about.bugs_reports'); ?></dt>
- <dd><?php echo _t('index.about.github'); ?></dd>
+ <dt><?= _t('index.about.bugs_reports') ?></dt>
+ <dd><?= _t('index.about.github') ?></dd>
- <dt><?php echo _t('index.about.license'); ?></dt>
- <dd><?php echo _t('index.about.agpl3'); ?></dd>
+ <dt><?= _t('index.about.license') ?></dt>
+ <dd><?= _t('index.about.agpl3') ?></dd>
<?php if (FreshRSS_Auth::hasAccess()): ?>
- <dt><?php echo _t('index.about.version'); ?></dt>
- <dd><?php echo FRESHRSS_VERSION; ?></dd>
+ <dt><?= _t('index.about.version') ?></dt>
+ <dd><?= FRESHRSS_VERSION ?></dd>
<?php endif; ?>
</dl>
- <p><?php echo _t('index.about.freshrss_description'); ?></p>
+ <p><?= _t('index.about.freshrss_description') ?></p>
- <h1><?php echo _t('index.about.credits'); ?></h1>
- <p><?php echo _t('index.about.credits_content'); ?></p>
+ <h1><?= _t('index.about.credits') ?></h1>
+ <p><?= _t('index.about.credits_content') ?></p>
</div>
diff --git a/app/views/index/global.phtml b/app/views/index/global.phtml
index 2f25b6dc2..a49e16525 100644
--- a/app/views/index/global.phtml
+++ b/app/views/index/global.phtml
@@ -9,7 +9,7 @@
}
?>
-<div id="stream" class="global<?php echo $class; ?>">
+<div id="stream" class="global<?= $class ?>">
<?php
$params = Minz_Request::fetchGET();
unset($params['c']);
@@ -26,8 +26,8 @@
if (!empty($feeds)) {
?>
- <div class="box category" data-unread="<?php echo $cat->nbNotRead(); ?>">
- <div class="box-title"><a class="title" data-unread="<?php echo format_number($cat->nbNotRead()); ?>" href="<?php echo Minz_Url::display($url_base); ?>"><?php echo $cat->name(); ?></a></div>
+ <div class="box category" data-unread="<?= $cat->nbNotRead() ?>">
+ <div class="box-title"><a class="title" data-unread="<?= format_number($cat->nbNotRead()) ?>" href="<?= Minz_Url::display($url_base) ?>"><?= $cat->name() ?></a></div>
<ul class="box-content">
<?php
@@ -37,9 +37,9 @@
$empty = $feed->nbEntries() === 0 ? ' empty' : '';
$url_base['params']['get'] = 'f_' . $feed->id();
?>
- <li id="f_<?php echo $feed->id(); ?>" class="item feed<?php echo $error, $empty, $feed->mute() ? ' mute' : ''; ?>" data-unread="<?php echo $feed->nbNotRead(); ?>" data-priority="<?php echo $feed->priority(); ?>">
- <img class="favicon" src="<?php echo $feed->favicon(); ?>" alt="✇" />
- <a class="item-title" data-unread="<?php echo format_number($feed->nbNotRead()); ?>" href="<?php echo Minz_Url::display($url_base); ?>"><?php echo $feed->name(); ?></a>
+ <li id="f_<?= $feed->id() ?>" class="item feed<?= $error, $empty, $feed->mute() ? ' mute' : '' ?>" data-unread="<?= $feed->nbNotRead() ?>" data-priority="<?= $feed->priority() ?>">
+ <img class="favicon" src="<?= $feed->favicon() ?>" alt="✇" />
+ <a class="item-title" data-unread="<?= format_number($feed->nbNotRead()) ?>" href="<?= Minz_Url::display($url_base) ?>"><?= $feed->name() ?></a>
</li>
<?php } ?>
</ul>
@@ -51,7 +51,7 @@
</div>
<div id="overlay">
- <a class="close" href="#"><?php echo _i('close'); ?></a>
+ <a class="close" href="#"><?= _i('close') ?></a>
</div>
-<div id="panel"<?php echo FreshRSS_Context::$user_conf->display_posts ? '' : ' class="hide_posts"'; ?>>
+<div id="panel"<?= FreshRSS_Context::$user_conf->display_posts ? '' : ' class="hide_posts"' ?>>
</div>
diff --git a/app/views/index/logs.phtml b/app/views/index/logs.phtml
index a88f89278..2deb1c315 100644
--- a/app/views/index/logs.phtml
+++ b/app/views/index/logs.phtml
@@ -1,11 +1,11 @@
<div class="post content">
- <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
+ <a href="<?= _url('index', 'index') ?>"><?= _t('gen.action.back_to_rss_feeds') ?></a>
- <h1><?php echo _t('index.log'); ?></h1>
- <form method="post" action="<?php echo _url('index', 'logs'); ?>"><p>
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
+ <h1><?= _t('index.log') ?></h1>
+ <form method="post" action="<?= _url('index', 'logs') ?>"><p>
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
<input type="hidden" name="clearLogs" />
- <button type="submit" class="btn"><?php echo _t('index.log.clear'); ?></button>
+ <button type="submit" class="btn"><?= _t('index.log.clear') ?></button>
</p></form>
<?php $items = $this->logsPaginator->items(); ?>
@@ -15,12 +15,12 @@
<?php $this->logsPaginator->render('logs_pagination.phtml', 'page'); ?>
<?php foreach ($items as $log) { ?>
- <div class="log <?php echo $log->level(); ?>"><span class="date"><?php echo @date('Y-m-d H:i:s', @strtotime($log->date())); ?></span><?php echo htmlspecialchars($log->info(), ENT_NOQUOTES, 'UTF-8'); ?></div>
+ <div class="log <?= $log->level() ?>"><span class="date"><?= @date('Y-m-d H:i:s', @strtotime($log->date())) ?></span><?= htmlspecialchars($log->info(), ENT_NOQUOTES, 'UTF-8') ?></div>
<?php } ?>
<?php $this->logsPaginator->render('logs_pagination.phtml','page'); ?>
</div>
<?php } else { ?>
- <p class="alert alert-warn"><?php echo _t('index.log.empty'); ?></p>
+ <p class="alert alert-warn"><?= _t('index.log.empty') ?></p>
<?php } ?>
</div>
diff --git a/app/views/index/normal.phtml b/app/views/index/normal.phtml
index ac2ea812d..f556df201 100644
--- a/app/views/index/normal.phtml
+++ b/app/views/index/normal.phtml
@@ -14,9 +14,9 @@ if (!empty($this->entries)) {
$today = @strtotime('today');
?>
-<div id="stream" class="normal<?php echo $hidePosts ? ' hide_posts' : ''; ?>"><?php
+<div id="stream" class="normal<?= $hidePosts ? ' hide_posts' : '' ?>"><?php
?><div id="new-article">
- <a href="<?php echo Minz_Url::display(Minz_Request::currentRequest()); ?>"><?php echo _t('gen.js.new_article'); /* TODO: move string in JS*/ ?></a>
+ <a href="<?= Minz_Url::display(Minz_Request::currentRequest()) ?>"><?= _t('gen.js.new_article'); /* TODO: move string in JS*/ ?></a>
</div><?php
foreach ($this->entries as $item) {
$this->entry = Minz_ExtensionManager::callHook('entry_before_display', $item);
@@ -36,23 +36,23 @@ if (!empty($this->entries)) {
if ($display_today && $this->entry->isDay(FreshRSS_Days::TODAY, $today)) {
?><div class="day" id="day_today"><?php
echo _t('gen.date.today');
- ?><span class="date"> — <?php echo timestamptodate(time(), false); ?></span><?php
- ?><span class="name"><?php echo FreshRSS_Context::$name; ?></span><?php
+ ?><span class="date"> — <?= timestamptodate(time(), false) ?></span><?php
+ ?><span class="name"><?= FreshRSS_Context::$name ?></span><?php
?></div><?php
$display_today = false;
}
if ($display_yesterday && $this->entry->isDay(FreshRSS_Days::YESTERDAY, $today)) {
?><div class="day" id="day_yesterday"><?php
echo _t('gen.date.yesterday');
- ?><span class="date"> — <?php echo timestamptodate(time() - 86400, false); ?></span><?php
- ?><span class="name"><?php echo FreshRSS_Context::$name; ?></span><?php
+ ?><span class="date"> — <?= timestamptodate(time() - 86400, false) ?></span><?php
+ ?><span class="name"><?= FreshRSS_Context::$name ?></span><?php
?></div><?php
$display_yesterday = false;
}
if ($display_others && $this->entry->isDay(FreshRSS_Days::BEFORE_YESTERDAY, $today)) {
?><div class="day" id="day_before_yesterday"><?php
echo _t('gen.date.before_yesterday');
- ?><span class="name"><?php echo FreshRSS_Context::$name; ?></span><?php
+ ?><span class="name"><?= FreshRSS_Context::$name ?></span><?php
?></div><?php
$display_others = false;
}
@@ -65,8 +65,8 @@ if (!empty($this->entries)) {
$this->renderHelper('index/normal/entry_header');
?><div class="flux_content">
- <div class="content <?php echo $content_width; ?>">
- <h1 class="title"><a target="_blank" rel="noreferrer" class="go_website" href="<?php echo $this->entry->link(); ?>"><?php echo $this->entry->title(); ?></a></h1>
+ <div class="content <?= $content_width ?>">
+ <h1 class="title"><a target="_blank" rel="noreferrer" class="go_website" href="<?= $this->entry->link() ?>"><?= $this->entry->title() ?></a></h1>
<div class="author"><?php
$authors = $this->entry->authors();
if (is_array($authors)):
@@ -75,7 +75,7 @@ if (!empty($this->entries)) {
echo $first ? _t('gen.short.by_author') . ' ' : '· ';
$first = false;
?>
-<em><a href="<?php echo _url('index', 'index', 'search', 'author:' . str_replace(' ', '+', htmlspecialchars_decode($author, ENT_QUOTES))); ?>"><?php echo $author; ?></a></em>
+<em><a href="<?= _url('index', 'index', 'search', 'author:' . str_replace(' ', '+', htmlspecialchars_decode($author, ENT_QUOTES))) ?>"><?= $author ?></a></em>
<?php endforeach; ?>
</div><?php
endif;
@@ -96,7 +96,7 @@ if (!empty($this->entries)) {
<?php } else { ?>
<div id="stream" class="prompt alert alert-warn normal">
- <h2><?php echo _t('index.feed.empty'); ?></h2>
- <a href="<?php echo _url('subscription', 'index'); ?>"><?php echo _t('index.feed.add'); ?></a><br /><br />
+ <h2><?= _t('index.feed.empty') ?></h2>
+ <a href="<?= _url('subscription', 'index') ?>"><?= _t('index.feed.add') ?></a><br /><br />
</div>
<?php } ?>
diff --git a/app/views/index/reader.phtml b/app/views/index/reader.phtml
index 129fae937..bbb6bd22b 100644
--- a/app/views/index/reader.phtml
+++ b/app/views/index/reader.phtml
@@ -9,16 +9,16 @@ if (!empty($this->entries)) {
<div id="stream" class="reader">
<div id="new-article">
- <a href="<?php echo Minz_Url::display(Minz_Request::currentRequest()); ?>"><?php echo _t('gen.js.new_article'); /* TODO: move string in JS*/ ?></a>
+ <a href="<?= Minz_Url::display(Minz_Request::currentRequest()) ?>"><?= _t('gen.js.new_article'); /* TODO: move string in JS*/ ?></a>
</div>
<?php foreach ($this->entries as $item) {
$item = Minz_ExtensionManager::callHook('entry_before_display', $item);
if (is_null($item)) {
continue;
}
- ?><div class="flux<?php echo !$item->isRead() ? ' not_read' : ''; ?><?php echo $item->isFavorite() ? ' favorite' : ''; ?>" id="flux_<?php echo $item->id(); ?>">
+ ?><div class="flux<?= !$item->isRead() ? ' not_read' : '' ?><?= $item->isFavorite() ? ' favorite' : '' ?>" id="flux_<?= $item->id() ?>">
<div class="flux_content">
- <div class="content <?php echo $content_width; ?>">
+ <div class="content <?= $content_width ?>">
<?php
$feed = FreshRSS_CategoryDAO::findFeed($this->categories, $item->feed()); //We most likely already have the feed object in cache
if (empty($feed)) $feed = $item->feed(true);
@@ -31,16 +31,16 @@ if (!empty($this->entries)) {
$readUrl['params']['is_read'] = 0;
}
?>
- <a class="read" href="<?php echo Minz_Url::display($readUrl); ?>">
- <?php echo _i($item->isRead() ? 'read' : 'unread'); ?>
+ <a class="read" href="<?= Minz_Url::display($readUrl) ?>">
+ <?= _i($item->isRead() ? 'read' : 'unread') ?>
</a>
- <a class="bookmark" href="<?php echo Minz_Url::display($favoriteUrl); ?>">
- <?php echo _i($item->isFavorite() ? 'starred' : 'non-starred'); ?>
+ <a class="bookmark" href="<?= Minz_Url::display($favoriteUrl) ?>">
+ <?= _i($item->isFavorite() ? 'starred' : 'non-starred') ?>
</a>
- <a class="website" href="<?php echo _url('index', 'reader', 'get', 'f_' . $feed->id()); ?>">
- <img class="favicon" src="<?php echo $feed->favicon(); ?>" alt="✇" /> <span><?php echo $feed->name(); ?></span>
+ <a class="website" href="<?= _url('index', 'reader', 'get', 'f_' . $feed->id()) ?>">
+ <img class="favicon" src="<?= $feed->favicon() ?>" alt="✇" /> <span><?= $feed->name() ?></span>
</a>
- <h1 class="title"><a target="_blank" rel="noreferrer" class="go_website" href="<?php echo $item->link(); ?>"><?php echo $item->title(); ?></a></h1>
+ <h1 class="title"><a target="_blank" rel="noreferrer" class="go_website" href="<?= $item->link() ?>"><?= $item->title() ?></a></h1>
<div class="author"><?php
$authors = $item->authors();
@@ -50,7 +50,7 @@ if (!empty($this->entries)) {
echo $first ? _t('gen.short.by_author') . ' ' : '· ';
$first = false;
?>
-<em><a href="<?php echo _url('index', 'index', 'search', 'author:' . str_replace(' ', '+', htmlspecialchars_decode($author, ENT_QUOTES))); ?>"><?php echo $author; ?></a></em>
+<em><a href="<?= _url('index', 'index', 'search', 'author:' . str_replace(' ', '+', htmlspecialchars_decode($author, ENT_QUOTES))) ?>"><?= $author ?></a></em>
<?php
endforeach;
echo ' — ';
@@ -58,7 +58,7 @@ if (!empty($this->entries)) {
echo $item->date();
?></div>
- <?php echo $item->content(); ?>
+ <?= $item->content() ?>
</div>
</div>
</div>
@@ -69,7 +69,7 @@ if (!empty($this->entries)) {
<?php } else { ?>
<div id="stream" class="prompt alert alert-warn reader">
- <h2><?php echo _t('index.feed.empty'); ?></h2>
- <a href="<?php echo _url('subscription', 'index'); ?>"><?php echo _t('index.feed.add'); ?></a><br /><br />
+ <h2><?= _t('index.feed.empty') ?></h2>
+ <a href="<?= _url('subscription', 'index') ?>"><?= _t('index.feed.add') ?></a><br /><br />
</div>
<?php } ?>
diff --git a/app/views/index/rss.phtml b/app/views/index/rss.phtml
index 104e03d15..00be01c28 100755
--- a/app/views/index/rss.phtml
+++ b/app/views/index/rss.phtml
@@ -1,23 +1,23 @@
-<?php echo '<?xml version="1.0" encoding="UTF-8" ?>'; ?>
+<?= '<?xml version="1.0" encoding="UTF-8" ?>'; ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
- <title><?php echo $this->rss_title; ?></title>
- <link><?php echo Minz_Url::display(null, 'html', true); ?></link>
- <description><?php echo _t('index.feed.rss_of', $this->rss_title); ?></description>
- <pubDate><?php echo date('D, d M Y H:i:s O'); ?></pubDate>
- <lastBuildDate><?php echo gmdate('D, d M Y H:i:s'); ?> GMT</lastBuildDate>
- <atom:link href="<?php echo Minz_Url::display($this->url, 'html', true); ?>" rel="self" type="application/rss+xml" />
+ <title><?= $this->rss_title ?></title>
+ <link><?= Minz_Url::display(null, 'html', true) ?></link>
+ <description><?= _t('index.feed.rss_of', $this->rss_title) ?></description>
+ <pubDate><?= date('D, d M Y H:i:s O') ?></pubDate>
+ <lastBuildDate><?= gmdate('D, d M Y H:i:s') ?> GMT</lastBuildDate>
+ <atom:link href="<?= Minz_Url::display($this->url, 'html', true) ?>" rel="self" type="application/rss+xml" />
<?php
foreach ($this->entries as $item) {
?>
<item>
- <title><?php echo $item->title(); ?></title>
- <link><?php echo $item->link(); ?></link>
+ <title><?= $item->title() ?></title>
+ <link><?= $item->link() ?></link>
<?php
$authors = $item->authors();
if (is_array($authors)) {
foreach ($authors as $author) {
- echo "\t\t\t" , '<author>', $author, '</author>', "\n";
+ echo "\t\t\t" , '<dc:creator>', $author, '</dc:creator>', "\n";
}
}
$categories = $item->tags();
@@ -30,8 +30,8 @@ foreach ($this->entries as $item) {
<description><![CDATA[<?php
echo $item->content();
?>]]></description>
- <pubDate><?php echo date('D, d M Y H:i:s O', $item->date(true)); ?></pubDate>
- <guid isPermaLink="false"><?php echo $item->id(); ?></guid>
+ <pubDate><?= date('D, d M Y H:i:s O', $item->date(true)) ?></pubDate>
+ <guid isPermaLink="false"><?= $item->id() ?></guid>
</item>
<?php } ?>
diff --git a/app/views/index/tos.phtml b/app/views/index/tos.phtml
new file mode 100644
index 000000000..38dd0add6
--- /dev/null
+++ b/app/views/index/tos.phtml
@@ -0,0 +1,13 @@
+<div class="post content">
+ <?php if ($this->can_register) { ?>
+ <a href="<?= _url('auth', 'register') ?>">
+ <?= _t('gen.action.back') ?>
+ </a>
+ <?php } else { ?>
+ <a href="<?= _url('index', 'index') ?>">
+ <?= _t('gen.action.back') ?>
+ </a>
+ <?php } ?>
+
+ <?= $this->terms_of_service ?>
+</div>
diff --git a/app/views/stats/idle.phtml b/app/views/stats/idle.phtml
index 88c78d465..9421893fb 100644
--- a/app/views/stats/idle.phtml
+++ b/app/views/stats/idle.phtml
@@ -1,9 +1,9 @@
<?php $this->partial('aside_stats'); ?>
<div class="post">
- <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
+ <a href="<?= _url('index', 'index') ?>"><?= _t('gen.action.back_to_rss_feeds') ?></a>
- <h1><?php echo _t('admin.stats.idle'); ?></h1>
+ <h1><?= _t('admin.stats.idle') ?></h1>
<?php
$current_url = Minz_Url::display(
@@ -16,21 +16,21 @@
$nothing = false;
?>
<div class="stat">
- <h2><?php echo _t('gen.date.' . $period); ?></h2>
+ <h2><?= _t('gen.date.' . $period) ?></h2>
<form id="form-delete" method="post">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
<?php foreach ($feeds as $feed) { ?>
<ul class="horizontal-list">
<li class="item">
<div class="stick">
- <a class="btn" href="<?php echo _url('index', 'index', 'get', 'f_' . $feed['id']); ?>"><?php echo _i('link'); ?> <?php echo _t('gen.action.filter'); ?></a>
- <a class="btn" href="<?php echo _url('subscription', 'index', 'id', $feed['id']); ?>"><?php echo _i('configure'); ?> <?php echo _t('gen.action.manage'); ?></a>
- <button class="btn btn-attention confirm" form="form-delete" formaction="<?php echo _url('feed', 'delete', 'id', $feed['id'], 'r', $current_url); ?>"><?php echo _t('gen.action.remove'); ?></button>
+ <a class="btn" href="<?= _url('index', 'index', 'get', 'f_' . $feed['id']) ?>"><?= _i('link') ?> <?= _t('gen.action.filter') ?></a>
+ <a class="btn" href="<?= _url('subscription', 'index', 'id', $feed['id']) ?>"><?= _i('configure') ?> <?= _t('gen.action.manage') ?></a>
+ <button class="btn btn-attention confirm" form="form-delete" formaction="<?= _url('feed', 'delete', 'id', $feed['id'], 'r', $current_url) ?>"><?= _t('gen.action.remove') ?></button>
</div>
</li>
<li class="item">
- <span title="<?php echo timestamptodate($feed['last_date'], false); ?>"><?php echo $feed['name']; ?> (<?php echo _t('admin.stats.number_entries', $feed['nb_articles']); ?>)</span>
+ <span title="<?= timestamptodate($feed['last_date'], false) ?>"><?= $feed['name'] ?> (<?= _t('admin.stats.number_entries', $feed['nb_articles']) ?>)</span>
</li>
</ul>
<?php } ?>
@@ -43,7 +43,7 @@
if ($nothing) {
?>
<p class="alert alert-warn">
- <span class="alert-head"><?php echo _t('admin.stats.no_idle'); ?></span>
+ <span class="alert-head"><?= _t('admin.stats.no_idle') ?></span>
</p>
<?php } ?>
</div>
diff --git a/app/views/stats/index.phtml b/app/views/stats/index.phtml
index 2ff3e6c52..4af197c5b 100644
--- a/app/views/stats/index.phtml
+++ b/app/views/stats/index.phtml
@@ -1,63 +1,63 @@
<?php $this->partial('aside_stats'); ?>
<div class="post">
- <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
+ <a href="<?= _url('index', 'index') ?>"><?= _t('gen.action.back_to_rss_feeds') ?></a>
- <h1><?php echo _t('admin.stats.main'); ?></h1>
+ <h1><?= _t('admin.stats.main') ?></h1>
<div class="stat half">
- <h2><?php echo _t('admin.stats.entry_repartition'); ?></h2>
+ <h2><?= _t('admin.stats.entry_repartition') ?></h2>
<table>
<thead>
<tr>
<th> </th>
- <th><?php echo _t('admin.stats.main_stream'); ?></th>
- <th><?php echo _t('admin.stats.all_feeds'); ?></th>
+ <th><?= _t('admin.stats.main_stream') ?></th>
+ <th><?= _t('admin.stats.all_feeds') ?></th>
</tr>
</thead>
<tbody>
<tr>
- <th><?php echo _t('admin.stats.status_total'); ?></th>
- <td class="numeric"><?php echo format_number($this->repartition['main_stream']['total']); ?></td>
- <td class="numeric"><?php echo format_number($this->repartition['all_feeds']['total']); ?></td>
+ <th><?= _t('admin.stats.status_total') ?></th>
+ <td class="numeric"><?= format_number($this->repartition['main_stream']['total']) ?></td>
+ <td class="numeric"><?= format_number($this->repartition['all_feeds']['total']) ?></td>
</tr>
<tr>
- <th><?php echo _t('admin.stats.status_read'); ?></th>
- <td class="numeric"><?php echo format_number($this->repartition['main_stream']['count_reads']); ?></td>
- <td class="numeric"><?php echo format_number($this->repartition['all_feeds']['count_reads']); ?></td>
+ <th><?= _t('admin.stats.status_read') ?></th>
+ <td class="numeric"><?= format_number($this->repartition['main_stream']['count_reads']) ?></td>
+ <td class="numeric"><?= format_number($this->repartition['all_feeds']['count_reads']) ?></td>
</tr>
<tr>
- <th><?php echo _t('admin.stats.status_unread'); ?></th>
- <td class="numeric"><?php echo format_number($this->repartition['main_stream']['count_unreads']); ?></td>
- <td class="numeric"><?php echo format_number($this->repartition['all_feeds']['count_unreads']); ?></td>
+ <th><?= _t('admin.stats.status_unread') ?></th>
+ <td class="numeric"><?= format_number($this->repartition['main_stream']['count_unreads']) ?></td>
+ <td class="numeric"><?= format_number($this->repartition['all_feeds']['count_unreads']) ?></td>
</tr>
<tr>
- <th><?php echo _t('admin.stats.status_favorites'); ?></th>
- <td class="numeric"><?php echo format_number($this->repartition['main_stream']['count_favorites']); ?></td>
- <td class="numeric"><?php echo format_number($this->repartition['all_feeds']['count_favorites']); ?></td>
+ <th><?= _t('admin.stats.status_favorites') ?></th>
+ <td class="numeric"><?= format_number($this->repartition['main_stream']['count_favorites']) ?></td>
+ <td class="numeric"><?= format_number($this->repartition['all_feeds']['count_favorites']) ?></td>
</tr>
</tbody>
</table>
</div><!--
--><div class="stat half">
- <h2><?php echo _t('admin.stats.top_feed'); ?></h2>
+ <h2><?= _t('admin.stats.top_feed') ?></h2>
<table>
<thead>
<tr>
- <th><?php echo _t('admin.stats.feed'); ?></th>
- <th><?php echo _t('admin.stats.category'); ?></th>
- <th><?php echo _t('admin.stats.entry_count'); ?></th>
- <th><?php echo _t('admin.stats.percent_of_total'); ?></th>
+ <th><?= _t('admin.stats.feed') ?></th>
+ <th><?= _t('admin.stats.category') ?></th>
+ <th><?= _t('admin.stats.entry_count') ?></th>
+ <th><?= _t('admin.stats.percent_of_total') ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($this->topFeed as $feed) { ?>
<tr>
- <td><a href="<?php echo _url('stats', 'repartition', 'id', $feed['id']); ?>"><?php echo $feed['name']; ?></a></td>
- <td><?php echo $feed['category']; ?></td>
- <td class="numeric"><?php echo format_number($feed['count']); ?></td>
- <td class="numeric"><?php echo format_number($feed['count'] / $this->repartition['all_feeds']['total'] * 100, 1);?></td>
+ <td><a href="<?= _url('stats', 'repartition', 'id', $feed['id']) ?>"><?= $feed['name'] ?></a></td>
+ <td><?= $feed['category'] ?></td>
+ <td class="numeric"><?= format_number($feed['count']) ?></td>
+ <td class="numeric"><?= format_number($feed['count'] / $this->repartition['all_feeds']['total'] * 100, 1) ?></td>
</tr>
<?php } ?>
</tbody>
@@ -65,18 +65,18 @@
</div>
<div class="stat">
- <h2><?php echo _t('admin.stats.entry_per_day'); ?></h2>
+ <h2><?= _t('admin.stats.entry_per_day') ?></h2>
<div id="statsEntryPerDay" class="statGraph"></div>
</div>
<div class="stat half">
- <h2><?php echo _t('admin.stats.feed_per_category'); ?></h2>
+ <h2><?= _t('admin.stats.feed_per_category') ?></h2>
<div id="statsFeedPerCategory" class="statGraph"></div>
<div id="statsFeedPerCategoryLegend"></div>
</div>
<div class="stat half">
- <h2><?php echo _t('admin.stats.entry_per_category'); ?></h2>
+ <h2><?= _t('admin.stats.entry_per_category') ?></h2>
<div id="statsEntryPerCategory" class="statGraph"></div>
<div id="statsEntryPerCategoryLegend"></div>
</div>
@@ -90,4 +90,4 @@ echo htmlspecialchars(json_encode(array(
'entryByCategory' => $this->entryByCategory,
), JSON_UNESCAPED_UNICODE), ENT_NOQUOTES, 'UTF-8');
?></script>
-<script src="../scripts/stats.js?<?php echo @filemtime(PUBLIC_PATH . '/scripts/stats.js'); ?>"></script>
+<script src="../scripts/stats.js?<?= @filemtime(PUBLIC_PATH . '/scripts/stats.js') ?>"></script>
diff --git a/app/views/stats/repartition.phtml b/app/views/stats/repartition.phtml
index 4bce418c9..7b445a7cc 100644
--- a/app/views/stats/repartition.phtml
+++ b/app/views/stats/repartition.phtml
@@ -1,12 +1,12 @@
<?php $this->partial('aside_stats'); ?>
<div class="post ">
- <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
+ <a href="<?= _url('index', 'index') ?>"><?= _t('gen.action.back_to_rss_feeds') ?></a>
- <h1><?php echo _t('admin.stats.repartition'); ?></h1>
+ <h1><?= _t('admin.stats.repartition') ?></h1>
<select id="feed_select" class="select-change">
- <option data-url="<?php echo _url('stats', 'repartition')?>"><?php echo _t('admin.stats.all_feeds')?></option>
+ <option data-url="<?= _url('stats', 'repartition') ?>"><?= _t('admin.stats.all_feeds') ?></option>
<?php foreach ($this->categories as $category) {
$feeds = $category->feeds();
if (!empty($feeds)) {
@@ -24,40 +24,40 @@
</select>
<?php if ($this->feed) {?>
- <a class="btn" href="<?php echo _url('subscription', 'index', 'id', $this->feed->id()); ?>">
- <?php echo _i('configure'); ?> <?php echo _t('gen.action.manage'); ?>
+ <a class="btn" href="<?= _url('subscription', 'index', 'id', $this->feed->id()) ?>">
+ <?= _i('configure') ?> <?= _t('gen.action.manage') ?>
</a>
<?php }?>
<div class="stat">
<table>
<tr>
- <th><?php echo _t('admin.stats.status_total'); ?></th>
- <th><?php echo _t('admin.stats.status_read'); ?></th>
- <th><?php echo _t('admin.stats.status_unread'); ?></th>
- <th><?php echo _t('admin.stats.status_favorites'); ?></th>
+ <th><?= _t('admin.stats.status_total') ?></th>
+ <th><?= _t('admin.stats.status_read') ?></th>
+ <th><?= _t('admin.stats.status_unread') ?></th>
+ <th><?= _t('admin.stats.status_favorites') ?></th>
</tr>
<tr>
- <td class="numeric"><?php echo $this->repartition['total']; ?></td>
- <td class="numeric"><?php echo $this->repartition['count_reads']; ?></td>
- <td class="numeric"><?php echo $this->repartition['count_unreads']; ?></td>
- <td class="numeric"><?php echo $this->repartition['count_favorites']; ?></td>
+ <td class="numeric"><?= $this->repartition['total'] ?></td>
+ <td class="numeric"><?= $this->repartition['count_reads'] ?></td>
+ <td class="numeric"><?= $this->repartition['count_unreads'] ?></td>
+ <td class="numeric"><?= $this->repartition['count_favorites'] ?></td>
</tr>
</table>
</div>
<div class="stat">
- <h2><?php echo _t('admin.stats.entry_per_hour', $this->averageHour); ?></h2>
+ <h2><?= _t('admin.stats.entry_per_hour', $this->averageHour) ?></h2>
<div id="statsEntryPerHour" class="statGraph"></div>
</div>
<div class="stat half">
- <h2><?php echo _t('admin.stats.entry_per_day_of_week', $this->averageDayOfWeek); ?></h2>
+ <h2><?= _t('admin.stats.entry_per_day_of_week', $this->averageDayOfWeek) ?></h2>
<div id="statsEntryPerDayOfWeek" class="statGraph"></div>
</div>
<div class="stat half">
- <h2><?php echo _t('admin.stats.entry_per_month', $this->averageMonth); ?></h2>
+ <h2><?= _t('admin.stats.entry_per_month', $this->averageMonth) ?></h2>
<div id="statsEntryPerMonth" class="statGraph"></div>
</div>
</div>
@@ -71,4 +71,4 @@ echo htmlspecialchars(json_encode(array(
'months' => $this->months,
), JSON_UNESCAPED_UNICODE), ENT_NOQUOTES, 'UTF-8');
?></script>
-<script src="../scripts/repartition.js?<?php echo @filemtime(PUBLIC_PATH . '/scripts/repartition.js'); ?>"></script>
+<script src="../scripts/repartition.js?<?= @filemtime(PUBLIC_PATH . '/scripts/repartition.js') ?>"></script>
diff --git a/app/views/subscription/bookmarklet.phtml b/app/views/subscription/bookmarklet.phtml
index 76ac700e0..e6f311f58 100644
--- a/app/views/subscription/bookmarklet.phtml
+++ b/app/views/subscription/bookmarklet.phtml
@@ -1,17 +1,20 @@
<?php $this->partial('aside_subscription'); ?>
<div class="post">
- <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
+ <a href="<?= _url('index', 'index') ?>"><?= _t('gen.action.back_to_rss_feeds') ?></a>
- <legend><?php echo _t('sub.bookmarklet.title'); ?></legend>
- <p><a class="btn btn-important" href="javascript:(function(){var%20url%20=%20location.href;var%20otherWindow=window.open('about:blank','_blank');otherWindow.opener=null;otherWindow.location='<?php echo Minz_Url::display(array('c' => 'feed', 'a' => 'add'), 'html', true); ?>&amp;url_rss='+encodeURIComponent(url);})();"><?php echo _t('sub.bookmarklet.label'); ?></a></p>
- <?php echo _t('sub.bookmarklet.documentation'); ?>
+ <legend><?= _t('sub.bookmarklet.title') ?></legend>
+ <p><a class="btn btn-important" href="javascript:(function(){var%20url%20=%20location.href;var%20otherWindow=window.open('about:blank','_blank');otherWindow.opener=null;otherWindow.location='<?= Minz_Url::display(array('c' => 'feed', 'a' => 'add'), 'html', true) ?>&amp;url_rss='+encodeURIComponent(url);})();"><?= _t('sub.bookmarklet.label') ?></a></p>
+ <?= _t('sub.bookmarklet.documentation') ?>
- <legend><?php echo _t('sub.firefox.title'); ?></legend>
- <p><?php echo _t('sub.firefox.documentation'); ?></p>
- <pre>browser.contentHandlers.types.number.uri → <?php echo Minz_Url::display(array('c' => 'feed', 'a' => 'add'), 'html', true); ?>&amp;url_rss=%s</pre>
+ <legend><?= _t('sub.firefox.title') ?></legend>
+ <p class="alert alert-warn">
+ <?= _t('sub.firefox.obsolete_63', $this->default_category->name()) ?>
+ </p>
+ <p><?= _t('sub.firefox.documentation') ?></p>
+ <pre>browser.contentHandlers.types.number.uri → <?= Minz_Url::display(array('c' => 'feed', 'a' => 'add'), 'html', true) ?>&amp;url_rss=%s</pre>
- <legend><?php echo _t('sub.api.title'); ?></legend>
- <p><?php echo _t('sub.api.documentation'); ?></p>
- <pre><?php echo Minz_Url::display(array('c' => 'feed', 'a' => 'add'), 'html', true); ?>&amp;url_rss=%s</pre>
+ <legend><?= _t('sub.api.title') ?></legend>
+ <p><?= _t('sub.api.documentation') ?></p>
+ <pre><?= Minz_Url::display(array('c' => 'feed', 'a' => 'add'), 'html', true) ?>&amp;url_rss=%s</pre>
</div> \ No newline at end of file
diff --git a/app/views/subscription/feed.phtml b/app/views/subscription/feed.phtml
index 60664fdee..1a167777f 100644
--- a/app/views/subscription/feed.phtml
+++ b/app/views/subscription/feed.phtml
@@ -9,7 +9,7 @@ if ($this->feed) {
} else {
?>
<div class="alert alert-warn">
- <span class="alert-head"><?php echo _t('sub.feed.no_selected'); ?></span>
- <?php echo _t('sub.feed.think_to_add'); ?>
+ <span class="alert-head"><?= _t('sub.feed.no_selected') ?></span>
+ <?= _t('sub.feed.think_to_add') ?>
</div>
<?php } ?>
diff --git a/app/views/subscription/index.phtml b/app/views/subscription/index.phtml
index 20f72ad66..da7593a8d 100644
--- a/app/views/subscription/index.phtml
+++ b/app/views/subscription/index.phtml
@@ -1,77 +1,77 @@
<?php $this->partial('aside_subscription'); ?>
<div class="post drop-section">
- <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
+ <a href="<?= _url('index', 'index') ?>"><?= _t('gen.action.back_to_rss_feeds') ?></a>
- <h2><?php echo _t('sub.title'); ?></h2>
+ <h2><?= _t('sub.title') ?></h2>
- <form id="add_rss" method="post" action="<?php echo _url('feed', 'add'); ?>" autocomplete="off">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
+ <form id="add_rss" method="post" action="<?= _url('feed', 'add') ?>" autocomplete="off">
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
<div class="stick">
- <input type="url" name="url_rss" class="long" placeholder="<?php echo _t('sub.feed.add'); ?>" />
+ <input type="url" name="url_rss" class="long" placeholder="<?= _t('sub.feed.add') ?>" />
<div class="dropdown">
<div id="dropdown-cat" class="dropdown-target"></div>
- <a class="dropdown-toggle btn" href="#dropdown-cat"><?php echo _i('down'); ?></a>
+ <a class="dropdown-toggle btn" href="#dropdown-cat"><?= _i('down') ?></a>
<ul class="dropdown-menu">
<li class="dropdown-close"><a href="#close">❌</a></li>
- <li class="dropdown-header"><?php echo _t('sub.category'); ?></li>
+ <li class="dropdown-header"><?= _t('sub.category') ?></li>
<li class="input">
<select name="category" id="category">
<?php foreach ($this->categories as $cat) { ?>
- <option value="<?php echo $cat->id(); ?>"<?php echo $cat->id() == 1 ? ' selected="selected"' : ''; ?>>
- <?php echo $cat->name(); ?>
+ <option value="<?= $cat->id() ?>"<?= $cat->id() == 1 ? ' selected="selected"' : '' ?>>
+ <?= $cat->name() ?>
</option>
<?php } ?>
- <option value="nc"><?php echo _t('sub.category.new'); ?></option>
+ <option value="nc"><?= _t('sub.category.new') ?></option>
</select>
</li>
<li class="input" aria-hidden="true">
- <input type="text" name="new_category[name]" id="new_category_name" autocomplete="off" placeholder="<?php echo _t('sub.category.new'); ?>" />
+ <input type="text" name="new_category[name]" id="new_category_name" autocomplete="off" placeholder="<?= _t('sub.category.new') ?>" />
</li>
<li class="separator"></li>
- <li class="dropdown-header"><?php echo _t('sub.feed.auth.http'); ?></li>
+ <li class="dropdown-header"><?= _t('sub.feed.auth.http') ?></li>
<li class="input">
- <input type="text" name="http_user" id="http_user_feed" value=" " autocomplete="off" placeholder="<?php echo _t('sub.feed.auth.username'); ?>" />
+ <input type="text" name="http_user" id="http_user_feed" value=" " autocomplete="off" placeholder="<?= _t('sub.feed.auth.username') ?>" />
</li>
<li class="input">
- <input type="password" name="http_pass" id="http_pass_feed" autocomplete="new-password" placeholder="<?php echo _t('sub.feed.auth.password'); ?>" />
+ <input type="password" name="http_pass" id="http_pass_feed" autocomplete="new-password" placeholder="<?= _t('sub.feed.auth.password') ?>" />
</li>
</ul>
</div>
- <button class="btn" type="submit"><?php echo _i('add'); ?></button>
+ <button class="btn" type="submit"><?= _i('add') ?></button>
</div>
</form>
<p class="alert alert-warn">
- <?php echo _t('sub.feed.moved_category_deleted', $this->default_category->name()); ?>
+ <?= _t('sub.feed.moved_category_deleted', $this->default_category->name()) ?>
</p>
<?php if ($this->onlyFeedsWithError): ?>
<p class="alert alert-warn">
- <?php echo _t('sub.feed.showing.error'); ?>
+ <?= _t('sub.feed.showing.error') ?>
</p>
<?php endif; ?>
<div class="box">
- <div class="box-title"><label for="new-category"><?php echo _t('sub.category.add'); ?></label></div>
+ <div class="box-title"><label for="new-category"><?= _t('sub.category.add') ?></label></div>
<ul class="box-content box-content-centered">
- <form action="<?php echo _url('category', 'create'); ?>" method="post">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
- <li class="item"><input type="text" id="new-category" name="new-category" placeholder="<?php echo _t('sub.category.new'); ?>" /></li>
- <li class="item"><button class="btn btn-important" type="submit"><?php echo _t('gen.action.submit'); ?></button></li>
+ <form action="<?= _url('category', 'create') ?>" method="post">
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
+ <li class="item"><input type="text" id="new-category" name="new-category" placeholder="<?= _t('sub.category.new') ?>" /></li>
+ <li class="item"><button class="btn btn-important" type="submit"><?= _t('gen.action.submit') ?></button></li>
</form>
</ul>
</div>
<form id="controller-category" method="post" aria-hidden="true">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
</form>
<?php
@@ -80,10 +80,10 @@
?>
<div class="box">
<div class="box-title">
- <a class="configure open-slider" href="<?php echo _url('subscription', 'category', 'id', $cat->id()); ?>"><?php echo _i('configure'); ?></a>
- <?php echo $cat->name(); ?>
+ <a class="configure open-slider" href="<?= _url('subscription', 'category', 'id', $cat->id()) ?>"><?= _i('configure') ?></a>
+ <?= $cat->name() ?>
</div>
- <ul class="box-content" data-cat-id="<?php echo $cat->id(); ?>">
+ <ul class="box-content" data-cat-id="<?= $cat->id() ?>">
<?php if (!empty($feeds)) { ?>
<?php
foreach ($feeds as $feed) {
@@ -93,17 +93,17 @@
$error = $feed->inError() ? ' error' : '';
$empty = $feed->nbEntries() == 0 ? ' empty' : '';
?>
- <li class="item feed<?php echo $error, $empty, $feed->mute() ? ' mute': ''; ?>"
+ <li class="item feed<?= $error, $empty, $feed->mute() ? ' mute': '' ?>"
draggable="true"
- data-feed-id="<?php echo $feed->id(); ?>"
+ data-feed-id="<?= $feed->id() ?>"
dropzone="move">
- <a class="configure open-slider" href="<?php echo _url('subscription', 'feed', 'id', $feed->id()); ?>"><?php echo _i('configure'); ?></a>
- <img class="favicon" src="<?php echo $feed->favicon(); ?>" alt="✇" /> <?php echo $feed->name(); ?>
+ <a class="configure open-slider" href="<?= _url('subscription', 'feed', 'id', $feed->id()) ?>"><?= _i('configure') ?></a>
+ <img class="favicon" src="<?= $feed->favicon() ?>" alt="✇" /> <?= $feed->name() ?>
</li>
<?php }
} else {
?>
- <li class="item disabled" dropzone="move"><?php echo _t('sub.category.empty'); ?></li>
+ <li class="item disabled" dropzone="move"><?= _t('sub.category.empty') ?></li>
<?php } ?>
</ul>
</div>
@@ -111,16 +111,16 @@
<ul>
<?php if ($this->onlyFeedsWithError): ?>
- <li><a href="<?php echo _url('subscription', 'index'); ?>"><?php echo _t('sub.feed.show.all'); ?></a></li>
+ <li><a href="<?= _url('subscription', 'index') ?>"><?= _t('sub.feed.show.all') ?></a></li>
<?php else: ?>
- <li><a href="<?php echo _url('subscription', 'index', 'error', 1); ?>"><?php echo _t('sub.feed.show.error'); ?></a></li>
+ <li><a href="<?= _url('subscription', 'index', 'error', 1) ?>"><?= _t('sub.feed.show.error') ?></a></li>
<?php endif; ?>
</ul>
</div>
<?php $class = $this->displaySlider ? ' class="active"' : ''; ?>
-<a href="#" id="close-slider"<?php echo $class; ?>></a>
-<div id="slider"<?php echo $class; ?>>
+<a href="#" id="close-slider"<?= $class ?>></a>
+<div id="slider"<?= $class ?>>
<?php
if (isset($this->feed)) {
$this->renderHelper('feed/update');
diff --git a/app/views/update/apply.phtml b/app/views/update/apply.phtml
index 8221929ae..c5e6884db 100644
--- a/app/views/update/apply.phtml
+++ b/app/views/update/apply.phtml
@@ -1,9 +1,9 @@
<?php $this->partial('aside_configure'); ?>
<div class="post">
- <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
+ <a href="<?= _url('index', 'index') ?>"><?= _t('gen.action.back_to_rss_feeds') ?></a>
- <h1><?php echo _t('admin.update'); ?></h1>
+ <h1><?= _t('admin.update') ?></h1>
<?php ask_info_update(); ?>
</div>
diff --git a/app/views/update/checkInstall.phtml b/app/views/update/checkInstall.phtml
index 33d78cbe7..183f914c0 100644
--- a/app/views/update/checkInstall.phtml
+++ b/app/views/update/checkInstall.phtml
@@ -1,15 +1,15 @@
<?php $this->partial('aside_configure'); ?>
<div class="post">
- <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
+ <a href="<?= _url('index', 'index') ?>"><?= _t('gen.action.back_to_rss_feeds') ?></a>
- <h2><?php echo _t('admin.check_install.php'); ?></h2>
+ <h2><?= _t('admin.check_install.php') ?></h2>
<?php foreach ($this->status_php as $key => $status) { ?>
- <p class="alert <?php echo $status ? 'alert-success' : 'alert-error'; ?>">
+ <p class="alert <?= $status ? 'alert-success' : 'alert-error' ?>">
<?php
if ($key === 'php') {
- echo _t('admin.check_install.' . $key . '.' . ($status ? 'ok' : 'nok'), PHP_VERSION, '5.3.8');
+ echo _t('admin.check_install.' . $key . '.' . ($status ? 'ok' : 'nok'), PHP_VERSION, '5.6.0');
} else {
echo _t('admin.check_install.' . $key . '.' . ($status ? 'ok' : 'nok'));
}
@@ -17,20 +17,20 @@
</p>
<?php } ?>
- <h2><?php echo _t('admin.check_install.files'); ?></h2>
+ <h2><?= _t('admin.check_install.files') ?></h2>
<?php foreach ($this->status_files as $key => $status) { ?>
- <p class="alert <?php echo $status ? 'alert-success' : 'alert-error'; ?>">
- <?php echo _t('admin.check_install.' . $key . '.' . ($status ? 'ok' : 'nok')); ?>
+ <p class="alert <?= $status ? 'alert-success' : 'alert-error' ?>">
+ <?= _t('admin.check_install.' . $key . '.' . ($status ? 'ok' : 'nok')) ?>
</p>
<?php } ?>
<?php /*
- <h2><?php echo _t('admin.check_install.database'); ?></h2>
+ <h2><?= _t('admin.check_install.database') ?></h2>
<?php foreach ($this->status_database as $key => $status) { ?>
- <p class="alert <?php echo $status ? 'alert-success' : 'alert-error'; ?>">
- <?php echo _t('admin.check_install.' . $key . '.' . ($status ? 'ok' : 'nok')); ?>
+ <p class="alert <?= $status ? 'alert-success' : 'alert-error' ?>">
+ <?= _t('admin.check_install.' . $key . '.' . ($status ? 'ok' : 'nok')) ?>
</p>
<?php } ?>
*/ ?>
diff --git a/app/views/update/index.phtml b/app/views/update/index.phtml
index 0599d5b0d..041941e39 100644
--- a/app/views/update/index.phtml
+++ b/app/views/update/index.phtml
@@ -1,16 +1,16 @@
<?php $this->partial('aside_configure'); ?>
<div class="post">
- <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
+ <a href="<?= _url('index', 'index') ?>"><?= _t('gen.action.back_to_rss_feeds') ?></a>
- <h1><?php echo _t('admin.update'); ?></h1>
+ <h1><?= _t('admin.update') ?></h1>
<p>
- <?php echo _i('help'); ?> <?php echo _t('admin.update.current_version', FRESHRSS_VERSION); ?>
+ <?= _i('help') ?> <?= _t('admin.update.current_version', FRESHRSS_VERSION) ?>
</p>
<p>
- <?php echo _t('admin.update.last', $this->last_update_time); ?>
+ <?= _t('admin.update.last', $this->last_update_time) ?>
</p>
<?php if (!empty($this->message)) { ?>
@@ -28,9 +28,9 @@
break;
}
?>
- <p class="alert <?php echo $class; ?>">
- <span class="alert-head"><?php echo $this->message['title']; ?></span>
- <?php echo $this->message['body']; ?>
+ <p class="alert <?= $class ?>">
+ <span class="alert-head"><?= $this->message['title'] ?></span>
+ <?= $this->message['body'] ?>
</p>
<?php } ?>
@@ -38,11 +38,11 @@
if (empty($this->message) || $this->message['status'] !== 'good') {
?>
<p>
- <a href="<?php echo _url('update', 'check'); ?>" class="btn"><?php echo _t('admin.update.check'); ?></a>
+ <a href="<?= _url('update', 'check') ?>" class="btn"><?= _t('admin.update.check') ?></a>
</p>
<?php } ?>
<?php if ($this->update_to_apply) { ?>
- <a class="btn btn-important" href="<?php echo _url('update', 'apply'); ?>"><?php echo _t('admin.update.apply'); ?></a>
+ <a class="btn btn-important" href="<?= _url('update', 'apply') ?>"><?= _t('admin.update.apply') ?></a>
<?php } ?>
</div>
diff --git a/app/views/user/manage.phtml b/app/views/user/manage.phtml
index d0e5928ef..93d1008b5 100644
--- a/app/views/user/manage.phtml
+++ b/app/views/user/manage.phtml
@@ -1,98 +1,109 @@
<?php $this->partial('aside_configure'); ?>
<div class="post">
- <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
+ <a href="<?= _url('index', 'index') ?>"><?= _t('gen.action.back_to_rss_feeds') ?></a>
- <form method="post" action="<?php echo _url('user', 'create'); ?>" autocomplete="off">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
- <legend><?php echo _t('admin.user.create'); ?></legend>
+ <form method="post" action="<?= _url('user', 'create') ?>" autocomplete="off">
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
+ <legend><?= _t('admin.user.create') ?></legend>
<div class="form-group">
- <label class="group-name" for="new_user_language"><?php echo _t('admin.user.language'); ?></label>
+ <label class="group-name" for="new_user_language"><?= _t('admin.user.language') ?></label>
<div class="group-controls">
<select name="new_user_language" id="new_user_language">
<?php $languages = Minz_Translate::availableLanguages(); ?>
<?php foreach ($languages as $lang) { ?>
- <option value="<?php echo $lang; ?>"<?php echo FreshRSS_Context::$user_conf->language === $lang ? ' selected="selected"' : ''; ?>><?php echo _t('gen.lang.' . $lang); ?></option>
+ <option value="<?= $lang ?>"<?= FreshRSS_Context::$user_conf->language === $lang ? ' selected="selected"' : '' ?>><?= _t('gen.lang.' . $lang) ?></option>
<?php } ?>
</select>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="new_user_name"><?php echo _t('admin.user.username'); ?></label>
+ <label class="group-name" for="new_user_name"><?= _t('admin.user.username') ?></label>
<div class="group-controls">
- <input id="new_user_name" name="new_user_name" type="text" size="16" required="required" autocomplete="off" pattern="<?php echo FreshRSS_user_Controller::USERNAME_PATTERN; ?>" placeholder="demo" />
+ <input id="new_user_name" name="new_user_name" type="text" size="16" required="required" autocomplete="off" pattern="<?= FreshRSS_user_Controller::USERNAME_PATTERN ?>" placeholder="demo" />
</div>
</div>
+ <?php if ($this->show_email_field) { ?>
+ <div class="form-group">
+ <label class="group-name" for="new_user_email">
+ <?= _t('gen.auth.email') ?>
+ </label>
+ <div class="group-controls">
+ <input id="new_user_email" name="new_user_email" type="email" required />
+ </div>
+ </div>
+ <?php } ?>
+
<div class="form-group">
- <label class="group-name" for="new_user_passwordPlain"><?php echo _t('admin.user.password_form'); ?></label>
+ <label class="group-name" for="new_user_passwordPlain"><?= _t('admin.user.password_form') ?></label>
<div class="group-controls">
<div class="stick">
<input type="password" id="new_user_passwordPlain" name="new_user_passwordPlain" autocomplete="new-password" pattern=".{7,}" />
- <a class="btn toggle-password" data-toggle="new_user_passwordPlain"><?php echo _i('key'); ?></a>
+ <a class="btn toggle-password" data-toggle="new_user_passwordPlain"><?= _i('key') ?></a>
</div>
- <?php echo _i('help'); ?> <?php echo _t('admin.user.password_format'); ?>
- <noscript><b><?php echo _t('gen.js.should_be_activated'); ?></b></noscript>
+ <?= _i('help') ?> <?= _t('admin.user.password_format') ?>
+ <noscript><b><?= _t('gen.js.should_be_activated') ?></b></noscript>
</div>
</div>
<div class="form-group form-actions">
<div class="group-controls">
- <button type="submit" class="btn btn-important"><?php echo _t('gen.action.create'); ?></button>
- <button type="reset" class="btn"><?php echo _t('gen.action.cancel'); ?></button>
+ <button type="submit" class="btn btn-important"><?= _t('gen.action.create') ?></button>
+ <button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button>
</div>
</div>
</form>
- <form method="post" action="<?php echo _url('user', 'update'); ?>">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
- <legend><?php echo _t('admin.user.update_users'); ?></legend>
+ <form method="post" action="<?= _url('user', 'update') ?>">
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
+ <legend><?= _t('admin.user.update_users') ?></legend>
<div class="form-group">
- <label class="group-name" for="current_user"><?php echo _t('admin.user.selected'); ?></label>
+ <label class="group-name" for="current_user"><?= _t('admin.user.selected') ?></label>
<div class="group-controls">
<select id="current_user" name="username">
<option selected="selected"> </option>
<?php foreach (listUsers() as $username) { ?>
- <option value="<?php echo $username; ?>"><?php echo $username; ?></option>
+ <option value="<?= $username ?>"><?= $username ?></option>
<?php } ?>
</select>
</div>
</div>
<div class="form-group">
- <label class="group-name" for="newPasswordPlain"><?php echo _t('admin.user.password_form'); ?></label>
+ <label class="group-name" for="newPasswordPlain"><?= _t('admin.user.password_form') ?></label>
<div class="group-controls">
<div class="stick">
- <input type="password" id="newPasswordPlain" name="newPasswordPlain" autocomplete="new-password" pattern=".{7,}" <?php echo cryptAvailable() ? '' : 'disabled="disabled" '; ?>/>
- <a class="btn toggle-password" data-toggle="newPasswordPlain"><?php echo _i('key'); ?></a>
+ <input type="password" id="newPasswordPlain" name="newPasswordPlain" autocomplete="new-password" pattern=".{7,}" <?= cryptAvailable() ? '' : 'disabled="disabled" ' ?>/>
+ <a class="btn toggle-password" data-toggle="newPasswordPlain"><?= _i('key') ?></a>
</div>
- <?php echo _i('help'); ?> <?php echo _t('conf.profile.password_format'); ?>
- <noscript><b><?php echo _t('gen.js.should_be_activated'); ?></b></noscript>
+ <?= _i('help') ?> <?= _t('conf.profile.password_format') ?>
+ <noscript><b><?= _t('gen.js.should_be_activated') ?></b></noscript>
</div>
</div>
<div class="form-group form-actions">
<div class="group-controls">
- <button type="submit" class="btn btn-important"><?php echo _t('gen.action.update'); ?></button>
- <button type="reset" class="btn"><?php echo _t('gen.action.cancel'); ?></button>
+ <button type="submit" class="btn btn-important"><?= _t('gen.action.update') ?></button>
+ <button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button>
</div>
</div>
</form>
- <form method="post" action="<?php echo _url('user', 'delete'); ?>">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
- <legend><?php echo _t('admin.user.delete_users'); ?></legend>
+ <form method="post" action="<?= _url('user', 'delete') ?>">
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
+ <legend><?= _t('admin.user.delete_users') ?></legend>
<div class="form-group">
- <label class="group-name" for="user-list"><?php echo _t('admin.user.selected'); ?></label>
+ <label class="group-name" for="user-list"><?= _t('admin.user.selected') ?></label>
<div class="group-controls">
<select id="user-list" class="select-change" name="username">
<option selected="selected"> </option>
<?php foreach (listUsers() as $username) { ?>
- <option data-url="<?php echo _url('user', 'manage', 'u', $username); ?>" <?php echo $this->current_user === $username ? 'selected="selected"' : ''; ?> value="<?php echo $username; ?>"><?php echo $username; ?></option>
+ <option data-url="<?= _url('user', 'manage', 'u', $username) ?>" <?= $this->current_user === $username ? 'selected="selected"' : '' ?> value="<?= $username ?>"><?= $username ?></option>
<?php } ?>
</select>
@@ -104,7 +115,7 @@
<div class="form-group form-actions">
<div class="group-controls">
- <button type="submit" class="btn btn-attention confirm"><?php echo _t('gen.action.remove'); ?></button>
+ <button type="submit" class="btn btn-attention confirm"><?= _t('gen.action.remove') ?></button>
</div>
</div>
</form>
diff --git a/app/views/user/profile.phtml b/app/views/user/profile.phtml
index 83140376d..b8bb5cee9 100644
--- a/app/views/user/profile.phtml
+++ b/app/views/user/profile.phtml
@@ -1,82 +1,100 @@
-<?php $this->partial('aside_configure'); ?>
+<?php
+ if (!$this->disable_aside) {
+ $this->partial('aside_configure');
+ }
+?>
<div class="post">
- <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a>
+ <a href="<?= _url('index', 'index') ?>"><?= _t('gen.action.back_to_rss_feeds') ?></a>
- <form method="post" action="<?php echo _url('user', 'profile'); ?>">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
- <legend><?php echo _t('conf.profile'); ?></legend>
+ <form method="post" action="<?= _url('user', 'profile') ?>">
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
+ <legend><?= _t('conf.profile') ?></legend>
<div class="form-group">
- <label class="group-name" for="current_user"><?php echo _t('conf.user.current'); ?></label>
+ <label class="group-name" for="current_user"><?= _t('conf.user.current') ?></label>
<div class="group-controls">
- <input id="current_user" type="text" disabled="disabled" value="<?php echo Minz_Session::param('currentUser', '_'); ?>" />
- <label class="checkbox" for="is_admin">
- <input type="checkbox" id="is_admin" disabled="disabled" <?php echo FreshRSS_Auth::hasAccess('admin') ? 'checked="checked" ' : ''; ?>/>
- <?php echo _t('conf.user.is_admin'); ?>
- </label>
+ <input id="current_user" type="text" disabled="disabled" value="<?= Minz_Session::param('currentUser', '_') ?>" />
+ </div>
+ </div>
+
+ <?php if (FreshRSS_Auth::hasAccess('admin')) { ?>
+ <div class="form-group">
+ <div class="group-controls">
+ <label class="checkbox" for="is_admin">
+ <input type="checkbox" id="is_admin" disabled checked />
+ <?= _t('conf.user.is_admin') ?>
+ </label>
+ </div>
+ </div>
+ <?php } ?>
+
+ <div class="form-group">
+ <label class="group-name" for="email"><?= _t('conf.profile.email') ?></label>
+ <div class="group-controls">
+ <input id="email" name="email" type="email" value="<?= FreshRSS_Context::$user_conf->mail_login ?>" />
</div>
</div>
<div class="form-group">
- <label class="group-name" for="newPasswordPlain"><?php echo _t('conf.profile.password_form'); ?></label>
+ <label class="group-name" for="newPasswordPlain"><?= _t('conf.profile.password_form') ?></label>
<div class="group-controls">
<div class="stick">
- <input type="password" id="newPasswordPlain" name="newPasswordPlain" autocomplete="new-password" pattern=".{7,}" <?php echo cryptAvailable() ? '' : 'disabled="disabled" '; ?>/>
- <a class="btn toggle-password" data-toggle="newPasswordPlain"><?php echo _i('key'); ?></a>
+ <input type="password" id="newPasswordPlain" name="newPasswordPlain" autocomplete="new-password" pattern=".{7,}" <?= cryptAvailable() ? '' : 'disabled="disabled" ' ?>/>
+ <a class="btn toggle-password" data-toggle="newPasswordPlain"><?= _i('key') ?></a>
</div>
- <?php echo _i('help'); ?> <?php echo _t('conf.profile.password_format'); ?>
- <noscript><b><?php echo _t('gen.js.should_be_activated'); ?></b></noscript>
+ <?= _i('help') ?> <?= _t('conf.profile.password_format') ?>
+ <noscript><b><?= _t('gen.js.should_be_activated') ?></b></noscript>
</div>
</div>
<?php if (FreshRSS_Context::$system_conf->api_enabled) { ?>
<div class="form-group">
- <label class="group-name" for="apiPasswordPlain"><?php echo _t('conf.profile.password_api'); ?></label>
+ <label class="group-name" for="apiPasswordPlain"><?= _t('conf.profile.password_api') ?></label>
<div class="group-controls">
<div class="stick">
- <input type="password" id="apiPasswordPlain" name="apiPasswordPlain" autocomplete="new-password" pattern=".{7,}" <?php echo cryptAvailable() ? '' : 'disabled="disabled" '; ?>/>
- <a class="btn toggle-password" data-toggle="apiPasswordPlain"><?php echo _i('key'); ?></a>
+ <input type="password" id="apiPasswordPlain" name="apiPasswordPlain" autocomplete="new-password" pattern=".{7,}" <?= cryptAvailable() ? '' : 'disabled="disabled" ' ?>/>
+ <a class="btn toggle-password" data-toggle="apiPasswordPlain"><?= _i('key') ?></a>
</div>
- <?php echo _i('help'); ?> <kbd><a href="../api/"><?php echo Minz_Url::display('/api/', 'html', true); ?></a></kbd>
+ <?= _i('help') ?> <kbd><a href="../api/"><?= Minz_Url::display('/api/', 'html', true) ?></a></kbd>
</div>
</div>
<?php } ?>
<?php if (FreshRSS_Auth::accessNeedsAction()) { ?>
<div class="form-group">
- <label class="group-name" for="token"><?php echo _t('admin.auth.token'); ?></label>
+ <label class="group-name" for="token"><?= _t('admin.auth.token') ?></label>
<?php $token = FreshRSS_Context::$user_conf->token; ?>
<div class="group-controls">
- <input type="text" id="token" name="token" value="<?php echo $token; ?>" placeholder="<?php echo _t('gen.short.blank_to_disable'); ?>"<?php
- echo FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"'; ?> data-leave-validation="<?php echo $token; ?>"/>
- <?php echo _i('help'); ?> <?php echo _t('admin.auth.token_help'); ?>
- <kbd><?php echo Minz_Url::display(array('a' => 'rss', 'params' => array('user' => Minz_Session::param('currentUser'), 'token' => $token, 'hours' => FreshRSS_Context::$user_conf->since_hours_posts_per_rss)), 'html', true); ?></kbd>
+ <input type="text" id="token" name="token" value="<?= $token ?>" placeholder="<?= _t('gen.short.blank_to_disable') ?>"<?php
+ echo FreshRSS_Auth::accessNeedsAction() ? '' : ' disabled="disabled"'; ?> data-leave-validation="<?= $token ?>"/>
+ <?= _i('help') ?> <?= _t('admin.auth.token_help') ?>
+ <kbd><?= Minz_Url::display(array('a' => 'rss', 'params' => array('user' => Minz_Session::param('currentUser'), 'token' => $token, 'hours' => FreshRSS_Context::$user_conf->since_hours_posts_per_rss)), 'html', true) ?></kbd>
</div>
</div>
<?php } ?>
<div class="form-group form-actions">
<div class="group-controls">
- <button type="submit" class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button>
- <button type="reset" class="btn"><?php echo _t('gen.action.cancel'); ?></button>
+ <button type="submit" class="btn btn-important"><?= _t('gen.action.submit') ?></button>
+ <button type="reset" class="btn"><?= _t('gen.action.cancel') ?></button>
</div>
</div>
</form>
<?php if (!FreshRSS_Auth::hasAccess('admin')) { ?>
- <form id="crypto-form" method="post" action="<?php echo _url('user', 'delete'); ?>">
- <input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
- <legend><?php echo _t('conf.profile.delete'); ?></legend>
+ <form id="crypto-form" method="post" action="<?= _url('user', 'delete') ?>">
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
+ <legend><?= _t('conf.profile.delete') ?></legend>
- <p class="alert alert-warn"><span class="alert-head"><?php echo _t('gen.short.attention'); ?></span> <?php echo _t('conf.profile.delete.warn'); ?></p>
+ <p class="alert alert-warn"><span class="alert-head"><?= _t('gen.short.attention') ?></span> <?= _t('conf.profile.delete.warn') ?></p>
<div class="form-group">
- <label class="group-name" for="passwordPlain"><?php echo _t('gen.auth.password'); ?></label>
+ <label class="group-name" for="passwordPlain"><?= _t('gen.auth.password') ?></label>
<div class="group-controls">
<input type="password" id="passwordPlain" required="required" />
<input type="hidden" id="challenge" name="challenge" /><br />
- <noscript><strong><?php echo _t('gen.js.should_be_activated'); ?></strong></noscript>
+ <noscript><strong><?= _t('gen.js.should_be_activated') ?></strong></noscript>
</div>
</div>
@@ -88,9 +106,9 @@
'php', true
));
?>
- <input type="hidden" name="r" value="<?php echo $redirect_url; ?>" />
- <input type="hidden" name="username" id="username" value="<?php echo Minz_Session::param('currentUser', '_'); ?>" />
- <button type="submit" class="btn btn-attention confirm"><?php echo _t('gen.action.remove'); ?></button>
+ <input type="hidden" name="r" value="<?= $redirect_url ?>" />
+ <input type="hidden" name="username" id="username" value="<?= Minz_Session::param('currentUser', '_') ?>" />
+ <button type="submit" class="btn btn-attention confirm"><?= _t('gen.action.remove') ?></button>
</div>
</div>
</form>
diff --git a/app/views/user/validateEmail.phtml b/app/views/user/validateEmail.phtml
new file mode 100644
index 000000000..e525b1b6b
--- /dev/null
+++ b/app/views/user/validateEmail.phtml
@@ -0,0 +1,22 @@
+<div class="post">
+ <p>
+ <?= _t('user.email.validation.need_to', FreshRSS_Context::$system_conf->title) ?>
+ </p>
+
+ <p>
+ <?= _t('user.email.validation.email_sent_to', FreshRSS_Context::$user_conf->mail_login) ?>
+ </p>
+
+ <form action="<?= _url('user', 'sendValidationEmail') ?>" method="post">
+ <input type="hidden" name="_csrf" value="<?= FreshRSS_Auth::csrfToken() ?>" />
+ <button type="submit" class="btn">
+ <?= _t('user.email.validation.resend_email') ?>
+ </button>
+ </form>
+
+ <p>
+ <small>
+ <?= _t('user.email.validation.change_email', _url('user', 'profile')) ?>
+ </small>
+ </p>
+</div>
diff --git a/app/views/user_mailer/email_need_validation.txt b/app/views/user_mailer/email_need_validation.txt
new file mode 100644
index 000000000..c1f4d9911
--- /dev/null
+++ b/app/views/user_mailer/email_need_validation.txt
@@ -0,0 +1,5 @@
+<?= _t('user.mailer.email_need_validation.welcome', $this->username) ?>
+
+<?= _t('user.mailer.email_need_validation.body', $this->site_title) ?>
+
+<?= $this->validation_url ?>