Moved account activation and password reset to API

This commit is contained in:
Marcin Kurczewski 2014-05-04 15:43:38 +02:00
parent 893e841a87
commit 47f7ff3490
7 changed files with 163 additions and 110 deletions

View file

@ -151,10 +151,10 @@ $userValidation =
\Chibi\Router::register(['UserController', 'activationView'], 'GET', '/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', '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', 'banAction'], 'POST', '/user/{name}/ban', $userValidation);

View 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);
}
}

View file

@ -24,11 +24,8 @@ class AddUserJob extends AbstractJob
Api::enablePrivilegeChecking();
LogHelper::setBuffer([]);
if ($firstUser and empty($user->emailConfirmed))
{
$user->emailConfirmed = $user->emailUnconfirmed;
$user->emailUnconfirmed = null;
}
if ($firstUser)
$user->confirmEmail();
//load the user after edits
$user = UserModel::findById($user->id);

View file

@ -16,20 +16,17 @@ class EditUserEmailJob extends AbstractUserJob
if ($oldEmail == $newEmail)
return $user;
if (Auth::getCurrentUser()->id == $user->id)
{
$user->emailUnconfirmed = $newEmail;
$user->emailConfirmed = null;
if (!empty($newEmail))
if (Auth::getCurrentUser()->id == $user->id)
{
$this->sendEmail($user);
}
if (!empty($newEmail))
ActivateUserEmailJob::sendEmail($user);
}
else
{
$user->emailUnconfirmed = null;
$user->emailConfirmed = $newEmail;
$user->confirmEmail();
}
UserModel::save($user);
@ -50,29 +47,4 @@ class EditUserEmailJob extends AbstractUserJob
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);
}
}

View 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);
}
}

View file

@ -223,51 +223,30 @@ class UserController
Assets::setSubTitle('account activation');
}
public function activationAction($token)
public function activationAction($tokenText)
{
$context = getContext();
$context->viewName = 'message';
Assets::setSubTitle('account activation');
if (empty($token))
{
$name = InputHelper::get('name');
$user = UserModel::findByNameOrEmail($name);
if (empty($user->emailUnconfirmed))
if (empty($tokenText))
{
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);
Api::run(new ActivateUserEmailJob(), [ ActivateUserEmailJob::USER_NAME => $name ]);
Messenger::message('Activation e-mail resent.');
}
else
{
$dbToken = TokenModel::findByToken($token);
TokenModel::checkValidity($dbToken);
$user = Api::run(new ActivateUserEmailJob(), [ ActivateUserEmailJob::TOKEN => $tokenText ]);
$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.';
if (getConfig()->registration->staffActivation)
$message .= ' However, your account still must be confirmed by staff.';
Messenger::message($message);
if (!getConfig()->registration->staffActivation)
{
Auth::setCurrentUser($dbUser);
}
Auth::setCurrentUser($user);
}
}
@ -278,64 +257,31 @@ class UserController
Assets::setSubTitle('password reset');
}
public function passwordResetAction($token)
public function passwordResetAction($tokenText)
{
$context = getContext();
$context->viewName = 'message';
Assets::setSubTitle('password reset');
if (empty($token))
{
$name = InputHelper::get('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);
if (empty($tokenText))
{
Api::run(new PasswordResetJob(), [ PasswordResetJob::USER_NAME => $name ]);
Messenger::message('E-mail sent. Follow instructions to reset password.');
}
else
{
$dbToken = TokenModel::findByToken($token);
TokenModel::checkValidity($dbToken);
$ret = Api::run(new PasswordResetJob(), [ PasswordResetJob::TOKEN => $tokenText ]);
$alphabet = array_merge(range('A', 'Z'), range('a', 'z'), range('0', '9'));
$randomPassword = join('', array_map(function($x) use ($alphabet)
{
return $alphabet[$x];
}, array_rand($alphabet, 8)));
Messenger::message(sprintf(
'Password reset successful. Your new password is **%s**.',
$ret->newPassword));
$dbUser = $dbToken->getUser();
$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);
Auth::setCurrentUser($ret->user);
}
}
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()
{
$user = getContext()->transport->user;

View file

@ -112,6 +112,15 @@ class UserEntity extends AbstractEntity
$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)
{
$stmt = new Sql\SelectStatement();