diff options
| author | 2015-01-08 21:33:13 +0100 | |
|---|---|---|
| committer | 2015-01-08 21:33:13 +0100 | |
| commit | 250cd79251f5474915ad2230e786db70643b0ef3 (patch) | |
| tree | 3b757a544dfb0239bd119b953c316d27860f70cf /app | |
| parent | 0e4e16ac55097aa173c7c439367294ebd7645562 (diff) | |
| parent | b23fc3187cb90800aad6417badf7822a8d280b74 (diff) | |
Merge branch '252-extensions' into dev
Diffstat (limited to 'app')
| -rw-r--r-- | app/Controllers/extensionController.php | 192 | ||||
| -rwxr-xr-x | app/Controllers/feedController.php | 31 | ||||
| -rw-r--r-- | app/Controllers/importExportController.php | 36 | ||||
| -rw-r--r-- | app/FreshRSS.php | 34 | ||||
| -rw-r--r-- | app/Models/ConfigurationSetter.php | 10 | ||||
| -rw-r--r-- | app/i18n/en/admin.php | 6 | ||||
| -rw-r--r-- | app/i18n/en/feedback.php | 8 | ||||
| -rw-r--r-- | app/i18n/en/gen.php | 5 | ||||
| -rw-r--r-- | app/i18n/fr/admin.php | 6 | ||||
| -rw-r--r-- | app/i18n/fr/feedback.php | 8 | ||||
| -rw-r--r-- | app/i18n/fr/gen.php | 5 | ||||
| -rw-r--r-- | app/install.php | 28 | ||||
| -rw-r--r-- | app/layout/aside_configure.phtml | 4 | ||||
| -rw-r--r-- | app/layout/header.phtml | 1 | ||||
| -rw-r--r-- | app/views/configure/display.phtml | 4 | ||||
| -rw-r--r-- | app/views/extension/configure.phtml | 23 | ||||
| -rw-r--r-- | app/views/extension/index.phtml | 39 | ||||
| -rw-r--r-- | app/views/helpers/index/normal/entry_bottom.phtml | 86 | ||||
| -rw-r--r-- | app/views/helpers/index/normal/entry_header.phtml | 33 | ||||
| -rw-r--r-- | app/views/index/index.phtml | 23 | ||||
| -rw-r--r-- | app/views/index/normal.phtml | 170 | ||||
| -rw-r--r-- | app/views/index/reader.phtml | 11 | ||||
| -rw-r--r-- | app/views/user/manage.phtml | 4 |
23 files changed, 540 insertions, 227 deletions
diff --git a/app/Controllers/extensionController.php b/app/Controllers/extensionController.php new file mode 100644 index 000000000..e013bb369 --- /dev/null +++ b/app/Controllers/extensionController.php @@ -0,0 +1,192 @@ +<?php + +/** + * The controller to manage extensions. + */ +class FreshRSS_extension_Controller extends Minz_ActionController { + /** + * This action is called before every other action in that class. It is + * the common boiler plate for every action. It is triggered by the + * underlying framework. + */ + public function firstAction() { + if (!FreshRSS_Auth::hasAccess()) { + Minz_Error::error(403); + } + } + + /** + * This action lists all the extensions available to the current user. + */ + public function indexAction() { + Minz_View::prependTitle(_t('admin.extensions.title') . ' · '); + $this->view->extension_list = Minz_ExtensionManager::list_extensions(); + } + + /** + * This action handles configuration of a given extension. + * + * Only administrator can configure a system extension. + * + * Parameters are: + * - e: the extension name (urlencoded) + * - additional parameters which should be handle by the extension + * handleConfigureAction() method (POST request). + */ + public function configureAction() { + if (Minz_Request::param('ajax')) { + $this->view->_useLayout(false); + } + + $ext_name = urldecode(Minz_Request::param('e')); + $ext = Minz_ExtensionManager::find_extension($ext_name); + + if (is_null($ext)) { + Minz_Error::error(404); + } + if ($ext->getType() === 'system' && !FreshRSS_Auth::hasAccess('admin')) { + Minz_Error::error(403); + } + + $this->view->extension = $ext; + $this->view->extension->handleConfigureAction(); + } + + /** + * This action enables a disabled extension for the current user. + * + * System extensions can only be enabled by an administrator. + * This action must be reached by a POST request. + * + * Parameter is: + * - e: the extension name (urlencoded). + */ + public function enableAction() { + $url_redirect = array('c' => 'extension', 'a' => 'index'); + + if (Minz_Request::isPost()) { + $ext_name = urldecode(Minz_Request::param('e')); + $ext = Minz_ExtensionManager::find_extension($ext_name); + + if (is_null($ext)) { + Minz_Request::bad(_t('feedback.extensions.not_found', $ext_name), + $url_redirect); + } + + if ($ext->is_enabled()) { + Minz_Request::bad(_t('feedback.extensions.already_enabled', $ext_name), + $url_redirect); + } + + $conf = null; + if ($ext->getType() === 'system' && FreshRSS_Auth::hasAccess('admin')) { + $conf = FreshRSS_Context::$system_conf; + } elseif ($ext->getType() === 'user') { + $conf = FreshRSS_Context::$user_conf; + } else { + Minz_Request::bad(_t('feedback.extensions.no_access', $ext_name), + $url_redirect); + } + + $ext->install(); + + $ext_list = $conf->extensions_enabled; + array_push_unique($ext_list, $ext_name); + $conf->extensions_enabled = $ext_list; + $conf->save(); + + Minz_Request::good(_t('feedback.extensions.enabled', $ext_name), + $url_redirect); + } + + Minz_Request::forward($url_redirect, true); + } + + /** + * This action disables an enabled extension for the current user. + * + * System extensions can only be disabled by an administrator. + * This action must be reached by a POST request. + * + * Parameter is: + * - e: the extension name (urlencoded). + */ + public function disableAction() { + $url_redirect = array('c' => 'extension', 'a' => 'index'); + + if (Minz_Request::isPost()) { + $ext_name = urldecode(Minz_Request::param('e')); + $ext = Minz_ExtensionManager::find_extension($ext_name); + + if (is_null($ext)) { + Minz_Request::bad(_t('feedback.extensions.not_found', $ext_name), + $url_redirect); + } + + if (!$ext->is_enabled()) { + Minz_Request::bad(_t('feedback.extensions.not_enabled', $ext_name), + $url_redirect); + } + + $conf = null; + if ($ext->getType() === 'system' && FreshRSS_Auth::hasAccess('admin')) { + $conf = FreshRSS_Context::$system_conf; + } elseif ($ext->getType() === 'user') { + $conf = FreshRSS_Context::$user_conf; + } else { + Minz_Request::bad(_t('feedback.extensions.no_access', $ext_name), + $url_redirect); + } + + $ext->uninstall(); + + $ext_list = $conf->extensions_enabled; + array_remove($ext_list, $ext_name); + $conf->extensions_enabled = $ext_list; + $conf->save(); + + Minz_Request::good(_t('feedback.extensions.disabled', $ext_name), + $url_redirect); + } + + Minz_Request::forward($url_redirect, true); + } + + /** + * This action handles deletion of an extension. + * + * Only administrator can remove an extension. + * This action must be reached by a POST request. + * + * Parameter is: + * -e: extension name (urlencoded) + */ + public function removeAction() { + if (!FreshRSS_Auth::hasAccess('admin')) { + Minz_Error::error(403); + } + + $url_redirect = array('c' => 'extension', 'a' => 'index'); + + if (Minz_Request::isPost()) { + $ext_name = urldecode(Minz_Request::param('e')); + $ext = Minz_ExtensionManager::find_extension($ext_name); + + if (is_null($ext)) { + Minz_Request::bad(_t('feedback.extensions.not_found', $ext_name), + $url_redirect); + } + + $res = recursive_unlink($ext->getPath()); + if ($res) { + Minz_Request::good(_t('feedback.extensions.removed', $ext_name), + $url_redirect); + } else { + Minz_Request::bad(_t('feedback.extensions.cannot_delete', $ext_name), + $url_redirect); + } + } + + Minz_Request::forward($url_redirect, true); + } +} diff --git a/app/Controllers/feedController.php b/app/Controllers/feedController.php index c110fda4e..6f544d834 100755 --- a/app/Controllers/feedController.php +++ b/app/Controllers/feedController.php @@ -142,6 +142,13 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feed->_category($cat); $feed->_httpAuth($http_auth); + // Call the extension hook + $name = $feed->name(); + $feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed); + if (is_null($feed)) { + Minz_Request::bad(_t('feed_not_added', $name), $url_redirect); + } + $values = array( 'url' => $feed->url(), 'category' => $feed->category(), @@ -178,10 +185,17 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $feedDAO->beginTransaction(); foreach ($entries as $entry) { // Entries are added without any verification. + $entry->_feed($feed->id()); + $entry->_id(min(time(), $entry->date(true)) . uSecString()); + $entry->_isRead($is_read); + + $entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry); + if (is_null($entry)) { + // An extension has returned a null value, there is nothing to insert. + continue; + } + $values = $entry->toArray(); - $values['id_feed'] = $feed->id(); - $values['id'] = min(time(), $entry->date(true)) . uSecString(); - $values['is_read'] = $is_read; $entryDAO->addEntry($values, $prepared_statement); } $feedDAO->updateLastUpdate($feed->id()); @@ -333,9 +347,16 @@ class FreshRSS_feed_Controller extends Minz_ActionController { $id = min(time(), $entry_date) . uSecString(); } + $entry->_id($id); + $entry->_isRead($is_read); + + $entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry); + if (is_null($entry)) { + // An extension has returned a null value, there is nothing to insert. + continue; + } + $values = $entry->toArray(); - $values['id'] = $id; - $values['is_read'] = $is_read; $entryDAO->addEntry($values, $prepared_statement); } } diff --git a/app/Controllers/importExportController.php b/app/Controllers/importExportController.php index 4ce24719e..db9db66a7 100644 --- a/app/Controllers/importExportController.php +++ b/app/Controllers/importExportController.php @@ -257,10 +257,16 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $feed->_website($website); $feed->_description($description); - // addFeedObject checks if feed is already in DB so nothing else to - // check here - $id = $this->feedDAO->addFeedObject($feed); - $error = ($id === false); + // Call the extension hook + $feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed); + if (!is_null($feed)) { + // addFeedObject checks if feed is already in DB so nothing else to + // check here + $id = $this->feedDAO->addFeedObject($feed); + $error = ($id === false); + } else { + $error = true; + } } catch (FreshRSS_Feed_Exception $e) { Minz_Log::warning($e->getMessage()); $error = true; @@ -383,6 +389,12 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $entry->_id(min(time(), $entry->date(true)) . uSecString()); $entry->_tags($tags); + $entry = Minz_ExtensionManager::callHook('entry_before_insert', $entry); + if (is_null($entry)) { + // An extension has returned a null value, there is nothing to insert. + continue; + } + $values = $entry->toArray(); $id = $this->entryDAO->addEntry($values, $prepared_statement); @@ -419,13 +431,17 @@ class FreshRSS_importExport_Controller extends Minz_ActionController { $feed->_name($name); $feed->_website($website); - // addFeedObject checks if feed is already in DB so nothing else to - // check here. - $id = $this->feedDAO->addFeedObject($feed); + // Call the extension hook + $feed = Minz_ExtensionManager::callHook('feed_before_insert', $feed); + if (!is_null($feed)) { + // addFeedObject checks if feed is already in DB so nothing else to + // check here. + $id = $this->feedDAO->addFeedObject($feed); - if ($id !== false) { - $feed->_id($id); - $return = $feed; + if ($id !== false) { + $feed->_id($id); + $return = $feed; + } } } catch (FreshRSS_Feed_Exception $e) { Minz_Log::warning($e->getMessage()); diff --git a/app/FreshRSS.php b/app/FreshRSS.php index 002a70af5..453cc2d69 100644 --- a/app/FreshRSS.php +++ b/app/FreshRSS.php @@ -6,6 +6,8 @@ class FreshRSS extends Minz_FrontController { Minz_Session::init('FreshRSS'); } + // Load list of extensions and enable the "system" ones. + Minz_ExtensionManager::init(); $this->initConfiguration(); $this->initAuth(); FreshRSS_Context::init(); @@ -13,7 +15,11 @@ class FreshRSS extends Minz_FrontController { FreshRSS_Share::load(join_path(DATA_PATH, 'shares.php')); $this->loadStylesAndScripts(); $this->loadNotifications(); - $this->loadExtensions(); + // Enable extensions for the current (logged) user. + if (FreshRSS_Auth::hasAccess()) { + $ext_list = FreshRSS_Context::$user_conf->extensions_enabled; + Minz_ExtensionManager::enable_by_list($ext_list); + } } private function initConfiguration() { @@ -46,11 +52,7 @@ class FreshRSS extends Minz_FrontController { private function initI18n() { Minz_Session::_param('language', FreshRSS_Context::$user_conf->language); - - Minz_Translate::init(array( - 'en' => 'English', - 'fr' => 'Français', - ), FreshRSS_Context::$user_conf->language); + Minz_Translate::init(FreshRSS_Context::$user_conf->language); } private function loadStylesAndScripts() { @@ -91,24 +93,4 @@ class FreshRSS extends Minz_FrontController { Minz_Session::_param('notification'); } } - - private function loadExtensions() { - $extensionPath = FRESHRSS_PATH . '/extensions/'; - //TODO: Add a preference to load only user-selected extensions - foreach (scandir($extensionPath) as $key => $extension) { - if (ctype_alpha($extension)) { - $mtime = @filemtime($extensionPath . $extension . '/style.css'); - if ($mtime !== false) { - Minz_View::appendStyle(Minz_Url::display('/ext.php?c&e=' . $extension . '&' . $mtime)); - } - $mtime = @filemtime($extensionPath . $extension . '/script.js'); - if ($mtime !== false) { - Minz_View::appendScript(Minz_Url::display('/ext.php?j&e=' . $extension . '&' . $mtime)); - } - if (file_exists($extensionPath . $extension . '/module.php')) { - //TODO: include - } - } - } - } } diff --git a/app/Models/ConfigurationSetter.php b/app/Models/ConfigurationSetter.php index 9830fed28..f1c465c7c 100644 --- a/app/Models/ConfigurationSetter.php +++ b/app/Models/ConfigurationSetter.php @@ -67,6 +67,14 @@ class FreshRSS_ConfigurationSetter { } } + // It works for system config too! + private function _extensions_enabled(&$data, $value) { + if (!is_array($value)) { + $value = array($value); + } + $data['extensions_enabled'] = $value; + } + private function _html5_notif_timeout(&$data, $value) { $value = intval($value); $data['html5_notif_timeout'] = $value >= 0 ? $value : 0; @@ -81,7 +89,7 @@ class FreshRSS_ConfigurationSetter { private function _language(&$data, $value) { $value = strtolower($value); $languages = Minz_Translate::availableLanguages(); - if (!isset($languages[$value])) { + if (!in_array($value, $languages)) { $value = 'en'; } $data['language'] = $value; diff --git a/app/i18n/en/admin.php b/app/i18n/en/admin.php index 5653453df..6a89d4a31 100644 --- a/app/i18n/en/admin.php +++ b/app/i18n/en/admin.php @@ -102,6 +102,12 @@ return array( 'ok' => 'You have ZIP extension.', ), ), + 'extensions' => array( + 'empty_list' => 'There is no installed extension', + 'no_configure_view' => 'This extension cannot be configured.', + 'system' => 'System extension (you have no rights on it)', + 'title' => 'Extensions', + ), 'stats' => array( '_' => 'Statistics', 'all_feeds' => 'All feeds', diff --git a/app/i18n/en/feedback.php b/app/i18n/en/feedback.php index 8df83ac0a..5f7183da3 100644 --- a/app/i18n/en/feedback.php +++ b/app/i18n/en/feedback.php @@ -29,6 +29,14 @@ return array( 'shortcuts_updated' => 'Shortcuts have been updated', 'updated' => 'Configuration has been updated', ), + 'extensions' => array( + 'already_enabled' => '%s is already enabled', + 'disabled' => '%s is now disabled', + 'enabled' => '%s is now enabled', + 'no_access' => 'You have no access on %s', + 'not_enabled' => '%s is not enabled yet', + 'not_found' => '%s does not exist', + ), 'import_export' => array( 'export_no_zip_extension' => 'Zip extension is not present on your server. Please try to export files one by one.', 'feeds_imported' => 'Your feeds have been imported and will now be updated', diff --git a/app/i18n/en/gen.php b/app/i18n/en/gen.php index 4a6f8a71b..6271717d4 100644 --- a/app/i18n/en/gen.php +++ b/app/i18n/en/gen.php @@ -100,6 +100,10 @@ return array( 'notif_title_new_articles' => 'FreshRSS: new articles!', 'should_be_activated' => 'JavaScript must be enabled', ), + 'lang' => array( + 'en' => 'English', + 'fr' => 'Français', + ), 'menu' => array( 'about' => 'About', 'admin' => 'Administration', @@ -108,6 +112,7 @@ return array( 'check_install' => 'Installation checking', 'configuration' => 'Configuration', 'display' => 'Display', + 'extensions' => 'Extensions', 'logs' => 'Logs', 'queries' => 'User queries', 'reading' => 'Reading', diff --git a/app/i18n/fr/admin.php b/app/i18n/fr/admin.php index 7a4215722..2e879da61 100644 --- a/app/i18n/fr/admin.php +++ b/app/i18n/fr/admin.php @@ -102,6 +102,12 @@ return array( 'ok' => 'Vous disposez de l\'extension ZIP.', ), ), + 'extensions' => array( + 'empty_list' => 'Il n’y a aucune extension installée.', + 'no_configure_view' => 'Cette extension ne peut pas être configurée.', + 'system' => 'Extension système (vous n’avez aucun droit dessus)', + 'title' => 'Extensions', + ), 'stats' => array( '_' => 'Statistiques', 'all_feeds' => 'Tous les flux', diff --git a/app/i18n/fr/feedback.php b/app/i18n/fr/feedback.php index b9d1f6c99..5c71bbae1 100644 --- a/app/i18n/fr/feedback.php +++ b/app/i18n/fr/feedback.php @@ -29,6 +29,14 @@ return array( 'shortcuts_updated' => 'Les raccourcis ont été mis à jour.', 'updated' => 'La configuration a été mise à jour', ), + 'extensions' => array( + 'already_enabled' => '%s est déjà activée', + 'disabled' => '%s est désormais désactivée', + 'enabled' => '%s est désormais activée', + 'no_access' => 'Vous n’avez aucun accès sur %s', + 'not_enabled' => '%s n’est pas encore activée', + 'not_found' => '%s n’existe pas', + ), 'import_export' => array( 'export_no_zip_extension' => 'L’extension Zip n’est pas présente sur votre serveur. Veuillez essayer d’exporter les fichiers un par un.', 'feeds_imported' => 'Vos flux ont été importés et vont maintenant être actualisés.', diff --git a/app/i18n/fr/gen.php b/app/i18n/fr/gen.php index d990dad4a..6b449484f 100644 --- a/app/i18n/fr/gen.php +++ b/app/i18n/fr/gen.php @@ -100,6 +100,10 @@ return array( 'notif_title_new_articles' => 'FreshRSS : nouveaux articles !', 'should_be_activated' => 'Le JavaScript doit être activé.', ), + 'lang' => array( + 'en' => 'English', + 'fr' => 'Français', + ), 'menu' => array( 'about' => 'À propos', 'admin' => 'Administration', @@ -108,6 +112,7 @@ return array( 'check_install' => 'Vérification de l’installation', 'configuration' => 'Configuration', 'display' => 'Affichage', + 'extensions' => 'Extensions', 'logs' => 'Logs', 'queries' => 'Filtres utilisateurs', 'reading' => 'Lecture', diff --git a/app/install.php b/app/install.php index a9faa764b..a79b0d318 100644 --- a/app/install.php +++ b/app/install.php @@ -43,24 +43,18 @@ function param($key, $default = false) { // gestion internationalisation function initTranslate() { - $available_languages = array( - 'en' => 'English', - 'fr' => 'Français' - ); + Minz_Translate::init(); + $available_languages = Minz_Translate::availableLanguages(); if (!isset($_SESSION['language'])) { - $best = get_best_language(); - if (!isset($available_languages[$best])) { - $best = 'en'; - } + $_SESSION['language'] = get_best_language(); + } - $_SESSION['language'] = $best; + if (!in_array($_SESSION['language'], $available_languages)) { + $_SESSION['language'] = 'en'; } - Minz_Translate::init(array( - 'en' => 'English', - 'fr' => 'Français', - ), $_SESSION['language']); + Minz_Translate::reset($_SESSION['language']); } function get_best_language() { @@ -257,7 +251,7 @@ function checkStep() { function checkStep0() { $languages = Minz_Translate::availableLanguages(); $language = isset($_SESSION['language']) && - isset($languages[$_SESSION['language']]); + in_array($_SESSION['language'], $languages); return array( 'language' => $language ? 'ok' : 'ko', @@ -432,8 +426,10 @@ function printStep0() { <label class="group-name" for="language"><?php echo _t('install.language'); ?></label> <div class="group-controls"> <select name="language" id="language"> - <?php foreach ($languages as $short => $lib) { ?> - <option value="<?php echo $short; ?>"<?php echo $actual == $short ? ' selected="selected"' : ''; ?>><?php echo $lib; ?></option> + <?php foreach ($languages as $lang) { ?> + <option value="<?php echo $lang; ?>"<?php echo $actual == $lang ? ' selected="selected"' : ''; ?>> + <?php echo _t('gen.lang.' . $lang); ?> + </option> <?php } ?> </select> </div> diff --git a/app/layout/aside_configure.phtml b/app/layout/aside_configure.phtml index 25b8037e6..2d4cb9cad 100644 --- a/app/layout/aside_configure.phtml +++ b/app/layout/aside_configure.phtml @@ -22,6 +22,10 @@ Minz_Request::actionName() === 'profile'? ' active' : ''; ?>"> <a href="<?php echo _url('user', 'profile'); ?>"><?php echo _t('gen.menu.user_profile'); ?></a> </li> + <li class="item<?php echo Minz_Request::controllerName() === 'extension' && + Minz_Request::actionName() === 'index'? ' active' : ''; ?>"> + <a href="<?php echo _url('extension', 'index'); ?>"><?php echo _t('gen.menu.extensions'); ?></a> + </li> <?php if (FreshRSS_Auth::hasAccess('admin')) { ?> <li class="nav-header"><?php echo _t('gen.menu.admin'); ?></li> <li class="item<?php echo Minz_Request::controllerName() === 'user' && diff --git a/app/layout/header.phtml b/app/layout/header.phtml index 0c2e171dd..2b968252b 100644 --- a/app/layout/header.phtml +++ b/app/layout/header.phtml @@ -64,6 +64,7 @@ if (FreshRSS_Auth::accessNeedsAction()) { <li class="item"><a href="<?php echo _url('configure', 'shortcut'); ?>"><?php echo _t('gen.menu.shortcuts'); ?></a></li> <li class="item"><a href="<?php echo _url('configure', 'queries'); ?>"><?php echo _t('gen.menu.queries'); ?></a></li> <li class="item"><a href="<?php echo _url('user', 'profile'); ?>"><?php echo _t('gen.menu.user_profile'); ?></a></li> + <li class="item"><a href="<?php echo _url('extension', 'index'); ?>"><?php echo _t('gen.menu.extensions'); ?></a></li> <?php if (FreshRSS_Auth::hasAccess('admin')) { ?> <li class="separator"></li> <li class="dropdown-header"><?php echo _t('gen.menu.admin'); ?></li> diff --git a/app/views/configure/display.phtml b/app/views/configure/display.phtml index 36a075ea7..02249bc55 100644 --- a/app/views/configure/display.phtml +++ b/app/views/configure/display.phtml @@ -11,8 +11,8 @@ <div class="group-controls"> <select name="language" id="language"> <?php $languages = Minz_Translate::availableLanguages(); ?> - <?php foreach ($languages as $short => $lib) { ?> - <option value="<?php echo $short; ?>"<?php echo FreshRSS_Context::$user_conf->language === $short ? ' selected="selected"' : ''; ?>><?php echo $lib; ?></option> + <?php foreach ($languages as $lang) { ?> + <option value="<?php echo $lang; ?>"<?php echo FreshRSS_Context::$user_conf->language === $lang ? ' selected="selected"' : ''; ?>><?php echo _t('gen.lang.' . $lang); ?></option> <?php } ?> </select> </div> diff --git a/app/views/extension/configure.phtml b/app/views/extension/configure.phtml new file mode 100644 index 000000000..c03439a75 --- /dev/null +++ b/app/views/extension/configure.phtml @@ -0,0 +1,23 @@ +<?php + +if (!Minz_Request::param('ajax')) { + $this->partial('aside_configure'); +} + +?> + +<div class="post"> + <h1><?php echo $this->extension->getName(); ?> (<?php echo $this->extension->getVersion(); ?>) — <?php echo $this->extension->getType(); ?></h1> + + <p class="alert alert-warn"><?php echo $this->extension->getDescription(); ?> — <?php echo _t('gen.short.by_author', $this->extension->getAuthor()); ?></p> + + <h2><?php echo _t('gen.action.manage'); ?></h2> + <?php + $configure_view = $this->extension->getConfigureView(); + if ($configure_view !== false) { + echo $configure_view; + } else { + ?> + <p class="alert alert-warn"><?php echo _t('admin.extensions.no_configure_view'); ?></p> + <?php } ?> +</div> diff --git a/app/views/extension/index.phtml b/app/views/extension/index.phtml new file mode 100644 index 000000000..fd97c5e81 --- /dev/null +++ b/app/views/extension/index.phtml @@ -0,0 +1,39 @@ +<?php $this->partial('aside_configure'); ?> + +<div class="post"> + <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('gen.action.back_to_rss_feeds'); ?></a> + + <h1><?php echo _t('admin.extensions.title'); ?></h1> + + <?php if (!empty($this->extension_list)) { ?> + <form id="form-extension" method="post" style="display: none"></form> + <?php foreach ($this->extension_list as $ext) { ?> + <ul class="horizontal-list"> + <li class="item"> + <?php if ($ext->getType() === 'user' || FreshRSS_Auth::hasAccess('admin')) { ?> + <?php $name_encoded = urlencode($ext->getName()); ?> + <div class="stick"> + <a class="btn open-slider" href="<?php echo _url('extension', 'configure', 'e', $name_encoded); ?>"><?php echo _i('configure'); ?> <?php echo _t('gen.action.manage'); ?></a> + <?php if ($ext->is_enabled()) { ?> + <button class="btn active" form="form-extension" formaction="<?php echo _url('extension', 'disable', 'e', $name_encoded); ?>"><?php echo _t('gen.action.disable'); ?></button> + <?php } else { ?> + <button class="btn" form="form-extension" formaction="<?php echo _url('extension', 'enable', 'e', $name_encoded); ?>"><?php echo _t('gen.action.enable'); ?></button> + <?php } ?> + <?php if (FreshRSS_Auth::hasAccess('admin')) { ?> + <button class="btn btn-attention confirm" form="form-extension" formaction="<?php echo _url('extension', 'remove', 'e', $name_encoded); ?>"><?php echo _t('gen.action.remove'); ?></button> + <?php } ?> + </div> + <?php } else { ?> + <?php echo _t('admin.extensions.system'); ?> + <?php } ?> + </li> + <li class="item"><?php echo $ext->getName(); ?></li> + </ul> + <?php } ?> + <?php } else { ?> + <p class="alert alert-warn"><?php echo _t('admin.extensions.empty_list'); ?></p> + <?php } ?> +</div> + +<a href="#" id="close-slider"></a> +<div id="slider"></div> diff --git a/app/views/helpers/index/normal/entry_bottom.phtml b/app/views/helpers/index/normal/entry_bottom.phtml new file mode 100644 index 000000000..32317d027 --- /dev/null +++ b/app/views/helpers/index/normal/entry_bottom.phtml @@ -0,0 +1,86 @@ +<?php + $sharing = array(); + if (FreshRSS_Auth::hasAccess()) { + $sharing = FreshRSS_Context::$user_conf->sharing; + } + + $bottomline_read = FreshRSS_Context::$user_conf->bottomline_read; + $bottomline_favorite = FreshRSS_Context::$user_conf->bottomline_favorite; + $bottomline_sharing = FreshRSS_Context::$user_conf->bottomline_sharing && (count($sharing) > 0); + $bottomline_tags = FreshRSS_Context::$user_conf->bottomline_tags; + $bottomline_date = FreshRSS_Context::$user_conf->bottomline_date; + $bottomline_link = FreshRSS_Context::$user_conf->bottomline_link; +?><ul class="horizontal-list bottom"><?php + if (FreshRSS_Auth::hasAccess()) { + if ($bottomline_read) { + ?><li class="item manage"><?php + $arUrl = array('c' => 'entry', 'a' => 'read', 'params' => array('id' => $this->entry->id())); + if ($this->entry->isRead()) { + $arUrl['params']['is_read'] = 0; + } + ?><a class="read" href="<?php echo Minz_Url::display($arUrl); ?>"><?php + echo _i($this->entry->isRead() ? 'read' : 'unread'); ?></a><?php + ?></li><?php + } + if ($bottomline_favorite) { + ?><li class="item manage"><?php + $arUrl = array('c' => 'entry', 'a' => 'bookmark', 'params' => array('id' => $this->entry->id())); + if ($this->entry->isFavorite()) { + $arUrl['params']['is_favorite'] = 0; + } + ?><a class="bookmark" href="<?php echo Minz_Url::display($arUrl); ?>"><?php + echo _i($this->entry->isFavorite() ? 'starred' : 'non-starred'); ?></a><?php + ?></li><?php + } + } ?> + <li class="item"><?php + if ($bottomline_sharing) { + ?><div class="dropdown"> + <div id="dropdown-share-<?php echo $item->id();?>" class="dropdown-target"></div> + <a class="dropdown-toggle" href="#dropdown-share-<?php echo $item->id();?>"> + <?php echo _i('share'); ?> + <?php echo _t('index.share'); ?> + </a> + + <ul class="dropdown-menu"> + <li class="dropdown-close"><a href="#close">❌</a></li><?php + $link = $item->link(); + $title = $item->title() . ' · ' . $feed->name(); + foreach (FreshRSS_Context::$user_conf->sharing as $share_options) { + $share = FreshRSS_Share::get($share_options['type']); + $share_options['link'] = $link; + $share_options['title'] = $title; + $share->update($share_options); + ?><li class="item share"> + <a target="_blank" href="<?php echo $share->url(); ?>"><?php echo $share->name(); ?></a> + </li><?php + } + ?></ul> + </div> + <?php } ?> + </li><?php + $tags = $bottomline_tags ? $this->entry->tags() : null; + if (!empty($tags)) { + ?><li class="item"> + <div class="dropdown"> + <div id="dropdown-tags-<?php echo $this->entry->id();?>" class="dropdown-target"></div> + <?php echo _i('tag'); ?> + <a class="dropdown-toggle" href="#dropdown-tags-<?php echo $this->entry->id();?>"><?php + echo _t('index.tag.related'); + ?></a> + <ul class="dropdown-menu"> + <li class="dropdown-close"><a href="#close">❌</a></li><?php + foreach($tags as $tag) { + ?><li class="item"><a href="<?php echo _url('index', 'index', 'search', urlencode('#' . $tag)); ?>"><?php echo $tag; ?></a></li><?php + } ?> + </ul> + </div> + </li><?php + } + if ($bottomline_date) { + ?><li class="item date"><?php echo $this->entry->date(); ?></li><?php + } + if ($bottomline_link) { + ?><li class="item link"><a target="_blank" href="<?php echo $this->entry->link(); ?>"><?php echo _i('link'); ?></a></li><?php + } ?> +</ul> diff --git a/app/views/helpers/index/normal/entry_header.phtml b/app/views/helpers/index/normal/entry_header.phtml new file mode 100644 index 000000000..dc544298f --- /dev/null +++ b/app/views/helpers/index/normal/entry_header.phtml @@ -0,0 +1,33 @@ +<?php + $topline_read = FreshRSS_Context::$user_conf->topline_read; + $topline_favorite = FreshRSS_Context::$user_conf->topline_favorite; + $topline_date = FreshRSS_Context::$user_conf->topline_date; + $topline_link = FreshRSS_Context::$user_conf->topline_link; +?><ul class="horizontal-list flux_header"><?php + if (FreshRSS_Auth::hasAccess()) { + if ($topline_read) { + ?><li class="item manage"><?php + $arUrl = array('c' => 'entry', 'a' => 'read', 'params' => array('id' => $this->entry->id())); + if ($this->entry->isRead()) { + $arUrl['params']['is_read'] = 0; + } + ?><a class="read" href="<?php echo Minz_Url::display($arUrl); ?>"><?php + echo _i($this->entry->isRead() ? 'read' : 'unread'); ?></a><?php + ?></li><?php + } + if ($topline_favorite) { + ?><li class="item manage"><?php + $arUrl = array('c' => 'entry', 'a' => 'bookmark', 'params' => array('id' => $this->entry->id())); + if ($this->entry->isFavorite()) { + $arUrl['params']['is_favorite'] = 0; + } + ?><a class="bookmark" href="<?php echo Minz_Url::display($arUrl); ?>"><?php + echo _i($this->entry->isFavorite() ? 'starred' : 'non-starred'); ?></a><?php + ?></li><?php + } + } + ?><li class="item website"><a href="<?php echo _url('index', 'index', 'get', 'f_' . $this->feed->id()); ?>"><img class="favicon" src="<?php echo $this->feed->favicon(); ?>" alt="✇" /> <span><?php echo $this->feed->name(); ?></span></a></li> + <li class="item title"><a target="_blank" href="<?php echo $this->entry->link(); ?>"><?php echo $this->entry->title(); ?></a></li> + <?php if ($topline_date) { ?><li class="item date"><?php echo $this->entry->date(); ?> </li><?php } ?> + <?php if ($topline_link) { ?><li class="item link"><a target="_blank" href="<?php echo $this->entry->link(); ?>"><?php echo _i('link'); ?></a></li><?php } ?> +</ul> diff --git a/app/views/index/index.phtml b/app/views/index/index.phtml index 8b94c7f7d..e69de29bb 100644 --- a/app/views/index/index.phtml +++ b/app/views/index/index.phtml @@ -1,23 +0,0 @@ -<?php - -$output = Minz_Request::param('output', 'normal'); - -if (FreshRSS_Auth::hasAccess() || FreshRSS_Context::$system_conf->allow_anonymous) { - if ($output === 'normal') { - $this->renderHelper('view/normal_view'); - } elseif ($output === 'reader') { - $this->renderHelper('view/reader_view'); - } elseif ($output === 'rss') { - $this->renderHelper('view/rss_view'); - } else { - Minz_Request::_param('output', 'normal'); - $output = 'normal'; - $this->renderHelper('view/normal_view'); - } -} elseif ($output === 'rss') { - // token has already been checked in the controller so we can show the view - $this->renderHelper('view/rss_view'); -} else { - // Normally, it should not happen, but log it anyway - Minz_Log::error('Something is wrong in ' . __FILE__ . ' line ' . __LINE__); -} diff --git a/app/views/index/normal.phtml b/app/views/index/normal.phtml index 8c6ddd1ee..f71abf158 100644 --- a/app/views/index/normal.phtml +++ b/app/views/index/normal.phtml @@ -7,24 +7,8 @@ if (!empty($this->entries)) { $display_today = true; $display_yesterday = true; $display_others = true; - if (FreshRSS_Auth::hasAccess()) { - $sharing = FreshRSS_Context::$user_conf->sharing; - } else { - $sharing = array(); - } $hidePosts = !FreshRSS_Context::$user_conf->display_posts; $lazyload = FreshRSS_Context::$user_conf->lazyload; - $topline_read = FreshRSS_Context::$user_conf->topline_read; - $topline_favorite = FreshRSS_Context::$user_conf->topline_favorite; - $topline_date = FreshRSS_Context::$user_conf->topline_date; - $topline_link = FreshRSS_Context::$user_conf->topline_link; - $bottomline_read = FreshRSS_Context::$user_conf->bottomline_read; - $bottomline_favorite = FreshRSS_Context::$user_conf->bottomline_favorite; - $bottomline_sharing = FreshRSS_Context::$user_conf->bottomline_sharing && (count($sharing)); - $bottomline_tags = FreshRSS_Context::$user_conf->bottomline_tags; - $bottomline_date = FreshRSS_Context::$user_conf->bottomline_date; - $bottomline_link = FreshRSS_Context::$user_conf->bottomline_link; - $content_width = FreshRSS_Context::$user_conf->content_width; $today = @strtotime('today'); @@ -35,7 +19,21 @@ if (!empty($this->entries)) { <a href="<?php echo Minz_Url::display(Minz_Request::currentRequest()); ?>"><?php echo _t('gen.js.new_article'); /* TODO: move string in JS*/ ?></a> </div><?php foreach ($this->entries as $item) { - if ($display_today && $item->isDay(FreshRSS_Days::TODAY, $today)) { + $this->entry = Minz_ExtensionManager::callHook('entry_before_display', $item); + if (is_null($this->entry)) { + continue; + } + + // We most likely already have the feed object in cache + $this->feed = FreshRSS_CategoryDAO::findFeed($this->categories, $this->entry->feed()); + if ($this->feed == null) { + $this->feed = $this->entry->feed(true); + if ($this->feed == null) { + $this->feed = FreshRSS_Feed::example(); + } + } + + if ($display_today && $this->entry->isDay(FreshRSS_Days::TODAY, $today)) { ?><div class="day" id="day_today"><?php echo _t('gen.date.today'); ?><span class="date"> — <?php echo timestamptodate(time(), false); ?></span><?php @@ -43,7 +41,7 @@ if (!empty($this->entries)) { ?></div><?php $display_today = false; } - if ($display_yesterday && $item->isDay(FreshRSS_Days::YESTERDAY, $today)) { + if ($display_yesterday && $this->entry->isDay(FreshRSS_Days::YESTERDAY, $today)) { ?><div class="day" id="day_yesterday"><?php echo _t('gen.date.yesterday'); ?><span class="date"> — <?php echo timestamptodate(time() - 86400, false); ?></span><?php @@ -51,139 +49,35 @@ if (!empty($this->entries)) { ?></div><?php $display_yesterday = false; } - if ($display_others && $item->isDay(FreshRSS_Days::BEFORE_YESTERDAY, $today)) { + if ($display_others && $this->entry->isDay(FreshRSS_Days::BEFORE_YESTERDAY, $today)) { ?><div class="day" id="day_before_yesterday"><?php echo _t('gen.date.before_yesterday'); ?><span class="name"><?php echo FreshRSS_Context::$name; ?></span><?php ?></div><?php $display_others = false; } - ?><div class="flux<?php echo !$item->isRead() ? ' not_read' : ''; ?><?php echo $item->isFavorite() ? ' favorite' : ''; ?>" id="flux_<?php echo $item->id(); ?>"> - <ul class="horizontal-list flux_header"><?php - if (FreshRSS_Auth::hasAccess()) { - if ($topline_read) { - ?><li class="item manage"><?php - $arUrl = array('c' => 'entry', 'a' => 'read', 'params' => array('id' => $item->id())); - if ($item->isRead()) { - $arUrl['params']['is_read'] = 0; - } - ?><a class="read" href="<?php echo Minz_Url::display($arUrl); ?>"><?php - echo _i($item->isRead() ? 'read' : 'unread'); ?></a><?php - ?></li><?php - } - if ($topline_favorite) { - ?><li class="item manage"><?php - $arUrl = array('c' => 'entry', 'a' => 'bookmark', 'params' => array('id' => $item->id())); - if ($item->isFavorite()) { - $arUrl['params']['is_favorite'] = 0; - } - ?><a class="bookmark" href="<?php echo Minz_Url::display($arUrl); ?>"><?php - echo _i($item->isFavorite() ? 'starred' : 'non-starred'); ?></a><?php - ?></li><?php - } - } - $feed = FreshRSS_CategoryDAO::findFeed($this->categories, $item->feed()); //We most likely already have the feed object in cache - if ($feed == null) { - $feed = $item->feed(true); - if ($feed == null) { - $feed = FreshRSS_Feed::example(); - } - } - ?><li class="item website"><a href="<?php echo _url('index', 'index', 'get', 'f_' . $feed->id()); ?>"><img class="favicon" src="<?php echo $feed->favicon(); ?>" alt="✇" /> <span><?php echo $feed->name(); ?></span></a></li> - <li class="item title"><a target="_blank" href="<?php echo $item->link(); ?>"><?php echo $item->title(); ?></a></li> - <?php if ($topline_date) { ?><li class="item date"><?php echo $item->date(); ?> </li><?php } ?> - <?php if ($topline_link) { ?><li class="item link"><a target="_blank" href="<?php echo $item->link(); ?>"><?php echo _i('link'); ?></a></li><?php } ?> - </ul> + ?><div class="flux<?php echo !$this->entry->isRead() ? ' not_read' : ''; ?><?php echo $this->entry->isFavorite() ? ' favorite' : ''; ?>" id="flux_<?php echo $this->entry->id(); ?>"><?php - <div class="flux_content"> + $this->renderHelper('index/normal/entry_header'); + + ?><div class="flux_content"> <div class="content <?php echo $content_width; ?>"> - <h1 class="title"><a target="_blank" href="<?php echo $item->link(); ?>"><?php echo $item->title(); ?></a></h1> + <h1 class="title"><a target="_blank" href="<?php echo $this->entry->link(); ?>"><?php echo $this->entry->title(); ?></a></h1> <?php - $author = $item->author(); + $author = $this->entry->author(); echo $author != '' ? '<div class="author">' . _t('gen.short.by_author', $author) . '</div>' : '', - $lazyload && $hidePosts ? lazyimg($item->content()) : $item->content(); + $lazyload && $hidePosts ? lazyimg($this->entry->content()) : $this->entry->content(); ?> - </div> - <ul class="horizontal-list bottom"><?php - if (FreshRSS_Auth::hasAccess()) { - if ($bottomline_read) { - ?><li class="item manage"><?php - $arUrl = array('c' => 'entry', 'a' => 'read', 'params' => array('id' => $item->id())); - if ($item->isRead()) { - $arUrl['params']['is_read'] = 0; - } - ?><a class="read" href="<?php echo Minz_Url::display($arUrl); ?>"><?php - echo _i($item->isRead() ? 'read' : 'unread'); ?></a><?php - ?></li><?php - } - if ($bottomline_favorite) { - ?><li class="item manage"><?php - $arUrl = array('c' => 'entry', 'a' => 'bookmark', 'params' => array('id' => $item->id())); - if ($item->isFavorite()) { - $arUrl['params']['is_favorite'] = 0; - } - ?><a class="bookmark" href="<?php echo Minz_Url::display($arUrl); ?>"><?php - echo _i($item->isFavorite() ? 'starred' : 'non-starred'); ?></a><?php - ?></li><?php - } - } ?> - <li class="item"><?php - if ($bottomline_sharing) { - ?><div class="dropdown"> - <div id="dropdown-share-<?php echo $item->id();?>" class="dropdown-target"></div> - <a class="dropdown-toggle" href="#dropdown-share-<?php echo $item->id();?>"> - <?php echo _i('share'); ?> - <?php echo _t('index.share'); ?> - </a> + </div><?php - <ul class="dropdown-menu"> - <li class="dropdown-close"><a href="#close">❌</a></li><?php - $link = $item->link(); - $title = $item->title() . ' · ' . $feed->name(); - foreach (FreshRSS_Context::$user_conf->sharing as $share_options) { - $share = FreshRSS_Share::get($share_options['type']); - $share_options['link'] = $link; - $share_options['title'] = $title; - $share->update($share_options); - ?><li class="item share"> - <a target="_blank" href="<?php echo $share->url(); ?>"><?php echo $share->name(); ?></a> - </li><?php - } - ?></ul> - </div> - <?php } ?> - </li><?php - $tags = $bottomline_tags ? $item->tags() : null; - if (!empty($tags)) { - ?><li class="item"> - <div class="dropdown"> - <div id="dropdown-tags-<?php echo $item->id();?>" class="dropdown-target"></div> - <?php echo _i('tag'); ?> - <a class="dropdown-toggle" href="#dropdown-tags-<?php echo $item->id();?>"><?php - echo _t('index.tag.related'); - ?></a> - <ul class="dropdown-menu"> - <li class="dropdown-close"><a href="#close">❌</a></li><?php - foreach($tags as $tag) { - ?><li class="item"><a href="<?php echo _url('index', 'index', 'search', urlencode('#' . $tag)); ?>"><?php echo $tag; ?></a></li><?php - } ?> - </ul> - </div> - </li><?php - } - if ($bottomline_date) { - ?><li class="item date"><?php echo $item->date(); ?></li><?php - } - if ($bottomline_link) { - ?><li class="item link"><a target="_blank" href="<?php echo $item->link(); ?>"><?php echo _i('link'); ?></a></li><?php - } ?> - </ul> - </div> - </div> - <?php } ?> + $this->renderHelper('index/normal/entry_bottom'); - <?php $this->renderHelper('pagination'); ?> -</div> + ?></div> + </div><?php + } + + $this->renderHelper('pagination'); +?></div> <?php $this->partial('nav_entries'); ?> diff --git a/app/views/index/reader.phtml b/app/views/index/reader.phtml index 017297710..a19ee322e 100644 --- a/app/views/index/reader.phtml +++ b/app/views/index/reader.phtml @@ -6,10 +6,13 @@ if (!empty($this->entries)) { $content_width = FreshRSS_Context::$user_conf->content_width; ?> -<div id="stream" class="reader"> - <?php foreach ($this->entries as $item) { ?> - - <div class="flux<?php echo !$item->isRead() ? ' not_read' : ''; ?><?php echo $item->isFavorite() ? ' favorite' : ''; ?>" id="flux_<?php echo $item->id(); ?>"> +<div id="stream" class="reader"><?php + foreach ($this->entries as $item) { + $item = Minz_ExtensionManager::callHook('entry_before_display', $item); + if (is_null($item)) { + continue; + } + ?><div class="flux<?php echo !$item->isRead() ? ' not_read' : ''; ?><?php echo $item->isFavorite() ? ' favorite' : ''; ?>" id="flux_<?php echo $item->id(); ?>"> <div class="flux_content"> <div class="content <?php echo $content_width; ?>"> <?php diff --git a/app/views/user/manage.phtml b/app/views/user/manage.phtml index 11c42a857..466446f2f 100644 --- a/app/views/user/manage.phtml +++ b/app/views/user/manage.phtml @@ -11,8 +11,8 @@ <div class="group-controls"> <select name="new_user_language" id="new_user_language"> <?php $languages = Minz_Translate::availableLanguages(); ?> - <?php foreach ($languages as $short => $lib) { ?> - <option value="<?php echo $short; ?>"<?php echo FreshRSS_Context::$user_conf->language === $short ? ' selected="selected"' : ''; ?>><?php echo $lib; ?></option> + <?php foreach ($languages as $lang) { ?> + <option value="<?php echo $lang; ?>"<?php echo FreshRSS_Context::$user_conf->language === $lang ? ' selected="selected"' : ''; ?>><?php echo _t('gen.lang.' . $lang); ?></option> <?php } ?> </select> </div> |
