Skip to content

Commit 52edc60

Browse files
authored
[6.0] Notification email on admin registration approval (#45802)
1 parent 03fcfec commit 52edc60

File tree

8 files changed

+203
-24
lines changed

8 files changed

+203
-24
lines changed

administrator/components/com_users/src/Controller/UserController.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use Joomla\CMS\Access\Access;
1414
use Joomla\CMS\MVC\Controller\FormController;
1515
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
16+
use Joomla\CMS\Response\JsonResponse;
1617
use Joomla\CMS\Router\Route;
1718
use Joomla\CMS\Uri\Uri;
1819

@@ -160,4 +161,34 @@ public function batch($model = null)
160161
protected function postSaveHook(BaseDatabaseModel $model, $validData = [])
161162
{
162163
}
164+
165+
/**
166+
* Get the XHR request to activate a user
167+
* js: media/com_users/js/activate-user-send-email
168+
*
169+
* @return void
170+
*
171+
* @since __DEPLOY_VERSION__
172+
*/
173+
public function active(): void
174+
{
175+
// Get the ID of the user
176+
$userId = $this->input->getString('userid', '');
177+
178+
// Prepare the default response
179+
$responseError = false;
180+
$responseMessage = null;
181+
182+
// Set the model
183+
$model = $this->getModel('User', 'Administrator', []);
184+
185+
// Activate the user and send the email
186+
if (!$model->activate($userId)) {
187+
$responseError = true;
188+
}
189+
190+
$responseMessage = \Joomla\CMS\Factory::getApplication()->getMessageQueue();
191+
192+
echo new JsonResponse(null, $responseMessage, $responseError);
193+
}
163194
}

administrator/components/com_users/src/Model/UserModel.php

Lines changed: 82 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Joomla\CMS\Form\Form;
1717
use Joomla\CMS\Language\Multilanguage;
1818
use Joomla\CMS\Language\Text;
19+
use Joomla\CMS\Mail\MailTemplate;
1920
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
2021
use Joomla\CMS\MVC\Model\AdminModel;
2122
use Joomla\CMS\Plugin\PluginHelper;
@@ -224,9 +225,8 @@ protected function preprocessForm(Form $form, $data, $group = 'user')
224225
*/
225226
public function save($data)
226227
{
227-
$pk = (!empty($data['id'])) ? $data['id'] : (int) $this->getState('user.id');
228-
$user = $this->getUserFactory()->loadUserById($pk);
229-
228+
$pk = (!empty($data['id'])) ? $data['id'] : (int) $this->getState('user.id');
229+
$user = $this->getUserFactory()->loadUserById($pk);
230230
$my = $this->getCurrentUser();
231231
$iAmSuperAdmin = $my->authorise('core.admin');
232232

@@ -292,7 +292,7 @@ public function save($data)
292292
}
293293

