This commit is contained in:
Marcin Kurczewski 2013-10-16 18:07:23 +02:00
parent 52956b56c8
commit 39db2a64e1
14 changed files with 188 additions and 172 deletions

View file

@ -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"

View file

@ -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;
}

View file

@ -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();
});
}

View file

@ -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();
}
}
}

View file

@ -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']))
{

View file

@ -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();
}
}
}

View file

@ -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();

View file

@ -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)

View file

@ -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 ?>

View file

@ -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>

View file

@ -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
{

View 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 ?>

View file

@ -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>

View file

@ -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 ?>