Closed #32
This commit is contained in:
parent
52956b56c8
commit
39db2a64e1
14 changed files with 188 additions and 172 deletions
|
@ -19,14 +19,16 @@ endlessScrolling=1
|
|||
maxSearchTokens=4
|
||||
|
||||
[registration]
|
||||
emailActivation = 0
|
||||
staffActivation = 0
|
||||
staffActivation = 1
|
||||
passMinLength = 5
|
||||
passRegex = "/^.+$/"
|
||||
userNameMinLength = 3
|
||||
userNameRegex = "/^[\w_-]+$/ui"
|
||||
salt = "1A2/$_4xVa"
|
||||
|
||||
needEmailForRegistering = 1
|
||||
needEmailForCommenting = 0
|
||||
needEmailForUploading = 1
|
||||
activationEmailSenderName = "{host} registration engine"
|
||||
activationEmailSenderEmail = "noreply@{host}"
|
||||
activationEmailSubject = "{host} activation"
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
img {
|
||||
.user img {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
float: left;
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
h1 {
|
||||
.user h1 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ function scrolled()
|
|||
var dom = $(response);
|
||||
var nextPage = dom.find('.paginator .next:not(.disabled) a').attr('href');
|
||||
$(document).data('page-next', nextPage);
|
||||
$('.paginator-content').append($(response).find('.paginator-content').children().fadeIn('slow'));
|
||||
$('.paginator-content').append($(response).find('.paginator-content').children().css({opacity: 0}).animate({opacity: 1}, 'slow'));
|
||||
scrolled();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -35,8 +35,8 @@ class AuthController
|
|||
if ($dbUser->banned)
|
||||
throw new SimpleException('You are banned');
|
||||
|
||||
if (!$dbUser->email_confirmed and $this->config->registration->emailActivation)
|
||||
throw new SimpleException('You haven\'t confirmed your e-mail address yet');
|
||||
if ($this->config->registration->needEmailForRegistering)
|
||||
PrivilegesHelper::confirmEmail($dbUser);
|
||||
|
||||
$_SESSION['user-id'] = $dbUser->id;
|
||||
\Chibi\UrlHelper::forward(\Chibi\UrlHelper::route('index', 'index'));
|
||||
|
@ -54,144 +54,4 @@ class AuthController
|
|||
unset($_SESSION['user-id']);
|
||||
\Chibi\UrlHelper::forward(\Chibi\UrlHelper::route('index', 'index'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @route /register
|
||||
*/
|
||||
public function registerAction()
|
||||
{
|
||||
$this->context->handleExceptions = true;
|
||||
$this->context->stylesheets []= 'auth.css';
|
||||
$this->context->subTitle = 'registration form';
|
||||
|
||||
//check if already logged in
|
||||
if ($this->context->loggedIn)
|
||||
{
|
||||
\Chibi\UrlHelper::forward(\Chibi\UrlHelper::route('index', 'index'));
|
||||
return;
|
||||
}
|
||||
|
||||
$suppliedName = InputHelper::get('name');
|
||||
$suppliedPassword1 = InputHelper::get('password1');
|
||||
$suppliedPassword2 = InputHelper::get('password2');
|
||||
$suppliedEmail = InputHelper::get('email');
|
||||
$this->context->suppliedName = $suppliedName;
|
||||
$this->context->suppliedPassword1 = $suppliedPassword1;
|
||||
$this->context->suppliedPassword2 = $suppliedPassword2;
|
||||
$this->context->suppliedEmail = $suppliedEmail;
|
||||
|
||||
$regConfig = $this->config->registration;
|
||||
$emailActivation = $regConfig->emailActivation;
|
||||
$staffActivation = $regConfig->staffActivation;
|
||||
|
||||
$this->context->transport->staffActivation = $staffActivation;
|
||||
$this->context->transport->emailActivation = $emailActivation;
|
||||
|
||||
if ($suppliedName !== null)
|
||||
{
|
||||
$suppliedName = Model_User::validateUserName($suppliedName);
|
||||
|
||||
if ($suppliedPassword1 != $suppliedPassword2)
|
||||
throw new SimpleException('Specified passwords must be the same');
|
||||
$suppliedPassword = Model_User::validatePassword($suppliedPassword1);
|
||||
|
||||
$suppliedEmail = Model_User::validateEmail($suppliedEmail);
|
||||
if (empty($suppliedEmail) and $emailActivation)
|
||||
throw new SimpleException('E-mail address is required - you will be sent confirmation e-mail.');
|
||||
|
||||
//register the user
|
||||
$dbUser = R::dispense('user');
|
||||
$dbUser->name = $suppliedName;
|
||||
$dbUser->pass_salt = md5(mt_rand() . uniqid());
|
||||
$dbUser->pass_hash = Model_User::hashPassword($suppliedPassword, $dbUser->pass_salt);
|
||||
$dbUser->email = $suppliedEmail;
|
||||
$dbUser->join_date = time();
|
||||
if (R::findOne('user') === null)
|
||||
{
|
||||
$dbUser->staff_confirmed = true;
|
||||
$dbUser->email_confirmed = true;
|
||||
$dbUser->access_rank = AccessRank::Admin;
|
||||
}
|
||||
else
|
||||
{
|
||||
$dbUser->staff_confirmed = false;
|
||||
$dbUser->email_confirmed = false;
|
||||
$dbUser->access_rank = AccessRank::Registered;
|
||||
}
|
||||
|
||||
//prepare unique registration token
|
||||
do
|
||||
{
|
||||
$emailToken = md5(mt_rand() . uniqid());
|
||||
}
|
||||
while (R::findOne('user', 'email_token = ?', [$emailToken]) !== null);
|
||||
$dbUser->email_token = $emailToken;
|
||||
|
||||
//send the e-mail
|
||||
if ($emailActivation)
|
||||
{
|
||||
$tokens = [];
|
||||
$tokens['host'] = $_SERVER['HTTP_HOST'];
|
||||
$tokens['link'] = \Chibi\UrlHelper::route('auth', 'activation', ['token' => $dbUser->email_token]);
|
||||
|
||||
$body = wordwrap(TextHelper::replaceTokens($regConfig->activationEmailBody, $tokens), 70);
|
||||
$subject = TextHelper::replaceTokens($regConfig->activationEmailSubject, $tokens);
|
||||
$senderName = TextHelper::replaceTokens($regConfig->activationEmailSenderName, $tokens);
|
||||
$senderEmail = $regConfig->activationEmailSenderEmail;
|
||||
|
||||
$headers = [];
|
||||
$headers[] = sprintf('From: %s <%s>', $senderName, $senderEmail);
|
||||
$headers[] = sprintf('Subject: %s', $subject);
|
||||
$headers[] = sprintf('X-Mailer: PHP/%s', phpversion());
|
||||
mail($dbUser->email, $subject, $body, implode("\r\n", $headers));
|
||||
}
|
||||
|
||||
//save the user to db if everything went okay
|
||||
R::store($dbUser);
|
||||
$this->context->transport->success = true;
|
||||
|
||||
if (!$emailActivation and !$staffActivation)
|
||||
{
|
||||
$_SESSION['user-id'] = $dbUser->id;
|
||||
\Chibi\Registry::getBootstrap()->attachUser();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @route /activation/{token}
|
||||
*/
|
||||
public function activationAction($token)
|
||||
{
|
||||
$this->context->subTitle = 'account activation';
|
||||
|
||||
//check if already logged in
|
||||
if ($this->context->loggedIn)
|
||||
{
|
||||
\Chibi\UrlHelper::forward(\Chibi\UrlHelper::route('index', 'index'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($token))
|
||||
throw new SimpleException('Invalid activation token');
|
||||
|
||||
$dbUser = R::findOne('user', 'email_token = ?', [$token]);
|
||||
if ($dbUser === null)
|
||||
throw new SimpleException('No user with such activation token');
|
||||
|
||||
if ($dbUser->email_confirmed)
|
||||
throw new SimpleException('This user was already activated');
|
||||
|
||||
$dbUser->email_confirmed = true;
|
||||
R::store($dbUser);
|
||||
$this->context->transport->success = true;
|
||||
|
||||
$staffActivation = $this->config->registration->staffActivation;
|
||||
$this->context->transport->staffActivation = $staffActivation;
|
||||
if (!$staffActivation)
|
||||
{
|
||||
$_SESSION['user-id'] = $dbUser->id;
|
||||
\Chibi\Registry::getBootstrap()->attachUser();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -175,6 +175,8 @@ class PostController
|
|||
$this->context->scripts []= 'upload.js';
|
||||
$this->context->subTitle = 'upload';
|
||||
PrivilegesHelper::confirmWithException($this->context->user, Privilege::UploadPost);
|
||||
if ($this->config->registration->needEmailForUploading)
|
||||
PrivilegesHelper::confirmEmail($this->context->user);
|
||||
|
||||
if (!empty($_FILES['file']['name']))
|
||||
{
|
||||
|
|
|
@ -9,6 +9,27 @@ class UserController
|
|||
return $user;
|
||||
}
|
||||
|
||||
private static function sendEmailConfirmation($user)
|
||||
{
|
||||
\Chibi\Registry::getContext()->mailSent = true;
|
||||
$regConfig = \Chibi\Registry::getConfig()->registration;
|
||||
$tokens = [];
|
||||
$tokens['host'] = $_SERVER['HTTP_HOST'];
|
||||
$tokens['link'] = \Chibi\UrlHelper::route('user', 'activation', ['token' => $user->email_token]);
|
||||
|
||||
$body = wordwrap(TextHelper::replaceTokens($regConfig->activationEmailBody, $tokens), 70);
|
||||
$subject = TextHelper::replaceTokens($regConfig->activationEmailSubject, $tokens);
|
||||
$senderName = TextHelper::replaceTokens($regConfig->activationEmailSenderName, $tokens);
|
||||
$senderEmail = $regConfig->activationEmailSenderEmail;
|
||||
$recipientEmail = $user->email_unconfirmed;
|
||||
|
||||
$headers = [];
|
||||
$headers[] = sprintf('From: %s <%s>', $senderName, $senderEmail);
|
||||
$headers[] = sprintf('Subject: %s', $subject);
|
||||
$headers[] = sprintf('X-Mailer: PHP/%s', phpversion());
|
||||
mail($recipientEmail, $subject, $body, implode("\r\n", $headers));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
@ -55,7 +76,8 @@ class UserController
|
|||
$dbQuery->orderBy('join_date')->desc();
|
||||
break;
|
||||
case 'pending':
|
||||
$dbQuery->whereNot('staff_confirmed')->and($this->config->registration->staffActivation);
|
||||
$dbQuery->where('staff_confirmed IS NULL');
|
||||
$dbQuery->or('staff_confirmed = 0');
|
||||
break;
|
||||
default:
|
||||
throw new SimpleException('Unknown sort style');
|
||||
|
@ -218,11 +240,20 @@ class UserController
|
|||
$edited = true;
|
||||
}
|
||||
|
||||
if ($suppliedEmail != '' and $suppliedEmail != $user->email)
|
||||
if ($suppliedEmail != '' and $suppliedEmail != $user->email_confirmed)
|
||||
{
|
||||
PrivilegesHelper::confirmWithException($this->context->user, Privilege::ChangeUserEmail, $secondary);
|
||||
$suppliedEmail = Model_User::validateEmail($suppliedEmail);
|
||||
$user->email = $suppliedEmail;
|
||||
if ($this->context->user->id == $user->id)
|
||||
{
|
||||
$user->email_unconfirmed = $suppliedEmail;
|
||||
if (!empty($user->email_unconfirmed))
|
||||
self::sendEmailConfirmation($user);
|
||||
}
|
||||
else
|
||||
{
|
||||
$user->email_confirmed = $suppliedEmail;
|
||||
}
|
||||
$edited = true;
|
||||
}
|
||||
|
||||
|
@ -370,4 +401,117 @@ class UserController
|
|||
|
||||
$this->context->transport->success = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @route /register
|
||||
*/
|
||||
public function registrationAction()
|
||||
{
|
||||
$this->context->handleExceptions = true;
|
||||
$this->context->stylesheets []= 'auth.css';
|
||||
$this->context->subTitle = 'registration form';
|
||||
|
||||
//check if already logged in
|
||||
if ($this->context->loggedIn)
|
||||
{
|
||||
\Chibi\UrlHelper::forward(\Chibi\UrlHelper::route('index', 'index'));
|
||||
return;
|
||||
}
|
||||
|
||||
$suppliedName = InputHelper::get('name');
|
||||
$suppliedPassword1 = InputHelper::get('password1');
|
||||
$suppliedPassword2 = InputHelper::get('password2');
|
||||
$suppliedEmail = InputHelper::get('email');
|
||||
$this->context->suppliedName = $suppliedName;
|
||||
$this->context->suppliedPassword1 = $suppliedPassword1;
|
||||
$this->context->suppliedPassword2 = $suppliedPassword2;
|
||||
$this->context->suppliedEmail = $suppliedEmail;
|
||||
|
||||
if ($suppliedName !== null)
|
||||
{
|
||||
$suppliedName = Model_User::validateUserName($suppliedName);
|
||||
|
||||
if ($suppliedPassword1 != $suppliedPassword2)
|
||||
throw new SimpleException('Specified passwords must be the same');
|
||||
$suppliedPassword = Model_User::validatePassword($suppliedPassword1);
|
||||
|
||||
$suppliedEmail = Model_User::validateEmail($suppliedEmail);
|
||||
if (empty($suppliedEmail) and $this->config->registration->needEmailForRegistering)
|
||||
throw new SimpleException('E-mail address is required - you will be sent confirmation e-mail.');
|
||||
|
||||
//register the user
|
||||
$dbUser = R::dispense('user');
|
||||
$dbUser->name = $suppliedName;
|
||||
$dbUser->pass_salt = md5(mt_rand() . uniqid());
|
||||
$dbUser->pass_hash = Model_User::hashPassword($suppliedPassword, $dbUser->pass_salt);
|
||||
$dbUser->email_unconfirmed = $suppliedEmail;
|
||||
|
||||
//prepare unique registration token
|
||||
do
|
||||
{
|
||||
$emailToken = md5(mt_rand() . uniqid());
|
||||
}
|
||||
while (R::findOne('user', 'email_token = ?', [$emailToken]) !== null);
|
||||
$dbUser->email_token = $emailToken;
|
||||
|
||||
$dbUser->join_date = time();
|
||||
if (R::findOne('user') === null)
|
||||
{
|
||||
$dbUser->access_rank = AccessRank::Admin;
|
||||
$dbUser->staff_confirmed = true;
|
||||
$dbUser->email_confirmed = $suppliedEmail;
|
||||
}
|
||||
else
|
||||
{
|
||||
$dbUser->access_rank = AccessRank::Registered;
|
||||
$dbUser->staff_confirmed = false;
|
||||
$dbUser->staff_confirmed = null;
|
||||
if (!empty($dbUser->email_unconfirmed))
|
||||
self::sendEmailConfirmation($dbUser);
|
||||
}
|
||||
|
||||
//save the user to db if everything went okay
|
||||
R::store($dbUser);
|
||||
$this->context->transport->success = true;
|
||||
|
||||
if (!$this->config->registration->needEmailForRegistering and !$this->config->registration->staffActivation)
|
||||
{
|
||||
$_SESSION['user-id'] = $dbUser->id;
|
||||
\Chibi\Registry::getBootstrap()->attachUser();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @route /activation/{token}
|
||||
*/
|
||||
public function activationAction($token)
|
||||
{
|
||||
$this->context->subTitle = 'account activation';
|
||||
|
||||
if (empty($token))
|
||||
throw new SimpleException('Invalid activation token');
|
||||
|
||||
$dbUser = R::findOne('user', 'email_token = ?', [$token]);
|
||||
if ($dbUser === null)
|
||||
throw new SimpleException('No user with such activation token');
|
||||
|
||||
if (!$dbUser->email_unconfirmed)
|
||||
throw new SimpleException('This user was already activated');
|
||||
|
||||
$dbUser->email_confirmed = $dbUser->email_unconfirmed;
|
||||
$dbUser->email_unconfirmed = null;
|
||||
R::store($dbUser);
|
||||
$this->context->transport->success = true;
|
||||
|
||||
if (!$this->config->registration->staffActivation)
|
||||
{
|
||||
$_SESSION['user-id'] = $dbUser->id;
|
||||
\Chibi\Registry::getBootstrap()->attachUser();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,12 @@ class PrivilegesHelper
|
|||
throw new SimpleException('Insufficient privileges');
|
||||
}
|
||||
}
|
||||
|
||||
public static function confirmEmail($user)
|
||||
{
|
||||
if (!$user->email_confirmed)
|
||||
throw new SimpleException('Need e-mail address confirmation to continue');
|
||||
}
|
||||
}
|
||||
|
||||
PrivilegesHelper::init();
|
||||
|
|
|
@ -3,8 +3,8 @@ class Model_User extends RedBean_SimpleModel
|
|||
{
|
||||
public function getAvatarUrl($size = 32)
|
||||
{
|
||||
$subject = !empty($this->email)
|
||||
? $this->email
|
||||
$subject = !empty($this->email_confirmed)
|
||||
? $this->email_confirmed
|
||||
: $this->pass_salt . $this->name;
|
||||
$hash = md5(strtolower(trim($subject)));
|
||||
$url = 'http://www.gravatar.com/avatar/' . $hash . '?s=' . $size . '&d=retro';
|
||||
|
@ -59,7 +59,7 @@ class Model_User extends RedBean_SimpleModel
|
|||
$dbUser = R::findOne('user', 'name = ?', [$userName]);
|
||||
if ($dbUser !== null)
|
||||
{
|
||||
if (!$dbUser->email_confirmed and \Chibi\Registry::getConfig()->registration->emailActivation)
|
||||
if (!$dbUser->email_confirmed and \Chibi\Registry::getConfig()->registration->needEmailForRegistering)
|
||||
throw new SimpleException('User with this name is already registered and awaits e-mail confirmation');
|
||||
|
||||
if (!$dbUser->staff_confirmed and \Chibi\Registry::getConfig()->registration->staffActivation)
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
<?php if ($this->context->transport->success === true): ?>
|
||||
<p>Activation completed successfully.</p>
|
||||
<?php if ($this->context->transport->staffActivation): ?>
|
||||
<p>However, your account still must be confirmed by staff.</p>
|
||||
<?php endif ?>
|
||||
<?php endif ?>
|
|
@ -1,7 +1,7 @@
|
|||
<form action="<?php echo \Chibi\UrlHelper::route('auth', 'login') ?>" class="auth aligned" method="post">
|
||||
|
||||
<div>
|
||||
<p>If you don't have an account yet,<br/><a href="<?php echo \Chibi\UrlHelper::route('auth', 'register'); ?>">click here</a> to create a new one.</p>
|
||||
<p>If you don't have an account yet,<br/><a href="<?php echo \Chibi\UrlHelper::route('user', 'registration'); ?>">click here</a> to create a new one.</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
if (!$this->context->loggedIn)
|
||||
{
|
||||
$nav []= ['Log in', \Chibi\UrlHelper::route('auth', 'login')];
|
||||
$nav []= ['Register', \Chibi\UrlHelper::route('auth', 'register')];
|
||||
$nav []= ['Register', \Chibi\UrlHelper::route('user', 'registration')];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
6
src/Views/user-activation.phtml
Normal file
6
src/Views/user-activation.phtml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?php if ($this->context->transport->success === true): ?>
|
||||
<p class="alert alert-success">Activation completed successfully.
|
||||
<?php if ($this->config->registration->staffActivation): ?>
|
||||
<br>However, your account still must be confirmed by staff.
|
||||
<?php endif ?></p>
|
||||
<?php endif ?>
|
|
@ -1,13 +1,13 @@
|
|||
<?php if ($this->context->transport->success === true): ?>
|
||||
<p>Congratulations, your account was created.</p>
|
||||
<?php if ($this->context->transport->emailActivation): ?>
|
||||
<p>Please wait for activation e-mail.</p>
|
||||
<?php if ($this->context->transport->staffActivation): ?>
|
||||
<p>After this, your registration must be confirmed by staff.</p>
|
||||
<p class="alert alert-success">Congratulations, your account was created.
|
||||
<?php if (!empty($this->context->mailSent)): ?>
|
||||
<br>Please wait for activation e-mail.
|
||||
<?php if ($this->config->registration->staffActivation): ?>
|
||||
<br>After this, your registration must be confirmed by staff.
|
||||
<?php endif ?>
|
||||
<?php elseif ($this->context->transport->staffActivation): ?>
|
||||
<p>Your registration must be confirmed by staff.</p>
|
||||
<?php endif ?>
|
||||
<?php elseif ($this->config->registration->staffActivation): ?>
|
||||
<br>Your registration must be now confirmed by staff.
|
||||
<?php endif ?></p>
|
||||
<?php else: ?>
|
||||
<form action="<?php echo \Chibi\UrlHelper::route('auth', 'register') ?>" class="auth aligned" method="post">
|
||||
<div>
|
||||
|
@ -30,7 +30,7 @@
|
|||
</div>
|
||||
|
||||
<div>
|
||||
<label class="left" for="email">E-mail address<?php if ($this->context->transport->emailActivation) echo ' (required)' ?>:</label>
|
||||
<label class="left" for="email">E-mail address:</label>
|
||||
<input id="email" name="email" value="<?php echo $this->context->suppliedEmail ?>" placeholder="e.g. vader@empire.gov" autocomplete="off"/>
|
||||
</div>
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
<?php if ($this->context->user->id == $this->context->transport->user->id): ?>
|
||||
<div class="key-value email">
|
||||
<span class="key">E-mail:</span>
|
||||
<span class="value" title="<?php echo $val = ($this->context->transport->user->email ?: 'none specified') ?>"><?php echo $val ?></span>
|
||||
<span class="value" title="<?php echo $val = ($this->context->transport->user->email_unconfirmed ? '(unconfirmed) ' . $this->context->transport->user->email_unconfirmed : $this->context->transport->user->email_confirmed ?: 'none specified') ?>"><?php echo $val ?></span>
|
||||
<br>(only you can see this)
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
@ -199,7 +199,7 @@
|
|||
<?php endif ?>
|
||||
|
||||
<?php if ($this->context->transport->success === true): ?>
|
||||
<p class="alert alert-success">Account settings updated!</p>
|
||||
<p class="alert alert-success">Account settings updated! <?php if (!empty($this->context->mailSent)) echo 'You will be sent new e-mail address confirmation message soon.' ?></p>
|
||||
<?php elseif (isset($this->context->transport->errorMessage)): ?>
|
||||
<p class="alert alert-error">Error: <?php echo $this->context->transport->errorMessage ?></p>
|
||||
<?php endif ?>
|
||||
|
|
Loading…
Reference in a new issue