diff --git a/administrator/components/com_admin/sql/updates/mysql/6.1.0-2025-09-05.sql b/administrator/components/com_admin/sql/updates/mysql/6.1.0-2025-09-05.sql new file mode 100644 index 000000000000..d2adee50b444 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/mysql/6.1.0-2025-09-05.sql @@ -0,0 +1,38 @@ +-- remove old email parameter from scheduled tasks +UPDATE `#__scheduler_task` +SET `params` = JSON_REMOVE(`params`, '$.email') +WHERE JSON_CONTAINS_PATH(`params`, 'one', '$.email'); + +-- add post-installation message for task update notification. +-- +-- See https://github.com/joomla/joomla-cms/pull/43182 for details. +-- +INSERT INTO `#__postinstall_messages` +(`extension_id`, +`title_key`, +`description_key`, +`action_key`, +`language_extension`, +`language_client_id`, +`type`, +`action_file`, +`action`, +`condition_file`, +`condition_method`, +`version_introduced`, +`enabled`) +SELECT +`extension_id`, +'PLG_TASK_UPDATENOTIFICATION_POSTINSTALL_TITLE', +'PLG_TASK_UPDATENOTIFICATION_POSTINSTALL_DESCRIPTION', +'', +'plg_task_updatenotification', +1, +'message', +'', +'', +'admin://plugins/task/updatenotification/postinstall/updatenotification.php', +'', +'6.1.0', +1 +FROM `#__extensions` WHERE `name` = 'files_joomla'; diff --git a/administrator/components/com_admin/sql/updates/postgresql/6.1.0-2025-09-05.sql b/administrator/components/com_admin/sql/updates/postgresql/6.1.0-2025-09-05.sql new file mode 100644 index 000000000000..14ae40f5cf17 --- /dev/null +++ b/administrator/components/com_admin/sql/updates/postgresql/6.1.0-2025-09-05.sql @@ -0,0 +1,38 @@ +-- remove old email parameter from scheduled tasks +UPDATE "#__scheduler_task" +SET "params" = jsonb_set("params", '{email}', '""') +WHERE "params" ? 'email'; + +-- add post-installation message for task update notification. +-- +-- See https://github.com/joomla/joomla-cms/pull/43182 for details. +-- +INSERT INTO "#__postinstall_messages" +("extension_id", +"title_key", +"description_key", +"action_key", +"language_extension", +"language_client_id", +"type", +"action_file", +"action", +"condition_file", +"condition_method", +"version_introduced", +"enabled") +SELECT +"extension_id", +'PLG_TASK_UPDATENOTIFICATION_POSTINSTALL_TITLE', +'PLG_TASK_UPDATENOTIFICATION_POSTINSTALL_DESCRIPTION', +'', +'plg_task_updatenotification', +1, +'message', +'', +'', +'admin://plugins/task/updatenotification/postinstall/updatenotification.php', +'', +'6.1.0', +1 +FROM "#__extensions" WHERE "name" = 'files_joomla'; \ No newline at end of file diff --git a/administrator/language/en-GB/plg_task_updatenotification.ini b/administrator/language/en-GB/plg_task_updatenotification.ini index 141df42dbb93..2bb8de8c1a16 100644 --- a/administrator/language/en-GB/plg_task_updatenotification.ini +++ b/administrator/language/en-GB/plg_task_updatenotification.ini @@ -4,8 +4,12 @@ ; Note : All ini files need to be saved as UTF-8 PLG_TASK_UPDATENOTIFICATION="Task - Joomla! Update Notification" +; The following string is deprecated and will be removed with 8. PLG_TASK_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 belongs to Super Users, or if it's left blank, all Super Users of this site will receive the update notification email." +; The following string is deprecated and will be removed with 8. PLG_TASK_UPDATENOTIFICATION_EMAIL_LBL="Super User Emails" +PLG_TASK_UPDATENOTIFICATION_EMAILGROUPS_DESC="All users in the selected groups will receive the emails. If no users are found, the emails are sent to all Super Users. Recipients MUST have the Receive System Emails option enabled." +PLG_TASK_UPDATENOTIFICATION_EMAILGROUPS_LBL="Send Email to User Groups" PLG_TASK_UPDATENOTIFICATION_SEND_TITLE="Joomla! Update Notification" PLG_TASK_UPDATENOTIFICATION_SEND_DESC="This task periodically checks for the availability of new Joomla! versions. When one is found it will send you an email, reminding you to update. You can customise the email at System → Mail Templates." PLG_TASK_UPDATENOTIFICATION_LANGUAGE_OVERRIDE_DESC="Select a language for the update notification emails. Set to Auto to send them in the site language at the time." @@ -23,4 +27,6 @@ PLG_TASK_UPDATENOTIFICATION_EMAIL_BODY="This email IS NOT sent by the Joomla! pr PLG_TASK_UPDATENOTIFICATION_EMAIL_SUBJECT="Joomla! Update available for {SITENAME} – {URL}" PLG_TASK_UPDATENOTIFICATION_MAIL_MAIL_DESC="Sent to the site administrators when the "Joomla! Update Notification" task plugin detects an update." PLG_TASK_UPDATENOTIFICATION_MAIL_MAIL_TITLE="Joomla: Update Notification" -PLG_TASK_UPDATENOTIFICATION_XML_DESCRIPTION="This task periodically checks for the availability of new Joomla! versions. When one is found it will send you an email, reminding you to update. You can customise the email at System → Mail Templates." +PLG_TASK_UPDATENOTIFICATION_POSTINSTALL_DESCRIPTION="

The "Joomla! Update Notification" task sends an email to the site administrators when it detects that a new Joomla! version is available. The email is per default sent to all super users of the system.

It is now possible to send notifications to one or more groups of users, who have the sendEmail permission, also if they are not super users.

If in your system recipients were defined as a comma separated list of email addresses, this list has been removed with update to version 6.1.

Please check the plugin's options and adjust them to your needs.

" +PLG_TASK_UPDATENOTIFICATION_POSTINSTALL_TITLE="Joomla! Update Notification Recipient Change" +PLG_TASK_UPDATENOTIFICATION_XML_DESCRIPTION="This task periodically checks for the availability of new Joomla! versions. When one is found it will send you an email, reminding you to update. You can customise the email at System → Mail Templates." \ No newline at end of file diff --git a/plugins/task/updatenotification/forms/sendForm.xml b/plugins/task/updatenotification/forms/sendForm.xml index 47fe0c72d808..ae96c428e5f8 100644 --- a/plugins/task/updatenotification/forms/sendForm.xml +++ b/plugins/task/updatenotification/forms/sendForm.xml @@ -3,11 +3,13 @@
getArgument('params')->email ?? ''; $forcedLanguage = $event->getArgument('params')->language_override ?? ''; - - $updateParams = ComponentHelper::getParams('com_joomlaupdate'); + $updateParams = ComponentHelper::getParams('com_joomlaupdate'); // Don't send when automated updates are active and working $registrationState = AutoupdateRegisterState::tryFrom($updateParams->get('autoupdate_status', '')); @@ -135,7 +134,6 @@ private function sendNotification(ExecuteTaskEvent $event): int if (version_compare($update->version, JVERSION, 'le')) { return Status::OK; } - // If we're here, we have updates. First, get a link to the Joomla! Update component. $baseURL = Uri::base(); $baseURL = rtrim($baseURL, '/'); @@ -158,17 +156,10 @@ private function sendNotification(ExecuteTaskEvent $event): int $this->getApplication()->triggerEvent('onBuildAdministratorLoginURL', [&$uri]); // Let's find out the email addresses to notify - $superUsers = []; - - if (!empty($specificEmail)) { - $superUsers = $this->getSuperUsers($specificEmail); - } - - if (empty($superUsers)) { - $superUsers = $this->getSuperUsers(); - } + $emailReceivers = $this->getEmailReceivers(); - if (empty($superUsers)) { + if (empty($emailReceivers)) { + // Just in case - at least one super user exists in every Joomla! site return Status::KNOCKOUT; } @@ -205,11 +196,11 @@ private function sendNotification(ExecuteTaskEvent $event): int 'releasenews' => 'https://www.joomla.org/announcements/release-news/', ]; - // Send the emails to the Super Users - foreach ($superUsers as $superUser) { + // Send the emails + foreach ($emailReceivers as $receiver) { try { $mailer = new MailTemplate('plg_task_updatenotification.mail', $jLanguage->getTag()); - $mailer->addRecipient($superUser->email); + $mailer->addRecipient($receiver->email); $mailer->addTemplateData($substitutions); $mailer->send(); } catch (MailDisabledException | phpMailerException $exception) { @@ -227,94 +218,76 @@ private function sendNotification(ExecuteTaskEvent $event): int } /** - * 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. + * Returns all Email recipients: super users and the users of email receiver groups * - * @param null|string $email A list of Super Users to email + * @return array The list of email recipients * - * @return array The list of Super User emails - * - * @since 3.5 + * @since __DEPLOY_VERSION__ */ - private function getSuperUsers($email = null) + private function getEmailReceivers(): array { - $db = $this->getDatabase(); - $emails = []; + $emailReceivers = []; - // Convert the email list to an array - if (!empty($email)) { - $temp = explode(',', $email); + // Find groups with core.admin rights (super users) + $superUserGroups = $this->getSuperUserGroups(); - foreach ($temp as $entry) { - $emails[] = trim($entry); - } + // Get User group ids from input field, if empty fallback to super user groups + $params = ComponentHelper::getParams('com_joomlaupdate'); + $emailGroups = $params->get('email_groups', $superUserGroups); - $emails = array_unique($emails); + if (!\is_array($emailGroups)) { + $emailGroups = ArrayHelper::toInteger(explode(',', $emailGroups)); } - // Get a list of groups which have Super User privileges - $ret = []; + // Make the array unique to avoid multiple queries for the same group + $emailGroups = array_unique($emailGroups); - try { - $table = new Asset($db); - $rootId = $table->getRootId(); - $rules = Access::getAssetRules($rootId)->getData(); - $rawGroups = $rules['core.admin']->getData(); - $groups = []; + // Get the users of all groups in the emailGroups + $usersModel = Factory::getApplication()->bootComponent('com_users') + ->getMVCFactory()->createModel('Users', 'Administrator'); + $usersModel->setState('filter.state', (int) 0); - if (empty($rawGroups)) { - return $ret; + foreach ($emailGroups as $group) { + // Skip invalid group ids. Group ids are always numeric and > 0 + if (!is_numeric($group) || $group < 1) { + continue; } - foreach ($rawGroups as $g => $enabled) { - if ($enabled) { - $groups[] = $g; - } + $usersModel->setState('filter.group_id', $group); + + $usersInGroup = $usersModel->getItems(); + if (empty($usersInGroup)) { + continue; } - if (empty($groups)) { - return $ret; + // Users can be in more than one group. Accept only one entry + foreach ($usersInGroup as $user) { + if (MailHelper::isEmailAddress($user->email) && $user->sendEmail === 1) { + $emailReceivers[$user->id] ??= $user; + } } - } catch (\Exception $exc) { - return $ret; } - // Get the user IDs of users belonging to the SA groups - try { - $query = $db->getQuery(true) - ->select($db->quoteName('user_id')) - ->from($db->quoteName('#__user_usergroup_map')) - ->whereIn($db->quoteName('group_id'), $groups); - - $db->setQuery($query); - $userIDs = $db->loadColumn(0); + return $emailReceivers; + } - if (empty($userIDs)) { - return $ret; - } - } catch (\Exception $exc) { - return $ret; - } + /** + * Returns all Super Users + * + * @return array The list of super user groups. + * + * @since __DEPLOY_VERSION__ + */ + private function getSuperUserGroups(): array + { + $groups = UserGroupsHelper::getInstance()->getAll(); + $ret = []; - // Get the user information for the Super Administrator users - try { - $query = $db->getQuery(true) - ->select($db->quoteName(['id', 'username', 'email'])) - ->from($db->quoteName('#__users')) - ->whereIn($db->quoteName('id'), $userIDs) - ->where($db->quoteName('block') . ' = 0') - ->where($db->quoteName('sendEmail') . ' = 1'); - - if (!empty($emails)) { - $lowerCaseEmails = array_map('strtolower', $emails); - $query->whereIn('LOWER(' . $db->quoteName('email') . ')', $lowerCaseEmails, ParameterType::STRING); + // Find groups with core.admin rights (super users) + foreach ($groups as $group) { + if (Access::checkGroup($group->id, 'core.admin')) { + $ret[] = $group->id; } - - $db->setQuery($query); - $ret = $db->loadObjectList(); - } catch (\Exception) { - return $ret; } return $ret;