diff --git a/config.ini b/config.ini index 1c5ba094..2ce57da2 100644 --- a/config.ini +++ b/config.ini @@ -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" diff --git a/public_html/media/css/user-list.css b/public_html/media/css/user-list.css index 832587aa..25158075 100644 --- a/public_html/media/css/user-list.css +++ b/public_html/media/css/user-list.css @@ -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; } diff --git a/public_html/media/js/paginator-endless.js b/public_html/media/js/paginator-endless.js index 8f698e8d..aaef4317 100644 --- a/public_html/media/js/paginator-endless.js +++ b/public_html/media/js/paginator-endless.js @@ -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(); }); } diff --git a/src/Controllers/AuthController.php b/src/Controllers/AuthController.php index c2199e6d..fa4fa275 100644 --- a/src/Controllers/AuthController.php +++ b/src/Controllers/AuthController.php @@ -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(); - } - } } diff --git a/src/Controllers/PostController.php b/src/Controllers/PostController.php index c98ceb67..96efeb80 100644 --- a/src/Controllers/PostController.php +++ b/src/Controllers/PostController.php @@ -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'])) { diff --git a/src/Controllers/UserController.php b/src/Controllers/UserController.php index 09972eb4..5a5a64ba 100644 --- a/src/Controllers/UserController.php +++ b/src/Controllers/UserController.php @@ -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(); + } + } } diff --git a/src/Helpers/PrivilegesHelper.php b/src/Helpers/PrivilegesHelper.php index 74bac2bc..c80e1174 100644 --- a/src/Helpers/PrivilegesHelper.php +++ b/src/Helpers/PrivilegesHelper.php @@ -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(); diff --git a/src/Models/Model_User.php b/src/Models/Model_User.php index 50d94518..3f57e86a 100644 --- a/src/Models/Model_User.php +++ b/src/Models/Model_User.php @@ -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) diff --git a/src/Views/auth-activation.phtml b/src/Views/auth-activation.phtml deleted file mode 100644 index bfc8b2ea..00000000 --- a/src/Views/auth-activation.phtml +++ /dev/null @@ -1,6 +0,0 @@ -context->transport->success === true): ?> -
Activation completed successfully.
- context->transport->staffActivation): ?> -However, your account still must be confirmed by staff.
- - diff --git a/src/Views/auth-login.phtml b/src/Views/auth-login.phtml index 06b8f948..3cb44bcc 100644 --- a/src/Views/auth-login.phtml +++ b/src/Views/auth-login.phtml @@ -1,7 +1,7 @@