diff --git a/administrator/components/com_admin/sql/updates/mysql/3.4.2-2015-05-03.sql b/administrator/components/com_admin/sql/updates/mysql/3.4.2-2015-05-03.sql new file mode 100644 index 0000000000000..e2921fc346193 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/3.4.2-2015-05-03.sql @@ -0,0 +1,2 @@ +INSERT INTO `#__extensions` (`extension_id`, `name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `manifest_cache`, `params`, `custom_data`, `system_data`, `checked_out`, `checked_out_time`, `ordering`, `state`) VALUES +(452, 'plg_system_updatenotification', 'plugin', 'updatenotification', 'system', 0, 1, 1, 0, '', '', '', '', 0, '0000-00-00 00:00:00', 0, 0); diff --git a/administrator/components/com_admin/sql/updates/postgresql/3.4.2-2015-05-03.sql b/administrator/components/com_admin/sql/updates/postgresql/3.4.2-2015-05-03.sql new file mode 100644 index 0000000000000..895cf8faf99e6 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/postgresql/3.4.2-2015-05-03.sql @@ -0,0 +1,2 @@ +INSERT INTO "#__extensions" ("extension_id", "name", "type", "element", "folder", "client_id", "enabled", "access", "protected", "manifest_cache", "params", "custom_data", "system_data", "checked_out", "checked_out_time", "ordering", "state") VALUES +(452, 'plg_system_updatenotification', 'plugin', 'updatenotification', 'system', 0, 1, 1, 0, '', '', '', '', 0, '1970-01-01 00:00:00', 0, 0); diff --git a/administrator/components/com_admin/sql/updates/sqlazure/3.4.2-2015-05-03.sql b/administrator/components/com_admin/sql/updates/sqlazure/3.4.2-2015-05-03.sql new file mode 100644 index 0000000000000..0435fa8fa6402 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/sqlazure/3.4.2-2015-05-03.sql @@ -0,0 +1,6 @@ +SET IDENTITY_INSERT [#__extensions] ON; + +INSERT [#__extensions] ([extension_id], [name], [type], [element], [folder], [client_id], [enabled], [access], [protected], [manifest_cache], [params], [custom_data], [system_data], [checked_out], [checked_out_time], [ordering], [state]) +SELECT 452, 'plg_system_updatenotification', 'plugin', 'updatenotification', 'system', 0, 1, 1, 0, '', '', '', '', 0, '1900-01-01 00:00:00', 0, 0; + +SET IDENTITY_INSERT [#__extensions] OFF; diff --git a/administrator/language/en-GB/en-GB.plg_system_updatenotification.ini b/administrator/language/en-GB/en-GB.plg_system_updatenotification.ini new file mode 100644 index 0000000000000..bca688cb3049c --- /dev/null +++ b/administrator/language/en-GB/en-GB.plg_system_updatenotification.ini @@ -0,0 +1,23 @@ +; Joomla! Project +; Copyright (C) 2005 - 2015 Open Source Matters. All rights reserved. +; License GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php +; Note : All ini files need to be saved as UTF-8 + +PLG_SYSTEM_UPDATENOTIFICATION="System - Joomla! Update Notification" +PLG_SYSTEM_UPDATENOTIFICATION_DESCRIPTION="This plugin periodically checks for the availability of new Joomla! versions. When one is found it will send you an email, reminding you to update Joomla!. Pro Tip: You can customise the email message by overriding the language string keys PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_SUBJECT and PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_BODY." + +PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_LBL="Super User Emails" +PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_DESC="A comma separated list of the email addresses which will receive the update notification emails. The addresses in the list MUST belong to existing users of your site who have the Super User privilege. If none of the listed emails belogns to Super Users, or if it's left blank, all Super Users of this site will receive the update notification email." +PLG_SYSTEM_UPDATENOTIFICATION_LANGUAGE_OVERRIDE_LBL="Email language" +PLG_SYSTEM_UPDATENOTIFICATION_LANGUAGE_OVERRIDE_DESC="If you choose Auto (default), the update notification email to Super Users will be in the logged in user's front-end language at the time the plugin is triggered. In multi-language sites this can create confusion: the user's language may be one the Super User receiving the email doesn't speak. By selecting a language here you are forcing the update notification emails to be sent in this specific language." +PLG_SYSTEM_UPDATENOTIFICATION_LANGUAGE_OVERRIDE_NONE="Auto" + +; You can use the following merge codes: +; [NEWVERSION] New Joomla! version, e.g. 1.2.3 +; [CURVERSION] Currently installed Joomla! version, e.g. 1.2.0 +; [SITENAME] Site name, as set in Global Configuration. +; [URL] URL of the site's front-end page. +; [LINK] Update URL (link to com_joomlaupdate, will request login if the Super User isn't already logged in). +; \n Newline character. Use it to start a new line in the email. NO LINE SHOULD EXCEED 300 CHARACTERS! +PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_SUBJECT="Joomla! Update available for [SITENAME] – [URL]" +PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_BODY="This email IS NOT sent by Joomla.org It is sent automatically by your own site,\n[SITENAME]\n\n================================================================================\nUPDATE INFORMATION\n================================================================================\n\nYour site has discovered that there is an updated version of Joomla! available\nfor download.\n\nJoomla! version currently installed: [CURVERSION]\nJoomla! version available for installation: [NEWVERSION]\n\nThis email is sent to you by your site to remind you of this fact. The Joomla!\nproject will never contact you directly about available updates of Joomla! on\nyour site.\n\n================================================================================\nUPDATE INSTRUCTIONS\n================================================================================\n\nTo install the update on [SITENAME] please click the following link. (If the URL\nis not a link, simply copy & paste it to your browser).\n\nUpdate link: [LINK]\n\n================================================================================\nWHY AM I RECEIVING THIS EMAIL?\n================================================================================\n\nThis email has been automatically sent by a plugin provided by Joomla!, the\nsoftware which powers your site. This plugin looks for updated versions of\nJoomla! and sends an email notification to its administrators. You will receive\nseveral similar emails from your site until you either update the software or\ndisable these emails.\n\nTo disable these emails, please unpublish the 'System - Joomla! Update\nNotification' plugin in the Plugin Manager on your site.\n\nIf you do not understand what is Joomla! and what you need to do please do not\ncontact the Joomla! project. They are NOT sending you this email and they cannot\nhelp you. Instead, please contact the person who built or manages your site.\n\nIf you are the person who built or manages your website, please note that this\nplugin may have been activated automatically when you installed or updated Joomla!\non your site.\n\n================================================================================\nWHO SENT ME THIS EMAIL?\n================================================================================\n\nThis email is sent to you by your own site, [SITENAME]" \ No newline at end of file diff --git a/administrator/language/en-GB/en-GB.plg_system_updatenotification.sys.ini b/administrator/language/en-GB/en-GB.plg_system_updatenotification.sys.ini new file mode 100644 index 0000000000000..894a51561a1ca --- /dev/null +++ b/administrator/language/en-GB/en-GB.plg_system_updatenotification.sys.ini @@ -0,0 +1,7 @@ +; Joomla! Project +; Copyright (C) 2005 - 2015 Open Source Matters. All rights reserved. +; License GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php +; Note : All ini files need to be saved as UTF-8 + +PLG_SYSTEM_UPDATENOTIFICATION="System - Joomla! Update Notification" +PLG_SYSTEM_UPDATENOTIFICATION_DESCRIPTION="This plugin periodically checks for the availability of new Joomla! versions. When one is found it will send you an email, reminding you to update Joomla!. Pro Tip: You can customise the email message by overriding the language string keys PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_SUBJECT and PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_BODY." \ No newline at end of file diff --git a/installation/sql/mysql/joomla.sql b/installation/sql/mysql/joomla.sql index 1fcc2322cd4e1..1c6bc04112472 100644 --- a/installation/sql/mysql/joomla.sql +++ b/installation/sql/mysql/joomla.sql @@ -610,6 +610,7 @@ INSERT INTO `#__extensions` (`extension_id`, `name`, `type`, `element`, `folder` (449, 'plg_authentication_cookie', 'plugin', 'cookie', 'authentication', 0, 1, 1, 0, '', '', '', '', 0, '0000-00-00 00:00:00', 0, 0), (450, 'plg_twofactorauth_yubikey', 'plugin', 'yubikey', 'twofactorauth', 0, 0, 1, 0, '', '', '', '', 0, '0000-00-00 00:00:00', 0, 0), (451, 'plg_search_tags', 'plugin', 'tags', 'search', 0, 1, 1, 0, '', '{"search_limit":"50","show_tagged_items":"1"}', '', '', 0, '0000-00-00 00:00:00', 0, 0), +(452, 'plg_system_updatenotification', 'plugin', 'updatenotification', 'system', 0, 1, 1, 0, '', '', '', '', 0, '0000-00-00 00:00:00', 0, 0), (503, 'beez3', 'template', 'beez3', '', 0, 1, 1, 0, '', '{"wrapperSmall":"53","wrapperLarge":"72","sitetitle":"","sitedescription":"","navposition":"center","templatecolor":"nature"}', '', '', 0, '0000-00-00 00:00:00', 0, 0), (504, 'hathor', 'template', 'hathor', '', 1, 1, 1, 0, '', '{"showSiteName":"0","colourChoice":"0","boldText":"0"}', '', '', 0, '0000-00-00 00:00:00', 0, 0), (506, 'protostar', 'template', 'protostar', '', 0, 1, 1, 0, '', '{"templateColor":"","logoFile":"","googleFont":"1","googleFontName":"Open+Sans","fluidContainer":"0"}', '', '', 0, '0000-00-00 00:00:00', 0, 0), diff --git a/installation/sql/postgresql/joomla.sql b/installation/sql/postgresql/joomla.sql index 876d4263487aa..cdf03653eaece 100644 --- a/installation/sql/postgresql/joomla.sql +++ b/installation/sql/postgresql/joomla.sql @@ -610,7 +610,8 @@ INSERT INTO "#__extensions" ("extension_id", "name", "type", "element", "folder" (448, 'plg_twofactorauth_totp', 'plugin', 'totp', 'twofactorauth', 0, 0, 1, 0, '', '', '', '', 0, '1970-01-01 00:00:00', 0, 0), (449, 'plg_authentication_cookie', 'plugin', 'cookie', 'authentication', 0, 1, 1, 0, '', '', '', '', 0, '1970-01-01 00:00:00', 0, 0), (450, 'plg_twofactorauth_yubikey', 'plugin', 'yubikey', 'twofactorauth', 0, 0, 1, 0, '', '', '', '', 0, '1970-01-01 00:00:00', 0, 0), -(451, 'plg_search_tags', 'plugin', 'tags', 'search', 0, 1, 1, 0, '', '{"search_limit":"50","show_tagged_items":"1"}', '', '', 0, '1970-01-01 00:00:00', 0, 0); +(451, 'plg_search_tags', 'plugin', 'tags', 'search', 0, 1, 1, 0, '', '{"search_limit":"50","show_tagged_items":"1"}', '', '', 0, '1970-01-01 00:00:00', 0, 0), +(452, 'plg_system_updatenotification', 'plugin', 'updatenotification', 'system', 0, 1, 1, 0, '', '', '', '', 0, '1970-01-01 00:00:00', 0, 0); -- Templates INSERT INTO "#__extensions" ("extension_id", "name", "type", "element", "folder", "client_id", "enabled", "access", "protected", "manifest_cache", "params", "custom_data", "system_data", "checked_out", "checked_out_time", "ordering", "state") VALUES diff --git a/installation/sql/sqlazure/joomla.sql b/installation/sql/sqlazure/joomla.sql index 9ef97578f6c9d..b0d54edddb22a 100644 --- a/installation/sql/sqlazure/joomla.sql +++ b/installation/sql/sqlazure/joomla.sql @@ -1011,7 +1011,9 @@ SELECT 449, 'plg_authentication_cookie', 'plugin', 'cookie', 'authentication', 0 UNION ALL SELECT 450, 'plg_twofactorauth_yubikey', 'plugin', 'yubikey', 'twofactorauth', 0, 0, 1, 0, '', '', '', '', 0, '1900-01-01 00:00:00', 0, 0 UNION ALL -SELECT 451, 'plg_search_tags', 'plugin', 'tags', 'search', 0, 1, 1, 0, '', '{"search_limit":"50","show_tagged_items":"1"}', '', '', 0, '1900-01-01 00:00:00', 0, 0; +SELECT 451, 'plg_search_tags', 'plugin', 'tags', 'search', 0, 1, 1, 0, '', '{"search_limit":"50","show_tagged_items":"1"}', '', '', 0, '1900-01-01 00:00:00', 0, 0 +UNION ALL +SELECT 452, 'plg_system_updatenotification', 'plugin', 'updatenotification', 'system', 0, 1, 1, 0, '', '', '', '', 0, '1900-01-01 00:00:00', 0, 0; INSERT [#__extensions] ([extension_id], [name], [type], [element], [folder], [client_id], [enabled], [access], [protected], [manifest_cache], [params], [custom_data], [system_data], [checked_out], [checked_out_time], [ordering], [state]) diff --git a/libraries/joomla/updater/updater.php b/libraries/joomla/updater/updater.php index b260b701d5ae8..be96c27d51aec 100644 --- a/libraries/joomla/updater/updater.php +++ b/libraries/joomla/updater/updater.php @@ -100,9 +100,9 @@ public static function getInstance() /** * Finds an update for an extension * - * @param integer $eid Extension Identifier; if zero use all sites - * @param integer $cacheTimeout How many seconds to cache update information; if zero, force reload the update information - * @param integer $minimum_stability Minimum stability for the updates; 0=dev, 1=alpha, 2=beta, 3=rc, 4=stable + * @param int|array $eid Extension Identifier or list of Extension Identifiers; if zero use all sites + * @param integer $cacheTimeout How many seconds to cache update information; if zero, force reload the update information + * @param integer $minimum_stability Minimum stability for the updates; 0=dev, 1=alpha, 2=beta, 3=rc, 4=stable * * @return boolean True if there are updates * diff --git a/plugins/system/updatenotification/updatenotification.php b/plugins/system/updatenotification/updatenotification.php new file mode 100644 index 0000000000000..3bf0c71654c56 --- /dev/null +++ b/plugins/system/updatenotification/updatenotification.php @@ -0,0 +1,408 @@ +params; + $cache_timeout = $params->get('cachetimeout', 6, 'int'); + $cache_timeout = 3600 * $cache_timeout; + + // Do we need to run? Compare the last run timestamp stored in the plugin's options with the current + // timestamp. If the difference is greater than the cache timeout we shall not execute again. + $now = time(); + $last = (int) $this->params->get('lastrun', 0); + + if (!defined('PLG_SYSTEM_UPDATENOTIFICATION_DEBUG') && (abs($now - $last) < $cache_timeout)) + { + return; + } + + // Update last run status + // If I have the time of the last run, I can update, otherwise insert + $this->params->set('lastrun', $now); + + $db = JFactory::getDbo(); + $query = $db->getQuery(true) + ->update($db->qn('#__extensions')) + ->set($db->qn('params') . ' = ' . $db->q($this->params->toString('JSON'))) + ->where($db->qn('type') . ' = ' . $db->q('plugin')) + ->where($db->qn('folder') . ' = ' . $db->q('system')) + ->where($db->qn('element') . ' = ' . $db->q('updatenotification')); + + try + { + // Lock the tables to prevent multiple plugin executions causing a race condition + $db->lockTable('#__extensions'); + } + catch (Exception $e) + { + // If we can't lock the tables it's too risk continuing execution + return; + } + + try + { + // Update the plugin parameters + $result = $db->setQuery($query)->execute(); + + $this->clearCacheGroups(array('com_plugins'), array(0, 1)); + } + catch (Exception $exc) + { + // If we failed to execite + $db->unlockTables(); + $result = false; + } + + try + { + // Unlock the tables after writing + $db->unlockTables(); + } + catch (Exception $e) + { + // If we can't lock the tables assume we have somehow failed + $result = false; + } + + // Abort on failure + if (!$result) + { + return; + } + + // This is the extension ID for Joomla! itself + $eid = 700; + + // Get any available updates + $updater = JUpdater::getInstance(); + $results = $updater->findUpdates(array($eid), $cache_timeout); + + // If there are no updates our job is done. We need BOTH this check AND the one below. + if (!$results) + { + return; + } + + // Unfortunately Joomla! MVC doesn't allow us to autoload classes, hence the need for an ugly require_once + require_once JPATH_ADMINISTRATOR . '/components/com_installer/models/update.php'; + + // Get the update model and retrieve the Joomla! core updates + $model = JModelLegacy::getInstance('Update', 'InstallerModel'); + $model->setState('filter.extension_id', $eid); + $updates = $model->getItems(); + + // If there are no updates we don't have to notify anyone about anything. This is NOT a duplicate check. + if (empty($updates)) + { + return; + } + + // Get the available update + $update = array_pop($updates); + + // Check the available version. If it's the same as the installed version we have no updates to notify about. + if (version_compare($update->version, JVERSION, 'eq')) + { + return; + } + + // If we're here, we have updates. First, get a link to the Joomla! Update component. + $baseURL = JURI::base(); + $baseURL = rtrim($baseURL, '/'); + $baseURL .= (substr($baseURL, -13) != 'administrator') ? '/administrator/' : '/'; + $baseURL .= 'index.php?option=com_joomlaupdate'; + $uri = new JUri($baseURL); + + /** + * Some third party security solutions require a secret query parameter to allow log in to the administrator + * back-end of the site. The link generated above will be invalid and could probably block the user out of their + * site, confusing them (they can't understand the third party security solution is not part of Joomla! proper). + * So, we're calling the onBuildAdministratorLoginURL system plugin event to let these third party solutions + * add any necessary secret query parameters to the URL. The plugins are supposed to have a method with the + * signature: + * + * public function onBuildAdministratorLoginURL(JUri &$uri); + * + * The plugins should modify the $uri object directly and return null. + */ + + JEventDispatcher::getInstance()->trigger('onBuildAdministratorLoginURL', array(&$uri)); + + // Let's find out the email addresses to notify + $superUsers = array(); + $specificEmail = $this->params->get('email', ''); + + if (!empty($specificEmail)) + { + $superUsers = $this->getSuperUsers($specificEmail); + } + + if (empty($superUsers)) + { + $superUsers = $this->getSuperUsers(); + } + + if (empty($superUsers)) + { + return; + } + + /* Load the appropriate language. We try to load English (UK), the current user's language and the forced + * language preference, in this order. This ensures that we'll never end up with untranslated strings in the + * update email which would make Joomla! seem bad. So, please, if you don't fully understand what the + * following code does DO NOT TOUCH IT. It makes the difference between a hobbyist CMS and a professional + * solution! */ + $jLanguage = JFactory::getLanguage(); + $jLanguage->load('plg_system_updatenotification', JPATH_ADMINISTRATOR, 'en-GB', true, true); + $jLanguage->load('plg_system_updatenotification', JPATH_ADMINISTRATOR, null, true, false); + + // Then try loading the preferred (forced) language + $forcedLanguage = $this->params->get('language_override', ''); + + if (!empty($forcedLanguage)) + { + $jLanguage->load('plg_system_updatenotification', JPATH_ADMINISTRATOR, $forcedLanguage, true, false); + } + + // Set up the email subject and body + + $email_subject = JText::_('PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_SUBJECT'); + $email_body = JText::_('PLG_SYSTEM_UPDATENOTIFICATION_EMAIL_BODY'); + + // Replace merge codes with their values + $newVersion = $update->version; + + $jVersion = new JVersion; + $currentVersion = $jVersion->getShortVersion(); + + $jConfig = JFactory::getConfig(); + $sitename = $jConfig->get('sitename'); + $mailFrom = $jConfig->get('mailfrom'); + $fromName = $jConfig->get('fromname'); + + $substitutions = array( + '[NEWVERSION]' => $newVersion, + '[CURVERSION]' => $currentVersion, + '[SITENAME]' => $sitename, + '[URL]' => JUri::base(), + '[LINK]' => $uri->toString(), + '\\n' => "\n", + ); + + foreach ($substitutions as $k => $v) + { + $email_subject = str_replace($k, $v, $email_subject); + $email_body = str_replace($k, $v, $email_body); + } + + // Send the emails to the Super Users + foreach ($superUsers as $superUser) + { + $mailer = JFactory::getMailer(); + $mailer->setSender(array($mailFrom, $fromName)); + $mailer->addRecipient($superUser->email); + $mailer->setSubject($email_subject); + $mailer->setBody($email_body); + $mailer->Send(); + } + } + + /** + * Returns the Super Users email information. If you provide a comma separated $email list + * we will check that these emails do belong to Super Users and that they have not blocked + * system emails. + * + * @param null|string $email A list of Super Users to email + * + * @return array The list of Super User emails + */ + private function getSuperUsers($email = null) + { + // Get a reference to the database object + $db = JFactory::getDBO(); + + // Convert the email list to an array + if (!empty($email)) + { + $temp = explode(',', $email); + $emails = array(); + + foreach ($temp as $entry) + { + $entry = trim($entry); + $emails[] = $db->q($entry); + } + + $emails = array_unique($emails); + } + else + { + $emails = array(); + } + + // Get a list of groups which have Super User privileges + $ret = array(); + + try + { + $query = $db->getQuery(true) + ->select($db->qn('rules')) + ->from($db->qn('#__assets')) + ->where($db->qn('parent_id') . ' = ' . $db->q(0)); + $db->setQuery($query, 0, 1); + $rulesJSON = $db->loadResult(); + $rules = json_decode($rulesJSON, true); + + $rawGroups = $rules['core.admin']; + $groups = array(); + + if (empty($rawGroups)) + { + return $ret; + } + + foreach ($rawGroups as $g => $enabled) + { + if ($enabled) + { + $groups[] = $db->q($g); + } + } + + if (empty($groups)) + { + return $ret; + } + } + catch (Exception $exc) + { + return $ret; + } + + // Get the user IDs of users belonging to the SA groups + try + { + $query = $db->getQuery(true) + ->select($db->qn('user_id')) + ->from($db->qn('#__user_usergroup_map')) + ->where($db->qn('group_id') . ' IN(' . implode(',', $groups) . ')'); + $db->setQuery($query); + $rawUserIDs = $db->loadColumn(0); + + if (empty($rawUserIDs)) + { + return $ret; + } + + $userIDs = array(); + + foreach ($rawUserIDs as $id) + { + $userIDs[] = $db->q($id); + } + } + catch (Exception $exc) + { + return $ret; + } + + // Get the user information for the Super Administrator users + try + { + $query = $db->getQuery(true) + ->select( + array( + $db->qn('id'), + $db->qn('username'), + $db->qn('email'), + ) + )->from($db->qn('#__users')) + ->where($db->qn('id') . ' IN(' . implode(',', $userIDs) . ')') + ->where($db->qn('sendEmail') . ' = ' . $db->q('1')); + + if (!empty($emails)) + { + $query->where($db->qn('email') . 'IN(' . implode(',', $emails) . ')'); + } + + $db->setQuery($query); + $ret = $db->loadObjectList(); + } + catch (Exception $exc) + { + return $ret; + } + + return $ret; + } + + /** + * Clears cache groups. We use it to clear the plugins cache after we update the last run timestamp. + * + * @param array $clearGroups The cache groups to clean + * @param array $cacheClients The cache clients (site, admin) to clean + * + * @return void + */ + private function clearCacheGroups(array $clearGroups, array $cacheClients = array(0, 1)) + { + $conf = JFactory::getConfig(); + + foreach ($clearGroups as $group) + { + foreach ($cacheClients as $client_id) + { + try + { + $options = array( + 'defaultgroup' => $group, + 'cachebase' => ($client_id) ? JPATH_ADMINISTRATOR . '/cache' : + $conf->get('cache_path', JPATH_SITE . '/cache') + ); + + $cache = JCache::getInstance('callback', $options); + $cache->clean(); + } + catch (Exception $e) + { + // Ignore it + } + } + } + } +} diff --git a/plugins/system/updatenotification/updatenotification.xml b/plugins/system/updatenotification/updatenotification.xml new file mode 100644 index 0000000000000..faaf3492b8ae4 --- /dev/null +++ b/plugins/system/updatenotification/updatenotification.xml @@ -0,0 +1,34 @@ + + + PLG_SYSTEM_UPDATENOTIFICATION + Joomla! Project + May 2015 + Copyright (C) 2005 - 2015 Open Source Matters. All rights reserved. + GNU General Public License version 2 or later; see LICENSE.txt + admin@joomla.org + www.joomla.org + 3.0.0 + PLG_SYSTEM_UPDATENOTIFICATION_DESCRIPTION + + updatenotification.php + + + en-GB.plg_system_updatenotification.ini + en-GB.plg_system_updatenotification.sys.ini + + + +
+ + + + + +
+
+
+