From 295570a28d43aa7607a302dcd775fa2823bc0f55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=91cze=20Bence?= Date: Sun, 21 Jun 2020 01:21:42 +0200 Subject: [PATCH 01/13] MAPG-69 fix missing relations in UserConfirmation --- src/PersistentData/Model/UserConfirmation.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/PersistentData/Model/UserConfirmation.php b/src/PersistentData/Model/UserConfirmation.php index 70a76d6..fac2b2d 100644 --- a/src/PersistentData/Model/UserConfirmation.php +++ b/src/PersistentData/Model/UserConfirmation.php @@ -6,6 +6,8 @@ class UserConfirmation extends Model protected static array $fields = ['user_id', 'token']; + protected static array $relations = ['user' => User::class]; + private ?User $user = null; private ?int $userId = null; From 99c72d99be357b76ffe40de62102208e7c9854d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=91cze=20Bence?= Date: Sun, 21 Jun 2020 01:27:37 +0200 Subject: [PATCH 02/13] MAPG-69 make Redirect able to redirect to external sources --- public/index.php | 2 +- src/Controller/HomeController.php | 2 +- src/Response/Redirect.php | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/public/index.php b/public/index.php index ad425a0..d025071 100644 --- a/public/index.php +++ b/public/index.php @@ -40,7 +40,7 @@ if ($match !== null) { return; } elseif ($response instanceof MapGuesser\Interfaces\Response\IRedirect) { - header('Location: ' . Container::$request->getBase() . '/' . $response->getUrl(), true, $response->getHttpCode()); + header('Location: ' . $response->getUrl(), true, $response->getHttpCode()); return; } diff --git a/src/Controller/HomeController.php b/src/Controller/HomeController.php index ae2fa61..b5a180e 100644 --- a/src/Controller/HomeController.php +++ b/src/Controller/HomeController.php @@ -7,6 +7,6 @@ class HomeController { public function getIndex(): IRedirect { - return new Redirect([\Container::$routeCollection->getRoute('maps'), []], IRedirect::TEMPORARY); + return new Redirect(\Container::$routeCollection->getRoute('maps')->generateLink(), IRedirect::TEMPORARY); } } diff --git a/src/Response/Redirect.php b/src/Response/Redirect.php index de5ab39..ed78183 100644 --- a/src/Response/Redirect.php +++ b/src/Response/Redirect.php @@ -4,11 +4,11 @@ use MapGuesser\Interfaces\Response\IRedirect; class Redirect implements IRedirect { - private $target; + private string $target; private int $type; - public function __construct($target, int $type = IRedirect::TEMPORARY) + public function __construct(string $target, int $type = IRedirect::TEMPORARY) { $this->target = $target; $this->type = $type; @@ -16,10 +16,10 @@ class Redirect implements IRedirect public function getUrl(): string { - if (is_array($this->target)) { - $link = $this->target[0]->generateLink($this->target[1]); - } else { + if (preg_match('/^http(s)?/', $this->target)) { $link = $this->target; + } else { + $link = \Container::$request->getBase() . '/' . $this->target; } return $link; From 7ba11f34cc7ed9a7af6f49cc1e99bd527412d8bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=91cze=20Bence?= Date: Sun, 21 Jun 2020 01:28:17 +0200 Subject: [PATCH 03/13] MAPG-69 add new field to User --- .../structure/20200620_2113_google_login.sql | 8 ++++++++ src/PersistentData/Model/User.php | 20 +++++++++++++++---- src/Repository/UserRepository.php | 8 ++++++++ 3 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 database/migrations/structure/20200620_2113_google_login.sql diff --git a/database/migrations/structure/20200620_2113_google_login.sql b/database/migrations/structure/20200620_2113_google_login.sql new file mode 100644 index 0000000..152f328 --- /dev/null +++ b/database/migrations/structure/20200620_2113_google_login.sql @@ -0,0 +1,8 @@ +ALTER TABLE + `users` +ADD + `google_sub` varchar(255) CHARACTER SET ascii COLLATE ascii_bin NULL DEFAULT NULL, +ADD + UNIQUE `google_sub` (`google_sub`), +MODIFY + `password` varchar(60) NULL DEFAULT NULL; diff --git a/src/PersistentData/Model/User.php b/src/PersistentData/Model/User.php index fc3b185..e13adfd 100644 --- a/src/PersistentData/Model/User.php +++ b/src/PersistentData/Model/User.php @@ -6,24 +6,26 @@ class User extends Model implements IUser { protected static string $table = 'users'; - protected static array $fields = ['email', 'password', 'type', 'active']; + protected static array $fields = ['email', 'password', 'type', 'active', 'google_sub']; private static array $types = ['user', 'admin']; private string $email = ''; - private string $password = ''; + private ?string $password = null; private string $type = 'user'; private bool $active = false; + private ?string $googleSub = null; + public function setEmail(string $email): void { $this->email = $email; } - public function setPassword(string $hashedPassword): void + public function setPassword(?string $hashedPassword): void { $this->password = $hashedPassword; } @@ -45,12 +47,17 @@ class User extends Model implements IUser $this->active = (bool) $active; } + public function setGoogleSub(?string $googleSub): void + { + $this->googleSub = $googleSub; + } + public function getEmail(): string { return $this->email; } - public function getPassword(): string + public function getPassword(): ?string { return $this->password; } @@ -65,6 +72,11 @@ class User extends Model implements IUser return $this->active; } + public function getGoogleSub(): ?string + { + return $this->googleSub; + } + public function hasPermission(int $permission): bool { switch ($permission) { diff --git a/src/Repository/UserRepository.php b/src/Repository/UserRepository.php index b67771d..c7ddcaf 100644 --- a/src/Repository/UserRepository.php +++ b/src/Repository/UserRepository.php @@ -25,4 +25,12 @@ class UserRepository return $this->pdm->selectFromDb($select, User::class); } + + public function getByGoogleSub(string $sub): ?User + { + $select = new Select(\Container::$dbConnection); + $select->where('google_sub', '=', $sub); + + return $this->pdm->selectFromDb($select, User::class); + } } From 2d2e218002bb22fed3e12e6f864b45d603616c2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=91cze=20Bence?= Date: Sun, 21 Jun 2020 01:31:20 +0200 Subject: [PATCH 04/13] MAPG-69 add simple JWT parser --- src/Util/JwtParser.php | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/Util/JwtParser.php diff --git a/src/Util/JwtParser.php b/src/Util/JwtParser.php new file mode 100644 index 0000000..b6e57a1 --- /dev/null +++ b/src/Util/JwtParser.php @@ -0,0 +1,33 @@ +setToken($token); + } + } + + public function setToken(string $token) + { + $this->token = explode('.', str_replace(['_', '-'], ['/', '+'], $token)); + } + + public function getHeader(): array + { + return json_decode(base64_decode($this->token[0]), true); + } + + public function getPayload(): array + { + return json_decode(base64_decode($this->token[1]), true); + } + + public function getSignature(): string + { + return base64_decode($this->token[2]); + } +} From d1c9e221f7ebd72eefe539ccd38cfcc37be46901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=91cze=20Bence?= Date: Sun, 21 Jun 2020 01:31:36 +0200 Subject: [PATCH 05/13] MAPG-69 add Google OAuth handler --- src/OAuth/GoogleOAuth.php | 41 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/OAuth/GoogleOAuth.php diff --git a/src/OAuth/GoogleOAuth.php b/src/OAuth/GoogleOAuth.php new file mode 100644 index 0000000..07c2107 --- /dev/null +++ b/src/OAuth/GoogleOAuth.php @@ -0,0 +1,41 @@ + 'code', + 'client_id' => $_ENV['GOOGLE_OAUTH_CLIENT_ID'], + 'scope' => 'openid email', + 'redirect_uri' => $redirectUrl, + 'state' => $state, + 'nonce' => hash('sha256', random_bytes(10) . microtime()), + ]; + + return self::$dialogUrlBase . '?' . http_build_query($oauthParams); + } + + public function getToken(string $code, string $redirectUrl) + { + $tokenParams = [ + 'code' => $code, + 'client_id' => $_ENV['GOOGLE_OAUTH_CLIENT_ID'], + 'client_secret' => $_ENV['GOOGLE_OAUTH_CLIENT_SECRET'], + 'redirect_uri' => $redirectUrl, + 'grant_type' => 'authorization_code', + ]; + + $request = new Request(self::$tokenUrlBase, Request::HTTP_POST); + $request->setQuery($tokenParams); + $response = $request->send(); + + return json_decode($response->getBody(), true); + } +} From 96971634573e5dba958221141037e68f7c0803f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=91cze=20Bence?= Date: Sun, 21 Jun 2020 01:33:33 +0200 Subject: [PATCH 06/13] MAPG-69 merge SignupController to LoginController and introduce Google login/sign up --- mail/signup-noconfirm.html | 9 + mail/signup.html | 3 +- public/static/css/mapguesser.css | 4 + src/Controller/LoginController.php | 268 ++++++++++++++++++++++++++- src/Controller/SignupController.php | 170 ----------------- views/{signup => login}/activate.php | 0 views/{signup => login}/cancel.php | 0 views/login/google_login.php | 9 + views/login/google_signup.php | 40 ++++ views/{ => login}/login.php | 4 + views/{signup => login}/signup.php | 4 + web.php | 12 +- 12 files changed, 345 insertions(+), 178 deletions(-) create mode 100644 mail/signup-noconfirm.html delete mode 100644 src/Controller/SignupController.php rename views/{signup => login}/activate.php (100%) rename views/{signup => login}/cancel.php (100%) create mode 100644 views/login/google_login.php create mode 100644 views/login/google_signup.php rename views/{ => login}/login.php (81%) rename views/{signup => login}/signup.php (84%) diff --git a/mail/signup-noconfirm.html b/mail/signup-noconfirm.html new file mode 100644 index 0000000..8c00ae0 --- /dev/null +++ b/mail/signup-noconfirm.html @@ -0,0 +1,9 @@ +Hi, +

