mirror of
https://github.com/FreshRSS/FreshRSS.git
synced 2026-04-02 13:46:09 -04:00
Merge branch 'dev' into beta
This commit is contained in:
49
CHANGELOG
49
CHANGELOG
@@ -1,5 +1,54 @@
|
||||
# Journal des modifications
|
||||
|
||||
## 2014-06-13 FreshRSS 0.7.2
|
||||
|
||||
* API compatible with Google Reader API level 2
|
||||
* FreshRSS can now be used from e.g.:
|
||||
* (Android) News+ https://play.google.com/store/apps/details?id=com.noinnion.android.newsplus.extension.google_reader
|
||||
* (Android) EasyRSS https://github.com/Alkarex/EasyRSS
|
||||
* Basic support for audio and video podcasts
|
||||
* Searching
|
||||
* New search filters date: and pubdate: accepting ISO 8601 date intervals such as `date:2013-2014` or `pubdate:P1W`
|
||||
* Possibility to combine search filters, e.g. `date:2014-05 intitle:FreshRSS intitle:Open great reader #Internet`
|
||||
* Change nav menu with more buttons instead of dropdown menus and add some filters
|
||||
* New system of import / export
|
||||
* Support OPML, Json (like Google Reader) and Zip archives
|
||||
* Can export and import articles (specific option for favorites)
|
||||
* Refactor "Origine" theme
|
||||
* Some improvements
|
||||
* Based on a template file (other themes will use it too)
|
||||
|
||||
|
||||
## 2014-02-19 FreshRSS 0.7.1
|
||||
|
||||
* Mise à jour des flux plus rapide grâce à une meilleure utilisation du cache
|
||||
* Utilisation d’une signature MD5 du contenu intéressant pour les flux n’implémentant pas les requêtes conditionnelles
|
||||
* Modification des raccourcis
|
||||
* "s" partage directement si un seul moyen de partage
|
||||
* Moyens de partage accessibles par "1", "2", "3", etc.
|
||||
* Premier article : Home ; Dernier article : End
|
||||
* Ajout du déplacement au sein des catégories / flux (via modificateurs shift et alt)
|
||||
* UI
|
||||
* Séparation des descriptions des raccourcis par groupes
|
||||
* Revue rapide de la page de connexion
|
||||
* Amélioration de l'affichage des notifications sur mobile
|
||||
* Revue du système de rafraîchissement des flux
|
||||
* Meilleure gestion de la file de flux à rafraîchir en JSON
|
||||
* Rafraîchissement uniquement pour les flux non rafraîchis récemment
|
||||
* Possibilité donnée aux anonymes de rafraîchir les flux
|
||||
* SimplePie
|
||||
* Mise à jour de la lib
|
||||
* Corrige fuite de mémoire
|
||||
* Meilleure tolérance aux flux invalides
|
||||
* Corrections divers
|
||||
* Ne déplie plus l'article lors du clic sur l'icône lien externe
|
||||
* Ne boucle plus à la fin de la navigation dans les articles
|
||||
* Suppression du champ category.color inutile
|
||||
* Corrige bug redirection infinie (Persona)
|
||||
* Amélioration vérification de la requête POST
|
||||
* Ajout d'un verrou lorsqu'une action mark_read ou mark_favorite est en cours
|
||||
|
||||
|
||||
## 2014-01-29 FreshRSS 0.7
|
||||
|
||||
* Nouveau mode multi-utilisateur
|
||||
|
||||
19
README.md
19
README.md
@@ -8,12 +8,19 @@ Il permet de gérer plusieurs utilisateurs, et dispose d’un mode de lecture an
|
||||
* Site officiel : http://freshrss.org
|
||||
* Démo : http://demo.freshrss.org/
|
||||
* Développeur : Marien Fressinaud <dev@marienfressinaud.fr>
|
||||
* Version actuelle : 0.7
|
||||
* Date de publication 2014-01-29
|
||||
* Version actuelle : 0.8-dev
|
||||
* Date de publication 2014-0x-xx
|
||||
* License [GNU AGPL 3](http://www.gnu.org/licenses/agpl-3.0.html)
|
||||
|
||||

|
||||
|
||||
# Note sur les branches
|
||||
**Ce logiciel est encore en développement !** Veuillez vous assurer d'utiliser la branche qui vous correspond :
|
||||
|
||||
* Utilisez [la branche master](https://github.com/marienfressinaud/FreshRSS/tree/master/) si vous visez la stabilité.
|
||||
* [La branche beta](https://github.com/marienfressinaud/FreshRSS/tree/beta) est celle par défaut : les nouveautés y sont ajoutées environ tous les mois.
|
||||
* Pour les développeurs et ceux qui savent ce qu'ils font, [la branche dev](https://github.com/marienfressinaud/FreshRSS/tree/dev) vous ouvre les bras !
|
||||
|
||||
# Disclaimer
|
||||
Cette application a été développée pour s’adapter à des besoins personnels et non professionnels.
|
||||
Je ne garantis en aucun cas la sécurité de celle-ci, ni son bon fonctionnement.
|
||||
@@ -25,9 +32,9 @@ Privilégiez pour cela des demandes sur GitHub
|
||||
* Serveur modeste, par exemple sous Linux ou Windows
|
||||
* Fonctionne même sur un Raspberry Pi avec des temps de réponse < 1s (testé sur 150 flux, 22k articles, soit 32Mo de données partiellement compressées)
|
||||
* Serveur Web Apache2 ou Nginx (non testé sur les autres)
|
||||
* PHP 5.2+ (PHP 5.3.7+ recommandé)
|
||||
* PHP 5.2.1+ (PHP 5.3.7+ recommandé)
|
||||
* Requis : [PDO_MySQL](http://php.net/pdo-mysql), [cURL](http://php.net/curl), [LibXML](http://php.net/xml), [PCRE](http://php.net/pcre), [ctype](http://php.net/ctype)
|
||||
* Recommandés : [JSON](http://php.net/json), [zlib](http://php.net/zlib), [mbstring](http://php.net/mbstring), [iconv](http://php.net/iconv)
|
||||
* Recommandés : [JSON](http://php.net/json), [zlib](http://php.net/zlib), [mbstring](http://php.net/mbstring), [iconv](http://php.net/iconv), [Zip](http://php.net/zip)
|
||||
* MySQL 5.0.3+ (ou SQLite 3.7.4+ à venir)
|
||||
* Un navigateur Web récent tel Firefox 4+, Chrome, Opera, Safari, Internet Explorer 9+
|
||||
* Fonctionne aussi sur mobile
|
||||
@@ -42,7 +49,8 @@ Privilégiez pour cela des demandes sur GitHub
|
||||
5. Tout devrait fonctionner :) En cas de problème, n’hésitez pas à me contacter.
|
||||
|
||||
# Contrôle d’accès
|
||||
Il est requis pour le mode multi-utilisateur, et recommandé dans tous les cas, de limiter l’accès à votre FreshRSS :
|
||||
Il est requis pour le mode multi-utilisateur, et recommandé dans tous les cas, de limiter l’accès à votre FreshRSS. Au choix :
|
||||
* En utilisant l’identification par formulaire (requiert JavaScript, et PHP 5.3.7+ recommandé – fonctionne avec certaines versions de PHP 5.3.3+)
|
||||
* En utilisant l’identification par [Mozilla Persona](https://login.persona.org/about) incluse dans FreshRSS
|
||||
* En utilisant un contrôle d’accès HTTP défini par votre serveur Web
|
||||
* Voir par exemple la [documentation d’Apache sur l’authentification](http://httpd.apache.org/docs/trunk/howto/auth.html)
|
||||
@@ -80,6 +88,7 @@ mysqldump -u utilisateur -p --databases freshrss > freshrss.sql
|
||||
* [php-http-304](http://alexandre.alapetite.fr/doc-alex/php-http-304/)
|
||||
* [jQuery](http://jquery.com/)
|
||||
* [keyboard_shortcuts](http://www.openjs.com/scripts/events/keyboard_shortcuts/)
|
||||
* [flotr2](http://www.humblesoftware.com/flotr2)
|
||||
|
||||
## Uniquement pour certaines options
|
||||
* [bcrypt.js](https://github.com/dcodeIO/bcrypt.js)
|
||||
|
||||
@@ -29,7 +29,6 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
|
||||
$cat = new FreshRSS_Category ($name);
|
||||
$values = array (
|
||||
'name' => $cat->name (),
|
||||
'color' => $cat->color ()
|
||||
);
|
||||
$catDAO->updateCategory ($ids[$key], $values);
|
||||
} elseif ($ids[$key] != $defaultId) {
|
||||
@@ -43,10 +42,9 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
|
||||
$values = array (
|
||||
'id' => $cat->id (),
|
||||
'name' => $cat->name (),
|
||||
'color' => $cat->color ()
|
||||
);
|
||||
|
||||
if ($catDAO->searchByName ($newCat) == false) {
|
||||
if ($catDAO->searchByName ($newCat) == null) {
|
||||
$catDAO->addCategory ($values);
|
||||
}
|
||||
}
|
||||
@@ -64,7 +62,6 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
|
||||
$this->view->categories = $catDAO->listCategories (false);
|
||||
$this->view->defaultCategory = $catDAO->getDefault ();
|
||||
$this->view->feeds = $feedDAO->listFeeds ();
|
||||
$this->view->flux = false;
|
||||
|
||||
Minz_View::prependTitle (Minz_Translate::t ('categories_management') . ' · ');
|
||||
}
|
||||
@@ -116,7 +113,7 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
|
||||
|
||||
if ($feedDAO->updateFeed ($id, $values)) {
|
||||
$this->view->flux->_category ($cat);
|
||||
|
||||
$this->view->flux->faviconPrepare();
|
||||
$notif = array (
|
||||
'type' => 'good',
|
||||
'content' => Minz_Translate::t ('feed_updated')
|
||||
@@ -143,25 +140,12 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
|
||||
public function displayAction () {
|
||||
if (Minz_Request::isPost()) {
|
||||
$this->view->conf->_language(Minz_Request::param('language', 'en'));
|
||||
$this->view->conf->_posts_per_page(Minz_Request::param('posts_per_page', 10));
|
||||
$this->view->conf->_view_mode(Minz_Request::param('view_mode', 'normal'));
|
||||
$this->view->conf->_default_view (Minz_Request::param('default_view', 'a'));
|
||||
$this->view->conf->_auto_load_more(Minz_Request::param('auto_load_more', false));
|
||||
$this->view->conf->_display_posts(Minz_Request::param('display_posts', false));
|
||||
$this->view->conf->_onread_jump_next(Minz_Request::param('onread_jump_next', false));
|
||||
$this->view->conf->_lazyload (Minz_Request::param('lazyload', false));
|
||||
$this->view->conf->_sort_order(Minz_Request::param('sort_order', 'DESC'));
|
||||
$this->view->conf->_mark_when (array(
|
||||
'article' => Minz_Request::param('mark_open_article', false),
|
||||
'site' => Minz_Request::param('mark_open_site', false),
|
||||
'scroll' => Minz_Request::param('mark_scroll', false),
|
||||
'reception' => Minz_Request::param('mark_upon_reception', false),
|
||||
));
|
||||
$themeId = Minz_Request::param('theme', '');
|
||||
if ($themeId == '') {
|
||||
$themeId = FreshRSS_Themes::defaultTheme;
|
||||
}
|
||||
$this->view->conf->_theme($themeId);
|
||||
$this->view->conf->_content_width(Minz_Request::param('content_width', 'thin'));
|
||||
$this->view->conf->_topline_read(Minz_Request::param('topline_read', false));
|
||||
$this->view->conf->_topline_favorite(Minz_Request::param('topline_favorite', false));
|
||||
$this->view->conf->_topline_date(Minz_Request::param('topline_date', false));
|
||||
@@ -189,21 +173,48 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
|
||||
|
||||
$this->view->themes = FreshRSS_Themes::get();
|
||||
|
||||
Minz_View::prependTitle (Minz_Translate::t ('display_configuration') . ' · ');
|
||||
}
|
||||
|
||||
public function readingAction () {
|
||||
if (Minz_Request::isPost()) {
|
||||
$this->view->conf->_posts_per_page(Minz_Request::param('posts_per_page', 10));
|
||||
$this->view->conf->_view_mode(Minz_Request::param('view_mode', 'normal'));
|
||||
$this->view->conf->_default_view (Minz_Request::param('default_view', 'a'));
|
||||
$this->view->conf->_auto_load_more(Minz_Request::param('auto_load_more', false));
|
||||
$this->view->conf->_display_posts(Minz_Request::param('display_posts', false));
|
||||
$this->view->conf->_onread_jump_next(Minz_Request::param('onread_jump_next', false));
|
||||
$this->view->conf->_lazyload (Minz_Request::param('lazyload', false));
|
||||
$this->view->conf->_sticky_post (Minz_Request::param('sticky_post', false));
|
||||
$this->view->conf->_sort_order(Minz_Request::param('sort_order', 'DESC'));
|
||||
$this->view->conf->_mark_when (array(
|
||||
'article' => Minz_Request::param('mark_open_article', false),
|
||||
'site' => Minz_Request::param('mark_open_site', false),
|
||||
'scroll' => Minz_Request::param('mark_scroll', false),
|
||||
'reception' => Minz_Request::param('mark_upon_reception', false),
|
||||
));
|
||||
$this->view->conf->save();
|
||||
|
||||
Minz_Session::_param ('language', $this->view->conf->language);
|
||||
Minz_Translate::reset ();
|
||||
invalidateHttpCache();
|
||||
|
||||
$notif = array (
|
||||
'type' => 'good',
|
||||
'content' => Minz_Translate::t ('configuration_updated')
|
||||
);
|
||||
Minz_Session::_param ('notification', $notif);
|
||||
|
||||
Minz_Request::forward (array ('c' => 'configure', 'a' => 'reading'), true);
|
||||
}
|
||||
|
||||
Minz_View::prependTitle (Minz_Translate::t ('reading_configuration') . ' · ');
|
||||
}
|
||||
|
||||
public function sharingAction () {
|
||||
if (Minz_Request::isPost ()) {
|
||||
$this->view->conf->_sharing (array(
|
||||
'shaarli' => Minz_Request::param ('shaarli', false),
|
||||
'wallabag' => Minz_Request::param ('wallabag', false),
|
||||
'diaspora' => Minz_Request::param ('diaspora', false),
|
||||
'twitter' => Minz_Request::param ('twitter', false),
|
||||
'g+' => Minz_Request::param ('g+', false),
|
||||
'facebook' => Minz_Request::param ('facebook', false),
|
||||
'email' => Minz_Request::param ('email', false),
|
||||
'print' => Minz_Request::param ('print', false),
|
||||
));
|
||||
$params = Minz_Request::params();
|
||||
$this->view->conf->_sharing ($params['share']);
|
||||
$this->view->conf->save();
|
||||
invalidateHttpCache();
|
||||
|
||||
@@ -219,74 +230,9 @@ class FreshRSS_configure_Controller extends Minz_ActionController {
|
||||
Minz_View::prependTitle (Minz_Translate::t ('sharing') . ' · ');
|
||||
}
|
||||
|
||||
public function importExportAction () {
|
||||
require_once(LIB_PATH . '/lib_opml.php');
|
||||
$catDAO = new FreshRSS_CategoryDAO ();
|
||||
$this->view->categories = $catDAO->listCategories ();
|
||||
|
||||
$this->view->req = Minz_Request::param ('q');
|
||||
|
||||
if ($this->view->req == 'export') {
|
||||
Minz_View::_title ('freshrss_feeds.opml');
|
||||
|
||||
$this->view->_useLayout (false);
|
||||
header('Content-Type: application/xml; charset=utf-8');
|
||||
header('Content-disposition: attachment; filename=freshrss_feeds.opml');
|
||||
|
||||
$feedDAO = new FreshRSS_FeedDAO ();
|
||||
$catDAO = new FreshRSS_CategoryDAO ();
|
||||
|
||||
$list = array ();
|
||||
foreach ($catDAO->listCategories () as $key => $cat) {
|
||||
$list[$key]['name'] = $cat->name ();
|
||||
$list[$key]['feeds'] = $feedDAO->listByCategory ($cat->id ());
|
||||
}
|
||||
|
||||
$this->view->categories = $list;
|
||||
} elseif ($this->view->req == 'import' && Minz_Request::isPost ()) {
|
||||
if ($_FILES['file']['error'] == 0) {
|
||||
invalidateHttpCache();
|
||||
// on parse le fichier OPML pour récupérer les catégories et les flux associés
|
||||
try {
|
||||
list ($categories, $feeds) = opml_import (
|
||||
file_get_contents ($_FILES['file']['tmp_name'])
|
||||
);
|
||||
|
||||
// On redirige vers le controller feed qui va se charger d'insérer les flux en BDD
|
||||
// les flux sont mis au préalable dans des variables de Request
|
||||
Minz_Request::_param ('q', 'null');
|
||||
Minz_Request::_param ('categories', $categories);
|
||||
Minz_Request::_param ('feeds', $feeds);
|
||||
Minz_Request::forward (array ('c' => 'feed', 'a' => 'massiveImport'));
|
||||
} catch (FreshRSS_Opml_Exception $e) {
|
||||
Minz_Log::record ($e->getMessage (), Minz_Log::WARNING);
|
||||
|
||||
$notif = array (
|
||||
'type' => 'bad',
|
||||
'content' => Minz_Translate::t ('bad_opml_file')
|
||||
);
|
||||
Minz_Session::_param ('notification', $notif);
|
||||
|
||||
Minz_Request::forward (array (
|
||||
'c' => 'configure',
|
||||
'a' => 'importExport'
|
||||
), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$feedDAO = new FreshRSS_FeedDAO ();
|
||||
$this->view->feeds = $feedDAO->listFeeds ();
|
||||
|
||||
// au niveau de la vue, permet de ne pas voir un flux sélectionné dans la liste
|
||||
$this->view->flux = false;
|
||||
|
||||
Minz_View::prependTitle (Minz_Translate::t ('import_export_opml') . ' · ');
|
||||
}
|
||||
|
||||
public function shortcutAction () {
|
||||
$list_keys = array ('a', 'b', 'backspace', 'c', 'd', 'delete', 'down', 'e', 'end', 'enter',
|
||||
'escape', 'f', 'g', 'h', 'i', 'insert', 'j', 'k', 'l', 'left',
|
||||
'escape', 'f', 'g', 'h', 'home', 'i', 'insert', 'j', 'k', 'l', 'left',
|
||||
'm', 'n', 'o', 'p', 'page_down', 'page_up', 'q', 'r', 'return', 'right',
|
||||
's', 'space', 't', 'tab', 'u', 'up', 'v', 'w', 'x', 'y',
|
||||
'z', '0', '1', '2', '3', '4', '5', '6', '7', '8',
|
||||
|
||||
@@ -100,6 +100,9 @@ class FreshRSS_entry_Controller extends Minz_ActionController {
|
||||
$entryDAO = new FreshRSS_EntryDAO();
|
||||
$entryDAO->optimizeTable();
|
||||
|
||||
$feedDAO = new FreshRSS_FeedDAO();
|
||||
$feedDAO->updateCachedValues();
|
||||
|
||||
invalidateHttpCache();
|
||||
|
||||
$notif = array (
|
||||
@@ -137,11 +140,13 @@ class FreshRSS_entry_Controller extends Minz_ActionController {
|
||||
if ($nb > 0) {
|
||||
$nbTotal += $nb;
|
||||
Minz_Log::record($nb . ' old entries cleaned in feed [' . $feed->url() . ']', Minz_Log::DEBUG);
|
||||
$feedDAO->updateLastUpdate($feed->id());
|
||||
//$feedDAO->updateLastUpdate($feed->id());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$feedDAO->updateCachedValues();
|
||||
|
||||
invalidateHttpCache();
|
||||
|
||||
$notif = array(
|
||||
|
||||
@@ -3,28 +3,51 @@
|
||||
class FreshRSS_feed_Controller extends Minz_ActionController {
|
||||
public function firstAction () {
|
||||
if (!$this->view->loginOk) {
|
||||
$token = $this->view->conf->token; //TODO: check the token logic again, and if it is still needed
|
||||
// Token is useful in the case that anonymous refresh is forbidden
|
||||
// and CRON task cannot be used with php command so the user can
|
||||
// set a CRON task to refresh his feeds by using token inside url
|
||||
$token = $this->view->conf->token;
|
||||
$token_param = Minz_Request::param ('token', '');
|
||||
$token_is_ok = ($token != '' && $token == $token_param);
|
||||
$action = Minz_Request::actionName ();
|
||||
if (!($token_is_ok && $action === 'actualize')) {
|
||||
if (!(($token_is_ok || Minz_Configuration::allowAnonymousRefresh()) &&
|
||||
$action === 'actualize')
|
||||
) {
|
||||
Minz_Error::error (
|
||||
403,
|
||||
array ('error' => array (Minz_Translate::t ('access_denied')))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$this->catDAO = new FreshRSS_CategoryDAO ();
|
||||
$this->catDAO->checkDefault ();
|
||||
}
|
||||
|
||||
public function addAction () {
|
||||
@set_time_limit(300);
|
||||
$url = Minz_Request::param('url_rss', false);
|
||||
|
||||
if ($url === false) {
|
||||
Minz_Request::forward(array(
|
||||
'c' => 'configure',
|
||||
'a' => 'feed'
|
||||
), true);
|
||||
}
|
||||
|
||||
$feedDAO = new FreshRSS_FeedDAO ();
|
||||
$this->catDAO = new FreshRSS_CategoryDAO ();
|
||||
$this->catDAO->checkDefault ();
|
||||
|
||||
if (Minz_Request::isPost()) {
|
||||
@set_time_limit(300);
|
||||
|
||||
|
||||
if (Minz_Request::isPost ()) {
|
||||
$url = Minz_Request::param ('url_rss');
|
||||
$cat = Minz_Request::param ('category', false);
|
||||
if ($cat === 'nc') {
|
||||
$new_cat = Minz_Request::param ('new_category');
|
||||
if (empty($new_cat['name'])) {
|
||||
$cat = false;
|
||||
} else {
|
||||
$cat = $this->catDAO->addCategory($new_cat);
|
||||
}
|
||||
}
|
||||
if ($cat === false) {
|
||||
$def_cat = $this->catDAO->getDefault ();
|
||||
$cat = $def_cat->id ();
|
||||
@@ -47,7 +70,6 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
|
||||
|
||||
$feed->load(true);
|
||||
|
||||
$feedDAO = new FreshRSS_FeedDAO ();
|
||||
$values = array (
|
||||
'url' => $feed->url (),
|
||||
'category' => $feed->category (),
|
||||
@@ -123,7 +145,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
|
||||
Minz_Log::record ($e->getMessage (), Minz_Log::WARNING);
|
||||
$notif = array (
|
||||
'type' => 'bad',
|
||||
'content' => Minz_Translate::t ('internal_problem_feed')
|
||||
'content' => Minz_Translate::t ('internal_problem_feed', Minz_Url::display(array('a' => 'logs')))
|
||||
);
|
||||
Minz_Session::_param ('notification', $notif);
|
||||
} catch (Minz_FileNotExistException $e) {
|
||||
@@ -131,7 +153,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
|
||||
Minz_Log::record ($e->getMessage (), Minz_Log::ERROR);
|
||||
$notif = array (
|
||||
'type' => 'bad',
|
||||
'content' => Minz_Translate::t ('internal_problem_feed')
|
||||
'content' => Minz_Translate::t ('internal_problem_feed', Minz_Url::display(array('a' => 'logs')))
|
||||
);
|
||||
Minz_Session::_param ('notification', $notif);
|
||||
}
|
||||
@@ -141,6 +163,38 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
|
||||
|
||||
Minz_Request::forward (array ('c' => 'configure', 'a' => 'feed', 'params' => $params), true);
|
||||
}
|
||||
|
||||
// GET request so we must ask confirmation to user
|
||||
Minz_View::prependTitle(Minz_Translate::t('add_rss_feed') . ' · ');
|
||||
$this->view->categories = $this->catDAO->listCategories();
|
||||
$this->view->feed = new FreshRSS_Feed($url);
|
||||
try {
|
||||
// We try to get some more information about the feed
|
||||
$this->view->feed->load(true);
|
||||
$this->view->load_ok = true;
|
||||
} catch (Exception $e) {
|
||||
$this->view->load_ok = false;
|
||||
}
|
||||
|
||||
$feed = $feedDAO->searchByUrl($this->view->feed->url());
|
||||
if ($feed) {
|
||||
// Already subscribe so we redirect to the feed configuration page
|
||||
$notif = array(
|
||||
'type' => 'bad',
|
||||
'content' => Minz_Translate::t(
|
||||
'already_subscribed', $feed->name()
|
||||
)
|
||||
);
|
||||
Minz_Session::_param('notification', $notif);
|
||||
|
||||
Minz_Request::forward(array(
|
||||
'c' => 'configure',
|
||||
'a' => 'feed',
|
||||
'params' => array(
|
||||
'id' => $feed->id()
|
||||
)
|
||||
), true);
|
||||
}
|
||||
}
|
||||
|
||||
public function truncateAction () {
|
||||
@@ -189,38 +243,51 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
|
||||
$flux_update = 0;
|
||||
$is_read = $this->view->conf->mark_when['reception'] ? 1 : 0;
|
||||
foreach ($feeds as $feed) {
|
||||
if (!$feed->lock()) {
|
||||
Minz_Log::record('Feed already being actualized: ' . $feed->url(), Minz_Log::NOTICE);
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
$url = $feed->url();
|
||||
$feedHistory = $feed->keepHistory();
|
||||
|
||||
$feed->load(false);
|
||||
$entries = array_reverse($feed->entries()); //We want chronological order and SimplePie uses reverse order
|
||||
$hasTransaction = false;
|
||||
|
||||
//For this feed, check last n entry GUIDs already in database
|
||||
$existingGuids = array_fill_keys ($entryDAO->listLastGuidsByFeed ($feed->id (), count($entries) + 10), 1);
|
||||
$useDeclaredDate = empty($existingGuids);
|
||||
if (count($entries) > 0) {
|
||||
//For this feed, check last n entry GUIDs already in database
|
||||
$existingGuids = array_fill_keys ($entryDAO->listLastGuidsByFeed ($feed->id (), count($entries) + 10), 1);
|
||||
$useDeclaredDate = empty($existingGuids);
|
||||
|
||||
$feedHistory = $feed->keepHistory();
|
||||
if ($feedHistory == -2) { //default
|
||||
$feedHistory = $this->view->conf->keep_history_default;
|
||||
}
|
||||
if ($feedHistory == -2) { //default
|
||||
$feedHistory = $this->view->conf->keep_history_default;
|
||||
}
|
||||
|
||||
// On ne vérifie pas strictement que l'article n'est pas déjà en BDD
|
||||
// La BDD refusera l'ajout car (id_feed, guid) doit être unique
|
||||
$feedDAO->beginTransaction ();
|
||||
foreach ($entries as $entry) {
|
||||
$eDate = $entry->date (true);
|
||||
if ((!isset ($existingGuids[$entry->guid ()])) &&
|
||||
(($feedHistory != 0) || ($eDate >= $date_min))) {
|
||||
$values = $entry->toArray ();
|
||||
//Use declared date at first import, otherwise use discovery date
|
||||
$values['id'] = ($useDeclaredDate || $eDate < $date_min) ?
|
||||
min(time(), $eDate) . uSecString() :
|
||||
uTimeString();
|
||||
$values['is_read'] = $is_read;
|
||||
$entryDAO->addEntry ($values);
|
||||
$hasTransaction = true;
|
||||
$feedDAO->beginTransaction();
|
||||
|
||||
// On ne vérifie pas strictement que l'article n'est pas déjà en BDD
|
||||
// La BDD refusera l'ajout car (id_feed, guid) doit être unique
|
||||
foreach ($entries as $entry) {
|
||||
$eDate = $entry->date (true);
|
||||
if ((!isset ($existingGuids[$entry->guid ()])) &&
|
||||
(($feedHistory != 0) || ($eDate >= $date_min))) {
|
||||
$values = $entry->toArray ();
|
||||
//Use declared date at first import, otherwise use discovery date
|
||||
$values['id'] = ($useDeclaredDate || $eDate < $date_min) ?
|
||||
min(time(), $eDate) . uSecString() :
|
||||
uTimeString();
|
||||
$values['is_read'] = $is_read;
|
||||
$entryDAO->addEntry ($values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (($feedHistory >= 0) && (rand(0, 30) === 1)) {
|
||||
if (!$hasTransaction) {
|
||||
$feedDAO->beginTransaction();
|
||||
}
|
||||
$nb = $feedDAO->cleanOldEntries ($feed->id (), $date_min, max($feedHistory, count($entries) + 10));
|
||||
if ($nb > 0) {
|
||||
Minz_Log::record ($nb . ' old entries cleaned in feed [' . $feed->url() . ']', Minz_Log::DEBUG);
|
||||
@@ -228,18 +295,23 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
|
||||
}
|
||||
|
||||
// on indique que le flux vient d'être mis à jour en BDD
|
||||
$feedDAO->updateLastUpdate ($feed->id ());
|
||||
$feedDAO->commit ();
|
||||
$feedDAO->updateLastUpdate ($feed->id (), 0, $hasTransaction);
|
||||
if ($hasTransaction) {
|
||||
$feedDAO->commit();
|
||||
}
|
||||
$flux_update++;
|
||||
if ($feed->url() !== $url) { //URL has changed (auto-discovery)
|
||||
$feedDAO->updateFeed($feed->id(), array('url' => $feed->url()));
|
||||
}
|
||||
$feed->faviconPrepare();
|
||||
} catch (FreshRSS_Feed_Exception $e) {
|
||||
Minz_Log::record ($e->getMessage (), Minz_Log::NOTICE);
|
||||
$feedDAO->updateLastUpdate ($feed->id (), 1);
|
||||
}
|
||||
|
||||
$feed->faviconPrepare();
|
||||
$feed->unlock();
|
||||
unset($feed);
|
||||
|
||||
// On arrête à 10 flux pour ne pas surcharger le serveur
|
||||
// sauf si le paramètre $force est à vrai
|
||||
$i++;
|
||||
@@ -251,6 +323,7 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
|
||||
$url = array ();
|
||||
if ($flux_update === 1) {
|
||||
// on a mis un seul flux à jour
|
||||
$feed = reset ($feeds);
|
||||
$notif = array (
|
||||
'type' => 'good',
|
||||
'content' => Minz_Translate::t ('feed_actualized', $feed->name ())
|
||||
@@ -264,8 +337,8 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
|
||||
} else {
|
||||
// aucun flux n'a été mis à jour, oups
|
||||
$notif = array (
|
||||
'type' => 'bad',
|
||||
'content' => Minz_Translate::t ('no_feed_actualized')
|
||||
'type' => 'good',
|
||||
'content' => Minz_Translate::t ('no_feed_to_refresh')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -295,77 +368,6 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
|
||||
}
|
||||
}
|
||||
|
||||
public function massiveImportAction () {
|
||||
@set_time_limit(300);
|
||||
|
||||
$entryDAO = new FreshRSS_EntryDAO ();
|
||||
$feedDAO = new FreshRSS_FeedDAO ();
|
||||
|
||||
$categories = Minz_Request::param ('categories', array (), true);
|
||||
$feeds = Minz_Request::param ('feeds', array (), true);
|
||||
|
||||
// on ajoute les catégories en masse dans une fonction à part
|
||||
$this->addCategories ($categories);
|
||||
|
||||
// on calcule la date des articles les plus anciens qu'on accepte
|
||||
$nb_month_old = $this->view->conf->old_entries;
|
||||
$date_min = time () - (3600 * 24 * 30 * $nb_month_old);
|
||||
|
||||
// la variable $error permet de savoir si une erreur est survenue
|
||||
// Le but est de ne pas arrêter l'import même en cas d'erreur
|
||||
// L'utilisateur sera mis au courant s'il y a eu des erreurs, mais
|
||||
// ne connaîtra pas les détails. Ceux-ci seront toutefois logguées
|
||||
$error = false;
|
||||
$i = 0;
|
||||
foreach ($feeds as $feed) {
|
||||
try {
|
||||
$values = array (
|
||||
'id' => $feed->id (),
|
||||
'url' => $feed->url (),
|
||||
'category' => $feed->category (),
|
||||
'name' => $feed->name (),
|
||||
'website' => $feed->website (),
|
||||
'description' => $feed->description (),
|
||||
'lastUpdate' => 0,
|
||||
'httpAuth' => $feed->httpAuth ()
|
||||
);
|
||||
|
||||
// ajout du flux que s'il n'est pas déjà en BDD
|
||||
if (!$feedDAO->searchByUrl ($values['url'])) {
|
||||
$id = $feedDAO->addFeed ($values);
|
||||
if ($id) {
|
||||
$feed->_id ($id);
|
||||
$feed->faviconPrepare();
|
||||
} else {
|
||||
$error = true;
|
||||
}
|
||||
}
|
||||
} catch (FreshRSS_Feed_Exception $e) {
|
||||
$error = true;
|
||||
Minz_Log::record ($e->getMessage (), Minz_Log::WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
if ($error) {
|
||||
$res = Minz_Translate::t ('feeds_imported_with_errors');
|
||||
} else {
|
||||
$res = Minz_Translate::t ('feeds_imported');
|
||||
}
|
||||
|
||||
$notif = array (
|
||||
'type' => 'good',
|
||||
'content' => $res
|
||||
);
|
||||
Minz_Session::_param ('notification', $notif);
|
||||
Minz_Session::_param ('actualize_feeds', true);
|
||||
|
||||
// et on redirige vers la page d'accueil
|
||||
Minz_Request::forward (array (
|
||||
'c' => 'index',
|
||||
'a' => 'index'
|
||||
), true);
|
||||
}
|
||||
|
||||
public function deleteAction () {
|
||||
if (Minz_Request::isPost ()) {
|
||||
$type = Minz_Request::param ('type', 'feed');
|
||||
@@ -409,17 +411,4 @@ class FreshRSS_feed_Controller extends Minz_ActionController {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function addCategories ($categories) {
|
||||
foreach ($categories as $cat) {
|
||||
if (!$this->catDAO->searchByName ($cat->name ())) {
|
||||
$values = array (
|
||||
'id' => $cat->id (),
|
||||
'name' => $cat->name (),
|
||||
'color' => $cat->color ()
|
||||
);
|
||||
$catDAO->addCategory ($values);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
390
app/Controllers/importExportController.php
Normal file
390
app/Controllers/importExportController.php
Normal file
@@ -0,0 +1,390 @@
|
||||
<?php
|
||||
|
||||
class FreshRSS_importExport_Controller extends Minz_ActionController {
|
||||
public function firstAction() {
|
||||
if (!$this->view->loginOk) {
|
||||
Minz_Error::error(
|
||||
403,
|
||||
array('error' => array(Minz_Translate::t('access_denied')))
|
||||
);
|
||||
}
|
||||
|
||||
require_once(LIB_PATH . '/lib_opml.php');
|
||||
|
||||
$this->catDAO = new FreshRSS_CategoryDAO();
|
||||
$this->entryDAO = new FreshRSS_EntryDAO();
|
||||
$this->feedDAO = new FreshRSS_FeedDAO();
|
||||
}
|
||||
|
||||
public function indexAction() {
|
||||
$this->view->categories = $this->catDAO->listCategories();
|
||||
$this->view->feeds = $this->feedDAO->listFeeds();
|
||||
|
||||
Minz_View::prependTitle(Minz_Translate::t('import_export') . ' · ');
|
||||
}
|
||||
|
||||
public function importAction() {
|
||||
if (Minz_Request::isPost() && $_FILES['file']['error'] == 0) {
|
||||
@set_time_limit(300);
|
||||
|
||||
$file = $_FILES['file'];
|
||||
$type_file = $this->guessFileType($file['name']);
|
||||
|
||||
$list_files = array(
|
||||
'opml' => array(),
|
||||
'json_starred' => array(),
|
||||
'json_feed' => array()
|
||||
);
|
||||
|
||||
// We try to list all files according to their type
|
||||
// A zip file is first opened and then its files are listed
|
||||
$list = array();
|
||||
if ($type_file === 'zip') {
|
||||
$zip = zip_open($file['tmp_name']);
|
||||
|
||||
while (($zipfile = zip_read($zip)) !== false) {
|
||||
$type_zipfile = $this->guessFileType(
|
||||
zip_entry_name($zipfile)
|
||||
);
|
||||
|
||||
if ($type_file !== 'unknown') {
|
||||
$list_files[$type_zipfile][] = zip_entry_read(
|
||||
$zipfile,
|
||||
zip_entry_filesize($zipfile)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
zip_close($zip);
|
||||
} elseif ($type_file !== 'unknown') {
|
||||
$list_files[$type_file][] = file_get_contents(
|
||||
$file['tmp_name']
|
||||
);
|
||||
}
|
||||
|
||||
// Import different files.
|
||||
// OPML first(so categories and feeds are imported)
|
||||
// Starred articles then so the "favourite" status is already set
|
||||
// And finally all other files.
|
||||
$error = false;
|
||||
foreach ($list_files['opml'] as $opml_file) {
|
||||
$error = $this->importOpml($opml_file);
|
||||
}
|
||||
foreach ($list_files['json_starred'] as $article_file) {
|
||||
$error = $this->importArticles($article_file, true);
|
||||
}
|
||||
foreach ($list_files['json_feed'] as $article_file) {
|
||||
$error = $this->importArticles($article_file);
|
||||
}
|
||||
|
||||
// And finally, we get import status and redirect to the home page
|
||||
$notif = null;
|
||||
if ($error === true) {
|
||||
$content_notif = Minz_Translate::t(
|
||||
'feeds_imported_with_errors'
|
||||
);
|
||||
} else {
|
||||
$content_notif = Minz_Translate::t(
|
||||
'feeds_imported'
|
||||
);
|
||||
}
|
||||
|
||||
Minz_Session::_param('notification', array(
|
||||
'type' => 'good',
|
||||
'content' => $content_notif
|
||||
));
|
||||
Minz_Session::_param('actualize_feeds', true);
|
||||
|
||||
Minz_Request::forward(array(
|
||||
'c' => 'index',
|
||||
'a' => 'index'
|
||||
), true);
|
||||
}
|
||||
|
||||
// What are you doing? you have to call this controller
|
||||
// with a POST request!
|
||||
Minz_Request::forward(array(
|
||||
'c' => 'importExport',
|
||||
'a' => 'index'
|
||||
));
|
||||
}
|
||||
|
||||
private function guessFileType($filename) {
|
||||
// A *very* basic guess file type function. Only based on filename
|
||||
// That's could be improved but should be enough, at least for a first
|
||||
// implementation.
|
||||
// TODO: improve this function?
|
||||
|
||||
if (substr_compare($filename, '.zip', -4) === 0) {
|
||||
return 'zip';
|
||||
} elseif (substr_compare($filename, '.opml', -5) === 0 ||
|
||||
substr_compare($filename, '.xml', -4) === 0) {
|
||||
return 'opml';
|
||||
} elseif (strcmp($filename, 'starred.json') === 0) {
|
||||
return 'json_starred';
|
||||
} elseif (substr_compare($filename, '.json', -5) === 0 &&
|
||||
strpos($filename, 'feed_') === 0) {
|
||||
return 'json_feed';
|
||||
} else {
|
||||
return 'unknown';
|
||||
}
|
||||
}
|
||||
|
||||
private function importOpml($opml_file) {
|
||||
$opml_array = array();
|
||||
try {
|
||||
$opml_array = libopml_parse_string($opml_file);
|
||||
} catch (LibOPML_Exception $e) {
|
||||
Minz_Log::warning($e->getMessage());
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->catDAO->checkDefault();
|
||||
|
||||
return $this->addOpmlElements($opml_array['body']);
|
||||
}
|
||||
|
||||
private function addOpmlElements($opml_elements, $parent_cat = null) {
|
||||
$error = false;
|
||||
foreach ($opml_elements as $elt) {
|
||||
$res = false;
|
||||
if (isset($elt['xmlUrl'])) {
|
||||
$res = $this->addFeedOpml($elt, $parent_cat);
|
||||
} else {
|
||||
$res = $this->addCategoryOpml($elt, $parent_cat);
|
||||
}
|
||||
|
||||
if (!$error && $res) {
|
||||
// oops: there is at least one error!
|
||||
$error = $res;
|
||||
}
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
private function addFeedOpml($feed_elt, $parent_cat) {
|
||||
if (is_null($parent_cat)) {
|
||||
// This feed has no parent category so we get the default one
|
||||
$parent_cat = $this->catDAO->getDefault()->name();
|
||||
}
|
||||
|
||||
$cat = $this->catDAO->searchByName($parent_cat);
|
||||
|
||||
if (!$cat) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// We get different useful information
|
||||
$url = html_chars_utf8($feed_elt['xmlUrl']);
|
||||
$name = html_chars_utf8($feed_elt['text']);
|
||||
$website = '';
|
||||
if (isset($feed_elt['htmlUrl'])) {
|
||||
$website = html_chars_utf8($feed_elt['htmlUrl']);
|
||||
}
|
||||
$description = '';
|
||||
if (isset($feed_elt['description'])) {
|
||||
$description = html_chars_utf8($feed_elt['description']);
|
||||
}
|
||||
|
||||
$error = false;
|
||||
try {
|
||||
// Create a Feed object and add it in DB
|
||||
$feed = new FreshRSS_Feed($url);
|
||||
$feed->_category($cat->id());
|
||||
$feed->_name($name);
|
||||
$feed->_website($website);
|
||||
$feed->_description($description);
|
||||
|
||||
// addFeedObject checks if feed is already in DB so nothing else to
|
||||
// check here
|
||||
$id = $this->feedDAO->addFeedObject($feed);
|
||||
$error = ($id === false);
|
||||
} catch (FreshRSS_Feed_Exception $e) {
|
||||
Minz_Log::warning($e->getMessage());
|
||||
$error = true;
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
private function addCategoryOpml($cat_elt, $parent_cat) {
|
||||
// Create a new Category object
|
||||
$cat = new FreshRSS_Category(html_chars_utf8($cat_elt['text']));
|
||||
|
||||
$id = $this->catDAO->addCategoryObject($cat);
|
||||
$error = ($id === false);
|
||||
|
||||
if (isset($cat_elt['@outlines'])) {
|
||||
// Our cat_elt contains more categories or more feeds, so we
|
||||
// add them recursively.
|
||||
// Note: FreshRSS does not support yet category arborescence
|
||||
$res = $this->addOpmlElements($cat_elt['@outlines'], $cat->name());
|
||||
if (!$error && $res) {
|
||||
$error = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
private function importArticles($article_file, $starred = false) {
|
||||
$article_object = json_decode($article_file, true);
|
||||
if (is_null($article_object)) {
|
||||
Minz_Log::warning('Try to import a non-JSON file');
|
||||
return true;
|
||||
}
|
||||
|
||||
$is_read = $this->view->conf->mark_when['reception'] ? 1 : 0;
|
||||
|
||||
$google_compliant = (
|
||||
strpos($article_object['id'], 'com.google') !== false
|
||||
);
|
||||
|
||||
$error = false;
|
||||
foreach ($article_object['items'] as $item) {
|
||||
$feed = $this->addFeedArticles($item['origin'], $google_compliant);
|
||||
if (is_null($feed)) {
|
||||
$error = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
$author = isset($item['author']) ? $item['author'] : '';
|
||||
$key_content = ($google_compliant && !isset($item['content'])) ?
|
||||
'summary' : 'content';
|
||||
$tags = $item['categories'];
|
||||
if ($google_compliant) {
|
||||
$tags = array_filter($tags, function($var) {
|
||||
return strpos($var, '/state/com.google') === false;
|
||||
});
|
||||
}
|
||||
|
||||
$entry = new FreshRSS_Entry(
|
||||
$feed->id(), $item['id'], $item['title'], $author,
|
||||
$item[$key_content]['content'], $item['alternate'][0]['href'],
|
||||
$item['published'], $is_read, $starred
|
||||
);
|
||||
$entry->_tags($tags);
|
||||
|
||||
$id = $this->entryDAO->addEntryObject(
|
||||
$entry, $this->view->conf, $feed->keepHistory()
|
||||
);
|
||||
|
||||
if (!$error && ($id === false)) {
|
||||
$error = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $error;
|
||||
}
|
||||
|
||||
private function addFeedArticles($origin, $google_compliant) {
|
||||
$default_cat = $this->catDAO->getDefault();
|
||||
|
||||
$return = null;
|
||||
$key = $google_compliant ? 'htmlUrl' : 'feedUrl';
|
||||
$url = $origin[$key];
|
||||
$name = $origin['title'];
|
||||
$website = $origin['htmlUrl'];
|
||||
$error = false;
|
||||
try {
|
||||
// Create a Feed object and add it in DB
|
||||
$feed = new FreshRSS_Feed($url);
|
||||
$feed->_category($default_cat->id());
|
||||
$feed->_name($name);
|
||||
$feed->_website($website);
|
||||
|
||||
// addFeedObject checks if feed is already in DB so nothing else to
|
||||
// check here
|
||||
$id = $this->feedDAO->addFeedObject($feed);
|
||||
|
||||
if ($id !== false) {
|
||||
$feed->_id($id);
|
||||
$return = $feed;
|
||||
}
|
||||
} catch (FreshRSS_Feed_Exception $e) {
|
||||
Minz_Log::warning($e->getMessage());
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
public function exportAction() {
|
||||
if (Minz_Request::isPost()) {
|
||||
$this->view->_useLayout(false);
|
||||
|
||||
$export_opml = Minz_Request::param('export_opml', false);
|
||||
$export_starred = Minz_Request::param('export_starred', false);
|
||||
$export_feeds = Minz_Request::param('export_feeds', false);
|
||||
|
||||
// From https://stackoverflow.com/questions/1061710/php-zip-files-on-the-fly
|
||||
$file = tempnam('tmp', 'zip');
|
||||
$zip = new ZipArchive();
|
||||
$zip->open($file, ZipArchive::OVERWRITE);
|
||||
|
||||
// Stuff with content
|
||||
if ($export_opml) {
|
||||
$zip->addFromString(
|
||||
'feeds.opml', $this->generateOpml()
|
||||
);
|
||||
}
|
||||
if ($export_starred) {
|
||||
$zip->addFromString(
|
||||
'starred.json', $this->generateArticles('starred')
|
||||
);
|
||||
}
|
||||
foreach ($export_feeds as $feed_id) {
|
||||
$feed = $this->feedDAO->searchById($feed_id);
|
||||
$zip->addFromString(
|
||||
'feed_' . $feed->category() . '_' . $feed->id() . '.json',
|
||||
$this->generateArticles('feed', $feed)
|
||||
);
|
||||
}
|
||||
|
||||
// Close and send to user
|
||||
$zip->close();
|
||||
header('Content-Type: application/zip');
|
||||
header('Content-Length: ' . filesize($file));
|
||||
header('Content-Disposition: attachment; filename="freshrss_export.zip"');
|
||||
readfile($file);
|
||||
unlink($file);
|
||||
}
|
||||
}
|
||||
|
||||
private function generateOpml() {
|
||||
$list = array();
|
||||
foreach ($this->catDAO->listCategories() as $key => $cat) {
|
||||
$list[$key]['name'] = $cat->name();
|
||||
$list[$key]['feeds'] = $this->feedDAO->listByCategory($cat->id());
|
||||
}
|
||||
|
||||
$this->view->categories = $list;
|
||||
return $this->view->helperToString('export/opml');
|
||||
}
|
||||
|
||||
private function generateArticles($type, $feed = NULL) {
|
||||
$this->view->categories = $this->catDAO->listCategories();
|
||||
|
||||
if ($type == 'starred') {
|
||||
$this->view->list_title = Minz_Translate::t('starred_list');
|
||||
$this->view->type = 'starred';
|
||||
$unread_fav = $this->entryDAO->countUnreadReadFavorites();
|
||||
$this->view->entries = $this->entryDAO->listWhere(
|
||||
's', '', FreshRSS_Entry::STATE_ALL, 'ASC',
|
||||
$unread_fav['all']
|
||||
);
|
||||
} elseif ($type == 'feed' && !is_null($feed)) {
|
||||
$this->view->list_title = Minz_Translate::t(
|
||||
'feed_list', $feed->name()
|
||||
);
|
||||
$this->view->type = 'feed/' . $feed->id();
|
||||
$this->view->entries = $this->entryDAO->listWhere(
|
||||
'f', $feed->id(), FreshRSS_Entry::STATE_ALL, 'ASC',
|
||||
$this->view->conf->posts_per_page
|
||||
);
|
||||
$this->view->feed = $feed;
|
||||
}
|
||||
|
||||
return $this->view->helperToString('export/articles');
|
||||
}
|
||||
}
|
||||
@@ -5,27 +5,32 @@ class FreshRSS_index_Controller extends Minz_ActionController {
|
||||
|
||||
public function indexAction () {
|
||||
$output = Minz_Request::param ('output');
|
||||
$token = '';
|
||||
$token = $this->view->conf->token;
|
||||
|
||||
// check if user is logged in
|
||||
if (!$this->view->loginOk && !Minz_Configuration::allowAnonymous())
|
||||
{
|
||||
$token = $this->view->conf->token;
|
||||
if (!$this->view->loginOk && !Minz_Configuration::allowAnonymous()) {
|
||||
$token_param = Minz_Request::param ('token', '');
|
||||
$token_is_ok = ($token != '' && $token === $token_param);
|
||||
if (!($output === 'rss' && $token_is_ok)) {
|
||||
if ($output === 'rss' && !$token_is_ok) {
|
||||
Minz_Error::error (
|
||||
403,
|
||||
array ('error' => array (Minz_Translate::t ('access_denied')))
|
||||
);
|
||||
return;
|
||||
} elseif ($output !== 'rss') {
|
||||
// "hard" redirection is not required, just ask dispatcher to
|
||||
// forward to the login form without 302 redirection
|
||||
Minz_Request::forward(array('c' => 'index', 'a' => 'formLogin'));
|
||||
return;
|
||||
}
|
||||
$params['token'] = $token;
|
||||
}
|
||||
|
||||
// construction of RSS url of this feed
|
||||
$params = Minz_Request::params ();
|
||||
$params['output'] = 'rss';
|
||||
if (isset ($params['search'])) {
|
||||
$params['search'] = urlencode ($params['search']);
|
||||
}
|
||||
$this->view->rss_url = array (
|
||||
|
||||
$this->view->url = array (
|
||||
'c' => 'index',
|
||||
'a' => 'index',
|
||||
'params' => $params
|
||||
@@ -75,20 +80,22 @@ class FreshRSS_index_Controller extends Minz_ActionController {
|
||||
|
||||
// On récupère les différents éléments de filtrage
|
||||
$this->view->state = $state = Minz_Request::param ('state', $this->view->conf->default_view);
|
||||
$state_param = Minz_Request::param ('state', null);
|
||||
$filter = Minz_Request::param ('search', '');
|
||||
if (!empty($filter)) {
|
||||
$state = 'all'; //Search always in read and unread articles
|
||||
$state = FreshRSS_Entry::STATE_ALL; //Search always in read and unread articles
|
||||
}
|
||||
$this->view->order = $order = Minz_Request::param ('order', $this->view->conf->sort_order);
|
||||
$nb = Minz_Request::param ('nb', $this->view->conf->posts_per_page);
|
||||
$first = Minz_Request::param ('next', '');
|
||||
|
||||
if ($state === 'not_read') { //Any unread article in this category at all?
|
||||
if ($state === FreshRSS_Entry::STATE_NOT_READ) { //Any unread article in this category at all?
|
||||
switch ($getType) {
|
||||
case 'a':
|
||||
$hasUnread = $this->view->nb_not_read > 0;
|
||||
break;
|
||||
case 's':
|
||||
// This is deprecated. The favorite button does not exist anymore
|
||||
$hasUnread = $this->view->nb_favorites['unread'] > 0;
|
||||
break;
|
||||
case 'c':
|
||||
@@ -102,8 +109,8 @@ class FreshRSS_index_Controller extends Minz_ActionController {
|
||||
$hasUnread = true;
|
||||
break;
|
||||
}
|
||||
if (!$hasUnread) {
|
||||
$this->view->state = $state = 'all';
|
||||
if (!$hasUnread && ($state_param === null)) {
|
||||
$this->view->state = $state = FreshRSS_Entry::STATE_ALL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,14 +123,14 @@ class FreshRSS_index_Controller extends Minz_ActionController {
|
||||
$keepHistoryDefault = $this->view->conf->keep_history_default;
|
||||
|
||||
try {
|
||||
$entries = $entryDAO->listWhere($getType, $getId, $state, $order, $nb + 1, $first, $filter, $date_min, $keepHistoryDefault);
|
||||
$entries = $entryDAO->listWhere($getType, $getId, $state, $order, $nb + 1, $first, $filter, $date_min, true, $keepHistoryDefault);
|
||||
|
||||
// Si on a récupéré aucun article "non lus"
|
||||
// on essaye de récupérer tous les articles
|
||||
if ($state === 'not_read' && empty($entries)) {
|
||||
if ($state === FreshRSS_Entry::STATE_NOT_READ && empty($entries) && ($state_param === null)) {
|
||||
Minz_Log::record ('Conflicting information about nbNotRead!', Minz_Log::DEBUG);
|
||||
$this->view->state = 'all';
|
||||
$entries = $entryDAO->listWhere($getType, $getId, 'all', $order, $nb, $first, $filter, $date_min, $keepHistoryDefault);
|
||||
$this->view->state = FreshRSS_Entry::STATE_ALL;
|
||||
$entries = $entryDAO->listWhere($getType, $getId, $this->view->state, $order, $nb, $first, $filter, $date_min, true, $keepHistoryDefault);
|
||||
}
|
||||
|
||||
if (count($entries) <= $nb) {
|
||||
@@ -342,6 +349,37 @@ class FreshRSS_index_Controller extends Minz_ActionController {
|
||||
}
|
||||
$this->view->_useLayout(false);
|
||||
Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true);
|
||||
} elseif (Minz_Configuration::unsafeAutologinEnabled() && isset($_GET['u']) && isset($_GET['p'])) {
|
||||
Minz_Session::_param('currentUser');
|
||||
Minz_Session::_param('mail');
|
||||
Minz_Session::_param('passwordHash');
|
||||
$username = ctype_alnum($_GET['u']) ? $_GET['u'] : '';
|
||||
$passwordPlain = $_GET['p'];
|
||||
Minz_Request::_param('p'); //Discard plain-text password ASAP
|
||||
$_GET['p'] = '';
|
||||
if (!function_exists('password_verify')) {
|
||||
include_once(LIB_PATH . '/password_compat.php');
|
||||
}
|
||||
try {
|
||||
$conf = new FreshRSS_Configuration($username);
|
||||
$s = $conf->passwordHash;
|
||||
$ok = password_verify($passwordPlain, $s);
|
||||
unset($passwordPlain);
|
||||
if ($ok) {
|
||||
Minz_Session::_param('currentUser', $username);
|
||||
Minz_Session::_param('passwordHash', $s);
|
||||
} else {
|
||||
Minz_Log::record('Unsafe password mismatch for user ' . $username, Minz_Log::WARNING);
|
||||
}
|
||||
} catch (Minz_Exception $me) {
|
||||
Minz_Log::record('Unsafe login failure: ' . $me->getMessage(), Minz_Log::WARNING);
|
||||
}
|
||||
Minz_Request::forward(array('c' => 'index', 'a' => 'index'), true);
|
||||
} elseif (!Minz_Configuration::canLogIn()) {
|
||||
Minz_Error::error (
|
||||
403,
|
||||
array ('error' => array (Minz_Translate::t ('access_denied')))
|
||||
);
|
||||
}
|
||||
invalidateHttpCache();
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ class FreshRSS_javascript_Controller extends Minz_ActionController {
|
||||
public function actualizeAction () {
|
||||
header('Content-Type: text/javascript; charset=UTF-8');
|
||||
$feedDAO = new FreshRSS_FeedDAO ();
|
||||
$this->view->feeds = $feedDAO->listFeeds ();
|
||||
$this->view->feeds = $feedDAO->listFeedsOrderUpdate();
|
||||
}
|
||||
|
||||
public function nbUnreadsPerFeedAction() {
|
||||
|
||||
@@ -32,6 +32,18 @@ class FreshRSS_users_Controller extends Minz_ActionController {
|
||||
}
|
||||
Minz_Session::_param('passwordHash', $this->view->conf->passwordHash);
|
||||
|
||||
$passwordPlain = Minz_Request::param('apiPasswordPlain', false);
|
||||
if ($passwordPlain != '') {
|
||||
if (!function_exists('password_hash')) {
|
||||
include_once(LIB_PATH . '/password_compat.php');
|
||||
}
|
||||
$passwordHash = password_hash($passwordPlain, PASSWORD_BCRYPT, array('cost' => self::BCRYPT_COST));
|
||||
$passwordPlain = '';
|
||||
$passwordHash = preg_replace('/^\$2[xy]\$/', '\$2a\$', $passwordHash); //Compatibility with bcrypt.js
|
||||
$ok &= ($passwordHash != '');
|
||||
$this->view->conf->_apiPasswordHash($passwordHash);
|
||||
}
|
||||
|
||||
if (Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_'))) {
|
||||
$this->view->conf->_mail_login(Minz_Request::param('mail_login', false));
|
||||
}
|
||||
@@ -54,11 +66,22 @@ class FreshRSS_users_Controller extends Minz_ActionController {
|
||||
|
||||
$anon = Minz_Request::param('anon_access', false);
|
||||
$anon = ((bool)$anon) && ($anon !== 'no');
|
||||
$anon_refresh = Minz_Request::param('anon_refresh', false);
|
||||
$anon_refresh = ((bool)$anon_refresh) && ($anon_refresh !== 'no');
|
||||
$auth_type = Minz_Request::param('auth_type', 'none');
|
||||
$unsafe_autologin = Minz_Request::param('unsafe_autologin', false);
|
||||
$api_enabled = Minz_Request::param('api_enabled', false);
|
||||
if ($anon != Minz_Configuration::allowAnonymous() ||
|
||||
$auth_type != Minz_Configuration::authType()) {
|
||||
$auth_type != Minz_Configuration::authType() ||
|
||||
$anon_refresh != Minz_Configuration::allowAnonymousRefresh() ||
|
||||
$unsafe_autologin != Minz_Configuration::unsafeAutologinEnabled() ||
|
||||
$api_enabled != Minz_Configuration::apiEnabled()) {
|
||||
|
||||
Minz_Configuration::_authType($auth_type);
|
||||
Minz_Configuration::_allowAnonymous($anon);
|
||||
Minz_Configuration::_allowAnonymousRefresh($anon_refresh);
|
||||
Minz_Configuration::_enableAutologin($unsafe_autologin);
|
||||
Minz_Configuration::_enableApi($api_enabled);
|
||||
$ok &= Minz_Configuration::writeFile();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
class FreshRSS_Opml_Exception extends FreshRSS_Feed_Exception {
|
||||
public function __construct ($name_file) {
|
||||
parent::__construct ('OPML file is invalid');
|
||||
}
|
||||
}
|
||||
@@ -94,10 +94,6 @@ class FreshRSS extends Minz_FrontController {
|
||||
$loginOk = false;
|
||||
break;
|
||||
}
|
||||
if ((!$loginOk) && (PHP_SAPI === 'cli') && (Minz_Request::actionName() === 'actualize')) { //Command line
|
||||
Minz_Configuration::_authType('none');
|
||||
$loginOk = true;
|
||||
}
|
||||
}
|
||||
Minz_View::_param ('loginOk', $loginOk);
|
||||
return $loginOk;
|
||||
|
||||
@@ -3,14 +3,12 @@
|
||||
class FreshRSS_Category extends Minz_Model {
|
||||
private $id = 0;
|
||||
private $name;
|
||||
private $color;
|
||||
private $nbFeed = -1;
|
||||
private $nbNotRead = -1;
|
||||
private $feeds = null;
|
||||
|
||||
public function __construct ($name = '', $color = '#0062BE', $feeds = null) {
|
||||
public function __construct ($name = '', $feeds = null) {
|
||||
$this->_name ($name);
|
||||
$this->_color ($color);
|
||||
if (isset ($feeds)) {
|
||||
$this->_feeds ($feeds);
|
||||
$this->nbFeed = 0;
|
||||
@@ -28,9 +26,6 @@ class FreshRSS_Category extends Minz_Model {
|
||||
public function name () {
|
||||
return $this->name;
|
||||
}
|
||||
public function color () {
|
||||
return $this->color;
|
||||
}
|
||||
public function nbFeed () {
|
||||
if ($this->nbFeed < 0) {
|
||||
$catDAO = new FreshRSS_CategoryDAO ();
|
||||
@@ -68,13 +63,6 @@ class FreshRSS_Category extends Minz_Model {
|
||||
public function _name ($value) {
|
||||
$this->name = $value;
|
||||
}
|
||||
public function _color ($value) {
|
||||
if (preg_match ('/^#([0-9a-f]{3}|[0-9a-f]{6})$/i', $value)) {
|
||||
$this->color = $value;
|
||||
} else {
|
||||
$this->color = '#0062BE';
|
||||
}
|
||||
}
|
||||
public function _feeds ($values) {
|
||||
if (!is_array ($values)) {
|
||||
$values = array ($values);
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
|
||||
class FreshRSS_CategoryDAO extends Minz_ModelPdo {
|
||||
public function addCategory ($valuesTmp) {
|
||||
$sql = 'INSERT INTO `' . $this->prefix . 'category` (name, color) VALUES(?, ?)';
|
||||
$sql = 'INSERT INTO `' . $this->prefix . 'category` (name) VALUES(?)';
|
||||
$stm = $this->bd->prepare ($sql);
|
||||
|
||||
$values = array (
|
||||
substr($valuesTmp['name'], 0, 255),
|
||||
substr($valuesTmp['color'], 0, 7),
|
||||
);
|
||||
|
||||
if ($stm && $stm->execute ($values)) {
|
||||
@@ -19,13 +18,25 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo {
|
||||
}
|
||||
}
|
||||
|
||||
public function addCategoryObject($category) {
|
||||
$cat = $this->searchByName($category->name());
|
||||
if (!$cat) {
|
||||
// Category does not exist yet in DB so we add it before continue
|
||||
$values = array(
|
||||
'name' => $category->name(),
|
||||
);
|
||||
return $this->addCategory($values);
|
||||
}
|
||||
|
||||
return $cat->id();
|
||||
}
|
||||
|
||||
public function updateCategory ($id, $valuesTmp) {
|
||||
$sql = 'UPDATE `' . $this->prefix . 'category` SET name=?, color=? WHERE id=?';
|
||||
$sql = 'UPDATE `' . $this->prefix . 'category` SET name=? WHERE id=?';
|
||||
$stm = $this->bd->prepare ($sql);
|
||||
|
||||
$values = array (
|
||||
$valuesTmp['name'],
|
||||
$valuesTmp['color'],
|
||||
$id
|
||||
);
|
||||
|
||||
@@ -66,7 +77,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo {
|
||||
if (isset ($cat[0])) {
|
||||
return $cat[0];
|
||||
} else {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public function searchByName ($name) {
|
||||
@@ -82,14 +93,13 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo {
|
||||
if (isset ($cat[0])) {
|
||||
return $cat[0];
|
||||
} else {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function listCategories ($prePopulateFeeds = true, $details = false) {
|
||||
if ($prePopulateFeeds) {
|
||||
$sql = 'SELECT c.id AS c_id, c.name AS c_name, '
|
||||
. ($details ? 'c.color AS c_color, ' : '')
|
||||
. ($details ? 'f.* ' : 'f.id, f.name, f.url, f.website, f.priority, f.error, f.cache_nbEntries, f.cache_nbUnreads ')
|
||||
. 'FROM `' . $this->prefix . 'category` c '
|
||||
. 'LEFT OUTER JOIN `' . $this->prefix . 'feed` f ON f.category = c.id '
|
||||
@@ -123,14 +133,13 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo {
|
||||
public function checkDefault () {
|
||||
$def_cat = $this->searchById (1);
|
||||
|
||||
if ($def_cat === false) {
|
||||
if ($def_cat == null) {
|
||||
$cat = new FreshRSS_Category (Minz_Translate::t ('default_category'));
|
||||
$cat->_id (1);
|
||||
|
||||
$values = array (
|
||||
'id' => $cat->id (),
|
||||
'name' => $cat->name (),
|
||||
'color' => $cat->color ()
|
||||
);
|
||||
|
||||
$this->addCategory ($values);
|
||||
@@ -203,7 +212,6 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo {
|
||||
// End of the current category, we add it to the $list
|
||||
$cat = new FreshRSS_Category (
|
||||
$previousLine['c_name'],
|
||||
isset($previousLine['c_color']) ? $previousLine['c_color'] : '',
|
||||
FreshRSS_FeedDAO::daoToFeed ($feedsDao, $previousLine['c_id'])
|
||||
);
|
||||
$cat->_id ($previousLine['c_id']);
|
||||
@@ -220,7 +228,6 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo {
|
||||
if ($previousLine != null) {
|
||||
$cat = new FreshRSS_Category (
|
||||
$previousLine['c_name'],
|
||||
isset($previousLine['c_color']) ? $previousLine['c_color'] : '',
|
||||
FreshRSS_FeedDAO::daoToFeed ($feedsDao, $previousLine['c_id'])
|
||||
);
|
||||
$cat->_id ($previousLine['c_id']);
|
||||
@@ -239,8 +246,7 @@ class FreshRSS_CategoryDAO extends Minz_ModelPdo {
|
||||
|
||||
foreach ($listDAO as $key => $dao) {
|
||||
$cat = new FreshRSS_Category (
|
||||
$dao['name'],
|
||||
$dao['color']
|
||||
$dao['name']
|
||||
);
|
||||
$cat->_id ($dao['id']);
|
||||
$list[$key] = $cat;
|
||||
|
||||
@@ -10,13 +10,15 @@ class FreshRSS_Configuration {
|
||||
'mail_login' => '',
|
||||
'token' => '',
|
||||
'passwordHash' => '', //CRYPT_BLOWFISH
|
||||
'apiPasswordHash' => '', //CRYPT_BLOWFISH
|
||||
'posts_per_page' => 20,
|
||||
'view_mode' => 'normal',
|
||||
'default_view' => 'not_read',
|
||||
'default_view' => FreshRSS_Entry::STATE_NOT_READ,
|
||||
'auto_load_more' => true,
|
||||
'display_posts' => false,
|
||||
'onread_jump_next' => true,
|
||||
'lazyload' => true,
|
||||
'sticky_post' => true,
|
||||
'sort_order' => 'DESC',
|
||||
'anon_access' => false,
|
||||
'mark_when' => array(
|
||||
@@ -26,15 +28,19 @@ class FreshRSS_Configuration {
|
||||
'reception' => false,
|
||||
),
|
||||
'theme' => 'Origine',
|
||||
'content_width' => 'thin',
|
||||
'shortcuts' => array(
|
||||
'mark_read' => 'r',
|
||||
'mark_favorite' => 'f',
|
||||
'go_website' => 'space',
|
||||
'next_entry' => 'j',
|
||||
'prev_entry' => 'k',
|
||||
'first_entry' => 'home',
|
||||
'last_entry' => 'end',
|
||||
'collapse_entry' => 'c',
|
||||
'load_more' => 'm',
|
||||
'auto_share' => 's',
|
||||
'focus_search' => 'a',
|
||||
),
|
||||
'topline_read' => true,
|
||||
'topline_favorite' => true,
|
||||
@@ -46,16 +52,7 @@ class FreshRSS_Configuration {
|
||||
'bottomline_tags' => true,
|
||||
'bottomline_date' => true,
|
||||
'bottomline_link' => true,
|
||||
'sharing' => array(
|
||||
'shaarli' => '',
|
||||
'wallabag' => '',
|
||||
'diaspora' => '',
|
||||
'twitter' => true,
|
||||
'g+' => true,
|
||||
'facebook' => true,
|
||||
'email' => true,
|
||||
'print' => true,
|
||||
),
|
||||
'sharing' => array(),
|
||||
);
|
||||
|
||||
private $available_languages = array(
|
||||
@@ -63,8 +60,10 @@ class FreshRSS_Configuration {
|
||||
'fr' => 'Français',
|
||||
);
|
||||
|
||||
public function __construct ($user) {
|
||||
$this->filename = DATA_PATH . '/' . $user . '_user.php';
|
||||
private $shares;
|
||||
|
||||
public function __construct($user) {
|
||||
$this->filename = DATA_PATH . DIRECTORY_SEPARATOR . $user . '_user.php';
|
||||
|
||||
$data = @include($this->filename);
|
||||
if (!is_array($data)) {
|
||||
@@ -78,10 +77,20 @@ class FreshRSS_Configuration {
|
||||
}
|
||||
}
|
||||
$this->data['user'] = $user;
|
||||
|
||||
$this->shares = DATA_PATH . DIRECTORY_SEPARATOR . 'shares.php';
|
||||
|
||||
$shares = @include($this->shares);
|
||||
if (!is_array($shares)) {
|
||||
throw new Minz_PermissionDeniedException($this->shares);
|
||||
}
|
||||
|
||||
$this->data['shares'] = $shares;
|
||||
}
|
||||
|
||||
public function save() {
|
||||
@rename($this->filename, $this->filename . '.bak.php');
|
||||
unset($this->data['shares']); // Remove shares because it is not intended to be stored in user configuration
|
||||
if (file_put_contents($this->filename, "<?php\n return " . var_export($this->data, true) . ';', LOCK_EX) === false) {
|
||||
throw new Minz_PermissionDeniedException($this->filename);
|
||||
}
|
||||
@@ -102,16 +111,6 @@ class FreshRSS_Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
public function sharing($key = false) {
|
||||
if ($key === false) {
|
||||
return $this->data['sharing'];
|
||||
}
|
||||
if (isset($this->data['sharing'][$key])) {
|
||||
return $this->data['sharing'][$key];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function availableLanguages() {
|
||||
return $this->available_languages;
|
||||
}
|
||||
@@ -134,7 +133,7 @@ class FreshRSS_Configuration {
|
||||
}
|
||||
}
|
||||
public function _default_view ($value) {
|
||||
$this->data['default_view'] = $value === 'all' ? 'all' : 'not_read';
|
||||
$this->data['default_view'] = $value === FreshRSS_Entry::STATE_ALL ? FreshRSS_Entry::STATE_ALL : FreshRSS_Entry::STATE_NOT_READ;
|
||||
}
|
||||
public function _display_posts ($value) {
|
||||
$this->data['display_posts'] = ((bool)$value) && $value !== 'no';
|
||||
@@ -145,6 +144,9 @@ class FreshRSS_Configuration {
|
||||
public function _lazyload ($value) {
|
||||
$this->data['lazyload'] = ((bool)$value) && $value !== 'no';
|
||||
}
|
||||
public function _sticky_post($value) {
|
||||
$this->data['sticky_post'] = ((bool)$value) && $value !== 'no';
|
||||
}
|
||||
public function _sort_order ($value) {
|
||||
$this->data['sort_order'] = $value === 'ASC' ? 'ASC' : 'DESC';
|
||||
}
|
||||
@@ -166,6 +168,9 @@ class FreshRSS_Configuration {
|
||||
public function _passwordHash ($value) {
|
||||
$this->data['passwordHash'] = ctype_graph($value) && (strlen($value) >= 60) ? $value : '';
|
||||
}
|
||||
public function _apiPasswordHash ($value) {
|
||||
$this->data['apiPasswordHash'] = ctype_graph($value) && (strlen($value) >= 60) ? $value : '';
|
||||
}
|
||||
public function _mail_login ($value) {
|
||||
$value = filter_var($value, FILTER_VALIDATE_EMAIL);
|
||||
if ($value) {
|
||||
@@ -185,29 +190,47 @@ class FreshRSS_Configuration {
|
||||
}
|
||||
}
|
||||
public function _sharing ($values) {
|
||||
$are_url = array ('shaarli', 'wallabag', 'diaspora');
|
||||
foreach ($values as $key => $value) {
|
||||
if (in_array($key, $are_url)) {
|
||||
$this->data['sharing'] = array();
|
||||
foreach ($values as $value) {
|
||||
if (!is_array($value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Verify URL and add default value when needed
|
||||
if (isset($value['url'])) {
|
||||
$is_url = (
|
||||
filter_var ($value, FILTER_VALIDATE_URL) ||
|
||||
filter_var ($value['url'], FILTER_VALIDATE_URL) ||
|
||||
(version_compare(PHP_VERSION, '5.3.3', '<') &&
|
||||
(strpos($value, '-') > 0) &&
|
||||
($value === filter_var($value, FILTER_SANITIZE_URL)))
|
||||
); //PHP bug #51192
|
||||
|
||||
if (!$is_url) {
|
||||
$value = '';
|
||||
continue;
|
||||
}
|
||||
} elseif (!is_bool($value)) {
|
||||
$value = true;
|
||||
} else {
|
||||
$value['url'] = null;
|
||||
}
|
||||
|
||||
$this->data['sharing'][$key] = $value;
|
||||
// Add a default name
|
||||
if (empty($value['name'])) {
|
||||
$value['name'] = $value['type'];
|
||||
}
|
||||
|
||||
$this->data['sharing'][] = $value;
|
||||
}
|
||||
}
|
||||
public function _theme($value) {
|
||||
$this->data['theme'] = $value;
|
||||
}
|
||||
public function _content_width($value) {
|
||||
if ($value === 'medium' ||
|
||||
$value === 'large' ||
|
||||
$value === 'no_limit') {
|
||||
$this->data['content_width'] = $value;
|
||||
} else {
|
||||
$this->data['content_width'] = 'thin';
|
||||
}
|
||||
}
|
||||
public function _token($value) {
|
||||
$this->data['token'] = $value;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
<?php
|
||||
|
||||
class FreshRSS_Entry extends Minz_Model {
|
||||
const STATE_ALL = 0;
|
||||
const STATE_READ = 1;
|
||||
const STATE_NOT_READ = 2;
|
||||
const STATE_FAVORITE = 4;
|
||||
const STATE_NOT_FAVORITE = 8;
|
||||
|
||||
private $id = 0;
|
||||
private $guid;
|
||||
|
||||
@@ -35,11 +35,45 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
|
||||
}
|
||||
}
|
||||
|
||||
public function markFavorite ($id, $is_favorite = true) {
|
||||
public function addEntryObject($entry, $conf, $feedHistory) {
|
||||
$existingGuids = array_fill_keys(
|
||||
$this->listLastGuidsByFeed($entry->feed(), 20), 1
|
||||
);
|
||||
|
||||
$nb_month_old = max($conf->old_entries, 1);
|
||||
$date_min = time() - (3600 * 24 * 30 * $nb_month_old);
|
||||
|
||||
$eDate = $entry->date(true);
|
||||
|
||||
if ($feedHistory == -2) {
|
||||
$feedHistory = $conf->keep_history_default;
|
||||
}
|
||||
|
||||
if (!isset($existingGuids[$entry->guid()]) &&
|
||||
($feedHistory != 0 || $eDate >= $date_min)) {
|
||||
$values = $entry->toArray();
|
||||
|
||||
$useDeclaredDate = empty($existingGuids);
|
||||
$values['id'] = ($useDeclaredDate || $eDate < $date_min) ?
|
||||
min(time(), $eDate) . uSecString() :
|
||||
uTimeString();
|
||||
|
||||
return $this->addEntry($values);
|
||||
}
|
||||
|
||||
// We don't return Entry object to avoid a research in DB
|
||||
return -1;
|
||||
}
|
||||
|
||||
public function markFavorite($ids, $is_favorite = true) {
|
||||
if (!is_array($ids)) {
|
||||
$ids = array($ids);
|
||||
}
|
||||
$sql = 'UPDATE `' . $this->prefix . 'entry` e '
|
||||
. 'SET e.is_favorite = ? '
|
||||
. 'WHERE e.id=?';
|
||||
$values = array ($is_favorite ? 1 : 0, $id);
|
||||
. 'WHERE e.id IN (' . str_repeat('?,', count($ids) - 1). '?)';
|
||||
$values = array ($is_favorite ? 1 : 0);
|
||||
$values = array_merge($values, $ids);
|
||||
$stm = $this->bd->prepare ($sql);
|
||||
if ($stm && $stm->execute ($values)) {
|
||||
return $stm->rowCount();
|
||||
@@ -49,30 +83,79 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public function markRead ($id, $is_read = true) {
|
||||
$sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
|
||||
. 'SET e.is_read = ?,'
|
||||
. 'f.cache_nbUnreads=f.cache_nbUnreads' . ($is_read ? '-' : '+') . '1 '
|
||||
. 'WHERE e.id=?';
|
||||
$values = array ($is_read ? 1 : 0, $id);
|
||||
$stm = $this->bd->prepare ($sql);
|
||||
if ($stm && $stm->execute ($values)) {
|
||||
return $stm->rowCount();
|
||||
|
||||
public function markRead($ids, $is_read = true) {
|
||||
if (is_array($ids)) {
|
||||
if (count($ids) < 6) { //Speed heuristics
|
||||
$affected = 0;
|
||||
foreach ($ids as $id) {
|
||||
$affected += $this->markRead($id, $is_read);
|
||||
}
|
||||
return $affected;
|
||||
}
|
||||
|
||||
$this->bd->beginTransaction();
|
||||
$sql = 'UPDATE `' . $this->prefix . 'entry` e '
|
||||
. 'SET e.is_read = ? '
|
||||
. 'WHERE e.id IN (' . str_repeat('?,', count($ids) - 1). '?)';
|
||||
$values = array($is_read ? 1 : 0);
|
||||
$values = array_merge($values, $ids);
|
||||
$stm = $this->bd->prepare($sql);
|
||||
if (!($stm && $stm->execute($values))) {
|
||||
$info = $stm->errorInfo();
|
||||
Minz_Log::record('SQL error : ' . $info[2], Minz_Log::ERROR);
|
||||
$this->bd->rollBack();
|
||||
return false;
|
||||
}
|
||||
$affected = $stm->rowCount();
|
||||
|
||||
if ($affected > 0) {
|
||||
$sql = 'UPDATE `' . $this->prefix . 'feed` f '
|
||||
. 'INNER JOIN ('
|
||||
. 'SELECT e.id_feed, '
|
||||
. 'COUNT(CASE WHEN e.is_read = 0 THEN 1 END) AS nbUnreads, '
|
||||
. 'COUNT(e.id) AS nbEntries '
|
||||
. 'FROM `' . $this->prefix . 'entry` e '
|
||||
. 'GROUP BY e.id_feed'
|
||||
. ') x ON x.id_feed=f.id '
|
||||
. 'SET f.cache_nbEntries=x.nbEntries, f.cache_nbUnreads=x.nbUnreads';
|
||||
$stm = $this->bd->prepare($sql);
|
||||
if (!($stm && $stm->execute())) {
|
||||
$info = $stm->errorInfo();
|
||||
Minz_Log::record('SQL error : ' . $info[2], Minz_Log::ERROR);
|
||||
$this->bd->rollBack();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->bd->commit();
|
||||
return $affected;
|
||||
} else {
|
||||
$info = $stm->errorInfo();
|
||||
Minz_Log::record ('SQL error : ' . $info[2], Minz_Log::ERROR);
|
||||
return false;
|
||||
$sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
|
||||
. 'SET e.is_read = ?,'
|
||||
. 'f.cache_nbUnreads=f.cache_nbUnreads' . ($is_read ? '-' : '+') . '1 '
|
||||
. 'WHERE e.id=?';
|
||||
$values = array($is_read ? 1 : 0, $ids);
|
||||
$stm = $this->bd->prepare($sql);
|
||||
if ($stm && $stm->execute($values)) {
|
||||
return $stm->rowCount();
|
||||
} else {
|
||||
$info = $stm->errorInfo();
|
||||
Minz_Log::record('SQL error : ' . $info[2], Minz_Log::ERROR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
public function markReadEntries ($idMax = 0, $favorites = false) {
|
||||
if ($idMax === 0) {
|
||||
|
||||
public function markReadEntries ($idMax = 0, $onlyFavorites = false, $priorityMin = 0) {
|
||||
if ($idMax == 0) {
|
||||
$sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
|
||||
. 'SET e.is_read = 1, f.cache_nbUnreads=0 '
|
||||
. 'WHERE e.is_read = 0 AND ';
|
||||
if ($favorites) {
|
||||
$sql .= 'e.is_favorite = 1';
|
||||
} else {
|
||||
$sql .= 'f.priority > 0';
|
||||
. 'WHERE e.is_read = 0';
|
||||
if ($onlyFavorites) {
|
||||
$sql .= ' AND e.is_favorite = 1';
|
||||
} elseif ($priorityMin >= 0) {
|
||||
$sql .= ' AND f.priority > ' . intval($priorityMin);
|
||||
}
|
||||
$stm = $this->bd->prepare ($sql);
|
||||
if ($stm && $stm->execute ()) {
|
||||
@@ -87,11 +170,11 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
|
||||
|
||||
$sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
|
||||
. 'SET e.is_read = 1 '
|
||||
. 'WHERE e.is_read = 0 AND e.id <= ? AND ';
|
||||
if ($favorites) {
|
||||
$sql .= 'e.is_favorite = 1';
|
||||
} else {
|
||||
$sql .= 'f.priority > 0';
|
||||
. 'WHERE e.is_read = 0 AND e.id <= ?';
|
||||
if ($onlyFavorites) {
|
||||
$sql .= ' AND e.is_favorite = 1';
|
||||
} elseif ($priorityMin >= 0) {
|
||||
$sql .= ' AND f.priority > ' . intval($priorityMin);
|
||||
}
|
||||
$values = array ($idMax);
|
||||
$stm = $this->bd->prepare ($sql);
|
||||
@@ -126,8 +209,9 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
|
||||
return $affected;
|
||||
}
|
||||
}
|
||||
|
||||
public function markReadCat ($id, $idMax = 0) {
|
||||
if ($idMax === 0) {
|
||||
if ($idMax == 0) {
|
||||
$sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
|
||||
. 'SET e.is_read = 1, f.cache_nbUnreads=0 '
|
||||
. 'WHERE f.category = ? AND e.is_read = 0';
|
||||
@@ -181,8 +265,70 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
|
||||
return $affected;
|
||||
}
|
||||
}
|
||||
|
||||
public function markReadCatName($name, $idMax = 0) {
|
||||
if ($idMax == 0) {
|
||||
$sql = 'UPDATE `' . $this->prefix . 'entry` e '
|
||||
. 'INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
|
||||
. 'INNER JOIN `' . $this->prefix . 'category` c ON c.id = f.category '
|
||||
. 'SET e.is_read = 1, f.cache_nbUnreads=0 '
|
||||
. 'WHERE c.name = ?';
|
||||
$values = array($name);
|
||||
$stm = $this->bd->prepare($sql);
|
||||
if ($stm && $stm->execute($values)) {
|
||||
return $stm->rowCount();
|
||||
} else {
|
||||
$info = $stm->errorInfo();
|
||||
Minz_Log::record('SQL error : ' . $info[2], Minz_Log::ERROR);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$this->bd->beginTransaction();
|
||||
|
||||
$sql = 'UPDATE `' . $this->prefix . 'entry` e '
|
||||
. 'INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
|
||||
. 'INNER JOIN `' . $this->prefix . 'category` c ON c.id = f.category '
|
||||
. 'SET e.is_read = 1 '
|
||||
. 'WHERE c.name = ? AND e.id <= ?';
|
||||
$values = array($name, $idMax);
|
||||
$stm = $this->bd->prepare($sql);
|
||||
if (!($stm && $stm->execute($values))) {
|
||||
$info = $stm->errorInfo();
|
||||
Minz_Log::record('SQL error : ' . $info[2], Minz_Log::ERROR);
|
||||
$this->bd->rollBack();
|
||||
return false;
|
||||
}
|
||||
$affected = $stm->rowCount();
|
||||
|
||||
if ($affected > 0) {
|
||||
$sql = 'UPDATE `' . $this->prefix . 'feed` f '
|
||||
. 'LEFT OUTER JOIN ('
|
||||
. 'SELECT e.id_feed, '
|
||||
. 'COUNT(*) AS nbUnreads '
|
||||
. 'FROM `' . $this->prefix . 'entry` e '
|
||||
. 'WHERE e.is_read = 0 '
|
||||
. 'GROUP BY e.id_feed'
|
||||
. ') x ON x.id_feed=f.id '
|
||||
. 'INNER JOIN `' . $this->prefix . 'category` c ON c.id = f.category '
|
||||
. 'SET f.cache_nbUnreads=COALESCE(x.nbUnreads, 0) '
|
||||
. 'WHERE c.name = ?';
|
||||
$values = array($name);
|
||||
$stm = $this->bd->prepare($sql);
|
||||
if (!($stm && $stm->execute($values))) {
|
||||
$info = $stm->errorInfo();
|
||||
Minz_Log::record('SQL error : ' . $info[2], Minz_Log::ERROR);
|
||||
$this->bd->rollBack();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->bd->commit();
|
||||
return $affected;
|
||||
}
|
||||
}
|
||||
|
||||
public function markReadFeed ($id, $idMax = 0) {
|
||||
if ($idMax === 0) {
|
||||
if ($idMax == 0) {
|
||||
$sql = 'UPDATE `' . $this->prefix . 'entry` e INNER JOIN `' . $this->prefix . 'feed` f ON e.id_feed = f.id '
|
||||
. 'SET e.is_read = 1, f.cache_nbUnreads=0 '
|
||||
. 'WHERE f.id=? AND e.is_read = 0';
|
||||
@@ -244,7 +390,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
|
||||
$stm->execute ($values);
|
||||
$res = $stm->fetchAll (PDO::FETCH_ASSOC);
|
||||
$entries = self::daoToEntry ($res);
|
||||
return isset ($entries[0]) ? $entries[0] : false;
|
||||
return isset ($entries[0]) ? $entries[0] : null;
|
||||
}
|
||||
|
||||
public function searchById ($id) {
|
||||
@@ -257,10 +403,13 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
|
||||
$stm->execute ($values);
|
||||
$res = $stm->fetchAll (PDO::FETCH_ASSOC);
|
||||
$entries = self::daoToEntry ($res);
|
||||
return isset ($entries[0]) ? $entries[0] : false;
|
||||
return isset ($entries[0]) ? $entries[0] : null;
|
||||
}
|
||||
|
||||
public function listWhere($type = 'a', $id = '', $state = 'all', $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $keepHistoryDefault = 0) {
|
||||
private function sqlListWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) {
|
||||
if (!$state) {
|
||||
$state = FreshRSS_Entry::STATE_ALL;
|
||||
}
|
||||
$where = '';
|
||||
$joinFeed = false;
|
||||
$values = array();
|
||||
@@ -269,7 +418,7 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
|
||||
$where .= 'f.priority > 0 ';
|
||||
$joinFeed = true;
|
||||
break;
|
||||
case 's':
|
||||
case 's': //Deprecated: use $state instead
|
||||
$where .= 'e1.is_favorite = 1 ';
|
||||
break;
|
||||
case 'c':
|
||||
@@ -281,24 +430,30 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
|
||||
$where .= 'e1.id_feed = ? ';
|
||||
$values[] = intval($id);
|
||||
break;
|
||||
case 'A':
|
||||
$where .= '1 ';
|
||||
break;
|
||||
default:
|
||||
throw new FreshRSS_EntriesGetter_Exception ('Bad type in Entry->listByType: [' . $type . ']!');
|
||||
}
|
||||
switch ($state) {
|
||||
case 'all':
|
||||
break;
|
||||
case 'not_read':
|
||||
|
||||
if ($state & FreshRSS_Entry::STATE_NOT_READ) {
|
||||
if (!($state & FreshRSS_Entry::STATE_READ)) {
|
||||
$where .= 'AND e1.is_read = 0 ';
|
||||
break;
|
||||
case 'read':
|
||||
$where .= 'AND e1.is_read = 1 ';
|
||||
break;
|
||||
case 'favorite':
|
||||
$where .= 'AND e1.is_favorite = 1 ';
|
||||
break;
|
||||
default:
|
||||
throw new FreshRSS_EntriesGetter_Exception ('Bad state in Entry->listByType: [' . $state . ']!');
|
||||
}
|
||||
}
|
||||
elseif ($state & FreshRSS_Entry::STATE_READ) {
|
||||
$where .= 'AND e1.is_read = 1 ';
|
||||
}
|
||||
if ($state & FreshRSS_Entry::STATE_FAVORITE) {
|
||||
if (!($state & FreshRSS_Entry::STATE_NOT_FAVORITE)) {
|
||||
$where .= 'AND e1.is_favorite = 1 ';
|
||||
}
|
||||
}
|
||||
elseif ($state & FreshRSS_Entry::STATE_NOT_FAVORITE) {
|
||||
$where .= 'AND e1.is_favorite = 0 ';
|
||||
}
|
||||
|
||||
switch ($order) {
|
||||
case 'DESC':
|
||||
case 'ASC':
|
||||
@@ -310,70 +465,84 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
|
||||
$where .= 'AND e1.id ' . ($order === 'DESC' ? '<=' : '>=') . $firstId . ' ';
|
||||
}
|
||||
if (($date_min > 0) && ($type !== 's')) {
|
||||
$where .= 'AND (e1.id >= ' . $date_min . '000000 OR e1.is_read = 0 OR e1.is_favorite = 1 OR (f.keep_history <> 0';
|
||||
if (intval($keepHistoryDefault) === 0) {
|
||||
$where .= ' AND f.keep_history <> -2'; //default
|
||||
$where .= 'AND (e1.id >= ' . $date_min . '000000';
|
||||
if ($showOlderUnreadsorFavorites) { //Lax date constraint
|
||||
$where .= ' OR e1.is_read = 0 OR e1.is_favorite = 1 OR (f.keep_history <> 0';
|
||||
if (intval($keepHistoryDefault) === 0) {
|
||||
$where .= ' AND f.keep_history <> -2'; //default
|
||||
}
|
||||
$where .= ')';
|
||||
}
|
||||
$where .= ')) ';
|
||||
$where .= ') ';
|
||||
$joinFeed = true;
|
||||
}
|
||||
$search = '';
|
||||
if ($filter !== '') {
|
||||
require_once(LIB_PATH . '/lib_date.php');
|
||||
$filter = trim($filter);
|
||||
$filter = addcslashes($filter, '\\%_');
|
||||
if (stripos($filter, 'intitle:') === 0) {
|
||||
$filter = substr($filter, strlen('intitle:'));
|
||||
$intitle = true;
|
||||
} else {
|
||||
$intitle = false;
|
||||
}
|
||||
if (stripos($filter, 'inurl:') === 0) {
|
||||
$filter = substr($filter, strlen('inurl:'));
|
||||
$inurl = true;
|
||||
} else {
|
||||
$inurl = false;
|
||||
}
|
||||
if (stripos($filter, 'author:') === 0) {
|
||||
$filter = substr($filter, strlen('author:'));
|
||||
$author = true;
|
||||
} else {
|
||||
$author = false;
|
||||
}
|
||||
$terms = array_unique(explode(' ', $filter));
|
||||
sort($terms); //Put #tags first
|
||||
//sort($terms); //Put #tags first //TODO: Put the cheapest filters first
|
||||
foreach ($terms as $word) {
|
||||
$word = trim($word);
|
||||
if (strlen($word) > 0) {
|
||||
if ($intitle) {
|
||||
$search .= 'AND e1.title LIKE ? ';
|
||||
$values[] = '%' . $word .'%';
|
||||
} elseif ($inurl) {
|
||||
$search .= 'AND CONCAT(e1.link, e1.guid) LIKE ? ';
|
||||
$values[] = '%' . $word .'%';
|
||||
} elseif ($author) {
|
||||
$search .= 'AND e1.author LIKE ? ';
|
||||
if (stripos($word, 'intitle:') === 0) {
|
||||
$word = substr($word, strlen('intitle:'));
|
||||
$search .= 'AND e1.title LIKE ? ';
|
||||
$values[] = '%' . $word .'%';
|
||||
} elseif (stripos($word, 'inurl:') === 0) {
|
||||
$word = substr($word, strlen('inurl:'));
|
||||
$search .= 'AND CONCAT(e1.link, e1.guid) LIKE ? ';
|
||||
$values[] = '%' . $word .'%';
|
||||
} elseif (stripos($word, 'author:') === 0) {
|
||||
$word = substr($word, strlen('author:'));
|
||||
$search .= 'AND e1.author LIKE ? ';
|
||||
$values[] = '%' . $word .'%';
|
||||
} elseif (stripos($word, 'date:') === 0) {
|
||||
$word = substr($word, strlen('date:'));
|
||||
list($minDate, $maxDate) = parseDateInterval($word);
|
||||
if ($minDate) {
|
||||
$search .= 'AND e1.id >= ' . $minDate . '000000 ';
|
||||
}
|
||||
if ($maxDate) {
|
||||
$search .= 'AND e1.id <= ' . $maxDate . '000000 ';
|
||||
}
|
||||
} elseif (stripos($word, 'pubdate:') === 0) {
|
||||
$word = substr($word, strlen('pubdate:'));
|
||||
list($minDate, $maxDate) = parseDateInterval($word);
|
||||
if ($minDate) {
|
||||
$search .= 'AND e1.date >= ' . $minDate . ' ';
|
||||
}
|
||||
if ($maxDate) {
|
||||
$search .= 'AND e1.date <= ' . $maxDate . ' ';
|
||||
}
|
||||
} else {
|
||||
if ($word[0] === '#' && isset($word[1])) {
|
||||
$search .= 'AND e1.tags LIKE ? ';
|
||||
$values[] = '%' . $word .'%';
|
||||
} else {
|
||||
if ($word[0] === '#' && isset($word[1])) {
|
||||
$search .= 'AND e1.tags LIKE ? ';
|
||||
$values[] = '%' . $word .'%';
|
||||
} else {
|
||||
$search .= 'AND CONCAT(e1.title, UNCOMPRESS(e1.content_bin)) LIKE ? ';
|
||||
$values[] = '%' . $word .'%';
|
||||
}
|
||||
$search .= 'AND CONCAT(e1.title, UNCOMPRESS(e1.content_bin)) LIKE ? ';
|
||||
$values[] = '%' . $word .'%';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array($values,
|
||||
'SELECT e1.id FROM `' . $this->prefix . 'entry` e1 '
|
||||
. ($joinFeed ? 'INNER JOIN `' . $this->prefix . 'feed` f ON e1.id_feed = f.id ' : '')
|
||||
. 'WHERE ' . $where
|
||||
. $search
|
||||
. 'ORDER BY e1.id ' . $order
|
||||
. ($limit > 0 ? ' LIMIT ' . $limit : '')); //TODO: See http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/
|
||||
}
|
||||
|
||||
public function listWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) {
|
||||
list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min, $showOlderUnreadsorFavorites, $keepHistoryDefault);
|
||||
|
||||
$sql = 'SELECT e.id, e.guid, e.title, e.author, UNCOMPRESS(e.content_bin) AS content, e.link, e.date, e.is_read, e.is_favorite, e.id_feed, e.tags '
|
||||
. 'FROM `' . $this->prefix . 'entry` e '
|
||||
. 'INNER JOIN (SELECT e1.id FROM `' . $this->prefix . 'entry` e1 '
|
||||
. ($joinFeed ? 'INNER JOIN `' . $this->prefix . 'feed` f ON e1.id_feed = f.id ' : '')
|
||||
. 'WHERE ' . $where
|
||||
. $search
|
||||
. 'ORDER BY e1.id ' . $order
|
||||
. ($limit > 0 ? ' LIMIT ' . $limit : '') //TODO: See http://explainextended.com/2009/10/23/mysql-order-by-limit-performance-late-row-lookups/
|
||||
. 'INNER JOIN ('
|
||||
. $sql
|
||||
. ') e2 ON e2.id = e.id '
|
||||
. 'ORDER BY e.id ' . $order;
|
||||
|
||||
@@ -383,6 +552,15 @@ class FreshRSS_EntryDAO extends Minz_ModelPdo {
|
||||
return self::daoToEntry ($stm->fetchAll (PDO::FETCH_ASSOC));
|
||||
}
|
||||
|
||||
public function listIdsWhere($type = 'a', $id = '', $state = FreshRSS_Entry::STATE_ALL, $order = 'DESC', $limit = 1, $firstId = '', $filter = '', $date_min = 0, $showOlderUnreadsorFavorites = false, $keepHistoryDefault = 0) { //For API
|
||||
list($values, $sql) = $this->sqlListWhere($type, $id, $state, $order, $limit, $firstId, $filter, $date_min, $showOlderUnreadsorFavorites, $keepHistoryDefault);
|
||||
|
||||
$stm = $this->bd->prepare($sql);
|
||||
$stm->execute($values);
|
||||
|
||||
return $stm->fetchAll(PDO::FETCH_COLUMN, 0);
|
||||
}
|
||||
|
||||
public function listLastGuidsByFeed($id, $n) {
|
||||
$sql = 'SELECT guid FROM `' . $this->prefix . 'entry` WHERE id_feed=? ORDER BY id DESC LIMIT ' . intval($n);
|
||||
$stm = $this->bd->prepare ($sql);
|
||||
|
||||
@@ -193,10 +193,10 @@ class FreshRSS_Feed extends Minz_Model {
|
||||
}
|
||||
$feed = customSimplePie();
|
||||
$feed->set_feed_url ($url);
|
||||
$feed->init ();
|
||||
$mtime = $feed->init();
|
||||
|
||||
if ($feed->error ()) {
|
||||
throw new FreshRSS_Feed_Exception ($feed->error . ' [' . $url . ']');
|
||||
if ((!$mtime) || $feed->error()) {
|
||||
throw new FreshRSS_Feed_Exception ($feed->error() . ' [' . $url . ']');
|
||||
}
|
||||
|
||||
// si on a utilisé l'auto-discover, notre url va avoir changé
|
||||
@@ -210,18 +210,27 @@ class FreshRSS_Feed extends Minz_Model {
|
||||
}
|
||||
|
||||
if ($loadDetails) {
|
||||
$title = htmlspecialchars(html_only_entity_decode($feed->get_title()), ENT_COMPAT, 'UTF-8');
|
||||
$this->_name ($title === null ? $this->url : $title);
|
||||
$title = strtr(html_only_entity_decode($feed->get_title()), array('<' => '<', '>' => '>', '"' => '"')); //HTML to HTML-PRE //ENT_COMPAT except &
|
||||
$this->_name ($title == '' ? $this->url : $title);
|
||||
|
||||
$this->_website(html_only_entity_decode($feed->get_link()));
|
||||
$this->_description(html_only_entity_decode($feed->get_description()));
|
||||
}
|
||||
|
||||
// et on charge les articles du flux
|
||||
$this->loadEntries ($feed);
|
||||
if (($mtime === true) || ($mtime > $this->lastUpdate)) {
|
||||
syslog(LOG_DEBUG, 'FreshRSS no cache ' . $mtime . ' > ' . $this->lastUpdate . ' for ' . $subscribe_url);
|
||||
$this->loadEntries($feed); // et on charge les articles du flux
|
||||
} else {
|
||||
syslog(LOG_DEBUG, 'FreshRSS use cache for ' . $subscribe_url);
|
||||
$this->entries = array();
|
||||
}
|
||||
|
||||
$feed->__destruct(); //http://simplepie.org/wiki/faq/i_m_getting_memory_leaks
|
||||
unset($feed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function loadEntries ($feed) {
|
||||
$entries = array ();
|
||||
|
||||
@@ -245,11 +254,16 @@ class FreshRSS_Feed extends Minz_Model {
|
||||
$elinks = array();
|
||||
foreach ($item->get_enclosures() as $enclosure) {
|
||||
$elink = $enclosure->get_link();
|
||||
if (array_key_exists($elink, $elinks)) continue;
|
||||
$elinks[$elink] = '1';
|
||||
$mime = strtolower($enclosure->get_type());
|
||||
if (strpos($mime, 'image/') === 0) {
|
||||
$content .= '<br /><img src="' . $elink . '" alt="" />';
|
||||
if (empty($elinks[$elink])) {
|
||||
$elinks[$elink] = '1';
|
||||
$mime = strtolower($enclosure->get_type());
|
||||
if (strpos($mime, 'image/') === 0) {
|
||||
$content .= '<br /><img src="' . $elink . '" alt="" />';
|
||||
} elseif (strpos($mime, 'audio/') === 0) {
|
||||
$content .= '<br /><audio src="' . $elink . '" controls="controls" />';
|
||||
} elseif (strpos($mime, 'video/') === 0) {
|
||||
$content .= '<br /><video src="' . $elink . '" controls="controls" />';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,8 +281,27 @@ class FreshRSS_Feed extends Minz_Model {
|
||||
$entry->loadCompleteContent($this->pathEntries());
|
||||
|
||||
$entries[] = $entry;
|
||||
unset($item);
|
||||
}
|
||||
|
||||
$this->entries = $entries;
|
||||
}
|
||||
|
||||
function lock() {
|
||||
$lock = TMP_PATH . '/' . md5(Minz_Configuration::salt() . $this->url) . '.freshrss.lock';
|
||||
if (file_exists($lock) && ((time() - @filemtime($lock)) > 3600)) {
|
||||
@unlink($lock);
|
||||
}
|
||||
if (($handle = @fopen($lock, 'x')) === false) {
|
||||
return false;
|
||||
}
|
||||
//register_shutdown_function('unlink', $lock);
|
||||
@fclose($handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
function unlock() {
|
||||
$lock = TMP_PATH . '/' . md5(Minz_Configuration::salt() . $this->url) . '.freshrss.lock';
|
||||
@unlink($lock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,36 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
|
||||
}
|
||||
}
|
||||
|
||||
public function addFeedObject($feed) {
|
||||
// TODO: not sure if we should write this method in DAO since DAO
|
||||
// should not be aware about feed class
|
||||
|
||||
// Add feed only if we don't find it in DB
|
||||
$feed_search = $this->searchByUrl($feed->url());
|
||||
if (!$feed_search) {
|
||||
$values = array(
|
||||
'id' => $feed->id(),
|
||||
'url' => $feed->url(),
|
||||
'category' => $feed->category(),
|
||||
'name' => $feed->name(),
|
||||
'website' => $feed->website(),
|
||||
'description' => $feed->description(),
|
||||
'lastUpdate' => 0,
|
||||
'httpAuth' => $feed->httpAuth()
|
||||
);
|
||||
|
||||
$id = $this->addFeed($values);
|
||||
if ($id) {
|
||||
$feed->_id($id);
|
||||
$feed->faviconPrepare();
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
return $feed_search->id();
|
||||
}
|
||||
|
||||
public function updateFeed ($id, $valuesTmp) {
|
||||
$set = '';
|
||||
foreach ($valuesTmp as $key => $v) {
|
||||
@@ -52,21 +82,27 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
|
||||
}
|
||||
}
|
||||
|
||||
public function updateLastUpdate ($id, $inError = 0) {
|
||||
$sql = 'UPDATE `' . $this->prefix . 'feed` f ' //2 sub-requests with FOREIGN KEY(e.id_feed), INDEX(e.is_read) faster than 1 request with GROUP BY or CASE
|
||||
. 'SET f.cache_nbEntries=(SELECT COUNT(e1.id) FROM `' . $this->prefix . 'entry` e1 WHERE e1.id_feed=f.id),'
|
||||
. 'f.cache_nbUnreads=(SELECT COUNT(e2.id) FROM `' . $this->prefix . 'entry` e2 WHERE e2.id_feed=f.id AND e2.is_read=0),'
|
||||
. 'lastUpdate=?, error=? '
|
||||
. 'WHERE f.id=?';
|
||||
|
||||
$stm = $this->bd->prepare ($sql);
|
||||
public function updateLastUpdate ($id, $inError = 0, $updateCache = true) {
|
||||
if ($updateCache) {
|
||||
$sql = 'UPDATE `' . $this->prefix . 'feed` f ' //2 sub-requests with FOREIGN KEY(e.id_feed), INDEX(e.is_read) faster than 1 request with GROUP BY or CASE
|
||||
. 'SET f.cache_nbEntries=(SELECT COUNT(e1.id) FROM `' . $this->prefix . 'entry` e1 WHERE e1.id_feed=f.id),'
|
||||
. 'f.cache_nbUnreads=(SELECT COUNT(e2.id) FROM `' . $this->prefix . 'entry` e2 WHERE e2.id_feed=f.id AND e2.is_read=0),'
|
||||
. 'lastUpdate=?, error=? '
|
||||
. 'WHERE f.id=?';
|
||||
} else {
|
||||
$sql = 'UPDATE `' . $this->prefix . 'feed` f '
|
||||
. 'SET lastUpdate=?, error=? '
|
||||
. 'WHERE f.id=?';
|
||||
}
|
||||
|
||||
$values = array (
|
||||
time (),
|
||||
time(),
|
||||
$inError,
|
||||
$id,
|
||||
);
|
||||
|
||||
$stm = $this->bd->prepare ($sql);
|
||||
|
||||
if ($stm && $stm->execute ($values)) {
|
||||
return $stm->rowCount();
|
||||
} else {
|
||||
@@ -164,7 +200,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
|
||||
if (isset ($feed[$id])) {
|
||||
return $feed[$id];
|
||||
} else {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public function searchByUrl ($url) {
|
||||
@@ -180,7 +216,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
|
||||
if (isset ($feed)) {
|
||||
return $feed;
|
||||
} else {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,8 +228,27 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
|
||||
return self::daoToFeed ($stm->fetchAll (PDO::FETCH_ASSOC));
|
||||
}
|
||||
|
||||
public function listFeedsOrderUpdate () {
|
||||
$sql = 'SELECT id, name, url, pathEntries, httpAuth, keep_history FROM `' . $this->prefix . 'feed` ORDER BY lastUpdate';
|
||||
public function arrayFeedCategoryNames() { //For API
|
||||
$sql = 'SELECT f.id, f.name, c.name as c_name FROM `' . $this->prefix . 'feed` f '
|
||||
. 'INNER JOIN `' . $this->prefix . 'category` c ON c.id = f.category';
|
||||
$stm = $this->bd->prepare ($sql);
|
||||
$stm->execute ();
|
||||
$res = $stm->fetchAll(PDO::FETCH_ASSOC);
|
||||
$feedCategoryNames = array();
|
||||
foreach ($res as $line) {
|
||||
$feedCategoryNames[$line['id']] = array(
|
||||
'name' => $line['name'],
|
||||
'c_name' => $line['c_name'],
|
||||
);
|
||||
}
|
||||
return $feedCategoryNames;
|
||||
}
|
||||
|
||||
public function listFeedsOrderUpdate ($cacheDuration = 1500) {
|
||||
$sql = 'SELECT id, name, url, lastUpdate, pathEntries, httpAuth, keep_history '
|
||||
. 'FROM `' . $this->prefix . 'feed` '
|
||||
. 'WHERE lastUpdate < ' . (time() - intval($cacheDuration))
|
||||
. ' ORDER BY lastUpdate';
|
||||
$stm = $this->bd->prepare ($sql);
|
||||
$stm->execute ();
|
||||
|
||||
@@ -220,6 +275,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
|
||||
|
||||
return $res[0]['count'];
|
||||
}
|
||||
|
||||
public function countNotRead ($id) {
|
||||
$sql = 'SELECT COUNT(*) AS count FROM `' . $this->prefix . 'entry` WHERE id_feed=? AND is_read=0';
|
||||
$stm = $this->bd->prepare ($sql);
|
||||
@@ -229,6 +285,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
|
||||
|
||||
return $res[0]['count'];
|
||||
}
|
||||
|
||||
public function updateCachedValues () { //For one single feed, call updateLastUpdate($id)
|
||||
$sql = 'UPDATE `' . $this->prefix . 'feed` f '
|
||||
. 'INNER JOIN ('
|
||||
@@ -241,9 +298,7 @@ class FreshRSS_FeedDAO extends Minz_ModelPdo {
|
||||
. 'SET f.cache_nbEntries=x.nbEntries, f.cache_nbUnreads=x.nbUnreads';
|
||||
$stm = $this->bd->prepare ($sql);
|
||||
|
||||
$values = array ($feed_id);
|
||||
|
||||
if ($stm && $stm->execute ($values)) {
|
||||
if ($stm && $stm->execute()) {
|
||||
return $stm->rowCount();
|
||||
} else {
|
||||
$info = $stm->errorInfo();
|
||||
|
||||
44
app/Models/Share.php
Normal file
44
app/Models/Share.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
class FreshRSS_Share {
|
||||
|
||||
static public function generateUrl($options, $selected, $link, $title) {
|
||||
$share = $options[$selected['type']];
|
||||
$matches = array(
|
||||
'~URL~',
|
||||
'~TITLE~',
|
||||
'~LINK~',
|
||||
);
|
||||
$replaces = array(
|
||||
$selected['url'],
|
||||
self::transformData($title, self::getTransform($share, 'title')),
|
||||
self::transformData($link, self::getTransform($share, 'link')),
|
||||
);
|
||||
$url = str_replace($matches, $replaces, $share['url']);
|
||||
return $url;
|
||||
}
|
||||
|
||||
static private function transformData($data, $transform) {
|
||||
if (!is_array($transform)) {
|
||||
return $data;
|
||||
}
|
||||
if (count($transform) === 0) {
|
||||
return $data;
|
||||
}
|
||||
foreach ($transform as $action) {
|
||||
$data = call_user_func($action, $data);
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
static private function getTransform($options, $type) {
|
||||
$transform = $options['transform'];
|
||||
|
||||
if (array_key_exists($type, $transform)) {
|
||||
return $transform[$type];
|
||||
}
|
||||
|
||||
return $transform;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -77,6 +77,7 @@ class FreshRSS_Themes extends Minz_Model {
|
||||
'down' => '▽',
|
||||
'favorite' => '★',
|
||||
'help' => 'ⓘ',
|
||||
'key' => '⚿',
|
||||
'link' => '↗',
|
||||
'login' => '🔒',
|
||||
'logout' => '🔓',
|
||||
@@ -84,6 +85,7 @@ class FreshRSS_Themes extends Minz_Model {
|
||||
'non-starred' => '☆',
|
||||
'prev' => '⏪',
|
||||
'read' => '☑',
|
||||
'rss' => '☄',
|
||||
'unread' => '☐',
|
||||
'refresh' => '🔃', //↻
|
||||
'search' => '🔍',
|
||||
@@ -91,6 +93,9 @@ class FreshRSS_Themes extends Minz_Model {
|
||||
'starred' => '★',
|
||||
'tag' => '⚐',
|
||||
'up' => '△',
|
||||
'view-normal' => '☰',
|
||||
'view-global' => '☷',
|
||||
'view-reader' => '☕',
|
||||
);
|
||||
if (!isset($alts[$name])) {
|
||||
return '';
|
||||
|
||||
@@ -1,21 +1,5 @@
|
||||
<?php
|
||||
require(dirname(__FILE__) . '/../constants.php');
|
||||
|
||||
//<Mutex>
|
||||
$lock = DATA_PATH . '/actualize.lock.txt';
|
||||
if (file_exists($lock) && ((time() - @filemtime($lock)) > 3600)) {
|
||||
@unlink($lock);
|
||||
}
|
||||
if (($handle = @fopen($lock, 'x')) === false) {
|
||||
syslog(LOG_NOTICE, 'FreshRSS actualize already running?');
|
||||
fwrite(STDERR, 'FreshRSS actualize already running?' . "\n");
|
||||
return;
|
||||
}
|
||||
register_shutdown_function('unlink', $lock);
|
||||
//Could use http://php.net/function.pcntl-signal.php to catch interruptions
|
||||
@fclose($handle);
|
||||
//</Mutex>
|
||||
|
||||
require(LIB_PATH . '/lib_rss.php'); //Includes class autoloader
|
||||
|
||||
session_cache_limiter('');
|
||||
@@ -32,7 +16,9 @@ $users = array_unique($users);
|
||||
|
||||
foreach ($users as $myUser) {
|
||||
syslog(LOG_INFO, 'FreshRSS actualize ' . $myUser);
|
||||
fwrite(STDOUT, 'Actualize ' . $myUser . "...\n"); //Unbuffered
|
||||
if (defined('STDOUT')) {
|
||||
fwrite(STDOUT, 'Actualize ' . $myUser . "...\n"); //Unbuffered
|
||||
}
|
||||
echo $myUser, ' '; //Buffered
|
||||
|
||||
$_GET['c'] = 'feed';
|
||||
@@ -42,7 +28,8 @@ foreach ($users as $myUser) {
|
||||
$_SERVER['HTTP_HOST'] = '';
|
||||
|
||||
$freshRSS = new FreshRSS();
|
||||
$freshRSS->_useOb(false);
|
||||
|
||||
Minz_Configuration::_authType('none');
|
||||
|
||||
Minz_Session::init('FreshRSS');
|
||||
Minz_Session::_param('currentUser', $myUser);
|
||||
@@ -50,10 +37,18 @@ foreach ($users as $myUser) {
|
||||
$freshRSS->init();
|
||||
$freshRSS->run();
|
||||
|
||||
invalidateHttpCache();
|
||||
if (!invalidateHttpCache()) {
|
||||
syslog(LOG_NOTICE, 'FreshRSS write access problem in ' . LOG_PATH . '/*.log!');
|
||||
if (defined('STDERR')) {
|
||||
fwrite(STDERR, 'Write access problem in ' . LOG_PATH . '/*.log!' . "\n");
|
||||
}
|
||||
}
|
||||
Minz_Session::unset_session(true);
|
||||
Minz_ModelPdo::clean();
|
||||
}
|
||||
syslog(LOG_INFO, 'FreshRSS actualize done.');
|
||||
if (defined('STDOUT')) {
|
||||
fwrite(STDOUT, 'Done.' . "\n");
|
||||
}
|
||||
echo 'End.', "\n";
|
||||
ob_end_flush();
|
||||
fwrite(STDOUT, 'Done.' . "\n");
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
return array (
|
||||
// LAYOUT
|
||||
'login' => 'Login',
|
||||
'login_with_persona' => 'Login with Persona',
|
||||
'logout' => 'Logout',
|
||||
'search' => 'Search words or #tags',
|
||||
'search_short' => 'Search',
|
||||
@@ -20,12 +21,13 @@ return array (
|
||||
'your_rss_feeds' => 'Your RSS feeds',
|
||||
'add_rss_feed' => 'Add a RSS feed',
|
||||
'no_rss_feed' => 'No RSS feed',
|
||||
'import_export_opml' => 'Import / export (OPML)',
|
||||
'import_export' => 'Import / export',
|
||||
'bookmark' => 'Subscribe (FreshRSS bookmark)',
|
||||
|
||||
'subscription_management' => 'Subscriptions management',
|
||||
'main_stream' => 'Main stream',
|
||||
'all_feeds' => 'All feeds',
|
||||
'favorite_feeds' => 'Favourites (%d)',
|
||||
'favorite_feeds' => 'Favourites (%s)',
|
||||
'not_read' => '%d unread',
|
||||
'not_reads' => '%d unread',
|
||||
|
||||
@@ -49,7 +51,8 @@ return array (
|
||||
'show_all_articles' => 'Show all articles',
|
||||
'show_not_reads' => 'Show only unread',
|
||||
'show_read' => 'Show only read',
|
||||
'show_favorite' => 'Show favorites',
|
||||
'show_favorite' => 'Show only favorites',
|
||||
'show_not_favorite' => 'Show all but favorites',
|
||||
'older_first' => 'Oldest first',
|
||||
'newer_first' => 'Newer first',
|
||||
|
||||
@@ -77,14 +80,17 @@ return array (
|
||||
'sharing_management' => 'Sharing options management',
|
||||
'bad_opml_file' => 'Your OPML file is invalid',
|
||||
'shortcuts_updated' => 'Shortcuts have been updated',
|
||||
'shortcuts_management' => 'Shortcuts management',
|
||||
'shortcuts_navigation' => 'Navigation',
|
||||
'shortcuts_navigation_help' => 'With the "Shift" modifier, navigation shortcuts apply on feeds.<br/>With the "Alt" modifier, navigation shortcuts apply on categories.',
|
||||
'shortcuts_article_action' => 'Article actions',
|
||||
'shortcuts_other_action' => 'Other actions',
|
||||
'feeds_marked_read' => 'Feeds have been marked as read',
|
||||
'updated' => 'Modifications have been updated',
|
||||
|
||||
'already_subscribed' => 'You have already subscribed to <em>%s</em>',
|
||||
'feed_added' => 'RSS feed <em>%s</em> has been added',
|
||||
'feed_not_added' => '<em>%s</em> could not be added',
|
||||
'internal_problem_feed' => 'The RSS feed could not be added. Check FressRSS logs for details.',
|
||||
'internal_problem_feed' => 'The RSS feed could not be added. <a href="%s">Check FressRSS logs</a> for details.',
|
||||
'invalid_url' => 'URL <em>%s</em> is invalid',
|
||||
'feed_actualized' => '<em>%s</em> has been updated',
|
||||
'n_feeds_actualized' => '%d feeds have been updated',
|
||||
@@ -121,23 +127,31 @@ return array (
|
||||
'javascript_for_shortcuts' => 'JavaScript must be enabled in order to use shortcuts',
|
||||
'javascript_should_be_activated'=> 'JavaScript must be enabled',
|
||||
'shift_for_all_read' => '+ <code>shift</code> to mark all articles as read',
|
||||
'see_on_website' => 'See article on its original website',
|
||||
'see_on_website' => 'See on original website',
|
||||
'next_article' => 'Skip to the next article',
|
||||
'shift_for_last' => '+ <code>shift</code> to skip to the last article of page',
|
||||
'last_article' => 'Skip to the last article',
|
||||
'previous_article' => 'Skip to the previous article',
|
||||
'shift_for_first' => '+ <code>shift</code> to skip to the first article of page',
|
||||
'first_article' => 'Skip to the first article',
|
||||
'next_page' => 'Skip to the next page',
|
||||
'previous_page' => 'Skip to the previous page',
|
||||
'collapse_article' => 'Collapse current article',
|
||||
'auto_share' => 'Share current article',
|
||||
'collapse_article' => 'Collapse',
|
||||
'auto_share' => 'Share',
|
||||
'auto_share_help' => 'If there is only one sharing mode, it is used. Else modes are accessible by their number.',
|
||||
'focus_search' => 'Access search box',
|
||||
|
||||
'file_to_import' => 'File to import',
|
||||
'file_to_import' => 'File to import<br />(OPML, Json or Zip)',
|
||||
'import' => 'Import',
|
||||
'export' => 'Export',
|
||||
'export_opml' => 'Export list of feeds (OPML)',
|
||||
'export_starred' => 'Export your favourites',
|
||||
'starred_list' => 'List of favourite articles',
|
||||
'feed_list' => 'List of %s articles',
|
||||
'or' => 'or',
|
||||
|
||||
'informations' => 'Information',
|
||||
'damn' => 'Damn!',
|
||||
'feed_in_error' => 'This feed has encountered a problem. Please verify that it is always reachable then actualize it.',
|
||||
'feed_empty' => 'This feed is empty. Please verify that it is still maintained.',
|
||||
'feed_description' => 'Description',
|
||||
'website_url' => 'Website URL',
|
||||
'feed_url' => 'Feed URL',
|
||||
@@ -158,6 +172,8 @@ return array (
|
||||
'http_username' => 'HTTP username',
|
||||
'http_password' => 'HTTP password',
|
||||
'blank_to_disable' => 'Leave blank to disable',
|
||||
'share_name' => 'Share name to display',
|
||||
'share_url' => 'Share URL to use',
|
||||
'not_yet_implemented' => 'Not yet implemented',
|
||||
'access_protected_feeds' => 'Connection allows to access HTTP protected RSS feeds',
|
||||
'no_selected_feed' => 'No feed selected.',
|
||||
@@ -166,8 +182,12 @@ return array (
|
||||
'current_user' => 'Current user',
|
||||
'default_user' => 'Username of the default user <small>(maximum 16 alphanumeric characters)</small>',
|
||||
'password_form' => 'Password<br /><small>(for the Web-form login method)</small>',
|
||||
'password_api' => 'Password API<br /><small>(e.g., for mobile apps)</small>',
|
||||
'persona_connection_email' => 'Login mail address<br /><small>(for <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>',
|
||||
'allow_anonymous' => 'Allow anonymous reading of the articles of the default user (%s)',
|
||||
'allow_anonymous_refresh' => 'Allow anonymous refresh of the articles',
|
||||
'unsafe_autologin' => 'Allow unsafe automatic login using the format: ',
|
||||
'api_enabled' => 'Allow <abbr>API</abbr> access <small>(required for mobile apps)</small>',
|
||||
'auth_token' => 'Authentication token',
|
||||
'explain_token' => 'Allows to access RSS output of the default user without authentication.<br /><kbd>%s?output=rss&token=%s</kbd>',
|
||||
'login_configuration' => 'Login',
|
||||
@@ -193,6 +213,7 @@ return array (
|
||||
'purge_completed' => 'Purge completed (%d articles deleted)',
|
||||
'archiving_configuration_help' => 'More options are available in the individual stream settings',
|
||||
'reading_configuration' => 'Reading',
|
||||
'display_configuration' => 'Display',
|
||||
'articles_per_page' => 'Number of articles per page',
|
||||
'default_view' => 'Default view',
|
||||
'sort_order' => 'Sort order',
|
||||
@@ -200,10 +221,11 @@ return array (
|
||||
'display_articles_unfolded' => 'Show articles unfolded by default',
|
||||
'after_onread' => 'After “mark all as read”,',
|
||||
'jump_next' => 'jump to next unread sibling (feed or category)',
|
||||
'reading_icons' => 'Reading icons',
|
||||
'article_icons' => 'Article icons',
|
||||
'top_line' => 'Top line',
|
||||
'bottom_line' => 'Bottom line',
|
||||
'img_with_lazyload' => 'Use "lazy load" mode to load pictures',
|
||||
'sticky_post' => 'Stick the article to the top when opened',
|
||||
'auto_read_when' => 'Mark article as read…',
|
||||
'article_selected' => 'when article is selected',
|
||||
'article_open_on_website' => 'when article is opened on its original website',
|
||||
@@ -218,9 +240,15 @@ return array (
|
||||
'optimize_bdd' => 'Optimize database',
|
||||
'optimize_todo_sometimes' => 'To do occasionally to reduce the size of the database',
|
||||
'theme' => 'Theme',
|
||||
'content_width' => 'Content width',
|
||||
'width_thin' => 'Thin',
|
||||
'width_medium' => 'Medium',
|
||||
'width_large' => 'Large',
|
||||
'width_no_limit' => 'No limit',
|
||||
'more_information' => 'More information',
|
||||
'activate_sharing' => 'Activate sharing',
|
||||
'shaarli' => 'Shaarli',
|
||||
'blogotext' => 'Blogotext',
|
||||
'wallabag' => 'wallabag',
|
||||
'diaspora' => 'Diaspora*',
|
||||
'twitter' => 'Twitter',
|
||||
@@ -241,6 +269,7 @@ return array (
|
||||
'rss_feeds_of' => 'RSS feed of %s',
|
||||
|
||||
'refresh' => 'Refresh',
|
||||
'no_feed_to_refresh' => 'There is no feed to refresh…',
|
||||
|
||||
'today' => 'Today',
|
||||
'yesterday' => 'Yesterday',
|
||||
@@ -267,7 +296,7 @@ return array (
|
||||
'logs_empty' => 'Log file is empty',
|
||||
'clear_logs' => 'Clear the logs',
|
||||
|
||||
'forbidden_access' => 'Access forbidden! (%s)',
|
||||
'forbidden_access' => 'Access is forbidden!',
|
||||
'login_required' => 'Login required:',
|
||||
|
||||
'confirm_action' => 'Are you sure you want to perform this action? It cannot be cancelled!',
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
return array (
|
||||
// LAYOUT
|
||||
'login' => 'Connexion',
|
||||
'login_with_persona' => 'Connexion avec Persona',
|
||||
'logout' => 'Déconnexion',
|
||||
'search' => 'Rechercher des mots ou des #tags',
|
||||
'search_short' => 'Rechercher',
|
||||
@@ -20,12 +21,13 @@ return array (
|
||||
'your_rss_feeds' => 'Vos flux RSS',
|
||||
'add_rss_feed' => 'Ajouter un flux RSS',
|
||||
'no_rss_feed' => 'Aucun flux RSS',
|
||||
'import_export_opml' => 'Importer / exporter (OPML)',
|
||||
'import_export' => 'Importer / exporter',
|
||||
'bookmark' => 'S’abonner (bookmark FreshRSS)',
|
||||
|
||||
'subscription_management' => 'Gestion des abonnements',
|
||||
'main_stream' => 'Flux principal',
|
||||
'all_feeds' => 'Tous les flux',
|
||||
'favorite_feeds' => 'Favoris (%d)',
|
||||
'favorite_feeds' => 'Favoris (%s)',
|
||||
'not_read' => '%d non lu',
|
||||
'not_reads' => '%d non lus',
|
||||
|
||||
@@ -50,6 +52,7 @@ return array (
|
||||
'show_not_reads' => 'Afficher les non lus',
|
||||
'show_read' => 'Afficher les lus',
|
||||
'show_favorite' => 'Afficher les favoris',
|
||||
'show_not_favorite' => 'Afficher tout sauf les favoris',
|
||||
'older_first' => 'Plus anciens en premier',
|
||||
'newer_first' => 'Plus récents en premier',
|
||||
|
||||
@@ -77,14 +80,17 @@ return array (
|
||||
'sharing_management' => 'Gestion des options de partage',
|
||||
'bad_opml_file' => 'Votre fichier OPML n’est pas valide',
|
||||
'shortcuts_updated' => 'Les raccourcis ont été mis à jour',
|
||||
'shortcuts_management' => 'Gestion des raccourcis',
|
||||
'shortcuts_navigation' => 'Navigation',
|
||||
'shortcuts_navigation_help' => 'Avec le modificateur "Shift", les raccourcis de navigation s’appliquent aux flux.<br/>Avec le modificateur "Alt", les raccourcis de navigation s’appliquent aux catégories.',
|
||||
'shortcuts_article_action' => 'Actions associées à l’article courant',
|
||||
'shortcuts_other_action' => 'Autres actions',
|
||||
'feeds_marked_read' => 'Les flux ont été marqués comme lus',
|
||||
'updated' => 'Modifications enregistrées',
|
||||
|
||||
'already_subscribed' => 'Vous êtes déjà abonné à <em>%s</em>',
|
||||
'feed_added' => 'Le flux <em>%s</em> a bien été ajouté',
|
||||
'feed_not_added' => '<em>%s</em> n’a pas pu être ajouté',
|
||||
'internal_problem_feed' => 'Le flux n’a pas pu être ajouté. Consulter les logs de FreshRSS pour plus de détails.',
|
||||
'internal_problem_feed' => 'Le flux ne peut pas être ajouté. <a href="%s">Consulter les logs de FreshRSS</a> pour plus de détails.',
|
||||
'invalid_url' => 'L’url <em>%s</em> est invalide',
|
||||
'feed_actualized' => '<em>%s</em> a été mis à jour',
|
||||
'n_feeds_actualized' => '%d flux ont été mis à jour',
|
||||
@@ -121,23 +127,31 @@ return array (
|
||||
'javascript_for_shortcuts' => 'Le JavaScript doit être activé pour pouvoir profiter des raccourcis',
|
||||
'javascript_should_be_activated'=> 'Le JavaScript doit être activé',
|
||||
'shift_for_all_read' => '+ <code>shift</code> pour marquer tous les articles comme lus',
|
||||
'see_on_website' => 'Voir l’article sur le site d’origine',
|
||||
'see_on_website' => 'Voir sur le site d’origine',
|
||||
'next_article' => 'Passer à l’article suivant',
|
||||
'shift_for_last' => '+ <code>shift</code> pour passer au dernier article de la page',
|
||||
'last_article' => 'Passer au dernier article',
|
||||
'previous_article' => 'Passer à l’article précédent',
|
||||
'shift_for_first' => '+ <code>shift</code> pour passer au premier article de la page',
|
||||
'first_article' => 'Passer au premier article',
|
||||
'next_page' => 'Passer à la page suivante',
|
||||
'previous_page' => 'Passer à la page précédente',
|
||||
'collapse_article' => 'Refermer l’article courant',
|
||||
'auto_share' => 'Partager l’article courant',
|
||||
'collapse_article' => 'Refermer',
|
||||
'auto_share' => 'Partager',
|
||||
'auto_share_help' => 'Si il n’y a qu’un mode de partage, celui ci est utilisé automatiquement. Sinon ils sont accessibles par leur numéro.',
|
||||
'focus_search' => 'Accéder à la recherche',
|
||||
|
||||
'file_to_import' => 'Fichier à importer',
|
||||
'file_to_import' => 'Fichier à importer<br />(OPML, Json ou Zip)',
|
||||
'import' => 'Importer',
|
||||
'export' => 'Exporter',
|
||||
'export_opml' => 'Exporter la liste des flux (OPML)',
|
||||
'export_starred' => 'Exporter les favoris',
|
||||
'starred_list' => 'Liste des articles favoris',
|
||||
'feed_list' => 'Liste des articles de %s',
|
||||
'or' => 'ou',
|
||||
|
||||
'informations' => 'Informations',
|
||||
'damn' => 'Arf !',
|
||||
'feed_in_error' => 'Ce flux a rencontré un problème. Veuillez vérifier qu’il est toujours accessible puis actualisez-le.',
|
||||
'feed_empty' => 'Ce flux est vide. Veuillez vérifier qu’il est toujours maintenu.',
|
||||
'feed_description' => 'Description',
|
||||
'website_url' => 'URL du site',
|
||||
'feed_url' => 'URL du flux',
|
||||
@@ -158,6 +172,8 @@ return array (
|
||||
'http_username' => 'Identifiant HTTP',
|
||||
'http_password' => 'Mot de passe HTTP',
|
||||
'blank_to_disable' => 'Laissez vide pour désactiver',
|
||||
'share_name' => 'Nom du partage à afficher',
|
||||
'share_url' => 'URL du partage à utiliser',
|
||||
'not_yet_implemented' => 'Pas encore implémenté',
|
||||
'access_protected_feeds' => 'La connexion permet d’accéder aux flux protégés par une authentification HTTP',
|
||||
'no_selected_feed' => 'Aucun flux sélectionné.',
|
||||
@@ -165,9 +181,13 @@ return array (
|
||||
|
||||
'current_user' => 'Utilisateur actuel',
|
||||
'password_form' => 'Mot de passe<br /><small>(pour connexion par formulaire)</small>',
|
||||
'password_api' => 'Mot de passe API<br /><small>(ex. : pour applis mobiles)</small>',
|
||||
'default_user' => 'Nom de l’utilisateur par défaut <small>(16 caractères alphanumériques maximum)</small>',
|
||||
'persona_connection_email' => 'Adresse courriel de connexion<br /><small>(pour <a href="https://persona.org/" rel="external">Mozilla Persona</a>)</small>',
|
||||
'allow_anonymous' => 'Autoriser la lecture anonyme des articles de l’utilisateur par défaut (%s)',
|
||||
'allow_anonymous_refresh' => 'Autoriser le rafraîchissement anonyme des flux',
|
||||
'unsafe_autologin' => 'Autoriser les connexion automatiques non-sûres au format : ',
|
||||
'api_enabled' => 'Autoriser l’accès par <abbr>API</abbr> <small>(nécessaire pour les applis mobiles)</small>',
|
||||
'auth_token' => 'Jeton d’identification',
|
||||
'explain_token' => 'Permet d’accéder à la sortie RSS de l’utilisateur par défaut sans besoin de s’authentifier.<br /><kbd>%s?output=rss&token=%s</kbd>',
|
||||
'login_configuration' => 'Identification',
|
||||
@@ -193,6 +213,7 @@ return array (
|
||||
'purge_completed' => 'Purge effectuée (%d articles supprimés)',
|
||||
'archiving_configuration_help' => 'D’autres options sont disponibles dans la configuration individuelle des flux',
|
||||
'reading_configuration' => 'Lecture',
|
||||
'display_configuration' => 'Affichage',
|
||||
'articles_per_page' => 'Nombre d’articles par page',
|
||||
'default_view' => 'Vue par défaut',
|
||||
'sort_order' => 'Ordre de tri',
|
||||
@@ -200,10 +221,11 @@ return array (
|
||||
'display_articles_unfolded' => 'Afficher les articles dépliés par défaut',
|
||||
'after_onread' => 'Après “marquer tout comme lu”,',
|
||||
'jump_next' => 'sauter au prochain voisin non lu (flux ou catégorie)',
|
||||
'reading_icons' => 'Icônes de lecture',
|
||||
'article_icons' => 'Icônes d’article',
|
||||
'top_line' => 'Ligne du haut',
|
||||
'bottom_line' => 'Ligne du bas',
|
||||
'img_with_lazyload' => 'Utiliser le mode “chargement différé” pour les images',
|
||||
'sticky_post' => 'Aligner l’article en haut quand il est ouvert',
|
||||
'auto_read_when' => 'Marquer un article comme lu…',
|
||||
'article_selected' => 'lorsque l’article est sélectionné',
|
||||
'article_open_on_website' => 'lorsque l’article est ouvert sur le site d’origine',
|
||||
@@ -218,9 +240,15 @@ return array (
|
||||
'optimize_bdd' => 'Optimiser la base de données',
|
||||
'optimize_todo_sometimes' => 'À faire de temps en temps pour réduire la taille de la BDD',
|
||||
'theme' => 'Thème',
|
||||
'content_width' => 'Largeur du contenu',
|
||||
'width_thin' => 'Fine',
|
||||
'width_medium' => 'Moyenne',
|
||||
'width_large' => 'Large',
|
||||
'width_no_limit' => 'Pas de limite',
|
||||
'more_information' => 'Plus d’informations',
|
||||
'activate_sharing' => 'Activer le partage',
|
||||
'shaarli' => 'Shaarli',
|
||||
'blogotext' => 'Blogotext',
|
||||
'wallabag' => 'wallabag',
|
||||
'diaspora' => 'Diaspora*',
|
||||
'twitter' => 'Twitter',
|
||||
@@ -241,6 +269,7 @@ return array (
|
||||
'rss_feeds_of' => 'Flux RSS de %s',
|
||||
|
||||
'refresh' => 'Actualisation',
|
||||
'no_feed_to_refresh' => 'Il n’y a aucun flux à actualiser…',
|
||||
|
||||
'today' => 'Aujourd’hui',
|
||||
'yesterday' => 'Hier',
|
||||
@@ -267,7 +296,7 @@ return array (
|
||||
'logs_empty' => 'Les logs sont vides',
|
||||
'clear_logs' => 'Effacer les logs',
|
||||
|
||||
'forbidden_access' => 'Accès interdit ! (%s)',
|
||||
'forbidden_access' => 'L’accès vous est interdit !',
|
||||
'login_required' => 'Accès protégé par mot de passe :',
|
||||
|
||||
'confirm_action' => 'Êtes-vous sûr(e) de vouloir continuer ? Cette action ne peut être annulée !',
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
<ul class="nav nav-list aside">
|
||||
<li class="nav-header"><?php echo Minz_Translate::t ('configuration'); ?></li>
|
||||
<li class="item<?php echo Minz_Request::actionName () == 'display' ? ' active' : ''; ?>">
|
||||
<a href="<?php echo _url ('configure', 'display'); ?>"><?php echo Minz_Translate::t ('reading_configuration'); ?></a>
|
||||
<a href="<?php echo _url ('configure', 'display'); ?>"><?php echo Minz_Translate::t ('display_configuration'); ?></a>
|
||||
</li>
|
||||
<li class="item<?php echo Minz_Request::actionName () == 'reading' ? ' active' : ''; ?>">
|
||||
<a href="<?php echo _url ('configure', 'reading'); ?>"><?php echo Minz_Translate::t ('reading_configuration'); ?></a>
|
||||
</li>
|
||||
<li class="item<?php echo Minz_Request::actionName () == 'archiving' ? ' active' : ''; ?>">
|
||||
<a href="<?php echo _url ('configure', 'archiving'); ?>"><?php echo Minz_Translate::t ('archiving_configuration'); ?></a>
|
||||
|
||||
@@ -20,9 +20,14 @@
|
||||
<?php echo $cat->name (); ?>
|
||||
</option>
|
||||
<?php } ?>
|
||||
<option value="nc"><?php echo Minz_Translate::t ('new_category'); ?></option>
|
||||
</select>
|
||||
</li>
|
||||
|
||||
<li class="input" style="display:none">
|
||||
<input type="text" name="new_category[name]" id="new_category_name" autocomplete="off" placeholder="<?php echo Minz_Translate::t ('new_category'); ?>" />
|
||||
</li>
|
||||
|
||||
<li class="separator"></li>
|
||||
|
||||
<li class="dropdown-header"><?php echo Minz_Translate::t ('http_authentication'); ?></li>
|
||||
@@ -38,8 +43,14 @@
|
||||
</div>
|
||||
</form></li>
|
||||
|
||||
<li class="item<?php echo Minz_Request::actionName () == 'importExport' ? ' active' : ''; ?>">
|
||||
<a href="<?php echo _url ('configure', 'importExport'); ?>"><?php echo Minz_Translate::t ('import_export_opml'); ?></a>
|
||||
<li class="item">
|
||||
<a onclick="return false;" href="javascript:(function(){var%20url%20=%20location.href;window.open('<?php echo Minz_Url::display(array('c' => 'feed', 'a' => 'add'), 'html', true); ?>&url_rss='+encodeURIComponent(url), '_blank');})();">
|
||||
<?php echo Minz_Translate::t('bookmark'); ?>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="item<?php echo Minz_Request::controllerName () == 'importExport' ? ' active' : ''; ?>">
|
||||
<a href="<?php echo _url ('importExport', 'index'); ?>"><?php echo Minz_Translate::t ('import_export'); ?></a>
|
||||
</li>
|
||||
|
||||
<li class="item<?php echo Minz_Request::actionName () == 'categorize' ? ' active' : ''; ?>">
|
||||
@@ -51,7 +62,7 @@
|
||||
<?php if (!empty ($this->feeds)) { ?>
|
||||
<?php foreach ($this->feeds as $feed) { ?>
|
||||
<?php $nbEntries = $feed->nbEntries (); ?>
|
||||
<li class="item<?php echo ($this->flux && $this->flux->id () == $feed->id ()) ? ' active' : ''; ?><?php echo $feed->inError () ? ' error' : ''; ?><?php echo $nbEntries == 0 ? ' empty' : ''; ?>">
|
||||
<li class="item<?php echo (isset($this->flux) && $this->flux->id () == $feed->id ()) ? ' active' : ''; ?><?php echo $feed->inError () ? ' error' : ''; ?><?php echo $nbEntries == 0 ? ' empty' : ''; ?>">
|
||||
<a href="<?php echo _url ('configure', 'feed', 'id', $feed->id ()); ?>">
|
||||
<img class="favicon" src="<?php echo $feed->favicon (); ?>" alt="✇" />
|
||||
<?php echo $feed->name (); ?>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
}
|
||||
?>
|
||||
<li>
|
||||
<div class="category all">
|
||||
<div class="category all<?php echo $this->get_c == 'a' ? ' active' : ''; ?>">
|
||||
<a data-unread="<?php echo formatNumber($this->nb_not_read); ?>" class="btn<?php echo $this->get_c == 'a' ? ' active' : ''; ?>" href="<?php echo Minz_Url::display($arUrl); ?>">
|
||||
<?php echo FreshRSS_Themes::icon('all'); ?>
|
||||
<?php echo Minz_Translate::t ('main_stream'); ?>
|
||||
@@ -29,7 +29,7 @@
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<div class="category favorites">
|
||||
<div class="category favorites<?php echo $this->get_c == 's' ? ' active' : ''; ?>">
|
||||
<a data-unread="<?php echo formatNumber($this->nb_favorites['unread']); ?>" class="btn<?php echo $this->get_c == 's' ? ' active' : ''; ?>" href="<?php $arUrl['params']['get'] = 's'; echo Minz_Url::display($arUrl); ?>">
|
||||
<?php echo FreshRSS_Themes::icon('bookmark'); ?>
|
||||
<?php echo Minz_Translate::t('favorite_feeds', formatNumber($this->nb_favorites['all'])); ?>
|
||||
|
||||
@@ -67,7 +67,8 @@ if (Minz_Configuration::canLogIn()) {
|
||||
<ul class="dropdown-menu">
|
||||
<li class="dropdown-close"><a href="#close">❌</a></li>
|
||||
<li class="dropdown-header"><?php echo Minz_Translate::t ('configuration'); ?></li>
|
||||
<li class="item"><a href="<?php echo _url ('configure', 'display'); ?>"><?php echo Minz_Translate::t ('reading_configuration'); ?></a></li>
|
||||
<li class="item"><a href="<?php echo _url ('configure', 'display'); ?>"><?php echo Minz_Translate::t ('display_configuration'); ?></a></li>
|
||||
<li class="item"><a href="<?php echo _url ('configure', 'reading'); ?>"><?php echo Minz_Translate::t ('reading_configuration'); ?></a></li>
|
||||
<li class="item"><a href="<?php echo _url ('configure', 'archiving'); ?>"><?php echo Minz_Translate::t ('archiving_configuration'); ?></a></li>
|
||||
<li class="item"><a href="<?php echo _url ('configure', 'sharing'); ?>"><?php echo Minz_Translate::t ('sharing'); ?></a></li>
|
||||
<li class="item"><a href="<?php echo _url ('configure', 'shortcut'); ?>"><?php echo Minz_Translate::t ('shortcuts'); ?></a></li>
|
||||
@@ -75,8 +76,8 @@ if (Minz_Configuration::canLogIn()) {
|
||||
<li class="item"><a href="<?php echo _url ('configure', 'users'); ?>"><?php echo Minz_Translate::t ('users'); ?></a></li>
|
||||
<li class="separator"></li>
|
||||
<li class="item"><a href="<?php echo _url ('index', 'stats'); ?>"><?php echo Minz_Translate::t ('stats'); ?></a></li>
|
||||
<li class="item"><a href="<?php echo _url ('index', 'about'); ?>"><?php echo Minz_Translate::t ('about'); ?></a></li>
|
||||
<li class="item"><a href="<?php echo _url ('index', 'logs'); ?>"><?php echo Minz_Translate::t ('logs'); ?></a></li>
|
||||
<li class="item"><a href="<?php echo _url ('index', 'about'); ?>"><?php echo Minz_Translate::t ('about'); ?></a></li>
|
||||
<?php
|
||||
if (Minz_Configuration::canLogIn()) {
|
||||
?><li class="separator"></li><?php
|
||||
|
||||
@@ -3,46 +3,59 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="initial-scale=1.0" />
|
||||
<?php echo self::headTitle (); ?>
|
||||
<?php echo self::headStyle (); ?>
|
||||
<?php echo self::headScript (); ?>
|
||||
<?php echo self::headTitle(); ?>
|
||||
<?php echo self::headStyle(); ?>
|
||||
<?php echo self::headScript(); ?>
|
||||
<script>//<![CDATA[
|
||||
<?php $this->renderHelper ('javascript_vars'); ?>
|
||||
<?php $this->renderHelper('javascript_vars'); ?>
|
||||
//]]></script>
|
||||
<?php
|
||||
if (!empty($this->nextId)) {
|
||||
$params = Minz_Request::params ();
|
||||
$params = Minz_Request::params();
|
||||
$params['next'] = $this->nextId;
|
||||
?>
|
||||
<link id="prefetch" rel="next prefetch" href="<?php echo Minz_Url::display (array ('c' => Minz_Request::controllerName (), 'a' => Minz_Request::actionName (), 'params' => $params)); ?>" />
|
||||
<link id="prefetch" rel="next prefetch" href="<?php echo Minz_Url::display(array('c' => Minz_Request::controllerName(), 'a' => Minz_Request::actionName(), 'params' => $params)); ?>" />
|
||||
<?php } ?>
|
||||
<link rel="shortcut icon" type="image/x-icon" sizes="16x16 64x64" href="<?php echo Minz_Url::display('/favicon.ico'); ?>" />
|
||||
<link rel="icon msapplication-TileImage apple-touch-icon" type="image/png" sizes="256x256" href="<?php echo Minz_Url::display('/themes/icons/favicon-256.png'); ?>" />
|
||||
<?php if (isset ($this->rss_url)) { ?>
|
||||
<link rel="alternate" type="application/rss+xml" title="<?php echo $this->rss_title; ?>" href="<?php echo Minz_Url::display ($this->rss_url); ?>" />
|
||||
<?php
|
||||
if (isset($this->url)) {
|
||||
$rss_url = $this->url;
|
||||
$rss_url['params']['output'] = 'rss';
|
||||
?>
|
||||
<link rel="alternate" type="application/rss+xml" title="<?php echo $this->rss_title; ?>" href="<?php echo Minz_Url::display($rss_url); ?>" />
|
||||
<?php } ?>
|
||||
<link rel="prefetch" href="<?php echo FreshRSS_Themes::icon('starred', true); ?>">
|
||||
<link rel="prefetch" href="<?php echo FreshRSS_Themes::icon('non-starred', true); ?>">
|
||||
<link rel="prefetch" href="<?php echo FreshRSS_Themes::icon('read', true); ?>">
|
||||
<link rel="prefetch" href="<?php echo FreshRSS_Themes::icon('unread', true); ?>">
|
||||
<link rel="apple-touch-icon" href="<?php echo Minz_Url::display('/themes/icons/apple-touch-icon.png'); ?>">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
|
||||
<meta name="apple-mobile-web-app-title" content="<?php echo Minz_Configuration::title(); ?>">
|
||||
<meta name="msapplication-TileColor" content="#FFF" />
|
||||
<meta name="robots" content="noindex,nofollow" />
|
||||
</head>
|
||||
<body class="<?php echo Minz_Request::param('output', 'normal'); ?>">
|
||||
<?php $this->partial ('header'); ?>
|
||||
<?php $this->partial('header'); ?>
|
||||
|
||||
<div id="global">
|
||||
<?php $this->render (); ?>
|
||||
<?php $this->render(); ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
if (isset ($this->notification)) {
|
||||
$msg = '';
|
||||
$status = 'closed';
|
||||
if (isset($this->notification)) {
|
||||
$msg = $this->notification['content'];
|
||||
$status = $this->notification['type'];
|
||||
|
||||
invalidateHttpCache();
|
||||
}
|
||||
?>
|
||||
<div class="notification <?php echo $this->notification['type']; ?>">
|
||||
<?php echo $this->notification['content']; ?>
|
||||
<div id="notification" class="notification <?php echo $status; ?>">
|
||||
<span class="msg"><?php echo $msg; ?></span>
|
||||
<a class="close" href=""><?php echo FreshRSS_Themes::icon('close'); ?></a>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,8 +7,80 @@
|
||||
<?php } ?>
|
||||
|
||||
<?php if ($this->loginOk) { ?>
|
||||
<a id="actualize" class="btn" href="<?php echo _url ('feed', 'actualize'); ?>"><?php echo FreshRSS_Themes::icon('refresh'); ?></a>
|
||||
|
||||
<?php $url_state = $this->url;
|
||||
if ($this->state & FreshRSS_Entry::STATE_READ) {
|
||||
$url_state['params']['state'] = $this->state & ~FreshRSS_Entry::STATE_READ;
|
||||
$checked = 'true';
|
||||
$class = 'active';
|
||||
} else {
|
||||
$url_state['params']['state'] = $this->state | FreshRSS_Entry::STATE_READ;
|
||||
$checked = 'false';
|
||||
$class = '';
|
||||
}
|
||||
?>
|
||||
<div class="stick">
|
||||
<a id="toggle-read"
|
||||
class="btn <?php echo $class; ?>"
|
||||
aria-checked="<?php echo $checked; ?>"
|
||||
href="<?php echo Minz_Url::display ($url_state); ?>"
|
||||
title="<?php echo Minz_Translate::t ('show_read'); ?>">
|
||||
<?php echo FreshRSS_Themes::icon('read'); ?>
|
||||
</a>
|
||||
<?php
|
||||
if ($this->state & FreshRSS_Entry::STATE_NOT_READ) {
|
||||
$url_state['params']['state'] = $this->state & ~FreshRSS_Entry::STATE_NOT_READ;
|
||||
$checked = 'true';
|
||||
$class = 'active';
|
||||
} else {
|
||||
$url_state['params']['state'] = $this->state | FreshRSS_Entry::STATE_NOT_READ;
|
||||
$checked = 'false';
|
||||
$class = '';
|
||||
}
|
||||
?>
|
||||
<a id="toggle-unread"
|
||||
class="btn <?php echo $class; ?>"
|
||||
aria-checked="<?php echo $checked; ?>"
|
||||
href="<?php echo Minz_Url::display ($url_state); ?>"
|
||||
title="<?php echo Minz_Translate::t ('show_not_reads'); ?>">
|
||||
<?php echo FreshRSS_Themes::icon('unread'); ?>
|
||||
</a>
|
||||
<?php
|
||||
if ($this->state & FreshRSS_Entry::STATE_FAVORITE) {
|
||||
$url_state['params']['state'] = $this->state & ~FreshRSS_Entry::STATE_FAVORITE;
|
||||
$checked = 'true';
|
||||
$class = 'active';
|
||||
} else {
|
||||
$url_state['params']['state'] = $this->state | FreshRSS_Entry::STATE_FAVORITE;
|
||||
$checked = 'false';
|
||||
$class = '';
|
||||
}
|
||||
?>
|
||||
<a id="toggle-favorite"
|
||||
class="btn <?php echo $class; ?>"
|
||||
aria-checked="<?php echo $checked; ?>"
|
||||
href="<?php echo Minz_Url::display ($url_state); ?>"
|
||||
title="<?php echo Minz_Translate::t ('show_favorite'); ?>">
|
||||
<?php echo FreshRSS_Themes::icon('starred'); ?>
|
||||
</a>
|
||||
<?php
|
||||
if ($this->state & FreshRSS_Entry::STATE_NOT_FAVORITE) {
|
||||
$url_state['params']['state'] = $this->state & ~FreshRSS_Entry::STATE_NOT_FAVORITE;
|
||||
$checked = 'true';
|
||||
$class = 'active';
|
||||
} else {
|
||||
$url_state['params']['state'] = $this->state | FreshRSS_Entry::STATE_NOT_FAVORITE;
|
||||
$checked = 'false';
|
||||
$class = '';
|
||||
}
|
||||
?>
|
||||
<a id="toggle-not-favorite"
|
||||
class="btn <?php echo $class; ?>"
|
||||
aria-checked="<?php echo $checked; ?>"
|
||||
href="<?php echo Minz_Url::display ($url_state); ?>"
|
||||
title="<?php echo Minz_Translate::t ('show_not_favorite'); ?>">
|
||||
<?php echo FreshRSS_Themes::icon('non-starred'); ?>
|
||||
</a>
|
||||
</div>
|
||||
<?php
|
||||
$get = false;
|
||||
$string_mark = Minz_Translate::t ('mark_all_read');
|
||||
@@ -59,8 +131,12 @@
|
||||
break;
|
||||
}
|
||||
}
|
||||
$p = isset($this->entries[0]) ? $this->entries[0] : null;
|
||||
$idMax = $p === null ? '0' : $p->id();
|
||||
if ($this->order === 'ASC') {
|
||||
$idMax = 0;
|
||||
} else {
|
||||
$p = isset($this->entries[0]) ? $this->entries[0] : null;
|
||||
$idMax = $p === null ? '0' : $p->id();
|
||||
}
|
||||
|
||||
$arUrl = array('c' => 'entry', 'a' => 'read', 'params' => array('get' => $get, 'nextGet' => $nextGet, 'idMax' => $idMax));
|
||||
$output = Minz_Request::param('output', '');
|
||||
@@ -80,7 +156,7 @@
|
||||
<ul class="dropdown-menu">
|
||||
<li class="dropdown-close"><a href="#close">❌</a></li>
|
||||
|
||||
<li class="item"><a href="<?php echo $markReadUrl; ?>"><?php echo $string_mark; ?></a></li>
|
||||
<li class="item"><a href="<?php echo $markReadUrl; ?>"><?php echo $string_mark; ?></a></li>
|
||||
<li class="separator"></li>
|
||||
<?php
|
||||
$today = $this->today;
|
||||
@@ -93,113 +169,30 @@
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<?php
|
||||
$params = Minz_Request::params ();
|
||||
if (isset ($params['search'])) {
|
||||
$params['search'] = urlencode ($params['search']);
|
||||
}
|
||||
$url = array (
|
||||
'c' => 'index',
|
||||
'a' => 'index',
|
||||
'params' => $params
|
||||
);
|
||||
?>
|
||||
<div class="dropdown" id="nav_menu_views">
|
||||
<div id="dropdown-views" class="dropdown-target"></div>
|
||||
<a class="dropdown-toggle btn" href="#dropdown-views"><?php echo Minz_Translate::t ('display'); ?> <?php echo FreshRSS_Themes::icon('down'); ?></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li class="dropdown-close"><a href="#close">❌</a></li>
|
||||
<?php $url_output = $this->url; ?>
|
||||
<div class="stick" id="nav_menu_views">
|
||||
<?php $url_output['params']['output'] = 'normal'; ?>
|
||||
<a class="view_normal btn <?php echo $actual_view == 'normal'? 'active' : ''; ?>" title="<?php echo Minz_Translate::t('normal_view'); ?>" href="<?php echo Minz_Url::display($url_output); ?>">
|
||||
<?php echo FreshRSS_Themes::icon("view-normal"); ?>
|
||||
</a>
|
||||
|
||||
<?php
|
||||
$url_output = $url;
|
||||
if ($actual_view !== 'normal') { ?>
|
||||
<li class="item">
|
||||
<?php $url_output['params']['output'] = 'normal'; ?>
|
||||
<a class="view_normal" href="<?php echo Minz_Url::display ($url_output); ?>">
|
||||
<?php echo Minz_Translate::t ('normal_view'); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php } if($actual_view !== 'reader') { ?>
|
||||
<li class="item">
|
||||
<?php $url_output['params']['output'] = 'reader'; ?>
|
||||
<a class="view_normal" href="<?php echo Minz_Url::display ($url_output); ?>">
|
||||
<?php echo Minz_Translate::t ('reader_view'); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php } if($actual_view !== 'global') { ?>
|
||||
<li class="item">
|
||||
<?php $url_output['params']['output'] = 'global'; ?>
|
||||
<a class="view_normal" href="<?php echo Minz_Url::display ($url_output); ?>">
|
||||
<?php echo Minz_Translate::t ('global_view'); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php } ?>
|
||||
<?php $url_output['params']['output'] = 'global'; ?>
|
||||
<a class="view_global btn <?php echo $actual_view == 'global'? 'active' : ''; ?>" title="<?php echo Minz_Translate::t('global_view'); ?>" href="<?php echo Minz_Url::display($url_output); ?>">
|
||||
<?php echo FreshRSS_Themes::icon("view-global"); ?>
|
||||
</a>
|
||||
|
||||
<li class="separator"></li>
|
||||
<?php $url_output['params']['output'] = 'reader'; ?>
|
||||
<a class="view_reader btn <?php echo $actual_view == 'reader'? 'active' : ''; ?>" title="<?php echo Minz_Translate::t('reader_view'); ?>" href="<?php echo Minz_Url::display($url_output); ?>">
|
||||
<?php echo FreshRSS_Themes::icon("view-reader"); ?>
|
||||
</a>
|
||||
|
||||
<?php
|
||||
$url_state = $url;
|
||||
$url_state['params']['state'] = 'all';
|
||||
?>
|
||||
<li class="item" role="checkbox" aria-checked="<?php echo ($this->state === 'all') ? 'true' :'false'; ?>">
|
||||
<a class="print_all" href="<?php echo Minz_Url::display ($url_state); ?>">
|
||||
<?php echo Minz_Translate::t ('show_all_articles'); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
$url_state['params']['state'] = 'not_read';
|
||||
?>
|
||||
<li class="item" role="checkbox" aria-checked="<?php echo ($this->state === 'not_read') ? 'true' :'false'; ?>">
|
||||
<a class="print_non_read" href="<?php echo Minz_Url::display ($url_state); ?>">
|
||||
<?php echo Minz_Translate::t ('show_not_reads'); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
$url_state['params']['state'] = 'read';
|
||||
?>
|
||||
<li class="item" role="checkbox" aria-checked="<?php echo ($this->state === 'read') ? 'true' :'false'; ?>">
|
||||
<a class="print_read" href="<?php echo Minz_Url::display ($url_state); ?>">
|
||||
<?php echo Minz_Translate::t ('show_read'); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php
|
||||
$url_state['params']['state'] = 'favorite';
|
||||
?>
|
||||
<li class="item" role="checkbox" aria-checked="<?php echo ($this->state === 'favorite') ? 'true' :'false'; ?>">
|
||||
<a class="print_favorite" href="<?php echo Minz_Url::display ($url_state); ?>">
|
||||
<?php echo Minz_Translate::t ('show_favorite'); ?>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="separator"></li>
|
||||
|
||||
<li class="item">
|
||||
<?php
|
||||
$url_order = $url;
|
||||
if ($this->order === 'DESC') {
|
||||
$url_order['params']['order'] = 'ASC';
|
||||
?>
|
||||
<a href="<?php echo Minz_Url::display ($url_order); ?>">
|
||||
<?php echo Minz_Translate::t ('older_first'); ?>
|
||||
</a>
|
||||
<?php
|
||||
} else {
|
||||
$url_order['params']['order'] = 'DESC';
|
||||
?>
|
||||
<a href="<?php echo Minz_Url::display ($url_order); ?>">
|
||||
<?php echo Minz_Translate::t ('newer_first'); ?>
|
||||
</a>
|
||||
<?php } ?>
|
||||
</li>
|
||||
|
||||
<li class="separator"></li>
|
||||
|
||||
<li class="item">
|
||||
<a class="view_rss" target="_blank" href="<?php echo Minz_Url::display ($this->rss_url); ?>">
|
||||
<?php echo Minz_Translate::t ('rss_view'); ?>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<?php
|
||||
$url_output['params']['output'] = 'rss';
|
||||
$url_output['params']['token'] = $this->conf->token;
|
||||
?>
|
||||
<a class="view_rss btn" target="_blank" title="<?php echo Minz_Translate::t ('rss_view'); ?>" href="<?php echo Minz_Url::display($url_output); ?>">
|
||||
<?php echo FreshRSS_Themes::icon('rss'); ?>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="item search">
|
||||
@@ -223,4 +216,25 @@
|
||||
<?php } ?>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
if ($this->order === 'DESC') {
|
||||
$order = 'ASC';
|
||||
$icon = 'up';
|
||||
$title = 'older_first';
|
||||
} else {
|
||||
$order = 'DESC';
|
||||
$icon = 'down';
|
||||
$title = 'newer_first';
|
||||
}
|
||||
$url_order = $this->url;
|
||||
$url_order['params']['order'] = $order;
|
||||
?>
|
||||
<a class="btn" href="<?php echo Minz_Url::display ($url_order); ?>" title="<?php echo Minz_Translate::t ($title); ?>">
|
||||
<?php echo FreshRSS_Themes::icon($icon); ?>
|
||||
</a>
|
||||
|
||||
<?php if ($this->loginOk || Minz_Configuration::allowAnonymousRefresh()) { ?>
|
||||
<a id="actualize" class="btn" href="<?php echo _url ('feed', 'actualize'); ?>"><?php echo FreshRSS_Themes::icon('refresh'); ?></a>
|
||||
<?php } ?>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,6 @@ define('SQL_CREATE_TABLES', '
|
||||
CREATE TABLE IF NOT EXISTS `%1$scategory` (
|
||||
`id` SMALLINT NOT NULL AUTO_INCREMENT, -- v0.7
|
||||
`name` varchar(255) NOT NULL,
|
||||
`color` char(7),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY (`name`) -- v0.7
|
||||
) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci
|
||||
|
||||
@@ -14,14 +14,16 @@
|
||||
<?php echo Minz_Translate::t ('category_number', $i); ?>
|
||||
</label>
|
||||
<div class="group-controls">
|
||||
<input type="text" id="cat_<?php echo $cat->id (); ?>" name="categories[]" value="<?php echo $cat->name (); ?>" />
|
||||
<div class="stick">
|
||||
<input type="text" id="cat_<?php echo $cat->id (); ?>" name="categories[]" value="<?php echo $cat->name (); ?>" />
|
||||
|
||||
<?php if ($cat->nbFeed () > 0) { ?>
|
||||
<a class="confirm" href="<?php echo _url ('feed', 'delete', 'id', $cat->id (), 'type', 'category'); ?>"><?php echo Minz_Translate::t ('ask_empty'); ?></a>
|
||||
<?php } ?>
|
||||
<?php if ($cat->nbFeed () > 0) { ?>
|
||||
<button type="submit" class="btn btn-attention confirm" formaction="<?php echo _url ('feed', 'delete', 'id', $cat->id (), 'type', 'category'); ?>"><?php echo Minz_Translate::t ('ask_empty'); ?></button>
|
||||
<?php } ?>
|
||||
</div>
|
||||
(<?php echo Minz_Translate::t ('number_feeds', $cat->nbFeed ()); ?>)
|
||||
|
||||
<?php if ($cat->id () == $this->defaultCategory->id ()) { ?>
|
||||
<?php if ($cat->id () === $this->defaultCategory->id ()) { ?>
|
||||
<?php echo FreshRSS_Themes::icon('help'); ?> <?php echo Minz_Translate::t ('can_not_be_deleted'); ?>
|
||||
<?php } ?>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<a href="<?php echo _url ('index', 'index'); ?>"><?php echo Minz_Translate::t ('back_to_rss_feeds'); ?></a>
|
||||
|
||||
<form method="post" action="<?php echo _url ('configure', 'display'); ?>">
|
||||
<legend><?php echo Minz_Translate::t ('theme'); ?></legend>
|
||||
<legend><?php echo Minz_Translate::t ('display_configuration'); ?></legend>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="language"><?php echo Minz_Translate::t ('language'); ?></label>
|
||||
@@ -35,122 +35,29 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group form-actions">
|
||||
<div class="group-controls">
|
||||
<button type="submit" class="btn btn-important"><?php echo Minz_Translate::t ('save'); ?></button>
|
||||
<button type="reset" class="btn"><?php echo Minz_Translate::t ('cancel'); ?></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<legend><?php echo Minz_Translate::t ('reading_configuration'); ?></legend>
|
||||
|
||||
<?php $width = $this->conf->content_width; ?>
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="posts_per_page"><?php echo Minz_Translate::t ('articles_per_page'); ?></label>
|
||||
<label class="group-name" for="content_width"><?php echo Minz_Translate::t('content_width'); ?></label>
|
||||
<div class="group-controls">
|
||||
<input type="number" id="posts_per_page" name="posts_per_page" value="<?php echo $this->conf->posts_per_page; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="sort_order"><?php echo Minz_Translate::t ('sort_order'); ?></label>
|
||||
<div class="group-controls">
|
||||
<select name="sort_order" id="sort_order">
|
||||
<option value="DESC"<?php echo $this->conf->sort_order === 'DESC' ? ' selected="selected"' : ''; ?>><?php echo Minz_Translate::t ('newer_first'); ?></option>
|
||||
<option value="ASC"<?php echo $this->conf->sort_order === 'ASC' ? ' selected="selected"' : ''; ?>><?php echo Minz_Translate::t ('older_first'); ?></option>
|
||||
<select name="content_width" id="content_width" required="">
|
||||
<option value="thin" <?php echo $width === 'thin'? 'selected="selected"' : ''; ?>>
|
||||
<?php echo Minz_Translate::t('width_thin'); ?>
|
||||
</option>
|
||||
<option value="medium" <?php echo $width === 'medium'? 'selected="selected"' : ''; ?>>
|
||||
<?php echo Minz_Translate::t('width_medium'); ?>
|
||||
</option>
|
||||
<option value="large" <?php echo $width === 'large'? 'selected="selected"' : ''; ?>>
|
||||
<?php echo Minz_Translate::t('width_large'); ?>
|
||||
</option>
|
||||
<option value="no_limit" <?php echo $width === 'no_limit'? 'selected="selected"' : ''; ?>>
|
||||
<?php echo Minz_Translate::t('width_no_limit'); ?>
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="view_mode"><?php echo Minz_Translate::t ('default_view'); ?></label>
|
||||
<div class="group-controls">
|
||||
<select name="view_mode" id="view_mode">
|
||||
<option value="normal"<?php echo $this->conf->view_mode === 'normal' ? ' selected="selected"' : ''; ?>><?php echo Minz_Translate::t ('normal_view'); ?></option>
|
||||
<option value="reader"<?php echo $this->conf->view_mode === 'reader' ? ' selected="selected"' : ''; ?>><?php echo Minz_Translate::t ('reader_view'); ?></option>
|
||||
<option value="global"<?php echo $this->conf->view_mode === 'global' ? ' selected="selected"' : ''; ?>><?php echo Minz_Translate::t ('global_view'); ?></option>
|
||||
</select>
|
||||
<label class="radio" for="radio_all">
|
||||
<input type="radio" name="default_view" id="radio_all" value="all"<?php echo $this->conf->default_view === 'all' ? ' checked="checked"' : ''; ?> />
|
||||
<?php echo Minz_Translate::t ('show_all_articles'); ?>
|
||||
</label>
|
||||
<label class="radio" for="radio_not_read">
|
||||
<input type="radio" name="default_view" id="radio_not_read" value="not_read"<?php echo $this->conf->default_view === 'not_read' ? ' checked="checked"' : ''; ?> />
|
||||
<?php echo Minz_Translate::t ('show_not_reads'); ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="group-controls">
|
||||
<label class="checkbox" for="auto_load_more">
|
||||
<input type="checkbox" name="auto_load_more" id="auto_load_more" value="1"<?php echo $this->conf->auto_load_more ? ' checked="checked"' : ''; ?> />
|
||||
<?php echo Minz_Translate::t ('auto_load_more'); ?>
|
||||
<noscript> — <strong><?php echo Minz_Translate::t ('javascript_should_be_activated'); ?></strong></noscript>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="group-controls">
|
||||
<label class="checkbox" for="display_posts">
|
||||
<input type="checkbox" name="display_posts" id="display_posts" value="1"<?php echo $this->conf->display_posts ? ' checked="checked"' : ''; ?> />
|
||||
<?php echo Minz_Translate::t ('display_articles_unfolded'); ?>
|
||||
<noscript> — <strong><?php echo Minz_Translate::t ('javascript_should_be_activated'); ?></strong></noscript>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="group-controls">
|
||||
<label class="checkbox" for="lazyload">
|
||||
<input type="checkbox" name="lazyload" id="lazyload" value="1"<?php echo $this->conf->lazyload ? ' checked="checked"' : ''; ?> />
|
||||
<?php echo Minz_Translate::t ('img_with_lazyload'); ?>
|
||||
<noscript> — <strong><?php echo Minz_Translate::t ('javascript_should_be_activated'); ?></strong></noscript>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name"><?php echo Minz_Translate::t ('auto_read_when'); ?></label>
|
||||
<div class="group-controls">
|
||||
<label class="checkbox" for="check_open_article">
|
||||
<input type="checkbox" name="mark_open_article" id="check_open_article" value="1"<?php echo $this->conf->mark_when['article'] ? ' checked="checked"' : ''; ?> />
|
||||
<?php echo Minz_Translate::t ('article_selected'); ?>
|
||||
</label>
|
||||
<label class="checkbox" for="check_open_site">
|
||||
<input type="checkbox" name="mark_open_site" id="check_open_site" value="1"<?php echo $this->conf->mark_when['site'] ? ' checked="checked"' : ''; ?> />
|
||||
<?php echo Minz_Translate::t ('article_open_on_website'); ?>
|
||||
</label>
|
||||
<label class="checkbox" for="check_scroll">
|
||||
<input type="checkbox" name="mark_scroll" id="check_scroll" value="1"<?php echo $this->conf->mark_when['scroll'] ? ' checked="checked"' : ''; ?> />
|
||||
<?php echo Minz_Translate::t ('scroll'); ?>
|
||||
</label>
|
||||
<label class="checkbox" for="check_reception">
|
||||
<input type="checkbox" name="mark_upon_reception" id="check_reception" value="1"<?php echo $this->conf->mark_when['reception'] ? ' checked="checked"' : ''; ?> />
|
||||
<?php echo Minz_Translate::t ('upon_reception'); ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name"><?php echo Minz_Translate::t ('after_onread'); ?></label>
|
||||
<div class="group-controls">
|
||||
<label class="checkbox" for="onread_jump_next">
|
||||
<input type="checkbox" name="onread_jump_next" id="onread_jump_next" value="1"<?php echo $this->conf->onread_jump_next ? ' checked="checked"' : ''; ?> />
|
||||
<?php echo Minz_Translate::t ('jump_next'); ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group form-actions">
|
||||
<div class="group-controls">
|
||||
<button type="submit" class="btn btn-important"><?php echo Minz_Translate::t ('save'); ?></button>
|
||||
<button type="reset" class="btn"><?php echo Minz_Translate::t ('cancel'); ?></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<legend><?php echo Minz_Translate::t ('reading_icons'); ?></legend>
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="theme"><?php echo Minz_Translate::t ('article_icons'); ?></label>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
@@ -7,8 +7,12 @@
|
||||
<h1><?php echo $this->flux->name (); ?></h1>
|
||||
<?php echo $this->flux->description (); ?>
|
||||
|
||||
<?php $nbEntries = $this->flux->nbEntries (); ?>
|
||||
|
||||
<?php if ($this->flux->inError ()) { ?>
|
||||
<p class="alert alert-error"><span class="alert-head"><?php echo Minz_Translate::t ('damn'); ?></span> <?php echo Minz_Translate::t ('feed_in_error'); ?></p>
|
||||
<?php } elseif ($nbEntries === 0) { ?>
|
||||
<p class="alert alert-warn"><?php echo Minz_Translate::t ('feed_empty'); ?></p>
|
||||
<?php } ?>
|
||||
|
||||
<form method="post" action="<?php echo _url ('configure', 'feed', 'id', $this->flux->id ()); ?>" autocomplete="off">
|
||||
@@ -28,16 +32,21 @@
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="website"><?php echo Minz_Translate::t ('website_url'); ?></label>
|
||||
<div class="group-controls">
|
||||
<input type="text" name="website" id="website" class="extend" value="<?php echo $this->flux->website (); ?>" />
|
||||
<a target="_blank" href="<?php echo $this->flux->website (); ?>"><?php echo FreshRSS_Themes::icon('link'); ?></a>
|
||||
<div class="stick">
|
||||
<input type="text" name="website" id="website" class="extend" value="<?php echo $this->flux->website (); ?>" />
|
||||
<a class="btn" target="_blank" href="<?php echo $this->flux->website (); ?>"><?php echo FreshRSS_Themes::icon('link'); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="url"><?php echo Minz_Translate::t ('feed_url'); ?></label>
|
||||
<div class="group-controls">
|
||||
<input type="text" name="url" id="url" class="extend" value="<?php echo $this->flux->url (); ?>" />
|
||||
<a target="_blank" href="<?php echo $this->flux->url (); ?>"><?php echo FreshRSS_Themes::icon('link'); ?></a>
|
||||
<a class="btn" target="_blank" href="http://validator.w3.org/feed/check.cgi?url=<?php echo $this->flux->url (); ?>"><?php echo Minz_Translate::t ('feed_validator'); ?></a>
|
||||
<div class="stick">
|
||||
<input type="text" name="url" id="url" class="extend" value="<?php echo $this->flux->url (); ?>" />
|
||||
<a class="btn" target="_blank" href="<?php echo $this->flux->url (); ?>"><?php echo FreshRSS_Themes::icon('link'); ?></a>
|
||||
</div>
|
||||
|
||||
<a class="btn" target="_blank" href="http://validator.w3.org/feed/check.cgi?url=<?php echo $this->flux->url (); ?>"><?php echo Minz_Translate::t ('feed_validator'); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@@ -81,7 +90,7 @@
|
||||
<div class="form-group">
|
||||
<label class="group-name"><?php echo Minz_Translate::t ('number_articles'); ?></label>
|
||||
<div class="group-controls">
|
||||
<span class="control"><?php echo $this->flux->nbEntries (); ?></span>
|
||||
<span class="control"><?php echo $nbEntries; ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
<?php
|
||||
require_once(LIB_PATH . '/lib_opml.php');
|
||||
if ($this->req == 'export') {
|
||||
echo '<?xml version="1.0" encoding="UTF-8" ?>';
|
||||
?>
|
||||
<!-- Generated by <?php echo Minz_Configuration::title (); ?> -->
|
||||
<opml version="2.0">
|
||||
<head>
|
||||
<title><?php echo Minz_Configuration::title (); ?> OPML Feed</title>
|
||||
<dateCreated><?php echo date('D, d M Y H:i:s'); ?></dateCreated>
|
||||
</head>
|
||||
<body>
|
||||
<?php echo opml_export ($this->categories); ?>
|
||||
</body>
|
||||
</opml>
|
||||
<?php } else { ?>
|
||||
<?php $this->partial ('aside_feed'); ?>
|
||||
|
||||
<div class="post ">
|
||||
<a href="<?php echo _url ('index', 'index'); ?>"><?php echo Minz_Translate::t ('back_to_rss_feeds'); ?></a>
|
||||
|
||||
<form method="post" action="<?php echo Minz_Url::display (array ('c' => 'configure', 'a' => 'importExport', 'params' => array ('q' => 'import'))); ?>" enctype="multipart/form-data">
|
||||
<legend><?php echo Minz_Translate::t ('import_export_opml'); ?></legend>
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="file"><?php echo Minz_Translate::t ('file_to_import'); ?></label>
|
||||
<div class="group-controls">
|
||||
<input type="file" name="file" id="file" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group form-actions">
|
||||
<div class="group-controls">
|
||||
<button type="submit" class="btn btn-important"><?php echo Minz_Translate::t ('import'); ?></button>
|
||||
<?php echo Minz_Translate::t ('or'); ?>
|
||||
<a target="_blank" class="btn btn-important" href="<?php echo _url ('configure', 'importExport', 'q', 'export'); ?>"><?php echo Minz_Translate::t ('export'); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<?php } ?>
|
||||
125
app/views/configure/reading.phtml
Normal file
125
app/views/configure/reading.phtml
Normal file
@@ -0,0 +1,125 @@
|
||||
<?php $this->partial ('aside_configure'); ?>
|
||||
|
||||
<div class="post">
|
||||
<a href="<?php echo _url ('index', 'index'); ?>"><?php echo Minz_Translate::t ('back_to_rss_feeds'); ?></a>
|
||||
|
||||
<form method="post" action="<?php echo _url ('configure', 'reading'); ?>">
|
||||
<legend><?php echo Minz_Translate::t ('reading_configuration'); ?></legend>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="posts_per_page"><?php echo Minz_Translate::t ('articles_per_page'); ?></label>
|
||||
<div class="group-controls">
|
||||
<input type="number" id="posts_per_page" name="posts_per_page" value="<?php echo $this->conf->posts_per_page; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="sort_order"><?php echo Minz_Translate::t ('sort_order'); ?></label>
|
||||
<div class="group-controls">
|
||||
<select name="sort_order" id="sort_order">
|
||||
<option value="DESC"<?php echo $this->conf->sort_order === 'DESC' ? ' selected="selected"' : ''; ?>><?php echo Minz_Translate::t ('newer_first'); ?></option>
|
||||
<option value="ASC"<?php echo $this->conf->sort_order === 'ASC' ? ' selected="selected"' : ''; ?>><?php echo Minz_Translate::t ('older_first'); ?></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="view_mode"><?php echo Minz_Translate::t ('default_view'); ?></label>
|
||||
<div class="group-controls">
|
||||
<select name="view_mode" id="view_mode">
|
||||
<option value="normal"<?php echo $this->conf->view_mode === 'normal' ? ' selected="selected"' : ''; ?>><?php echo Minz_Translate::t ('normal_view'); ?></option>
|
||||
<option value="reader"<?php echo $this->conf->view_mode === 'reader' ? ' selected="selected"' : ''; ?>><?php echo Minz_Translate::t ('reader_view'); ?></option>
|
||||
<option value="global"<?php echo $this->conf->view_mode === 'global' ? ' selected="selected"' : ''; ?>><?php echo Minz_Translate::t ('global_view'); ?></option>
|
||||
</select>
|
||||
<label class="radio" for="radio_all">
|
||||
<input type="radio" name="default_view" id="radio_all" value="<?php echo FreshRSS_Entry::STATE_ALL; ?>"<?php echo $this->conf->default_view === FreshRSS_Entry::STATE_ALL ? ' checked="checked"' : ''; ?> />
|
||||
<?php echo Minz_Translate::t ('show_all_articles'); ?>
|
||||
</label>
|
||||
<label class="radio" for="radio_not_read">
|
||||
<input type="radio" name="default_view" id="radio_not_read" value="<?php echo FreshRSS_Entry::STATE_NOT_READ; ?>"<?php echo $this->conf->default_view === FreshRSS_Entry::STATE_NOT_READ ? ' checked="checked"' : ''; ?> />
|
||||
<?php echo Minz_Translate::t ('show_not_reads'); ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="group-controls">
|
||||
<label class="checkbox" for="auto_load_more">
|
||||
<input type="checkbox" name="auto_load_more" id="auto_load_more" value="1"<?php echo $this->conf->auto_load_more ? ' checked="checked"' : ''; ?> />
|
||||
<?php echo Minz_Translate::t ('auto_load_more'); ?>
|
||||
<noscript> — <strong><?php echo Minz_Translate::t ('javascript_should_be_activated'); ?></strong></noscript>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="group-controls">
|
||||
<label class="checkbox" for="display_posts">
|
||||
<input type="checkbox" name="display_posts" id="display_posts" value="1"<?php echo $this->conf->display_posts ? ' checked="checked"' : ''; ?> />
|
||||
<?php echo Minz_Translate::t ('display_articles_unfolded'); ?>
|
||||
<noscript> — <strong><?php echo Minz_Translate::t ('javascript_should_be_activated'); ?></strong></noscript>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="group-controls">
|
||||
<label class="checkbox" for="lazyload">
|
||||
<input type="checkbox" name="lazyload" id="lazyload" value="1"<?php echo $this->conf->lazyload ? ' checked="checked"' : ''; ?> />
|
||||
<?php echo Minz_Translate::t ('img_with_lazyload'); ?>
|
||||
<noscript> — <strong><?php echo Minz_Translate::t ('javascript_should_be_activated'); ?></strong></noscript>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="group-controls">
|
||||
<label class="checkbox" for="sticky_post">
|
||||
<input type="checkbox" name="sticky_post" id="sticky_post" value="1"<?php echo $this->conf->sticky_post ? ' checked="checked"' : ''; ?> />
|
||||
<?php echo Minz_Translate::t ('sticky_post'); ?>
|
||||
<noscript> — <strong><?php echo Minz_Translate::t ('javascript_should_be_activated'); ?></strong></noscript>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name"><?php echo Minz_Translate::t ('auto_read_when'); ?></label>
|
||||
<div class="group-controls">
|
||||
<label class="checkbox" for="check_open_article">
|
||||
<input type="checkbox" name="mark_open_article" id="check_open_article" value="1"<?php echo $this->conf->mark_when['article'] ? ' checked="checked"' : ''; ?> />
|
||||
<?php echo Minz_Translate::t ('article_selected'); ?>
|
||||
</label>
|
||||
<label class="checkbox" for="check_open_site">
|
||||
<input type="checkbox" name="mark_open_site" id="check_open_site" value="1"<?php echo $this->conf->mark_when['site'] ? ' checked="checked"' : ''; ?> />
|
||||
<?php echo Minz_Translate::t ('article_open_on_website'); ?>
|
||||
</label>
|
||||
<label class="checkbox" for="check_scroll">
|
||||
<input type="checkbox" name="mark_scroll" id="check_scroll" value="1"<?php echo $this->conf->mark_when['scroll'] ? ' checked="checked"' : ''; ?> />
|
||||
<?php echo Minz_Translate::t ('scroll'); ?>
|
||||
</label>
|
||||
<label class="checkbox" for="check_reception">
|
||||
<input type="checkbox" name="mark_upon_reception" id="check_reception" value="1"<?php echo $this->conf->mark_when['reception'] ? ' checked="checked"' : ''; ?> />
|
||||
<?php echo Minz_Translate::t ('upon_reception'); ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name"><?php echo Minz_Translate::t ('after_onread'); ?></label>
|
||||
<div class="group-controls">
|
||||
<label class="checkbox" for="onread_jump_next">
|
||||
<input type="checkbox" name="onread_jump_next" id="onread_jump_next" value="1"<?php echo $this->conf->onread_jump_next ? ' checked="checked"' : ''; ?> />
|
||||
<?php echo Minz_Translate::t ('jump_next'); ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group form-actions">
|
||||
<div class="group-controls">
|
||||
<button type="submit" class="btn btn-important"><?php echo Minz_Translate::t ('save'); ?></button>
|
||||
<button type="reset" class="btn"><?php echo Minz_Translate::t ('cancel'); ?></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
@@ -3,54 +3,49 @@
|
||||
<div class="post">
|
||||
<a href="<?php echo _url ('index', 'index'); ?>"><?php echo Minz_Translate::t ('back_to_rss_feeds'); ?></a>
|
||||
|
||||
<form method="post" action="<?php echo _url ('configure', 'sharing'); ?>">
|
||||
<form method="post" action="<?php echo _url ('configure', 'sharing'); ?>"
|
||||
data-simple='<div class="form-group"><label class="group-name">##label##</label><div class="group-controls"><a href="#" class="share remove btn btn-attention"><?php echo FreshRSS_Themes::icon('close'); ?></a>
|
||||
<input type="hidden" id="share_##key##_type" name="share[##key##][type]" value="##type##" /></div></div>'
|
||||
data-advanced='<div class="form-group"><label class="group-name">##label##</label><div class="group-controls">
|
||||
<input type="hidden" id="share_##key##_type" name="share[##key##][type]" value="##type##" />
|
||||
<div class="stick">
|
||||
<input type="text" id="share_##key##_name" name="share[##key##][name]" class="extend" value="" placeholder="<?php echo Minz_Translate::t ('share_name'); ?>" size="64" />
|
||||
<input type="url" id="share_##key##_url" name="share[##key##][url]" class="extend" value="" placeholder="<?php echo Minz_Translate::t ('share_url'); ?>" size="64" />
|
||||
<a href="#" class="share remove btn btn-attention"><?php echo FreshRSS_Themes::icon('close'); ?></a></div>
|
||||
<a target="_blank" class="btn" title="<?php echo Minz_Translate::t('more_information'); ?>" href="##help##"><?php echo FreshRSS_Themes::icon('help'); ?></a>
|
||||
</div></div>'>
|
||||
<legend><?php echo Minz_Translate::t ('sharing'); ?></legend>
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="shaarli">
|
||||
<?php echo Minz_Translate::t ('your_shaarli'); ?>
|
||||
</label>
|
||||
<div class="group-controls">
|
||||
<input type="url" id="shaarli" name="shaarli" class="extend" value="<?php echo $this->conf->sharing ('shaarli'); ?>" placeholder="<?php echo Minz_Translate::t ('blank_to_disable'); ?>" size="64" />
|
||||
|
||||
<?php echo FreshRSS_Themes::icon('help'); ?> <a target="_blank" href="http://sebsauvage.net/wiki/doku.php?id=php:shaarli"><?php echo Minz_Translate::t ('more_information'); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="wallabag">
|
||||
<?php echo Minz_Translate::t ('your_wallabag'); ?>
|
||||
</label>
|
||||
<div class="group-controls">
|
||||
<input type="url" id="wallabag" name="wallabag" class="extend" value="<?php echo $this->conf->sharing ('wallabag'); ?>" placeholder="<?php echo Minz_Translate::t ('blank_to_disable'); ?>" size="64" />
|
||||
|
||||
<?php echo FreshRSS_Themes::icon('help'); ?> <a target="_blank" href="http://www.wallabag.org"><?php echo Minz_Translate::t ('more_information'); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="diaspora">
|
||||
<?php echo Minz_Translate::t ('your_diaspora_pod'); ?>
|
||||
</label>
|
||||
<div class="group-controls">
|
||||
<input type="url" id="diaspora" name="diaspora" class="extend" value="<?php echo $this->conf->sharing ('diaspora'); ?>" placeholder="<?php echo Minz_Translate::t ('blank_to_disable'); ?>" size="64" />
|
||||
|
||||
<?php echo FreshRSS_Themes::icon('help'); ?> <a target="_blank" href="https://diasporafoundation.org/"><?php echo Minz_Translate::t ('more_information'); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name"><?php echo Minz_Translate::t ('activate_sharing'); ?></label>
|
||||
<div class="group-controls">
|
||||
<?php
|
||||
$services = array ('twitter', 'g+', 'facebook', 'email', 'print');
|
||||
|
||||
foreach ($services as $service) {
|
||||
?>
|
||||
<label class="checkbox" for="<?php echo $service; ?>">
|
||||
<input type="checkbox" name="<?php echo $service; ?>" id="<?php echo $service; ?>" value="1"<?php echo $this->conf->sharing($service) ? ' checked="checked"' : ''; ?> />
|
||||
<?php echo Minz_Translate::t ($service); ?>
|
||||
<?php foreach ($this->conf->sharing as $key => $sharing): ?>
|
||||
<?php $share = $this->conf->shares[$sharing['type']]; ?>
|
||||
<div class="form-group">
|
||||
<label class="group-name">
|
||||
<?php echo Minz_Translate::t ($sharing['type']); ?>
|
||||
</label>
|
||||
<?php } ?>
|
||||
<div class="group-controls">
|
||||
<input type='hidden' id='share_<?php echo $key;?>_type' name="share[<?php echo $key;?>][type]" value='<?php echo $sharing['type']?>' />
|
||||
<?php if ($share['form'] === 'advanced'){ ?>
|
||||
<div class="stick">
|
||||
<input type="text" id="share_<?php echo $key;?>_name" name="share[<?php echo $key;?>][name]" class="extend" value="<?php echo $sharing['name']?>" placeholder="<?php echo Minz_Translate::t ('share_name'); ?>" size="64" />
|
||||
<input type="url" id="share_<?php echo $key;?>_url" name="share[<?php echo $key;?>][url]" class="extend" value="<?php echo $sharing['url']?>" placeholder="<?php echo Minz_Translate::t ('share_url'); ?>" size="64" />
|
||||
<a href='#' class='share remove btn btn-attention'><?php echo FreshRSS_Themes::icon('close'); ?></a>
|
||||
</div>
|
||||
|
||||
<a target="_blank" class="btn" title="<?php echo Minz_Translate::t('more_information'); ?>" href="<?php echo $share['help']?>"><?php echo FreshRSS_Themes::icon('help'); ?></a>
|
||||
<?php } else { ?>
|
||||
<a href='#' class='share remove btn btn-attention'><?php echo FreshRSS_Themes::icon('close'); ?></a>
|
||||
<?php } ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach;?>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="group-controls">
|
||||
<select>
|
||||
<?php foreach($this->conf->shares as $key => $params):?>
|
||||
<option value='<?php echo $key?>' data-form='<?php echo $params['form']?>' data-help='<?php if (!empty($params['help'])) {echo $params['help'];}?>'><?php echo Minz_Translate::t($key) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<a href='#' class='share add btn'><?php echo FreshRSS_Themes::icon('add'); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -12,10 +12,44 @@
|
||||
<?php $s = $this->conf->shortcuts; ?>
|
||||
|
||||
<form method="post" action="<?php echo _url ('configure', 'shortcut'); ?>">
|
||||
<legend><?php echo Minz_Translate::t ('shortcuts_management'); ?></legend>
|
||||
<legend><?php echo Minz_Translate::t ('shortcuts'); ?></legend>
|
||||
|
||||
<noscript><p class="alert alert-error"><?php echo Minz_Translate::t ('javascript_for_shortcuts'); ?></p></noscript>
|
||||
|
||||
<legend><?php echo Minz_Translate::t ('shortcuts_navigation'); ?></legend>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="next_entry"><?php echo Minz_Translate::t ('next_article'); ?></label>
|
||||
<div class="group-controls">
|
||||
<input type="text" id="next_entry" name="shortcuts[next_entry]" list="keys" value="<?php echo $s['next_entry']; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="prev_entry"><?php echo Minz_Translate::t ('previous_article'); ?></label>
|
||||
<div class="group-controls">
|
||||
<input type="text" id="prev_entry" name="shortcuts[prev_entry]" list="keys" value="<?php echo $s['prev_entry']; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="first_entry"><?php echo Minz_Translate::t ('first_article'); ?></label>
|
||||
<div class="group-controls">
|
||||
<input type="text" id="first_entry" name="shortcuts[first_entry]" list="keys" value="<?php echo $s['first_entry']; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="last_entry"><?php echo Minz_Translate::t ('last_article'); ?></label>
|
||||
<div class="group-controls">
|
||||
<input type="text" id="last_entry" name="shortcuts[last_entry]" list="keys" value="<?php echo $s['last_entry']; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div><?php echo Minz_Translate::t ('shortcuts_navigation_help');?></div>
|
||||
|
||||
<legend><?php echo Minz_Translate::t ('shortcuts_article_action');?></legend>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="mark_read"><?php echo Minz_Translate::t ('mark_read'); ?></label>
|
||||
<div class="group-controls">
|
||||
@@ -39,18 +73,10 @@
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="next_entry"><?php echo Minz_Translate::t ('next_article'); ?></label>
|
||||
<label class="group-name" for="auto_share_shortcut"><?php echo Minz_Translate::t ('auto_share'); ?></label>
|
||||
<div class="group-controls">
|
||||
<input type="text" id="next_entry" name="shortcuts[next_entry]" list="keys" value="<?php echo $s['next_entry']; ?>" />
|
||||
<?php echo Minz_Translate::t ('shift_for_last'); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="prev_entry"><?php echo Minz_Translate::t ('previous_article'); ?></label>
|
||||
<div class="group-controls">
|
||||
<input type="text" id="prev_entry" name="shortcuts[prev_entry]" list="keys" value="<?php echo $s['prev_entry']; ?>" />
|
||||
<?php echo Minz_Translate::t ('shift_for_first'); ?>
|
||||
<input type="text" id="auto_share_shortcut" name="shortcuts[auto_share]" list="keys" value="<?php echo $s['auto_share']; ?>" />
|
||||
<?php echo Minz_Translate::t ('auto_share_help'); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -61,6 +87,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<legend><?php echo Minz_Translate::t ('shortcuts_other_action');?></legend>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="load_more_shortcut"><?php echo Minz_Translate::t ('load_more'); ?></label>
|
||||
<div class="group-controls">
|
||||
@@ -69,9 +97,9 @@
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="auto_share_shortcut"><?php echo Minz_Translate::t ('auto_share'); ?></label>
|
||||
<label class="group-name" for="focus_search_shortcut"><?php echo Minz_Translate::t ('focus_search'); ?></label>
|
||||
<div class="group-controls">
|
||||
<input type="text" id="auto_share_shortcut" name="shortcuts[auto_share]" list="keys" value="<?php echo $s['auto_share']; ?>" />
|
||||
<input type="text" id="focus_search_shortcut" name="shortcuts[focus_search]" list="keys" value="<?php echo $s['focus_search']; ?>" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -20,16 +20,31 @@
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="passwordPlain"><?php echo Minz_Translate::t('password_form'); ?></label>
|
||||
<div class="group-controls">
|
||||
<input type="password" id="passwordPlain" name="passwordPlain" pattern=".{7,}" />
|
||||
<div class="stick">
|
||||
<input type="password" id="passwordPlain" name="passwordPlain" autocomplete="off" pattern=".{7,}" <?php echo cryptAvailable() ? '' : 'disabled="disabled" '; ?>/>
|
||||
<a class="btn toggle-password"><?php echo FreshRSS_Themes::icon('key'); ?></a>
|
||||
</div>
|
||||
<noscript><b><?php echo Minz_Translate::t('javascript_should_be_activated'); ?></b></noscript>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (Minz_Configuration::apiEnabled()) { ?>
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="apiPasswordPlain"><?php echo Minz_Translate::t('password_api'); ?></label>
|
||||
<div class="group-controls">
|
||||
<div class="stick">
|
||||
<input type="password" id="apiPasswordPlain" name="apiPasswordPlain" autocomplete="off" pattern=".{7,}" <?php echo cryptAvailable() ? '' : 'disabled="disabled" '; ?>/>
|
||||
<a class="btn toggle-password"><?php echo FreshRSS_Themes::icon('key'); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="mail_login"><?php echo Minz_Translate::t('persona_connection_email'); ?></label>
|
||||
<?php $mail = $this->conf->mail_login; ?>
|
||||
<div class="group-controls">
|
||||
<input type="email" id="mail_login" name="mail_login" class="extend" value="<?php echo $mail; ?>" <?php echo Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_')) ? '' : 'disabled="disabled"'; ?> placeholder="alice@example.net" />
|
||||
<input type="email" id="mail_login" name="mail_login" class="extend" autocomplete="off" value="<?php echo $mail; ?>" <?php echo Minz_Configuration::isAdmin(Minz_Session::param('currentUser', '_')) ? '' : 'disabled="disabled"'; ?> placeholder="alice@example.net" />
|
||||
<noscript><b><?php echo Minz_Translate::t('javascript_should_be_activated'); ?></b></noscript>
|
||||
</div>
|
||||
</div>
|
||||
@@ -52,7 +67,7 @@
|
||||
<?php if (!in_array(Minz_Configuration::authType(), array('form', 'persona', 'http_auth', 'none'))) { ?>
|
||||
<option selected="selected"></option>
|
||||
<?php } ?>
|
||||
<option value="form"<?php echo Minz_Configuration::authType() === 'form' ? ' selected="selected"' : '', version_compare(PHP_VERSION, '5.3', '<') ? ' disabled="disabled"' : ''; ?>><?php echo Minz_Translate::t('auth_form'); ?></option>
|
||||
<option value="form"<?php echo Minz_Configuration::authType() === 'form' ? ' selected="selected"' : '', cryptAvailable() ? '' : ' disabled="disabled"'; ?>><?php echo Minz_Translate::t('auth_form'); ?></option>
|
||||
<option value="persona"<?php echo Minz_Configuration::authType() === 'persona' ? ' selected="selected"' : '', $this->conf->mail_login == '' ? ' disabled="disabled"' : ''; ?>><?php echo Minz_Translate::t('auth_persona'); ?></option>
|
||||
<option value="http_auth"<?php echo Minz_Configuration::authType() === 'http_auth' ? ' selected="selected"' : '', httpAuthUser() == '' ? ' disabled="disabled"' : ''; ?>><?php echo Minz_Translate::t('http_auth'); ?> (REMOTE_USER = '<?php echo httpAuthUser(); ?>')</option>
|
||||
<option value="none"<?php echo Minz_Configuration::authType() === 'none' ? ' selected="selected"' : ''; ?>><?php echo Minz_Translate::t('auth_none'); ?></option>
|
||||
@@ -70,18 +85,49 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="group-controls">
|
||||
<label class="checkbox" for="anon_refresh">
|
||||
<input type="checkbox" name="anon_refresh" id="anon_refresh" value="1"<?php echo Minz_Configuration::allowAnonymousRefresh() ? ' checked="checked"' : '',
|
||||
Minz_Configuration::canLogIn() ? '' : ' disabled="disabled"'; ?> />
|
||||
<?php echo Minz_Translate::t('allow_anonymous_refresh'); ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="group-controls">
|
||||
<label class="checkbox" for="unsafe_autologin">
|
||||
<input type="checkbox" name="unsafe_autologin" id="unsafe_autologin" value="1"<?php echo Minz_Configuration::unsafeAutologinEnabled() ? ' checked="checked"' : '',
|
||||
Minz_Configuration::canLogIn() ? '' : ' disabled="disabled"'; ?> />
|
||||
<?php echo Minz_Translate::t('unsafe_autologin'); ?>
|
||||
<kbd>p/i/?a=formLogin&u=Alice&p=1234</kbd>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (Minz_Configuration::canLogIn()) { ?>
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="token"><?php echo Minz_Translate::t('auth_token'); ?></label>
|
||||
<?php $token = $this->conf->token; ?>
|
||||
<div class="group-controls">
|
||||
<input type="text" id="token" name="token" value="<?php echo $token; ?>" placeholder="<?php echo Minz_Translate::t('blank_to_disable'); ?>"<?php
|
||||
<input type="text" id="token" name="token" value="<?php echo $token; ?>" placeholder="<?php echo Minz_Translate::t('blank_to_disable'); ?>"<?php
|
||||
echo Minz_Configuration::canLogIn() ? '' : ' disabled="disabled"'; ?> />
|
||||
<?php echo FreshRSS_Themes::icon('help'); ?> <?php echo Minz_Translate::t('explain_token', Minz_Url::display(null, 'html', true), $token); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="group-controls">
|
||||
<label class="checkbox" for="api_enabled">
|
||||
<input type="checkbox" name="api_enabled" id="api_enabled" value="1"<?php echo Minz_Configuration::apiEnabled() ? ' checked="checked"' : '',
|
||||
Minz_Configuration::needsLogin() ? '' : ' disabled="disabled"'; ?> />
|
||||
<?php echo Minz_Translate::t('api_enabled'); ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group form-actions">
|
||||
<div class="group-controls">
|
||||
<button type="submit" class="btn btn-important"><?php echo Minz_Translate::t('save'); ?></button>
|
||||
@@ -129,14 +175,17 @@
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="new_user_name"><?php echo Minz_Translate::t('username'); ?></label>
|
||||
<div class="group-controls">
|
||||
<input id="new_user_name" name="new_user_name" type="text" size="16" required="required" maxlength="16" pattern="[0-9a-zA-Z]{1,16}" placeholder="demo" />
|
||||
<input id="new_user_name" name="new_user_name" type="text" size="16" required="required" maxlength="16" autocomplete="off" pattern="[0-9a-zA-Z]{1,16}" placeholder="demo" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="new_user_passwordPlain"><?php echo Minz_Translate::t('password_form'); ?></label>
|
||||
<div class="group-controls">
|
||||
<input type="password" id="new_user_passwordPlain" name="new_user_passwordPlain" pattern=".{7,}" />
|
||||
<div class="stick">
|
||||
<input type="password" id="new_user_passwordPlain" name="new_user_passwordPlain" autocomplete="off" pattern=".{7,}" />
|
||||
<a class="btn toggle-password"><?php echo FreshRSS_Themes::icon('key'); ?></a>
|
||||
</div>
|
||||
<noscript><b><?php echo Minz_Translate::t('javascript_should_be_activated'); ?></b></noscript>
|
||||
</div>
|
||||
</div>
|
||||
@@ -145,7 +194,7 @@
|
||||
<label class="group-name" for="new_user_email"><?php echo Minz_Translate::t('persona_connection_email'); ?></label>
|
||||
<?php $mail = $this->conf->mail_login; ?>
|
||||
<div class="group-controls">
|
||||
<input type="email" id="new_user_email" name="new_user_email" class="extend" placeholder="alice@example.net" />
|
||||
<input type="email" id="new_user_email" name="new_user_email" class="extend" autocomplete="off" placeholder="alice@example.net" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -3,7 +3,15 @@
|
||||
<h1 class="alert-head"><?php echo $this->code; ?></h1>
|
||||
|
||||
<p>
|
||||
<?php echo Minz_Translate::t ('page_not_found'); ?><br />
|
||||
<?php
|
||||
switch(Minz_Request::param ('code')) {
|
||||
case 403:
|
||||
echo Minz_Translate::t ('forbidden_access');
|
||||
break;
|
||||
case 404:
|
||||
default:
|
||||
echo Minz_Translate::t ('page_not_found');
|
||||
} ?><br />
|
||||
<a href="<?php echo _url ('index', 'index'); ?>"><?php echo Minz_Translate::t ('back_to_rss_feeds'); ?></a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
91
app/views/feed/add.phtml
Normal file
91
app/views/feed/add.phtml
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php if ($this->feed) { ?>
|
||||
<div class="post">
|
||||
<h1><?php echo Minz_Translate::t ('add_rss_feed'); ?></h1>
|
||||
|
||||
<?php if (!$this->load_ok) { ?>
|
||||
<p class="alert alert-error"><span class="alert-head"><?php echo Minz_Translate::t('damn'); ?></span> <?php echo Minz_Translate::t('internal_problem_feed', _url('index', 'logs')); ?></p>
|
||||
<?php } ?>
|
||||
|
||||
<form method="post" action="<?php echo _url('feed', 'add'); ?>" autocomplete="off">
|
||||
<legend><?php echo Minz_Translate::t('informations'); ?></legend>
|
||||
<?php if ($this->load_ok) { ?>
|
||||
<div class="form-group">
|
||||
<label class="group-name"><?php echo Minz_Translate::t('title'); ?></label>
|
||||
<div class="group-controls">
|
||||
<label><?php echo $this->feed->name() ; ?></label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php $desc = $this->feed->description(); if ($desc != '') { ?>
|
||||
<div class="form-group">
|
||||
<label class="group-name"><?php echo Minz_Translate::t('feed_description'); ?></label>
|
||||
<div class="group-controls">
|
||||
<label><?php echo htmlspecialchars($desc, ENT_NOQUOTES, 'UTF-8'); ?></label>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name"><?php echo Minz_Translate::t('website_url'); ?></label>
|
||||
<div class="group-controls">
|
||||
<?php echo $this->feed->website(); ?>
|
||||
<a class="btn" target="_blank" href="<?php echo $this->feed->website(); ?>"><?php echo FreshRSS_Themes::icon('link'); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="url"><?php echo Minz_Translate::t('feed_url'); ?></label>
|
||||
<div class="group-controls">
|
||||
<div class="stick">
|
||||
<input type="text" name="url_rss" id="url" class="extend" value="<?php echo $this->feed->url(); ?>" />
|
||||
<a class="btn" target="_blank" href="<?php echo $this->feed->url(); ?>"><?php echo FreshRSS_Themes::icon('link'); ?></a>
|
||||
</div>
|
||||
<a class="btn" target="_blank" href="http://validator.w3.org/feed/check.cgi?url=<?php echo $this->feed->url(); ?>"><?php echo Minz_Translate::t('feed_validator'); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="category"><?php echo Minz_Translate::t('category'); ?></label>
|
||||
<div class="group-controls">
|
||||
<select name="category" id="category">
|
||||
<?php foreach ($this->categories as $cat) { ?>
|
||||
<option value="<?php echo $cat->id(); ?>"<?php echo $cat->id() == 1 ? ' selected="selected"' : ''; ?>>
|
||||
<?php echo $cat->name(); ?>
|
||||
</option>
|
||||
<?php } ?>
|
||||
<option value="nc"><?php echo Minz_Translate::t('new_category'); ?></option>
|
||||
</select>
|
||||
|
||||
<span style="display: none;">
|
||||
<input type="text" name="new_category[name]" id="new_category_name" autocomplete="off" placeholder="<?php echo Minz_Translate::t('new_category'); ?>" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<legend><?php echo Minz_Translate::t('http_authentication'); ?></legend>
|
||||
<?php $auth = $this->feed->httpAuth(false); ?>
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="http_user"><?php echo Minz_Translate::t('http_username'); ?></label>
|
||||
<div class="group-controls">
|
||||
<input type="text" name="http_user" id="http_user" class="extend" value="<?php echo $auth['username']; ?>" autocomplete="off" />
|
||||
</div>
|
||||
|
||||
<label class="group-name" for="http_pass"><?php echo Minz_Translate::t('http_password'); ?></label>
|
||||
<div class="group-controls">
|
||||
<input type="password" name="http_pass" id="http_pass" class="extend" value="<?php echo $auth['password']; ?>" autocomplete="off" />
|
||||
</div>
|
||||
|
||||
<div class="group-controls">
|
||||
<?php echo FreshRSS_Themes::icon('help'); ?> <?php echo Minz_Translate::t('access_protected_feeds'); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group form-actions">
|
||||
<div class="group-controls">
|
||||
<button type="submit" class="btn btn-important"><?php echo Minz_Translate::t('save'); ?></button>
|
||||
<button type="reset" class="btn"><?php echo Minz_Translate::t('cancel'); ?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<?php } ?>
|
||||
47
app/views/helpers/export/articles.phtml
Normal file
47
app/views/helpers/export/articles.phtml
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
$username = Minz_Session::param('currentUser', '_');
|
||||
|
||||
$articles = array(
|
||||
'id' => 'user/' . str_replace('/', '', $username) . '/state/org.freshrss/' . $this->type,
|
||||
'title' => $this->list_title,
|
||||
'author' => $username,
|
||||
'items' => array()
|
||||
);
|
||||
|
||||
foreach ($this->entries as $entry) {
|
||||
if (!isset($this->feed)) {
|
||||
$feed = FreshRSS_CategoryDAO::findFeed($this->categories, $entry->feed ());
|
||||
} else {
|
||||
$feed = $this->feed;
|
||||
}
|
||||
|
||||
$articles['items'][] = array(
|
||||
'id' => $entry->guid(),
|
||||
'categories' => array_values($entry->tags()),
|
||||
'title' => $entry->title(),
|
||||
'author' => $entry->author(),
|
||||
'published' => $entry->date(true),
|
||||
'updated' => $entry->date(true),
|
||||
'alternate' => array(array(
|
||||
'href' => $entry->link(),
|
||||
'type' => 'text/html'
|
||||
)),
|
||||
'content' => array(
|
||||
'content' => $entry->content()
|
||||
),
|
||||
'origin' => array(
|
||||
'streamId' => $feed->id(),
|
||||
'title' => $feed->name(),
|
||||
'htmlUrl' => $feed->website(),
|
||||
'feedUrl' => $feed->url()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$options = 0;
|
||||
if (version_compare(PHP_VERSION, '5.4.0') >= 0) {
|
||||
$options = JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE;
|
||||
}
|
||||
|
||||
echo json_encode($articles, $options);
|
||||
?>
|
||||
28
app/views/helpers/export/opml.phtml
Normal file
28
app/views/helpers/export/opml.phtml
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
$opml_array = array(
|
||||
'head' => array(
|
||||
'title' => Minz_Configuration::title(),
|
||||
'dateCreated' => date('D, d M Y H:i:s')
|
||||
),
|
||||
'body' => array()
|
||||
);
|
||||
|
||||
foreach ($this->categories as $key => $cat) {
|
||||
$opml_array['body'][$key] = array(
|
||||
'text' => $cat['name'],
|
||||
'@outlines' => array()
|
||||
);
|
||||
|
||||
foreach ($cat['feeds'] as $feed) {
|
||||
$opml_array['body'][$key]['@outlines'][] = array(
|
||||
'text' => htmlspecialchars_decode($feed->name()),
|
||||
'type' => 'rss',
|
||||
'xmlUrl' => $feed->url(),
|
||||
'htmlUrl' => $feed->website(),
|
||||
'description' => $feed->description()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
echo libopml_render($opml_array);
|
||||
@@ -5,12 +5,14 @@ echo '"use strict";', "\n";
|
||||
$mark = $this->conf->mark_when;
|
||||
echo 'var ',
|
||||
'hide_posts=', ($this->conf->display_posts || Minz_Request::param('output') === 'reader') ? 'false' : 'true',
|
||||
',display_order="', Minz_Request::param('order', $this->conf->sort_order), '"',
|
||||
',auto_mark_article=', $mark['article'] ? 'true' : 'false',
|
||||
',auto_mark_site=', $mark['site'] ? 'true' : 'false',
|
||||
',auto_mark_scroll=', $mark['scroll'] ? 'true' : 'false',
|
||||
',auto_load_more=', $this->conf->auto_load_more ? 'true' : 'false',
|
||||
',full_lazyload=', $this->conf->lazyload && ($this->conf->display_posts || Minz_Request::param('output') === 'reader') ? 'true' : 'false',
|
||||
',does_lazyload=', $this->conf->lazyload ? 'true' : 'false';
|
||||
',does_lazyload=', $this->conf->lazyload ? 'true' : 'false',
|
||||
',sticky_post=', $this->conf->sticky_post ? 'true' : 'false';
|
||||
|
||||
$s = $this->conf->shortcuts;
|
||||
echo ',shortcuts={',
|
||||
@@ -19,9 +21,12 @@ echo ',shortcuts={',
|
||||
'go_website:"', $s['go_website'], '",',
|
||||
'prev_entry:"', $s['prev_entry'], '",',
|
||||
'next_entry:"', $s['next_entry'], '",',
|
||||
'first_entry:"', $s['first_entry'], '",',
|
||||
'last_entry:"', $s['last_entry'], '",',
|
||||
'collapse_entry:"', $s['collapse_entry'], '",',
|
||||
'load_more:"', $s['load_more'], '",',
|
||||
'auto_share:"', $s['auto_share'], '"',
|
||||
'auto_share:"', $s['auto_share'], '",',
|
||||
'focus_search:"', $s['focus_search'], '"',
|
||||
"},\n";
|
||||
|
||||
if (Minz_Request::param ('output') === 'global') {
|
||||
@@ -30,7 +35,13 @@ if (Minz_Request::param ('output') === 'global') {
|
||||
|
||||
$authType = Minz_Configuration::authType();
|
||||
if ($authType === 'persona') {
|
||||
echo 'current_user_mail="' . Minz_Session::param ('mail', '') . '",';
|
||||
// If user is disconnected, current_user_mail MUST be null
|
||||
$mail = Minz_Session::param ('mail', false);
|
||||
if ($mail) {
|
||||
echo 'current_user_mail="' . $mail . '",';
|
||||
} else {
|
||||
echo 'current_user_mail=null,';
|
||||
}
|
||||
}
|
||||
|
||||
echo 'authType="', $authType, '",',
|
||||
|
||||
@@ -8,19 +8,10 @@ if (!empty($this->entries)) {
|
||||
$display_yesterday = true;
|
||||
$display_others = true;
|
||||
if ($this->loginOk) {
|
||||
$shaarli = $this->conf->sharing ('shaarli');
|
||||
$wallabag = $this->conf->sharing ('wallabag');
|
||||
$diaspora = $this->conf->sharing ('diaspora');
|
||||
$sharing = $this->conf->sharing;
|
||||
} else {
|
||||
$shaarli = '';
|
||||
$wallabag = '';
|
||||
$diaspora = '';
|
||||
$sharing = array();
|
||||
}
|
||||
$twitter = $this->conf->sharing ('twitter');
|
||||
$google_plus = $this->conf->sharing ('g+');
|
||||
$facebook = $this->conf->sharing ('facebook');
|
||||
$email = $this->conf->sharing ('email');
|
||||
$print = $this->conf->sharing ('print');
|
||||
$hidePosts = !$this->conf->display_posts;
|
||||
$lazyload = $this->conf->lazyload;
|
||||
$topline_read = $this->conf->topline_read;
|
||||
@@ -29,17 +20,17 @@ if (!empty($this->entries)) {
|
||||
$topline_link = $this->conf->topline_link;
|
||||
$bottomline_read = $this->conf->bottomline_read;
|
||||
$bottomline_favorite = $this->conf->bottomline_favorite;
|
||||
$bottomline_sharing = $this->conf->bottomline_sharing && (
|
||||
$shaarli || $wallabag || $diaspora || $twitter ||
|
||||
$google_plus || $facebook || $email || $print);
|
||||
$bottomline_sharing = $this->conf->bottomline_sharing && (count($sharing));
|
||||
$bottomline_tags = $this->conf->bottomline_tags;
|
||||
$bottomline_date = $this->conf->bottomline_date;
|
||||
$bottomline_link = $this->conf->bottomline_link;
|
||||
|
||||
$content_width = $this->conf->content_width;
|
||||
?>
|
||||
|
||||
<div id="stream" class="normal<?php echo $hidePosts ? ' hide_posts' : ''; ?>"><?php
|
||||
?><div id="new-article">
|
||||
<a href="<?php echo _url('index', 'index'); ?>"><?php echo Minz_Translate::t ('new_article'); ?></a>
|
||||
<a href="<?php echo Minz_Url::display ($this->url); ?>"><?php echo Minz_Translate::t ('new_article'); ?></a>
|
||||
</div><?php
|
||||
foreach ($this->entries as $item) {
|
||||
if ($display_today && $item->isDay (FreshRSS_Days::TODAY, $this->today)) {
|
||||
@@ -98,8 +89,8 @@ if (!empty($this->entries)) {
|
||||
</ul>
|
||||
|
||||
<div class="flux_content">
|
||||
<div class="content">
|
||||
<h1 class="title"><?php echo $item->title (); ?></h1>
|
||||
<div class="content <?php echo $content_width; ?>">
|
||||
<h1 class="title"><a target="_blank" href="<?php echo $item->link (); ?>"><?php echo $item->title (); ?></a></h1>
|
||||
<?php
|
||||
$author = $item->author ();
|
||||
echo $author != '' ? '<div class="author">' . Minz_Translate::t ('by_author', $author) . '</div>' : '';
|
||||
@@ -146,55 +137,13 @@ if (!empty($this->entries)) {
|
||||
|
||||
<ul class="dropdown-menu">
|
||||
<li class="dropdown-close"><a href="#close">❌</a></li>
|
||||
<?php if ($shaarli) { ?>
|
||||
<li class="item">
|
||||
<a target="_blank" href="<?php echo $shaarli . '?post=' . $link . '&title=' . $title . '&source=FreshRSS'; ?>">
|
||||
<?php echo Minz_Translate::t ('shaarli'); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php } if ($wallabag) { ?>
|
||||
<li class="item">
|
||||
<a target="_blank" href="<?php echo $wallabag . '?action=add&url=' . base64_encode (urldecode($link)); ?>">
|
||||
<?php echo Minz_Translate::t ('wallabag'); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php } if ($diaspora) { ?>
|
||||
<li class="item">
|
||||
<a target="_blank" href="<?php echo $diaspora . '/bookmarklet?url=' . $link . '&title=' . $title; ?>">
|
||||
<?php echo Minz_Translate::t ('diaspora'); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php } if ($twitter) { ?>
|
||||
<li class="item">
|
||||
<a target="_blank" href="https://twitter.com/share?url=<?php echo $link; ?>&text=<?php echo $title; ?>">
|
||||
<?php echo Minz_Translate::t ('twitter'); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php } if ($google_plus) { ?>
|
||||
<li class="item">
|
||||
<a target="_blank" href="https://plus.google.com/share?url=<?php echo $link; ?>">
|
||||
<?php echo Minz_Translate::t ('g+'); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php } if ($facebook) { ?>
|
||||
<li class="item">
|
||||
<a target="_blank" href="https://www.facebook.com/sharer.php?u=<?php echo $link; ?>&t=<?php echo $title; ?>">
|
||||
<?php echo Minz_Translate::t ('facebook'); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php } if ($email) { ?>
|
||||
<li class="item">
|
||||
<a href="mailto:?subject=<?php echo urldecode($title); ?>&body=<?php echo $link; ?>">
|
||||
<?php echo Minz_Translate::t ('by_email'); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php } if ($print) { ?>
|
||||
<li class="item">
|
||||
<a href="#" class="print-article">
|
||||
<?php echo Minz_Translate::t ('print'); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php } ?>
|
||||
<?php foreach ($sharing as $share) :?>
|
||||
<li class="item share">
|
||||
<a target="_blank" href="<?php echo FreshRSS_Share::generateUrl($this->conf->shares, $share, $item->link(), $item->title() . ' . ' . $feed->name())?>">
|
||||
<?php echo Minz_Translate::t ($share['name']);?>
|
||||
</a>
|
||||
</li>
|
||||
<?php endforeach;?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
@@ -3,6 +3,7 @@ $this->partial ('nav_menu');
|
||||
|
||||
if (!empty($this->entries)) {
|
||||
$lazyload = $this->conf->lazyload;
|
||||
$content_width = $this->conf->content_width;
|
||||
?>
|
||||
|
||||
<div id="stream" class="reader">
|
||||
@@ -10,7 +11,7 @@ if (!empty($this->entries)) {
|
||||
|
||||
<div class="flux<?php echo !$item->isRead () ? ' not_read' : ''; ?><?php echo $item->isFavorite () ? ' favorite' : ''; ?>" id="flux_<?php echo $item->id (); ?>">
|
||||
<div class="flux_content">
|
||||
<div class="content">
|
||||
<div class="content <?php echo $content_width; ?>">
|
||||
<?php
|
||||
$feed = FreshRSS_CategoryDAO::findFeed($this->cat_aside, $item->feed ()); //We most likely already have the feed object in cache
|
||||
if (empty($feed)) $feed = $item->feed (true);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<description><?php echo Minz_Translate::t ('rss_feeds_of', $this->rss_title); ?></description>
|
||||
<pubDate><?php echo date('D, d M Y H:i:s O'); ?></pubDate>
|
||||
<lastBuildDate><?php echo gmdate('D, d M Y H:i:s'); ?> GMT</lastBuildDate>
|
||||
<atom:link href="<?php echo Minz_Url::display ($this->rss_url, 'html', true); ?>" rel="self" type="application/rss+xml" />
|
||||
<atom:link href="<?php echo Minz_Url::display ($this->url, 'html', true); ?>" rel="self" type="application/rss+xml" />
|
||||
<?php
|
||||
foreach ($this->entries as $item) {
|
||||
?>
|
||||
|
||||
52
app/views/importExport/index.phtml
Normal file
52
app/views/importExport/index.phtml
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php $this->partial ('aside_feed'); ?>
|
||||
|
||||
<div class="post ">
|
||||
<a href="<?php echo _url ('index', 'index'); ?>"><?php echo Minz_Translate::t ('back_to_rss_feeds'); ?></a>
|
||||
|
||||
<form method="post" action="<?php echo _url('importExport', 'import'); ?>" enctype="multipart/form-data">
|
||||
<legend><?php echo Minz_Translate::t ('import'); ?></legend>
|
||||
<div class="form-group">
|
||||
<label class="group-name" for="file"><?php echo Minz_Translate::t ('file_to_import'); ?></label>
|
||||
<div class="group-controls">
|
||||
<input type="file" name="file" id="file" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group form-actions">
|
||||
<div class="group-controls">
|
||||
<button type="submit" class="btn btn-important"><?php echo Minz_Translate::t ('import'); ?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<?php if (count($this->feeds) > 0) { ?>
|
||||
<form method="post" action="<?php echo _url('importExport', 'export'); ?>">
|
||||
<legend><?php echo Minz_Translate::t ('export'); ?></legend>
|
||||
<div class="form-group">
|
||||
<div class="group-controls">
|
||||
<label class="checkbox" for="export_opml">
|
||||
<input type="checkbox" name="export_opml" id="export_opml" value="1" checked="checked" />
|
||||
<?php echo Minz_Translate::t ('export_opml'); ?>
|
||||
</label>
|
||||
|
||||
<label class="checkbox" for="export_starred">
|
||||
<input type="checkbox" name="export_starred" id="export_starred" value="1" checked="checked" />
|
||||
<?php echo Minz_Translate::t ('export_starred'); ?>
|
||||
</label>
|
||||
|
||||
<select name="export_feeds[]" size="<?php echo min(10, count($this->feeds)); ?>" multiple="multiple">
|
||||
<?php foreach ($this->feeds as $feed) { ?>
|
||||
<option value="<?php echo $feed->id(); ?>"><?php echo $feed->name(); ?></option>
|
||||
<?php } ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group form-actions">
|
||||
<div class="group-controls">
|
||||
<button type="submit" class="btn btn-important"><?php echo Minz_Translate::t ('export'); ?></button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<?php } ?>
|
||||
</div>
|
||||
@@ -1,34 +1,32 @@
|
||||
<div class="prompt">
|
||||
<?php
|
||||
if (Minz_Configuration::canLogIn()) {
|
||||
?><h1><?php echo Minz_Translate::t('login'); ?></h1><?php
|
||||
<h1><?php echo Minz_Translate::t('login'); ?></h1><?php
|
||||
|
||||
switch (Minz_Configuration::authType()) {
|
||||
case 'form':
|
||||
?><form id="loginForm" method="post" action="<?php echo _url('index', 'formLogin'); ?>">
|
||||
<div>
|
||||
<label for="username"><?php echo Minz_Translate::t('username'); ?></label>
|
||||
<input type="text" id="username" name="username" size="16" required="required" maxlength="16" pattern="[0-9a-zA-Z]{1,16}" autofocus="autofocus" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="passwordPlain"><?php echo Minz_Translate::t('password'); ?></label>
|
||||
<input type="password" id="passwordPlain" required="required" />
|
||||
<input type="hidden" id="challenge" name="challenge" /><br />
|
||||
<noscript><strong><?php echo Minz_Translate::t('javascript_should_be_activated'); ?></strong></noscript>
|
||||
</div>
|
||||
<div>
|
||||
<button id="loginButton" type="submit" class="btn btn-important"><?php echo Minz_Translate::t('login'); ?></button>
|
||||
</div>
|
||||
</form><?php
|
||||
break;
|
||||
|
||||
case 'form':
|
||||
?><form id="loginForm" method="post" action="<?php echo _url('index', 'formLogin'); ?>">
|
||||
<p>
|
||||
<label for="username"><?php echo Minz_Translate::t('username'); ?></label>
|
||||
<input type="text" id="username" name="username" size="16" required="required" maxlength="16" pattern="[0-9a-zA-Z]{1,16}" autofocus="autofocus" />
|
||||
</p><p>
|
||||
<label for="passwordPlain"><?php echo Minz_Translate::t('password'); ?></label>
|
||||
<input type="password" id="passwordPlain" required="required" />
|
||||
<input type="hidden" id="challenge" name="challenge" /><br />
|
||||
<noscript><strong><?php echo Minz_Translate::t('javascript_should_be_activated'); ?></strong></noscript>
|
||||
</p><p>
|
||||
<button id="loginButton" type="submit" class="btn btn-important"><?php echo Minz_Translate::t('login'); ?></button>
|
||||
</p>
|
||||
</form><?php
|
||||
break;
|
||||
case 'persona':
|
||||
?><p>
|
||||
<?php echo FreshRSS_Themes::icon('login'); ?>
|
||||
<a class="signin" href="#"><?php echo Minz_Translate::t('login_with_persona'); ?></a>
|
||||
</p><?php
|
||||
break;
|
||||
} ?>
|
||||
|
||||
case 'persona':
|
||||
?><p><?php echo FreshRSS_Themes::icon('login'); ?> <a class="signin" href="#"><?php echo Minz_Translate::t('login'); ?></a></p><?php
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
?><h1>FreshRSS</h1>
|
||||
<p><?php echo Minz_Translate::t('forbidden_access', Minz_Configuration::authType()); ?></p><?php
|
||||
}
|
||||
?>
|
||||
|
||||
<p><a href="<?php echo _url('index', 'about'); ?>"><?php echo Minz_Translate::t('about_freshrss'); ?></a></p>
|
||||
<p><a href="<?php echo _url('index', 'about'); ?>"><?php echo Minz_Translate::t('about_freshrss'); ?></a></p>
|
||||
</div>
|
||||
|
||||
@@ -5,26 +5,21 @@ $output = Minz_Request::param ('output', 'normal');
|
||||
if ($this->loginOk || Minz_Configuration::allowAnonymous()) {
|
||||
if ($output === 'normal') {
|
||||
$this->renderHelper ('view/normal_view');
|
||||
} elseif ($output === 'rss') {
|
||||
$this->renderHelper ('view/rss_view');
|
||||
} elseif ($output === 'reader') {
|
||||
$this->renderHelper ('view/reader_view');
|
||||
} elseif ($output === 'global') {
|
||||
$this->renderHelper ('view/global_view');
|
||||
} elseif ($output === 'rss') {
|
||||
$this->renderHelper ('view/rss_view');
|
||||
} else {
|
||||
Minz_Request::_param ('output', 'normal');
|
||||
$output = 'normal';
|
||||
$this->renderHelper ('view/normal_view');
|
||||
}
|
||||
} elseif ($output === 'rss') {
|
||||
$token = $this->conf->token;
|
||||
$token_param = Minz_Request::param ('token', '');
|
||||
$token_is_ok = ($token != '' && $token == $token_param);
|
||||
if ($token_is_ok) {
|
||||
$this->renderHelper ('view/rss_view');
|
||||
} else {
|
||||
Minz_Request::forward(array('c' => 'index', 'a' => 'formLogin'), true);
|
||||
}
|
||||
// token has already been checked in the controller so we can show the view
|
||||
$this->renderHelper ('view/rss_view');
|
||||
} else {
|
||||
Minz_Request::forward(array('c' => 'index', 'a' => 'formLogin'), true);
|
||||
// Normally, it should not happen, but log it anyway
|
||||
Minz_Log::record ('Something is wrong in ' . __FILE__ . ' line ' . __LINE__, Minz_Log::ERROR);
|
||||
}
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
"use strict";
|
||||
var feeds = [];
|
||||
<?php foreach ($this->feeds as $feed) { ?>
|
||||
feeds.push("<?php echo Minz_Url::display (array ('c' => 'feed', 'a' => 'actualize', 'params' => array ('id' => $feed->id (), 'ajax' => '1')), 'php'); ?>");
|
||||
<?php } ?>
|
||||
var feeds = [<?php
|
||||
foreach ($this->feeds as $feed) {
|
||||
echo "'", Minz_Url::display(array('c' => 'feed', 'a' => 'actualize', 'params' => array('id' => $feed->id(), 'ajax' => '1')), 'php'), "',\n";
|
||||
}
|
||||
?>],
|
||||
feed_processed = 0,
|
||||
feed_count = feeds.length;
|
||||
|
||||
function initProgressBar(init) {
|
||||
if (init) {
|
||||
$("body").after("\<div id=\"actualizeProgress\" class=\"actualizeProgress\">\
|
||||
<?php echo Minz_Translate::t ('refresh'); ?> <span class=\"progress\">0 / " + feeds.length + "</span><br />\
|
||||
<progress id=\"actualizeProgressBar\" value=\"0\" max=\"" + feeds.length + "\"></progress>\
|
||||
$("body").after("\<div id=\"actualizeProgress\" class=\"notification good\">\
|
||||
<?php echo Minz_Translate::t ('refresh'); ?> <span class=\"progress\">0 / " + feed_count + "</span><br />\
|
||||
<progress id=\"actualizeProgressBar\" value=\"0\" max=\"" + feed_count + "\"></progress>\
|
||||
</div>");
|
||||
} else {
|
||||
window.location.reload();
|
||||
@@ -16,27 +19,37 @@ function initProgressBar(init) {
|
||||
}
|
||||
function updateProgressBar(i) {
|
||||
$("#actualizeProgressBar").val(i);
|
||||
$("#actualizeProgress .progress").html(i + " / " + feeds.length);
|
||||
$("#actualizeProgress .progress").html(i + " / " + feed_count);
|
||||
}
|
||||
|
||||
function updateFeeds() {
|
||||
if (feeds.length === 0) {
|
||||
if (feed_count === 0) {
|
||||
openNotification("<?php echo Minz_Translate::t ('no_feed_to_refresh'); ?>", "good");
|
||||
return;
|
||||
}
|
||||
initProgressBar(true);
|
||||
|
||||
var i = 0;
|
||||
for (var f in feeds) {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: feeds[f],
|
||||
}).done(function (data) {
|
||||
i++;
|
||||
updateProgressBar(i);
|
||||
|
||||
if (i === feeds.length) {
|
||||
initProgressBar(false);
|
||||
}
|
||||
});
|
||||
for (var i = 0; i < 10; i++) {
|
||||
updateFeed();
|
||||
}
|
||||
}
|
||||
|
||||
function updateFeed() {
|
||||
var feed = feeds.pop();
|
||||
if (feed == undefined) {
|
||||
return;
|
||||
}
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: feed,
|
||||
}).complete(function (data) {
|
||||
feed_processed++;
|
||||
updateProgressBar(feed_processed);
|
||||
|
||||
if (feed_processed === feed_count) {
|
||||
initProgressBar(false);
|
||||
} else {
|
||||
updateFeed();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
<?php
|
||||
define('FRESHRSS_VERSION', '0.7');
|
||||
define('FRESHRSS_VERSION', '0.8-dev');
|
||||
define('FRESHRSS_WEBSITE', 'http://freshrss.org');
|
||||
|
||||
// PHP text output compression http://php.net/ob_gzhandler (better to do it at Web server level)
|
||||
define('PHP_COMPRESSION', false);
|
||||
|
||||
// Constantes de chemins
|
||||
define('FRESHRSS_PATH', dirname(__FILE__));
|
||||
|
||||
@@ -15,3 +18,5 @@ define('FRESHRSS_PATH', dirname(__FILE__));
|
||||
|
||||
define('LIB_PATH', FRESHRSS_PATH . '/lib');
|
||||
define('APP_PATH', FRESHRSS_PATH . '/app');
|
||||
|
||||
define('TMP_PATH', sys_get_temp_dir());
|
||||
|
||||
75
data/shares.php
Normal file
75
data/shares.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This is a configuration file. You shouldn't modify it unless you know what
|
||||
* you are doing. If you want to add a share type, this is where you need to do
|
||||
* it.
|
||||
*
|
||||
* For each share there is different configuration options. Here is the description
|
||||
* of those options:
|
||||
* - url is a mandatory option. It is a string representing the share URL. It
|
||||
* supports 3 different placeholders for custom data. The ~URL~ placeholder
|
||||
* represents the URL of the system used to share, it is configured by the
|
||||
* user. The ~LINK~ placeholder represents the link of the shared article.
|
||||
* The ~TITLE~ placeholder represents the title of the shared article.
|
||||
* - transform is an array of transformation to apply on links and titles
|
||||
* - help is a URL to a help page
|
||||
*/
|
||||
|
||||
return array(
|
||||
'shaarli' => array(
|
||||
'url' => '~URL~?post=~LINK~&title=~TITLE~&source=FreshRSS',
|
||||
'transform' => array('urlencode'),
|
||||
'help' => 'http://sebsauvage.net/wiki/doku.php?id=php:shaarli',
|
||||
'form' => 'advanced',
|
||||
),
|
||||
'blogotext' => array(
|
||||
'url' => '~URL~/admin/links.php?url=~LINK~',
|
||||
'transform' => array(),
|
||||
'help' => 'http://lehollandaisvolant.net/blogotext/fr/',
|
||||
'form' => 'advanced',
|
||||
),
|
||||
'wallabag' => array(
|
||||
'url' => '~URL~?action=add&url=~LINK~',
|
||||
'transform' => array(
|
||||
'link' => array('base64_encode'),
|
||||
'title' => array(),
|
||||
),
|
||||
'help' => 'http://www.wallabag.org/',
|
||||
'form' => 'advanced',
|
||||
),
|
||||
'diaspora' => array(
|
||||
'url' => '~URL~/bookmarklet?url=~LINK~&title=~TITLE~',
|
||||
'transform' => array('urlencode'),
|
||||
'help' => 'https://diasporafoundation.org/',
|
||||
'form' => 'advanced',
|
||||
),
|
||||
'twitter' => array(
|
||||
'url' => 'https://twitter.com/share?url=~LINK~&text=~TITLE~',
|
||||
'transform' => array('urlencode'),
|
||||
'form' => 'simple',
|
||||
),
|
||||
'g+' => array(
|
||||
'url' => 'https://plus.google.com/share?url=~LINK~',
|
||||
'transform' => array('urlencode'),
|
||||
'form' => 'simple',
|
||||
),
|
||||
'facebook' => array(
|
||||
'url' => 'https://www.facebook.com/sharer.php?u=~LINK~&t=~TITLE~',
|
||||
'transform' => array('urlencode'),
|
||||
'form' => 'simple',
|
||||
),
|
||||
'email' => array(
|
||||
'url' => 'mailto:?subject=~TITLE~&body=~LINK~',
|
||||
'transform' => array(
|
||||
'link' => array('urlencode'),
|
||||
'title' => array(),
|
||||
),
|
||||
'form' => 'simple',
|
||||
),
|
||||
'print' => array(
|
||||
'url' => '#',
|
||||
'transform' => array(),
|
||||
'form' => 'simple',
|
||||
),
|
||||
);
|
||||
@@ -8,16 +8,12 @@
|
||||
* La classe ActionController représente le contrôleur de l'application
|
||||
*/
|
||||
class Minz_ActionController {
|
||||
protected $router;
|
||||
protected $view;
|
||||
|
||||
/**
|
||||
* Constructeur
|
||||
* @param $controller nom du controller
|
||||
* @param $action nom de l'action à lancer
|
||||
*/
|
||||
public function __construct ($router) {
|
||||
$this->router = $router;
|
||||
public function __construct () {
|
||||
$this->view = new Minz_View ();
|
||||
$this->view->attributeParams ();
|
||||
}
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* MINZ - Copyright 2011 Marien Fressinaud
|
||||
* Sous licence AGPL3 <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* La classe Cache permet de gérer facilement les pages en cache
|
||||
*/
|
||||
class Minz_Cache {
|
||||
/**
|
||||
* $expire timestamp auquel expire le cache de $url
|
||||
*/
|
||||
private $expire = 0;
|
||||
|
||||
/**
|
||||
* $file est le nom du fichier de cache
|
||||
*/
|
||||
private $file = '';
|
||||
|
||||
/**
|
||||
* $enabled permet de déterminer si le cache est activé
|
||||
*/
|
||||
private static $enabled = true;
|
||||
|
||||
/**
|
||||
* Constructeur
|
||||
*/
|
||||
public function __construct () {
|
||||
$this->_fileName ();
|
||||
$this->_expire ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setteurs
|
||||
*/
|
||||
public function _fileName () {
|
||||
$file = md5 (Minz_Request::getURI ());
|
||||
|
||||
$this->file = CACHE_PATH . '/'.$file;
|
||||
}
|
||||
|
||||
public function _expire () {
|
||||
if ($this->exist ()) {
|
||||
$this->expire = filemtime ($this->file)
|
||||
+ Minz_Configuration::delayCache ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de savoir si le cache est activé
|
||||
* @return true si activé, false sinon
|
||||
*/
|
||||
public static function isEnabled () {
|
||||
return Minz_Configuration::cacheEnabled () && self::$enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Active / désactive le cache
|
||||
*/
|
||||
public static function switchOn () {
|
||||
self::$enabled = true;
|
||||
}
|
||||
public static function switchOff () {
|
||||
self::$enabled = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Détermine si le cache de $url a expiré ou non
|
||||
* @return true si il a expiré, false sinon
|
||||
*/
|
||||
public function expired () {
|
||||
return time () > $this->expire;
|
||||
}
|
||||
|
||||
/**
|
||||
* Affiche le contenu du cache
|
||||
* @print le code html du cache
|
||||
*/
|
||||
public function render () {
|
||||
if ($this->exist ()) {
|
||||
include ($this->file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enregistre $html en cache
|
||||
* @param $html le html à mettre en cache
|
||||
*/
|
||||
public function cache ($html) {
|
||||
file_put_contents ($this->file, $html);
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de savoir si le cache existe
|
||||
* @return true si il existe, false sinon
|
||||
*/
|
||||
public function exist () {
|
||||
return file_exists ($this->file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Nettoie le cache en supprimant tous les fichiers
|
||||
*/
|
||||
public static function clean () {
|
||||
$files = opendir (CACHE_PATH);
|
||||
|
||||
while ($fic = readdir ($files)) {
|
||||
if ($fic != '.' && $fic != '..') {
|
||||
unlink (CACHE_PATH.'/'.$fic);
|
||||
}
|
||||
}
|
||||
|
||||
closedir ($files);
|
||||
}
|
||||
}
|
||||
@@ -30,12 +30,9 @@ class Minz_Configuration {
|
||||
* définition des variables de configuration
|
||||
* $salt une chaîne de caractères aléatoires (obligatoire)
|
||||
* $environment gère le niveau d'affichage pour log et erreurs
|
||||
* $use_url_rewriting indique si on utilise l'url_rewriting
|
||||
* $base_url le chemin de base pour accéder à l'application
|
||||
* $title le nom de l'application
|
||||
* $language la langue par défaut de l'application
|
||||
* $cacheEnabled permet de savoir si le cache doit être activé
|
||||
* $delayCache la limite de cache
|
||||
* $db paramètres pour la base de données (tableau)
|
||||
* - host le serveur de la base
|
||||
* - user nom d'utilisateur
|
||||
@@ -45,14 +42,14 @@ class Minz_Configuration {
|
||||
private static $salt = '';
|
||||
private static $environment = Minz_Configuration::PRODUCTION;
|
||||
private static $base_url = '';
|
||||
private static $use_url_rewriting = false;
|
||||
private static $title = '';
|
||||
private static $language = 'en';
|
||||
private static $cache_enabled = false;
|
||||
private static $delay_cache = 3600;
|
||||
private static $default_user = '';
|
||||
private static $allow_anonymous = false;
|
||||
private static $allow_anonymous_refresh = false;
|
||||
private static $auth_type = 'none';
|
||||
private static $api_enabled = false;
|
||||
private static $unsafe_autologin_enabled = false;
|
||||
|
||||
private static $db = array (
|
||||
'type' => 'mysql',
|
||||
@@ -91,21 +88,12 @@ class Minz_Configuration {
|
||||
public static function baseUrl () {
|
||||
return self::$base_url;
|
||||
}
|
||||
public static function useUrlRewriting () {
|
||||
return self::$use_url_rewriting;
|
||||
}
|
||||
public static function title () {
|
||||
return self::$title;
|
||||
}
|
||||
public static function language () {
|
||||
return self::$language;
|
||||
}
|
||||
public static function cacheEnabled () {
|
||||
return self::$cache_enabled;
|
||||
}
|
||||
public static function delayCache () {
|
||||
return self::$delay_cache;
|
||||
}
|
||||
public static function dataBase () {
|
||||
return self::$db;
|
||||
}
|
||||
@@ -118,6 +106,9 @@ class Minz_Configuration {
|
||||
public static function allowAnonymous() {
|
||||
return self::$allow_anonymous;
|
||||
}
|
||||
public static function allowAnonymousRefresh() {
|
||||
return self::$allow_anonymous_refresh;
|
||||
}
|
||||
public static function authType() {
|
||||
return self::$auth_type;
|
||||
}
|
||||
@@ -127,10 +118,19 @@ class Minz_Configuration {
|
||||
public static function canLogIn() {
|
||||
return self::$auth_type === 'form' || self::$auth_type === 'persona';
|
||||
}
|
||||
public static function apiEnabled() {
|
||||
return self::$api_enabled;
|
||||
}
|
||||
public static function unsafeAutologinEnabled() {
|
||||
return self::$unsafe_autologin_enabled;
|
||||
}
|
||||
|
||||
public static function _allowAnonymous($allow = false) {
|
||||
self::$allow_anonymous = ((bool)$allow) && self::canLogIn();
|
||||
}
|
||||
public static function _allowAnonymousRefresh($allow = false) {
|
||||
self::$allow_anonymous_refresh = ((bool)$allow) && self::allowAnonymous();
|
||||
}
|
||||
public static function _authType($value) {
|
||||
$value = strtolower($value);
|
||||
switch ($value) {
|
||||
@@ -144,6 +144,13 @@ class Minz_Configuration {
|
||||
self::_allowAnonymous(self::$allow_anonymous);
|
||||
}
|
||||
|
||||
public static function _enableApi($value = false) {
|
||||
self::$api_enabled = (bool)$value;
|
||||
}
|
||||
public static function _enableAutologin($value = false) {
|
||||
self::$unsafe_autologin_enabled = (bool)$value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise les variables de configuration
|
||||
* @exception Minz_FileNotExistException si le CONF_PATH_NAME n'existe pas
|
||||
@@ -164,13 +171,15 @@ class Minz_Configuration {
|
||||
$ini_array = array(
|
||||
'general' => array(
|
||||
'environment' => self::environment(true),
|
||||
'use_url_rewriting' => self::$use_url_rewriting,
|
||||
'salt' => self::$salt,
|
||||
'base_url' => self::$base_url,
|
||||
'title' => self::$title,
|
||||
'default_user' => self::$default_user,
|
||||
'allow_anonymous' => self::$allow_anonymous,
|
||||
'allow_anonymous_refresh' => self::$allow_anonymous_refresh,
|
||||
'auth_type' => self::$auth_type,
|
||||
'api_enabled' => self::$api_enabled,
|
||||
'unsafe_autologin_enabled' => self::$unsafe_autologin_enabled,
|
||||
),
|
||||
'db' => self::$db,
|
||||
);
|
||||
@@ -247,9 +256,6 @@ class Minz_Configuration {
|
||||
if (isset ($general['base_url'])) {
|
||||
self::$base_url = $general['base_url'];
|
||||
}
|
||||
if (isset ($general['use_url_rewriting'])) {
|
||||
self::$use_url_rewriting = $general['use_url_rewriting'];
|
||||
}
|
||||
|
||||
if (isset ($general['title'])) {
|
||||
self::$title = $general['title'];
|
||||
@@ -257,18 +263,6 @@ class Minz_Configuration {
|
||||
if (isset ($general['language'])) {
|
||||
self::$language = $general['language'];
|
||||
}
|
||||
if (isset ($general['cache_enabled'])) {
|
||||
self::$cache_enabled = $general['cache_enabled'];
|
||||
if (CACHE_PATH === false && self::$cache_enabled) {
|
||||
throw new FileNotExistException (
|
||||
'CACHE_PATH',
|
||||
Minz_Exception::ERROR
|
||||
);
|
||||
}
|
||||
}
|
||||
if (isset ($general['delay_cache'])) {
|
||||
self::$delay_cache = inval($general['delay_cache']);
|
||||
}
|
||||
if (isset ($general['default_user'])) {
|
||||
self::$default_user = $general['default_user'];
|
||||
}
|
||||
@@ -276,7 +270,28 @@ class Minz_Configuration {
|
||||
self::_authType($general['auth_type']);
|
||||
}
|
||||
if (isset ($general['allow_anonymous'])) {
|
||||
self::$allow_anonymous = ((bool)($general['allow_anonymous'])) && ($general['allow_anonymous'] !== 'no');
|
||||
self::$allow_anonymous = (
|
||||
((bool)($general['allow_anonymous'])) &&
|
||||
($general['allow_anonymous'] !== 'no')
|
||||
);
|
||||
}
|
||||
if (isset ($general['allow_anonymous_refresh'])) {
|
||||
self::$allow_anonymous_refresh = (
|
||||
((bool)($general['allow_anonymous_refresh'])) &&
|
||||
($general['allow_anonymous_refresh'] !== 'no')
|
||||
);
|
||||
}
|
||||
if (isset ($general['api_enabled'])) {
|
||||
self::$api_enabled = (
|
||||
((bool)($general['api_enabled'])) &&
|
||||
($general['api_enabled'] !== 'no')
|
||||
);
|
||||
}
|
||||
if (isset ($general['unsafe_autologin_enabled'])) {
|
||||
self::$unsafe_autologin_enabled = (
|
||||
((bool)($general['unsafe_autologin_enabled'])) &&
|
||||
($general['unsafe_autologin_enabled'] !== 'no')
|
||||
);
|
||||
}
|
||||
|
||||
// Base de données
|
||||
|
||||
@@ -14,85 +14,55 @@ class Minz_Dispatcher {
|
||||
|
||||
/* singleton */
|
||||
private static $instance = null;
|
||||
private static $needsReset;
|
||||
|
||||
private $router;
|
||||
private $controller;
|
||||
|
||||
/**
|
||||
* Récupère l'instance du Dispatcher
|
||||
*/
|
||||
public static function getInstance ($router) {
|
||||
public static function getInstance () {
|
||||
if (self::$instance === null) {
|
||||
self::$instance = new Minz_Dispatcher ($router);
|
||||
self::$instance = new Minz_Dispatcher ();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructeur
|
||||
*/
|
||||
private function __construct ($router) {
|
||||
$this->router = $router;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lance le controller indiqué dans Request
|
||||
* Remplit le body de Response à partir de la Vue
|
||||
* @exception Minz_Exception
|
||||
*/
|
||||
public function run ($ob = true) {
|
||||
$cache = new Minz_Cache();
|
||||
// Le ob_start est dupliqué : sans ça il y a un bug sous Firefox
|
||||
// ici on l'appelle avec 'ob_gzhandler', après sans.
|
||||
// Vraisemblablement la compression fonctionne mais c'est sale
|
||||
// J'ignore les effets de bord :(
|
||||
if ($ob) {
|
||||
ob_start ('ob_gzhandler');
|
||||
}
|
||||
public function run () {
|
||||
do {
|
||||
self::$needsReset = false;
|
||||
|
||||
if (Minz_Cache::isEnabled () && !$cache->expired ()) {
|
||||
if ($ob) {
|
||||
ob_start ();
|
||||
}
|
||||
$cache->render ();
|
||||
if ($ob) {
|
||||
$text = ob_get_clean();
|
||||
}
|
||||
} else {
|
||||
$text = ''; //TODO: Clean this code
|
||||
while (Minz_Request::$reseted) {
|
||||
Minz_Request::$reseted = false;
|
||||
|
||||
try {
|
||||
$this->createController ('FreshRSS_' . Minz_Request::controllerName () . '_Controller');
|
||||
$this->controller->init ();
|
||||
$this->controller->firstAction ();
|
||||
try {
|
||||
$this->createController ('FreshRSS_' . Minz_Request::controllerName () . '_Controller');
|
||||
$this->controller->init ();
|
||||
$this->controller->firstAction ();
|
||||
if (!self::$needsReset) {
|
||||
$this->launchAction (
|
||||
Minz_Request::actionName ()
|
||||
. 'Action'
|
||||
);
|
||||
$this->controller->lastAction ();
|
||||
|
||||
if (!Minz_Request::$reseted) {
|
||||
if ($ob) {
|
||||
ob_start ();
|
||||
}
|
||||
$this->controller->view ()->build ();
|
||||
if ($ob) {
|
||||
$text = ob_get_clean();
|
||||
}
|
||||
}
|
||||
} catch (Minz_Exception $e) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
$this->controller->lastAction ();
|
||||
|
||||
if (Minz_Cache::isEnabled ()) {
|
||||
$cache->cache ($text);
|
||||
if (!self::$needsReset) {
|
||||
$this->controller->view ()->build ();
|
||||
}
|
||||
} catch (Minz_Exception $e) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
} while (self::$needsReset);
|
||||
}
|
||||
|
||||
Minz_Response::setBody ($text);
|
||||
/**
|
||||
* Informe le contrôleur qu'il doit recommancer car la requête a été modifiée
|
||||
*/
|
||||
public static function reset() {
|
||||
self::$needsReset = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,7 +82,7 @@ class Minz_Dispatcher {
|
||||
Minz_Exception::ERROR
|
||||
);
|
||||
}
|
||||
$this->controller = new $controller_name ($this->router);
|
||||
$this->controller = new $controller_name ();
|
||||
|
||||
if (! ($this->controller instanceof Minz_ActionController)) {
|
||||
throw new Minz_ControllerNotActionControllerException (
|
||||
@@ -129,21 +99,19 @@ class Minz_Dispatcher {
|
||||
* le controller
|
||||
*/
|
||||
private function launchAction ($action_name) {
|
||||
if (!Minz_Request::$reseted) {
|
||||
if (!is_callable (array (
|
||||
$this->controller,
|
||||
$action_name
|
||||
))) {
|
||||
throw new Minz_ActionException (
|
||||
get_class ($this->controller),
|
||||
$action_name,
|
||||
Minz_Exception::ERROR
|
||||
);
|
||||
}
|
||||
call_user_func (array (
|
||||
$this->controller,
|
||||
$action_name
|
||||
));
|
||||
if (!is_callable (array (
|
||||
$this->controller,
|
||||
$action_name
|
||||
))) {
|
||||
throw new Minz_ActionException (
|
||||
get_class ($this->controller),
|
||||
$action_name,
|
||||
Minz_Exception::ERROR
|
||||
);
|
||||
}
|
||||
call_user_func (array (
|
||||
$this->controller,
|
||||
$action_name
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,13 +23,32 @@ class Minz_Error {
|
||||
$logs = self::processLogs ($logs);
|
||||
$error_filename = APP_PATH . '/Controllers/errorController.php';
|
||||
|
||||
switch ($code) {
|
||||
case 200 :
|
||||
header('HTTP/1.1 200 OK');
|
||||
break;
|
||||
case 403 :
|
||||
header('HTTP/1.1 403 Forbidden');
|
||||
break;
|
||||
case 404 :
|
||||
header('HTTP/1.1 404 Not Found');
|
||||
break;
|
||||
case 500 :
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
break;
|
||||
case 503 :
|
||||
header('HTTP/1.1 503 Service Unavailable');
|
||||
break;
|
||||
default :
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
}
|
||||
|
||||
if (file_exists ($error_filename)) {
|
||||
$params = array (
|
||||
'code' => $code,
|
||||
'logs' => $logs
|
||||
);
|
||||
|
||||
Minz_Response::setHeader ($code);
|
||||
if ($redirect) {
|
||||
Minz_Request::forward (array (
|
||||
'c' => 'error'
|
||||
@@ -41,19 +60,16 @@ class Minz_Error {
|
||||
), false);
|
||||
}
|
||||
} else {
|
||||
$text = '<h1>An error occured</h1>'."\n";
|
||||
echo '<h1>An error occured</h1>' . "\n";
|
||||
|
||||
if (!empty ($logs)) {
|
||||
$text .= '<ul>'."\n";
|
||||
echo '<ul>' . "\n";
|
||||
foreach ($logs as $log) {
|
||||
$text .= '<li>' . $log . '</li>'."\n";
|
||||
echo '<li>' . $log . '</li>' . "\n";
|
||||
}
|
||||
$text .= '</ul>'."\n";
|
||||
echo '</ul>' . "\n";
|
||||
}
|
||||
|
||||
Minz_Response::setHeader ($code);
|
||||
Minz_Response::setBody ($text);
|
||||
Minz_Response::send ();
|
||||
exit ();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,13 +24,10 @@
|
||||
*/
|
||||
class Minz_FrontController {
|
||||
protected $dispatcher;
|
||||
protected $router;
|
||||
|
||||
private $useOb = true;
|
||||
|
||||
/**
|
||||
* Constructeur
|
||||
* Initialise le router et le dispatcher
|
||||
* Initialise le dispatcher, met à jour la Request
|
||||
*/
|
||||
public function __construct () {
|
||||
if (LOG_PATH === false) {
|
||||
@@ -42,29 +39,50 @@ class Minz_FrontController {
|
||||
|
||||
Minz_Request::init ();
|
||||
|
||||
$this->router = new Minz_Router ();
|
||||
$this->router->init ();
|
||||
} catch (Minz_RouteNotFoundException $e) {
|
||||
Minz_Log::record ($e->getMessage (), Minz_Log::ERROR);
|
||||
Minz_Error::error (
|
||||
404,
|
||||
array ('error' => array ($e->getMessage ()))
|
||||
$url = $this->buildUrl();
|
||||
$url['params'] = array_merge (
|
||||
$url['params'],
|
||||
Minz_Request::fetchPOST ()
|
||||
);
|
||||
Minz_Request::forward ($url);
|
||||
} catch (Minz_Exception $e) {
|
||||
Minz_Log::record ($e->getMessage (), Minz_Log::ERROR);
|
||||
$this->killApp ($e->getMessage ());
|
||||
}
|
||||
|
||||
$this->dispatcher = Minz_Dispatcher::getInstance ($this->router);
|
||||
$this->dispatcher = Minz_Dispatcher::getInstance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Démarre l'application (lance le dispatcher et renvoie la réponse
|
||||
* Retourne un tableau représentant l'url passée par la barre d'adresses
|
||||
* @return tableau représentant l'url
|
||||
*/
|
||||
private function buildUrl() {
|
||||
$url = array ();
|
||||
|
||||
$url['c'] = Minz_Request::fetchGET (
|
||||
'c',
|
||||
Minz_Request::defaultControllerName ()
|
||||
);
|
||||
$url['a'] = Minz_Request::fetchGET (
|
||||
'a',
|
||||
Minz_Request::defaultActionName ()
|
||||
);
|
||||
$url['params'] = Minz_Request::fetchGET ();
|
||||
|
||||
// post-traitement
|
||||
unset ($url['params']['c']);
|
||||
unset ($url['params']['a']);
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Démarre l'application (lance le dispatcher et renvoie la réponse)
|
||||
*/
|
||||
public function run () {
|
||||
try {
|
||||
$this->dispatcher->run ($this->useOb);
|
||||
Minz_Response::send ();
|
||||
$this->dispatcher->run();
|
||||
} catch (Minz_Exception $e) {
|
||||
try {
|
||||
Minz_Log::record ($e->getMessage (), Minz_Log::ERROR);
|
||||
@@ -96,15 +114,4 @@ class Minz_FrontController {
|
||||
}
|
||||
exit ('### Application problem ###<br />'."\n".$txt);
|
||||
}
|
||||
|
||||
public function useOb() {
|
||||
return $this->useOb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use ob_start('ob_gzhandler') or not.
|
||||
*/
|
||||
public function _useOb($ob) {
|
||||
return $this->useOb = (bool)$ob;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,4 +80,21 @@ class Minz_Log {
|
||||
self::record($msg_get, Minz_Log::DEBUG, $file_name);
|
||||
self::record($msg_post, Minz_Log::DEBUG, $file_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Some helpers to Minz_Log::record() method
|
||||
* Parameters are the same of those of the record() method.
|
||||
*/
|
||||
public static function debug($msg, $file_name = null) {
|
||||
self::record($msg, Minz_Log::DEBUG, $file_name);
|
||||
}
|
||||
public static function notice($msg, $file_name = null) {
|
||||
self::record($msg, Minz_Log::NOTICE, $file_name);
|
||||
}
|
||||
public static function warning($msg, $file_name = null) {
|
||||
self::record($msg, Minz_Log::WARNING, $file_name);
|
||||
}
|
||||
public static function error($msg, $file_name = null) {
|
||||
self::record($msg, Minz_Log::ERROR, $file_name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,8 +15,6 @@ class Minz_Request {
|
||||
private static $default_controller_name = 'index';
|
||||
private static $default_action_name = 'index';
|
||||
|
||||
public static $reseted = true;
|
||||
|
||||
/**
|
||||
* Getteurs
|
||||
*/
|
||||
@@ -137,14 +135,13 @@ class Minz_Request {
|
||||
header ('Location: ' . Minz_Url::display ($url, 'php'));
|
||||
exit ();
|
||||
} else {
|
||||
self::$reseted = true;
|
||||
|
||||
self::_controllerName ($url['c']);
|
||||
self::_actionName ($url['a']);
|
||||
self::_params (array_merge (
|
||||
self::$params,
|
||||
$url['params']
|
||||
));
|
||||
Minz_Dispatcher::reset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,6 +196,6 @@ class Minz_Request {
|
||||
}
|
||||
|
||||
public static function isPost () {
|
||||
return !empty ($_POST) || !empty ($_FILES);
|
||||
return $_SERVER['REQUEST_METHOD'] === 'POST';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* MINZ - Copyright 2011 Marien Fressinaud
|
||||
* Sous licence AGPL3 <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* Response représente la requête http renvoyée à l'utilisateur
|
||||
*/
|
||||
class Minz_Response {
|
||||
private static $header = 'HTTP/1.0 200 OK';
|
||||
private static $body = '';
|
||||
|
||||
/**
|
||||
* Mets à jour le body de la Response
|
||||
* @param $text le texte à incorporer dans le body
|
||||
*/
|
||||
public static function setBody ($text) {
|
||||
self::$body = $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mets à jour le header de la Response
|
||||
* @param $code le code HTTP, valeurs possibles
|
||||
* - 200 (OK)
|
||||
* - 403 (Forbidden)
|
||||
* - 404 (Forbidden)
|
||||
* - 500 (Forbidden) -> par défaut si $code erroné
|
||||
* - 503 (Forbidden)
|
||||
*/
|
||||
public static function setHeader ($code) {
|
||||
switch ($code) {
|
||||
case 200 :
|
||||
self::$header = 'HTTP/1.0 200 OK';
|
||||
break;
|
||||
case 403 :
|
||||
self::$header = 'HTTP/1.0 403 Forbidden';
|
||||
break;
|
||||
case 404 :
|
||||
self::$header = 'HTTP/1.0 404 Not Found';
|
||||
break;
|
||||
case 500 :
|
||||
self::$header = 'HTTP/1.0 500 Internal Server Error';
|
||||
break;
|
||||
case 503 :
|
||||
self::$header = 'HTTP/1.0 503 Service Unavailable';
|
||||
break;
|
||||
default :
|
||||
self::$header = 'HTTP/1.0 500 Internal Server Error';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Envoie la Response à l'utilisateur
|
||||
*/
|
||||
public static function send () {
|
||||
header (self::$header);
|
||||
echo self::$body;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
class Minz_RouteNotFoundException extends Minz_Exception {
|
||||
private $route;
|
||||
|
||||
public function __construct ($route, $code = self::ERROR) {
|
||||
$this->route = $route;
|
||||
|
||||
$message = 'Route `' . $route . '` not found';
|
||||
|
||||
parent::__construct ($message, $code);
|
||||
}
|
||||
|
||||
public function route () {
|
||||
return $this->route;
|
||||
}
|
||||
}
|
||||
@@ -1,209 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* MINZ - Copyright 2011 Marien Fressinaud
|
||||
* Sous licence AGPL3 <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* La classe Router gère le routage de l'application
|
||||
* Les routes sont définies dans APP_PATH.'/configuration/routes.php'
|
||||
*/
|
||||
class Minz_Router {
|
||||
const ROUTES_PATH_NAME = '/configuration/routes.php';
|
||||
|
||||
private $routes = array ();
|
||||
|
||||
/**
|
||||
* Constructeur
|
||||
* @exception FileNotExistException si ROUTES_PATH_NAME n'existe pas
|
||||
* et que l'on utilise l'url rewriting
|
||||
*/
|
||||
public function __construct () {
|
||||
if (Minz_Configuration::useUrlRewriting ()) {
|
||||
if (file_exists (APP_PATH . self::ROUTES_PATH_NAME)) {
|
||||
$routes = include (
|
||||
APP_PATH . self::ROUTES_PATH_NAME
|
||||
);
|
||||
|
||||
if (!is_array ($routes)) {
|
||||
$routes = array ();
|
||||
}
|
||||
|
||||
$this->routes = array_map (
|
||||
array ('Url', 'checkUrl'),
|
||||
$routes
|
||||
);
|
||||
} else {
|
||||
throw new Minz_FileNotExistException (
|
||||
self::ROUTES_PATH_NAME,
|
||||
Minz_Exception::ERROR
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise le Router en déterminant le couple Controller / Action
|
||||
* Mets à jour la Request
|
||||
* @exception RouteNotFoundException si l'uri n'est pas présente dans
|
||||
* > la table de routage
|
||||
*/
|
||||
public function init () {
|
||||
$url = array ();
|
||||
|
||||
if (Minz_Configuration::useUrlRewriting ()) {
|
||||
try {
|
||||
$url = $this->buildWithRewriting ();
|
||||
} catch (Minz_RouteNotFoundException $e) {
|
||||
throw $e;
|
||||
}
|
||||
} else {
|
||||
$url = $this->buildWithoutRewriting ();
|
||||
}
|
||||
|
||||
$url['params'] = array_merge (
|
||||
$url['params'],
|
||||
Minz_Request::fetchPOST ()
|
||||
);
|
||||
|
||||
Minz_Request::forward ($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne un tableau représentant l'url passée par la barre d'adresses
|
||||
* Ne se base PAS sur la table de routage
|
||||
* @return tableau représentant l'url
|
||||
*/
|
||||
public function buildWithoutRewriting () {
|
||||
$url = array ();
|
||||
|
||||
$url['c'] = Minz_Request::fetchGET (
|
||||
'c',
|
||||
Minz_Request::defaultControllerName ()
|
||||
);
|
||||
$url['a'] = Minz_Request::fetchGET (
|
||||
'a',
|
||||
Minz_Request::defaultActionName ()
|
||||
);
|
||||
$url['params'] = Minz_Request::fetchGET ();
|
||||
|
||||
// post-traitement
|
||||
unset ($url['params']['c']);
|
||||
unset ($url['params']['a']);
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne un tableau représentant l'url passée par la barre d'adresses
|
||||
* Se base sur la table de routage
|
||||
* @return tableau représentant l'url
|
||||
* @exception RouteNotFoundException si l'uri n'est pas présente dans
|
||||
* > la table de routage
|
||||
*/
|
||||
public function buildWithRewriting () {
|
||||
$url = array ();
|
||||
$uri = Minz_Request::getURI ();
|
||||
$find = false;
|
||||
|
||||
foreach ($this->routes as $route) {
|
||||
$regex = '*^' . $route['route'] . '$*';
|
||||
if (preg_match ($regex, $uri, $matches)) {
|
||||
$url['c'] = $route['controller'];
|
||||
$url['a'] = $route['action'];
|
||||
$url['params'] = $this->getParams (
|
||||
$route['params'],
|
||||
$matches
|
||||
);
|
||||
$find = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$find && $uri != '/') {
|
||||
throw new Minz_RouteNotFoundException (
|
||||
$uri,
|
||||
Minz_Exception::ERROR
|
||||
);
|
||||
}
|
||||
|
||||
// post-traitement
|
||||
$url = Minz_Url::checkUrl ($url);
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne l'uri d'une url en se basant sur la table de routage
|
||||
* @param l'url sous forme de tableau
|
||||
* @return l'uri formatée (string) selon une route trouvée
|
||||
*/
|
||||
public function printUriRewrited ($url) {
|
||||
$route = $this->searchRoute ($url);
|
||||
|
||||
if ($route !== false) {
|
||||
return $this->replaceParams ($route, $url['params']);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Recherche la route correspondante à une url
|
||||
* @param l'url sous forme de tableau
|
||||
* @return la route telle que spécifiée dans la table de routage,
|
||||
* false si pas trouvée
|
||||
*/
|
||||
public function searchRoute ($url) {
|
||||
foreach ($this->routes as $route) {
|
||||
if ($route['controller'] == $url['c']
|
||||
&& $route['action'] == $url['a']) {
|
||||
// calcule la différence des tableaux de params
|
||||
$params = array_flip ($route['params']);
|
||||
$difference_params = array_diff_key (
|
||||
$params,
|
||||
$url['params']
|
||||
);
|
||||
|
||||
// vérifie que pas de différence
|
||||
// et le cas où $params est vide et pas $url['params']
|
||||
if (empty ($difference_params)
|
||||
&& (!empty ($params) || empty ($url['params']))) {
|
||||
return $route;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère un tableau dont
|
||||
* - les clés sont définies dans $params_route
|
||||
* - les valeurs sont situées dans $matches
|
||||
* Le tableau $matches est décalé de +1 par rapport à $params_route
|
||||
*/
|
||||
private function getParams($params_route, $matches) {
|
||||
$params = array ();
|
||||
|
||||
for ($i = 0; $i < count ($params_route); $i++) {
|
||||
$param = $params_route[$i];
|
||||
$params[$param] = $matches[$i + 1];
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remplace les éléments de la route par les valeurs contenues dans $params
|
||||
*/
|
||||
private function replaceParams ($route, $params_replace) {
|
||||
$uri = $route['route'];
|
||||
$params = array();
|
||||
foreach($route['params'] as $param) {
|
||||
$uri = preg_replace('#\((.+)\)#U', $params_replace[$param], $uri, 1);
|
||||
}
|
||||
|
||||
return stripslashes($uri);
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,7 @@
|
||||
*/
|
||||
class Minz_Url {
|
||||
/**
|
||||
* Affiche une Url formatée selon que l'on utilise l'url_rewriting ou non
|
||||
* si oui, on cherche dans la table de routage la correspondance pour formater
|
||||
* Affiche une Url formatée
|
||||
* @param $url l'url à formater définie comme un tableau :
|
||||
* $url['c'] = controller
|
||||
* $url['a'] = action
|
||||
@@ -39,13 +38,7 @@ class Minz_Url {
|
||||
}
|
||||
|
||||
if ($isArray) {
|
||||
$router = new Minz_Router ();
|
||||
|
||||
if (Minz_Configuration::useUrlRewriting ()) {
|
||||
$url_string .= $router->printUriRewrited ($url);
|
||||
} else {
|
||||
$url_string .= self::printUri ($url, $encodage);
|
||||
}
|
||||
$url_string .= self::printUri ($url, $encodage);
|
||||
} else {
|
||||
$url_string .= $url;
|
||||
}
|
||||
@@ -54,14 +47,14 @@ class Minz_Url {
|
||||
}
|
||||
|
||||
/**
|
||||
* Construit l'URI d'une URL sans url rewriting
|
||||
* Construit l'URI d'une URL
|
||||
* @param l'url sous forme de tableau
|
||||
* @param $encodage pour indiquer comment encoder les & (& ou & pour html)
|
||||
* @return l'uri sous la forme ?key=value&key2=value2
|
||||
*/
|
||||
private static function printUri ($url, $encodage) {
|
||||
$uri = '';
|
||||
$separator = '/?';
|
||||
$separator = '?';
|
||||
|
||||
if($encodage == 'html') {
|
||||
$and = '&';
|
||||
|
||||
@@ -102,6 +102,16 @@ class Minz_View {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne renderHelper() dans une chaîne
|
||||
* @param $helper l'élément à traîter
|
||||
*/
|
||||
public function helperToString($helper) {
|
||||
ob_start();
|
||||
$this->renderHelper($helper);
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Permet de choisir si on souhaite utiliser le layout
|
||||
* @param $use true si on souhaite utiliser le layout, false sinon
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev-FreshRSS
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
@@ -50,7 +50,7 @@ define('SIMPLEPIE_NAME', 'SimplePie');
|
||||
/**
|
||||
* SimplePie Version
|
||||
*/
|
||||
define('SIMPLEPIE_VERSION', '1.3.1');
|
||||
define('SIMPLEPIE_VERSION', '1.4-dev-FreshRSS');
|
||||
|
||||
/**
|
||||
* SimplePie Build
|
||||
@@ -602,7 +602,7 @@ class SimplePie
|
||||
public $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
|
||||
|
||||
/**
|
||||
* @var array Stores the default attributes to add to differet tags by add_attributes().
|
||||
* @var array Stores the default attributes to add to different tags by add_attributes().
|
||||
* @see SimplePie::add_attributes()
|
||||
* @access private
|
||||
*/
|
||||
@@ -644,7 +644,7 @@ class SimplePie
|
||||
if (func_num_args() > 0)
|
||||
{
|
||||
$level = defined('E_USER_DEPRECATED') ? E_USER_DEPRECATED : E_USER_WARNING;
|
||||
trigger_error('Passing parameters to the constructor is no longer supported. Please use set_feed_url(), set_cache_location(), and set_cache_location() directly.', $level);
|
||||
trigger_error('Passing parameters to the constructor is no longer supported. Please use set_feed_url(), set_cache_location(), and set_cache_duration() directly.', $level);
|
||||
|
||||
$args = func_get_args();
|
||||
switch (count($args)) {
|
||||
@@ -1212,6 +1212,20 @@ class SimplePie
|
||||
$this->item_limit = (int) $limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable throwing exceptions
|
||||
*
|
||||
* @param boolean $enable Should we throw exceptions, or use the old-style error property?
|
||||
*/
|
||||
public function enable_exceptions($enable = true)
|
||||
{
|
||||
$this->enable_exceptions = $enable;
|
||||
}
|
||||
|
||||
function cleanMd5($rss) { //FreshRSS
|
||||
return md5(preg_replace(array('#<(lastBuildDate|pubDate|updated|feedDate|dc:date|slash:comments)>[^<]+</\\1>#', '#<!--.+?-->#s'), '', $rss));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the feed object
|
||||
*
|
||||
@@ -1219,7 +1233,7 @@ class SimplePie
|
||||
* configuration options get processed, feeds are fetched, cached, and
|
||||
* parsed, and all of that other good stuff.
|
||||
*
|
||||
* @return boolean True if successful, false otherwise
|
||||
* @return positive integer with modification time if using cache, boolean true if otherwise successful, false otherwise
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
@@ -1298,13 +1312,17 @@ class SimplePie
|
||||
// Fetch the data via SimplePie_File into $this->raw_data
|
||||
if (($fetched = $this->fetch_data($cache)) === true)
|
||||
{
|
||||
return true;
|
||||
return $this->data['mtime']; //FreshRSS
|
||||
}
|
||||
elseif ($fetched === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
list($headers, $sniffed) = $fetched;
|
||||
|
||||
if (isset($this->data['md5'])) { //FreshRSS
|
||||
$md5 = $this->data['md5'];
|
||||
}
|
||||
}
|
||||
|
||||
// Set up array of possible encodings
|
||||
@@ -1386,6 +1404,8 @@ class SimplePie
|
||||
$this->data['headers'] = $headers;
|
||||
}
|
||||
$this->data['build'] = SIMPLEPIE_BUILD;
|
||||
$this->data['mtime'] = time(); //FreshRSS
|
||||
$this->data['md5'] = empty($md5) ? $this->cleanMd5($this->raw_data) : $md5; //FreshRSS
|
||||
|
||||
// Cache the file if caching is enabled
|
||||
if ($cache && !$cache->save($this))
|
||||
@@ -1461,7 +1481,7 @@ class SimplePie
|
||||
elseif ($cache->mtime() + $this->cache_duration < time())
|
||||
{
|
||||
// If we have last-modified and/or etag set
|
||||
if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag']))
|
||||
//if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag'])) //FreshRSS removed
|
||||
{
|
||||
$headers = array(
|
||||
'Accept' => 'application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1',
|
||||
@@ -1475,7 +1495,7 @@ class SimplePie
|
||||
$headers['if-none-match'] = $this->data['headers']['etag'];
|
||||
}
|
||||
|
||||
$file = $this->registry->create('File', array($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen));
|
||||
$file = $this->registry->create('File', array($this->feed_url, $this->timeout, 5, $headers, $this->useragent, $this->force_fsockopen)); //FreshRSS
|
||||
|
||||
if ($file->success)
|
||||
{
|
||||
@@ -1487,7 +1507,20 @@ class SimplePie
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($file);
|
||||
$this->error = $file->error; //FreshRSS
|
||||
return !empty($this->data); //FreshRSS
|
||||
//unset($file); //FreshRSS removed
|
||||
}
|
||||
}
|
||||
{ //FreshRSS
|
||||
$md5 = $this->cleanMd5($file->body);
|
||||
if ($this->data['md5'] === $md5) {
|
||||
syslog(LOG_DEBUG, 'SimplePie MD5 cache match for ' . $this->feed_url);
|
||||
$cache->touch();
|
||||
return true; //Content unchanged even though server did not send a 304
|
||||
} else {
|
||||
syslog(LOG_DEBUG, 'SimplePie MD5 cache no match for ' . $this->feed_url);
|
||||
$this->data['md5'] = $md5;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1555,6 +1588,8 @@ class SimplePie
|
||||
if ($cache)
|
||||
{
|
||||
$this->data = array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD);
|
||||
$this->data['mtime'] = time(); //FreshRSS
|
||||
$this->data['md5'] = empty($md5) ? $this->cleanMd5($file->body) : $md5; //FreshRSS
|
||||
if (!$cache->save($this))
|
||||
{
|
||||
trigger_error("$this->cache_location is not writeable. Make sure you've set the correct relative or absolute path, and that the location is server-writable.", E_USER_WARNING);
|
||||
@@ -1987,7 +2022,21 @@ class SimplePie
|
||||
*/
|
||||
public function sanitize($data, $type, $base = '')
|
||||
{
|
||||
return $this->sanitize->sanitize($data, $type, $base);
|
||||
try
|
||||
{
|
||||
return $this->sanitize->sanitize($data, $type, $base);
|
||||
}
|
||||
catch (SimplePie_Exception $e)
|
||||
{
|
||||
if (!$this->enable_exceptions)
|
||||
{
|
||||
$this->error = $e->getMessage();
|
||||
$this->registry->call('Misc', 'error', array($this->error, E_USER_WARNING, $e->getFile(), $e->getLine()));
|
||||
return '';
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
@@ -95,10 +95,8 @@ class SimplePie_Cache_Memcache implements SimplePie_Cache_Base
|
||||
'prefix' => 'simplepie_',
|
||||
),
|
||||
);
|
||||
$parsed = SimplePie_Cache::parse_URL($location);
|
||||
$this->options['host'] = empty($parsed['host']) ? $this->options['host'] : $parsed['host'];
|
||||
$this->options['port'] = empty($parsed['port']) ? $this->options['port'] : $parsed['port'];
|
||||
$this->options['extras'] = array_merge($this->options['extras'], $parsed['extras']);
|
||||
$this->options = SimplePie_Misc::array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
|
||||
|
||||
$this->name = $this->options['extras']['prefix'] . md5("$name:$type");
|
||||
|
||||
$this->cache = new Memcache();
|
||||
@@ -147,7 +145,7 @@ class SimplePie_Cache_Memcache implements SimplePie_Cache_Base
|
||||
|
||||
if ($data !== false)
|
||||
{
|
||||
// essentially ignore the mtime because Memcache expires on it's own
|
||||
// essentially ignore the mtime because Memcache expires on its own
|
||||
return time();
|
||||
}
|
||||
|
||||
@@ -165,7 +163,7 @@ class SimplePie_Cache_Memcache implements SimplePie_Cache_Base
|
||||
|
||||
if ($data !== false)
|
||||
{
|
||||
return $this->cache->set($this->name, $data, MEMCACHE_COMPRESSED, (int) $this->duration);
|
||||
return $this->cache->set($this->name, $data, MEMCACHE_COMPRESSED, (int) $this->options['extras']['timeout']);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
@@ -96,7 +96,8 @@ class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
|
||||
'prefix' => '',
|
||||
),
|
||||
);
|
||||
$this->options = array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
|
||||
|
||||
$this->options = SimplePie_Misc::array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));
|
||||
|
||||
// Path is prefixed with a "/"
|
||||
$this->options['dbname'] = substr($this->options['path'], 1);
|
||||
@@ -136,7 +137,7 @@ class SimplePie_Cache_MySQL extends SimplePie_Cache_DB
|
||||
|
||||
if (!in_array($this->options['extras']['prefix'] . 'items', $db))
|
||||
{
|
||||
$query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'items` (`feed_id` TEXT CHARACTER SET utf8 NOT NULL, `id` TEXT CHARACTER SET utf8 NOT NULL, `data` TEXT CHARACTER SET utf8 NOT NULL, `posted` INT UNSIGNED NOT NULL, INDEX `feed_id` (`feed_id`(125)))');
|
||||
$query = $this->mysql->exec('CREATE TABLE `' . $this->options['extras']['prefix'] . 'items` (`feed_id` TEXT CHARACTER SET utf8 NOT NULL, `id` TEXT CHARACTER SET utf8 NOT NULL, `data` MEDIUMBLOB CHARACTER SET utf8 NOT NULL, `posted` INT UNSIGNED NOT NULL, INDEX `feed_id` (`feed_id`(125)))');
|
||||
if ($query === false)
|
||||
{
|
||||
$this->mysql = null;
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
@@ -942,7 +942,7 @@ class SimplePie_Enclosure
|
||||
* - `height` (integer): The height of the embedded media. Accepts any
|
||||
* numeric pixel value (such as `360`) or `auto`. Defaults to `auto`,
|
||||
* and it is recommended that you use this default.
|
||||
* - `loop` (boolean): Do you want the media to loop when its done?
|
||||
* - `loop` (boolean): Do you want the media to loop when it's done?
|
||||
* Defaults to `false`.
|
||||
* - `mediaplayer` (string): The location of the included
|
||||
* `mediaplayer.swf` file. This allows for the playback of Flash Video
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
@@ -108,7 +108,7 @@ class SimplePie_File
|
||||
curl_setopt($fp, CURLOPT_REFERER, $url);
|
||||
curl_setopt($fp, CURLOPT_USERAGENT, $useragent);
|
||||
curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
|
||||
curl_setopt($fp, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($fp, CURLOPT_SSL_VERIFYPEER, false); //FreshRSS
|
||||
if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>='))
|
||||
{
|
||||
curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1);
|
||||
@@ -284,7 +284,7 @@ class SimplePie_File
|
||||
else
|
||||
{
|
||||
$this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS;
|
||||
if (!$this->body = file_get_contents($url))
|
||||
if (empty($url) || !($this->body = file_get_contents($url)))
|
||||
{
|
||||
$this->error = 'file_get_contents could not read the file';
|
||||
$this->success = false;
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
@@ -821,7 +821,7 @@ class SimplePie_Item
|
||||
if (!empty($this->data['updated']['raw']))
|
||||
{
|
||||
$parser = $this->registry->call('Parse_Date', 'get');
|
||||
$this->data['updated']['parsed'] = $parser->parse($this->data['date']['raw']);
|
||||
$this->data['updated']['parsed'] = $parser->parse($this->data['updated']['raw']);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1080,7 +1080,7 @@ class SimplePie_Item
|
||||
*
|
||||
* @since Beta 2
|
||||
* @todo Add support for end-user defined sorting of enclosures by type/handler (so we can prefer the faster-loading FLV over MP4).
|
||||
* @todo If an element exists at a level, but it's value is empty, we should fall back to the value from the parent (if it exists).
|
||||
* @todo If an element exists at a level, but its value is empty, we should fall back to the value from the parent (if it exists).
|
||||
* @return array|null List of SimplePie_Enclosure items
|
||||
*/
|
||||
public function get_enclosures()
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
@@ -277,7 +277,7 @@ class SimplePie_Locator
|
||||
$parsed = $this->registry->call('Misc', 'parse_url', array($href));
|
||||
if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme']))
|
||||
{
|
||||
if ($this->base_location < $link->getLineNo())
|
||||
if (method_exists($link, 'getLineNo') && $this->base_location < $link->getLineNo())
|
||||
{
|
||||
$href = $this->registry->call('Misc', 'absolutize_url', array(trim($link->getAttribute('href')), $this->base));
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
@@ -128,7 +128,7 @@ class SimplePie_Misc
|
||||
{
|
||||
$attribs[$j][2] = $attribs[$j][1];
|
||||
}
|
||||
$return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]), 'UTF-8');
|
||||
$return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]), 'UTF-8'); //FreshRSS
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,7 +142,7 @@ class SimplePie_Misc
|
||||
foreach ($element['attribs'] as $key => $value)
|
||||
{
|
||||
$key = strtolower($key);
|
||||
$full .= " $key=\"" . htmlspecialchars($value['data'], ENT_COMPAT, 'UTF-8') . '"';
|
||||
$full .= " $key=\"" . htmlspecialchars($value['data'], ENT_COMPAT, 'UTF-8') . '"'; //FreshRSS
|
||||
}
|
||||
if ($element['self_closing'])
|
||||
{
|
||||
@@ -228,6 +228,23 @@ class SimplePie_Misc
|
||||
}
|
||||
}
|
||||
|
||||
public static function array_merge_recursive($array1, $array2)
|
||||
{
|
||||
foreach ($array2 as $key => $value)
|
||||
{
|
||||
if (is_array($value))
|
||||
{
|
||||
$array1[$key] = SimplePie_Misc::array_merge_recursive($array1[$key], $value);
|
||||
}
|
||||
else
|
||||
{
|
||||
$array1[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $array1;
|
||||
}
|
||||
|
||||
public static function parse_url($url)
|
||||
{
|
||||
$iri = new SimplePie_IRI($url);
|
||||
@@ -2161,36 +2178,12 @@ function embed_wmedia(width, height, link) {
|
||||
/**
|
||||
* Get the SimplePie build timestamp
|
||||
*
|
||||
* Uses the git index if it exists, otherwise uses the modification time
|
||||
* of the newest file.
|
||||
* Return SimplePie.php modification time.
|
||||
*/
|
||||
public static function get_build()
|
||||
{
|
||||
$root = dirname(dirname(__FILE__));
|
||||
if (file_exists($root . '/.git/index'))
|
||||
{
|
||||
return filemtime($root . '/.git/index');
|
||||
}
|
||||
elseif (file_exists($root . '/SimplePie'))
|
||||
{
|
||||
$time = 0;
|
||||
foreach (glob($root . '/SimplePie/*.php') as $file)
|
||||
{
|
||||
if (($mtime = filemtime($file)) > $time)
|
||||
{
|
||||
$time = $mtime;
|
||||
}
|
||||
}
|
||||
return $time;
|
||||
}
|
||||
elseif (file_exists(dirname(__FILE__) . '/Core.php'))
|
||||
{
|
||||
return filemtime(dirname(__FILE__) . '/Core.php');
|
||||
}
|
||||
else
|
||||
{
|
||||
return filemtime(__FILE__);
|
||||
}
|
||||
$mtime = @filemtime(dirname(dirname(__FILE__)) . '/SimplePie.php'); //FreshRSS
|
||||
return $mtime ? $mtime : filemtime(__FILE__);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
@@ -145,10 +145,15 @@ class SimplePie_Parser
|
||||
$dom->loadXML($data);
|
||||
$this->encoding = $encoding = $dom->encoding = 'UTF-8';
|
||||
$data2 = $dom->saveXML();
|
||||
if (function_exists('mb_convert_encoding'))
|
||||
{
|
||||
$data2 = mb_convert_encoding($data2, 'UTF-8', 'UTF-8');
|
||||
}
|
||||
if (strlen($data2) > (strlen($data) / 2.0))
|
||||
{
|
||||
$data = $data2;
|
||||
}
|
||||
unset($data2);
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
@@ -267,6 +267,10 @@ class SimplePie_Sanitize
|
||||
if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML))
|
||||
{
|
||||
|
||||
if (!class_exists('DOMDocument'))
|
||||
{
|
||||
throw new SimplePie_Exception('DOMDocument not found, unable to use sanitizer');
|
||||
}
|
||||
$document = new DOMDocument();
|
||||
$document->encoding = 'UTF-8';
|
||||
$data = $this->preprocess($data, $type);
|
||||
@@ -339,7 +343,7 @@ class SimplePie_Sanitize
|
||||
}
|
||||
else
|
||||
{
|
||||
$file = $this->registry->create('File', array($img['attribs']['src']['data'], $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen));
|
||||
$file = $this->registry->create('File', array($img->getAttribute('src'), $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen));
|
||||
$headers = $file->headers;
|
||||
|
||||
if ($file->success && ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE === 0 || ($file->status_code === 200 || $file->status_code > 206 && $file->status_code < 300)))
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* @package SimplePie
|
||||
* @version 1.3.1
|
||||
* @version 1.4-dev
|
||||
* @copyright 2004-2012 Ryan Parman, Geoffrey Sneddon, Ryan McCue
|
||||
* @author Ryan Parman
|
||||
* @author Geoffrey Sneddon
|
||||
|
||||
131
lib/lib_date.php
Normal file
131
lib/lib_date.php
Normal file
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
/**
|
||||
* Author: Alexandre Alapetite http://alexandre.alapetite.fr
|
||||
* 2014-06-01
|
||||
* License: GNU AGPLv3 http://www.gnu.org/licenses/agpl-3.0.html
|
||||
*
|
||||
* Parser of ISO 8601 time intervals http://en.wikipedia.org/wiki/ISO_8601#Time_intervals
|
||||
* Examples: "2014-02/2014-04", "2014-02/04", "2014-06", "P1M"
|
||||
*/
|
||||
|
||||
/*
|
||||
example('2014-03');
|
||||
example('201403');
|
||||
example('2014-03-30');
|
||||
example('2014-05-30T13');
|
||||
example('2014-05-30T13:30');
|
||||
example('2014-02/2014-04');
|
||||
example('2014-02--2014-04');
|
||||
example('2014-02/04');
|
||||
example('2014-02-03/05');
|
||||
example('2014-02-03T22:00/22:15');
|
||||
example('2014-02-03T22:00/15');
|
||||
example('2014-03/');
|
||||
example('/2014-03');
|
||||
example('2014-03/P1W');
|
||||
example('P1W/2014-05-25T23:59:59');
|
||||
example('P1Y/');
|
||||
example('P1Y');
|
||||
example('P2M/');
|
||||
example('P3W/');
|
||||
example('P4D/');
|
||||
example('PT5H/');
|
||||
example('PT6M/');
|
||||
example('PT7S/');
|
||||
example('P1DT1H/');
|
||||
|
||||
function example($dateInterval) {
|
||||
$dateIntervalArray = parseDateInterval($dateInterval);
|
||||
echo $dateInterval, "\t=>\t",
|
||||
$dateIntervalArray[0] == null ? 'null' : @date('c', $dateIntervalArray[0]), '/',
|
||||
$dateIntervalArray[1] == null ? 'null' : @date('c', $dateIntervalArray[1]), "\n";
|
||||
}
|
||||
*/
|
||||
|
||||
function _dateFloor($isoDate) {
|
||||
$x = explode('T', $isoDate, 2);
|
||||
$t = isset($x[1]) ? str_pad($x[1], 6, '0') : '000000';
|
||||
return str_pad($x[0], 8, '01') . 'T' . $t;
|
||||
}
|
||||
|
||||
function _dateCeiling($isoDate) {
|
||||
$x = explode('T', $isoDate, 2);
|
||||
$t = isset($x[1]) && strlen($x[1]) > 1 ? str_pad($x[1], 6, '59') : '235959';
|
||||
switch (strlen($x[0])) {
|
||||
case 4:
|
||||
return $x[0] . '1231T' . $t;
|
||||
case 6:
|
||||
$d = @strtotime($x[0] . '01');
|
||||
return $x[0] . date('t', $d) . 'T' . $t;
|
||||
default:
|
||||
return $x[0] . 'T' . $t;
|
||||
}
|
||||
}
|
||||
|
||||
function _noDelimit($isoDate) {
|
||||
return $isoDate === null || $isoDate === '' ? null :
|
||||
str_replace(array('-', ':'), '', $isoDate); //FIXME: Bug with negative time zone
|
||||
}
|
||||
|
||||
function _dateRelative($d1, $d2) {
|
||||
if ($d2 === null) {
|
||||
return $d1 !== null && $d1[0] !== 'P' ? $d1 : null;
|
||||
} elseif ($d2 !== '' && $d2[0] != 'P' && $d1 !== null && $d1[0] !== 'P') {
|
||||
$y2 = substr($d2, 0, 4);
|
||||
if (strlen($y2) < 4 || !ctype_digit($y2)) { //Does not start by a year
|
||||
$d2 = _noDelimit($d2);
|
||||
return substr($d1, 0, -strlen($d2)) . $d2; //Add prefix from $d1
|
||||
}
|
||||
}
|
||||
return _noDelimit($d2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parameter $dateInterval is a string containing an ISO 8601 time interval.
|
||||
* Returns an array with the minimum and maximum Unix timestamp of this interval,
|
||||
* or null if open interval, or false if error.
|
||||
*/
|
||||
function parseDateInterval($dateInterval) {
|
||||
$dateInterval = trim($dateInterval);
|
||||
$dateInterval = str_replace('--', '/', $dateInterval);
|
||||
$dateInterval = strtoupper($dateInterval);
|
||||
$min = null;
|
||||
$max = null;
|
||||
$x = explode('/', $dateInterval, 2);
|
||||
$d1 = _noDelimit($x[0]);
|
||||
$d2 = _dateRelative($d1, count($x) > 1 ? $x[1] : null);
|
||||
if ($d1 !== null && $d1[0] !== 'P') {
|
||||
$min = @strtotime(_dateFloor($d1));
|
||||
}
|
||||
if ($d2 !== null) {
|
||||
if ($d2[0] === 'P') {
|
||||
try {
|
||||
$di2 = new DateInterval($d2);
|
||||
$dt1 = @date_create(); //new DateTime() would create an Exception if the default time zone is not defined
|
||||
if ($min !== null && $min !== false) {
|
||||
$dt1->setTimestamp($min);
|
||||
}
|
||||
$max = $dt1->add($di2)->getTimestamp() - 1;
|
||||
} catch (Exception $e) {
|
||||
$max = false;
|
||||
}
|
||||
} elseif ($d1 === null || $d1[0] !== 'P') {
|
||||
$max = @strtotime(_dateCeiling($d2));
|
||||
} else {
|
||||
$max = @strtotime($d2);
|
||||
}
|
||||
}
|
||||
if ($d1 !== null && $d1[0] === 'P') {
|
||||
try {
|
||||
$di1 = new DateInterval($d1);
|
||||
$dt2 = @date_create();
|
||||
if ($max !== null && $max !== false) {
|
||||
$dt2->setTimestamp($max);
|
||||
}
|
||||
$min = $dt2->sub($di1)->getTimestamp() + 1;
|
||||
} catch (Exception $e) {
|
||||
$min = false;
|
||||
}
|
||||
}
|
||||
return array($min, $max);
|
||||
}
|
||||
292
lib/lib_opml.php
292
lib/lib_opml.php
@@ -1,23 +1,86 @@
|
||||
<?php
|
||||
function opml_export ($cats) {
|
||||
$txt = '';
|
||||
|
||||
foreach ($cats as $cat) {
|
||||
$txt .= '<outline text="' . $cat['name'] . '">' . "\n";
|
||||
/* *
|
||||
* lib_opml is a free library to manage OPML format in PHP.
|
||||
* It takes in consideration only version 2.0 (http://dev.opml.org/spec2.html).
|
||||
* Basically it means "text" attribute for outline elements is required.
|
||||
*
|
||||
* lib_opml requires SimpleXML (http://php.net/manual/en/book.simplexml.php)
|
||||
*
|
||||
* Usages:
|
||||
* > include('lib_opml.php');
|
||||
* > $filename = 'my_opml_file.xml';
|
||||
* > $opml_array = libopml_parse_file($filename);
|
||||
* > print_r($opml_array);
|
||||
*
|
||||
* > $opml_string = [...];
|
||||
* > $opml_array = libopml_parse_string($opml_string);
|
||||
* > print_r($opml_array);
|
||||
*
|
||||
* > $opml_array = [...];
|
||||
* > $opml_string = libopml_render($opml_array);
|
||||
* > $opml_object = libopml_render($opml_array, true);
|
||||
* > echo $opml_string;
|
||||
* > print_r($opml_object);
|
||||
*
|
||||
* If parsing fails for any reason (e.g. not an XML string, does not match with
|
||||
* the specifications), a LibOPML_Exception is raised.
|
||||
*
|
||||
* Author: Marien Fressinaud <dev@marienfressinaud.fr>
|
||||
* Url: https://github.com/marienfressinaud/lib_opml
|
||||
* Version: 0.1
|
||||
* Date: 2014-03-29
|
||||
* License: public domain
|
||||
*
|
||||
* */
|
||||
|
||||
foreach ($cat['feeds'] as $feed) {
|
||||
$txt .= "\t" . '<outline text="' . $feed->name () . '" type="rss" xmlUrl="' . $feed->url () . '" htmlUrl="' . $feed->website () . '" description="' . htmlspecialchars($feed->description(), ENT_COMPAT, 'UTF-8') . '" />' . "\n";
|
||||
class LibOPML_Exception extends Exception {}
|
||||
|
||||
|
||||
// These elements are optional
|
||||
define('HEAD_ELEMENTS', serialize(array(
|
||||
'title', 'dateCreated', 'dateModified', 'ownerName', 'ownerEmail',
|
||||
'ownerId', 'docs', 'expansionState', 'vertScrollState', 'windowTop',
|
||||
'windowLeft', 'windowBottom', 'windowRight'
|
||||
)));
|
||||
|
||||
|
||||
function libopml_parse_outline($outline_xml) {
|
||||
$outline = array();
|
||||
|
||||
// An outline may contain any kind of attributes but "text" attribute is
|
||||
// required !
|
||||
$text_is_present = false;
|
||||
foreach ($outline_xml->attributes() as $key => $value) {
|
||||
$outline[$key] = (string)$value;
|
||||
|
||||
if ($key === 'text') {
|
||||
$text_is_present = true;
|
||||
}
|
||||
|
||||
$txt .= '</outline>' . "\n";
|
||||
}
|
||||
|
||||
return $txt;
|
||||
if (!$text_is_present) {
|
||||
throw new LibOPML_Exception(
|
||||
'Outline does not contain any text attribute'
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($outline_xml->children() as $key => $value) {
|
||||
// An outline may contain any number of outline children
|
||||
if ($key === 'outline') {
|
||||
$outline['@outlines'][] = libopml_parse_outline($value);
|
||||
} else {
|
||||
throw new LibOPML_Exception(
|
||||
'Body can contain only outline elements'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $outline;
|
||||
}
|
||||
|
||||
function opml_import ($xml) {
|
||||
$xml = html_only_entity_decode($xml); //!\ Assume UTF-8
|
||||
|
||||
function libopml_parse_string($xml) {
|
||||
$dom = new DOMDocument();
|
||||
$dom->recover = true;
|
||||
$dom->strictErrorChecking = false;
|
||||
@@ -27,95 +90,142 @@ function opml_import ($xml) {
|
||||
$opml = simplexml_import_dom($dom);
|
||||
|
||||
if (!$opml) {
|
||||
throw new FreshRSS_Opml_Exception ();
|
||||
throw new LibOPML_Exception();
|
||||
}
|
||||
|
||||
$catDAO = new FreshRSS_CategoryDAO();
|
||||
$catDAO->checkDefault();
|
||||
$defCat = $catDAO->getDefault();
|
||||
$array = array(
|
||||
'version' => (string)$opml['version'],
|
||||
'head' => array(),
|
||||
'body' => array()
|
||||
);
|
||||
|
||||
$categories = array ();
|
||||
$feeds = array ();
|
||||
|
||||
foreach ($opml->body->outline as $outline) {
|
||||
if (!isset ($outline['xmlUrl'])) {
|
||||
// Catégorie
|
||||
$title = '';
|
||||
|
||||
if (isset ($outline['text'])) {
|
||||
$title = (string) $outline['text'];
|
||||
} elseif (isset ($outline['title'])) {
|
||||
$title = (string) $outline['title'];
|
||||
}
|
||||
|
||||
if ($title) {
|
||||
// Permet d'éviter les soucis au niveau des id :
|
||||
// ceux-ci sont générés en fonction de la date,
|
||||
// un flux pourrait être dans une catégorie X avec l'id Y
|
||||
// alors qu'il existe déjà la catégorie X mais avec l'id Z
|
||||
// Y ne sera pas ajouté et le flux non plus vu que l'id
|
||||
// de sa catégorie n'exisera pas
|
||||
$title = htmlspecialchars($title, ENT_COMPAT, 'UTF-8');
|
||||
$catDAO = new FreshRSS_CategoryDAO ();
|
||||
$cat = $catDAO->searchByName ($title);
|
||||
if ($cat === false) {
|
||||
$cat = new FreshRSS_Category ($title);
|
||||
$values = array (
|
||||
'name' => $cat->name (),
|
||||
'color' => $cat->color ()
|
||||
);
|
||||
$cat->_id ($catDAO->addCategory ($values));
|
||||
}
|
||||
|
||||
$feeds = array_merge ($feeds, getFeedsOutline ($outline, $cat->id ()));
|
||||
}
|
||||
// First, we get all "head" elements. Head is required but its sub-elements
|
||||
// are optional.
|
||||
foreach ($opml->head->children() as $key => $value) {
|
||||
if (in_array($key, unserialize(HEAD_ELEMENTS), true)) {
|
||||
$array['head'][$key] = (string)$value;
|
||||
} else {
|
||||
// Flux rss sans catégorie, on récupère l'ajoute dans la catégorie par défaut
|
||||
$feeds[] = getFeed ($outline, $defCat->id());
|
||||
}
|
||||
}
|
||||
|
||||
return array ($categories, $feeds);
|
||||
}
|
||||
|
||||
/**
|
||||
* import all feeds of a given outline tag
|
||||
*/
|
||||
function getFeedsOutline ($outline, $cat_id) {
|
||||
$feeds = array ();
|
||||
|
||||
foreach ($outline->children () as $child) {
|
||||
if (isset ($child['xmlUrl'])) {
|
||||
$feeds[] = getFeed ($child, $cat_id);
|
||||
} else {
|
||||
$feeds = array_merge(
|
||||
$feeds,
|
||||
getFeedsOutline ($child, $cat_id)
|
||||
throw new LibOPML_Exception(
|
||||
$key . 'is not part of OPML format'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $feeds;
|
||||
// Then, we get body oulines. Body must contain at least one outline
|
||||
// element.
|
||||
$at_least_one_outline = false;
|
||||
foreach ($opml->body->children() as $key => $value) {
|
||||
if ($key === 'outline') {
|
||||
$at_least_one_outline = true;
|
||||
$array['body'][] = libopml_parse_outline($value);
|
||||
} else {
|
||||
throw new LibOPML_Exception(
|
||||
'Body can contain only outline elements'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$at_least_one_outline) {
|
||||
throw new LibOPML_Exception(
|
||||
'Body must contain at least one outline element'
|
||||
);
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
function getFeed ($outline, $cat_id) {
|
||||
$url = (string) $outline['xmlUrl'];
|
||||
$url = htmlspecialchars($url, ENT_COMPAT, 'UTF-8');
|
||||
$title = '';
|
||||
if (isset ($outline['text'])) {
|
||||
$title = (string) $outline['text'];
|
||||
} elseif (isset ($outline['title'])) {
|
||||
$title = (string) $outline['title'];
|
||||
|
||||
function libopml_parse_file($filename) {
|
||||
$file_content = file_get_contents($filename);
|
||||
|
||||
if ($file_content === false) {
|
||||
throw new LibOPML_Exception(
|
||||
$filename . ' cannot be found'
|
||||
);
|
||||
}
|
||||
|
||||
return libopml_parse_string($file_content);
|
||||
}
|
||||
|
||||
|
||||
function libopml_render_outline($parent_elt, $outline) {
|
||||
// Outline MUST be an array!
|
||||
if (!is_array($outline)) {
|
||||
throw new LibOPML_Exception(
|
||||
'Outline element must be defined as array'
|
||||
);
|
||||
}
|
||||
|
||||
$outline_elt = $parent_elt->addChild('outline');
|
||||
$text_is_present = false;
|
||||
foreach ($outline as $key => $value) {
|
||||
// Only outlines can be an array and so we consider children are also
|
||||
// outline elements.
|
||||
if ($key === '@outlines' && is_array($value)) {
|
||||
foreach ($value as $outline_child) {
|
||||
libopml_render_outline($outline_elt, $outline_child);
|
||||
}
|
||||
} elseif (is_array($value)) {
|
||||
throw new LibOPML_Exception(
|
||||
'Type of outline elements cannot be array: ' . $key
|
||||
);
|
||||
} else {
|
||||
// Detect text attribute is present, that's good :)
|
||||
if ($key === 'text') {
|
||||
$text_is_present = true;
|
||||
}
|
||||
|
||||
$outline_elt->addAttribute($key, $value);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$text_is_present) {
|
||||
throw new LibOPML_Exception(
|
||||
'You must define at least a text element for all outlines'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function libopml_render($array, $as_xml_object = false) {
|
||||
$opml = new SimpleXMLElement('<opml version="2.0"></opml>');
|
||||
|
||||
// Create head element. $array['head'] is optional but head element will
|
||||
// exist in the final XML object.
|
||||
$head = $opml->addChild('head');
|
||||
if (isset($array['head'])) {
|
||||
foreach ($array['head'] as $key => $value) {
|
||||
if (in_array($key, unserialize(HEAD_ELEMENTS), true)) {
|
||||
$head->addChild($key, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check body is set and contains at least one element
|
||||
if (!isset($array['body'])) {
|
||||
throw new LibOPML_Exception(
|
||||
'$array must contain a body element'
|
||||
);
|
||||
}
|
||||
if (count($array['body']) <= 0) {
|
||||
throw new LibOPML_Exception(
|
||||
'Body element must contain at least one element (array)'
|
||||
);
|
||||
}
|
||||
|
||||
// Create outline elements
|
||||
$body = $opml->addChild('body');
|
||||
foreach ($array['body'] as $outline) {
|
||||
libopml_render_outline($body, $outline);
|
||||
}
|
||||
|
||||
// And return the final result
|
||||
if ($as_xml_object) {
|
||||
return $opml;
|
||||
} else {
|
||||
$dom = dom_import_simplexml($opml)->ownerDocument;
|
||||
$dom->formatOutput = true;
|
||||
$dom->encoding = 'UTF-8';
|
||||
return $dom->saveXML();
|
||||
}
|
||||
$title = htmlspecialchars($title, ENT_COMPAT, 'UTF-8');
|
||||
$feed = new FreshRSS_Feed ($url);
|
||||
$feed->_category ($cat_id);
|
||||
$feed->_name ($title);
|
||||
if (isset($outline['htmlUrl'])) {
|
||||
$feed->_website(htmlspecialchars((string)$outline['htmlUrl'], ENT_COMPAT, 'UTF-8'));
|
||||
}
|
||||
if (isset($outline['description'])) {
|
||||
$feed->_description(sanitizeHTML((string)$outline['description']));
|
||||
}
|
||||
return $feed;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ function classAutoloader($class) {
|
||||
include(APP_PATH . '/Models/' . $components[1] . '.php');
|
||||
return;
|
||||
case 3: //Controllers, Exceptions
|
||||
include(APP_PATH . '/' . $components[2] . 's/' . $components[1] . $components[2] . '.php');
|
||||
@include(APP_PATH . '/' . $components[2] . 's/' . $components[1] . $components[2] . '.php');
|
||||
return;
|
||||
}
|
||||
} elseif (strpos($class, 'Minz') === 0) {
|
||||
@@ -214,12 +214,12 @@ function uSecString() {
|
||||
}
|
||||
|
||||
function invalidateHttpCache() {
|
||||
touch(LOG_PATH . '/' . Minz_Session::param('currentUser', '_') . '.log');
|
||||
Minz_Session::_param('touch', uTimeString());
|
||||
return touch(LOG_PATH . '/' . Minz_Session::param('currentUser', '_') . '.log');
|
||||
}
|
||||
|
||||
function usernameFromPath($userPath) {
|
||||
if (preg_match('%/([a-z0-9]{1,16})_user\.php$%', $userPath, $matches)) {
|
||||
if (preg_match('%/([A-Za-z0-9]{1,16})_user\.php$%', $userPath, $matches)) {
|
||||
return $matches[1];
|
||||
} else {
|
||||
return '';
|
||||
@@ -233,3 +233,18 @@ function listUsers() {
|
||||
function httpAuthUser() {
|
||||
return isset($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'] : '';
|
||||
}
|
||||
|
||||
function cryptAvailable() {
|
||||
if (version_compare(PHP_VERSION, '5.3.3', '>=')) {
|
||||
try {
|
||||
$hash = '$2y$04$usesomesillystringfore7hnbRJHxXVLeakoG8K30oukPsA.ztMG';
|
||||
return $hash === @crypt('password', $hash);
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function html_chars_utf8($str) {
|
||||
return htmlspecialchars($str, ENT_COMPAT, 'UTF-8');
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user