Creation page d'accueil
parent
c3c5d28aff
commit
795c89b9e6
@ -1,7 +1,7 @@
|
|||||||
framework:
|
framework:
|
||||||
default_locale: en
|
default_locale: fr
|
||||||
translator:
|
translator:
|
||||||
default_path: '%kernel.project_dir%/translations'
|
default_path: '%kernel.project_dir%/translations'
|
||||||
fallbacks:
|
fallbacks:
|
||||||
- en
|
- fr
|
||||||
providers:
|
providers:
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Attribute\Route;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controllers for "core" pages: home, etc.
|
||||||
|
*/
|
||||||
|
class CoreController extends AbstractController {
|
||||||
|
/**
|
||||||
|
* Home page
|
||||||
|
*
|
||||||
|
* @return Response The response
|
||||||
|
*/
|
||||||
|
#[Route('/', name: 'core_main')]
|
||||||
|
public function main (): Response {
|
||||||
|
return $this->render('Core/Main.html.twig');
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Entity;
|
||||||
|
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use JsonSerializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation for the base implementation of an entity: id, creation and last update date and time
|
||||||
|
*/
|
||||||
|
trait TEntityBase {
|
||||||
|
/**
|
||||||
|
* @var int|null The internal id
|
||||||
|
*
|
||||||
|
* @noinspection PhpPropertyNamingConventionInspection
|
||||||
|
*/
|
||||||
|
#[ORM\Id]
|
||||||
|
#[ORM\GeneratedValue]
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?int $id = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Les données du trait qui doivent être inclus dans le JSON
|
||||||
|
*
|
||||||
|
* @return array Les données du trait qui doivent être inclus dans le JSON
|
||||||
|
*
|
||||||
|
* @see JsonSerializable::jsonSerialize()
|
||||||
|
*
|
||||||
|
* @noinspection PhpMethodNamingConventionInspection
|
||||||
|
*/
|
||||||
|
protected final function TEntityBase__jsonSerialize (): array {
|
||||||
|
return [
|
||||||
|
'id' => $this->getId(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The internal id
|
||||||
|
*
|
||||||
|
* @return int|null The internal id
|
||||||
|
*/
|
||||||
|
public function getId (): ?int {
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,173 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Entity;
|
||||||
|
|
||||||
|
use App\Repository\UserRepository;
|
||||||
|
use DateTimeImmutable;
|
||||||
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
|
use Doctrine\Common\Collections\Collection;
|
||||||
|
use Doctrine\DBAL\Types\Types;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use Stringable;
|
||||||
|
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||||
|
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||||
|
use Symfony\Component\Security\Core\User\UserInterface;
|
||||||
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A registered user
|
||||||
|
*/
|
||||||
|
#[ORM\Entity(repositoryClass: UserRepository::class)]
|
||||||
|
#[UniqueEntity(fields: ['email'], message: 'Il existe déjà un compte avec cette adresse mail')]
|
||||||
|
class User implements UserInterface, PasswordAuthenticatedUserInterface, Stringable {
|
||||||
|
use TEntityBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string The email
|
||||||
|
*/
|
||||||
|
#[ORM\Column(length: 100, unique: true)]
|
||||||
|
#[Assert\NotBlank(message: 'Veuillez saisir un email')]
|
||||||
|
#[Assert\Email(message: 'Veuillez saisir un email valide')]
|
||||||
|
private string $email;
|
||||||
|
/**
|
||||||
|
* @var string The hashed password
|
||||||
|
*/
|
||||||
|
#[ORM\Column(length: 255)]
|
||||||
|
private string $password;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string|null The name
|
||||||
|
*/
|
||||||
|
#[ORM\Column(length: 100, nullable: true)]
|
||||||
|
private ?string $name = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string[] The roles
|
||||||
|
*/
|
||||||
|
#[ORM\Column]
|
||||||
|
private array $roles = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function __toString (): string {
|
||||||
|
return $this->getName() ?? $this->getEmail();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The email
|
||||||
|
*
|
||||||
|
* @return string|null The email
|
||||||
|
*/
|
||||||
|
public function getEmail (): ?string {
|
||||||
|
return $this->email;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Change the email
|
||||||
|
*
|
||||||
|
* @param string $email The new email
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setEmail (string $email): self {
|
||||||
|
$this->email = $email;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The hashed password
|
||||||
|
*
|
||||||
|
* @return string The hashed password
|
||||||
|
*
|
||||||
|
* @see PasswordAuthenticatedUserInterface
|
||||||
|
*/
|
||||||
|
public function getPassword (): string {
|
||||||
|
return $this->password;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Change the hashed password
|
||||||
|
*
|
||||||
|
* @param string $password The new hashed password
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setPassword (string $password): self {
|
||||||
|
$this->password = $password;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name
|
||||||
|
*
|
||||||
|
* @return string|null The name
|
||||||
|
*/
|
||||||
|
public function getName (): ?string {
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Change the name
|
||||||
|
*
|
||||||
|
* @param string|null $name The new name
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setName (?string $name): self {
|
||||||
|
$this->name = $name;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A visual identifier that represents this user
|
||||||
|
*
|
||||||
|
* @see UserInterface
|
||||||
|
*/
|
||||||
|
public function getUserIdentifier (): string {
|
||||||
|
return $this->email;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Has a role ?
|
||||||
|
*
|
||||||
|
* @param string $role The role
|
||||||
|
*
|
||||||
|
* @return bool True if the user has the role, else False
|
||||||
|
*/
|
||||||
|
public function hasRole (string $role): bool {
|
||||||
|
return in_array($role, $this->getRoles());
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* The roles
|
||||||
|
*
|
||||||
|
* @return string[] The roles
|
||||||
|
*
|
||||||
|
* @see UserInterface
|
||||||
|
*/
|
||||||
|
public function getRoles (): array {
|
||||||
|
$roles = $this->roles;
|
||||||
|
// guarantee every user at least has ROLE_USER
|
||||||
|
$roles[] = 'ROLE_USER';
|
||||||
|
|
||||||
|
return array_unique($roles);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Set the roles
|
||||||
|
*
|
||||||
|
* @param array $roles The new roles
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setRoles (array $roles): void {
|
||||||
|
$this->roles = $roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes sensitive data from the user
|
||||||
|
*
|
||||||
|
* @see UserInterface
|
||||||
|
*/
|
||||||
|
public function eraseCredentials (): void {
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repository;
|
||||||
|
|
||||||
|
use App\Entity\User;
|
||||||
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
|
||||||
|
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||||
|
use Symfony\Component\Security\Core\User\PasswordUpgraderInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends ServiceEntityRepository<User>
|
||||||
|
*
|
||||||
|
* @method User|null find($id, $lockMode = null, $lockVersion = null)
|
||||||
|
* @method User|null findOneBy(array $criteria, array $orderBy = null)
|
||||||
|
* @method User[] findAll()
|
||||||
|
* @method User[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||||
|
*/
|
||||||
|
class UserRepository extends ServiceEntityRepository implements PasswordUpgraderInterface {
|
||||||
|
public function __construct (ManagerRegistry $registry) {
|
||||||
|
parent::__construct($registry, User::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function save (User $entity, bool $flush = false): void {
|
||||||
|
$this->getEntityManager()->persist($entity);
|
||||||
|
|
||||||
|
if ($flush) {
|
||||||
|
$this->getEntityManager()->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function remove (User $entity, bool $flush = false): void {
|
||||||
|
$this->getEntityManager()->remove($entity);
|
||||||
|
|
||||||
|
if ($flush) {
|
||||||
|
$this->getEntityManager()->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to upgrade (rehash) the user's password automatically over time.
|
||||||
|
*/
|
||||||
|
public function upgradePassword (PasswordAuthenticatedUserInterface $user, string $newHashedPassword): void {
|
||||||
|
if (!$user instanceof User) {
|
||||||
|
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', \get_class($user)));
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->setPassword($newHashedPassword);
|
||||||
|
|
||||||
|
$this->save($user, true);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,115 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service;
|
||||||
|
|
||||||
|
use App\Entity\User;
|
||||||
|
use App\Misc\FlashType;
|
||||||
|
use Symfony\Bundle\SecurityBundle\Security;
|
||||||
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Session;
|
||||||
|
use Symfony\Component\Routing\RouterInterface;
|
||||||
|
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for the connected user
|
||||||
|
*/
|
||||||
|
readonly class ConnectedUserService {
|
||||||
|
/**
|
||||||
|
* @var Security The security service
|
||||||
|
*/
|
||||||
|
public Security $security;
|
||||||
|
/**
|
||||||
|
* @var RouterInterface The routing service
|
||||||
|
*/
|
||||||
|
private RouterInterface $router;
|
||||||
|
/**
|
||||||
|
* @var RequestStack The service for the request
|
||||||
|
*/
|
||||||
|
private RequestStack $request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialization
|
||||||
|
*
|
||||||
|
* @param Security $security The security service
|
||||||
|
* @param RouterInterface $router The routing service
|
||||||
|
* @param RequestStack $request The service for the request
|
||||||
|
*/
|
||||||
|
public function __construct (Security $security, RouterInterface $router, RequestStack $request) {
|
||||||
|
$this->security = $security;
|
||||||
|
$this->router = $router;
|
||||||
|
$this->request = $request;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The connected user
|
||||||
|
*
|
||||||
|
* @return User|null The connected user
|
||||||
|
*/
|
||||||
|
public function getUser (): ?User {
|
||||||
|
$user = $this->security->getUser();
|
||||||
|
if ($user === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!$user instanceof User) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the requested user the connected one ?
|
||||||
|
*
|
||||||
|
* @param User $requestedUser The requested user
|
||||||
|
*
|
||||||
|
* @return bool True if the requested user is the connected one, else false
|
||||||
|
*/
|
||||||
|
public function isRequestedUser (User $requestedUser): bool {
|
||||||
|
return $this->getUser()?->getId() !== $requestedUser->getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the user is NOT connected
|
||||||
|
*
|
||||||
|
* @return Response|null The response (warning and redirect) if user is connected, else Null
|
||||||
|
*/
|
||||||
|
public function checkNotConnected (): ?Response {
|
||||||
|
/** @var User|null $user */
|
||||||
|
$user = $this->getUser();
|
||||||
|
if ($user === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var Session $session */
|
||||||
|
$session = $this->request->getSession();
|
||||||
|
$session->getFlashBag()->add(
|
||||||
|
FlashType::WARNING,
|
||||||
|
"Vous êtes déjà connecté, merci de vous <a href=\"{$this->router->generate('user_signOut')}\">déconnecter</a> d'abord"
|
||||||
|
);
|
||||||
|
return new RedirectResponse($this->router->generate('core_main'), 302);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Check if the requested user is the connected one or if the last has administration privileges
|
||||||
|
*
|
||||||
|
* @param User $requestedUser The requested user
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @throws AccessDeniedException If the access is denied
|
||||||
|
*/
|
||||||
|
public function checkRequestedUserAccess (User $requestedUser): void {
|
||||||
|
if (!$this->isRequestedUser($requestedUser)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!$this->security->isGranted('ROLE_ADMIN')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$exception = new AccessDeniedException();
|
||||||
|
$exception->setAttributes(['ROLE_ADMIN']);
|
||||||
|
$exception->setSubject(null);
|
||||||
|
|
||||||
|
throw $exception;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,13 @@
|
|||||||
|
{% extends '/base.html.twig' %}
|
||||||
|
|
||||||
|
{% block title %}Accueil - {{ parent() }}{% endblock %}
|
||||||
|
|
||||||
|
{% block mainContent %}
|
||||||
|
<h1>Recipe Manager</h1>
|
||||||
|
{% if app.user %}
|
||||||
|
Bienvenu {{ app.user }}
|
||||||
|
{% else %}
|
||||||
|
<p>Bienvenu sur Recipe Manager, le gestionnaire de recette de jeux vidéos.</p>
|
||||||
|
{# <p>Merci de vous <a href="{{ path('user_signIn') }}">connecter</a> ou <a href="{{ path('user_signOut') }}">créer un compte</a> pour commencer.</p>#}
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,15 @@
|
|||||||
|
{% block flashTag %}
|
||||||
|
{% set flashes = app.flashes %}
|
||||||
|
{% if flashes|length > 0 %}
|
||||||
|
<section id="flashes" class="d-flex flex-column mt-3">
|
||||||
|
{% for flashType, flashMessages in flashes %}
|
||||||
|
{% for flashMessage in flashMessages %}
|
||||||
|
<div class="alert alert-{{ flashType }} alert-dismissible fade show" role="{{ flashType }}">
|
||||||
|
{{ flashMessage|raw }}
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
</section>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
@ -0,0 +1,21 @@
|
|||||||
|
{% extends "/root.twig" %}
|
||||||
|
|
||||||
|
{% block pageContent %}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
{% block htmlTag %}
|
||||||
|
<html lang="{{ app.request.getLocale() }}">
|
||||||
|
{% endblock %}
|
||||||
|
{% block headTag %}
|
||||||
|
<!--suppress HtmlRequiredTitleElement -->
|
||||||
|
<head>
|
||||||
|
{% endblock %}
|
||||||
|
{% block headContent %}{% endblock %}
|
||||||
|
</head>
|
||||||
|
{% block bodyTag %}
|
||||||
|
<body>
|
||||||
|
{% endblock %}
|
||||||
|
{% block bodyContent %}{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
{% endblock %}
|
@ -0,0 +1 @@
|
|||||||
|
{% block pageContent %}{% endblock %}
|
@ -0,0 +1,63 @@
|
|||||||
|
{% extends "/html.html.twig" %}
|
||||||
|
|
||||||
|
{% block headContent %}
|
||||||
|
{% block headContentMeta %}
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
<title>{% block title %}{% endblock %}</title>
|
||||||
|
|
||||||
|
{% block CSS %}{% endblock %}
|
||||||
|
|
||||||
|
{% block JS_head %}{% endblock %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block bodyTag %}
|
||||||
|
<body id="page-{{ app.current_route }}" class="m-2">
|
||||||
|
{% endblock %}
|
||||||
|
{% block bodyContent %}
|
||||||
|
{% block headerTag %}
|
||||||
|
<header>
|
||||||
|
{% endblock %}
|
||||||
|
{% block headerContent %}{% endblock %}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
{% block divBodyTag %}
|
||||||
|
<div id="div-body" class="d-flex flex-row">
|
||||||
|
{% endblock %}
|
||||||
|
{% block asideLeft %}{% endblock %}
|
||||||
|
|
||||||
|
{% block centerDivBodyTag %}
|
||||||
|
<div id="div-body-center" class="d-flex flex-column flex-grow-1">
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block sectionTop %}{% endblock %}
|
||||||
|
|
||||||
|
{% include '/_flashes.html.twig' %}
|
||||||
|
|
||||||
|
{% block sectionBefore %}{% endblock %}
|
||||||
|
{% block mainTag %}
|
||||||
|
<main>
|
||||||
|
{% endblock %}
|
||||||
|
{% block mainContent %}{% endblock %}
|
||||||
|
</main>
|
||||||
|
{% block sectionAfter %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
{% block asideRight %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% block footerTag %}
|
||||||
|
<footer>
|
||||||
|
{% endblock %}
|
||||||
|
{% block footerContent %}{% endblock %}
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
<div class="d-none">
|
||||||
|
{% block bodyHidden %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% block JS %}
|
||||||
|
{% block importmap %}{{ importmap('app') }}{% endblock %}
|
||||||
|
{% endblock %}
|
||||||
|
{% endblock %}
|
Loading…
Reference in New Issue