294294
// Destroy all active sessions for the user after changing the password or blocking him
295-
if (!empty($data['password2']) || $data['block']) {
295+
if (!empty($data['password2']) || !empty($data['block'])) {
296296
UserHelper::destroyUserSessions($user->id, true);
297297
}
298298

@@ -380,8 +380,8 @@ public function delete(&$pks)
380380
*/
381381
public function block(&$pks, $value = 1)
382382
{
383-
$app = Factory::getApplication();
384-
$user = $this->getCurrentUser();
383+
$app = Factory::getApplication();
384+
$user = $this->getCurrentUser();
385385

386386
// Check if I am a Super Admin
387387
$iAmSuperAdmin = $user->authorise('core.admin');
@@ -484,26 +484,80 @@ public function block(&$pks, $value = 1)
484484
*/
485485
public function activate(&$pks)
486486
{
487-
$user = $this->getCurrentUser();
487+
$app = Factory::getApplication();
488+
$user = $app->getIdentity();
488489

489-
// Check if I am a Super Admin
490+
// Check if I am a super admin
490491
$iAmSuperAdmin = $user->authorise('core.admin');
491-
$table = $this->getTable();
492-
$pks = (array) $pks;
492+
493+
// Load user table
494+
$table = $this->getTable();
495+
$pks = (array) $pks;
496+
497+
// Compile the user activated notification mail default values.
498+
$mailData = [];
499+
$mailData['siteurl'] = \Joomla\CMS\Uri\Uri::root();
500+
$mailData['fromname'] = $app->get('fromname');
501+
$mailData['mailfrom'] = $app->get('mailfrom');
502+
$mailData['sitename'] = $app->get('sitename');
503+
504+
// Load com_users site language strings, the mail template use it
505+
$app->getLanguage()->load('com_users', JPATH_SITE);
506+
507+
$sendMailTo = function ($userData) use ($app, $mailData) {
508+
$mailData['name'] = $userData['name'];
509+
$mailData['username'] = $userData['username'];
510+
511+
// Use the default language
512+
$langTag = ComponentHelper::getParams('com_languages')->get('site', 'en-GB');
513+
514+
$mailer = new MailTemplate('com_users.registration.user.admin_activated', $langTag);
515+
$mailer->addTemplateData($mailData);
516+
$mailer->addRecipient($userData['email']);
517+
518+
try {
519+
$return = $mailer->send();
520+
} catch (\Exception $exception) {
521+
try {
522+
\Joomla\CMS\Log\Log::add(Text::_($exception->getMessage()), \Joomla\CMS\Log\Log::WARNING, 'jerror');
523+
524+
$return = false;
525+
} catch (\RuntimeException $exception) {
526+
$app->enqueueMessage(Text::_($exception->errorMessage()), $app::MSG_WARNING);
527+
528+
$return = false;
529+
}
530+
}
531+
532+
// Check for an error.
533+
if ($return !== true) {
534+
$app->enqueueMessage(Text::_('COM_USERS_REGISTRATION_ACTIVATION_NOTIFY_SEND_MAIL_FAILED'), $app::MSG_WARNING);
535+
536+
return false;
537+
}
538+
539+
$app->enqueueMessage(Text::_('COM_USERS_REGISTRATION_ACTIVATION_NOTIFY_SEND_MAIL_SUCCESS'), $app::MSG_INFO);
540+
return true;
541+
};
493542

494543
PluginHelper::importPlugin($this->events_map['save']);
495544

496-
// Access checks.
545+
// Activate and send the notification email
497546
foreach ($pks as $i => $pk) {
498547
if ($table->load($pk)) {
499-
$old = $table->getProperties();
500-
$allow = $user->authorise('core.edit.state', 'com_users');
548+
$prevUserData = $table->getProperties();
549+
$allow = $user->authorise('core.edit.state', 'com_users');
501550

502-
// Don't allow non-super-admin to delete a super admin
551+
// Don't allow non-super-admin to edit the active status of a super admin
503552
$allow = (!$iAmSuperAdmin && Access::check($pk, 'core.admin')) ? false : $allow;
504553

554+
// Ignore activated accounts but check if we can still
555+
// resend the notification email
505556
if (empty($table->activation)) {
506-
// Ignore activated accounts.
557+
if (\is_null($table->lastvisitDate)) {
558+
$sendMailTo($prevUserData);
559+
}
560+
507561
unset($pks[$i]);
508562
} elseif ($allow) {
509563
$table->block = 0;
@@ -518,7 +572,7 @@ public function activate(&$pks)
518572
}
519573

520574
// Trigger the before save event.
521-
$result = Factory::getApplication()->triggerEvent($this->event_before_save, [$old, false, $table->getProperties()]);
575+
$result = Factory::getApplication()->triggerEvent($this->event_before_save, [$prevUserData, false, $table->getProperties()]);
522576

523577
if (\in_array(false, $result, true)) {
524578
// Plugin will have to raise it's own error or throw an exception.
@@ -534,6 +588,11 @@ public function activate(&$pks)
534588

535589
// Fire the after save event
536590
Factory::getApplication()->triggerEvent($this->event_after_save, [$table->getProperties(), false, true, null]);
591+
592+
// Send the email
593+
if (!$sendMailTo($prevUserData)) {
594+
return false;
595+
}
537596
} catch (\Exception $e) {
538597
$this->setError($e->getMessage());
539598

@@ -542,7 +601,7 @@ public function activate(&$pks)
542601
} else {
543602
// Prune items that you can't change.
544603
unset($pks[$i]);
545-
Factory::getApplication()->enqueueMessage(Text::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED'), 'error');
604+
$app->enqueueMessage(Text::_('JLIB_APPLICATION_ERROR_EDITSTATE_NOT_PERMITTED'), 'error');
546605
}
547606
}
548607
}
@@ -733,10 +792,10 @@ public function batchUser($groupId, $userIds, $action)
733792
// Remove the users from the group if requested.
734793
if (isset($doDelete)) {
735794
/*
736-
* First we need to check that the user is part of more than one group
737-
* otherwise we will end up with a user that is not part of any group
738-
* unless we are moving the user to a new group.
739-
*/
795+
* First we need to check that the user is part of more than one group
796+
* otherwise we will end up with a user that is not part of any group
797+
* unless we are moving the user to a new group.
798+
*/
740799
if ($doDelete === 'group') {
741800
$query = $db->getQuery(true);
742801
$query->select($db->quoteName('user_id'))
@@ -877,8 +936,8 @@ public function getAssignedGroups($userId = null)
877936
$userId = (!empty($userId)) ? $userId : (int) $this->getState('user.id');
878937

879938
if (empty($userId)) {
880-
$result = [];
881-
$form = $this->getForm();
939+
$result = [];
940+
$form = $this->getForm();
882941

883942
if ($form) {
884943
$groupsIDs = $form->getValue('groups');

administrator/components/com_users/src/View/User/HtmlView.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,26 @@ function (Toolbar $childBar) use ($canDo, $isProfile) {
195195
$toolbar->cancel('user.cancel');
196196
}
197197

198+
// Check lastvisitDate for allow resend the activation email
199+
$userIsNotActive = !empty($this->item->activation) || \is_null($this->item->lastvisitDate);
200+
201+
if ($this->item->id > 0 && $userIsNotActive) {
202+
$buttonText = !empty($this->item->activation)
203+
? Text::_('COM_USERS_USER_ACTIVATE_AND_MAIL')
204+
: Text::_('COM_USERS_USER_ACTIVATION_REMINDER');
205+
206+
$toolbar->standardButton('activate', $buttonText)
207+
->buttonClass('btn activate-send-mail')
208+
->attributes([
209+
'data-option' => 'com_users',
210+
'data-task' => 'user.active',
211+
'data-format' => 'json',
212+
'data-userid' => $this->item->id,
213+
])
214+
->icon('icon-mail')
215+
->onclick('');
216+
}
217+
198218
$toolbar->divider();
199219
$toolbar->help('Users:_Edit_Profile');
200220
}

administrator/components/com_users/tmpl/user/edit.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
/** @var Joomla\CMS\WebAsset\WebAssetManager $wa */
2222
$wa = $this->getDocument()->getWebAssetManager();
2323
$wa->useScript('keepalive')
24-
->useScript('form.validate');
24+
->useScript('form.validate')
25+
->useScript('com_users.activate-user-send-email');
2526

2627
$input = Factory::getApplication()->getInput();
2728

administrator/language/en-GB/com_users.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,8 @@ COM_USERS_USERS_N_ITEMS_DELETED="%d users deleted."
395395
COM_USERS_USERS_N_ITEMS_DELETED_1="User deleted."
396396
COM_USERS_USERS_TABLE_CAPTION="Users"
397397
COM_USERS_USER_ACCOUNT_DETAILS="Account Details"
398+
COM_USERS_USER_ACTIVATE_AND_MAIL="Activate & Send Email"
399+
COM_USERS_USER_ACTIVATION_REMINDER="Send Activation Reminder"
398400
COM_USERS_USER_ALLOWTOURAUTOSTART_LABEL="Allow Auto Starting Tours"
399401
COM_USERS_USER_BACKUPCODE="Backup Code"
400402
COM_USERS_USER_BACKUPCODES="Backup Codes"

build/media_source/com_users/joomla.asset.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,17 @@
3737
"attributes": {
3838
"type": "module"
3939
}
40+
},
41+
{
42+
"name": "com_users.activate-user-send-email",
43+
"type": "script",
44+
"uri": "com_users/activate-user-send-email.min.js",
45+
"dependencies": [
46+
"core"
47+
],
48+
"attributes": {
49+
"type": "module"
50+
}
4051
}
4152
]
4253
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
3+
* @license GNU General Public License version 2 or later; see LICENSE.txt
4+
*/
5+
6+
if (!Joomla) {
7+
throw new Error('Joomla API was not properly initialized');
8+
}
9+
10+
const button = document.querySelector('.activate-send-mail');
11+
12+
if (button && Object.keys(button.dataset).length !== 0) {
13+
button.addEventListener('click', () => {
14+
button.querySelector('span').className = 'icon-spinner';
15+
button.disabled = true;
16+
17+
const queryString = Object.keys(button.dataset)
18+
.reduce((a, k) => {
19+
a.push(`${k}=${encodeURIComponent(button.dataset[k])}`);
20+
return a;
21+
}, [])
22+
.join('&');
23+
24+
const url = `index.php?${queryString}`;
25+
26+
Joomla.request({
27+
url,
28+
method: 'GET',
29+
30+
onSuccess: (resp) => {
31+
let response;
32+
try {
33+
response = JSON.parse(resp);
34+
} catch (error) {
35+
button.classList.add('error');
36+
}
37+
38+
button.querySelector('span').className = 'icon-mail';
39+
button.disabled = false;
40+
41+
if (response.messages) {
42+
Joomla.renderMessages(response.messages);
43+
}
44+
},
45+
onError: (resp) => {
46+
const response = JSON.parse(resp);
47+
button.classList.add('error');
48+
if (response.messages) {
49+
Joomla.renderMessages(response.messages);
50+
}
51+
},
52+
});
53+
});
54+
}

language/en-GB/com_users.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ COM_USERS_REGISTRATION_ACL_ADMIN_ACTIVATION="Please log in to confirm that you a
108108
COM_USERS_REGISTRATION_ACL_ADMIN_ACTIVATION_PERMISSIONS="You are not authorised to activate new accounts, please log in with a privileged account."
109109
COM_USERS_REGISTRATION_ACTIVATE_SUCCESS="Your Account has been activated. You can now log in using the username and password you chose during the registration."
110110
COM_USERS_REGISTRATION_ACTIVATION_NOTIFY_SEND_MAIL_FAILED="An error was encountered while sending activation notification email"
111+
COM_USERS_REGISTRATION_ACTIVATION_NOTIFY_SEND_MAIL_SUCCESS="The user has been notified that their account has been activated."
111112
COM_USERS_REGISTRATION_ACTIVATION_SAVE_FAILED="Failed to save activation data: %s"
112113
COM_USERS_REGISTRATION_ADMINACTIVATE_SUCCESS="The user's account has been activated and the user has been notified about it."
113114
COM_USERS_REGISTRATION_COMPLETE_ACTIVATE="Your account has been created and an activation link has been sent to the email address you entered. Note that you must activate the account by selecting the activation link when you get the email before you can login."

0 commit comments

Comments
 (0)