Moved user account settings to API
This commit is contained in:
parent
816859c3e3
commit
b0bbdde112
9 changed files with 321 additions and 164 deletions
|
@ -5,6 +5,8 @@ class EditPostJob extends AbstractPostJob
|
|||
{
|
||||
$post = $this->post;
|
||||
|
||||
LogHelper::bufferChanges();
|
||||
|
||||
$subJobs =
|
||||
[
|
||||
new EditPostSafetyJob(),
|
||||
|
@ -29,6 +31,7 @@ class EditPostJob extends AbstractPostJob
|
|||
}
|
||||
}
|
||||
|
||||
LogHelper::flush();
|
||||
return $post;
|
||||
}
|
||||
}
|
||||
|
|
35
src/Api/Jobs/EditUserAccessRankJob.php
Normal file
35
src/Api/Jobs/EditUserAccessRankJob.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
class EditUserAccessRankJob extends AbstractUserJob
|
||||
{
|
||||
const NEW_ACCESS_RANK = 'new-access-rank';
|
||||
|
||||
public function execute()
|
||||
{
|
||||
$user = $this->user;
|
||||
$newAccessRank = UserModel::validateAccessRank($this->getArgument(self::NEW_ACCESS_RANK));
|
||||
|
||||
$oldAccessRank = $user->accessRank;
|
||||
if ($oldAccessRank == $newAccessRank)
|
||||
return $user;
|
||||
|
||||
$user->accessRank = $newAccessRank;
|
||||
|
||||
UserModel::save($user);
|
||||
|
||||
LogHelper::log('{user} changed {subject}\'s access rank to {rank}', [
|
||||
'user' => TextHelper::reprUser(Auth::getCurrentUser()),
|
||||
'subject' => TextHelper::reprUser($user),
|
||||
'rank' => AccessRank::toString($newAccessRank)]);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function requiresPrivilege()
|
||||
{
|
||||
return
|
||||
[
|
||||
Privilege::ChangeUserEmail,
|
||||
Access::getIdentity($this->user),
|
||||
];
|
||||
}
|
||||
}
|
74
src/Api/Jobs/EditUserEmailJob.php
Normal file
74
src/Api/Jobs/EditUserEmailJob.php
Normal file
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
class EditUserEmailJob extends AbstractUserJob
|
||||
{
|
||||
const NEW_EMAIL = 'new-email';
|
||||
|
||||
public function execute()
|
||||
{
|
||||
$user = $this->user;
|
||||
$newEmail = UserModel::validateEmail($this->getArgument(self::NEW_EMAIL));
|
||||
|
||||
$oldEmail = $user->emailConfirmed;
|
||||
if ($oldEmail == $newEmail)
|
||||
return $user;
|
||||
|
||||
if (Auth::getCurrentUser()->id == $user->id)
|
||||
{
|
||||
$user->emailUnconfirmed = $newEmail;
|
||||
$user->emailConfirmed = null;
|
||||
|
||||
if (!empty($newEmail))
|
||||
{
|
||||
$this->sendEmail($user);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$user->emailUnconfirmed = null;
|
||||
$user->emailConfirmed = $newEmail;
|
||||
}
|
||||
|
||||
UserModel::save($user);
|
||||
|
||||
LogHelper::log('{user} changed {subject}\'s e-mail to {mail}', [
|
||||
'user' => TextHelper::reprUser(Auth::getCurrentUser()),
|
||||
'subject' => TextHelper::reprUser($user),
|
||||
'mail' => $newEmail]);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function requiresPrivilege()
|
||||
{
|
||||
return
|
||||
[
|
||||
Privilege::ChangeUserAccessRank,
|
||||
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);
|
||||
}
|
||||
}
|
34
src/Api/Jobs/EditUserJob.php
Normal file
34
src/Api/Jobs/EditUserJob.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
class EditUserJob extends AbstractUserJob
|
||||
{
|
||||
public function execute()
|
||||
{
|
||||
$user = $this->user;
|
||||
|
||||
LogHelper::bufferChanges();
|
||||
|
||||
$subJobs =
|
||||
[
|
||||
new EditUserNameJob(),
|
||||
new EditUserPasswordJob(),
|
||||
new EditUserEmailJob(),
|
||||
new EditUserAccessRankJob(),
|
||||
];
|
||||
|
||||
foreach ($subJobs as $subJob)
|
||||
{
|
||||
$args = $this->getArguments();
|
||||
$args[self::USER_NAME] = $user->name;
|
||||
try
|
||||
{
|
||||
Api::run($subJob, $args);
|
||||
}
|
||||
catch (ApiMissingArgumentException $e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
LogHelper::flush();
|
||||
return $user;
|
||||
}
|
||||
}
|
35
src/Api/Jobs/EditUserNameJob.php
Normal file
35
src/Api/Jobs/EditUserNameJob.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
class EditUserNameJob extends AbstractUserJob
|
||||
{
|
||||
const NEW_USER_NAME = 'new-user-name';
|
||||
|
||||
public function execute()
|
||||
{
|
||||
$user = $this->user;
|
||||
$newName = UserModel::validateUserName($this->getArgument(self::NEW_USER_NAME));
|
||||
|
||||
$oldName = $user->name;
|
||||
if ($oldName == $newName)
|
||||
return $user;
|
||||
|
||||
$user->name = $newName;
|
||||
|
||||
UserModel::save($user);
|
||||
|
||||
LogHelper::log('{user} renamed {old} to {new}', [
|
||||
'user' => TextHelper::reprUser(Auth::getCurrentUser()),
|
||||
'old' => TextHelper::reprUser($oldName),
|
||||
'new' => TextHelper::reprUser($newName)]);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function requiresPrivilege()
|
||||
{
|
||||
return
|
||||
[
|
||||
Privilege::ChangeUserName,
|
||||
Access::getIdentity($this->user),
|
||||
];
|
||||
}
|
||||
}
|
35
src/Api/Jobs/EditUserPasswordJob.php
Normal file
35
src/Api/Jobs/EditUserPasswordJob.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
class EditUserPasswordJob extends AbstractUserJob
|
||||
{
|
||||
const NEW_PASSWORD = 'new-password';
|
||||
|
||||
public function execute()
|
||||
{
|
||||
$user = $this->user;
|
||||
$newPassword = UserModel::validatePassword($this->getArgument(self::NEW_PASSWORD));
|
||||
|
||||
$newPasswordHash = UserModel::hashPassword($newPassword, $user->passSalt);
|
||||
$oldPasswordHash = $user->passHash;
|
||||
if ($oldPasswordHash == $newPasswordHash)
|
||||
return $user;
|
||||
|
||||
$user->passHash = $newPasswordHash;
|
||||
|
||||
UserModel::save($user);
|
||||
|
||||
LogHelper::log('{user} changed {subject}\'s password', [
|
||||
'user' => TextHelper::reprUser(Auth::getCurrentUser()),
|
||||
'subject' => TextHelper::reprUser($user)]);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
public function requiresPrivilege()
|
||||
{
|
||||
return
|
||||
[
|
||||
Privilege::ChangeUserPassword,
|
||||
Access::getIdentity($this->user),
|
||||
];
|
||||
}
|
||||
}
|
|
@ -87,92 +87,26 @@ class UserController
|
|||
$this->genericView($name, 'edit');
|
||||
$this->requirePasswordConfirmation();
|
||||
|
||||
$user = getContext()->transport->user;
|
||||
if (InputHelper::get('password1') != InputHelper::get('password2'))
|
||||
throw new SimpleException('Specified passwords must be the same');
|
||||
|
||||
$suppliedCurrentPassword = InputHelper::get('current-password');
|
||||
$suppliedName = InputHelper::get('name');
|
||||
$suppliedPassword1 = InputHelper::get('password1');
|
||||
$suppliedPassword2 = InputHelper::get('password2');
|
||||
$suppliedEmail = InputHelper::get('email');
|
||||
$suppliedAccessRank = InputHelper::get('access-rank');
|
||||
$args =
|
||||
[
|
||||
EditUserNameJob::USER_NAME => $name,
|
||||
EditUserNameJob::NEW_USER_NAME => InputHelper::get('name'),
|
||||
EditUserPasswordJob::NEW_PASSWORD => InputHelper::get('password1'),
|
||||
EditUserEmailJob::NEW_EMAIL => InputHelper::get('email'),
|
||||
EditUserAccessRankJob::NEW_ACCESS_RANK => InputHelper::get('access-rank'),
|
||||
];
|
||||
|
||||
$confirmMail = false;
|
||||
LogHelper::bufferChanges();
|
||||
$args = array_filter($args);
|
||||
$user = Api::run(new EditUserJob(), $args);
|
||||
|
||||
if ($suppliedName != '' and $suppliedName != $user->name)
|
||||
{
|
||||
Access::assert(
|
||||
Privilege::ChangeUserName,
|
||||
Access::getIdentity($user));
|
||||
|
||||
$suppliedName = UserModel::validateUserName($suppliedName);
|
||||
$oldName = $user->name;
|
||||
$user->name = $suppliedName;
|
||||
LogHelper::log('{user} renamed {old} to {new}', [
|
||||
'old' => TextHelper::reprUser($oldName),
|
||||
'new' => TextHelper::reprUser($suppliedName)]);
|
||||
}
|
||||
|
||||
if ($suppliedPassword1 != '')
|
||||
{
|
||||
Access::assert(
|
||||
Privilege::ChangeUserPassword,
|
||||
Access::getIdentity($user));
|
||||
|
||||
if ($suppliedPassword1 != $suppliedPassword2)
|
||||
throw new SimpleException('Specified passwords must be the same');
|
||||
$suppliedPassword = UserModel::validatePassword($suppliedPassword1);
|
||||
$user->passHash = UserModel::hashPassword($suppliedPassword, $user->passSalt);
|
||||
LogHelper::log('{user} changed {subject}\'s password', ['subject' => TextHelper::reprUser($user)]);
|
||||
}
|
||||
|
||||
if ($suppliedEmail != '' and $suppliedEmail != $user->emailConfirmed)
|
||||
{
|
||||
Access::assert(
|
||||
Privilege::ChangeUserEmail,
|
||||
Access::getIdentity($user));
|
||||
|
||||
$suppliedEmail = UserModel::validateEmail($suppliedEmail);
|
||||
if (Auth::getCurrentUser()->id == $user->id)
|
||||
{
|
||||
$user->emailUnconfirmed = $suppliedEmail;
|
||||
if (!empty($user->emailUnconfirmed))
|
||||
$confirmMail = true;
|
||||
LogHelper::log('{user} changed e-mail to {mail}', ['mail' => $suppliedEmail]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$user->emailUnconfirmed = null;
|
||||
$user->emailConfirmed = $suppliedEmail;
|
||||
LogHelper::log('{user} changed {subject}\'s e-mail to {mail}', [
|
||||
'subject' => TextHelper::reprUser($user),
|
||||
'mail' => $suppliedEmail]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($suppliedAccessRank != '' and $suppliedAccessRank != $user->accessRank)
|
||||
{
|
||||
Access::assert(
|
||||
Privilege::ChangeUserAccessRank,
|
||||
Access::getIdentity($user));
|
||||
|
||||
$suppliedAccessRank = UserModel::validateAccessRank($suppliedAccessRank);
|
||||
$user->accessRank = $suppliedAccessRank;
|
||||
LogHelper::log('{user} changed {subject}\'s access rank to {rank}', [
|
||||
'subject' => TextHelper::reprUser($user),
|
||||
'rank' => AccessRank::toString($suppliedAccessRank)]);
|
||||
}
|
||||
|
||||
if ($confirmMail)
|
||||
self::sendEmailChangeConfirmation($user);
|
||||
|
||||
UserModel::save($user);
|
||||
if (Auth::getCurrentUser()->id == $user->id)
|
||||
Auth::setCurrentUser($user);
|
||||
|
||||
LogHelper::flush();
|
||||
$message = 'Account settings updated!';
|
||||
if ($confirmMail)
|
||||
if (Mailer::getMailCounter() > 0)
|
||||
$message .= ' You will be sent an e-mail address confirmation message soon.';
|
||||
|
||||
Messenger::message($message);
|
||||
|
@ -297,10 +231,10 @@ class UserController
|
|||
UserModel::save($dbUser);
|
||||
|
||||
if (!empty($dbUser->emailUnconfirmed))
|
||||
self::sendEmailChangeConfirmation($dbUser);
|
||||
EditUserEmailJob::sendEmail($dbUser);
|
||||
|
||||
$message = 'Congratulations, your account was created.';
|
||||
if (!empty($context->mailSent))
|
||||
if (Mailer::getMailCounter() > 0)
|
||||
{
|
||||
$message .= ' Please wait for activation e-mail.';
|
||||
if (getConfig()->registration->staffActivation)
|
||||
|
@ -410,97 +344,25 @@ class UserController
|
|||
else
|
||||
throw new SimpleException('This user has no e-mail specified; activation cannot proceed');
|
||||
}
|
||||
self::sendEmailChangeConfirmation($user);
|
||||
EditUserEmailJob::sendEmail($user);
|
||||
Messenger::message('Activation e-mail resent.');
|
||||
}
|
||||
|
||||
private static function sendTokenizedEmail(
|
||||
$user,
|
||||
$body,
|
||||
$subject,
|
||||
$senderName,
|
||||
$senderEmail,
|
||||
$recipientEmail,
|
||||
$linkActionName)
|
||||
{
|
||||
//prepare unique user token
|
||||
$token = TokenModel::spawn();
|
||||
$token->setUser($user);
|
||||
$token->token = TokenModel::forgeUnusedToken();
|
||||
$token->used = false;
|
||||
$token->expires = null;
|
||||
TokenModel::save($token);
|
||||
|
||||
getContext()->mailSent = true;
|
||||
$tokens = [];
|
||||
$tokens['host'] = $_SERVER['HTTP_HOST'];
|
||||
$tokens['token'] = $token->token; //gosh this code looks so silly
|
||||
$tokens['nl'] = PHP_EOL;
|
||||
if ($linkActionName !== null)
|
||||
$tokens['link'] = \Chibi\Router::linkTo(['UserController', $linkActionName], ['token' => $token->token]);
|
||||
|
||||
$body = wordwrap(TextHelper::replaceTokens($body, $tokens), 70);
|
||||
$subject = TextHelper::replaceTokens($subject, $tokens);
|
||||
$senderName = TextHelper::replaceTokens($senderName, $tokens);
|
||||
$senderEmail = TextHelper::replaceTokens($senderEmail, $tokens);
|
||||
|
||||
if (empty($recipientEmail))
|
||||
throw new SimpleException('Destination e-mail address was not found');
|
||||
|
||||
$messageId = $_SERVER['REQUEST_TIME'] . md5($_SERVER['REQUEST_TIME']) . '@' . $_SERVER['HTTP_HOST'];
|
||||
|
||||
$headers = [];
|
||||
$headers []= sprintf('MIME-Version: 1.0');
|
||||
$headers []= sprintf('Content-Transfer-Encoding: 7bit');
|
||||
$headers []= sprintf('Date: %s', date('r', $_SERVER['REQUEST_TIME']));
|
||||
$headers []= sprintf('Message-ID: <%s>', $messageId);
|
||||
$headers []= sprintf('From: %s <%s>', $senderName, $senderEmail);
|
||||
$headers []= sprintf('Reply-To: %s', $senderEmail);
|
||||
$headers []= sprintf('Return-Path: %s', $senderEmail);
|
||||
$headers []= sprintf('Subject: %s', $subject);
|
||||
$headers []= sprintf('Content-Type: text/plain; charset=utf-8', $subject);
|
||||
$headers []= sprintf('X-Mailer: PHP/%s', phpversion());
|
||||
$headers []= sprintf('X-Originating-IP: %s', $_SERVER['SERVER_ADDR']);
|
||||
$encodedSubject = '=?UTF-8?B?' . base64_encode($subject) . '?=';
|
||||
mail($recipientEmail, $encodedSubject, $body, implode("\r\n", $headers), '-f' . $senderEmail);
|
||||
|
||||
LogHelper::log('Sending e-mail with subject "{subject}" to {mail}', [
|
||||
'subject' => $subject,
|
||||
'mail' => $recipientEmail]);
|
||||
}
|
||||
|
||||
private static function sendEmailChangeConfirmation($user)
|
||||
{
|
||||
$regConfig = getConfig()->registration;
|
||||
if (!$regConfig->confirmationEmailEnabled)
|
||||
{
|
||||
$user->emailConfirmed = $user->emailUnconfirmed;
|
||||
$user->emailUnconfirmed = null;
|
||||
return;
|
||||
}
|
||||
|
||||
return self::sendTokenizedEmail(
|
||||
$user,
|
||||
$regConfig->confirmationEmailBody,
|
||||
$regConfig->confirmationEmailSubject,
|
||||
$regConfig->confirmationEmailSenderName,
|
||||
$regConfig->confirmationEmailSenderEmail,
|
||||
$user->emailUnconfirmed,
|
||||
'activationAction');
|
||||
}
|
||||
|
||||
private static function sendPasswordResetConfirmation($user)
|
||||
{
|
||||
$regConfig = getConfig()->registration;
|
||||
|
||||
return self::sendTokenizedEmail(
|
||||
$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,
|
||||
$regConfig->passwordResetEmailBody,
|
||||
$regConfig->passwordResetEmailSubject,
|
||||
$regConfig->passwordResetEmailSenderName,
|
||||
$regConfig->passwordResetEmailSenderEmail,
|
||||
$user->emailConfirmed,
|
||||
'passwordResetAction');
|
||||
['UserController', 'passwordResetAction'],
|
||||
$mail);
|
||||
}
|
||||
|
||||
private function requirePasswordConfirmation()
|
||||
|
|
9
src/Mail.php
Normal file
9
src/Mail.php
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
class Mail
|
||||
{
|
||||
public $body;
|
||||
public $subject;
|
||||
public $senderName;
|
||||
public $senderEmail;
|
||||
public $recipientEmail;
|
||||
}
|
70
src/Mailer.php
Normal file
70
src/Mailer.php
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
class Mailer
|
||||
{
|
||||
private static $mailCounter = 0;
|
||||
|
||||
public static function getMailCounter()
|
||||
{
|
||||
return self::$mailCounter;
|
||||
}
|
||||
|
||||
public static function sendMail(Mail $mail, array $tokens = [])
|
||||
{
|
||||
if (!isset($tokens['host']))
|
||||
$tokens['host'] = $_SERVER['HTTP_HOST'];
|
||||
|
||||
if (!isset($tokens['nl']))
|
||||
$tokens['nl'] = PHP_EOL;
|
||||
|
||||
$body = wordwrap(TextHelper::replaceTokens($mail->body, $tokens), 70);
|
||||
$subject = TextHelper::replaceTokens($mail->subject, $tokens);
|
||||
$senderName = TextHelper::replaceTokens($mail->senderName, $tokens);
|
||||
$senderEmail = TextHelper::replaceTokens($mail->senderEmail, $tokens);
|
||||
$recipientEmail = $mail->recipientEmail;
|
||||
|
||||
if (empty($recipientEmail))
|
||||
throw new SimpleException('Destination e-mail address was not found');
|
||||
|
||||
$messageId = $_SERVER['REQUEST_TIME'] . md5($_SERVER['REQUEST_TIME']) . '@' . $_SERVER['HTTP_HOST'];
|
||||
|
||||
$headers = [];
|
||||
$headers []= sprintf('MIME-Version: 1.0');
|
||||
$headers []= sprintf('Content-Transfer-Encoding: 7bit');
|
||||
$headers []= sprintf('Date: %s', date('r', $_SERVER['REQUEST_TIME']));
|
||||
$headers []= sprintf('Message-ID: <%s>', $messageId);
|
||||
$headers []= sprintf('From: %s <%s>', $senderName, $senderEmail);
|
||||
$headers []= sprintf('Reply-To: %s', $senderEmail);
|
||||
$headers []= sprintf('Return-Path: %s', $senderEmail);
|
||||
$headers []= sprintf('Subject: %s', $subject);
|
||||
$headers []= sprintf('Content-Type: text/plain; charset=utf-8', $subject);
|
||||
$headers []= sprintf('X-Mailer: PHP/%s', phpversion());
|
||||
$headers []= sprintf('X-Originating-IP: %s', $_SERVER['SERVER_ADDR']);
|
||||
$encodedSubject = '=?UTF-8?B?' . base64_encode($subject) . '?=';
|
||||
mail($recipientEmail, $encodedSubject, $body, implode("\r\n", $headers), '-f' . $senderEmail);
|
||||
|
||||
self::$mailCounter ++;
|
||||
|
||||
LogHelper::log('Sending e-mail with subject "{subject}" to {mail}', [
|
||||
'subject' => $subject,
|
||||
'mail' => $recipientEmail]);
|
||||
}
|
||||
|
||||
public static function sendMailWithTokenLink(
|
||||
UserEntity $user,
|
||||
$linkDestination,
|
||||
Mail $mail,
|
||||
array $tokens = [])
|
||||
{
|
||||
//prepare unique user token
|
||||
$token = TokenModel::spawn();
|
||||
$token->setUser($user);
|
||||
$token->token = TokenModel::forgeUnusedToken();
|
||||
$token->used = false;
|
||||
$token->expires = null;
|
||||
TokenModel::save($token);
|
||||
|
||||
$tokens['link'] = \Chibi\Router::linkTo($linkDestination, ['token' => $token->token]);
|
||||
|
||||
return self::sendMail($mail, $tokens);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue