Compare commits
43 Commits
@ -0,0 +1,13 @@
|
|||||||
|
# How to run
|
||||||
|
|
||||||
|
`composer update`
|
||||||
|
|
||||||
|
`php bin/console make:migration`
|
||||||
|
|
||||||
|
`php bin/console doctrine:migrations:migrate`
|
||||||
|
|
||||||
|
`php bin/console app:populateDB`
|
||||||
|
|
||||||
|
`php bin/console app:popDBEmojiAvai`
|
||||||
|
|
||||||
|
`symfony server:start`
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,62 +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 Version20250529204111 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 TEMPORARY TABLE __temp__emoji AS SELECT id, nom, code, intelligence FROM emoji
|
|
||||||
SQL);
|
|
||||||
$this->addSql(<<<'SQL'
|
|
||||||
DROP TABLE emoji
|
|
||||||
SQL);
|
|
||||||
$this->addSql(<<<'SQL'
|
|
||||||
CREATE TABLE emoji (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, rarity_id INTEGER NOT NULL, name VARCHAR(255) NOT NULL, code VARCHAR(255) NOT NULL, intelligence DOUBLE PRECISION NOT NULL, strength DOUBLE PRECISION NOT NULL, toughness DOUBLE PRECISION NOT NULL, speed DOUBLE PRECISION NOT NULL, fights_won INTEGER NOT NULL, CONSTRAINT FK_B64BF632F3747573 FOREIGN KEY (rarity_id) REFERENCES rarity (id) NOT DEFERRABLE INITIALLY IMMEDIATE)
|
|
||||||
SQL);
|
|
||||||
$this->addSql(<<<'SQL'
|
|
||||||
INSERT INTO emoji (id, name, code, intelligence) SELECT id, nom, code, intelligence FROM __temp__emoji
|
|
||||||
SQL);
|
|
||||||
$this->addSql(<<<'SQL'
|
|
||||||
DROP TABLE __temp__emoji
|
|
||||||
SQL);
|
|
||||||
$this->addSql(<<<'SQL'
|
|
||||||
CREATE INDEX IDX_B64BF632F3747573 ON emoji (rarity_id)
|
|
||||||
SQL);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function down(Schema $schema): void
|
|
||||||
{
|
|
||||||
// this down() migration is auto-generated, please modify it to your needs
|
|
||||||
$this->addSql(<<<'SQL'
|
|
||||||
CREATE TEMPORARY TABLE __temp__emoji AS SELECT id, name, code, intelligence FROM emoji
|
|
||||||
SQL);
|
|
||||||
$this->addSql(<<<'SQL'
|
|
||||||
DROP TABLE emoji
|
|
||||||
SQL);
|
|
||||||
$this->addSql(<<<'SQL'
|
|
||||||
CREATE TABLE emoji (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, nom VARCHAR(255) NOT NULL, code VARCHAR(255) NOT NULL, intelligence DOUBLE PRECISION NOT NULL, force DOUBLE PRECISION NOT NULL, robustesse DOUBLE PRECISION NOT NULL, vitesse DOUBLE PRECISION NOT NULL, nb_combat_gagne INTEGER NOT NULL, rarete INTEGER NOT NULL)
|
|
||||||
SQL);
|
|
||||||
$this->addSql(<<<'SQL'
|
|
||||||
INSERT INTO emoji (id, nom, code, intelligence) SELECT id, name, code, intelligence FROM __temp__emoji
|
|
||||||
SQL);
|
|
||||||
$this->addSql(<<<'SQL'
|
|
||||||
DROP TABLE __temp__emoji
|
|
||||||
SQL);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,71 +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 Version20250530163653 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 TEMPORARY TABLE __temp__emoji AS SELECT id, rarity_id, name, code, intelligence, strength, toughness, speed, fights_won FROM emoji
|
|
||||||
SQL);
|
|
||||||
$this->addSql(<<<'SQL'
|
|
||||||
DROP TABLE emoji
|
|
||||||
SQL);
|
|
||||||
$this->addSql(<<<'SQL'
|
|
||||||
CREATE TABLE emoji (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, rarity_id INTEGER NOT NULL, parent1_id INTEGER DEFAULT NULL, parent2_id INTEGER DEFAULT NULL, name VARCHAR(255) NOT NULL, code VARCHAR(255) NOT NULL, intelligence DOUBLE PRECISION NOT NULL, strength DOUBLE PRECISION NOT NULL, toughness DOUBLE PRECISION NOT NULL, speed DOUBLE PRECISION NOT NULL, fights_won INTEGER NOT NULL, CONSTRAINT FK_B64BF632F3747573 FOREIGN KEY (rarity_id) REFERENCES rarity (id) ON UPDATE NO ACTION ON DELETE NO ACTION NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_B64BF632861B2665 FOREIGN KEY (parent1_id) REFERENCES emoji (id) NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_B64BF63294AE898B FOREIGN KEY (parent2_id) REFERENCES emoji (id) NOT DEFERRABLE INITIALLY IMMEDIATE)
|
|
||||||
SQL);
|
|
||||||
$this->addSql(<<<'SQL'
|
|
||||||
INSERT INTO emoji (id, rarity_id, name, code, intelligence, strength, toughness, speed, fights_won) SELECT id, rarity_id, name, code, intelligence, strength, toughness, speed, fights_won FROM __temp__emoji
|
|
||||||
SQL);
|
|
||||||
$this->addSql(<<<'SQL'
|
|
||||||
DROP TABLE __temp__emoji
|
|
||||||
SQL);
|
|
||||||
$this->addSql(<<<'SQL'
|
|
||||||
CREATE INDEX IDX_B64BF632F3747573 ON emoji (rarity_id)
|
|
||||||
SQL);
|
|
||||||
$this->addSql(<<<'SQL'
|
|
||||||
CREATE INDEX IDX_B64BF632861B2665 ON emoji (parent1_id)
|
|
||||||
SQL);
|
|
||||||
$this->addSql(<<<'SQL'
|
|
||||||
CREATE INDEX IDX_B64BF63294AE898B ON emoji (parent2_id)
|
|
||||||
SQL);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function down(Schema $schema): void
|
|
||||||
{
|
|
||||||
// this down() migration is auto-generated, please modify it to your needs
|
|
||||||
$this->addSql(<<<'SQL'
|
|
||||||
CREATE TEMPORARY TABLE __temp__emoji AS SELECT id, rarity_id, name, code, strength, toughness, intelligence, speed, fights_won FROM emoji
|
|
||||||
SQL);
|
|
||||||
$this->addSql(<<<'SQL'
|
|
||||||
DROP TABLE emoji
|
|
||||||
SQL);
|
|
||||||
$this->addSql(<<<'SQL'
|
|
||||||
CREATE TABLE emoji (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, rarity_id INTEGER NOT NULL, name VARCHAR(255) NOT NULL, code VARCHAR(255) NOT NULL, strength DOUBLE PRECISION NOT NULL, toughness DOUBLE PRECISION NOT NULL, intelligence DOUBLE PRECISION NOT NULL, speed DOUBLE PRECISION NOT NULL, fights_won INTEGER NOT NULL, CONSTRAINT FK_B64BF632F3747573 FOREIGN KEY (rarity_id) REFERENCES rarity (id) NOT DEFERRABLE INITIALLY IMMEDIATE)
|
|
||||||
SQL);
|
|
||||||
$this->addSql(<<<'SQL'
|
|
||||||
INSERT INTO emoji (id, rarity_id, name, code, strength, toughness, intelligence, speed, fights_won) SELECT id, rarity_id, name, code, strength, toughness, intelligence, speed, fights_won FROM __temp__emoji
|
|
||||||
SQL);
|
|
||||||
$this->addSql(<<<'SQL'
|
|
||||||
DROP TABLE __temp__emoji
|
|
||||||
SQL);
|
|
||||||
$this->addSql(<<<'SQL'
|
|
||||||
CREATE INDEX IDX_B64BF632F3747573 ON emoji (rarity_id)
|
|
||||||
SQL);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,90 @@
|
|||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
background-color: #f4f6f8;
|
||||||
|
color: #333;
|
||||||
|
margin: 2rem auto;
|
||||||
|
max-width: 800px;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: #2c3e50;
|
||||||
|
font-size: 2rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
color: #34495e;
|
||||||
|
font-size: 1.4rem;
|
||||||
|
margin-top: 2rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
border-bottom: 2px solid #ccc;
|
||||||
|
padding-bottom: 0.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
background: white;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 1.5rem;
|
||||||
|
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul#user-list {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#user-list li {
|
||||||
|
background: #ecf0f1;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
padding: 0.8rem 1rem;
|
||||||
|
border-radius: 6px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#user-list li button {
|
||||||
|
background-color: #e74c3c;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#user-list li button:hover {
|
||||||
|
background-color: #c0392b;
|
||||||
|
}
|
||||||
|
|
||||||
|
form#add-user-form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
form#add-user-form input,
|
||||||
|
form#add-user-form select {
|
||||||
|
padding: 0.6rem;
|
||||||
|
border: 1px solid #bdc3c7;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
form#add-user-form button {
|
||||||
|
background-color: #3498db;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 0.7rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 1rem;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
form#add-user-form button:hover {
|
||||||
|
background-color: #2980b9;
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
After Width: | Height: | Size: 2.1 MiB |
After Width: | Height: | Size: 277 KiB |
After Width: | Height: | Size: 2.1 MiB |
After Width: | Height: | Size: 1.2 MiB |
@ -0,0 +1,65 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const left = document.querySelector('.left-emoji');
|
||||||
|
const right = document.querySelector('.right-emoji');
|
||||||
|
const winnerText = document.getElementById('winner-text');
|
||||||
|
|
||||||
|
fetch(`https://localhost:8000/emojis/fight/${id1}/${id2}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
const { leftEmoji, rightEmoji, winner } = data;
|
||||||
|
|
||||||
|
left.dataset.content = leftEmoji;
|
||||||
|
right.dataset.content = rightEmoji;
|
||||||
|
|
||||||
|
window.winnerSide = winner === 'left' ? 'left' : 'right';
|
||||||
|
window.loserSide = winner === 'left' ? 'right' : 'left';
|
||||||
|
|
||||||
|
insertEmojiOrImage(left);
|
||||||
|
insertEmojiOrImage(right);
|
||||||
|
|
||||||
|
left.classList.add('slide-in-left');
|
||||||
|
right.classList.add('slide-in-right');
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
left.style.left = '100px';
|
||||||
|
right.style.left = '300px';
|
||||||
|
|
||||||
|
left.classList.add('fight-animation');
|
||||||
|
right.classList.add('fight-animation');
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
left.classList.remove('fight-animation');
|
||||||
|
right.classList.remove('fight-animation');
|
||||||
|
|
||||||
|
const loser = window.loserSide === 'left' ? left : right;
|
||||||
|
loser.classList.add('loser-fly-up');
|
||||||
|
const winnerEl = window.winnerSide === 'left' ? left : right;
|
||||||
|
winnerEl.classList.add('winner-center', 'winner-crown');
|
||||||
|
|
||||||
|
let name = winnerEl.dataset.content;
|
||||||
|
if (/^https?:\/\//.test(name)) {
|
||||||
|
winnerText.innerHTML = `<img src="${name}" style="width:64px">a gagné ! 🎉`;
|
||||||
|
} else {
|
||||||
|
winnerText.textContent = `${name} a gagné ! 🎉`;
|
||||||
|
}
|
||||||
|
winnerText.style.display = 'block';
|
||||||
|
}, 1500);
|
||||||
|
}, 3000);
|
||||||
|
});
|
||||||
|
|
||||||
|
function insertEmojiOrImage(el) {
|
||||||
|
const value = el.dataset.content;
|
||||||
|
if (/^https?:\/\//.test(value)) {
|
||||||
|
const img = document.createElement('img');
|
||||||
|
img.src = value;
|
||||||
|
img.className = 'emoji-img';
|
||||||
|
el.appendChild(img);
|
||||||
|
} else {
|
||||||
|
el.textContent = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('btn-retour').addEventListener('click', () => {
|
||||||
|
window.location.href = `https://localhost:8000/`;
|
||||||
|
});
|
||||||
|
});
|
@ -0,0 +1,67 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
|
||||||
|
const left = document.querySelector('.left-emoji');
|
||||||
|
const right = document.querySelector('.right-emoji');
|
||||||
|
const childText = document.getElementById('child-text');
|
||||||
|
const heartGif = document.getElementById('heart-gif');
|
||||||
|
|
||||||
|
fetch(`https://localhost:8000/emojis/fusion/${id_user}/${id_left}/${id_right}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
child_emoji=data['baby'];
|
||||||
|
left.dataset.content=data['mommy'];
|
||||||
|
right.dataset.content=data['daddy'];
|
||||||
|
function insertEmojiOrImage(el) {
|
||||||
|
const value = el.dataset.content;
|
||||||
|
console.log(value)
|
||||||
|
if (/^https?:\/\//.test(value)) {
|
||||||
|
const img = document.createElement('img');
|
||||||
|
img.src = value;
|
||||||
|
img.className = 'emoji-img';
|
||||||
|
el.appendChild(img);
|
||||||
|
} else {
|
||||||
|
el.textContent = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
insertEmojiOrImage(left);
|
||||||
|
insertEmojiOrImage(right);
|
||||||
|
|
||||||
|
left.classList.add('slide-in-left');
|
||||||
|
right.classList.add('slide-in-right');
|
||||||
|
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
|
||||||
|
|
||||||
|
if (/^https?:\/\//.test(child_emoji)) {
|
||||||
|
emojiHtml = `
|
||||||
|
<div class="emoji-glow-img">
|
||||||
|
<img src="${child_emoji}" style="width:64px; height:64px">
|
||||||
|
</div>`;
|
||||||
|
} else {
|
||||||
|
emojiHtml = `
|
||||||
|
<span class="emoji-glow-text" data-emoji="${child_emoji}">${child_emoji}</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
childText.innerHTML = `
|
||||||
|
<div class="emoji-wrapper">
|
||||||
|
${emojiHtml}
|
||||||
|
|
||||||
|
</div>`;
|
||||||
|
childText.classList.add('growing-animation');
|
||||||
|
childText.style.display = 'block';
|
||||||
|
heartGif.style.display = 'block';
|
||||||
|
heartGif.classList.add('fade-in');
|
||||||
|
|
||||||
|
|
||||||
|
}, 3000);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Erreur:', error);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('btn-retour').addEventListener('click', () => {
|
||||||
|
window.location.href = `https://localhost:8000/`;
|
||||||
|
});
|
||||||
|
});
|
@ -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,98 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Entity\User;
|
||||||
|
use App\Repository\UserRepository;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||||
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
|
||||||
|
|
||||||
|
#[Route('/admin', name: 'admin_')]
|
||||||
|
#[IsGranted('ROLE_ADMIN')]
|
||||||
|
class AdminController extends AbstractController
|
||||||
|
{
|
||||||
|
private EntityManagerInterface $entityManager;
|
||||||
|
private UserPasswordHasherInterface $passwordHasher;
|
||||||
|
|
||||||
|
public function __construct(EntityManagerInterface $entityManager, UserPasswordHasherInterface $passwordHasher)
|
||||||
|
{
|
||||||
|
$this->entityManager = $entityManager;
|
||||||
|
$this->passwordHasher = $passwordHasher;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route('', name: 'admin_dashboard')]
|
||||||
|
public function dashboard(): Response
|
||||||
|
{
|
||||||
|
return $this->render('admin/index.html.twig');
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route('/users', name: 'users_list', methods: ['GET'])]
|
||||||
|
public function getUserById(UserRepository $userRepository): JsonResponse
|
||||||
|
{
|
||||||
|
$users = $userRepository->findAll();
|
||||||
|
|
||||||
|
$data = array_map(function (User $user) {
|
||||||
|
return [
|
||||||
|
'id' => $user->getId(),
|
||||||
|
'username' => $user->getUsername(),
|
||||||
|
'roles' => $user->getRoles(),
|
||||||
|
];
|
||||||
|
}, $users);
|
||||||
|
|
||||||
|
return $this->json($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route('/users/add', name: 'add_user', methods: ['POST'])]
|
||||||
|
public function addUser(Request $request, UserPasswordHasherInterface $passwordHasher): JsonResponse
|
||||||
|
{
|
||||||
|
$data = json_decode($request->getContent(), true);
|
||||||
|
|
||||||
|
$username = $data['username'] ?? null;
|
||||||
|
$password = $data['password'] ?? null;
|
||||||
|
$roles = $data['roles'] ?? ['ROLE_USER'];
|
||||||
|
|
||||||
|
if (!$username || !$password) {
|
||||||
|
return $this->json(['error' => 'Missing username or password'], Response::HTTP_BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
$existingUser = $this->entityManager->getRepository(User::class)->findOneBy(['username' => $username]);
|
||||||
|
if ($existingUser) {
|
||||||
|
return $this->json(['error' => 'User already exists'], Response::HTTP_CONFLICT);
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = new User();
|
||||||
|
$user->setUsername($username);
|
||||||
|
$user->setRoles($roles);
|
||||||
|
$user->setPassword($passwordHasher->hashPassword($user, $password));
|
||||||
|
|
||||||
|
$this->entityManager->persist($user);
|
||||||
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
return $this->json(['message' => 'User created successfully', 'id' => $user->getId()], Response::HTTP_CREATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route('/users/delete/{id}', name: 'delete_user', methods: ['DELETE'])]
|
||||||
|
public function deleteUser(int $id): JsonResponse
|
||||||
|
{
|
||||||
|
$user = $this->entityManager->getRepository(User::class)->find($id);
|
||||||
|
|
||||||
|
if (!$user) {
|
||||||
|
return $this->json(['error' => 'User not found'], Response::HTTP_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($user->getEmojis() as $userEmoji) {
|
||||||
|
$this->entityManager->remove($userEmoji);
|
||||||
|
}
|
||||||
|
$this->entityManager->remove($user);
|
||||||
|
$this->entityManager->flush();
|
||||||
|
|
||||||
|
return $this->json(['message' => 'User and related data deleted successfully'], Response::HTTP_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
|
class CombatController extends AbstractController
|
||||||
|
{
|
||||||
|
// Route designed for testing purposes
|
||||||
|
#[Route('/combat', name: 'app_combat')]
|
||||||
|
public function index(): Response
|
||||||
|
{
|
||||||
|
|
||||||
|
$leftEmoji = '🐱';
|
||||||
|
$rightEmoji = '🐶';
|
||||||
|
$winner = 'left'; // or 'right'
|
||||||
|
$loser = ($winner === 'left') ? 'right' : 'left';
|
||||||
|
|
||||||
|
return $this->render('combat/index.html.twig', [
|
||||||
|
'left_emoji' => $leftEmoji,
|
||||||
|
'right_emoji' => $rightEmoji,
|
||||||
|
'winner' => $winner,
|
||||||
|
'loser' => $loser,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function isEmoji(string $str): bool {
|
||||||
|
$emojiRegex = '/^\X$/u';
|
||||||
|
return preg_match($emojiRegex, $str) === 1 && mb_strlen($str, 'UTF-8') === 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route('/combat/{idLeft}/{idRight}', name: 'app_combat_with_params', requirements: ['leftEmoji' => '.+', 'rightEmoji' => '.+'])]
|
||||||
|
public function combatWithParams(string $idLeft, string $idRight): Response
|
||||||
|
// Example : /combat-🐱-🐶-left
|
||||||
|
// or /combat-🐌_☀%EF%B8%8F-🐌_☀%EF%B8%8F-left
|
||||||
|
{
|
||||||
|
return $this->render('combat/index.html.twig', [
|
||||||
|
'idLeft' => $idLeft,
|
||||||
|
'idRight' => $idRight,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Entity\User;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
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
|
||||||
|
{
|
||||||
|
private EntityManagerInterface $entityManager;
|
||||||
|
|
||||||
|
public function __construct(EntityManagerInterface $entityManager)
|
||||||
|
{
|
||||||
|
$this->entityManager = $entityManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[Route(path: '/login', name: 'app_login')]
|
||||||
|
public function login(AuthenticationUtils $authenticationUtils): Response
|
||||||
|
{
|
||||||
|
if ($this->getUser()) {
|
||||||
|
$user = $this->getUser();
|
||||||
|
$emojis = $user->getEmojis()->map(function ($userEmoji) {
|
||||||
|
$emoji = $userEmoji->getEmoji();
|
||||||
|
return [
|
||||||
|
'id' => $emoji->getId(),
|
||||||
|
'name' => $emoji->getName(),
|
||||||
|
'code' => $emoji->getCode(),
|
||||||
|
];
|
||||||
|
})->toArray();
|
||||||
|
|
||||||
|
return $this->render('home/index.html.twig', [
|
||||||
|
'user' => $user,
|
||||||
|
'emojis' => $emojis
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$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,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use App\Entity\User;
|
||||||
|
use App\Form\RegistrationFormType;
|
||||||
|
use App\Security\LoginFormAuthenticator;
|
||||||
|
use App\Service\EmojiService;
|
||||||
|
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,
|
||||||
|
EmojiService $emojiService
|
||||||
|
): 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();
|
||||||
|
|
||||||
|
$emojiService->addRandomStockEmojisToUser($user);
|
||||||
|
|
||||||
|
return $userAuthenticator->authenticateUser(
|
||||||
|
$user,
|
||||||
|
$authenticator,
|
||||||
|
$request
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('auth/register.html.twig', [
|
||||||
|
'registrationForm' => $form->createView(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
|
class ReproductionController extends AbstractController
|
||||||
|
{
|
||||||
|
// #[Route('/reproduction', name: 'app_reproduction')]
|
||||||
|
// public function index(): Response
|
||||||
|
// {
|
||||||
|
// $leftEmoji = '🐶'; // Emoji de gauche
|
||||||
|
// $rightEmoji = '🐱'; // Emoji de droite
|
||||||
|
// $childEmoji = 'https://emojik.vercel.app/s/%F0%9F%90%88_%F0%9F%90%95'; // Emoji enfant
|
||||||
|
// // $childEmoji = '🐱';
|
||||||
|
|
||||||
|
// return $this->render('reproduction/index.html.twig', [
|
||||||
|
// 'left_emoji' => $leftEmoji,
|
||||||
|
// 'right_emoji' => $rightEmoji,
|
||||||
|
// 'child_emoji' => $childEmoji
|
||||||
|
// ]);
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[Route('/reproduction/{idUser}/{id1}/{id2}', name: 'app_reproduction_with_params')]
|
||||||
|
public function reproductionWithParams(int $idUser, int $id1, int $id2): Response
|
||||||
|
{
|
||||||
|
|
||||||
|
return $this->render('reproduction/index.html.twig', [
|
||||||
|
'idUser' => $idUser,
|
||||||
|
'left_emoji' => $id1,
|
||||||
|
'right_emoji' => $id2,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
<?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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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,107 @@
|
|||||||
|
<?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\OneToMany(targetEntity: UserEmojis::class, mappedBy: 'user')]
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUserIdentifier(): string
|
||||||
|
{
|
||||||
|
return (string) $this->username;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Entity;
|
||||||
|
|
||||||
|
use App\Repository\UserEmojisRepository;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
#[ORM\Entity(repositoryClass: UserEmojisRepository::class)]
|
||||||
|
class UserEmojis
|
||||||
|
{
|
||||||
|
#[ORM\Id]
|
||||||
|
#[ORM\GeneratedValue]
|
||||||
|
#[ORM\Column]
|
||||||
|
private ?int $id = null;
|
||||||
|
|
||||||
|
#[ORM\ManyToOne(targetEntity: User::class)]
|
||||||
|
#[ORM\JoinColumn(nullable: false)]
|
||||||
|
private ?User $user = null;
|
||||||
|
|
||||||
|
#[ORM\ManyToOne(targetEntity: Emoji::class)]
|
||||||
|
#[ORM\JoinColumn(nullable: false)]
|
||||||
|
private ?Emoji $emoji = null;
|
||||||
|
|
||||||
|
public function getId(): ?int
|
||||||
|
{
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUser(): ?User
|
||||||
|
{
|
||||||
|
return $this->user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUser(?User $user): static
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEmoji(): ?Emoji
|
||||||
|
{
|
||||||
|
return $this->emoji;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setEmoji(?Emoji $emoji): static
|
||||||
|
{
|
||||||
|
$this->emoji = $emoji;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
@ -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,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Repository;
|
||||||
|
|
||||||
|
use App\Entity\UserEmojis;
|
||||||
|
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||||
|
use Doctrine\Persistence\ManagerRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @extends ServiceEntityRepository<UserEmojis>
|
||||||
|
*
|
||||||
|
* @method UserEmojis|null find($id, $lockMode = null, $lockVersion = null)
|
||||||
|
* @method UserEmojis|null findOneBy(array $criteria, array $orderBy = null)
|
||||||
|
* @method UserEmojis[] findAll()
|
||||||
|
* @method UserEmojis[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
|
||||||
|
*/
|
||||||
|
class UserEmojisRepository extends ServiceEntityRepository
|
||||||
|
{
|
||||||
|
public function __construct(ManagerRegistry $registry)
|
||||||
|
{
|
||||||
|
parent::__construct($registry, UserEmojis::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * @return UserEmojis[] Returns an array of UserEmojis 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): ?UserEmojis
|
||||||
|
// {
|
||||||
|
// return $this->createQueryBuilder('u')
|
||||||
|
// ->andWhere('u.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,104 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Service;
|
||||||
|
|
||||||
|
use App\Entity\Emoji;
|
||||||
|
use App\Entity\User;
|
||||||
|
use App\Entity\UserEmojis;
|
||||||
|
use App\Entity\Rarity;
|
||||||
|
use App\Repository\StockEmojiRepository;
|
||||||
|
use App\Repository\RarityRepository;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
|
||||||
|
class EmojiService
|
||||||
|
{
|
||||||
|
private $entityManager;
|
||||||
|
private $stockEmojiRepository;
|
||||||
|
private $rarityRepository;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
EntityManagerInterface $entityManager,
|
||||||
|
StockEmojiRepository $stockEmojiRepository,
|
||||||
|
RarityRepository $rarityRepository
|
||||||
|
) {
|
||||||
|
$this->entityManager = $entityManager;
|
||||||
|
$this->stockEmojiRepository = $stockEmojiRepository;
|
||||||
|
$this->rarityRepository = $rarityRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addRandomStockEmojisToUser(User $user, int $numberOfEmojis = 4): void
|
||||||
|
{
|
||||||
|
$stockEmojis = $this->stockEmojiRepository->findAll();
|
||||||
|
|
||||||
|
if (count($stockEmojis) < $numberOfEmojis) {
|
||||||
|
throw new \RuntimeException('Not enough emojis in stock.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$randomEmojis = $this->getRandomEmojis($stockEmojis, $numberOfEmojis);
|
||||||
|
|
||||||
|
foreach ($randomEmojis as $stockEmoji) {
|
||||||
|
$emoji = new Emoji();
|
||||||
|
$emoji->setName($stockEmoji->getName());
|
||||||
|
$emoji->setCode($stockEmoji->getCode());
|
||||||
|
$emoji->setStrength(mt_rand(0, 10));
|
||||||
|
$emoji->setToughness(mt_rand(0, 10));
|
||||||
|
$emoji->setIntelligence(mt_rand(0, 10));
|
||||||
|
$emoji->setSpeed(mt_rand(0, 10));
|
||||||
|
$emoji->setFightsWon(0);
|
||||||
|
|
||||||
|
// Set the rarity
|
||||||
|
$rarity = $this->generateRarity();
|
||||||
|
$emoji->setRarity($rarity);
|
||||||
|
|
||||||
|
$this->entityManager->persist($emoji);
|
||||||
|
|
||||||
|
$userEmoji = new UserEmojis();
|
||||||
|
$userEmoji->setUser($user);
|
||||||
|
$userEmoji->setEmoji($emoji);
|
||||||
|
|
||||||
|
$this->entityManager->persist($userEmoji);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->entityManager->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getRandomEmojis(array $stockEmojis, int $count): array
|
||||||
|
{
|
||||||
|
shuffle($stockEmojis);
|
||||||
|
return array_slice($stockEmojis, 0, $count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generateRarity(): Rarity
|
||||||
|
{
|
||||||
|
$rarities = $this->rarityRepository->findAll();
|
||||||
|
$rand = mt_rand() / mt_getrandmax();
|
||||||
|
|
||||||
|
$sum = 0.0;
|
||||||
|
foreach ($rarities as $rarity) {
|
||||||
|
$sum += $rarity->getDropRate();
|
||||||
|
if ($sum > $rand) {
|
||||||
|
return $rarity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $rarities[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEmojisByUser(User $user): array
|
||||||
|
{
|
||||||
|
return $user->getEmojis()->map(function ($userEmoji) {
|
||||||
|
$emoji = $userEmoji->getEmoji();
|
||||||
|
return [
|
||||||
|
'id' => $emoji->getId(),
|
||||||
|
'name' => $emoji->getName(),
|
||||||
|
'code' => $emoji->getCode(),
|
||||||
|
'strength' => $emoji->getStrength(),
|
||||||
|
'toughness' => $emoji->getToughness(),
|
||||||
|
'intelligence' => $emoji->getIntelligence(),
|
||||||
|
'speed' => $emoji->getSpeed(),
|
||||||
|
'fightsWon' => $emoji->getFightsWon(),
|
||||||
|
'rarity' => $emoji->getRarity() ? $emoji->getRarity()->getId() : 0,
|
||||||
|
];
|
||||||
|
})->toArray();
|
||||||
|
}
|
||||||
|
}
|
@ -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 %}
|
@ -0,0 +1,29 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Emoji Fight</title>
|
||||||
|
<link rel="stylesheet" href="{{ asset('style/combat.css?v=1.5') }}" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="arena">
|
||||||
|
<div class="emoji left-emoji" data-content=""></div>
|
||||||
|
<div class="emoji right-emoji" data-content=""></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<button id="btn-retour" class="btn-retour">🏠 Retour à la collection</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="winner-text"></div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const id1 = {{ idLeft }};
|
||||||
|
const id2 = {{ idRight }};
|
||||||
|
</script>
|
||||||
|
<script src="{{ asset('script/combat.js?v=1.4') }}"></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,31 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Emoji Reproduction</title>
|
||||||
|
<link rel="stylesheet" href="{{ asset('style/reproduction.css?v=1.7') }}" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="field">
|
||||||
|
<div class="emoji left-emoji"></div>
|
||||||
|
<div class="emoji right-emoji"></div>
|
||||||
|
</div>
|
||||||
|
<div id="child-text"></div>
|
||||||
|
<div id="heart-gif"></div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<button id="btn-retour" class="btn-retour">🏠 Retour à la collection</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
id_user={{ idUser }};
|
||||||
|
id_left={{ left_emoji }};
|
||||||
|
id_right={{ right_emoji }};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script src="{{ asset('script/reproduction.js?v=1.5') }}"></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Reference in new issue