Moved account activation and password reset to API
This commit is contained in:
parent
893e841a87
commit
47f7ff3490
7 changed files with 163 additions and 110 deletions
|
@ -151,10 +151,10 @@ $userValidation =
|
||||||
|
|
||||||
\Chibi\Router::register(['UserController', 'activationView'], 'GET', '/activation', $userValidation);
|
\Chibi\Router::register(['UserController', 'activationView'], 'GET', '/activation', $userValidation);
|
||||||
\Chibi\Router::register(['UserController', 'activationAction'], 'POST', '/activation', $userValidation);
|
\Chibi\Router::register(['UserController', 'activationAction'], 'POST', '/activation', $userValidation);
|
||||||
\Chibi\Router::register(['UserController', 'activationAction'], 'GET', '/activation/{token}', $userValidation);
|
\Chibi\Router::register(['UserController', 'activationAction'], 'GET', '/activation/{tokenText}', $userValidation);
|
||||||
\Chibi\Router::register(['UserController', 'passwordResetView'], 'GET', '/password-reset', $userValidation);
|
\Chibi\Router::register(['UserController', 'passwordResetView'], 'GET', '/password-reset', $userValidation);
|
||||||
\Chibi\Router::register(['UserController', 'passwordResetAction'], 'POST', '/password-reset', $userValidation);
|
\Chibi\Router::register(['UserController', 'passwordResetAction'], 'POST', '/password-reset', $userValidation);
|
||||||
\Chibi\Router::register(['UserController', 'passwordResetAction'], 'GET', '/password-reset/{token}', $userValidation);
|
\Chibi\Router::register(['UserController', 'passwordResetAction'], 'GET', '/password-reset/{tokenText}', $userValidation);
|
||||||
|
|
||||||
\Chibi\Router::register(['UserController', 'flagAction'], 'POST', '/user/{name}/flag', $userValidation);
|
\Chibi\Router::register(['UserController', 'flagAction'], 'POST', '/user/{name}/flag', $userValidation);
|
||||||
\Chibi\Router::register(['UserController', 'banAction'], 'POST', '/user/{name}/ban', $userValidation);
|
\Chibi\Router::register(['UserController', 'banAction'], 'POST', '/user/{name}/ban', $userValidation);
|
||||||
|
|
65
src/Api/Jobs/ActivateUserEmailJob.php
Normal file
65
src/Api/Jobs/ActivateUserEmailJob.php
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
<?php
|
||||||
|
class ActivateUserEmailJob extends AbstractJob
|
||||||
|
{
|
||||||
|
const TOKEN = 'token';
|
||||||
|
|
||||||
|
public function execute()
|
||||||
|
{
|
||||||
|
if (!$this->hasArgument(self::TOKEN))
|
||||||
|
{
|
||||||
|
$user = UserModel::findByNameOrEmail($this->getArgument(self::USER_NAME));
|
||||||
|
|
||||||
|
if (empty($user->emailUnconfirmed))
|
||||||
|
{
|
||||||
|
if (!empty($user->emailConfirmed))
|
||||||
|
throw new SimpleException('E-mail was already confirmed; activation skipped');
|
||||||
|
else
|
||||||
|
throw new SimpleException('This user has no e-mail specified; activation cannot proceed');
|
||||||
|
}
|
||||||
|
|
||||||
|
self::sendEmail($user);
|
||||||
|
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$tokenText = $this->getArgument(self::TOKEN);
|
||||||
|
$token = TokenModel::findByToken($tokenText);
|
||||||
|
TokenModel::checkValidity($token);
|
||||||
|
|
||||||
|
$user = $token->getUser();
|
||||||
|
$user->confirmEmail();
|
||||||
|
$token->used = true;
|
||||||
|
TokenModel::save($token);
|
||||||
|
UserModel::save($user);
|
||||||
|
|
||||||
|
LogHelper::log('{subject} just activated account', [
|
||||||
|
'subject' => TextHelper::reprUser($user)]);
|
||||||
|
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function sendEmail($user)
|
||||||
|
{
|
||||||
|
$regConfig = getConfig()->registration;
|
||||||
|
|
||||||
|
if (!$regConfig->confirmationEmailEnabled)
|
||||||
|
{
|
||||||
|
$user->confirmEmail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$mail = new Mail();
|
||||||
|
$mail->body = $regConfig->confirmationEmailBody;
|
||||||
|
$mail->subject = $regConfig->confirmationEmailSubject;
|
||||||
|
$mail->senderName = $regConfig->confirmationEmailSenderName;
|
||||||
|
$mail->senderEmail = $regConfig->confirmationEmailSenderEmail;
|
||||||
|
$mail->recipientEmail = $user->emailUnconfirmed;
|
||||||
|
|
||||||
|
return Mailer::sendMailWithTokenLink(
|
||||||
|
$user,
|
||||||
|
['UserController', 'activationAction'],
|
||||||
|
$mail);
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,11 +24,8 @@ class AddUserJob extends AbstractJob
|
||||||
Api::enablePrivilegeChecking();
|
Api::enablePrivilegeChecking();
|
||||||
LogHelper::setBuffer([]);
|
LogHelper::setBuffer([]);
|
||||||
|
|
||||||
if ($firstUser and empty($user->emailConfirmed))
|
if ($firstUser)
|
||||||
{
|
$user->confirmEmail();
|
||||||
$user->emailConfirmed = $user->emailUnconfirmed;
|
|
||||||
$user->emailUnconfirmed = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//load the user after edits
|
//load the user after edits
|
||||||
$user = UserModel::findById($user->id);
|
$user = UserModel::findById($user->id);
|
||||||
|
|
|
@ -16,20 +16,17 @@ class EditUserEmailJob extends AbstractUserJob
|
||||||
if ($oldEmail == $newEmail)
|
if ($oldEmail == $newEmail)
|
||||||
return $user;
|
return $user;
|
||||||
|
|
||||||
|
$user->emailUnconfirmed = $newEmail;
|
||||||
|
$user->emailConfirmed = null;
|
||||||
|
|
||||||
if (Auth::getCurrentUser()->id == $user->id)
|
if (Auth::getCurrentUser()->id == $user->id)
|
||||||
{
|
{
|
||||||
$user->emailUnconfirmed = $newEmail;
|
|
||||||
$user->emailConfirmed = null;
|
|
||||||
|
|
||||||
if (!empty($newEmail))
|
if (!empty($newEmail))
|
||||||
{
|
ActivateUserEmailJob::sendEmail($user);
|
||||||
$this->sendEmail($user);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$user->emailUnconfirmed = null;
|
$user->confirmEmail();
|
||||||
$user->emailConfirmed = $newEmail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UserModel::save($user);
|
UserModel::save($user);
|
||||||
|
@ -50,29 +47,4 @@ class EditUserEmailJob extends AbstractUserJob
|
||||||
Access::getIdentity($this->user),
|
Access::getIdentity($this->user),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo: change to private once finished refactors to UserController
|
|
||||||
public function sendEmail($user)
|
|
||||||
{
|
|
||||||
$regConfig = getConfig()->registration;
|
|
||||||
|
|
||||||
if (!$regConfig->confirmationEmailEnabled)
|
|
||||||
{
|
|
||||||
$user->emailUnconfirmed = null;
|
|
||||||
$user->emailConfirmed = $user->emailUnconfirmed;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$mail = new Mail();
|
|
||||||
$mail->body = $regConfig->confirmationEmailBody;
|
|
||||||
$mail->subject = $regConfig->confirmationEmailSubject;
|
|
||||||
$mail->senderName = $regConfig->confirmationEmailSenderName;
|
|
||||||
$mail->senderEmail = $regConfig->confirmationEmailSenderEmail;
|
|
||||||
$mail->recipientEmail = $user->emailUnconfirmed;
|
|
||||||
|
|
||||||
return Mailer::sendMailWithTokenLink(
|
|
||||||
$user,
|
|
||||||
['UserController', 'activationAction'],
|
|
||||||
$mail);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
64
src/Api/Jobs/PasswordResetJob.php
Normal file
64
src/Api/Jobs/PasswordResetJob.php
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
<?php
|
||||||
|
class PasswordResetJob extends AbstractJob
|
||||||
|
{
|
||||||
|
const TOKEN = 'token';
|
||||||
|
const NEW_PASSWORD = 'new-password';
|
||||||
|
|
||||||
|
public function execute()
|
||||||
|
{
|
||||||
|
if (!$this->hasArgument(self::TOKEN))
|
||||||
|
{
|
||||||
|
$user = UserModel::findByNameOrEmail($this->getArgument(self::USER_NAME));
|
||||||
|
|
||||||
|
if (empty($user->emailConfirmed))
|
||||||
|
throw new SimpleException('This user has no e-mail confirmed; password reset cannot proceed');
|
||||||
|
|
||||||
|
self::sendEmail($user);
|
||||||
|
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$tokenText = $this->getArgument(self::TOKEN);
|
||||||
|
$token = TokenModel::findByToken($tokenText);
|
||||||
|
TokenModel::checkValidity($token);
|
||||||
|
|
||||||
|
$alphabet = array_merge(range('A', 'Z'), range('a', 'z'), range('0', '9'));
|
||||||
|
$newPassword = join('', array_map(function($x) use ($alphabet)
|
||||||
|
{
|
||||||
|
return $alphabet[$x];
|
||||||
|
}, array_rand($alphabet, 8)));
|
||||||
|
|
||||||
|
$user = $token->getUser();
|
||||||
|
$user->passHash = UserModel::hashPassword($newPassword, $user->passSalt);
|
||||||
|
$token->used = true;
|
||||||
|
TokenModel::save($token);
|
||||||
|
UserModel::save($user);
|
||||||
|
|
||||||
|
LogHelper::log('{subject} just reset password', [
|
||||||
|
'subject' => TextHelper::reprUser($user)]);
|
||||||
|
|
||||||
|
$x = new StdClass;
|
||||||
|
$x->user = $user;
|
||||||
|
$x->newPassword = $newPassword;
|
||||||
|
return $x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function sendEmail($user)
|
||||||
|
{
|
||||||
|
$regConfig = getConfig()->registration;
|
||||||
|
|
||||||
|
$mail = new Mail();
|
||||||
|
$mail->body = $regConfig->passwordResetEmailBody;
|
||||||
|
$mail->subject = $regConfig->passwordResetEmailSubject;
|
||||||
|
$mail->senderName = $regConfig->passwordResetEmailSenderName;
|
||||||
|
$mail->senderEmail = $regConfig->passwordResetEmailSenderEmail;
|
||||||
|
$mail->recipientEmail = $user->emailConfirmed;
|
||||||
|
|
||||||
|
return Mailer::sendMailWithTokenLink(
|
||||||
|
$user,
|
||||||
|
['UserController', 'passwordResetAction'],
|
||||||
|
$mail);
|
||||||
|
}
|
||||||
|
}
|
|
@ -223,51 +223,30 @@ class UserController
|
||||||
Assets::setSubTitle('account activation');
|
Assets::setSubTitle('account activation');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function activationAction($token)
|
public function activationAction($tokenText)
|
||||||
{
|
{
|
||||||
$context = getContext();
|
$context = getContext();
|
||||||
$context->viewName = 'message';
|
$context->viewName = 'message';
|
||||||
Assets::setSubTitle('account activation');
|
Assets::setSubTitle('account activation');
|
||||||
|
$name = InputHelper::get('name');
|
||||||
|
|
||||||
if (empty($token))
|
if (empty($tokenText))
|
||||||
{
|
{
|
||||||
$name = InputHelper::get('name');
|
Api::run(new ActivateUserEmailJob(), [ ActivateUserEmailJob::USER_NAME => $name ]);
|
||||||
$user = UserModel::findByNameOrEmail($name);
|
|
||||||
if (empty($user->emailUnconfirmed))
|
|
||||||
{
|
|
||||||
if (!empty($user->emailConfirmed))
|
|
||||||
throw new SimpleException('E-mail was already confirmed; activation skipped');
|
|
||||||
else
|
|
||||||
throw new SimpleException('This user has no e-mail specified; activation cannot proceed');
|
|
||||||
}
|
|
||||||
EditUserEmailJob::sendEmail($user);
|
|
||||||
Messenger::message('Activation e-mail resent.');
|
Messenger::message('Activation e-mail resent.');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$dbToken = TokenModel::findByToken($token);
|
$user = Api::run(new ActivateUserEmailJob(), [ ActivateUserEmailJob::TOKEN => $tokenText ]);
|
||||||
TokenModel::checkValidity($dbToken);
|
|
||||||
|
|
||||||
$dbUser = $dbToken->getUser();
|
|
||||||
if (empty($dbUser->emailConfirmed))
|
|
||||||
{
|
|
||||||
$dbUser->emailConfirmed = $dbUser->emailUnconfirmed;
|
|
||||||
$dbUser->emailUnconfirmed = null;
|
|
||||||
}
|
|
||||||
$dbToken->used = true;
|
|
||||||
TokenModel::save($dbToken);
|
|
||||||
UserModel::save($dbUser);
|
|
||||||
|
|
||||||
LogHelper::log('{subject} just activated account', ['subject' => TextHelper::reprUser($dbUser)]);
|
|
||||||
$message = 'Activation completed successfully.';
|
$message = 'Activation completed successfully.';
|
||||||
if (getConfig()->registration->staffActivation)
|
if (getConfig()->registration->staffActivation)
|
||||||
$message .= ' However, your account still must be confirmed by staff.';
|
$message .= ' However, your account still must be confirmed by staff.';
|
||||||
Messenger::message($message);
|
Messenger::message($message);
|
||||||
|
|
||||||
if (!getConfig()->registration->staffActivation)
|
if (!getConfig()->registration->staffActivation)
|
||||||
{
|
Auth::setCurrentUser($user);
|
||||||
Auth::setCurrentUser($dbUser);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,64 +257,31 @@ class UserController
|
||||||
Assets::setSubTitle('password reset');
|
Assets::setSubTitle('password reset');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function passwordResetAction($token)
|
public function passwordResetAction($tokenText)
|
||||||
{
|
{
|
||||||
$context = getContext();
|
$context = getContext();
|
||||||
$context->viewName = 'message';
|
$context->viewName = 'message';
|
||||||
Assets::setSubTitle('password reset');
|
Assets::setSubTitle('password reset');
|
||||||
|
$name = InputHelper::get('name');
|
||||||
|
|
||||||
if (empty($token))
|
if (empty($tokenText))
|
||||||
{
|
{
|
||||||
$name = InputHelper::get('name');
|
Api::run(new PasswordResetJob(), [ PasswordResetJob::USER_NAME => $name ]);
|
||||||
$user = UserModel::findByNameOrEmail($name);
|
|
||||||
if (empty($user->emailConfirmed))
|
|
||||||
throw new SimpleException('This user has no e-mail confirmed; password reset cannot proceed');
|
|
||||||
|
|
||||||
self::sendPasswordResetConfirmation($user);
|
|
||||||
Messenger::message('E-mail sent. Follow instructions to reset password.');
|
Messenger::message('E-mail sent. Follow instructions to reset password.');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
$dbToken = TokenModel::findByToken($token);
|
$ret = Api::run(new PasswordResetJob(), [ PasswordResetJob::TOKEN => $tokenText ]);
|
||||||
TokenModel::checkValidity($dbToken);
|
|
||||||
|
|
||||||
$alphabet = array_merge(range('A', 'Z'), range('a', 'z'), range('0', '9'));
|
Messenger::message(sprintf(
|
||||||
$randomPassword = join('', array_map(function($x) use ($alphabet)
|
'Password reset successful. Your new password is **%s**.',
|
||||||
{
|
$ret->newPassword));
|
||||||
return $alphabet[$x];
|
|
||||||
}, array_rand($alphabet, 8)));
|
|
||||||
|
|
||||||
$dbUser = $dbToken->getUser();
|
Auth::setCurrentUser($ret->user);
|
||||||
$dbUser->passHash = UserModel::hashPassword($randomPassword, $dbUser->passSalt);
|
|
||||||
$dbToken->used = true;
|
|
||||||
TokenModel::save($dbToken);
|
|
||||||
UserModel::save($dbUser);
|
|
||||||
|
|
||||||
LogHelper::log('{subject} just reset password', ['subject' => TextHelper::reprUser($dbUser)]);
|
|
||||||
$message = 'Password reset successful. Your new password is **' . $randomPassword . '**.';
|
|
||||||
Messenger::message($message);
|
|
||||||
|
|
||||||
Auth::setCurrentUser($dbUser);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function sendPasswordResetConfirmation($user)
|
|
||||||
{
|
|
||||||
$regConfig = getConfig()->registration;
|
|
||||||
|
|
||||||
$mail = new Mail();
|
|
||||||
$mail->body = $regConfig->passwordResetEmailBody;
|
|
||||||
$mail->subject = $regConfig->passwordResetEmailSubject;
|
|
||||||
$mail->senderName = $regConfig->passwordResetEmailSenderName;
|
|
||||||
$mail->senderEmail = $regConfig->passwordResetEmailSenderEmail;
|
|
||||||
$mail->recipientEmail = $user->emailConfirmed;
|
|
||||||
|
|
||||||
return Mailer::sendMailWithTokenLink(
|
|
||||||
$user,
|
|
||||||
['UserController', 'passwordResetAction'],
|
|
||||||
$mail);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function requirePasswordConfirmation()
|
private function requirePasswordConfirmation()
|
||||||
{
|
{
|
||||||
$user = getContext()->transport->user;
|
$user = getContext()->transport->user;
|
||||||
|
|
|
@ -112,6 +112,15 @@ class UserEntity extends AbstractEntity
|
||||||
$this->setSetting(UserModel::SETTING_ENDLESS_SCROLLING, $enabled ? 1 : 0);
|
$this->setSetting(UserModel::SETTING_ENDLESS_SCROLLING, $enabled ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function confirmEmail()
|
||||||
|
{
|
||||||
|
if (!empty($this->emailConfirmed))
|
||||||
|
return;
|
||||||
|
|
||||||
|
$this->emailConfirmed = $user->emailUnconfirmed;
|
||||||
|
$this->emailUnconfirmed = null;
|
||||||
|
}
|
||||||
|
|
||||||
public function hasFavorited($post)
|
public function hasFavorited($post)
|
||||||
{
|
{
|
||||||
$stmt = new Sql\SelectStatement();
|
$stmt = new Sql\SelectStatement();
|
||||||
|
|
Loading…
Reference in a new issue