diff --git a/Documentation/models.puml b/Documentation/models.puml index 1f4877a..d95343c 100755 --- a/Documentation/models.puml +++ b/Documentation/models.puml @@ -68,4 +68,30 @@ class Color { + getValue(): int } +class AuthController{ + + + displayRegister() : HttpResponse + + displayBadFields(viewName : string, fails : array) : HttpResponse + + confirmRegister(request : array) : HttpResponse + + displayLogin() : HttpResponse + + confirmLogin() : HttpResponse +} +AuthController --> "- model" AuthModel + +class AuthModel{ + + + register(username : string, password : string, confirmPassword : string, email : string): array + + getUserFields(email : string):array + + login(email : string, password : string) +} +AuthModel --> "- gateway" AuthGateway + +class AuthGateway{ + -con : Connection + + + mailExist(email : string) : bool + + insertAccount(username : string, hash : string, email : string) + + getUserHash(email : string):string + + getUserFields (email : string): array +} @enduml \ No newline at end of file diff --git a/front/views/Visualizer.tsx b/front/views/Visualizer.tsx index ddf7fe2..541da09 100644 --- a/front/views/Visualizer.tsx +++ b/front/views/Visualizer.tsx @@ -2,9 +2,8 @@ import React, { CSSProperties, useState } from "react" import "../style/visualizer.css" import Court from "../assets/basketball_court.svg" - -export default function Visualizer({id, name}: { id: number; name: string }) { - const [style, setStyle] = useState({}); +export default function Visualizer({ id, name }: { id: number; name: string }) { + const [style, setStyle] = useState({}) return (
@@ -20,5 +19,5 @@ export default function Visualizer({id, name}: { id: number; name: string }) { />
- ); + ) } diff --git a/public/index.php b/public/index.php index 7f19f63..edc4cb3 100644 --- a/public/index.php +++ b/public/index.php @@ -14,6 +14,8 @@ use App\Http\JsonHttpResponse; use App\Http\ViewHttpResponse; use App\Model\TacticModel; use Twig\Loader\FilesystemLoader; +use App\Gateway\AuthGateway; +use App\Controller\AuthController; use App\Validation\ValidationFail; use App\Controller\ErrorController; use App\Controller\VisualizerController; @@ -29,6 +31,8 @@ $router = new AltoRouter(); $router->setBasePath($basePath); $sampleFormController = new SampleFormController(new FormResultGateway($con)); +$authGateway = new AuthGateway($con); +$authController = new \App\Controller\AuthController(new \App\Model\AuthModel($authGateway)); $editorController = new EditorController(new TacticModel(new TacticInfoGateway($con))); $visualizerController = new VisualizerController(new TacticModel(new TacticInfoGateway($con))); @@ -37,6 +41,10 @@ $router->map("GET", "/", fn() => $sampleFormController->displayFormReact()); $router->map("POST", "/submit", fn() => $sampleFormController->submitFormReact($_POST)); $router->map("GET", "/twig", fn() => $sampleFormController->displayFormTwig()); $router->map("POST", "/submit-twig", fn() => $sampleFormController->submitFormTwig($_POST)); +$router->map("GET", "/register", fn() => $authController->displayRegister()); +$router->map("POST", "/register", fn() => $authController->confirmRegister($_POST)); +$router->map("GET", "/login", fn() => $authController->displayLogin()); +$router->map("POST", "/login", fn() => $authController->confirmLogin($_POST)); $router->map("GET", "/tactic/new", fn() => $editorController->makeNew()); $router->map("GET", "/tactic/[i:id]/edit", fn(int $id) => $editorController->openEditorFor($id)); $router->map("GET", "/tactic/[i:id]", fn(int $id) => $visualizerController->openVisualizer($id)); diff --git a/sql/setup-tables.sql b/sql/setup-tables.sql index 068c2e1..108b62a 100644 --- a/sql/setup-tables.sql +++ b/sql/setup-tables.sql @@ -1,9 +1,15 @@ -- drop tables here DROP TABLE IF EXISTS FormEntries; +DROP TABLE IF EXISTS AccountUser; DROP TABLE IF EXISTS TacticInfo; CREATE TABLE FormEntries(name varchar, description varchar); +CREATE TABLE AccountUser( + username varchar, + hash varchar, + email varchar unique +); CREATE TABLE TacticInfo( id integer PRIMARY KEY AUTOINCREMENT, diff --git a/src/Controller/AuthController.php b/src/Controller/AuthController.php new file mode 100644 index 0000000..e42c27d --- /dev/null +++ b/src/Controller/AuthController.php @@ -0,0 +1,94 @@ +model = $model; + } + + public function displayRegister(): HttpResponse { + return ViewHttpResponse::twig("display_register.html.twig", []); + } + + /** + * @param string $viewName + * @param ValidationFail[] $fails + * @return HttpResponse + */ + private function displayBadFields(string $viewName, array $fails): HttpResponse { + $bad_fields = []; + foreach ($fails as $err) { + if ($err instanceof FieldValidationFail) { + $bad_fields[] = $err->getFieldName(); + } + } + return ViewHttpResponse::twig($viewName, ['bad_fields' => $bad_fields]); + } + + /** + * @param mixed[] $request + * @return HttpResponse + */ + public function confirmRegister(array $request): HttpResponse { + $fails = []; + $request = HttpRequest::from($request, $fails, [ + "username" => [Validators::name(), Validators::lenBetween(2, 32)], + "password" => [Validators::lenBetween(6, 256)], + "confirmpassword" => [Validators::lenBetween(6, 256)], + "email" => [Validators::regex("/^\\S+@\\S+\\.\\S+$/"),Validators::lenBetween(5, 256)], + ]); + if (!empty($fails)) { + return $this->displayBadFields("display_register.html.twig", $fails); + } + $fails = $this->model->register($request['username'], $request["password"], $request['confirmpassword'], $request['email']); + if (empty($fails)) { + $results = $this->model->getUserFields($request['email']); + return ViewHttpResponse::twig("display_auth_confirm.html.twig", ['username' => $results['username'], 'email' => $results['email']]); + } + return $this->displayBadFields("display_register.html.twig", $fails); + } + + + public function displayLogin(): HttpResponse { + return ViewHttpResponse::twig("display_login.html.twig", []); + } + + /** + * @param mixed[] $request + * @return HttpResponse + */ + public function confirmLogin(array $request): HttpResponse { + $fails = []; + $request = HttpRequest::from($request, $fails, [ + "password" => [Validators::lenBetween(6, 256)], + "email" => [Validators::regex("/^\\S+@\\S+\\.\\S+$/"),Validators::lenBetween(5, 256)], + ]); + if (!empty($fails)) { + return $this->displayBadFields("display_login.html.twig", $fails); + } + + $fails = $this->model->login($request['email'], $request['password']); + if (empty($fails)) { + $results = $this->model->getUserFields($request['email']); + return ViewHttpResponse::twig("display_auth_confirm.html.twig", ['username' => $results['username'], 'email' => $results['email']]); + } + return $this->displayBadFields("display_login.html.twig", $fails); + } + +} diff --git a/src/Gateway/AuthGateway.php b/src/Gateway/AuthGateway.php new file mode 100644 index 0000000..5acc01c --- /dev/null +++ b/src/Gateway/AuthGateway.php @@ -0,0 +1,47 @@ +con = $con; + } + + + public function mailExist(string $email): bool { + return $this->getUserFields($email) != null; + } + + + public function insertAccount(string $username, string $hash, string $email): void { + $this->con->exec("INSERT INTO AccountUser VALUES (:username,:hash,:email)", [':username' => [$username, PDO::PARAM_STR],':hash' => [$hash, PDO::PARAM_STR],':email' => [$email, PDO::PARAM_STR]]); + } + + public function getUserHash(string $email): string { + $results = $this->con->fetch("SELECT hash FROM AccountUser WHERE email = :email", [':email' => [$email, PDO::PARAM_STR]]); + return $results[0]['hash']; + } + + + /** + * @param string $email + * @return array|null + */ + public function getUserFields(string $email): ?array { + $results = $this->con->fetch("SELECT username,email FROM AccountUser WHERE email = :email", [':email' => [$email, PDO::PARAM_STR]]); + $firstRow = $results[0] ?? null; + return $firstRow; + } + + + + +} diff --git a/src/Model/AuthModel.php b/src/Model/AuthModel.php new file mode 100644 index 0000000..45b63e4 --- /dev/null +++ b/src/Model/AuthModel.php @@ -0,0 +1,80 @@ +gateway = $gateway; + } + + + /** + * @param string $username + * @param string $password + * @param string $confirmPassword + * @param string $email + * @return ValidationFail[] + */ + public function register(string $username, string $password, string $confirmPassword, string $email): array { + $errors = []; + + if ($password != $confirmPassword) { + $errors[] = new FieldValidationFail("confirmpassword", "password and password confirmation are not equals"); + } + + if ($this->gateway->mailExist($email)) { + $errors[] = new FieldValidationFail("email", "email already exist"); + } + + if(empty($errors)) { + $hash = password_hash($password, PASSWORD_DEFAULT); + $this->gateway->insertAccount($username, $hash, $email); + } + + return $errors; + } + + /** + * @param string $email + * @return array|null + */ + public function getUserFields(string $email): ?array { + return $this->gateway->getUserFields($email); + } + + + /** + * @param string $email + * @param string $password + * @return ValidationFail[] $errors + */ + public function login(string $email, string $password): array { + $errors = []; + + if (!$this->gateway->mailExist($email)) { + $errors[] = new FieldValidationFail("email", "email doesnt exists"); + return $errors; + } + $hash = $this->gateway->getUserHash($email); + + if (!password_verify($password, $hash)) { + $errors[] = new FieldValidationFail("password", "invalid password"); + } + + return $errors; + } + + + + + +} diff --git a/src/Views/display_auth_confirm.html.twig b/src/Views/display_auth_confirm.html.twig new file mode 100644 index 0000000..60c63b2 --- /dev/null +++ b/src/Views/display_auth_confirm.html.twig @@ -0,0 +1,46 @@ + + + + + Profil Utilisateur + + + + + + + + \ No newline at end of file diff --git a/src/Views/display_login.html.twig b/src/Views/display_login.html.twig new file mode 100644 index 0000000..33b2385 --- /dev/null +++ b/src/Views/display_login.html.twig @@ -0,0 +1,85 @@ + + + + Connexion + + + + + +
+

Se connecter

+
+
+ + + + + + +
+
+ +
+
+
+ + + + \ No newline at end of file diff --git a/src/Views/display_register.html.twig b/src/Views/display_register.html.twig new file mode 100644 index 0000000..40199a0 --- /dev/null +++ b/src/Views/display_register.html.twig @@ -0,0 +1,88 @@ + + + + S'enregistrer + + + + + +
+

S'enregistrer

+
+
+ + + + + + + + + +
+
+ +
+
+
+ + + + \ No newline at end of file diff --git a/src/Views/display_results.html.twig b/src/Views/display_results.html.twig index 6d2aef0..a33546b 100644 --- a/src/Views/display_results.html.twig +++ b/src/Views/display_results.html.twig @@ -1,4 +1,3 @@ - @@ -14,5 +13,6 @@

description: {{ v.description }}

{% endfor %} + \ No newline at end of file diff --git a/src/Views/sample_form.html.twig b/src/Views/sample_form.html.twig index bcb958e..6f4a9b5 100644 --- a/src/Views/sample_form.html.twig +++ b/src/Views/sample_form.html.twig @@ -1,4 +1,3 @@ -