+You recently signed up on MapGuesser with this Google account ({{EMAIL}}). +

+Have fun on MapGuesser! +

+Regards,
+MapGuesser
+{{BASE_URL}} diff --git a/mail/signup.html b/mail/signup.html index 480e0c1..629d774 100644 --- a/mail/signup.html +++ b/mail/signup.html @@ -10,4 +10,5 @@ However if you want to immediately delete it, please click on the following link Have fun on MapGuesser!

Regards,
-MapGuesser +MapGuesser
+{{BASE_URL}} diff --git a/public/static/css/mapguesser.css b/public/static/css/mapguesser.css index c492c19..0663d22 100644 --- a/public/static/css/mapguesser.css +++ b/public/static/css/mapguesser.css @@ -107,6 +107,10 @@ hr { margin-right: 10px; } +.center { + text-align: center; +} + .right { text-align: right; } diff --git a/src/Controller/LoginController.php b/src/Controller/LoginController.php index f83633d..be27d43 100644 --- a/src/Controller/LoginController.php +++ b/src/Controller/LoginController.php @@ -3,31 +3,84 @@ use MapGuesser\Interfaces\Request\IRequest; use MapGuesser\Interfaces\Response\IContent; use MapGuesser\Interfaces\Response\IRedirect; +use MapGuesser\Mailing\Mail; +use MapGuesser\OAuth\GoogleOAuth; +use MapGuesser\PersistentData\Model\User; +use MapGuesser\PersistentData\Model\UserConfirmation; +use MapGuesser\PersistentData\PersistentDataManager; +use MapGuesser\Repository\UserConfirmationRepository; use MapGuesser\Repository\UserRepository; use MapGuesser\Response\HtmlContent; use MapGuesser\Response\JsonContent; use MapGuesser\Response\Redirect; +use MapGuesser\Util\JwtParser; class LoginController { private IRequest $request; + private PersistentDataManager $pdm; + private UserRepository $userRepository; + private UserConfirmationRepository $userConfirmationRepository; + public function __construct(IRequest $request) { $this->request = $request; + $this->pdm = new PersistentDataManager(); $this->userRepository = new UserRepository(); + $this->userConfirmationRepository = new UserConfirmationRepository(); } public function getLoginForm() { if ($this->request->user() !== null) { - return new Redirect([\Container::$routeCollection->getRoute('index'), []], IRedirect::TEMPORARY); + return new Redirect(\Container::$routeCollection->getRoute('index')->generateLink(), IRedirect::TEMPORARY); } $data = []; - return new HtmlContent('login', $data); + return new HtmlContent('login/login', $data); + } + + public function getGoogleLoginRedirect() + { + $state = bin2hex(random_bytes(16)); + + $this->request->session()->set('oauth_state', $state); + + $oAuth = new GoogleOAuth(); + $url = $oAuth->getDialogUrl($state, $this->request->getBase() . '/' . \Container::$routeCollection->getRoute('login-google-action')->generateLink()); + + return new Redirect($url, IRedirect::TEMPORARY); + } + + public function getSignupForm() + { + if ($this->request->user() !== null) { + return new Redirect(\Container::$routeCollection->getRoute('index')->generateLink(), IRedirect::TEMPORARY); + } + + $data = []; + return new HtmlContent('login/signup', $data); + } + + public function getSignupWithGoogleForm() + { + if ($this->request->user() !== null) { + return new Redirect(\Container::$routeCollection->getRoute('index')->generateLink(), IRedirect::TEMPORARY); + } + + if (!$this->request->session()->has('google_user_data')) { + return new Redirect(\Container::$routeCollection->getRoute('login-google')->generateLink(), IRedirect::TEMPORARY); + } + + $userData = $this->request->session()->get('google_user_data'); + + $user = $this->userRepository->getByEmail($userData['email']); + + $data = ['found' => $user !== null, 'email' => $userData['email']]; + return new HtmlContent('login/google_signup', $data); } public function login(): IContent @@ -60,10 +113,219 @@ class LoginController return new JsonContent($data); } + public function loginWithGoogle() + { + if ($this->request->user() !== null) { + return new Redirect(\Container::$routeCollection->getRoute('index')->generateLink(), IRedirect::TEMPORARY); + } + + if ($this->request->query('state') !== $this->request->session()->get('oauth_state')) { + $data = []; + return new HtmlContent('login/google_login', $data); + } + + $oAuth = new GoogleOAuth(); + $tokenData = $oAuth->getToken($this->request->query('code'), $this->request->getBase() . '/' . \Container::$routeCollection->getRoute('login-google-action')->generateLink()); + + if (!isset($tokenData['id_token'])) { + $data = []; + return new HtmlContent('login/google_login', $data); + } + + $jwtParser = new JwtParser($tokenData['id_token']); + $userData = $jwtParser->getPayload(); + + if (!$userData['email_verified']) { + $data = []; + return new HtmlContent('login/google_login', $data); + } + + $user = $this->userRepository->getByGoogleSub($userData['sub']); + + if ($user === null) { + $this->request->session()->set('google_user_data', $userData); + + return new Redirect(\Container::$routeCollection->getRoute('signup-google')->generateLink(), IRedirect::TEMPORARY); + } + + $this->request->setUser($user); + + return new Redirect(\Container::$routeCollection->getRoute('index')->generateLink(), IRedirect::TEMPORARY); + } + public function logout(): IRedirect { $this->request->setUser(null); - return new Redirect([\Container::$routeCollection->getRoute('index'), []], IRedirect::TEMPORARY); + return new Redirect(\Container::$routeCollection->getRoute('index')->generateLink(), IRedirect::TEMPORARY); + } + + public function signup(): IContent + { + if ($this->request->user() !== null) { + $data = ['error' => 'logged_in']; + return new JsonContent($data); + } + + if (filter_var($this->request->post('email'), FILTER_VALIDATE_EMAIL) === false) { + $data = ['error' => 'email_not_valid']; + return new JsonContent($data); + } + + $user = $this->userRepository->getByEmail($this->request->post('email')); + + if ($user !== null) { + 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(); + $user->setEmail($this->request->post('email')); + $user->setPlainPassword($this->request->post('password')); + + \Container::$dbConnection->startTransaction(); + + $this->pdm->saveToDb($user); + + $token = hash('sha256', serialize($user) . random_bytes(10) . microtime()); + + $confirmation = new UserConfirmation(); + $confirmation->setUser($user); + $confirmation->setToken($token); + + $this->pdm->saveToDb($confirmation); + + \Container::$dbConnection->commit(); + + $this->sendConfirmationEmail($user->getEmail(), $token); + + $data = ['success' => true]; + return new JsonContent($data); + } + + public function signupWithGoogle() + { + if ($this->request->user() !== null) { + $data = ['success' => true]; + return new JsonContent($data); + } + + $userData = $this->request->session()->get('google_user_data'); + + $user = $this->userRepository->getByEmail($userData['email']); + + if ($user === null) { + $user = new User(); + $user->setEmail($userData['email']); + } + + $user->setActive(true); + $user->setGoogleSub($userData['sub']); + + $this->pdm->saveToDb($user); + + $this->sendWelcomeEmail($user->getEmail()); + + $this->request->session()->delete('google_user_data'); + $this->request->setUser($user); + + $data = ['success' => true]; + return new JsonContent($data); + } + + public function activate() + { + if ($this->request->user() !== null) { + return new Redirect(\Container::$routeCollection->getRoute('index')->generateLink(), IRedirect::TEMPORARY); + } + + $confirmation = $this->userConfirmationRepository->getByToken($this->request->query('token')); + + if ($confirmation === null) { + $data = []; + return new HtmlContent('login/activate', $data); + } + + \Container::$dbConnection->startTransaction(); + + $this->pdm->deleteFromDb($confirmation); + + $user = $this->userRepository->getById($confirmation->getUserId()); + $user->setActive(true); + + $this->pdm->saveToDb($user); + + \Container::$dbConnection->commit(); + + $this->request->setUser($user); + + return new Redirect(\Container::$routeCollection->getRoute('index')->generateLink(), IRedirect::TEMPORARY); + } + + public function cancel() + { + if ($this->request->user() !== null) { + return new Redirect(\Container::$routeCollection->getRoute('index')->generateLink(), IRedirect::TEMPORARY); + } + + $confirmation = $this->userConfirmationRepository->getByToken($this->request->query('token')); + + if ($confirmation === null) { + $data = ['success' => false]; + return new HtmlContent('login/cancel', $data); + } + + \Container::$dbConnection->startTransaction(); + + $this->pdm->deleteFromDb($confirmation); + + $user = $this->userRepository->getById($confirmation->getUserId()); + + $this->pdm->deleteFromDb($user); + + \Container::$dbConnection->commit(); + + $data = ['success' => true]; + return new HtmlContent('login/cancel', $data); + } + + private function sendConfirmationEmail(string $email, string $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() . '/'. \Container::$routeCollection->getRoute('signup.activate')->generateLink(['token' => $token]), + 'CANCEL_LINK' => $this->request->getBase() . '/' . \Container::$routeCollection->getRoute('signup.cancel')->generateLink(['token' => $token]), + 'BASE_URL' => $this->request->getBase(), + ]); + $mail->send(); + } + + private function sendWelcomeEmail(string $email): void + { + $mail = new Mail(); + $mail->addRecipient($email); + $mail->setSubject('Welcome to MapGuesser'); + $mail->setBodyFromTemplate('signup-noconfirm', [ + 'EMAIL' => $email, + 'BASE_URL' => $this->request->getBase(), + ]); + $mail->send(); } } diff --git a/src/Controller/SignupController.php b/src/Controller/SignupController.php deleted file mode 100644 index 77b3197..0000000 --- a/src/Controller/SignupController.php +++ /dev/null @@ -1,170 +0,0 @@ -request = $request; - $this->pdm = new PersistentDataManager(); - $this->userRepository = new UserRepository(); - $this->userConfirmationRepository = new UserConfirmationRepository(); - } - - public function getSignupForm() - { - if ($this->request->user() !== null) { - return new Redirect([\Container::$routeCollection->getRoute('index'), []], IRedirect::TEMPORARY); - } - - $data = []; - return new HtmlContent('signup/signup', $data); - } - - public function signup(): IContent - { - if ($this->request->user() !== null) { - //TODO: return with some error - $data = ['success' => true]; - return new JsonContent($data); - } - - if (filter_var($this->request->post('email'), FILTER_VALIDATE_EMAIL) === false) { - $data = ['error' => 'email_not_valid']; - return new JsonContent($data); - } - - $user = $this->userRepository->getByEmail($this->request->post('email')); - - if ($user !== null) { - 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(); - $user->setEmail($this->request->post('email')); - $user->setPlainPassword($this->request->post('password')); - - \Container::$dbConnection->startTransaction(); - - $this->pdm->saveToDb($user); - - $token = hash('sha256', serialize($user) . random_bytes(10) . microtime()); - - $confirmation = new UserConfirmation(); - $confirmation->setUser($user); - $confirmation->setToken($token); - - $this->pdm->saveToDb($confirmation); - - \Container::$dbConnection->commit(); - - $this->sendConfirmationEmail($user->getEmail(), $token); - - $data = ['success' => true]; - return new JsonContent($data); - } - - public function activate() - { - if ($this->request->user() !== null) { - return new Redirect([\Container::$routeCollection->getRoute('index'), []], IRedirect::TEMPORARY); - } - - $confirmation = $this->userConfirmationRepository->getByToken($this->request->query('token')); - - if ($confirmation === null) { - $data = []; - return new HtmlContent('signup/activate', $data); - } - - \Container::$dbConnection->startTransaction(); - - $this->pdm->deleteFromDb($confirmation); - - $user = $this->userRepository->getById($confirmation->getUserId()); - $user->setActive(true); - - $this->pdm->saveToDb($user); - - \Container::$dbConnection->commit(); - - $this->request->setUser($user); - - return new Redirect([\Container::$routeCollection->getRoute('index'), []], IRedirect::TEMPORARY); - } - - public function cancel() - { - if ($this->request->user() !== null) { - return new Redirect([\Container::$routeCollection->getRoute('index'), []], IRedirect::TEMPORARY); - } - - $confirmation = $this->userConfirmationRepository->getByToken($this->request->query('token')); - - if ($confirmation === null) { - $data = ['success' => false]; - return new HtmlContent('signup/cancel', $data); - } - - \Container::$dbConnection->startTransaction(); - - $this->pdm->deleteFromDb($confirmation); - - $user = $this->userRepository->getById($confirmation->getUserId()); - - $this->pdm->deleteFromDb($user); - - \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(); - } -} diff --git a/views/signup/activate.php b/views/login/activate.php similarity index 100% rename from views/signup/activate.php rename to views/login/activate.php diff --git a/views/signup/cancel.php b/views/login/cancel.php similarity index 100% rename from views/signup/cancel.php rename to views/login/cancel.php diff --git a/views/login/google_login.php b/views/login/google_login.php new file mode 100644 index 0000000..334857b --- /dev/null +++ b/views/login/google_login.php @@ -0,0 +1,9 @@ + + +
+

Login up with Google

+
+

Authenticating with Google failed. Please retry!

+
+
+ \ No newline at end of file diff --git a/views/login/google_signup.php b/views/login/google_signup.php new file mode 100644 index 0000000..b4851f7 --- /dev/null +++ b/views/login/google_signup.php @@ -0,0 +1,40 @@ + + +
+

Sign up

+
+
+ +

Please confirm that you link your account to your Google account.

+ +

Please confirm your sign up request. Your account will be linked to your Google account.

+ + +
+ +
+
+
+
+ + \ No newline at end of file diff --git a/views/login.php b/views/login/login.php similarity index 81% rename from views/login.php rename to views/login/login.php index 1dfdd94..c5bc6af 100644 --- a/views/login.php +++ b/views/login/login.php @@ -15,6 +15,10 @@ $jsFiles = [
+
+ diff --git a/views/signup/signup.php b/views/login/signup.php similarity index 84% rename from views/signup/signup.php rename to views/login/signup.php index c2c12bc..0dc8fcb 100644 --- a/views/signup/signup.php +++ b/views/login/signup.php @@ -16,6 +16,10 @@ $jsFiles = [
+
+ diff --git a/web.php b/web.php index 9d1ff68..044974f 100644 --- a/web.php +++ b/web.php @@ -15,10 +15,14 @@ Container::$routeCollection = new MapGuesser\Routing\RouteCollection(); 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('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('login-google', 'login/google', [MapGuesser\Controller\LoginController::class, 'getGoogleLoginRedirect']); +Container::$routeCollection->get('login-google-action', 'login/google/code', [MapGuesser\Controller\LoginController::class, 'loginWithGoogle']); +Container::$routeCollection->get('signup', 'signup', [MapGuesser\Controller\LoginController::class, 'getSignupForm']); +Container::$routeCollection->post('signup-action', 'signup', [MapGuesser\Controller\LoginController::class, 'signup']); +Container::$routeCollection->get('signup-google', 'signup/google', [MapGuesser\Controller\LoginController::class, 'getSignupWithGoogleForm']); +Container::$routeCollection->post('signup-google-action', 'signup/google', [MapGuesser\Controller\LoginController::class, 'signupWithGoogle']); +Container::$routeCollection->get('signup.activate', 'signup/activate/{token}', [MapGuesser\Controller\LoginController::class, 'activate']); +Container::$routeCollection->get('signup.cancel', 'signup/cancel/{token}', [MapGuesser\Controller\LoginController::class, 'cancel']); Container::$routeCollection->get('logout', 'logout', [MapGuesser\Controller\LoginController::class, 'logout']); Container::$routeCollection->get('profile', 'profile', [MapGuesser\Controller\UserController::class, 'getProfile']); Container::$routeCollection->post('profile-action', 'profile', [MapGuesser\Controller\UserController::class, 'saveProfile']); From 10b77664580d1e16999389eaa175a7ad47e58f6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=91cze=20Bence?= Date: Sun, 21 Jun 2020 12:55:49 +0200 Subject: [PATCH 07/13] MAPG-69 redirect to sign up when user not found during login --- public/static/js/login.js | 9 +++-- public/static/js/profile.js | 2 +- public/static/js/signup.js | 11 +++--- src/Controller/LoginController.php | 54 +++++++++++++++++++++++++----- src/Controller/UserController.php | 2 +- views/login/signup.php | 12 +++++-- views/login/signup_success.php | 9 +++++ web.php | 1 + 8 files changed, 78 insertions(+), 22 deletions(-) create mode 100644 views/login/signup_success.php diff --git a/public/static/js/login.js b/public/static/js/login.js index 0044488..cb97b3c 100644 --- a/public/static/js/login.js +++ b/public/static/js/login.js @@ -10,10 +10,15 @@ MapGuesser.httpRequest('POST', form.action, function () { if (this.response.error) { + if (this.response.error === 'user_not_found') { + window.location.replace('/signup'); + return; + } + var errorText; switch (this.response.error) { - case 'user_not_found': - errorText = 'No user found with the given email address. You can sign up here!'; + case 'password_too_short': + errorText = 'The given password is too short. Please choose a password that is at least 6 characters long!' break; case 'user_not_active': errorText = 'User found with the given email address, but the account is not activated. Please check your email and click on the activation link!'; diff --git a/public/static/js/profile.js b/public/static/js/profile.js index aff3137..0c2a2d3 100644 --- a/public/static/js/profile.js +++ b/public/static/js/profile.js @@ -25,7 +25,7 @@ case 'password_not_match': errorText = 'The given current password is wrong.' break; - case 'passwords_too_short': + case 'password_too_short': errorText = 'The given new password is too short. Please choose a password that is at least 6 characters long!' break; case 'passwords_not_match': diff --git a/public/static/js/signup.js b/public/static/js/signup.js index d4674f2..339713f 100644 --- a/public/static/js/signup.js +++ b/public/static/js/signup.js @@ -9,15 +9,13 @@ 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 'email_not_valid': errorText = 'The given email address is not valid.' break; - case 'passwords_too_short': + case 'password_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': @@ -31,6 +29,8 @@ break; } + document.getElementById('loading').style.visibility = 'hidden'; + var signupFormError = document.getElementById('signupFormError'); signupFormError.style.display = 'block'; signupFormError.innerHTML = errorText; @@ -38,10 +38,7 @@ return; } - document.getElementById('signupFormError').style.display = 'none'; - form.reset(); - - MapGuesser.showModalWithContent('Sign up successful', 'Sign up was successful. Please check your email and click on the activation link to activate your account!'); + window.location.replace('/signup/success'); }, formData); }; })(); diff --git a/src/Controller/LoginController.php b/src/Controller/LoginController.php index be27d43..5be2e92 100644 --- a/src/Controller/LoginController.php +++ b/src/Controller/LoginController.php @@ -61,10 +61,23 @@ class LoginController return new Redirect(\Container::$routeCollection->getRoute('index')->generateLink(), IRedirect::TEMPORARY); } - $data = []; + if ($this->request->session()->has('tmp_user_data')) { + $tmpUserData = $this->request->session()->get('tmp_user_data'); + + $data = ['email' => $tmpUserData['email']]; + } else { + $data = []; + } + return new HtmlContent('login/signup', $data); } + public function getSignupSuccess() + { + $data = []; + return new HtmlContent('login/signup_success', $data); + } + public function getSignupWithGoogleForm() { if ($this->request->user() !== null) { @@ -93,6 +106,16 @@ class LoginController $user = $this->userRepository->getByEmail($this->request->post('email')); if ($user === null) { + if (strlen($this->request->post('password')) < 6) { + $data = ['error' => 'password_too_short']; + return new JsonContent($data); + } + + $tmpUser = new User(); + $tmpUser->setPlainPassword($this->request->post('password')); + + $this->request->session()->set('tmp_user_data', ['email' => $this->request->post('email'), 'password_hashed' => $tmpUser->getPassword()]); + $data = ['error' => 'user_not_found']; return new JsonContent($data); } @@ -183,14 +206,27 @@ class LoginController 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); + if ($this->request->session()->has('tmp_user_data')) { + $tmpUserData = $this->request->session()->get('tmp_user_data'); + + $tmpUser = new User(); + $tmpUser->setPassword($tmpUserData['password_hashed']); + + if (!$tmpUser->checkPassword($this->request->post('password'))) { + $data = ['error' => 'passwords_not_match']; + return new JsonContent($data); + } + } else { + if (strlen($this->request->post('password')) < 6) { + $data = ['error' => 'password_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(); @@ -213,6 +249,8 @@ class LoginController $this->sendConfirmationEmail($user->getEmail(), $token); + $this->request->session()->delete('tmp_user_data'); + $data = ['success' => true]; return new JsonContent($data); } diff --git a/src/Controller/UserController.php b/src/Controller/UserController.php index 778217a..14ed237 100644 --- a/src/Controller/UserController.php +++ b/src/Controller/UserController.php @@ -52,7 +52,7 @@ class UserController implements ISecured if (strlen($this->request->post('password_new')) > 0) { if (strlen($this->request->post('password_new')) < 6) { - $data = ['error' => 'passwords_too_short']; + $data = ['error' => 'password_too_short']; return new JsonContent($data); } diff --git a/views/login/signup.php b/views/login/signup.php index 0dc8fcb..89dcba5 100644 --- a/views/login/signup.php +++ b/views/login/signup.php @@ -9,9 +9,15 @@ $jsFiles = [

Sign up

- - - + +

No user found with the given email address. Sign up with one click!

+ + + + + + +

diff --git a/views/login/signup_success.php b/views/login/signup_success.php new file mode 100644 index 0000000..2d7111d --- /dev/null +++ b/views/login/signup_success.php @@ -0,0 +1,9 @@ + + +
+

Sign up

+
+

Sign up was successful. Please check your email and click on the activation link to activate your account!

+
+
+ \ No newline at end of file diff --git a/web.php b/web.php index 044974f..81689f7 100644 --- a/web.php +++ b/web.php @@ -21,6 +21,7 @@ Container::$routeCollection->get('signup', 'signup', [MapGuesser\Controller\Logi Container::$routeCollection->post('signup-action', 'signup', [MapGuesser\Controller\LoginController::class, 'signup']); Container::$routeCollection->get('signup-google', 'signup/google', [MapGuesser\Controller\LoginController::class, 'getSignupWithGoogleForm']); Container::$routeCollection->post('signup-google-action', 'signup/google', [MapGuesser\Controller\LoginController::class, 'signupWithGoogle']); +Container::$routeCollection->get('signup.success', 'signup/success', [MapGuesser\Controller\LoginController::class, 'getSignupSuccess']); Container::$routeCollection->get('signup.activate', 'signup/activate/{token}', [MapGuesser\Controller\LoginController::class, 'activate']); Container::$routeCollection->get('signup.cancel', 'signup/cancel/{token}', [MapGuesser\Controller\LoginController::class, 'cancel']); Container::$routeCollection->get('logout', 'logout', [MapGuesser\Controller\LoginController::class, 'logout']); From 285f2dd0acfcf66ceb0fdbcc6cc6f5830ad135e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=91cze=20Bence?= Date: Sun, 21 Jun 2020 13:40:36 +0200 Subject: [PATCH 08/13] MAPG-69 login user when trying to sign up --- public/static/js/signup.js | 13 +++++++++---- src/Controller/LoginController.php | 18 ++++++++++++------ views/login/signup.php | 2 +- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/public/static/js/signup.js b/public/static/js/signup.js index 339713f..f97fa9e 100644 --- a/public/static/js/signup.js +++ b/public/static/js/signup.js @@ -10,6 +10,11 @@ MapGuesser.httpRequest('POST', form.action, function () { if (this.response.error) { + if (this.response.error === 'user_found') { + window.location.replace('/'); + return; + } + var errorText; switch (this.response.error) { case 'email_not_valid': @@ -21,12 +26,12 @@ 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 login here!'; - break; - case 'not_active_user_found': + case 'user_found_user_not_active': errorText = 'There is a user already registered with the given email address. Please check your email and click on the activation link!'; break; + case 'user_found_password_not_match': + errorText = 'There is a user already registered with the given email address, but the given password is wrong.' + break; } document.getElementById('loading').style.visibility = 'hidden'; diff --git a/src/Controller/LoginController.php b/src/Controller/LoginController.php index 5be2e92..dc280e6 100644 --- a/src/Controller/LoginController.php +++ b/src/Controller/LoginController.php @@ -190,22 +190,28 @@ class LoginController return new JsonContent($data); } - if (filter_var($this->request->post('email'), FILTER_VALIDATE_EMAIL) === false) { - $data = ['error' => 'email_not_valid']; - return new JsonContent($data); - } - $user = $this->userRepository->getByEmail($this->request->post('email')); if ($user !== null) { if ($user->getActive()) { + if (!$user->checkPassword($this->request->post('password'))) { + $data = ['error' => 'user_found_password_not_match']; + return new JsonContent($data); + } + + $this->request->setUser($user); + $data = ['error' => 'user_found']; } else { - $data = ['error' => 'not_active_user_found']; + $data = ['error' => 'user_found_user_not_active']; } return new JsonContent($data); } + if (filter_var($this->request->post('email'), FILTER_VALIDATE_EMAIL) === false) { + $data = ['error' => 'email_not_valid']; + return new JsonContent($data); + } if ($this->request->session()->has('tmp_user_data')) { $tmpUserData = $this->request->session()->get('tmp_user_data'); diff --git a/views/login/signup.php b/views/login/signup.php index 89dcba5..9f4e295 100644 --- a/views/login/signup.php +++ b/views/login/signup.php @@ -16,7 +16,7 @@ $jsFiles = [ - +

From a8777b897b9d5483cb2f17be8c2449fe4159a620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=91cze=20Bence?= Date: Sun, 21 Jun 2020 14:36:00 +0200 Subject: [PATCH 09/13] MAPG-69 ability to reset signup filled after login attempt --- public/static/css/mapguesser.css | 6 ++++++ public/static/js/signup.js | 11 +++++++++++ src/Controller/LoginController.php | 8 ++++++++ views/login/signup.php | 7 +++++-- web.php | 1 + 5 files changed, 31 insertions(+), 2 deletions(-) diff --git a/public/static/css/mapguesser.css b/public/static/css/mapguesser.css index 0663d22..0d2cf8c 100644 --- a/public/static/css/mapguesser.css +++ b/public/static/css/mapguesser.css @@ -354,6 +354,12 @@ div.box { padding: 0; width: 100%; } + button.marginLeft, a.button.marginLeft { + margin-left: 0; + } + button.marginRight, a.button.marginRight { + margin-right: 0; + } div.modal { left: 20px; right: 20px; diff --git a/public/static/js/signup.js b/public/static/js/signup.js index f97fa9e..89e4209 100644 --- a/public/static/js/signup.js +++ b/public/static/js/signup.js @@ -46,4 +46,15 @@ window.location.replace('/signup/success'); }, formData); }; + + var resetSignupButton = document.getElementById('resetSignupButton'); + if (resetSignupButton) { + resetSignupButton.onclick = function () { + document.getElementById('loading').style.visibility = 'visible'; + + MapGuesser.httpRequest('POST', '/signup/reset', function () { + window.location.reload(); + }); + }; + } })(); diff --git a/src/Controller/LoginController.php b/src/Controller/LoginController.php index dc280e6..08664b8 100644 --- a/src/Controller/LoginController.php +++ b/src/Controller/LoginController.php @@ -291,6 +291,14 @@ class LoginController return new JsonContent($data); } + public function resetSignup(): IContent + { + $this->request->session()->delete('tmp_user_data'); + + $data = ['success' => true]; + return new JsonContent($data); + } + public function activate() { if ($this->request->user() !== null) { diff --git a/views/login/signup.php b/views/login/signup.php index 9f4e295..22ef35f 100644 --- a/views/login/signup.php +++ b/views/login/signup.php @@ -19,8 +19,11 @@ $jsFiles = [

-
- +
+ +

diff --git a/web.php b/web.php index 81689f7..c8c727c 100644 --- a/web.php +++ b/web.php @@ -21,6 +21,7 @@ Container::$routeCollection->get('signup', 'signup', [MapGuesser\Controller\Logi Container::$routeCollection->post('signup-action', 'signup', [MapGuesser\Controller\LoginController::class, 'signup']); Container::$routeCollection->get('signup-google', 'signup/google', [MapGuesser\Controller\LoginController::class, 'getSignupWithGoogleForm']); Container::$routeCollection->post('signup-google-action', 'signup/google', [MapGuesser\Controller\LoginController::class, 'signupWithGoogle']); +Container::$routeCollection->post('signup.reset', 'signup/reset', [MapGuesser\Controller\LoginController::class, 'resetSignup']); Container::$routeCollection->get('signup.success', 'signup/success', [MapGuesser\Controller\LoginController::class, 'getSignupSuccess']); Container::$routeCollection->get('signup.activate', 'signup/activate/{token}', [MapGuesser\Controller\LoginController::class, 'activate']); Container::$routeCollection->get('signup.cancel', 'signup/cancel/{token}', [MapGuesser\Controller\LoginController::class, 'cancel']); From 1cfbef418e61331154962a6917a2e4ef3b63467a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=91cze=20Bence?= Date: Sun, 21 Jun 2020 15:19:36 +0200 Subject: [PATCH 10/13] MAPG-69 add missing return types in LoginController --- src/Controller/LoginController.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Controller/LoginController.php b/src/Controller/LoginController.php index 08664b8..85e4420 100644 --- a/src/Controller/LoginController.php +++ b/src/Controller/LoginController.php @@ -43,7 +43,7 @@ class LoginController return new HtmlContent('login/login', $data); } - public function getGoogleLoginRedirect() + public function getGoogleLoginRedirect(): IRedirect { $state = bin2hex(random_bytes(16)); @@ -72,7 +72,7 @@ class LoginController return new HtmlContent('login/signup', $data); } - public function getSignupSuccess() + public function getSignupSuccess(): IContent { $data = []; return new HtmlContent('login/signup_success', $data); @@ -261,7 +261,7 @@ class LoginController return new JsonContent($data); } - public function signupWithGoogle() + public function signupWithGoogle(): IContent { if ($this->request->user() !== null) { $data = ['success' => true]; From 6338e35cfb538a817dffb78fcdb560e0d65f82b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=91cze=20Bence?= Date: Sun, 21 Jun 2020 15:29:02 +0200 Subject: [PATCH 11/13] MAPG-69 ability to cancel Google signup --- src/Controller/LoginController.php | 8 ++++++++ views/login/google_signup.php | 15 ++++++++++++--- web.php | 1 + 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/Controller/LoginController.php b/src/Controller/LoginController.php index 85e4420..400f95d 100644 --- a/src/Controller/LoginController.php +++ b/src/Controller/LoginController.php @@ -299,6 +299,14 @@ class LoginController return new JsonContent($data); } + public function resetGoogleSignup(): IContent + { + $this->request->session()->delete('google_user_data'); + + $data = ['success' => true]; + return new JsonContent($data); + } + public function activate() { if ($this->request->user() !== null) { diff --git a/views/login/google_signup.php b/views/login/google_signup.php index b4851f7..510cb08 100644 --- a/views/login/google_signup.php +++ b/views/login/google_signup.php @@ -10,14 +10,15 @@

Please confirm your sign up request. Your account will be linked to your Google account.

-
- +
@@ -35,6 +36,14 @@ window.location.replace('/'); }); }; + + document.getElementById('cancelGoogleSignupButton').onclick = function () { + document.getElementById('loading').style.visibility = 'visible'; + + MapGuesser.httpRequest('POST', '/signup/google/reset', function () { + window.location.replace('/signup'); + }); + }; })(); \ No newline at end of file diff --git a/web.php b/web.php index c8c727c..b4310b3 100644 --- a/web.php +++ b/web.php @@ -22,6 +22,7 @@ Container::$routeCollection->post('signup-action', 'signup', [MapGuesser\Control Container::$routeCollection->get('signup-google', 'signup/google', [MapGuesser\Controller\LoginController::class, 'getSignupWithGoogleForm']); Container::$routeCollection->post('signup-google-action', 'signup/google', [MapGuesser\Controller\LoginController::class, 'signupWithGoogle']); Container::$routeCollection->post('signup.reset', 'signup/reset', [MapGuesser\Controller\LoginController::class, 'resetSignup']); +Container::$routeCollection->post('signup-google.reset', 'signup/google/reset', [MapGuesser\Controller\LoginController::class, 'resetGoogleSignup']); Container::$routeCollection->get('signup.success', 'signup/success', [MapGuesser\Controller\LoginController::class, 'getSignupSuccess']); Container::$routeCollection->get('signup.activate', 'signup/activate/{token}', [MapGuesser\Controller\LoginController::class, 'activate']); Container::$routeCollection->get('signup.cancel', 'signup/cancel/{token}', [MapGuesser\Controller\LoginController::class, 'cancel']); From df60efbb8c11841c3347627b7bcda6cfa3919e41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=91cze=20Bence?= Date: Sun, 21 Jun 2020 15:43:49 +0200 Subject: [PATCH 12/13] MAPG-69 group routes to better overview --- web.php | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/web.php b/web.php index b4310b3..ac3041e 100644 --- a/web.php +++ b/web.php @@ -13,22 +13,28 @@ if (!empty($_ENV['DEV'])) { Container::$routeCollection = new MapGuesser\Routing\RouteCollection(); 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('login-google', 'login/google', [MapGuesser\Controller\LoginController::class, 'getGoogleLoginRedirect']); -Container::$routeCollection->get('login-google-action', 'login/google/code', [MapGuesser\Controller\LoginController::class, 'loginWithGoogle']); -Container::$routeCollection->get('signup', 'signup', [MapGuesser\Controller\LoginController::class, 'getSignupForm']); -Container::$routeCollection->post('signup-action', 'signup', [MapGuesser\Controller\LoginController::class, 'signup']); -Container::$routeCollection->get('signup-google', 'signup/google', [MapGuesser\Controller\LoginController::class, 'getSignupWithGoogleForm']); -Container::$routeCollection->post('signup-google-action', 'signup/google', [MapGuesser\Controller\LoginController::class, 'signupWithGoogle']); -Container::$routeCollection->post('signup.reset', 'signup/reset', [MapGuesser\Controller\LoginController::class, 'resetSignup']); -Container::$routeCollection->post('signup-google.reset', 'signup/google/reset', [MapGuesser\Controller\LoginController::class, 'resetGoogleSignup']); -Container::$routeCollection->get('signup.success', 'signup/success', [MapGuesser\Controller\LoginController::class, 'getSignupSuccess']); -Container::$routeCollection->get('signup.activate', 'signup/activate/{token}', [MapGuesser\Controller\LoginController::class, 'activate']); -Container::$routeCollection->get('signup.cancel', 'signup/cancel/{token}', [MapGuesser\Controller\LoginController::class, 'cancel']); +Container::$routeCollection->group('login', function (MapGuesser\Routing\RouteCollection $routeCollection) { + $routeCollection->get('login', '', [MapGuesser\Controller\LoginController::class, 'getLoginForm']); + $routeCollection->post('login-action', '', [MapGuesser\Controller\LoginController::class, 'login']); + $routeCollection->get('login-google', 'google', [MapGuesser\Controller\LoginController::class, 'getGoogleLoginRedirect']); + $routeCollection->get('login-google-action', 'google/code', [MapGuesser\Controller\LoginController::class, 'loginWithGoogle']); +}); +Container::$routeCollection->group('signup', function (MapGuesser\Routing\RouteCollection $routeCollection) { + $routeCollection->get('signup', '', [MapGuesser\Controller\LoginController::class, 'getSignupForm']); + $routeCollection->post('signup-action', '', [MapGuesser\Controller\LoginController::class, 'signup']); + $routeCollection->get('signup-google', 'google', [MapGuesser\Controller\LoginController::class, 'getSignupWithGoogleForm']); + $routeCollection->post('signup-google-action', 'google', [MapGuesser\Controller\LoginController::class, 'signupWithGoogle']); + $routeCollection->post('signup.reset', 'reset', [MapGuesser\Controller\LoginController::class, 'resetSignup']); + $routeCollection->post('signup-google.reset', 'google/reset', [MapGuesser\Controller\LoginController::class, 'resetGoogleSignup']); + $routeCollection->get('signup.success', 'success', [MapGuesser\Controller\LoginController::class, 'getSignupSuccess']); + $routeCollection->get('signup.activate', 'activate/{token}', [MapGuesser\Controller\LoginController::class, 'activate']); + $routeCollection->get('signup.cancel', 'cancel/{token}', [MapGuesser\Controller\LoginController::class, 'cancel']); +}); Container::$routeCollection->get('logout', 'logout', [MapGuesser\Controller\LoginController::class, 'logout']); -Container::$routeCollection->get('profile', 'profile', [MapGuesser\Controller\UserController::class, 'getProfile']); -Container::$routeCollection->post('profile-action', 'profile', [MapGuesser\Controller\UserController::class, 'saveProfile']); +Container::$routeCollection->group('profile', function (MapGuesser\Routing\RouteCollection $routeCollection) { + $routeCollection->get('profile', '', [MapGuesser\Controller\UserController::class, 'getProfile']); + $routeCollection->post('profile-action', '', [MapGuesser\Controller\UserController::class, 'saveProfile']); +}); 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']); From 87d476065df3ebed23f40199ec7d366ae8e81a72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=91cze=20Bence?= Date: Sun, 21 Jun 2020 15:44:40 +0200 Subject: [PATCH 13/13] MAPG-69 fix routing to handle emptry string properly --- public/index.php | 2 +- src/Routing/RouteCollection.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/index.php b/public/index.php index d025071..24595aa 100644 --- a/public/index.php +++ b/public/index.php @@ -9,7 +9,7 @@ if (($pos = strpos($url, '?')) !== false) { } $url = rawurldecode($url); -$match = Container::$routeCollection->match($method, explode('/', $url)); +$match = Container::$routeCollection->match($method, $url == '' ? [] : explode('/', $url)); if ($match !== null) { list($route, $params) = $match; diff --git a/src/Routing/RouteCollection.php b/src/Routing/RouteCollection.php index c729c3e..d93007a 100644 --- a/src/Routing/RouteCollection.php +++ b/src/Routing/RouteCollection.php @@ -64,7 +64,7 @@ class RouteCollection throw new \Exception('Route already exists: ' . $id); } - $pattern = array_merge($this->groupStack, explode('/', $pattern)); + $pattern = array_merge($this->groupStack, $pattern === '' ? [] : explode('/', $pattern)); $route = new Route($id, $pattern, $handler); $groupNumber = count($pattern);