commit
f0bc442188
@ -0,0 +1,18 @@
|
||||
api_platform:
|
||||
title: Hello API Platform
|
||||
version: 1.0.0
|
||||
formats:
|
||||
jsonld: ['application/ld+json']
|
||||
docs_formats:
|
||||
jsonld: ['application/ld+json']
|
||||
jsonopenapi: ['application/vnd.openapi+json']
|
||||
html: ['text/html']
|
||||
defaults:
|
||||
stateless: true
|
||||
cache_headers:
|
||||
vary: ['Content-Type', 'Authorization', 'Origin']
|
||||
extra_properties:
|
||||
standard_put: true
|
||||
rfc_7807_compliant_errors: true
|
||||
event_listeners_backward_compatibility_layer: false
|
||||
keep_legacy_inflector: false
|
@ -0,0 +1,10 @@
|
||||
nelmio_cors:
|
||||
defaults:
|
||||
origin_regex: true
|
||||
allow_origin: ['%env(CORS_ALLOW_ORIGIN)%']
|
||||
allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE']
|
||||
allow_headers: ['Content-Type', 'Authorization']
|
||||
expose_headers: ['Link']
|
||||
max_age: 3600
|
||||
paths:
|
||||
'^/': null
|
@ -0,0 +1,4 @@
|
||||
api_platform:
|
||||
resource: .
|
||||
type: api_platform
|
||||
prefix: /api
|
@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20250529203532 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql(<<<'SQL'
|
||||
CREATE TABLE emoji (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, nom VARCHAR(255) NOT NULL, code VARCHAR(255) NOT NULL, force DOUBLE PRECISION NOT NULL, robustesse DOUBLE PRECISION NOT NULL, intelligence DOUBLE PRECISION NOT NULL, vitesse DOUBLE PRECISION NOT NULL, nb_combat_gagne INTEGER NOT NULL, rarete INTEGER NOT NULL)
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
CREATE TABLE rarity (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name VARCHAR(50) NOT NULL, drop_rate DOUBLE PRECISION NOT NULL)
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
CREATE UNIQUE INDEX UNIQ_B7C0BE465E237E06 ON rarity (name)
|
||||
SQL);
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql(<<<'SQL'
|
||||
DROP TABLE emoji
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
DROP TABLE rarity
|
||||
SQL);
|
||||
}
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
body {
|
||||
background-color: #314e57;
|
||||
font-family: 'Georgia', serif;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.login-container {
|
||||
background-color: #3b6068;
|
||||
border: 4px solid #000;
|
||||
border-radius: 15px;
|
||||
padding: 40px 30px;
|
||||
margin: 60px auto;
|
||||
width: 90%;
|
||||
max-width: 400px;
|
||||
box-shadow: 0 0 30px rgba(0,0,0,0.6);
|
||||
color: #f8f5e0;
|
||||
font-family: 'Georgia', serif;
|
||||
}
|
||||
|
||||
.login-title {
|
||||
font-size: 2.5rem;
|
||||
color: #f8b435;
|
||||
margin-bottom: 20px;
|
||||
text-shadow: 2px 2px 4px #000;
|
||||
}
|
||||
|
||||
.login-error {
|
||||
background-color: #8b0000;
|
||||
color: #fff8e1;
|
||||
padding: 10px;
|
||||
border: 2px solid #000;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.already-logged {
|
||||
background-color: #f2e6c9;
|
||||
color: #000;
|
||||
padding: 12px;
|
||||
border: 2px dashed #000;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.logout-link {
|
||||
display: inline-block;
|
||||
margin-top: 10px;
|
||||
color: #8b0000;
|
||||
font-weight: bold;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.login-form label {
|
||||
text-align: left;
|
||||
color: #f8f5e0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.login-form input[type="text"],
|
||||
.login-form input[type="password"] {
|
||||
padding: 10px;
|
||||
border: 2px solid #000;
|
||||
border-radius: 6px;
|
||||
background-color: #f2e6c9;
|
||||
font-family: 'Georgia', serif;
|
||||
font-size: 1rem;
|
||||
box-shadow: inset 2px 2px 5px rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
.btn-login {
|
||||
background-color: #f8b435;
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
border: 3px solid #000;
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
font-size: 1.2rem;
|
||||
cursor: pointer;
|
||||
box-shadow: 3px 3px 0 #000;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-login:hover {
|
||||
transform: scale(1.05);
|
||||
background-color: #e09f30;
|
||||
}
|
||||
|
||||
.no-account {
|
||||
margin-top: 30px;
|
||||
color: #f8f5e0;
|
||||
}
|
||||
|
||||
.btn-register {
|
||||
display: inline-block;
|
||||
margin-top: 10px;
|
||||
background-color: #f2e6c9;
|
||||
color: #000;
|
||||
border: 2px solid #000;
|
||||
padding: 8px 20px;
|
||||
border-radius: 6px;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
box-shadow: 2px 2px 0 #000;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-register:hover {
|
||||
transform: scale(1.05);
|
||||
background-color: #e5d6b8;
|
||||
}
|
@ -0,0 +1,88 @@
|
||||
body {
|
||||
background-color: #314e57 !important;
|
||||
font-family: 'Georgia', serif;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.register-container {
|
||||
background-color: #3b6068;
|
||||
border: 4px solid #000;
|
||||
border-radius: 15px;
|
||||
padding: 40px 30px;
|
||||
margin: 60px auto;
|
||||
width: 90%;
|
||||
max-width: 400px;
|
||||
box-shadow: 0 0 30px rgba(0,0,0,0.6);
|
||||
color: #f8f5e0;
|
||||
font-family: 'Georgia', serif;
|
||||
}
|
||||
|
||||
.register-title {
|
||||
font-size: 2.5rem;
|
||||
color: #f8b435;
|
||||
margin-bottom: 20px;
|
||||
text-shadow: 2px 2px 4px #000;
|
||||
}
|
||||
|
||||
.register-form label {
|
||||
text-align: left;
|
||||
color: #f8f5e0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.register-form input[type="text"],
|
||||
.register-form input[type="password"] {
|
||||
padding: 10px;
|
||||
border: 2px solid #000;
|
||||
border-radius: 6px;
|
||||
background-color: #f2e6c9;
|
||||
font-family: 'Georgia', serif;
|
||||
font-size: 1rem;
|
||||
box-shadow: inset 2px 2px 5px rgba(0,0,0,0.2);
|
||||
width: 100%;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.btn-register-submit {
|
||||
background-color: #f8b435;
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
border: 3px solid #000;
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
font-size: 1.2rem;
|
||||
cursor: pointer;
|
||||
box-shadow: 3px 3px 0 #000;
|
||||
transition: transform 0.2s ease;
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.btn-register-submit:hover {
|
||||
transform: scale(1.05);
|
||||
background-color: #e09f30;
|
||||
}
|
||||
|
||||
.already-account {
|
||||
color: #f8f5e0;
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.btn-login-link {
|
||||
display: inline-block;
|
||||
margin-top: 10px;
|
||||
background-color: #f2e6c9;
|
||||
color: #000;
|
||||
border: 2px solid #000;
|
||||
padding: 8px 20px;
|
||||
border-radius: 6px;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
box-shadow: 2px 2px 0 #000;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-login-link:hover {
|
||||
transform: scale(1.05);
|
||||
background-color: #e5d6b8;
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class PopulateDBEmojiAvailableCommand extends Command
|
||||
{
|
||||
|
||||
protected static $defaultName = 'app:popDBEmojiAvai';
|
||||
|
||||
private Connection $connection;
|
||||
|
||||
public function __construct(Connection $connection)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setDescription('Populate the database.');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
try {
|
||||
|
||||
// On supprime la table si elle existe déjà
|
||||
$this->connection->executeStatement('DROP TABLE IF EXISTS stock_emoji');
|
||||
|
||||
// On crée la table
|
||||
$this->connection->executeStatement('
|
||||
CREATE TABLE stock_emoji (
|
||||
id INT PRIMARY KEY,
|
||||
code VARCHAR(255) NOT NULL,
|
||||
name VARCHAR(255) NOT NULL
|
||||
)
|
||||
');
|
||||
|
||||
|
||||
// On peuple la table
|
||||
$this->connection->executeStatement("INSERT INTO stock_emoji (id, code, name) VALUES
|
||||
(1,'🤖','Rodolph'),
|
||||
(2,'😺','Bobette'),
|
||||
(3,'🧠','Diana'),
|
||||
(4,'👻','Ian'),
|
||||
(5,'🧟','Alice'),
|
||||
(6,'🐶','Eric'),
|
||||
(7,'👽','Hannah'),
|
||||
(8,'🧛','Fiona'),
|
||||
(9,'🎃','George'),
|
||||
(10,'🐸','John'),
|
||||
(11,'⚡','Charlie'),
|
||||
(12,'💀','Benoit'),
|
||||
(13,'🔥','Sophie'),
|
||||
(14,'🧙','Bob'),
|
||||
(15,'🌪️','Ethan'),
|
||||
(16,'😎','Luna'),
|
||||
(17,'😁','Maxence'),
|
||||
(18,'🌟','Jasper'),
|
||||
(19,'😈','Nora')
|
||||
");
|
||||
|
||||
$output->writeln('Base de données peuplée.');
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln('<error>Erreur : ' . $e->getMessage() . '</error>');
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
|
||||
|
||||
class LoginController extends AbstractController
|
||||
{
|
||||
#[Route(path: '/login', name: 'app_login')]
|
||||
public function login(AuthenticationUtils $authenticationUtils): Response
|
||||
{
|
||||
if ($this->getUser()) {
|
||||
return $this->redirectToRoute('app_home');
|
||||
}
|
||||
$error = $authenticationUtils->getLastAuthenticationError();
|
||||
$lastUsername = $authenticationUtils->getLastUsername();
|
||||
|
||||
return $this->render('auth/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
|
||||
}
|
||||
|
||||
#[Route(path: '/logout', name: 'app_logout')]
|
||||
public function logout(): void
|
||||
{
|
||||
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\Form\RegistrationFormType;
|
||||
use App\Security\LoginFormAuthenticator;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Authentication\UserAuthenticatorInterface;
|
||||
|
||||
class RegistrationController extends AbstractController
|
||||
{
|
||||
#[Route('/register', name: 'app_register')]
|
||||
public function register(Request $request, UserPasswordHasherInterface $userPasswordHasher, UserAuthenticatorInterface $userAuthenticator, LoginFormAuthenticator $authenticator, EntityManagerInterface $entityManager): Response
|
||||
{
|
||||
$user = new User();
|
||||
$form = $this->createForm(RegistrationFormType::class, $user);
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$user->setPassword(
|
||||
$userPasswordHasher->hashPassword(
|
||||
$user,
|
||||
$form->get('plainPassword')->getData()
|
||||
)
|
||||
);
|
||||
$user->setRoles(['ROLE_USER']);
|
||||
|
||||
$entityManager->persist($user);
|
||||
$entityManager->flush();
|
||||
|
||||
return $userAuthenticator->authenticateUser(
|
||||
$user,
|
||||
$authenticator,
|
||||
$request
|
||||
);
|
||||
}
|
||||
|
||||
return $this->render('auth/register.html.twig', [
|
||||
'registrationForm' => $form->createView(),
|
||||
]);
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\User;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
#[Route('/users', name: 'users_')]
|
||||
class UserController extends AbstractController
|
||||
{
|
||||
private EntityManagerInterface $entityManager;
|
||||
|
||||
public function __construct(EntityManagerInterface $entityManager)
|
||||
{
|
||||
$this->entityManager = $entityManager;
|
||||
}
|
||||
|
||||
#[Route('/{userId}', name: 'get_by_id', methods: ['GET'])]
|
||||
public function getUserById(int $userId): JsonResponse
|
||||
{
|
||||
$user = $this->entityManager->getRepository(User::class)->find($userId);
|
||||
|
||||
if (!$user) {
|
||||
return $this->json(['error' => 'User not found'], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'id' => $user->getId(),
|
||||
'username' => $user->getUsername(),
|
||||
'roles' => $user->getRoles(),
|
||||
];
|
||||
|
||||
return $this->json($data);
|
||||
}
|
||||
|
||||
#[Route('/{userId}/emojis', name: 'get_emojis_by_user', methods: ['GET'])]
|
||||
public function getEmojisByUserId(int $userId): JsonResponse
|
||||
{
|
||||
$user = $this->entityManager->getRepository(User::class)->find($userId);
|
||||
|
||||
if (!$user) {
|
||||
return $this->json(['error' => 'User not found'], Response::HTTP_NOT_FOUND);
|
||||
}
|
||||
|
||||
$emojis = $user->getEmojis()->map(function ($emoji) {
|
||||
return [
|
||||
'id' => $emoji->getId(),
|
||||
'name' => $emoji->getName(),
|
||||
'code' => $emoji->getCode(),
|
||||
];
|
||||
})->toArray();
|
||||
|
||||
return $this->json($emojis);
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\StockEmojiRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use ApiPlatform\Metadata\ApiResource;
|
||||
|
||||
#[ORM\Entity(repositoryClass: StockEmojiRepository::class)]
|
||||
#[ApiResource]
|
||||
class StockEmoji
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $code = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $name = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getCode(): ?string
|
||||
{
|
||||
return $this->code;
|
||||
}
|
||||
|
||||
public function setCode(string $code): self
|
||||
{
|
||||
$this->code = $code;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getName(): ?string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName(string $name): self
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\UserRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use ApiPlatform\Metadata\ApiResource;
|
||||
|
||||
#[ORM\Entity(repositoryClass: UserRepository::class)]
|
||||
#[UniqueEntity(fields: ['username'], message: 'Un compte existe déjà avec ce nom d\'utilisateur')]
|
||||
#[ApiResource]
|
||||
class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\Column(length: 180, unique: true)]
|
||||
private ?string $username = null;
|
||||
|
||||
#[ORM\Column]
|
||||
private array $roles = [];
|
||||
|
||||
/**
|
||||
* @var string The hashed password
|
||||
*/
|
||||
#[ORM\Column]
|
||||
private ?string $password = null;
|
||||
|
||||
#[ORM\ManyToMany(targetEntity: Emoji::class, inversedBy: 'users')]
|
||||
#[ORM\JoinTable(name: 'posseder')]
|
||||
private Collection $emojis;
|
||||
|
||||
public function __construct() {
|
||||
$this->emojis = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getUsername(): ?string
|
||||
{
|
||||
return $this->username;
|
||||
}
|
||||
|
||||
public function setUsername(string $username): static
|
||||
{
|
||||
$this->username = $username;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* A visual identifier that represents this user.
|
||||
*
|
||||
* @see UserInterface
|
||||
*/
|
||||
public function getUserIdentifier(): string
|
||||
{
|
||||
return (string) $this->username;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserInterface
|
||||
*/
|
||||
public function getRoles(): array
|
||||
{
|
||||
$roles = $this->roles;
|
||||
// guarantee every user at least has ROLE_USER
|
||||
$roles[] = 'ROLE_USER';
|
||||
|
||||
return array_unique($roles);
|
||||
}
|
||||
|
||||
public function setRoles(array $roles): static
|
||||
{
|
||||
$this->roles = $roles;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PasswordAuthenticatedUserInterface
|
||||
*/
|
||||
public function getPassword(): string
|
||||
{
|
||||
return $this->password;
|
||||
}
|
||||
|
||||
public function setPassword(string $password): static
|
||||
{
|
||||
$this->password = $password;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getEmojis(): Collection
|
||||
{
|
||||
return $this->emojis;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UserInterface
|
||||
*/
|
||||
public function eraseCredentials(): void
|
||||
{
|
||||
// If you store any temporary, sensitive data on the user, clear it here
|
||||
// $this->plainPassword = null;
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Form;
|
||||
|
||||
use App\Entity\User;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints\IsTrue;
|
||||
use Symfony\Component\Validator\Constraints\Length;
|
||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
|
||||
class RegistrationFormType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$builder
|
||||
->add('username')
|
||||
->add('plainPassword', PasswordType::class, [
|
||||
'mapped' => false,
|
||||
'attr' => ['autocomplete' => 'new-password'],
|
||||
'constraints' => [
|
||||
new NotBlank([
|
||||
'message' => 'Please enter a password',
|
||||
]),
|
||||
new Length([
|
||||
'min' => 6,
|
||||
'minMessage' => 'Your password should be at least {{ limit }} characters',
|
||||
'max' => 4096,
|
||||
]),
|
||||
],
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => User::class,
|
||||
]);
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\StockEmoji;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<StockEmoji>
|
||||
*
|
||||
* @method StockEmoji|null find($id, $lockMode = null, $lockVersion = null)
|
||||
* @method StockEmoji|null findOneBy(array $criteria, array $orderBy = null)
|
||||
* @method StockEmoji[] findAll()
|
||||
* @method StockEmoji[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||
*/
|
||||
class StockEmojiRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, StockEmoji::class);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @return StockEmoji[] Returns an array of StockEmoji objects
|
||||
// */
|
||||
// public function findByExampleField($value): array
|
||||
// {
|
||||
// return $this->createQueryBuilder('s')
|
||||
// ->andWhere('s.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->orderBy('s.id', 'ASC')
|
||||
// ->setMaxResults(10)
|
||||
// ->getQuery()
|
||||
// ->getResult()
|
||||
// ;
|
||||
// }
|
||||
|
||||
// public function findOneBySomeField($value): ?StockEmoji
|
||||
// {
|
||||
// return $this->createQueryBuilder('s')
|
||||
// ->andWhere('s.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->getQuery()
|
||||
// ->getOneOrNullResult()
|
||||
// ;
|
||||
// }
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
<?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>
|
||||
*
|
||||
* @implements PasswordUpgraderInterface<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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.', $user::class));
|
||||
}
|
||||
|
||||
$user->setPassword($newHashedPassword);
|
||||
$this->getEntityManager()->persist($user);
|
||||
$this->getEntityManager()->flush();
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @return User[] Returns an array of User objects
|
||||
// */
|
||||
// public function findByExampleField($value): array
|
||||
// {
|
||||
// return $this->createQueryBuilder('u')
|
||||
// ->andWhere('u.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->orderBy('u.id', 'ASC')
|
||||
// ->setMaxResults(10)
|
||||
// ->getQuery()
|
||||
// ->getResult()
|
||||
// ;
|
||||
// }
|
||||
|
||||
// public function findOneBySomeField($value): ?User
|
||||
// {
|
||||
// return $this->createQueryBuilder('u')
|
||||
// ->andWhere('u.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->getQuery()
|
||||
// ->getOneOrNullResult()
|
||||
// ;
|
||||
// }
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace App\Security;
|
||||
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge;
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge;
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
|
||||
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
|
||||
use Symfony\Component\Security\Http\Util\TargetPathTrait;
|
||||
|
||||
class LoginFormAuthenticator extends AbstractLoginFormAuthenticator
|
||||
{
|
||||
use TargetPathTrait;
|
||||
|
||||
public const LOGIN_ROUTE = 'app_login';
|
||||
|
||||
public function __construct(private UrlGeneratorInterface $urlGenerator)
|
||||
{
|
||||
}
|
||||
|
||||
public function authenticate(Request $request): Passport
|
||||
{
|
||||
$username = $request->request->get('username', '');
|
||||
|
||||
$request->getSession()->set(Security::LAST_USERNAME, $username);
|
||||
|
||||
return new Passport(
|
||||
new UserBadge($username),
|
||||
new PasswordCredentials($request->request->get('password', '')),
|
||||
[
|
||||
new CsrfTokenBadge('authenticate', $request->request->get('_csrf_token')),
|
||||
new RememberMeBadge(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
|
||||
{
|
||||
if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) {
|
||||
return new RedirectResponse($targetPath);
|
||||
}
|
||||
|
||||
return new RedirectResponse($this->urlGenerator->generate('app_home'));
|
||||
}
|
||||
|
||||
protected function getLoginUrl(Request $request): string
|
||||
{
|
||||
return $this->urlGenerator->generate(self::LOGIN_ROUTE);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}Connexion{% endblock %}
|
||||
|
||||
{% block stylesheets %}
|
||||
{{ parent() }}
|
||||
<link rel="stylesheet" href="{{ asset('css/login.css') }}">
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="login-container">
|
||||
|
||||
<h1 class="login-title">🔐 Connexion</h1>
|
||||
|
||||
{% if error %}
|
||||
<div class="login-error">Mauvais nom d'utilisateur ou mot de passe.</div>
|
||||
{% endif %}
|
||||
|
||||
{% if app.user %}
|
||||
<div class="already-logged">
|
||||
Connecté en tant que {{ app.user.userIdentifier }},
|
||||
<a href="{{ path('app_logout') }}" class="logout-link">Se déconnecter</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<form method="post" class="login-form">
|
||||
<label for="inputUsername">Nom d'utilisateur</label>
|
||||
<input type="text" id="inputUsername" name="username" value="{{ last_username }}" required autofocus>
|
||||
|
||||
<label for="inputPassword">Mot de passe</label>
|
||||
<input type="password" id="inputPassword" name="password" required>
|
||||
|
||||
<input type="hidden" name="_csrf_token" value="{{ csrf_token('authenticate') }}">
|
||||
|
||||
<button class="btn-login" type="submit">🚪 Se connecter</button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
<div class="no-account">
|
||||
<p>Pas encore de compte ?</p>
|
||||
<a href="{{ path('app_register') }}" class="btn-register">Créer un compte</a>
|
||||
</div>
|
||||
{% endblock %}
|
@ -0,0 +1,30 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block title %}Inscription{% endblock %}
|
||||
|
||||
{% block stylesheets %}
|
||||
{{ parent() }}
|
||||
<link rel="stylesheet" href="{{ asset('css/register.css') }}">
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
<div class="register-container">
|
||||
<h1 class="register-title">📝 Inscription</h1>
|
||||
|
||||
{{ form_start(registrationForm, {'attr': {'class': 'register-form'}}) }}
|
||||
{{ form_errors(registrationForm) }}
|
||||
|
||||
{{ form_row(registrationForm.username) }}
|
||||
{{ form_row(registrationForm.plainPassword, {
|
||||
label: 'Mot de passe'
|
||||
}) }}
|
||||
|
||||
<button type="submit" class="btn-register-submit">Créer mon compte</button>
|
||||
|
||||
<div class="already-account">
|
||||
<p>Déjà inscrit ?</p>
|
||||
<a href="{{ path('app_login') }}" class="btn-login-link">Se connecter</a>
|
||||
</div>
|
||||
{{ form_end(registrationForm) }}
|
||||
</div>
|
||||
{% endblock %}
|
Loading…
Reference in new issue