Add register and login of authentification actions #12

Merged
samuel.berion merged 22 commits from connexion/bootstrap into master 1 year ago

@ -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

@ -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<CSSProperties>({});
const [style, setStyle] = useState<CSSProperties>({})
return (
<div id="main">
@ -20,5 +19,5 @@ export default function Visualizer({id, name}: { id: number; name: string }) {
/>
</div>
</div>
);
)
}

@ -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));

@ -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,

@ -0,0 +1,94 @@
<?php
namespace App\Controller;
use App\Gateway\AuthGateway;
use App\Http\HttpRequest;
use App\Http\HttpResponse;
use App\Http\ViewHttpResponse;
use App\Model\AuthModel;
use App\Validation\FieldValidationFail;
use App\Validation\ValidationFail;
use App\Validation\Validators;
use Twig\Environment;
class AuthController {
private AuthModel $model;
/**
* @param AuthModel $model
*/
public function __construct(AuthModel $model) {
$this->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);
}
}

@ -0,0 +1,47 @@
<?php
namespace App\Gateway;
use App\Connexion;
use PDO;
class AuthGateway {
private Connexion $con;
/**
* @param Connexion $con
*/
public function __construct(Connexion $con) {
$this->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<string,string>|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;
}
}

@ -0,0 +1,80 @@
<?php
namespace App\Model;
use App\Controller\AuthController;
use App\Gateway\AuthGateway;
use App\Validation\FieldValidationFail;
use App\Validation\ValidationFail;
class AuthModel {
private AuthGateway $gateway;
/**
* @param AuthGateway $gateway
*/
public function __construct(AuthGateway $gateway) {
$this->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<string,string>|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;
}
}

@ -0,0 +1,46 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Profil Utilisateur</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
display: flex;
align-items: start;
justify-content: center;
height: 100vh;
}
.user-profile {
background-color: #7FBFFF;
padding: 20px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
max-width: 400px;
width: 100%;
text-align: center;
}
h1 {
color: #333;
}
p {
color: #666;
}
</style>
</head>
<body>
<div class="user-profile">
<h1>Votre profil</h1>
<p><strong>Pseudo : </strong> {{ username }} </p>
<p><strong>Email : {{ email }} </strong></p>
</div>
</body>
</html>

@ -0,0 +1,85 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Connexion</title>
</head>
<body>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f1f1f1;
}
.container {
max-width: 400px;
margin: 0 auto;
padding: 20px;
background-color: #fff;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
h2 {
text-align: center;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 5px;
}
input[type="text"], input[type="password"] {
width: 100%;
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
}
input[type="submit"] {
background-color: #007bff;
color: #fff;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
}
input[type="submit"]:hover {
background-color: #0056b3;
}
{% for err in bad_fields %}
.form-group #{{ err }} {
border-color: red;
}
{% endfor %}
</style>
<div class="container">
<center><h2>Se connecter</h2></center>
<form action="login" method="post">
<div class="form-group">
<label for="email">Email :</label>
<input type="text" id="email" name="email" required>
<label for= "password">Mot de passe :</label>
<input type="password" id="password" name="password" required>
</div>
<div class="form-group">
<input type="submit" value="S'identifier">
</div>
</form>
</div>
</body>
</html>

@ -0,0 +1,88 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<title>S'enregistrer</title>
</head>
<body>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f1f1f1;
}
.container {
max-width: 400px;
margin: 0 auto;
padding: 20px;
background-color: #fff;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
h2 {
text-align: center;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 5px;
}
input[type="text"], input[type="password"] {
width: 100%;
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
}
input[type="submit"] {
background-color: #007bff;
color: #fff;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
}
input[type="submit"]:hover {
background-color: #0056b3;
}
{% for err in bad_fields %}
.form-group #{{ err }} {
border-color: red;
}
{% endfor %}
</style>
<div class="container">
<center><h2>S'enregistrer</h2></center>
<form action="register" method="post">
<div class="form-group">
<label for="username">Nom d'utilisateur :</label>
<input type="text" id="username" name="username" required>
<label for= "password">Mot de passe :</label>
<input type="password" id="password" name="password" required>
<label for="confirmpassword">Confirmer le mot de passe :</label>
<input type="password" id="confirmpassword" name="confirmpassword" required>
<label for="email">Email :</label>
<input type="text" id="email" name="email" required>
</div>
<div class="form-group">
<input type="submit" value="Confirmer">
</div>
</form>
</div>
</body>
</html>

@ -1,4 +1,3 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
@ -14,5 +13,6 @@
<p>description: {{ v.description }}</p>
{% endfor %}
</body>
</html>

@ -1,4 +1,3 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">

Loading…
Cancel
Save