MAPG-115 add login functionality
This commit is contained in:
parent
d93a758cd2
commit
edc2e4111a
@ -12,6 +12,9 @@ if (($pos = strpos($url, '?')) !== false) {
|
|||||||
$url = rawurldecode($url);
|
$url = rawurldecode($url);
|
||||||
|
|
||||||
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->post('login-action', 'login', [MapGuesser\Controller\LoginController::class, 'login']);
|
||||||
|
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) {
|
||||||
$routeCollection->get('game', '{mapId}', [MapGuesser\Controller\GameController::class, 'getGame']);
|
$routeCollection->get('game', '{mapId}', [MapGuesser\Controller\GameController::class, 'getGame']);
|
||||||
|
@ -17,7 +17,7 @@ button::-moz-focus-inner, input::-moz-focus-inner {
|
|||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
p, h1, h2, button, a {
|
p, h1, h2, input, textarea, select, button, a {
|
||||||
font-family: 'Roboto', sans-serif;
|
font-family: 'Roboto', sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,6 +93,10 @@ sub {
|
|||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
svg.inline, img.inline {
|
svg.inline, img.inline {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 1em;
|
width: 1em;
|
||||||
@ -158,6 +162,54 @@ button.red:hover, button.red:focus, a.button.red:hover, a.button.red:focus {
|
|||||||
background-color: #7f2929;
|
background-color: #7f2929;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input, select, textarea {
|
||||||
|
background-color: #f9fafb;
|
||||||
|
border: solid #c8d2e1 1px;
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
font-size: 13px;
|
||||||
|
resize: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.big, select.big, textarea.big {
|
||||||
|
padding: 5px;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.fullWidth, select.fullWidth, textarea.fullWidth {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:disabled, select:disabled, textarea:disabled {
|
||||||
|
background-color: #dfdfdf;
|
||||||
|
border: solid #dfdfdf 1px;
|
||||||
|
color: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus, select:focus, textarea:focus {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border: solid #29457f 2px;
|
||||||
|
padding: 3px;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.big:focus, select.big:focus, textarea.big:focus {
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.formError {
|
||||||
|
color: #7f2929;
|
||||||
|
font-weight: 500;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
div.header {
|
div.header {
|
||||||
background-color: #333333;
|
background-color: #333333;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
@ -200,6 +252,15 @@ div.buttonContainer>button {
|
|||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.box {
|
||||||
|
width: 576px;
|
||||||
|
background-color: #eeeeee;
|
||||||
|
border-radius: 3px;
|
||||||
|
margin: 10px auto;
|
||||||
|
padding: 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 599px) {
|
@media screen and (max-width: 599px) {
|
||||||
div.header.small h1 span {
|
div.header.small h1 span {
|
||||||
display: none;
|
display: none;
|
||||||
@ -208,4 +269,7 @@ div.buttonContainer>button {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
div.box {
|
||||||
|
width: initial;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
42
public/static/js/login.js
Normal file
42
public/static/js/login.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
(function () {
|
||||||
|
var form = document.getElementById('loginForm');
|
||||||
|
|
||||||
|
form.onsubmit = function (e) {
|
||||||
|
document.getElementById('loading').style.visibility = 'visible';
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var formData = new FormData(form);
|
||||||
|
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.responseType = 'json';
|
||||||
|
xhr.onload = function () {
|
||||||
|
document.getElementById('loading').style.visibility = 'hidden';
|
||||||
|
|
||||||
|
if (this.response.error) {
|
||||||
|
var errorText;
|
||||||
|
switch (this.response.error) {
|
||||||
|
case 'user_not_found':
|
||||||
|
errorText = 'No user found with the given email address.';
|
||||||
|
break;
|
||||||
|
case 'password_not_match':
|
||||||
|
errorText = 'The given password is wrong.'
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var loginFormError = document.getElementById('loginFormError');
|
||||||
|
loginFormError.style.display = 'block';
|
||||||
|
loginFormError.innerHTML = errorText;
|
||||||
|
|
||||||
|
form.elements.email.select();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.location.replace('/');
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.open('POST', form.action, true);
|
||||||
|
xhr.send(formData);
|
||||||
|
};
|
||||||
|
})();
|
@ -22,9 +22,10 @@ class AddUserCommand extends Command
|
|||||||
{
|
{
|
||||||
$user = new User([
|
$user = new User([
|
||||||
'email' => $input->getArgument('email'),
|
'email' => $input->getArgument('email'),
|
||||||
'password' => $input->getArgument('password')
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$user->setPlainPassword($input->getArgument('password'));
|
||||||
|
|
||||||
if ($input->hasArgument('type')) {
|
if ($input->hasArgument('type')) {
|
||||||
$user->setType($input->getArgument('type'));
|
$user->setType($input->getArgument('type'));
|
||||||
}
|
}
|
||||||
|
73
src/Controller/LoginController.php
Normal file
73
src/Controller/LoginController.php
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<?php namespace MapGuesser\Controller;
|
||||||
|
|
||||||
|
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\Model\User;
|
||||||
|
use MapGuesser\Response\HtmlContent;
|
||||||
|
use MapGuesser\Response\JsonContent;
|
||||||
|
use MapGuesser\Response\Redirect;
|
||||||
|
|
||||||
|
class LoginController
|
||||||
|
{
|
||||||
|
private IRequest $request;
|
||||||
|
|
||||||
|
public function __construct(IRequest $request)
|
||||||
|
{
|
||||||
|
$this->request = $request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLoginForm()
|
||||||
|
{
|
||||||
|
$session = $this->request->session();
|
||||||
|
|
||||||
|
if ($session->get('user')) {
|
||||||
|
return new Redirect([\Container::$routeCollection->getRoute('index'), []], IRedirect::TEMPORARY);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
return new HtmlContent('login', $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function login(): IContent
|
||||||
|
{
|
||||||
|
$session = $this->request->session();
|
||||||
|
|
||||||
|
if ($session->get('user')) {
|
||||||
|
$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) {
|
||||||
|
$data = ['error' => 'user_not_found'];
|
||||||
|
return new JsonContent($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = new User($userData);
|
||||||
|
|
||||||
|
if (!$user->checkPassword($this->request->post('password'))) {
|
||||||
|
$data = ['error' => 'password_not_match'];
|
||||||
|
return new JsonContent($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
$session->set('user', $user);
|
||||||
|
|
||||||
|
$data = ['success' => true];
|
||||||
|
return new JsonContent($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function logout(): IRedirect
|
||||||
|
{
|
||||||
|
$this->request->session()->delete('user');
|
||||||
|
|
||||||
|
return new Redirect([\Container::$routeCollection->getRoute('login'), []], IRedirect::TEMPORARY);
|
||||||
|
}
|
||||||
|
}
|
17
views/login.php
Normal file
17
views/login.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php require ROOT . '/views/templates/main_header.php'; ?>
|
||||||
|
<?php require ROOT . '/views/templates/header.php'; ?>
|
||||||
|
<div class="main">
|
||||||
|
<h2>Login</h2>
|
||||||
|
<div class="box">
|
||||||
|
<form id="loginForm" action="/login" 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">
|
||||||
|
<p id="loginFormError" class="formError marginTop"></p>
|
||||||
|
<div class="right marginTop">
|
||||||
|
<button type="submit">Login</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="/static/js/login.js"></script>
|
||||||
|
<?php require ROOT . '/views/templates/main_footer.php'; ?>
|
Loading…
Reference in New Issue
Block a user