aboutsummaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGravatar Alexis Degrugillier <aledeg@users.noreply.github.com> 2019-10-23 00:52:15 +0200
committerGravatar Alexandre Alapetite <alexandre@alapetite.fr> 2019-10-23 00:52:15 +0200
commitcc0db9af4f980829faa4bf0960617807b32fb4fa (patch)
tree8a418edeee15e878a12dbff02e241d2d76820be6 /app
parentd7f888392678d711478ed64f4a52f43021d143af (diff)
Feature/new archiving (#2335)
* Change archiving config page layout I've changed some wording and moved actions into a maintenance section. * Update purge action Now we have more control on the purge action. The configuration allows us to choose what to keep and what to discard in a more precise way. At the moment, the configuration applies for all feeds. * Add purge configuration on feed level Now the extend purge configuration is available on feed level. It is stored as attributes and will be used in the purge action. * Update purge action Now the purge action uses the feed configuration if it exists and defaults on user configuration if not. * Add empty option in period list * Fix configuration warnings * Add archiving configuration on categories See #2369 * Add user info back * Add explanations in UI * Fixes for SQLite + error + misc. * Fix invalid feed reference * Short array syntax Only for new code, so far * Fix prefix error * Query performance, default values Work in progress * Fix default values and confirm before leaving Form cancel and confirm changes before leaving were broken. And start taking advantage of the short echo syntax `<?= ?>` as we have moved to PHP 5.4+ * More work * Tuning SQL * Fix MariaDB + performance issue * SQL performance * Fix SQLite bug * Fix some attributes JSON encoding bugs Especially for SQLite export/import * More uniform, fix bugs More uniform between global, category, feed settings * Drop special cases for old articles during refresh Instead will use lastSeen date with the new archiving logic. This was generating problems anyway https://github.com/FreshRSS/FreshRSS/issues/2154 * Draft drop index keep_history Not needed anymore * MySQL typo Now properly tested with MySQL, PostgreSQL, SQLite * More work for legacy values Important to avoid overriding user's preference and risking deleting data erroneously * Fix PHP 7.3 / 7.4 warnings @aledeg "Trying to use values of type null, bool, int, float or resource as an array (such as $null["key"]) will now generate a notice. " https://php.net/migration74.incompatible * Reintroduce min articles and take care of legacy parameters * A few changes forgotten * Draft of migration + DROP of feed.keep_history * Fix several errors And give up using const for SQL to allow multiple database types (and we cannot redefine a const) * Add keep_min to categories + factorise archiving logic * Legacy fix * Fix bug yield from * Minor: Use JSON_UNESCAPED_SLASHE for attributes And make more uniform * Fix sign and missing variable * Fine tune the logic
Diffstat (limited to 'app')
-rwxr-xr-xapp/Controllers/configureController.php43
-rwxr-xr-xapp/Controllers/entryController.php20
-rwxr-xr-xapp/Controllers/feedController.php24
-rw-r--r--app/Controllers/subscriptionController.php58
-rw-r--r--app/Models/Category.php24
-rw-r--r--app/Models/CategoryDAO.php122
-rw-r--r--app/Models/CategoryDAOSQLite.php17
-rw-r--r--app/Models/ConfigurationSetter.php10
-rw-r--r--app/Models/Context.php19
-rw-r--r--app/Models/DatabaseDAO.php12
-rw-r--r--app/Models/DatabaseDAOSQLite.php2
-rw-r--r--app/Models/EntryDAO.php65
-rw-r--r--app/Models/Factory.php8
-rw-r--r--app/Models/Feed.php38
-rw-r--r--app/Models/FeedDAO.php20
-rw-r--r--app/Models/FeedDAOSQLite.php2
-rw-r--r--app/Models/Tag.php2
-rw-r--r--app/Models/TagDAO.php14
-rw-r--r--app/Models/UserDAO.php11
-rw-r--r--app/SQL/install.sql.mysql.php21
-rw-r--r--app/SQL/install.sql.pgsql.php19
-rw-r--r--app/SQL/install.sql.sqlite.php17
-rw-r--r--app/i18n/cz/conf.php12
-rw-r--r--app/i18n/cz/gen.php7
-rw-r--r--app/i18n/cz/sub.php3
-rw-r--r--app/i18n/de/conf.php12
-rw-r--r--app/i18n/de/gen.php7
-rw-r--r--app/i18n/de/sub.php3
-rw-r--r--app/i18n/en/conf.php12
-rw-r--r--app/i18n/en/gen.php7
-rw-r--r--app/i18n/en/sub.php3
-rwxr-xr-xapp/i18n/es/conf.php12
-rwxr-xr-xapp/i18n/es/gen.php7
-rwxr-xr-xapp/i18n/es/sub.php3
-rw-r--r--app/i18n/fr/conf.php12
-rw-r--r--app/i18n/fr/gen.php7
-rw-r--r--app/i18n/fr/sub.php3
-rw-r--r--app/i18n/he/conf.php12
-rw-r--r--app/i18n/he/gen.php7
-rw-r--r--app/i18n/he/sub.php3
-rw-r--r--app/i18n/it/conf.php12
-rw-r--r--app/i18n/it/gen.php7
-rw-r--r--app/i18n/it/sub.php3
-rw-r--r--app/i18n/kr/conf.php12
-rw-r--r--app/i18n/kr/gen.php7
-rw-r--r--app/i18n/kr/sub.php3
-rw-r--r--app/i18n/nl/conf.php16
-rw-r--r--app/i18n/nl/gen.php7
-rw-r--r--app/i18n/nl/sub.php3
-rw-r--r--app/i18n/oc/conf.php11
-rw-r--r--app/i18n/oc/gen.php7
-rw-r--r--app/i18n/oc/sub.php3
-rw-r--r--app/i18n/pt-br/conf.php12
-rw-r--r--app/i18n/pt-br/gen.php7
-rw-r--r--app/i18n/pt-br/sub.php3
-rw-r--r--app/i18n/ru/conf.php14
-rw-r--r--app/i18n/ru/gen.php7
-rw-r--r--app/i18n/ru/sub.php3
-rw-r--r--app/i18n/sk/conf.php2
-rw-r--r--app/i18n/sk/sub.php2
-rw-r--r--app/i18n/tr/conf.php12
-rw-r--r--app/i18n/tr/gen.php7
-rw-r--r--app/i18n/tr/sub.php3
-rw-r--r--app/i18n/zh-cn/conf.php12
-rw-r--r--app/i18n/zh-cn/gen.php7
-rw-r--r--app/i18n/zh-cn/sub.php3
-rw-r--r--app/install.php20
-rw-r--r--app/views/configure/archiving.phtml110
-rw-r--r--app/views/helpers/category/update.phtml116
-rw-r--r--app/views/helpers/feed/update.phtml113
70 files changed, 990 insertions, 254 deletions
diff --git a/app/Controllers/configureController.php b/app/Controllers/configureController.php
index 85ca9da39..b38d3289a 100755
--- a/app/Controllers/configureController.php
+++ b/app/Controllers/configureController.php
@@ -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') . ' · ');
}
/**
diff --git a/app/Controllers/entryController.php b/app/Controllers/entryController.php
index 0215128f4..7881cb3ec 100755
--- a/app/Controllers/entryController.php
+++ b/app/Controllers/entryController.php
@@ -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/feedController.php b/app/Controllers/feedController.php
index ea07d96e4..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,17 +397,13 @@ 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) . ']');
}
}
diff --git a/app/Controllers/subscriptionController.php b/app/Controllers/subscriptionController.php
index f6d5e9457..f9497f0be 100644
--- a/app/Controllers/subscriptionController.php
+++ b/app/Controllers/subscriptionController.php
@@ -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(),
);
@@ -165,9 +190,36 @@ 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'),
+ ]);
+ }
+
+ $values = [
'name' => Minz_Request::param('name', ''),
- );
+ 'attributes' => $category->attributes(),
+ ];
invalidateHttpCache();
diff --git a/app/Models/Category.php b/app/Models/Category.php
index 29c0e586b..a0ee1ddaa 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,6 +69,14 @@ class FreshRSS_Category extends Minz_Model {
return $this->hasFeedsWithError;
}
+ 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) {
@@ -87,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 ($value === null) {
+ unset($this->attributes[$key]);
+ } else {
+ $this->attributes[$key] = $value;
+ }
+ }
}
diff --git a/app/Models/CategoryDAO.php b/app/Models/CategoryDAO.php
index dd49b542d..1b8717e83 100644
--- a/app/Models/CategoryDAO.php
+++ b/app/Models/CategoryDAO.php
@@ -4,15 +4,81 @@ 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 `_category`(name) '
- . 'SELECT * FROM (SELECT TRIM(?)) c2 ' //TRIM() to provide a type hint as text for PostgreSQL
+ $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'],
);
@@ -20,7 +86,10 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable
return $this->pdo->lastInsertId('`_category_id_seq`');
} else {
$info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
- Minz_Log::error('SQL error addCategory: ' . $info[2]);
+ 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 `_category` SET name=? WHERE id=? '
+ $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'],
);
@@ -54,7 +127,10 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable
return $stm->rowCount();
} else {
$info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
- Minz_Log::error('SQL error updateCategory: ' . $info[2]);
+ if ($this->autoUpdateDb($info)) {
+ return $this->updateCategory($valuesTmp);
+ }
+ Minz_Log::error('SQL error updateCategory: ' . json_encode($info));
return false;
}
}
@@ -70,16 +146,27 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable
return $stm->rowCount();
} else {
$info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
- Minz_Log::error('SQL error deleteCategory: ' . $info[2]);
+ Minz_Log::error('SQL error deleteCategory: ' . json_encode($info));
return false;
}
}
public function selectAll() {
- $sql = 'SELECT id, name FROM `_category`';
+ $sql = 'SELECT id, name, attributes FROM `_category`';
$stm = $this->pdo->query($sql);
- while ($row = $stm->fetch(PDO::FETCH_ASSOC)) {
- yield $row;
+ 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));
+ return false;
}
}
@@ -116,7 +203,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable
public function listCategories($prePopulateFeeds = true, $details = false) {
if ($prePopulateFeeds) {
- $sql = 'SELECT c.id AS c_id, c.name AS c_name, '
+ $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 `_category` c '
. 'LEFT OUTER JOIN `_feed` f ON f.category=c.id '
@@ -124,9 +211,17 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo implements FreshRSS_Searchable
. 'GROUP BY f.id, c_id '
. 'ORDER BY c.name, f.name';
$stm = $this->pdo->prepare($sql);
- $stm->bindValue(':priority_normal', FreshRSS_Feed::PRIORITY_NORMAL, PDO::PARAM_INT);
- $stm->execute();
- return self::daoToCategoryPrepopulated($stm->fetchAll(PDO::FETCH_ASSOC));
+ $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 `_category` ORDER BY name';
$stm = $this->pdo->query($sql);
@@ -282,6 +377,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 963d37e2b..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 : '';
}
diff --git a/app/Models/Context.php b/app/Models/Context.php
index 95dc47c8c..878b72c69 100644
--- a/app/Models/Context.php
+++ b/app/Models/Context.php
@@ -51,6 +51,25 @@ 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);
+ if ($oldEntries > 0) { //Freshrss < 1.15
+ $archiving['keep_period'] = 'P' . $oldEntries . 'M';
+ }
+
+ $keepMin = (int)FreshRSS_Context::$user_conf->param('keep_history_default', -5);
+ if ($keepMin != 0 && $keepMin > -5) { //Freshrss < 1.15
+ $archiving = FreshRSS_Context::$user_conf->archiving;
+ if ($keepMin > 0) {
+ $archiving['keep_min'] = $keepMin;
+ } elseif ($keepMin == -1) { //Infinite
+ $archiving['keep_period'] = false;
+ $archiving['keep_max'] = false;
+ $archiving['keep_min'] = false;
+ }
+ FreshRSS_Context::$user_conf->archiving = $archiving;
+ }
}
/**
diff --git a/app/Models/DatabaseDAO.php b/app/Models/DatabaseDAO.php
index f6cd2f756..a36b469b1 100644
--- a/app/Models/DatabaseDAO.php
+++ b/app/Models/DatabaseDAO.php
@@ -15,11 +15,11 @@ class FreshRSS_DatabaseDAO extends Minz_ModelPdo {
const LENGTH_INDEX_UNICODE = 191;
public function create() {
- require_once(APP_PATH . '/SQL/install.sql.' . $this->pdo->dbType() . '.php');
+ 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']);
+ $sql = sprintf($SQL_CREATE_DB, empty($db['base']) ? '' : $db['base']);
return $this->pdo->exec($sql) !== false;
} catch (PDOException $e) {
$_SESSION['bd_error'] = $e->getMessage();
@@ -86,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',
));
}
@@ -164,11 +164,11 @@ class FreshRSS_DatabaseDAO extends Minz_ModelPdo {
public function ensureCaseInsensitiveGuids() {
$ok = true;
if ($this->pdo->dbType() === 'mysql') {
- include_once(APP_PATH . '/SQL/install.sql.mysql.php');
+ include(APP_PATH . '/SQL/install.sql.mysql.php');
$ok = false;
try {
- $ok = $this->pdo->exec(SQL_UPDATE_GUID_LATIN1_BIN) !== false; //FreshRSS 1.12
+ $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());
@@ -243,7 +243,7 @@ class FreshRSS_DatabaseDAO extends Minz_ModelPdo {
Minz_ModelPdo::clean();
$userDAOSQLite = new FreshRSS_UserDAO('', $sqlite);
- $categoryDAOSQLite = new FreshRSS_CategoryDAO('', $sqlite);
+ $categoryDAOSQLite = new FreshRSS_CategoryDAOSQLite('', $sqlite);
$feedDAOSQLite = new FreshRSS_FeedDAOSQLite('', $sqlite);
$entryDAOSQLite = new FreshRSS_EntryDAOSQLite('', $sqlite);
$tagDAOSQLite = new FreshRSS_TagDAOSQLite('', $sqlite);
diff --git a/app/Models/DatabaseDAOSQLite.php b/app/Models/DatabaseDAOSQLite.php
index b1473ab09..413e7ee09 100644
--- a/app/Models/DatabaseDAOSQLite.php
+++ b/app/Models/DatabaseDAOSQLite.php
@@ -66,6 +66,6 @@ class FreshRSS_DatabaseDAOSQLite extends FreshRSS_DatabaseDAO {
}
public function optimize() {
- return $this->exec('VACUUM') !== false;
+ return $this->pdo->exec('VACUUM') !== false;
}
}
diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php
index 5ff3a5b70..6a8a25b3e 100644
--- a/app/Models/EntryDAO.php
+++ b/app/Models/EntryDAO.php
@@ -26,9 +26,9 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
$this->pdo->commit();
}
try {
- require_once(APP_PATH . '/SQL/install.sql.' . $this->pdo->dbType() . '.php');
+ 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;
+ $ok = $this->pdo->exec($SQL_CREATE_TABLE_ENTRYTMP . $SQL_CREATE_INDEX_ENTRY_1) !== false;
} catch (Exception $ex) {
Minz_Log::error(__method__ . ' error: ' . $ex->getMessage());
}
@@ -544,32 +544,57 @@ SQL;
return $affected;
}
- public function cleanOldEntries($id_feed, $date_min, $keep = 15) { //Remember to call updateCachedValue($id_feed) or updateCachedValues() just after
- $sql = 'DELETE FROM `_entry` '
- . 'WHERE id_feed=:id_feed1 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 `_entry` e3 WHERE e3.id_feed=:id_feed2) recent) ' //Do not remove the most newly seen articles, plus a few seconds of tolerance
- . 'AND id NOT IN (SELECT id_entry FROM `_entrytag`) ' //Do not purge tagged entries
- . 'AND id NOT IN (SELECT id FROM (SELECT e2.id FROM `_entry` e2 WHERE e2.id_feed=:id_feed3 ORDER BY id DESC LIMIT :keep) keep)'; //Double select: MySQL doesn't support 'LIMIT & IN/ALL/ANY/SOME subquery'
- $stm = $this->pdo->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_max', $id_max, PDO::PARAM_STR);
- $stm->bindParam(':id_feed1', $id_feed, PDO::PARAM_INT);
- $stm->bindParam(':id_feed2', $id_feed, PDO::PARAM_INT);
- $stm->bindParam(':id_feed3', $id_feed, PDO::PARAM_INT);
- $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) {
+ $sql .= ' AND `lastSeen` < (SELECT e2.`lastSeen` FROM `_entry` e2 WHERE e2.id_feed = :id_feed2'
+ . ' ORDER BY e2.`lastSeen` DESC LIMIT 1 OFFSET :keep_min)';
+ $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 MAX(e3.`lastSeen`) FROM `_entry` e3 WHERE e3.id_feed = :id_feed3)';
+ $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 e4.`lastSeen` FROM `_entry` e4 WHERE e4.id_feed = :id_feed4'
+ . ' ORDER BY e4.`lastSeen` DESC LIMIT 1 OFFSET :keep_max)';
+ $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 ? $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;
}
}
diff --git a/app/Models/Factory.php b/app/Models/Factory.php
index 6f2ca2217..69885c205 100644
--- a/app/Models/Factory.php
+++ b/app/Models/Factory.php
@@ -7,7 +7,13 @@ class FreshRSS_Factory {
}
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 8aee9d62f..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;
}
@@ -230,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);
@@ -469,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';
}
diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php
index d4a91c145..fa0001df7 100644
--- a/app/Models/FeedDAO.php
+++ b/app/Models/FeedDAO.php
@@ -17,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);
}
@@ -41,12 +41,11 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
`pathEntries`,
`httpAuth`,
error,
- keep_history,
ttl,
attributes
)
VALUES
- (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
+ (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
$stm = $this->pdo->prepare($sql);
$valuesTmp['url'] = safe_ascii($valuesTmp['url']);
@@ -54,6 +53,9 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
if (!isset($valuesTmp['pathEntries'])) {
$valuesTmp['pathEntries'] = '';
}
+ if (!isset($valuesTmp['attributes'])) {
+ $valuesTmp['attributes'] = [];
+ }
$values = array(
substr($valuesTmp['url'], 0, 511),
@@ -66,9 +68,8 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
mb_strcut($valuesTmp['pathEntries'], 0, 511, 'UTF-8'),
base64_encode($valuesTmp['httpAuth']),
isset($valuesTmp['error']) ? intval($valuesTmp['error']) : 0,
- isset($valuesTmp['keep_history']) ? intval($valuesTmp['keep_history']) : FreshRSS_Feed::KEEP_HISTORY_DEFAULT,
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)) {
@@ -135,7 +136,7 @@ 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);
@@ -246,7 +247,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
public function selectAll() {
$sql = 'SELECT id, url, category, name, website, description, `lastUpdate`, priority, '
- . '`pathEntries`, `httpAuth`, error, keep_history, ttl, attributes '
+ . '`pathEntries`, `httpAuth`, error, ttl, attributes '
. 'FROM `_feed`';
$stm = $this->pdo->query($sql);
while ($row = $stm->fetch(PDO::FETCH_ASSOC)) {
@@ -319,7 +320,7 @@ 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 '
+ $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)
@@ -407,7 +408,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
. '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($values))) {
+ if (!($stm && $stm->execute())) {
$info = $stm == null ? $this->pdo->errorInfo() : $stm->errorInfo();
Minz_Log::error('SQL error truncate: ' . $info[2]);
$this->pdo->rollBack();
@@ -448,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);
diff --git a/app/Models/FeedDAOSQLite.php b/app/Models/FeedDAOSQLite.php
index c56447df6..0f685867a 100644
--- a/app/Models/FeedDAOSQLite.php
+++ b/app/Models/FeedDAOSQLite.php
@@ -5,7 +5,7 @@ class FreshRSS_FeedDAOSQLite extends FreshRSS_FeedDAO {
protected function autoUpdateDb($errorInfo) {
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/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 9c0f591c9..5882eee76 100644
--- a/app/Models/TagDAO.php
+++ b/app/Models/TagDAO.php
@@ -13,14 +13,14 @@ class FreshRSS_TagDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
$this->pdo->commit();
}
try {
- require_once(APP_PATH . '/SQL/install.sql.' . $this->pdo->dbType() . '.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...');
- $ok = $this->pdo->exec(SQL_CREATE_TABLE_TAGS) !== false;
+ $ok = $this->pdo->exec($SQL_CREATE_TABLE_TAGS) !== false;
} catch (Exception $e) {
Minz_Log::error('FreshRSS_EntryDAO::createTagTable error: ' . $e->getMessage());
}
@@ -48,9 +48,12 @@ class FreshRSS_TagDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
$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'],
);
@@ -81,9 +84,12 @@ class FreshRSS_TagDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
$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'],
);
diff --git a/app/Models/UserDAO.php b/app/Models/UserDAO.php
index 8e7e977d0..4e824cf01 100644
--- a/app/Models/UserDAO.php
+++ b/app/Models/UserDAO.php
@@ -2,14 +2,14 @@
class FreshRSS_UserDAO extends Minz_ModelPdo {
public function createUser($insertDefaultFeeds = false) {
- require_once(APP_PATH . '/SQL/install.sql.' . $this->pdo->dbType() . '.php');
+ require(APP_PATH . '/SQL/install.sql.' . $this->pdo->dbType() . '.php');
try {
- $sql = SQL_CREATE_TABLES . SQL_CREATE_TABLE_ENTRYTMP . SQL_CREATE_TABLE_TAGS;
+ $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) {
$default_feeds = FreshRSS_Context::$system_conf->default_feeds;
- $stm = $this->pdo->prepare(SQL_INSERT_FEED);
+ $stm = $this->pdo->prepare($SQL_INSERT_FEED);
foreach ($default_feeds as $feed) {
$parameters = [
':url' => $feed['url'],
@@ -38,9 +38,8 @@ class FreshRSS_UserDAO extends Minz_ModelPdo {
fwrite(STDERR, 'Deleting SQL data for user “' . $this->current_user . "”…\n");
}
- require_once(APP_PATH . '/SQL/install.sql.' . $this->pdo->dbType() . '.php');
-
- $ok = $this->pdo->exec(SQL_DROP_TABLES) !== false;
+ require(APP_PATH . '/SQL/install.sql.' . $this->pdo->dbType() . '.php');
+ $ok = $this->pdo->exec($SQL_DROP_TABLES) !== false;
if ($ok) {
return true;
diff --git a/app/SQL/install.sql.mysql.php b/app/SQL/install.sql.mysql.php
index 87b5d1989..1eabfae8b 100644
--- a/app/SQL/install.sql.mysql.php
+++ b/app/SQL/install.sql.mysql.php
@@ -1,12 +1,13 @@
<?php
-const SQL_CREATE_DB = <<<'SQL'
+$SQL_CREATE_DB = <<<'SQL'
CREATE DATABASE IF NOT EXISTS `%1$s` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
SQL;
-const SQL_CREATE_TABLES = <<<'SQL'
+$SQL_CREATE_TABLES = <<<'SQL'
CREATE TABLE IF NOT EXISTS `_category` (
`id` SMALLINT NOT NULL AUTO_INCREMENT, -- v0.7
`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
@@ -24,7 +25,6 @@ CREATE TABLE IF NOT EXISTS `_feed` (
`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
@@ -33,8 +33,7 @@ CREATE TABLE IF NOT EXISTS `_feed` (
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;
@@ -65,11 +64,11 @@ ENGINE = INNODB;
INSERT IGNORE INTO `_category` (id, name) VALUES(1, "Uncategorized");
SQL;
-const SQL_CREATE_INDEX_ENTRY_1 = <<<'SQL'
+$SQL_CREATE_INDEX_ENTRY_1 = <<<'SQL'
CREATE INDEX `entry_feed_read_index` ON `_entry` (`id_feed`,`is_read`); -- v1.7
SQL;
-const SQL_CREATE_TABLE_ENTRYTMP = <<<'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,
@@ -92,7 +91,7 @@ CREATE TABLE IF NOT EXISTS `_entrytmp` ( -- v1.7
ENGINE = INNODB;
SQL;
-const SQL_CREATE_TABLE_TAGS = <<<'SQL'
+$SQL_CREATE_TABLE_TAGS = <<<'SQL'
CREATE TABLE IF NOT EXISTS `_tag` ( -- v1.12
`id` SMALLINT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(63) NOT NULL,
@@ -113,16 +112,16 @@ CREATE TABLE IF NOT EXISTS `_entrytag` ( -- v1.12
ENGINE = INNODB;
SQL;
-const SQL_INSERT_FEED = <<<'SQL'
+$SQL_INSERT_FEED = <<<'SQL'
INSERT IGNORE INTO `_feed` (url, category, name, website, description, ttl)
VALUES(:url, 1, :name, :website, :description, 86400);
SQL;
-const SQL_DROP_TABLES = <<<'SQL'
+$SQL_DROP_TABLES = <<<'SQL'
DROP TABLE IF EXISTS `_entrytag`, `_tag`, `_entrytmp`, `_entry`, `_feed`, `_category`;
SQL;
-const SQL_UPDATE_GUID_LATIN1_BIN = <<<'SQL'
+$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 d77fe917b..53afc8a17 100644
--- a/app/SQL/install.sql.pgsql.php
+++ b/app/SQL/install.sql.pgsql.php
@@ -1,12 +1,13 @@
<?php
-const SQL_CREATE_DB = <<<'SQL'
+$SQL_CREATE_DB = <<<'SQL'
CREATE DATABASE "%1$s" ENCODING 'UTF8';
SQL;
-const SQL_CREATE_TABLES = <<<'SQL'
+$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 `_feed` (
@@ -21,7 +22,6 @@ CREATE TABLE IF NOT EXISTS `_feed` (
"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,
@@ -30,7 +30,6 @@ CREATE TABLE IF NOT EXISTS `_feed` (
);
CREATE INDEX IF NOT EXISTS `_name_index` ON `_feed` ("name");
CREATE INDEX IF NOT EXISTS `_priority_index` ON `_feed` ("priority");
-CREATE INDEX IF NOT EXISTS `_keep_history_index` ON `_feed` ("keep_history");
CREATE TABLE IF NOT EXISTS `_entry` (
"id" BIGINT NOT NULL PRIMARY KEY,
@@ -60,11 +59,11 @@ INSERT INTO `_category` (id, name)
RETURNING nextval('`_category_id_seq`');
SQL;
-const SQL_CREATE_INDEX_ENTRY_1 = <<<'SQL'
+$SQL_CREATE_INDEX_ENTRY_1 = <<<'SQL'
CREATE INDEX IF NOT EXISTS `_entry_feed_read_index` ON `_entry` ("id_feed","is_read"); -- v1.7
SQL;
-const SQL_CREATE_TABLE_ENTRYTMP = <<<'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,
@@ -85,7 +84,7 @@ CREATE TABLE IF NOT EXISTS `_entrytmp` ( -- v1.7
CREATE INDEX IF NOT EXISTS `_entrytmp_date_index` ON `_entrytmp` ("date");
SQL;
-const SQL_CREATE_TABLE_TAGS = <<<'SQL'
+$SQL_CREATE_TABLE_TAGS = <<<'SQL'
CREATE TABLE IF NOT EXISTS `_tag` ( -- v1.12
"id" SERIAL PRIMARY KEY,
"name" VARCHAR(63) UNIQUE NOT NULL,
@@ -101,12 +100,12 @@ CREATE TABLE IF NOT EXISTS `_entrytag` (
CREATE INDEX IF NOT EXISTS `_entrytag_id_entry_index` ON `_entrytag` ("id_entry");
SQL;
-const SQL_INSERT_FEED = <<<'SQL'
+$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;
-const SQL_DROP_TABLES = <<<'SQL'
+$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 d3a5e0697..2a4763637 100644
--- a/app/SQL/install.sql.sqlite.php
+++ b/app/SQL/install.sql.sqlite.php
@@ -1,12 +1,13 @@
<?php
-const SQL_CREATE_DB = <<<'SQL'
+$SQL_CREATE_DB = <<<'SQL'
SELECT 1; -- Do nothing for SQLite
SQL;
-const SQL_CREATE_TABLES = <<<'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`)
);
@@ -22,7 +23,6 @@ CREATE TABLE IF NOT EXISTS `feed` (
`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,
@@ -32,7 +32,6 @@ CREATE TABLE IF NOT EXISTS `feed` (
);
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 TABLE IF NOT EXISTS `entry` (
`id` BIGINT NOT NULL,
@@ -60,11 +59,11 @@ CREATE INDEX IF NOT EXISTS entry_feed_read_index ON `entry`(`id_feed`,`is_read`)
INSERT OR IGNORE INTO `category` (id, name) VALUES(1, "Uncategorized");
SQL;
-const SQL_CREATE_INDEX_ENTRY_1 = <<<'SQL'
+$SQL_CREATE_INDEX_ENTRY_1 = <<<'SQL'
CREATE INDEX IF NOT EXISTS entry_feed_read_index ON `entry`(`id_feed`,`is_read`); -- v1.7
SQL;
-const SQL_CREATE_TABLE_ENTRYTMP = <<<'SQL'
+$SQL_CREATE_TABLE_ENTRYTMP = <<<'SQL'
CREATE TABLE IF NOT EXISTS `entrytmp` ( -- v1.7
`id` BIGINT NOT NULL,
`guid` VARCHAR(760) NOT NULL,
@@ -86,7 +85,7 @@ CREATE TABLE IF NOT EXISTS `entrytmp` ( -- v1.7
CREATE INDEX IF NOT EXISTS entrytmp_date_index ON `entrytmp`(`date`);
SQL;
-const SQL_CREATE_TABLE_TAGS = <<<'SQL'
+$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,
@@ -103,12 +102,12 @@ CREATE TABLE IF NOT EXISTS `entrytag` (
CREATE INDEX IF NOT EXISTS entrytag_id_entry_index ON `entrytag` (`id_entry`);
SQL;
-const SQL_INSERT_FEED = <<<'SQL'
+$SQL_INSERT_FEED = <<<'SQL'
INSERT OR IGNORE INTO `feed` (url, category, name, website, description, ttl)
VALUES(:url, 1, :name, :website, :description, 86400);
SQL;
-const SQL_DROP_TABLES = <<<'SQL'
+$SQL_DROP_TABLES = <<<'SQL'
DROP TABLE IF EXISTS `entrytag`;
DROP TABLE IF EXISTS `tag`;
DROP TABLE IF EXISTS `entrytmp`;
diff --git a/app/i18n/cz/conf.php b/app/i18n/cz/conf.php
index cd7535571..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ž',
),
diff --git a/app/i18n/cz/gen.php b/app/i18n/cz/gen.php
index c6dabd555..de1456187 100644
--- a/app/i18n/cz/gen.php
+++ b/app/i18n/cz/gen.php
@@ -162,6 +162,13 @@ 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*',
diff --git a/app/i18n/cz/sub.php b/app/i18n/cz/sub.php
index b2bdf416b..eaaff9acd 100644
--- a/app/i18n/cz/sub.php
+++ b/app/i18n/cz/sub.php
@@ -13,6 +13,7 @@ return array(
'category' => array(
'_' => 'Kategorie',
'add' => 'Přidat kategorii',
+ 'archiving' => 'Archivace',
'empty' => 'Vyprázdit kategorii',
'information' => 'Informace',
'new' => 'Nová kategorie',
@@ -40,7 +41,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.',
diff --git a/app/i18n/de/conf.php b/app/i18n/de/conf.php
index 99225da9c..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',
),
diff --git a/app/i18n/de/gen.php b/app/i18n/de/gen.php
index 6cc791d5e..e2dd2a251 100644
--- a/app/i18n/de/gen.php
+++ b/app/i18n/de/gen.php
@@ -162,6 +162,13 @@ 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*',
diff --git a/app/i18n/de/sub.php b/app/i18n/de/sub.php
index abc01b954..1227b5559 100644
--- a/app/i18n/de/sub.php
+++ b/app/i18n/de/sub.php
@@ -13,6 +13,7 @@ return array(
'category' => array(
'_' => 'Kategorie',
'add' => 'Eine Kategorie hinzufügen',
+ 'archiving' => 'Archivierung',
'empty' => 'Leere Kategorie',
'information' => 'Information',
'new' => 'Neue Kategorie',
@@ -40,7 +41,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.',
diff --git a/app/i18n/en/conf.php b/app/i18n/en/conf.php
index 1078c736c..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',
),
diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php
index a6ddcbb60..fc1bd587a 100644
--- a/app/i18n/en/gen.php
+++ b/app/i18n/en/gen.php
@@ -163,6 +163,13 @@ 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*',
diff --git a/app/i18n/en/sub.php b/app/i18n/en/sub.php
index fde01f9df..04ca793ec 100644
--- a/app/i18n/en/sub.php
+++ b/app/i18n/en/sub.php
@@ -13,6 +13,7 @@ return array(
'category' => array(
'_' => 'Category',
'add' => 'Add a category',
+ 'archiving' => 'Archiving',
'empty' => 'Empty category',
'information' => 'Information',
'new' => 'New category',
@@ -40,7 +41,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.',
diff --git a/app/i18n/es/conf.php b/app/i18n/es/conf.php
index 6aaad8d13..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',
),
diff --git a/app/i18n/es/gen.php b/app/i18n/es/gen.php
index 4affecc51..538ddc8fe 100755
--- a/app/i18n/es/gen.php
+++ b/app/i18n/es/gen.php
@@ -162,6 +162,13 @@ 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*',
diff --git a/app/i18n/es/sub.php b/app/i18n/es/sub.php
index 7d33c59fa..96be76c6c 100755
--- a/app/i18n/es/sub.php
+++ b/app/i18n/es/sub.php
@@ -13,6 +13,7 @@ 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',
@@ -40,7 +41,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.',
diff --git a/app/i18n/fr/conf.php b/app/i18n/fr/conf.php
index dcd623b5a..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',
),
diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php
index 01b66d316..a6875dd05 100644
--- a/app/i18n/fr/gen.php
+++ b/app/i18n/fr/gen.php
@@ -162,6 +162,13 @@ 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*',
diff --git a/app/i18n/fr/sub.php b/app/i18n/fr/sub.php
index df44150c2..d09a19e5a 100644
--- a/app/i18n/fr/sub.php
+++ b/app/i18n/fr/sub.php
@@ -13,6 +13,7 @@ return array(
'category' => array(
'_' => 'Catégorie',
'add' => 'Ajouter une catégorie',
+ 'archiving' => 'Archivage',
'empty' => 'Catégorie vide',
'information' => 'Informations',
'new' => 'Nouvelle catégorie',
@@ -40,7 +41,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é.',
diff --git a/app/i18n/he/conf.php b/app/i18n/he/conf.php
index 7e764b944..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' => 'אין לרענן אוטומטית יותר מ',
),
diff --git a/app/i18n/he/gen.php b/app/i18n/he/gen.php
index 158f11e5b..34e6d77de 100644
--- a/app/i18n/he/gen.php
+++ b/app/i18n/he/gen.php
@@ -162,6 +162,13 @@ 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*',
diff --git a/app/i18n/he/sub.php b/app/i18n/he/sub.php
index 8a629defb..15965d9e2 100644
--- a/app/i18n/he/sub.php
+++ b/app/i18n/he/sub.php
@@ -13,6 +13,7 @@ return array(
'category' => array(
'_' => 'קטגוריה',
'add' => 'הוספת קטגוריה',
+ 'archiving' => 'ארכוב',
'empty' => 'Empty category', //TODO - Translation
'information' => 'מידע',
'new' => 'קטגוריה חדשה',
@@ -40,7 +41,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' => 'אף הזנה לא נבחרה.',
diff --git a/app/i18n/it/conf.php b/app/i18n/it/conf.php
index f06302c72..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',
),
diff --git a/app/i18n/it/gen.php b/app/i18n/it/gen.php
index 604cc6941..50d4b4e6c 100644
--- a/app/i18n/it/gen.php
+++ b/app/i18n/it/gen.php
@@ -162,6 +162,13 @@ 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*',
diff --git a/app/i18n/it/sub.php b/app/i18n/it/sub.php
index 50738d9e3..22cd36986 100644
--- a/app/i18n/it/sub.php
+++ b/app/i18n/it/sub.php
@@ -13,6 +13,7 @@ return array(
'category' => array(
'_' => 'Categoria',
'add' => 'Aggiungi una categoria',
+ 'archiving' => 'Archiviazione',
'empty' => 'Categoria vuota',
'information' => 'Informazioni',
'new' => 'Nuova categoria',
@@ -40,7 +41,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.',
diff --git a/app/i18n/kr/conf.php b/app/i18n/kr/conf.php
index 397d57418..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' => '다음 시간이 지나기 전에 새로고침 금지',
),
diff --git a/app/i18n/kr/gen.php b/app/i18n/kr/gen.php
index 55fea3d66..fdc95d431 100644
--- a/app/i18n/kr/gen.php
+++ b/app/i18n/kr/gen.php
@@ -162,6 +162,13 @@ 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*',
diff --git a/app/i18n/kr/sub.php b/app/i18n/kr/sub.php
index f8eccfa27..2586395f2 100644
--- a/app/i18n/kr/sub.php
+++ b/app/i18n/kr/sub.php
@@ -13,6 +13,7 @@ return array(
'category' => array(
'_' => '카테고리',
'add' => '카테고리 추가',
+ 'archiving' => '보관',
'empty' => '빈 카테고리',
'information' => '정보',
'new' => '새 카테고리',
@@ -40,7 +41,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' => '선택된 피드가 없습니다.',
diff --git a/app/i18n/nl/conf.php b/app/i18n/nl/conf.php
index ec219d051..22302ccc0 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' => 'Purge exception', //TODO - Translation
'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' => 'Never delete favourites', //TODO - Translation
+ 'keep_min_by_feed' => 'Minimum aantal te behouden artikelen in de feed',
+ 'keep_labels' => 'Never delete labels', //TODO - Translation
+ 'keep_unreads' => 'Never delete unreads', //TODO - Translation
+ 'maintenance' => 'Maintenance', //TODO - Translation
+ 'optimize' => 'Optimaliseer database', //TODO - Translation
'optimize_help' => 'Doe dit zo af en toe om de omvang van de database te verkleinen',
+ 'policy' => 'Purge policy', //TODO - Translation
+ 'policy_warning' => 'If no purge policy is selected, every article will be kept.', //TODO - Translation
'purge_now' => 'Schoon nu op',
+ 'keep_max' => 'Maximum number of articles to keep', //TODO - Translation
+ 'keep_period' => 'Maximum age of articles to keep', //TODO - Translation
'title' => 'Archivering',
'ttl' => 'Vernieuw niet automatisch meer dan',
),
diff --git a/app/i18n/nl/gen.php b/app/i18n/nl/gen.php
index 0dcb3010a..4854e806e 100644
--- a/app/i18n/nl/gen.php
+++ b/app/i18n/nl/gen.php
@@ -162,6 +162,13 @@ return array(
'nothing_to_load' => 'Er zijn geen artikelen meer',
'previous' => 'Vorige',
),
+ 'period' => array(
+ 'days' => 'days', //TODO - Translation
+ 'hours' => 'hours', //TODO - Translation
+ 'months' => 'months', //TODO - Translation
+ 'weeks' => 'weeks', //TODO - Translation
+ 'years' => 'years', //TODO - Translation
+ ),
'share' => array(
'email' => 'Email',
'Known' => 'Known-gebaseerde sites',
diff --git a/app/i18n/nl/sub.php b/app/i18n/nl/sub.php
index 8ceb5aa28..6b498132f 100644
--- a/app/i18n/nl/sub.php
+++ b/app/i18n/nl/sub.php
@@ -13,6 +13,7 @@ return array(
'category' => array(
'_' => 'Categorie',
'add' => 'Voeg categorie toe',
+ 'archiving' => 'Archiveren',
'empty' => 'Lege categorie',
'information' => 'Informatie',
'new' => 'Nieuwe categorie',
@@ -40,7 +41,7 @@ return array(
'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.',
diff --git a/app/i18n/oc/conf.php b/app/i18n/oc/conf.php
index 76c41911e..e8de3b089 100644
--- a/app/i18n/oc/conf.php
+++ b/app/i18n/oc/conf.php
@@ -5,11 +5,20 @@ return array(
'_' => 'Archius',
'advanced' => 'Avançat',
'delete_after' => 'Levar los articles aprèp',
+ 'exception' => 'Purge exception', //TODO - Translation
'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' => 'Never delete favourites', //TODO - Translation
+ 'keep_min_by_feed' => 'Nombre minimum d’articles de servar per flux',
+ 'keep_labels' => 'Never delete labels', //TODO - Translation
+ 'keep_unreads' => 'Never delete unreads', //TODO - Translation
+ 'maintenance' => 'Maintenance', //TODO - Translation
'optimize' => 'Optimizar la basa de donada',
'optimize_help' => 'De far de temps en temps per redusir la talha de la basa de donadas',
+ 'policy' => 'Purge policy', //TODO - Translation
+ 'policy_warning' => 'If no purge policy is selected, every article will be kept.', //TODO - Translation
'purge_now' => 'Purgar ara',
+ 'keep_max' => 'Maximum number of articles to keep', //TODO - Translation
+ 'keep_period' => 'Maximum age of articles to keep', //TODO - Translation
'title' => 'Archius',
'ttl' => 'Actualizar pas automaticament mai sovent que',
),
diff --git a/app/i18n/oc/gen.php b/app/i18n/oc/gen.php
index 7ab56368f..928377997 100644
--- a/app/i18n/oc/gen.php
+++ b/app/i18n/oc/gen.php
@@ -162,6 +162,13 @@ return array(
'nothing_to_load' => 'I a pas mai d’articles',
'previous' => 'Precedent',
),
+ '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*',
diff --git a/app/i18n/oc/sub.php b/app/i18n/oc/sub.php
index eae9dff29..0f465d7ca 100644
--- a/app/i18n/oc/sub.php
+++ b/app/i18n/oc/sub.php
@@ -12,6 +12,7 @@ return array(
'category' => array(
'_' => 'Categoria',
'add' => 'Ajustar una categoria',
+ 'archiving' => 'Archivar',
'empty' => 'Categoria voida',
'information' => 'Informacions',
'new' => 'Nòva categoria',
@@ -39,7 +40,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.',
diff --git a/app/i18n/pt-br/conf.php b/app/i18n/pt-br/conf.php
index eb067e58a..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',
),
diff --git a/app/i18n/pt-br/gen.php b/app/i18n/pt-br/gen.php
index b327937d5..0e7f367ee 100644
--- a/app/i18n/pt-br/gen.php
+++ b/app/i18n/pt-br/gen.php
@@ -162,6 +162,13 @@ 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*',
diff --git a/app/i18n/pt-br/sub.php b/app/i18n/pt-br/sub.php
index d4bea33c4..c4c28bd6c 100644
--- a/app/i18n/pt-br/sub.php
+++ b/app/i18n/pt-br/sub.php
@@ -13,6 +13,7 @@ return array(
'category' => array(
'_' => 'Categoria',
'add' => 'Adicionar uma categoria',
+ 'archiving' => 'Arquivar',
'empty' => 'Categoria vazia',
'information' => 'Informações',
'new' => 'Nova categoria',
@@ -40,7 +41,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.',
diff --git a/app/i18n/ru/conf.php b/app/i18n/ru/conf.php
index af6f3b5f6..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' => 'Не обновлять чаще чем',
),
diff --git a/app/i18n/ru/gen.php b/app/i18n/ru/gen.php
index cc1d7e00e..5200a7005 100644
--- a/app/i18n/ru/gen.php
+++ b/app/i18n/ru/gen.php
@@ -162,6 +162,13 @@ 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*',
diff --git a/app/i18n/ru/sub.php b/app/i18n/ru/sub.php
index a2c4e4690..f4bda385d 100644
--- a/app/i18n/ru/sub.php
+++ b/app/i18n/ru/sub.php
@@ -13,6 +13,7 @@ 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
@@ -40,7 +41,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
diff --git a/app/i18n/sk/conf.php b/app/i18n/sk/conf.php
index f704fd4be..2e2289b79 100644
--- a/app/i18n/sk/conf.php
+++ b/app/i18n/sk/conf.php
@@ -6,7 +6,7 @@ return array(
'advanced' => 'Pokročilé',
'delete_after' => 'Vymazať články po',
'help' => 'Viac možností nájdete v nastaveniach kanála',
- 'keep_history_by_feed' => 'Minimálny počet článkov kanála na zachovanie',
+ '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',
diff --git a/app/i18n/sk/sub.php b/app/i18n/sk/sub.php
index 4dcd09f57..2167e1817 100644
--- a/app/i18n/sk/sub.php
+++ b/app/i18n/sk/sub.php
@@ -40,7 +40,7 @@ return array(
'help' => 'Napíšte jeden výraz hľadania na riadok.',
),
'information' => 'Informácia',
- 'keep_history' => 'Minimálny počet článkov na uchovanie',
+ '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.',
diff --git a/app/i18n/tr/conf.php b/app/i18n/tr/conf.php
index 2bf1e8a6a..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',
),
diff --git a/app/i18n/tr/gen.php b/app/i18n/tr/gen.php
index 5e361affb..ccc5b9ee6 100644
--- a/app/i18n/tr/gen.php
+++ b/app/i18n/tr/gen.php
@@ -162,6 +162,13 @@ 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*',
diff --git a/app/i18n/tr/sub.php b/app/i18n/tr/sub.php
index 858d15758..f6f40d3f7 100644
--- a/app/i18n/tr/sub.php
+++ b/app/i18n/tr/sub.php
@@ -13,6 +13,7 @@ return array(
'category' => array(
'_' => 'Kategori',
'add' => 'Kategori ekle',
+ 'archiving' => 'Arşiv',
'empty' => 'Boş kategori',
'information' => 'Bilgi',
'new' => 'Yeni kategori',
@@ -40,7 +41,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.',
diff --git a/app/i18n/zh-cn/conf.php b/app/i18n/zh-cn/conf.php
index 2960cd6b1..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' => '最小自动更新时间',
),
diff --git a/app/i18n/zh-cn/gen.php b/app/i18n/zh-cn/gen.php
index 7ae156573..31817260e 100644
--- a/app/i18n/zh-cn/gen.php
+++ b/app/i18n/zh-cn/gen.php
@@ -162,6 +162,13 @@ 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*',
diff --git a/app/i18n/zh-cn/sub.php b/app/i18n/zh-cn/sub.php
index bf517756b..f6f3a0f7a 100644
--- a/app/i18n/zh-cn/sub.php
+++ b/app/i18n/zh-cn/sub.php
@@ -13,6 +13,7 @@ return array(
'category' => array(
'_' => '分类',
'add' => '添加分类',
+ 'archiving' => '存档',
'empty' => '空分类',
'information' => '信息',
'new' => '新分类',
@@ -40,7 +41,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 源。',
diff --git a/app/install.php b/app/install.php
index 366fb0cfc..f8bc6dd4e 100644
--- a/app/install.php
+++ b/app/install.php
@@ -86,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;
@@ -184,14 +183,12 @@ function saveStep3() {
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', '');
}
- if (empty($_SESSION['old_entries']) ||
- empty($_SESSION['auth_type']) ||
+ if (empty($_SESSION['auth_type']) ||
empty($_SESSION['default_user'])) {
return false;
}
@@ -208,10 +205,6 @@ function saveStep3() {
FreshRSS_Context::$system_conf->default_user = $_SESSION['default_user'];
FreshRSS_Context::$system_conf->save();
- if ((!ctype_digit($_SESSION['old_entries'])) ||($_SESSION['old_entries'] < 1)) {
- $_SESSION['old_entries'] = $user_default_config->old_entries;
- }
-
// Create default user files but first, we delete previous data to
// avoid access right problems.
recursive_unlink(USERS_PATH . '/' . $_SESSION['default_user']);
@@ -225,7 +218,6 @@ function saveStep3() {
'',
[
'language' => $_SESSION['language'],
- 'old_entries' => $_SESSION['old_entries'],
]
);
} catch (Exception $e) {
@@ -317,8 +309,7 @@ function checkStep2() {
}
function checkStep3() {
- $conf = !empty($_SESSION['old_entries']) &&
- !empty($_SESSION['default_user']);
+ $conf = !empty($_SESSION['default_user']);
$form = isset($_SESSION['auth_type']);
@@ -594,13 +585,6 @@ function printStep3() {
<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" />
diff --git a/app/views/configure/archiving.phtml b/app/views/configure/archiving.phtml
index 09be55fd9..0387a2b96 100644
--- a/app/views/configure/archiving.phtml
+++ b/app/views/configure/archiving.phtml
@@ -9,23 +9,6 @@
<p><?php echo _i('help'); ?> <?php echo _t('conf.archiving.help'); ?></p>
<div class="form-group">
- <label class="group-name" for="old_entries"><?php echo _t('conf.archiving.delete_after'); ?></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
@@ -47,6 +30,76 @@
</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"><?php echo _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>
@@ -55,9 +108,9 @@
</div>
</form>
- <form method="post" action="<?php echo _url('entry', 'optimize'); ?>">
+ <legend><?php echo _t('conf.archiving.maintenance'); ?></legend>
+ <form method="post" action="<?php echo _url('entry', 'purge'); ?>">
<input type="hidden" name="_csrf" value="<?php echo FreshRSS_Auth::csrfToken(); ?>" />
- <legend><?php echo _t('conf.archiving.advanced'); ?></legend>
<div class="form-group">
<label class="group-name"><?php echo _t('conf.user.current'); ?></label>
@@ -66,21 +119,30 @@
</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"><?php echo _t('conf.archiving.purge_now'); ?></button>
</div>
</div>
+ </form>
- <div class="form-group form-actions">
+ <form method="post" action="<?php echo _url('entry', 'optimize'); ?>">
+ <input type="hidden" name="_csrf" value="<?php echo 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'); ?>
</div>
</div>
- <?php } ?>
</form>
+
+ <?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); ?>
+ </div>
+ </div>
+ <?php endif; ?>
</div>
diff --git a/app/views/helpers/category/update.phtml b/app/views/helpers/category/update.phtml
index b64bd786a..31482f163 100644
--- a/app/views/helpers/category/update.phtml
+++ b/app/views/helpers/category/update.phtml
@@ -33,5 +33,121 @@
<?php endif;?>
</div>
</div>
+
+ <legend><?php echo _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"><?php echo _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/feed/update.phtml b/app/views/helpers/feed/update.phtml
index 620806d7b..84461ed03 100644
--- a/app/views/helpers/feed/update.phtml
+++ b/app/views/helpers/feed/update.phtml
@@ -78,6 +78,7 @@
<div class="form-group form-actions">
<div class="group-controls">
<button class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button>
+ <button type="reset" class="btn"><?php echo _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()); ?>"
@@ -97,16 +98,115 @@
</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"><?php echo _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>
<div class="group-controls">
@@ -143,6 +243,7 @@
<div class="form-group form-actions">
<div class="group-controls">
<button class="btn btn-important"><?php echo _t('gen.action.submit'); ?></button>
+ <button type="reset" class="btn"><?php echo _t('gen.action.cancel'); ?></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>
</div>
</div>