From ed9621d581bb2fb78a853617bd868d20c6b39df9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=91cze=20Bence?= Date: Sun, 7 Jun 2020 21:38:19 +0200 Subject: [PATCH 1/7] MAPG-115 add users table --- database/migrations/structure/20200606_2352_users.sql | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 database/migrations/structure/20200606_2352_users.sql diff --git a/database/migrations/structure/20200606_2352_users.sql b/database/migrations/structure/20200606_2352_users.sql new file mode 100644 index 0000000..c3078a9 --- /dev/null +++ b/database/migrations/structure/20200606_2352_users.sql @@ -0,0 +1,8 @@ +CREATE TABLE `users` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `email` varchar(100) NOT NULL, + `password` varchar(60) NOT NULL, + `type` enum('user', 'admin') NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `email` (`email`) +) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4; From ecaf8ca9d493116b187f82fd49b8f3d230b5495f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=91cze=20Bence?= Date: Sun, 7 Jun 2020 23:37:01 +0200 Subject: [PATCH 2/7] MAPG-115 make possible to secure controllers --- public/index.php | 34 +++++++++++++++++------ src/Controller/MapAdminController.php | 10 ++++++- src/Interfaces/Authorization/ISecured.php | 6 ++++ src/Routing/Route.php | 13 ++++----- 4 files changed, 45 insertions(+), 18 deletions(-) create mode 100644 src/Interfaces/Authorization/ISecured.php diff --git a/public/index.php b/public/index.php index 829da88..acc664f 100644 --- a/public/index.php +++ b/public/index.php @@ -30,15 +30,31 @@ $match = Container::$routeCollection->match($method, explode('/', $url)); if ($match !== null) { list($route, $params) = $match; - $response = $route->callController($params); + $handler = $route->getHandler(); - if ($response instanceof MapGuesser\Interfaces\Response\IContent) { - header('Content-Type: ' . $response->getContentType() . '; charset=UTF-8'); - echo $response->render(); - } elseif ($response instanceof MapGuesser\Interfaces\Response\IRedirect) { - header('Location: ' . $host . '/' . $response->getUrl(), true, $response->getHttpCode()); + $controller = new $handler[0]; + + if ($controller instanceof MapGuesser\Interfaces\Authorization\ISecured) { + $authorized = $controller->authorize(); + } else { + $authorized = true; + } + + if ($authorized) { + $response = call_user_func([$controller, $handler[1]], $params); + + if ($response instanceof MapGuesser\Interfaces\Response\IContent) { + header('Content-Type: ' . $response->getContentType() . '; charset=UTF-8'); + echo $response->render(); + + return; + } elseif ($response instanceof MapGuesser\Interfaces\Response\IRedirect) { + header('Location: ' . $host . '/' . $response->getUrl(), true, $response->getHttpCode()); + + return; + } } -} else { - header('Content-Type: text/html; charset=UTF-8', true, 404); - require ROOT . '/views/error/404.php'; } + +header('Content-Type: text/html; charset=UTF-8', true, 404); +require ROOT . '/views/error/404.php'; diff --git a/src/Controller/MapAdminController.php b/src/Controller/MapAdminController.php index a0bd507..59a2c3f 100644 --- a/src/Controller/MapAdminController.php +++ b/src/Controller/MapAdminController.php @@ -1,6 +1,7 @@ placeRepository = new PlaceRepository(); } + public function authorize(): bool + { + //TODO + + return false; + } + public function getMaps(): IContent { //TODO diff --git a/src/Interfaces/Authorization/ISecured.php b/src/Interfaces/Authorization/ISecured.php new file mode 100644 index 0000000..4e3a84e --- /dev/null +++ b/src/Interfaces/Authorization/ISecured.php @@ -0,0 +1,6 @@ +id; } + public function getHandler(): array + { + return $this->handler; + } + public function generateLink(array $parameters = []): string { $link = []; @@ -51,14 +56,6 @@ class Route return implode('/', $link) . $query; } - public function callController(array $parameters) - { - $controllerName = $this->handler[0]; - $controller = new $controllerName(); - - return call_user_func([$controller, $this->handler[1]], $parameters); - } - public function testAgainst(array $path): ?array { $parameters = []; From fe814908c71901ceb8aae5828550f0c268e6a73f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=91cze=20Bence?= Date: Tue, 9 Jun 2020 00:54:44 +0200 Subject: [PATCH 3/7] MAPG-115 add new classes to store request data (get, post, session, etc.) --- src/Interfaces/Authentication/IUser.php | 10 +++++ src/Interfaces/Request/IRequest.php | 14 ++++++ src/Interfaces/Request/ISession.php | 12 ++++++ src/Request/Request.php | 57 +++++++++++++++++++++++++ src/Request/Session.php | 37 ++++++++++++++++ 5 files changed, 130 insertions(+) create mode 100644 src/Interfaces/Authentication/IUser.php create mode 100644 src/Interfaces/Request/IRequest.php create mode 100644 src/Interfaces/Request/ISession.php create mode 100644 src/Request/Request.php create mode 100644 src/Request/Session.php diff --git a/src/Interfaces/Authentication/IUser.php b/src/Interfaces/Authentication/IUser.php new file mode 100644 index 0000000..363cfe8 --- /dev/null +++ b/src/Interfaces/Authentication/IUser.php @@ -0,0 +1,10 @@ +get = &$get; + $this->routeParams = &$routeParams; + $this->post = &$post; + $this->session = new Session($session); + } + + public function query($key) + { + if (isset($this->get[$key])) { + return $this->get[$key]; + } + + if (isset($this->routeParams[$key])) { + return $this->routeParams[$key]; + } + + return null; + } + + public function post($key) + { + if (isset($this->post[$key])) { + return $this->post[$key]; + } + + return null; + } + + public function session(): ISession + { + return $this->session; + } + + public function user(): ?IUser + { + return $this->session->get('user'); + } +} diff --git a/src/Request/Session.php b/src/Request/Session.php new file mode 100644 index 0000000..f1fedab --- /dev/null +++ b/src/Request/Session.php @@ -0,0 +1,37 @@ +data = &$data; + } + + public function has($key): bool + { + return isset($this->data[$key]); + } + + public function get($key) + { + if (isset($this->data[$key])) { + return $this->data[$key]; + } + + return null; + } + + public function set($key, $value): void + { + $this->data[$key] = $value; + } + + public function delete($key): void + { + unset($this->data[$key]); + } +} From 00dc78b50c25459cf7667f0d4b9ae08e8a8e7834 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=91cze=20Bence?= Date: Tue, 9 Jun 2020 00:55:26 +0200 Subject: [PATCH 4/7] MAPG-115 add base model and User model --- src/Model/BaseModel.php | 49 +++++++++++++++++++++++++++++ src/Model/User.php | 70 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 src/Model/BaseModel.php create mode 100644 src/Model/User.php diff --git a/src/Model/BaseModel.php b/src/Model/BaseModel.php new file mode 100644 index 0000000..48713f7 --- /dev/null +++ b/src/Model/BaseModel.php @@ -0,0 +1,49 @@ + $value) { + $method = 'set' . str_replace('_', '', ucwords($key, '_')); + + if (method_exists($this, $method)) { + $this->$method($value); + } + } + } + + public function setId($id): void + { + $this->id = $id; + } + + public function getId() + { + return $this->id; + } + + function toArray(): array + { + $array = []; + + foreach (self::getFields() as $key) { + $method = 'get' . str_replace('_', '', ucwords($key, '_')); + + if (method_exists($this, $method)) { + $array[$key] = $this->$method(); + } + } + + return $array; + } +} diff --git a/src/Model/User.php b/src/Model/User.php new file mode 100644 index 0000000..cdc34dd --- /dev/null +++ b/src/Model/User.php @@ -0,0 +1,70 @@ +email = $email; + } + + public function setPassword(string $hashedPassword): void + { + $this->password = $hashedPassword; + } + + public function setPlainPassword(string $plainPassword): void + { + $this->password = password_hash($plainPassword, PASSWORD_BCRYPT); + } + + public function setType(string $type): void + { + if (in_array($type, self::$types)) { + $this->type = $type; + } + } + + public function getEmail(): string + { + return $this->email; + } + + public function getPassword(): string + { + return $this->password; + } + + public function getType(): string + { + return $this->type; + } + + public function hasPermission(int $permission): bool + { + switch ($permission) { + case IUser::PERMISSION_NORMAL: + return true; + break; + case IUser::PERMISSION_ADMIN: + return $this->type === 'admin'; + break; + } + } + + public function checkPassword(string $password): bool + { + return password_verify($password, $this->password); + } +} From e8f9d74283950a1a3d28bcaea84a67a6baaa457a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=91cze=20Bence?= Date: Tue, 9 Jun 2020 00:56:00 +0200 Subject: [PATCH 5/7] MAPG-115 adapt existing controllers to the new request classes --- public/index.php | 7 ++-- src/Controller/GameController.php | 24 ++++++++---- src/Controller/MapAdminController.php | 19 ++++++---- src/Controller/PositionController.php | 53 ++++++++++++++++----------- 4 files changed, 65 insertions(+), 38 deletions(-) diff --git a/public/index.php b/public/index.php index acc664f..bc3ea01 100644 --- a/public/index.php +++ b/public/index.php @@ -30,9 +30,10 @@ $match = Container::$routeCollection->match($method, explode('/', $url)); if ($match !== null) { list($route, $params) = $match; - $handler = $route->getHandler(); + $request = new MapGuesser\Request\Request($_GET, $params, $_POST, $_SESSION); - $controller = new $handler[0]; + $handler = $route->getHandler(); + $controller = new $handler[0]($request); if ($controller instanceof MapGuesser\Interfaces\Authorization\ISecured) { $authorized = $controller->authorize(); @@ -41,7 +42,7 @@ if ($match !== null) { } if ($authorized) { - $response = call_user_func([$controller, $handler[1]], $params); + $response = call_user_func([$controller, $handler[1]]); if ($response instanceof MapGuesser\Interfaces\Response\IContent) { header('Content-Type: ' . $response->getContentType() . '; charset=UTF-8'); diff --git a/src/Controller/GameController.php b/src/Controller/GameController.php index 246f9b8..1664623 100644 --- a/src/Controller/GameController.php +++ b/src/Controller/GameController.php @@ -2,6 +2,7 @@ use MapGuesser\Database\Query\Select; use MapGuesser\Interfaces\Database\IResultSet; +use MapGuesser\Interfaces\Request\IRequest; use MapGuesser\Util\Geo\Bounds; use MapGuesser\Response\HtmlContent; use MapGuesser\Response\JsonContent; @@ -9,16 +10,23 @@ use MapGuesser\Interfaces\Response\IContent; class GameController { - public function getGame(array $parameters): IContent + private IRequest $request; + + public function __construct(IRequest $request) { - $mapId = (int) $parameters['mapId']; + $this->request = $request; + } + + public function getGame(): IContent + { + $mapId = (int) $this->request->query('mapId'); $data = $this->prepareGame($mapId); return new HtmlContent('game', $data); } - public function getGameJson(array $parameters): IContent + public function getGameJson(): IContent { - $mapId = (int) $parameters['mapId']; + $mapId = (int) $this->request->query('mapId'); $data = $this->prepareGame($mapId); return new JsonContent($data); } @@ -27,12 +35,14 @@ class GameController { $bounds = $this->getMapBounds($mapId); - if (!isset($_SESSION['state']) || $_SESSION['state']['mapId'] !== $mapId) { - $_SESSION['state'] = [ + $session = $this->request->session(); + + if (($state = $session->get('state')) && $state['mapId'] !== $mapId) { + $session->set('state', [ 'mapId' => $mapId, 'area' => $bounds->calculateApproximateArea(), 'rounds' => [] - ]; + ]); } return ['mapId' => $mapId, 'bounds' => $bounds->toArray()]; diff --git a/src/Controller/MapAdminController.php b/src/Controller/MapAdminController.php index 59a2c3f..d96f8dc 100644 --- a/src/Controller/MapAdminController.php +++ b/src/Controller/MapAdminController.php @@ -1,8 +1,10 @@ request = $request; $this->placeRepository = new PlaceRepository(); } public function authorize(): bool { - //TODO + $user = $this->request->user(); - return false; + return $user !== null && $user->hasPermission(IUser::PERMISSION_ADMIN); } public function getMaps(): IContent @@ -32,9 +37,9 @@ class MapAdminController implements ISecured return new HtmlContent('admin/maps'); } - public function getMapEditor(array $parameters): IContent + public function getMapEditor(): IContent { - $mapId = (int) $parameters['mapId']; + $mapId = (int) $this->request->query('mapId'); $bounds = $this->getMapBounds($mapId); @@ -44,9 +49,9 @@ class MapAdminController implements ISecured return new HtmlContent('admin/map_editor', $data); } - public function getPlace(array $parameters) + public function getPlace() { - $placeId = (int) $parameters['placeId']; + $placeId = (int) $this->request->query('placeId'); $placeData = $this->placeRepository->getById($placeId); diff --git a/src/Controller/PositionController.php b/src/Controller/PositionController.php index 1564730..b804797 100644 --- a/src/Controller/PositionController.php +++ b/src/Controller/PositionController.php @@ -1,5 +1,6 @@ request = $request; $this->placeRepository = new PlaceRepository(); } - public function getPosition(array $parameters): IContent + public function getPosition(): IContent { - $mapId = (int) $parameters['mapId']; + $mapId = (int) $this->request->query('mapId'); - if (!isset($_SESSION['state']) || $_SESSION['state']['mapId'] !== $mapId) { + $session = $this->request->session(); + + if (!($state = $session->get('state')) || $state['mapId'] !== $mapId) { $data = ['error' => 'no_session_found']; return new JsonContent($data); } - if (count($_SESSION['state']['rounds']) === 0) { + if (count($state['rounds']) === 0) { $newPosition = $this->placeRepository->getForMapWithValidPano($mapId); - $_SESSION['state']['rounds'][] = $newPosition; + $state['rounds'][] = $newPosition; + $session->set('state', $state); $data = ['panoId' => $newPosition['panoId']]; } else { - $rounds = count($_SESSION['state']['rounds']); - $last = $_SESSION['state']['rounds'][$rounds - 1]; + $rounds = count($state['rounds']); + $last = $state['rounds'][$rounds - 1]; $history = []; for ($i = 0; $i < $rounds - 1; ++$i) { - $round = $_SESSION['state']['rounds'][$i]; + $round = $state['rounds'][$i]; $history[] = [ 'position' => $round['position']->toArray(), 'guessPosition' => $round['guessPosition']->toArray(), @@ -55,41 +62,45 @@ class PositionController return new JsonContent($data); } - public function evaluateGuess(array $parameters): IContent + public function evaluateGuess(): IContent { - $mapId = (int) $parameters['mapId']; + $mapId = (int) $this->request->query('mapId'); - if (!isset($_SESSION['state']) || $_SESSION['state']['mapId'] !== $mapId) { + $session = $this->request->session(); + + if (!($state = $session->get('state')) || $state['mapId'] !== $mapId) { $data = ['error' => 'no_session_found']; return new JsonContent($data); } - $last = &$_SESSION['state']['rounds'][count($_SESSION['state']['rounds']) - 1]; + $last = $state['rounds'][count($state['rounds']) - 1]; $position = $last['position']; - $guessPosition = new Position((float) $_POST['lat'], (float) $_POST['lng']); - - $last['guessPosition'] = $guessPosition; + $guessPosition = new Position((float) $this->request->post('lat'), (float) $this->request->post('lng')); $distance = $this->calculateDistance($position, $guessPosition); - $score = $this->calculateScore($distance, $_SESSION['state']['area']); + $score = $this->calculateScore($distance, $state['area']); + $last['guessPosition'] = $guessPosition; $last['distance'] = $distance; $last['score'] = $score; + $state['rounds'][count($state['rounds']) - 1] = $last; - if (count($_SESSION['state']['rounds']) < static::NUMBER_OF_ROUNDS) { + if (count($state['rounds']) < static::NUMBER_OF_ROUNDS) { $exclude = []; - foreach ($_SESSION['state']['rounds'] as $round) { + foreach ($state['rounds'] as $round) { $exclude = array_merge($exclude, $round['placesWithoutPano'], [$round['placeId']]); } $newPosition = $this->placeRepository->getForMapWithValidPano($mapId, $exclude); - $_SESSION['state']['rounds'][] = $newPosition; + $state['rounds'][] = $newPosition; + $session->set('state', $state); $panoId = $newPosition['panoId']; } else { - $_SESSION['state']['rounds'] = []; + $state['rounds'] = []; + $session->set('state', $state); $panoId = null; } From d93a758cd2001fdf4d22d0fd784a73d976e3af32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=91cze=20Bence?= Date: Tue, 9 Jun 2020 00:56:46 +0200 Subject: [PATCH 6/7] MAPG-115 make possible to add new users via command line --- mapg | 1 + src/Cli/AddUserCommand.php | 50 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 src/Cli/AddUserCommand.php diff --git a/mapg b/mapg index ab89fe9..6409a95 100755 --- a/mapg +++ b/mapg @@ -6,5 +6,6 @@ require 'main.php'; $app = new Symfony\Component\Console\Application('MapGuesser Console', ''); $app->add(new MapGuesser\Cli\DatabaseMigration()); +$app->add(new MapGuesser\Cli\AddUserCommand()); $app->run(); diff --git a/src/Cli/AddUserCommand.php b/src/Cli/AddUserCommand.php new file mode 100644 index 0000000..ce90058 --- /dev/null +++ b/src/Cli/AddUserCommand.php @@ -0,0 +1,50 @@ +setName('user:add') + ->setDescription('Adding of user.') + ->addArgument('email', InputArgument::REQUIRED, 'Email of user') + ->addArgument('password', InputArgument::REQUIRED, 'Password of user') + ->addArgument('type', InputArgument::OPTIONAL, 'Type of user');; + } + + public function execute(InputInterface $input, OutputInterface $output): int + { + $user = new User([ + 'email' => $input->getArgument('email'), + 'password' => $input->getArgument('password') + ]); + + if ($input->hasArgument('type')) { + $user->setType($input->getArgument('type')); + } + + try { + $modify = new Modify(\Container::$dbConnection, 'users'); + $modify->fill($user->toArray()); + $modify->save(); + } catch (\Exception $e) { + $output->writeln('Adding user failed!'); + $output->writeln(''); + + $output->writeln((string) $e); + $output->writeln(''); + + return 1; + } + + $output->writeln('User was successfully added!'); + + return 0; + } +} From edc2e4111a64c097b70007be5ac6db7a67d89c73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=91cze=20Bence?= Date: Tue, 9 Jun 2020 02:01:41 +0200 Subject: [PATCH 7/7] MAPG-115 add login functionality --- public/index.php | 3 ++ public/static/css/mapguesser.css | 66 ++++++++++++++++++++++++++- public/static/js/login.js | 42 +++++++++++++++++ src/Cli/AddUserCommand.php | 3 +- src/Controller/LoginController.php | 73 ++++++++++++++++++++++++++++++ views/login.php | 17 +++++++ 6 files changed, 202 insertions(+), 2 deletions(-) create mode 100644 public/static/js/login.js create mode 100644 src/Controller/LoginController.php create mode 100644 views/login.php diff --git a/public/index.php b/public/index.php index bc3ea01..d90278f 100644 --- a/public/index.php +++ b/public/index.php @@ -12,6 +12,9 @@ if (($pos = strpos($url, '?')) !== false) { $url = rawurldecode($url); 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->group('game', function (MapGuesser\Routing\RouteCollection $routeCollection) { $routeCollection->get('game', '{mapId}', [MapGuesser\Controller\GameController::class, 'getGame']); diff --git a/public/static/css/mapguesser.css b/public/static/css/mapguesser.css index d96bc8a..e95792f 100644 --- a/public/static/css/mapguesser.css +++ b/public/static/css/mapguesser.css @@ -17,7 +17,7 @@ button::-moz-focus-inner, input::-moz-focus-inner { border: 0; } -p, h1, h2, button, a { +p, h1, h2, input, textarea, select, button, a { font-family: 'Roboto', sans-serif; } @@ -93,6 +93,10 @@ sub { margin-bottom: 10px; } +.right { + text-align: right; +} + svg.inline, img.inline { display: inline-block; width: 1em; @@ -158,6 +162,54 @@ button.red:hover, button.red:focus, a.button.red:hover, a.button.red:focus { 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 { background-color: #333333; height: 50px; @@ -200,6 +252,15 @@ div.buttonContainer>button { 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) { div.header.small h1 span { display: none; @@ -208,4 +269,7 @@ div.buttonContainer>button { padding: 0; width: 100%; } + div.box { + width: initial; + } } diff --git a/public/static/js/login.js b/public/static/js/login.js new file mode 100644 index 0000000..0297b14 --- /dev/null +++ b/public/static/js/login.js @@ -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); + }; +})(); diff --git a/src/Cli/AddUserCommand.php b/src/Cli/AddUserCommand.php index ce90058..45fb57d 100644 --- a/src/Cli/AddUserCommand.php +++ b/src/Cli/AddUserCommand.php @@ -22,9 +22,10 @@ class AddUserCommand extends Command { $user = new User([ 'email' => $input->getArgument('email'), - 'password' => $input->getArgument('password') ]); + $user->setPlainPassword($input->getArgument('password')); + if ($input->hasArgument('type')) { $user->setType($input->getArgument('type')); } diff --git a/src/Controller/LoginController.php b/src/Controller/LoginController.php new file mode 100644 index 0000000..5f124d4 --- /dev/null +++ b/src/Controller/LoginController.php @@ -0,0 +1,73 @@ +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); + } +} diff --git a/views/login.php b/views/login.php new file mode 100644 index 0000000..565e7aa --- /dev/null +++ b/views/login.php @@ -0,0 +1,17 @@ + + +
+

Login

+
+
+ + +

+
+ +
+
+
+
+ + \ No newline at end of file