MAPG-69 implement sign up functionality
This commit is contained in:
parent
a69ba3a99b
commit
20102f0577
13
mail/signup.tpl
Normal file
13
mail/signup.tpl
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
Hi,
|
||||||
|
|
||||||
|
You recently signed up on MapGuesser with this email address ({{EMAIL}}). To activate your account, please click on the following link:
|
||||||
|
<a href="{{ACTIVATE_LINK}}" title="Account activation">{{ACTIVATE_LINK}}</a>
|
||||||
|
|
||||||
|
If you did not sign up on MapGuesser or changed your mind, no further action is required, your email address will be deleted soon.
|
||||||
|
However if you want to immediately delete it, please click on the following link:
|
||||||
|
<a href="{{CANCEL_LINK}}" title="Sign up cancellation">{{CANCEL_LINK}}</a>
|
||||||
|
|
||||||
|
Have fun on MapGuesser!
|
||||||
|
|
||||||
|
Regards,
|
||||||
|
MapGuesser
|
47
public/static/js/signup.js
Normal file
47
public/static/js/signup.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
(function () {
|
||||||
|
var form = document.getElementById('signupForm');
|
||||||
|
|
||||||
|
form.onsubmit = function (e) {
|
||||||
|
document.getElementById('loading').style.visibility = 'visible';
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var formData = new FormData(form);
|
||||||
|
|
||||||
|
MapGuesser.httpRequest('POST', form.action, function () {
|
||||||
|
document.getElementById('loading').style.visibility = 'hidden';
|
||||||
|
|
||||||
|
if (this.response.error) {
|
||||||
|
var errorText;
|
||||||
|
switch (this.response.error) {
|
||||||
|
case 'passwords_too_short':
|
||||||
|
errorText = 'The given password is too short. Please choose a password that is at least 6 characters long!'
|
||||||
|
break;
|
||||||
|
case 'passwords_not_match':
|
||||||
|
errorText = 'The given passwords do not match.'
|
||||||
|
break;
|
||||||
|
case 'user_found':
|
||||||
|
errorText = 'There is a user already registered with the given email address. Please <a href="/login" title="Login">login here</a>!';
|
||||||
|
break;
|
||||||
|
case 'not_active_user_found':
|
||||||
|
errorText = 'There is a user already registered with the given email address. Please check your email and click on the activation link!';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var signupFormError = document.getElementById('signupFormError');
|
||||||
|
signupFormError.style.display = 'block';
|
||||||
|
signupFormError.innerHTML = errorText;
|
||||||
|
|
||||||
|
form.elements.email.select();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('signupFormError').style.display = 'none';
|
||||||
|
form.reset();
|
||||||
|
form.elements.email.focus();
|
||||||
|
|
||||||
|
MapGuesser.showModalWithContent('Sign up successful', 'Sign up was successful. Please check your email and click on the activation link to activate your account!');
|
||||||
|
}, formData);
|
||||||
|
};
|
||||||
|
})();
|
192
src/Controller/SignupController.php
Normal file
192
src/Controller/SignupController.php
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
<?php namespace MapGuesser\Controller;
|
||||||
|
|
||||||
|
use MapGuesser\Database\Query\Modify;
|
||||||
|
use MapGuesser\Database\Query\Select;
|
||||||
|
use MapGuesser\Interfaces\Database\IResultSet;
|
||||||
|
use MapGuesser\Interfaces\Request\IRequest;
|
||||||
|
use MapGuesser\Interfaces\Response\IContent;
|
||||||
|
use MapGuesser\Interfaces\Response\IRedirect;
|
||||||
|
use MapGuesser\Mailing\Mail;
|
||||||
|
use MapGuesser\Model\User;
|
||||||
|
use MapGuesser\Response\HtmlContent;
|
||||||
|
use MapGuesser\Response\JsonContent;
|
||||||
|
use MapGuesser\Response\Redirect;
|
||||||
|
|
||||||
|
class SignupController
|
||||||
|
{
|
||||||
|
private IRequest $request;
|
||||||
|
|
||||||
|
public function __construct(IRequest $request)
|
||||||
|
{
|
||||||
|
$this->request = $request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSignupForm()
|
||||||
|
{
|
||||||
|
$session = $this->request->session();
|
||||||
|
|
||||||
|
if ($session->get('user')) {
|
||||||
|
return new Redirect([\Container::$routeCollection->getRoute('index'), []], IRedirect::TEMPORARY);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
return new HtmlContent('signup/signup', $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function signup(): IContent
|
||||||
|
{
|
||||||
|
$session = $this->request->session();
|
||||||
|
|
||||||
|
if ($session->get('user')) {
|
||||||
|
//TODO: return with some error
|
||||||
|
$data = ['success' => true];
|
||||||
|
return new JsonContent($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
$select = new Select(\Container::$dbConnection, 'users');
|
||||||
|
$select->columns(User::getFields());
|
||||||
|
$select->where('email', '=', $this->request->post('email'));
|
||||||
|
|
||||||
|
$userData = $select->execute()->fetch(IResultSet::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if ($userData !== null) {
|
||||||
|
$user = new User($userData);
|
||||||
|
|
||||||
|
if ($user->getActive()) {
|
||||||
|
$data = ['error' => 'user_found'];
|
||||||
|
} else {
|
||||||
|
$data = ['error' => 'not_active_user_found'];
|
||||||
|
}
|
||||||
|
return new JsonContent($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen($this->request->post('password')) < 6) {
|
||||||
|
$data = ['error' => 'passwords_too_short'];
|
||||||
|
return new JsonContent($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->request->post('password') !== $this->request->post('password_confirm')) {
|
||||||
|
$data = ['error' => 'passwords_not_match'];
|
||||||
|
return new JsonContent($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = new User([
|
||||||
|
'email' => $this->request->post('email'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user->setPlainPassword($this->request->post('password'));
|
||||||
|
|
||||||
|
\Container::$dbConnection->startTransaction();
|
||||||
|
|
||||||
|
$modify = new Modify(\Container::$dbConnection, 'users');
|
||||||
|
$modify->fill($user->toArray());
|
||||||
|
$modify->save();
|
||||||
|
$userId = $modify->getId();
|
||||||
|
|
||||||
|
$token = hash('sha256', serialize($user) . random_bytes(10) . microtime());
|
||||||
|
|
||||||
|
$modify = new Modify(\Container::$dbConnection, 'user_confirmations');
|
||||||
|
$modify->set('user_id', $userId);
|
||||||
|
$modify->set('token', $token);
|
||||||
|
$modify->save();
|
||||||
|
|
||||||
|
\Container::$dbConnection->commit();
|
||||||
|
|
||||||
|
$this->sendConfirmationEmail($user->getEmail(), $token);
|
||||||
|
|
||||||
|
$data = ['success' => true];
|
||||||
|
return new JsonContent($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function activate()
|
||||||
|
{
|
||||||
|
$session = $this->request->session();
|
||||||
|
|
||||||
|
if ($session->get('user')) {
|
||||||
|
return new Redirect([\Container::$routeCollection->getRoute('index'), []], IRedirect::TEMPORARY);
|
||||||
|
}
|
||||||
|
|
||||||
|
$select = new Select(\Container::$dbConnection, 'user_confirmations');
|
||||||
|
$select->columns(['id', 'user_id']);
|
||||||
|
$select->where('token', '=', $this->request->query('token'));
|
||||||
|
|
||||||
|
$confirmation = $select->execute()->fetch(IResultSet::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if ($confirmation === null) {
|
||||||
|
$data = [];
|
||||||
|
return new HtmlContent('signup/activate', $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
\Container::$dbConnection->startTransaction();
|
||||||
|
|
||||||
|
$modify = new Modify(\Container::$dbConnection, 'user_confirmations');
|
||||||
|
$modify->setId($confirmation['id']);
|
||||||
|
$modify->delete();
|
||||||
|
|
||||||
|
$modify = new Modify(\Container::$dbConnection, 'users');
|
||||||
|
$modify->setId($confirmation['user_id']);
|
||||||
|
$modify->set('active', true);
|
||||||
|
$modify->save();
|
||||||
|
|
||||||
|
\Container::$dbConnection->commit();
|
||||||
|
|
||||||
|
$select = new Select(\Container::$dbConnection, 'users');
|
||||||
|
$select->columns(User::getFields());
|
||||||
|
$select->whereId($confirmation['user_id']);
|
||||||
|
|
||||||
|
$userData = $select->execute()->fetch(IResultSet::FETCH_ASSOC);
|
||||||
|
$user = new User($userData);
|
||||||
|
|
||||||
|
$session->set('user', $user);
|
||||||
|
|
||||||
|
return new Redirect([\Container::$routeCollection->getRoute('index'), []], IRedirect::TEMPORARY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cancel()
|
||||||
|
{
|
||||||
|
$session = $this->request->session();
|
||||||
|
|
||||||
|
if ($session->get('user')) {
|
||||||
|
return new Redirect([\Container::$routeCollection->getRoute('index'), []], IRedirect::TEMPORARY);
|
||||||
|
}
|
||||||
|
|
||||||
|
$select = new Select(\Container::$dbConnection, 'user_confirmations');
|
||||||
|
$select->columns(['id', 'user_id']);
|
||||||
|
$select->where('token', '=', $this->request->query('token'));
|
||||||
|
|
||||||
|
$confirmation = $select->execute()->fetch(IResultSet::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if ($confirmation === null) {
|
||||||
|
$data = ['success' => false];
|
||||||
|
return new HtmlContent('signup/cancel', $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
\Container::$dbConnection->startTransaction();
|
||||||
|
|
||||||
|
$modify = new Modify(\Container::$dbConnection, 'user_confirmations');
|
||||||
|
$modify->setId($confirmation['id']);
|
||||||
|
$modify->delete();
|
||||||
|
|
||||||
|
$modify = new Modify(\Container::$dbConnection, 'users');
|
||||||
|
$modify->setId($confirmation['user_id']);
|
||||||
|
$modify->delete();
|
||||||
|
|
||||||
|
\Container::$dbConnection->commit();
|
||||||
|
|
||||||
|
$data = ['success' => true];
|
||||||
|
return new HtmlContent('signup/cancel', $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function sendConfirmationEmail($email, $token): void
|
||||||
|
{
|
||||||
|
$mail = new Mail();
|
||||||
|
$mail->addRecipient($email);
|
||||||
|
$mail->setSubject('Welcome to MapGuesser - Activate your account');
|
||||||
|
$mail->setBodyFromTemplate('signup', [
|
||||||
|
'EMAIL' => $email,
|
||||||
|
'ACTIVATE_LINK' => $this->request->getBase() . '/signup/activate/' . $token,
|
||||||
|
'CANCEL_LINK' => $this->request->getBase() . '/signup/cancel/' . $token,
|
||||||
|
]);
|
||||||
|
$mail->send();
|
||||||
|
}
|
||||||
|
}
|
9
views/signup/activate.php
Normal file
9
views/signup/activate.php
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?php require ROOT . '/views/templates/main_header.php'; ?>
|
||||||
|
<?php require ROOT . '/views/templates/header.php'; ?>
|
||||||
|
<div class="main">
|
||||||
|
<h2>Account activation</h2>
|
||||||
|
<div class="box">
|
||||||
|
<p class="error justify">Activation failed. Please check the link you entered or retry <a href="/signup" title="Sign up">sign up</a>!</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php require ROOT . '/views/templates/main_footer.php'; ?>
|
13
views/signup/cancel.php
Normal file
13
views/signup/cancel.php
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?php require ROOT . '/views/templates/main_header.php'; ?>
|
||||||
|
<?php require ROOT . '/views/templates/header.php'; ?>
|
||||||
|
<div class="main">
|
||||||
|
<h2>Account cancellation</h2>
|
||||||
|
<div class="box">
|
||||||
|
<?php if ($success) : ?>
|
||||||
|
<p class="justify">Cancellation was successfull. You can <a href="/signup" title="Sign up">sign up</a> any time if you want!</p>
|
||||||
|
<?php else: ?>
|
||||||
|
<p class="error justify">Cancellation failed. Please check the link you entered! Maybe the account was already deleted, in this case no further action is required.</p>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php require ROOT . '/views/templates/main_footer.php'; ?>
|
22
views/signup/signup.php
Normal file
22
views/signup/signup.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
$jsFiles = [
|
||||||
|
'js/signup.js',
|
||||||
|
];
|
||||||
|
?>
|
||||||
|
<?php require ROOT . '/views/templates/main_header.php'; ?>
|
||||||
|
<?php require ROOT . '/views/templates/header.php'; ?>
|
||||||
|
<div class="main">
|
||||||
|
<h2>Sign up</h2>
|
||||||
|
<div class="box">
|
||||||
|
<form id="signupForm" action="/signup" method="post">
|
||||||
|
<input class="big fullWidth" type="email" name="email" placeholder="Email address" autofocus>
|
||||||
|
<input class="big fullWidth marginTop" type="password" name="password" placeholder="Password">
|
||||||
|
<input class="big fullWidth marginTop" type="password" name="password_confirm" placeholder="Password confirmation">
|
||||||
|
<p id="signupFormError" class="formError justify marginTop"></p>
|
||||||
|
<div class="right marginTop">
|
||||||
|
<button type="submit">Sign up</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php require ROOT . '/views/templates/main_footer.php'; ?>
|
4
web.php
4
web.php
@ -15,6 +15,10 @@ Container::$routeCollection = new MapGuesser\Routing\RouteCollection();
|
|||||||
Container::$routeCollection->get('index', '', [MapGuesser\Controller\HomeController::class, 'getIndex']);
|
Container::$routeCollection->get('index', '', [MapGuesser\Controller\HomeController::class, 'getIndex']);
|
||||||
Container::$routeCollection->get('login', 'login', [MapGuesser\Controller\LoginController::class, 'getLoginForm']);
|
Container::$routeCollection->get('login', 'login', [MapGuesser\Controller\LoginController::class, 'getLoginForm']);
|
||||||
Container::$routeCollection->post('login-action', 'login', [MapGuesser\Controller\LoginController::class, 'login']);
|
Container::$routeCollection->post('login-action', 'login', [MapGuesser\Controller\LoginController::class, 'login']);
|
||||||
|
Container::$routeCollection->get('signup', 'signup', [MapGuesser\Controller\SignupController::class, 'getSignupForm']);
|
||||||
|
Container::$routeCollection->post('signup-action', 'signup', [MapGuesser\Controller\SignupController::class, 'signup']);
|
||||||
|
Container::$routeCollection->get('signup.activate', 'signup/activate/{token}', [MapGuesser\Controller\SignupController::class, 'activate']);
|
||||||
|
Container::$routeCollection->get('signup.cancel', 'signup/cancel/{token}', [MapGuesser\Controller\SignupController::class, 'cancel']);
|
||||||
Container::$routeCollection->get('logout', 'logout', [MapGuesser\Controller\LoginController::class, 'logout']);
|
Container::$routeCollection->get('logout', 'logout', [MapGuesser\Controller\LoginController::class, 'logout']);
|
||||||
Container::$routeCollection->get('maps', 'maps', [MapGuesser\Controller\MapsController::class, 'getMaps']);
|
Container::$routeCollection->get('maps', 'maps', [MapGuesser\Controller\MapsController::class, 'getMaps']);
|
||||||
Container::$routeCollection->group('game', function (MapGuesser\Routing\RouteCollection $routeCollection) {
|
Container::$routeCollection->group('game', function (MapGuesser\Routing\RouteCollection $routeCollection) {
|
||||||
|
Loading…
Reference in New Issue
Block a user