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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user