summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/Controllers/authController.php6
-rw-r--r--app/Controllers/importExportController.php114
-rw-r--r--app/Models/Auth.php9
-rw-r--r--app/Models/Entry.php1
-rw-r--r--app/Models/EntryDAO.php6
-rw-r--r--app/Models/FeedDAO.php5
-rw-r--r--app/Models/TagDAO.php14
-rw-r--r--app/Models/UserDAO.php10
-rwxr-xr-xapp/actualize_script.php8
-rw-r--r--app/i18n/cz/sub.php1
-rw-r--r--app/i18n/de/sub.php1
-rw-r--r--app/i18n/en/sub.php1
-rwxr-xr-xapp/i18n/es/sub.php1
-rw-r--r--app/i18n/fr/sub.php1
-rw-r--r--app/i18n/he/sub.php1
-rw-r--r--app/i18n/it/sub.php1
-rw-r--r--app/i18n/kr/sub.php1
-rw-r--r--app/i18n/nl/admin.php4
-rw-r--r--app/i18n/nl/conf.php6
-rw-r--r--app/i18n/nl/index.php4
-rw-r--r--app/i18n/nl/sub.php9
-rw-r--r--app/i18n/oc/conf.php4
-rw-r--r--app/i18n/oc/gen.php32
-rw-r--r--app/i18n/oc/sub.php13
-rw-r--r--app/i18n/pt-br/sub.php1
-rw-r--r--app/i18n/ru/sub.php1
-rw-r--r--app/i18n/tr/sub.php1
-rw-r--r--app/i18n/zh-cn/sub.php1
-rw-r--r--app/install.php3
-rw-r--r--app/layout/header.phtml2
-rw-r--r--app/views/configure/display.phtml2
-rw-r--r--app/views/helpers/export/articles.phtml11
-rw-r--r--app/views/importExport/index.phtml5
33 files changed, 193 insertions, 87 deletions
diff --git a/app/Controllers/authController.php b/app/Controllers/authController.php
index 5ad1a51d9..3b2d78b19 100644
--- a/app/Controllers/authController.php
+++ b/app/Controllers/authController.php
@@ -79,8 +79,12 @@ class FreshRSS_auth_Controller extends Minz_ActionController {
Minz_Request::forward(array('c' => 'auth', 'a' => 'formLogin'));
break;
case 'http_auth':
+ Minz_Error::error(403, array('error' => array(_t('feedback.access.denied'),
+ ' [HTTP Remote-User=' . htmlspecialchars(httpAuthUser(), ENT_NOQUOTES, 'UTF-8') . ']'
+ )), false);
+ break;
case 'none':
- // It should not happened!
+ // It should not happen!
Minz_Error::error(404);
default:
// TODO load plugin instead
diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php
index 2d8d4e01d..80b9868ec 100644
--- a/app/Controllers/importExportController.php
+++ b/app/Controllers/importExportController.php
@@ -41,7 +41,8 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
$list_files = array(
'opml' => array(),
'json_starred' => array(),
- 'json_feed' => array()
+ 'json_feed' => array(),
+ 'ttrss_starred' => array(),
);
// We try to list all files according to their type
@@ -434,10 +435,9 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
}
return false;
}
+ $items = isset($article_object['items']) ? $article_object['items'] : $article_object;
- $is_read = FreshRSS_Context::$user_conf->mark_when['reception'] ? 1 : 0;
-
- $google_compliant = strpos($article_object['id'], 'com.google') !== false;
+ $mark_as_read = FreshRSS_Context::$user_conf->mark_when['reception'] ? 1 : 0;
$error = false;
$article_to_feed = array();
@@ -447,9 +447,23 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
$limits = FreshRSS_Context::$system_conf->limits;
// First, we check feeds of articles are in DB (and add them if needed).
- foreach ($article_object['items'] as $item) {
- $key = $google_compliant ? 'htmlUrl' : 'feedUrl';
- $feed = new FreshRSS_Feed($item['origin'][$key]);
+ foreach ($items as $item) {
+ if (!isset($item['origin'])) {
+ $item['origin'] = array('title' => 'Import');
+ }
+ if (!empty($item['origin']['feedUrl'])) {
+ $feedUrl = $item['origin']['feedUrl'];
+ } elseif (!empty($item['origin']['streamId']) && strpos($item['origin']['streamId'], 'feed/') === 0) {
+ $feedUrl = substr($item['origin']['streamId'], 5); //Google Reader
+ $item['origin']['feedUrl'] = $feedUrl;
+ } elseif (!empty($item['origin']['htmlUrl'])) {
+ $feedUrl = $item['origin']['htmlUrl'];
+ } else {
+ $feedUrl = 'http://import.localhost/import.xml';
+ $item['origin']['feedUrl'] = $feedUrl;
+ $item['origin']['disable'] = true;
+ }
+ $feed = new FreshRSS_Feed($feedUrl);
$feed = $this->feedDAO->searchByUrl($feed->url());
if ($feed == null) {
@@ -497,7 +511,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
// Then, articles are imported.
$newGuids = array();
$this->entryDAO->beginTransaction();
- foreach ($article_object['items'] as $item) {
+ foreach ($items as $item) {
if (empty($article_to_feed[$item['id']])) {
// Related feed does not exist for this entry, do nothing.
continue;
@@ -505,14 +519,19 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
$feed_id = $article_to_feed[$item['id']];
$author = isset($item['author']) ? $item['author'] : '';
- $is_starred = $starred;
- $tags = $item['categories'];
+ $is_starred = false;
+ $is_read = null;
+ $tags = empty($item['categories']) ? array() : $item['categories'];
$labels = array();
for ($i = count($tags) - 1; $i >= 0; $i --) {
$tag = trim($tags[$i]);
if (strpos($tag, 'user/-/') !== false) {
if ($tag === 'user/-/state/com.google/starred') {
$is_starred = true;
+ } elseif ($tag === 'user/-/state/com.google/read') {
+ $is_read = true;
+ } elseif ($tag === 'user/-/state/com.google/unread') {
+ $is_read = false;
} elseif (strpos($tag, 'user/-/label/') === 0) {
$tag = trim(substr($tag, 13));
if ($tag != '') {
@@ -522,19 +541,49 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
unset($tags[$i]);
}
}
+ if ($starred && !$is_starred) {
+ //If the article has no label, mark it as starred (old format)
+ $is_starred = empty($labels);
+ }
+ if ($is_read === null) {
+ $is_read = $mark_as_read;
+ }
+
+ if (isset($item['alternate'][0]['href'])) {
+ $url = $item['alternate'][0]['href'];
+ } elseif (isset($item['url'])) {
+ $url = $item['url']; //FeedBin
+ } else {
+ $url = '';
+ }
- $url = $item['alternate'][0]['href'];
if (!empty($item['content']['content'])) {
$content = $item['content']['content'];
} elseif (!empty($item['summary']['content'])) {
$content = $item['summary']['content'];
+ } elseif (!empty($item['content'])) {
+ $content = $item['content']; //FeedBin
+ } else {
+ $content = '';
}
$content = sanitizeHTML($content, $url);
+ if (!empty($item['published'])) {
+ $published = $item['published'];
+ } elseif (!empty($item['timestampUsec'])) {
+ $published = substr($item['timestampUsec'], 0, -6);
+ } elseif (!empty($item['updated'])) {
+ $published = $item['updated'];
+ } else {
+ $published = 0;
+ }
+ if (!ctype_digit('' . $published)) {
+ $published = strtotime($published);
+ }
+
$entry = new FreshRSS_Entry(
$feed_id, $item['id'], $item['title'], $author,
- $content, $url,
- $item['published'], $is_read, $is_starred
+ $content, $url, $published, $is_read, $is_starred
);
$entry->_id(min(time(), $entry->date(true)) . uSecString());
$entry->_tags($tags);
@@ -626,6 +675,9 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
$feed->_category(FreshRSS_CategoryDAO::DEFAULTCATEGORYID);
$feed->_name($name);
$feed->_website($website);
+ if (!empty($origin['disable'])) {
+ $feed->_ttl(-1 * FreshRSS_Context::$user_conf->ttl_default);
+ }
// Call the extension hook
$feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed);
@@ -650,7 +702,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
return $return;
}
- public function exportFile($export_opml = true, $export_starred = false, $export_feeds = array(), $maxFeedEntries = 50, $username = null) {
+ public function exportFile($export_opml = true, $export_starred = false, $export_labelled = false, $export_feeds = array(), $maxFeedEntries = 50, $username = null) {
require_once(LIB_PATH . '/lib_opml.php');
$this->catDAO = new FreshRSS_CategoryDAO($username);
@@ -674,8 +726,11 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
$export_files["feeds_${day}.opml.xml"] = $this->generateOpml();
}
- if ($export_starred) {
- $export_files["starred_${day}.json"] = $this->generateEntries('starred');
+ if ($export_starred || $export_labelled) {
+ $export_files["starred_${day}.json"] = $this->generateEntries(
+ ($export_starred ? 'S' : '') .
+ ($export_labelled ? 'T' : '')
+ );
}
foreach ($export_feeds as $feed_id) {
@@ -683,7 +738,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
if ($feed) {
$filename = "feed_${day}_" . $feed->category() . '_'
. $feed->id() . '.json';
- $export_files[$filename] = $this->generateEntries('feed', $feed, $maxFeedEntries);
+ $export_files[$filename] = $this->generateEntries('f', $feed, $maxFeedEntries);
}
}
@@ -725,6 +780,7 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
$nb_files = $this->exportFile(
Minz_Request::param('export_opml', false),
Minz_Request::param('export_starred', false),
+ Minz_Request::param('export_labelled', false),
Minz_Request::param('export_feeds', array())
);
} catch (FreshRSS_ZipMissing_Exception $zme) {
@@ -758,27 +814,29 @@ class FreshRSS_importExport_Controller extends Minz_ActionController {
/**
* This method returns a JSON file content.
*
- * @param string $type must be "starred" or "feed"
+ * @param string $type must be one of:
+ * 'S' (starred/favourite), 'f' (feed), 'T' (taggued/labelled), 'ST' (starred or labelled)
* @param FreshRSS_Feed $feed feed of which we want to get entries.
* @return string the JSON file content.
*/
private function generateEntries($type, $feed = null, $maxFeedEntries = 50) {
$this->view->categories = $this->catDAO->listCategories();
+ $tagDAO = FreshRSS_Factory::createTagDao();
- if ($type == 'starred') {
+ if ($type === 's' || $type === 'S' || $type === 'T' || $type === 'ST') {
$this->view->list_title = _t('sub.import_export.starred_list');
$this->view->type = 'starred';
- $unread_fav = $this->entryDAO->countUnreadReadFavorites();
- $this->view->entriesRaw = $this->entryDAO->listWhereRaw(
- 's', '', FreshRSS_Entry::STATE_ALL, 'ASC', $unread_fav['all']
- );
- } elseif ($type === 'feed' && $feed != null) {
+ $this->view->entriesId = $this->entryDAO->listIdsWhere($type, '', FreshRSS_Entry::STATE_ALL, 'ASC', -1);
+ $this->view->entryIdsTagNames = $tagDAO->getEntryIdsTagNames($this->view->entriesId);
+ //The following is a streamable query, i.e. must be last
+ $this->view->entriesRaw = $this->entryDAO->listWhereRaw($type, '', FreshRSS_Entry::STATE_ALL, 'ASC', -1);
+ } elseif ($type === 'f' && $feed != null) {
$this->view->list_title = _t('sub.import_export.feed_list', $feed->name());
$this->view->type = 'feed/' . $feed->id();
- $this->view->entriesRaw = $this->entryDAO->listWhereRaw(
- 'f', $feed->id(), FreshRSS_Entry::STATE_ALL, 'ASC',
- $maxFeedEntries
- );
+ $this->view->entriesId = $this->entryDAO->listIdsWhere($type, $feed->id(), FreshRSS_Entry::STATE_ALL, 'ASC', $maxFeedEntries);
+ $this->view->entryIdsTagNames = $tagDAO->getEntryIdsTagNames($this->view->entriesId);
+ //The following is a streamable query, i.e. must be last
+ $this->view->entriesRaw = $this->entryDAO->listWhereRaw($type, $feed->id(), FreshRSS_Entry::STATE_ALL, 'ASC', $maxFeedEntries);
$this->view->feed = $feed;
}
diff --git a/app/Models/Auth.php b/app/Models/Auth.php
index 9c3e31952..513a9cb2f 100644
--- a/app/Models/Auth.php
+++ b/app/Models/Auth.php
@@ -28,13 +28,13 @@ class FreshRSS_Auth {
if (self::$login_ok) {
self::giveAccess();
- } elseif (self::accessControl()) {
- self::giveAccess();
+ } elseif (self::accessControl() && self::giveAccess()) {
FreshRSS_UserDAO::touch();
} else {
// Be sure all accesses are removed!
self::removeAccess();
}
+ return self::$login_ok;
}
/**
@@ -60,7 +60,7 @@ class FreshRSS_Auth {
return $current_user != '';
case 'http_auth':
$current_user = httpAuthUser();
- $login_ok = $current_user != '';
+ $login_ok = $current_user != '' && FreshRSS_UserDAO::exists($current_user);
if ($login_ok) {
Minz_Session::_param('currentUser', $current_user);
}
@@ -81,7 +81,7 @@ class FreshRSS_Auth {
$user_conf = get_user_configuration($current_user);
if ($user_conf == null) {
self::$login_ok = false;
- return;
+ return false;
}
$system_conf = Minz_Configuration::get('system');
@@ -102,6 +102,7 @@ class FreshRSS_Auth {
Minz_Session::_param('loginOk', self::$login_ok);
Minz_Session::_param('REMOTE_USER', httpAuthUser());
+ return self::$login_ok;
}
/**
diff --git a/app/Models/Entry.php b/app/Models/Entry.php
index 985276734..f2f3d08fe 100644
--- a/app/Models/Entry.php
+++ b/app/Models/Entry.php
@@ -209,6 +209,7 @@ class FreshRSS_Entry extends Minz_Model {
$feed_timeout = empty($attributes['timeout']) ? 0 : intval($attributes['timeout']);
if ($system_conf->simplepie_syslog_enabled) {
+ prepareSyslog();
syslog(LOG_INFO, 'FreshRSS GET ' . SimplePie_Misc::url_remove_credentials($url));
}
diff --git a/app/Models/EntryDAO.php b/app/Models/EntryDAO.php
index 6d77a33cd..08927196e 100644
--- a/app/Models/EntryDAO.php
+++ b/app/Models/EntryDAO.php
@@ -839,6 +839,9 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
$where .= 'f.priority >= ' . FreshRSS_Feed::PRIORITY_NORMAL . ' ';
$where .= 'AND e.is_favorite=1 ';
break;
+ case 'S': //Starred
+ $where .= 'e.is_favorite=1 ';
+ break;
case 'c': //Category
$where .= 'f.priority >= ' . FreshRSS_Feed::PRIORITY_NORMAL . ' ';
$where .= 'AND f.category=? ';
@@ -855,6 +858,9 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
case 'T': //Any tag
$where .= '1=1 ';
break;
+ case 'ST': //Starred or tagged
+ $where .= 'e.is_favorite=1 OR EXISTS (SELECT et2.id_tag FROM `' . $this->prefix . 'entrytag` et2 WHERE et2.id_entry = e.id) ';
+ break;
default:
throw new FreshRSS_EntriesGetter_Exception('Bad type in Entry->listByType: [' . $type . ']!');
}
diff --git a/app/Models/FeedDAO.php b/app/Models/FeedDAO.php
index 7f00642f4..c9c9f6301 100644
--- a/app/Models/FeedDAO.php
+++ b/app/Models/FeedDAO.php
@@ -61,7 +61,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
$valuesTmp['lastUpdate'],
base64_encode($valuesTmp['httpAuth']),
FreshRSS_Feed::KEEP_HISTORY_DEFAULT,
- FreshRSS_Feed::TTL_DEFAULT,
+ isset($valuesTmp['ttl']) ? intval($valuesTmp['ttl']) : FreshRSS_Feed::TTL_DEFAULT,
isset($valuesTmp['attributes']) ? json_encode($valuesTmp['attributes']) : '',
);
@@ -95,6 +95,9 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
'httpAuth' => $feed->httpAuth(),
'attributes' => $feed->attributes(),
);
+ if ($feed->mute() || $feed->ttl() != FreshRSS_Context::$user_conf->ttl_default) {
+ $values['ttl'] = $feed->ttl() * ($feed->mute() ? -1 : 1);
+ }
$id = $this->addFeed($values);
if ($id) {
diff --git a/app/Models/TagDAO.php b/app/Models/TagDAO.php
index b55d2b35d..dba854aa4 100644
--- a/app/Models/TagDAO.php
+++ b/app/Models/TagDAO.php
@@ -265,8 +265,18 @@ class FreshRSS_TagDAO extends Minz_ModelPdo implements FreshRSS_Searchable {
$values = array();
if (is_array($entries) && count($entries) > 0) {
$sql .= ' AND et.id_entry IN (' . str_repeat('?,', count($entries) - 1). '?)';
- foreach ($entries as $entry) {
- $values[] = is_array($entry) ? $entry['id'] : $entry->id();
+ if (is_array($entries[0])) {
+ foreach ($entries as $entry) {
+ $values[] = $entry['id'];
+ }
+ } elseif (is_object($entries[0])) {
+ foreach ($entries as $entry) {
+ $values[] = $entry->id();
+ }
+ } else {
+ foreach ($entries as $entry) {
+ $values[] = $entry;
+ }
}
}
$stm = $this->bd->prepare($sql);
diff --git a/app/Models/UserDAO.php b/app/Models/UserDAO.php
index 5fb46c947..e9d3a7329 100644
--- a/app/Models/UserDAO.php
+++ b/app/Models/UserDAO.php
@@ -65,7 +65,7 @@ class FreshRSS_UserDAO extends Minz_ModelPdo {
require_once(APP_PATH . '/SQL/install.sql.' . $db['type'] . '.php');
if ($db['type'] === 'sqlite') {
- return unlink(join_path(DATA_PATH, 'users', $username, 'db.sqlite'));
+ return unlink(USERS_PATH . '/' . $username . '/db.sqlite');
} else {
$userPDO = new Minz_ModelPdo($username);
@@ -81,18 +81,18 @@ class FreshRSS_UserDAO extends Minz_ModelPdo {
}
}
- public static function exist($username) {
- return is_dir(join_path(DATA_PATH, 'users', $username));
+ public static function exists($username) {
+ return is_dir(USERS_PATH . '/' . $username);
}
public static function touch($username = '') {
if (!FreshRSS_user_Controller::checkUsername($username)) {
$username = Minz_Session::param('currentUser', '_');
}
- return touch(join_path(DATA_PATH, 'users', $username, 'config.php'));
+ return touch(USERS_PATH . '/' . $username . '/config.php');
}
public static function mtime($username) {
- return @filemtime(join_path(DATA_PATH, 'users', $username, 'config.php'));
+ return @filemtime(USERS_PATH . '/' . $username . '/config.php');
}
}
diff --git a/app/actualize_script.php b/app/actualize_script.php
index ba9660a14..f1dec5640 100755
--- a/app/actualize_script.php
+++ b/app/actualize_script.php
@@ -12,6 +12,9 @@ if (defined('STDOUT')) {
fwrite(STDOUT, 'Starting feed actualization at ' . $begin_date->format('c') . "\n"); //Unbuffered
}
+prepareSyslog();
+syslog(LOG_INFO, 'FreshRSS Start feeds actualization...');
+
// Set the header params ($_GET) to call the FRSS application.
$_GET['c'] = 'feed';
$_GET['a'] = 'actualize';
@@ -64,7 +67,7 @@ foreach ($users as $user) {
if (!invalidateHttpCache()) {
Minz_Log::warning('FreshRSS write access problem in ' . join_path(USERS_PATH, $user, 'log.txt'), ADMIN_LOG);
if (defined('STDERR')) {
- fwrite(STDERR, 'Write access problem in ' . join_path(USERS_PATH, $user, 'log.txt') . "\n");
+ fwrite(STDERR, 'FreshRSS write access problem in ' . join_path(USERS_PATH, $user, 'log.txt') . "\n");
}
}
}
@@ -75,7 +78,8 @@ if (defined('STDOUT')) {
$end_date = date_create('now');
$duration = date_diff($end_date, $begin_date);
fwrite(STDOUT, 'Ending feed actualization at ' . $end_date->format('c') . "\n"); //Unbuffered
- fwrite(STDOUT, 'Feed actualizations took ' . $duration->format('%a day(s), %h hour(s), %i minute(s) and %s seconds') . ' for ' . count($users) . " users\n"); //Unbuffered
+ fwrite(STDOUT, 'Feed actualizations took ' . $duration->format('%a day(s), %h hour(s), %i minute(s) and %s seconds') . ' for ' . count($users) . " users\n"); //Unbuffered
}
echo 'End.', "\n";
ob_end_flush();
+syslog(LOG_INFO, 'FreshRSS feeds actualization done.');
diff --git a/app/i18n/cz/sub.php b/app/i18n/cz/sub.php
index ad02f6f49..5b5634fed 100644
--- a/app/i18n/cz/sub.php
+++ b/app/i18n/cz/sub.php
@@ -72,6 +72,7 @@ return array(
'export' => 'Export',
'export_opml' => 'Exportovat seznam kanálů (OPML)',
'export_starred' => 'Exportovat oblíbené',
+ 'export_labelled' => 'Export your labelled articles', //TODO
'feed_list' => 'Seznam %s článků',
'file_to_import' => 'Soubor k importu<br />(OPML, JSON nebo ZIP)',
'file_to_import_no_zip' => 'Soubor k importu<br />(OPML nebo JSON)',
diff --git a/app/i18n/de/sub.php b/app/i18n/de/sub.php
index aa408e8c7..27e893177 100644
--- a/app/i18n/de/sub.php
+++ b/app/i18n/de/sub.php
@@ -72,6 +72,7 @@ return array(
'export' => 'Exportieren',
'export_opml' => 'Liste der Feeds exportieren (OPML)',
'export_starred' => 'Ihre Favoriten exportieren',
+ 'export_labelled' => 'Export your labelled articles', //TODO
'feed_list' => 'Liste von %s Artikeln',
'file_to_import' => 'Zu importierende Datei<br />(OPML, JSON oder ZIP)',
'file_to_import_no_zip' => 'Zu importierende Datei<br />(OPML oder JSON)',
diff --git a/app/i18n/en/sub.php b/app/i18n/en/sub.php
index 9acbcbf33..4efd81ba4 100644
--- a/app/i18n/en/sub.php
+++ b/app/i18n/en/sub.php
@@ -72,6 +72,7 @@ return array(
'export' => 'Export',
'export_opml' => 'Export list of feeds (OPML)',
'export_starred' => 'Export your favourites',
+ 'export_labelled' => 'Export your labelled articles',
'feed_list' => 'List of %s articles',
'file_to_import' => 'File to import<br />(OPML, JSON or ZIP)',
'file_to_import_no_zip' => 'File to import<br />(OPML or JSON)',
diff --git a/app/i18n/es/sub.php b/app/i18n/es/sub.php
index 64e420dc1..854984891 100755
--- a/app/i18n/es/sub.php
+++ b/app/i18n/es/sub.php
@@ -72,6 +72,7 @@ return array(
'export' => 'Exportar',
'export_opml' => 'Exportar la lista de fuentes (OPML)',
'export_starred' => 'Exportar tus favoritos',
+ 'export_labelled' => 'Export your labelled articles', //TODO
'feed_list' => 'Lista de %s artículos',
'file_to_import' => 'Archivo a importar<br />(OPML, JSON o ZIP)',
'file_to_import_no_zip' => 'Archivo a importar<br />(OPML o JSON)',
diff --git a/app/i18n/fr/sub.php b/app/i18n/fr/sub.php
index 6cb31414d..d9964ac6e 100644
--- a/app/i18n/fr/sub.php
+++ b/app/i18n/fr/sub.php
@@ -72,6 +72,7 @@ return array(
'export' => 'Exporter',
'export_opml' => 'Exporter la liste des flux (OPML)',
'export_starred' => 'Exporter les favoris',
+ 'export_labelled' => 'Exporter les articles étiquetés',
'feed_list' => 'Liste des articles de %s',
'file_to_import' => 'Fichier à importer<br />(OPML, JSON ou ZIP)',
'file_to_import_no_zip' => 'Fichier à importer<br />(OPML ou JSON)',
diff --git a/app/i18n/he/sub.php b/app/i18n/he/sub.php
index e4c487b84..6d824e349 100644
--- a/app/i18n/he/sub.php
+++ b/app/i18n/he/sub.php
@@ -72,6 +72,7 @@ return array(
'export' => 'ייצוא',
'export_opml' => 'ייצוא רשימת הזנות (OPML)',
'export_starred' => 'ייצוא מועדפים',
+ 'export_labelled' => 'Export your labelled articles', //TODO
'feed_list' => 'רשימה של %s מאמרים',
'file_to_import' => 'קובץ לייבוא<br />(OPML, Json or Zip)',
'file_to_import_no_zip' => 'קובץ לייבוא<br />(OPML or Json)',
diff --git a/app/i18n/it/sub.php b/app/i18n/it/sub.php
index 6faa48d63..ff7fa6f1d 100644
--- a/app/i18n/it/sub.php
+++ b/app/i18n/it/sub.php
@@ -72,6 +72,7 @@ return array(
'export' => 'Esporta',
'export_opml' => 'Esporta tutta la lista dei feed (OPML)',
'export_starred' => 'Esporta i tuoi preferiti',
+ 'export_labelled' => 'Export your labelled articles', //TODO
'feed_list' => 'Elenco di %s articoli',
'file_to_import' => 'File da importare<br />(OPML, JSON o ZIP)',
'file_to_import_no_zip' => 'File da importare<br />(OPML o JSON)',
diff --git a/app/i18n/kr/sub.php b/app/i18n/kr/sub.php
index 463496c57..9f8967053 100644
--- a/app/i18n/kr/sub.php
+++ b/app/i18n/kr/sub.php
@@ -72,6 +72,7 @@ return array(
'export' => '내보내기',
'export_opml' => '피드 목록 내보내기 (OPML)',
'export_starred' => '즐겨찾기 내보내기',
+ 'export_labelled' => 'Export your labelled articles', //TODO
'feed_list' => '%s 개의 글 목록',
'file_to_import' => '불러올 파일<br />(OPML, JSON 또는 ZIP)',
'file_to_import_no_zip' => '불러올 파일<br />(OPML 또는 JSON)',
diff --git a/app/i18n/nl/admin.php b/app/i18n/nl/admin.php
index 8a63b885b..c6fd1dc9e 100644
--- a/app/i18n/nl/admin.php
+++ b/app/i18n/nl/admin.php
@@ -163,8 +163,8 @@ return array(
'max-categories' => 'Categoriën limiet per gebruiker',
'max-feeds' => 'Feed limiet per gebruiker',
'cookie-duration' => array(
- 'help' => 'in seconds', // @todo translate
- 'number' => 'Duration to keep logged in', // @todo translate
+ 'help' => 'in seconden',
+ 'number' => 'Tijdsduur om ingelogd te blijven',
),
'registration' => array(
'help' => '0 betekent geen account limiet',
diff --git a/app/i18n/nl/conf.php b/app/i18n/nl/conf.php
index ba21fc889..8e6a59d56 100644
--- a/app/i18n/nl/conf.php
+++ b/app/i18n/nl/conf.php
@@ -162,7 +162,7 @@ return array(
'mark_read' => 'Markeer als gelezen',
'navigation' => 'Navigatie',
'navigation_help' => 'Met de "Shift" toets, kunt u navigatie verwijzingen voor feeds gebruiken.<br/>Met de "Alt" toets, kunt u navigatie verwijzingen voor categoriën gebruiken.',
- 'navigation_no_mod_help' => 'The following navigation shortcuts do not support modifiers.', //TODO - Translation
+ 'navigation_no_mod_help' => 'De volgende navigatiesnelkoppelingen ondersteunen geen besturingstoetsen.',
'next_article' => 'Spring naar volgende artikel',
'normal_view' => 'Schakel naar gewoon aanzicht',
'other_action' => 'Andere acties',
@@ -171,8 +171,8 @@ return array(
'rss_view' => 'Open RSS-aanzicht in een nieuwe tab',
'see_on_website' => 'Bekijk op originale website',
'shift_for_all_read' => '+ <code>shift</code> om alle artikelen als gelezen te markeren',
- 'skip_next_article' => 'Focus next without opening', //TODO - Translation
- 'skip_previous_article' => 'Focus previous without opening', //TODO - Translation
+ 'skip_next_article' => 'Volgend artikel focusen zonder openen',
+ 'skip_previous_article' => 'Vorig artikel focusen zonder openen',
'title' => 'Verwijzingen',
'user_filter' => 'Toegang gebruikers filters',
'user_filter_help' => 'Als er slechts één gebruikersfilter is, dan wordt die gebruikt. Anders zijn ze toegankelijk met hun nummer.',
diff --git a/app/i18n/nl/index.php b/app/i18n/nl/index.php
index c2b550647..d202b812a 100644
--- a/app/i18n/nl/index.php
+++ b/app/i18n/nl/index.php
@@ -53,11 +53,11 @@ return array(
'starred' => 'Laat alleen favorieten zien',
'stats' => 'Statistieken',
'subscription' => 'Abonnementen beheer',
- 'tags' => 'My labels', //TODO - Translation
+ 'tags' => 'Mijn labels',
'unread' => 'Laat alleen ongelezen zien',
),
'share' => 'Delen',
'tag' => array(
- 'related' => 'Verwante labels', //TODO - Translation
+ 'related' => 'Verwante labels',
),
);
diff --git a/app/i18n/nl/sub.php b/app/i18n/nl/sub.php
index 36c96b53f..1d6c9f806 100644
--- a/app/i18n/nl/sub.php
+++ b/app/i18n/nl/sub.php
@@ -27,7 +27,7 @@ return array(
'password' => 'HTTP wachtwoord',
'username' => 'HTTP gebruikers naam',
),
- 'clear_cache' => 'Always clear cache', //TODO - Translation
+ 'clear_cache' => 'Cache altijd leegmaken',
'css_help' => 'Haalt verstoorde RSS feeds op (attentie, heeft meer tijd nodig!)',
'css_path' => 'Artikelen CSS pad op originele website',
'description' => 'Omschrijving',
@@ -47,11 +47,11 @@ return array(
),
'websub' => 'Directe notificaties met WebSub',
'show' => array(
- 'all' => 'Show all feeds', //TODO - Translation
- 'error' => 'Show only feeds with error', //TODO - Translation
+ 'all' => 'Alle feeds tonen',
+ 'error' => 'Alleen feeds met een foutmelding tonen',
),
'showing' => array(
- 'error' => 'Showing only feeds with error', //TODO - Translation
+ 'error' => 'Alleen feeds met een foutmelding worden getoond',
),
'ssl_verify' => 'SSL-veiligheid controleren',
'stats' => 'Statistieken',
@@ -72,6 +72,7 @@ return array(
'export' => 'Exporteer',
'export_opml' => 'Exporteer lijst van feeds (OPML)',
'export_starred' => 'Exporteer je favorieten',
+ 'export_labelled' => 'Exporteer gelabelde artikels',
'feed_list' => 'Lijst van %s artikelen',
'file_to_import' => 'Bestand om te importeren<br />(OPML, JSON of ZIP)',
'file_to_import_no_zip' => 'Bestand om te importeren<br />(OPML of JSON)',
diff --git a/app/i18n/oc/conf.php b/app/i18n/oc/conf.php
index 346f796e1..ad52691da 100644
--- a/app/i18n/oc/conf.php
+++ b/app/i18n/oc/conf.php
@@ -94,14 +94,14 @@ return array(
'display_articles_unfolded' => 'Mostrar los articles desplegats per defaut',
'display_categories_unfolded' => 'Mostrar las categorias plegadas per defaut',
'hide_read_feeds' => 'Rescondre las categorias & fluxes sens articles pas legits (fonciona pas amb la configuracion « Mostrar totes los articles »)',
- 'img_with_lazyload' => 'Utilizar lo mòde “cargament tardiu” per las imatges',
+ 'img_with_lazyload' => 'Utilizar lo mòde “cargament tardiu” pels imatges',
'jump_next' => 'sautar al vesin venent pas legit (flux o categoria)',
'mark_updated_article_unread' => 'Marcar los articles actualizats coma pas legits',
'number_divided_when_reader' => 'Devisat per 2 dins la vista de lectura.',
'read' => array(
'article_open_on_website' => 'quand l’article es dobèrt sul site d’origina',
'article_viewed' => 'quand l’article es mostrat',
- 'scroll' => 'en davalant la pagina',
+ 'scroll' => 'en davalar la pagina',
'upon_reception' => 'en recebre un article novèl',
'when' => 'Marcar un article coma legit…',
),
diff --git a/app/i18n/oc/gen.php b/app/i18n/oc/gen.php
index ffe10941d..168ea4732 100644
--- a/app/i18n/oc/gen.php
+++ b/app/i18n/oc/gen.php
@@ -43,29 +43,29 @@ return array(
),
),
'date' => array(
- 'Apr' => 'a\b\r\i\a\l',
+ 'Apr' => '\\a\\b\\r\\i\\a\\l',
'apr' => 'abr.',
'april' => 'abrial',
- 'Aug' => 'a\g\o\s\t',
+ 'Aug' => '\\a\\g\\o\\s\\t',
'aug' => 'agost',
'august' => 'agost',
'before_yesterday' => 'Abans ièr',
- 'Dec' => '\d\e\c\e\m\b\r\e',
+ 'Dec' => '\\d\\e\\c\\e\\m\\b\\r\\e',
'dec' => 'dec.',
'december' => 'decembre',
- 'Feb' => 'f\e\b\r\i\è\r',
+ 'Feb' => '\\f\\e\\b\\r\\i\\è\\r',
'feb' => 'feb.',
'february' => 'febrièr',
- 'format_date' => 'j %s \de\ Y',
- 'format_date_hour' => 'j %s \de\ Y \a H\:i',
+ 'format_date' => 'j \\d\\e %s \\d\\e Y',
+ 'format_date_hour' => 'j \\d\\e %s \\d\\e Y \\a H\:i',
'fri' => 'dv',
- 'Jan' => 'g\e\n\i\è\r',
+ 'Jan' => '\\g\\e\\n\\i\\è\\r',
'jan' => 'gen.',
'january' => 'genièr',
- 'Jul' => 'j\u\l\h\e\t',
+ 'Jul' => '\\j\\u\\l\\h\\e\\t',
'jul' => 'julh',
'july' => 'julhet',
- 'Jun' => 'j\u\n\h',
+ 'Jun' => '\\j\\u\\n\\h',
'jun' => 'junh',
'june' => 'junh',
'last_3_month' => 'Dempuèi los tres darrièrs meses',
@@ -73,22 +73,22 @@ return array(
'last_month' => 'Dempuèi lo mes passat',
'last_week' => 'Dempuèi la setmana passada',
'last_year' => 'Dempuèi l’annada passada',
- 'Mar' => 'm\a\r\ç',
+ 'Mar' => '\\m\\a\\r\\ç',
'mar' => 'març',
'march' => 'març',
- 'May' => '\m\a\i',
+ 'May' => '\\m\\a\\i',
'may' => 'mai',
'may_' => 'mai',
'mon' => 'dl',
'month' => 'meses',
- 'Nov' => '\n\o\v\e\m\b\r\e',
+ 'Nov' => '\\n\\o\\v\\e\\m\\b\\r\\e',
'nov' => 'nov.',
'november' => 'novembre',
- 'Oct' => '\o\c\t\ò\b\r\e',
+ 'Oct' => '\\o\\c\\t\\ò\\b\\r\\e',
'oct' => 'oct.',
'october' => 'octòbre',
'sat' => 'ds',
- 'Sep' => '\s\e\t\e\m\b\r\e',
+ 'Sep' => '\\s\\e\\t\\e\\m\\b\\r\\e',
'sep' => 'set.',
'september' => 'setembre',
'sun' => 'dg',
@@ -111,7 +111,7 @@ return array(
'request_failed' => 'Una requèsta a fach meuca, aquò pòt venir d’un problèma de connexion Internet.',
'title_new_articles' => 'FreshRSS : nòus articles !',
),
- 'new_article' => 'I a d’articles nòus disponibles, clicatz per actualizar la página.',
+ 'new_article' => 'I a d’articles nòus disponibles, clicatz per actualizar la pagina.',
'should_be_activated' => 'JavaScript deu èsser activat',
),
'lang' => array(
@@ -183,7 +183,7 @@ return array(
'short' => array(
'attention' => 'Atencion !',
'blank_to_disable' => 'Daissar void per desactivar',
- 'by_author' => 'Per <em>%s</em>',
+ 'by_author' => 'Per : ',
'by_default' => 'Per defaut',
'damn' => 'Zut !',
'default_category' => 'Pas triat',
diff --git a/app/i18n/oc/sub.php b/app/i18n/oc/sub.php
index f9ddf339a..fc5a0cc1f 100644
--- a/app/i18n/oc/sub.php
+++ b/app/i18n/oc/sub.php
@@ -1,7 +1,7 @@
<?php
return array(
'api' => array(
- 'documentation' => 'Copiar l’URL seguenta per l’utilizaire dins d’una aisina extèrna.',
+ 'documentation' => 'Copiatz l’URL seguenta per l’utilizaire dins d’una aisina extèrna.',
'title' => 'API',
),
'bookmarklet' => array(
@@ -46,11 +46,11 @@ return array(
),
'websub' => 'Notificaciones instantáneas amb WebSub',
'show' => array(
- 'all' => 'Show all feeds', //TODO - Translation
- 'error' => 'Show only feeds with error', //TODO - Translation
+ 'all' => 'Mostrar totes los fluxes',
+ 'error' => 'Mostrar pas que los fluxes amb errors',
),
'showing' => array(
- 'error' => 'Showing only feeds with error', //TODO - Translation
+ 'error' => 'Afichatge dels articles amb errors solament',
),
'ssl_verify' => 'Verificacion de la seguretat SSL',
'stats' => 'Estatisticas',
@@ -64,13 +64,14 @@ return array(
'website' => 'URL del site',
),
'firefox' => array(
- 'documentation' => 'Seguir las etapas descrichas <a href="https://developer.mozilla.org/en-US/Firefox/Releases/2/Adding_feed_readers_to_Firefox#Adding_a_new_feed_reader_manually">aquí</a> per ajustar FreshRSS a la lista dels lectors de flux de Firefox.',
+ 'documentation' => 'Seguissètz las etapas descrichas <a href="https://developer.mozilla.org/en-US/Firefox/Releases/2/Adding_feed_readers_to_Firefox#Adding_a_new_feed_reader_manually">aquí</a> per ajustar FreshRSS a la lista dels lectors de flux de Firefox.',
'title' => 'Lector de flux de Firefox',
),
'import_export' => array(
'export' => 'Exportar',
'export_opml' => 'Exportar la lista de fluxes (OPML)',
'export_starred' => 'Exportar los favorits',
+ 'export_labelled' => 'Exportar los articles etiquetats',
'feed_list' => 'Lista dels %s articles',
'file_to_import' => 'Fichièr d’importar<br />(OPML, JSON o ZIP)',
'file_to_import_no_zip' => 'Fichièr d’importar<br />(OPML o JSON)',
@@ -86,7 +87,7 @@ return array(
'subscription_tools' => 'Aisinas d’abonament',
),
'title' => array(
- '_' => 'Gestión dels abonaments',
+ '_' => 'Gestion dels abonaments',
'feed_management' => 'Gestion dels fluxes RSS',
'subscription_tools' => 'Aisinas d’abonament',
),
diff --git a/app/i18n/pt-br/sub.php b/app/i18n/pt-br/sub.php
index 78684c14c..58b2fc1f9 100644
--- a/app/i18n/pt-br/sub.php
+++ b/app/i18n/pt-br/sub.php
@@ -68,6 +68,7 @@ return array(
'export' => 'Exportar',
'export_opml' => 'Exporta a lista dos feeds (OPML)',
'export_starred' => 'Exportar seus favoritos',
+ 'export_labelled' => 'Export your labelled articles', //TODO
'feed_list' => 'Lista dos %s artigos',
'file_to_import' => 'Arquivo para importar<br />(OPML, JSON or ZIP)',
'file_to_import_no_zip' => 'Arquivo para importar<br />(OPML or JSON)',
diff --git a/app/i18n/ru/sub.php b/app/i18n/ru/sub.php
index 7de80586b..62f8a8e3a 100644
--- a/app/i18n/ru/sub.php
+++ b/app/i18n/ru/sub.php
@@ -72,6 +72,7 @@ return array(
'export' => 'Export', //TODO - Translation
'export_opml' => 'Export list of feeds (OPML)', //TODO - Translation
'export_starred' => 'Export your favourites', //TODO - Translation
+ 'export_labelled' => 'Export your labelled articles', //TODO
'feed_list' => 'List of %s articles', //TODO - Translation
'file_to_import' => 'File to import<br />(OPML, JSON or ZIP)', //TODO - Translation
'file_to_import_no_zip' => 'File to import<br />(OPML or JSON)', //TODO - Translation
diff --git a/app/i18n/tr/sub.php b/app/i18n/tr/sub.php
index b5b56f4b8..7f29633be 100644
--- a/app/i18n/tr/sub.php
+++ b/app/i18n/tr/sub.php
@@ -72,6 +72,7 @@ return array(
'export' => 'Dışa aktar',
'export_opml' => 'Akış listesini dışarı aktar (OPML)',
'export_starred' => 'Favorileri dışarı aktar',
+ 'export_labelled' => 'Export your labelled articles', //TODO
'feed_list' => '%s makalenin listesi',
'file_to_import' => 'Dosyadan içe aktar<br />(OPML, JSON or ZIP)',
'file_to_import_no_zip' => 'Dosyadan içe aktar<br />(OPML or JSON)',
diff --git a/app/i18n/zh-cn/sub.php b/app/i18n/zh-cn/sub.php
index e1c176bc6..3a9623468 100644
--- a/app/i18n/zh-cn/sub.php
+++ b/app/i18n/zh-cn/sub.php
@@ -72,6 +72,7 @@ return array(
'export' => '导出',
'export_opml' => '导出 RSS 源列表 (OPML)',
'export_starred' => '导出你的收藏',
+ 'export_labelled' => 'Export your labelled articles', //TODO
'feed_list' => '%s 文章列表',
'file_to_import' => '需要导入的文件<br />(OPML, JSON 或 ZIP)',
'file_to_import_no_zip' => '需要导入的文件<br />(OPML 或 JSON)',
diff --git a/app/install.php b/app/install.php
index dc79c2388..b15cc76ea 100644
--- a/app/install.php
+++ b/app/install.php
@@ -7,7 +7,8 @@ header("Content-Security-Policy: default-src 'self'");
require(LIB_PATH . '/lib_install.php');
session_name('FreshRSS');
-session_set_cookie_params(0, dirname(empty($_SERVER['REQUEST_URI']) ? '/' : dirname($_SERVER['REQUEST_URI'])), null, false, true);
+$forwardedPrefix = empty($_SERVER['HTTP_X_FORWARDED_PREFIX']) ? '' : rtrim($_SERVER['HTTP_X_FORWARDED_PREFIX'], '/ ');
+session_set_cookie_params(0, $forwardedPrefix . dirname(empty($_SERVER['REQUEST_URI']) ? '/' : dirname($_SERVER['REQUEST_URI'])), null, false, true);
session_start();
if (isset($_GET['step'])) {
diff --git a/app/layout/header.phtml b/app/layout/header.phtml
index 6b538851b..410ac1ff0 100644
--- a/app/layout/header.phtml
+++ b/app/layout/header.phtml
@@ -16,7 +16,7 @@ if (FreshRSS_Auth::accessNeedsAction()) {
<div class="item title">
<h1>
<a href="<?php echo _url('index', 'index'); ?>">
- <img class="logo" src="<?php echo _i('icon', true); ?>" alt="⊚" />
+ <img class="logo" src="<?php echo _i('icon', true); ?>" alt="" />
<?php echo FreshRSS_Context::$system_conf->title; ?>
</a>
</h1>
diff --git a/app/views/configure/display.phtml b/app/views/configure/display.phtml
index c6c08e3bc..58c4e219a 100644
--- a/app/views/configure/display.phtml
+++ b/app/views/configure/display.phtml
@@ -72,7 +72,7 @@
</div>
<div class="form-group">
- <label class="group-name" for="theme"><?php echo _t('conf.display.icon.entry'); ?></label>
+ <label class="group-name"><?php echo _t('conf.display.icon.entry'); ?></label>
<table>
<thead>
<tr>
diff --git a/app/views/helpers/export/articles.phtml b/app/views/helpers/export/articles.phtml
index 59a2c7ad7..2d1fcd133 100644
--- a/app/views/helpers/export/articles.phtml
+++ b/app/views/helpers/export/articles.phtml
@@ -16,14 +16,12 @@ $articles = array(
echo rtrim(json_encode($articles, $options), " ]}\n\r\t"), "\n";
$first = true;
-$tagDAO = FreshRSS_Factory::createTagDao();
-$entryIdsTagNames = $tagDAO->getEntryIdsTagNames($this->entriesRaw);
-if ($entryIdsTagNames == false) {
- $entryIdsTagNames = array();
+if (empty($this->entryIdsTagNames)) {
+ $this->entryIdsTagNames = array();
}
foreach ($this->entriesRaw as $entryRaw) {
- if (empty($entryRaw)) {
+ if ($entryRaw == null) {
continue;
}
$entry = FreshRSS_EntryDAO::daoToEntry($entryRaw);
@@ -58,10 +56,11 @@ foreach ($this->entriesRaw as $entryRaw) {
'feedUrl' => $feed == null ? '' : $feed->url(),
)
);
+ $article['categories'][] = $entry->isRead() ? 'user/-/state/com.google/read' : 'user/-/state/com.google/unread';
if ($entry->isFavorite()) {
$article['categories'][] = 'user/-/state/com.google/starred';
}
- $tagNames = isset($entryIdsTagNames['e_' . $entry->id()]) ? $entryIdsTagNames['e_' . $entry->id()] : array();
+ $tagNames = isset($this->entryIdsTagNames['e_' . $entry->id()]) ? $this->entryIdsTagNames['e_' . $entry->id()] : array();
foreach ($tagNames as $tagName) {
$article['categories'][] = 'user/-/label/' . $tagName;
}
diff --git a/app/views/importExport/index.phtml b/app/views/importExport/index.phtml
index c5049e3ea..139e715c5 100644
--- a/app/views/importExport/index.phtml
+++ b/app/views/importExport/index.phtml
@@ -33,6 +33,11 @@
<?php echo _t('sub.import_export.export_opml'); ?>
</label>
+ <label class="checkbox" for="export_labelled">
+ <input type="checkbox" name="export_labelled" id="export_labelled" value="1" <?php echo extension_loaded('zip') ? 'checked="checked"' : ''; ?> />
+ <?php echo _t('sub.import_export.export_labelled'); ?>
+ </label>
+
<label class="checkbox" for="export_starred">
<input type="checkbox" name="export_starred" id="export_starred" value="1" <?php echo extension_loaded('zip') ? 'checked="checked"' : ''; ?> />
<?php echo _t('sub.import_export.export_starred'); ?>