Compare commits

..

No commits in common. 'main' and 'Jade-Front' have entirely different histories.

@ -40,14 +40,12 @@ security:
access_control: access_control:
- { path: ^/login, roles: PUBLIC_ACCESS } - { path: ^/login, roles: PUBLIC_ACCESS }
- { path: ^/register, roles: PUBLIC_ACCESS } - { path: ^/register, roles: PUBLIC_ACCESS }
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/, roles: ROLE_USER } - { path: ^/, roles: ROLE_USER }
when@test: when@test:
security: security:
password_hashers: password_hashers:

@ -0,0 +1,62 @@
<?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);
}
}

@ -0,0 +1,71 @@
<?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 @@
<?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 Version20250610074721 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 stock_emoji (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, code VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL)
SQL);
$this->addSql(<<<'SQL'
CREATE TABLE user (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, username VARCHAR(180) NOT NULL, roles CLOB NOT NULL --(DC2Type:json)
, password VARCHAR(255) NOT NULL)
SQL);
$this->addSql(<<<'SQL'
CREATE UNIQUE INDEX UNIQ_8D93D649F85E0677 ON user (username)
SQL);
$this->addSql(<<<'SQL'
CREATE TABLE posseder (user_id INTEGER NOT NULL, emoji_id INTEGER NOT NULL, PRIMARY KEY(user_id, emoji_id), CONSTRAINT FK_62EF7CBAA76ED395 FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE, CONSTRAINT FK_62EF7CBAE2462A5B FOREIGN KEY (emoji_id) REFERENCES emoji (id) ON DELETE CASCADE NOT DEFERRABLE INITIALLY IMMEDIATE)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_62EF7CBAA76ED395 ON posseder (user_id)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_62EF7CBAE2462A5B ON posseder (emoji_id)
SQL);
$this->addSql(<<<'SQL'
CREATE TEMPORARY TABLE __temp__rarity AS SELECT id, name, drop_rate FROM rarity
SQL);
$this->addSql(<<<'SQL'
DROP TABLE rarity
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'
INSERT INTO rarity (id, name, drop_rate) SELECT id, name, drop_rate FROM __temp__rarity
SQL);
$this->addSql(<<<'SQL'
DROP TABLE __temp__rarity
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 stock_emoji
SQL);
$this->addSql(<<<'SQL'
DROP TABLE user
SQL);
$this->addSql(<<<'SQL'
DROP TABLE posseder
SQL);
$this->addSql(<<<'SQL'
CREATE TEMPORARY TABLE __temp__rarity AS SELECT id, name, drop_rate FROM rarity
SQL);
$this->addSql(<<<'SQL'
DROP TABLE rarity
SQL);
$this->addSql(<<<'SQL'
CREATE TABLE rarity (id INTEGER DEFAULT NULL, name VARCHAR(255) NOT NULL, drop_rate DOUBLE PRECISION NOT NULL, PRIMARY KEY(id))
SQL);
$this->addSql(<<<'SQL'
INSERT INTO rarity (id, name, drop_rate) SELECT id, name, drop_rate FROM __temp__rarity
SQL);
$this->addSql(<<<'SQL'
DROP TABLE __temp__rarity
SQL);
}
}

@ -0,0 +1,31 @@
<?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 Version20250610074733 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
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
}
}

@ -1,90 +0,0 @@
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;
}

@ -4,13 +4,6 @@ body {
text-align: center; text-align: center;
} }
body, html {
margin: 0;
padding: 0;
height: 100%;
overflow-x: hidden;
}
h1 { h1 {
font-size: 3rem; font-size: 3rem;
margin-bottom: 30px; margin-bottom: 30px;
@ -158,12 +151,6 @@ h1 {
margin-bottom: 10px; margin-bottom: 10px;
} }
.emoji img {
vertical-align: middle;
width: 68px;
height: 68px;
}
.emoji-name { .emoji-name {
font-weight: bold; font-weight: bold;
font-size: 1.2rem; font-size: 1.2rem;
@ -202,16 +189,10 @@ h1 {
background-color: #e5d6b8; background-color: #e5d6b8;
} }
.detail-icon {
.btn-logout {
width: 238px;
height: 50px;
}
.detail-icon-hierarchy {
position: absolute; position: absolute;
top: 8px; top: 8px;
left: 10px; right: 10px;
cursor: pointer; cursor: pointer;
font-size: 18px; font-size: 18px;
color: #555; color: #555;
@ -234,112 +215,6 @@ color: #555;
font-size: 14px; font-size: 14px;
} }
/* Partie Hierachie*/
.hierarchy-modal {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
display: none; /* sera activé par JS */
z-index: 1000;
}
.hierarchy-overlay {
position: fixed; /* ← Important ! */
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0,0,0,0.6);
z-index: 1001;
}
.hierarchy-content {
position: fixed; /* ← Pour rester centré par rapport au viewport */
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 20px;
border-radius: 12px;
z-index: 1002;
box-shadow: 0 0 20px rgba(0,0,0,0.5);
max-width: 90%;
width: 500px;
}
.close-btn {
position: absolute;
top: 10px;
right: 20px;
font-size: 30px;
cursor: pointer;
}
.hierarchy-graph {
display: grid;
grid-template-columns: 1fr auto 1fr;
grid-template-rows: auto auto;
grid-template-areas:
"parent1 arrows parent2"
". child .";
gap: 10px 30px;
align-items: center;
justify-items: center;
margin-top: 30px;
}
.child-block {
grid-area: child;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}
.parent-block {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}
.parent-block .emoji {
font-size: 40px;
margin-bottom: 5px;
}
.parent-block .name {
font-size: 14px;
color: #444;
font-style: italic;
}
.arrows {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.arrow {
font-size: 24px;
margin: 10px 0;
}
.child {
grid-area: child;
font-size: 50px;
padding: 10px;
}
.connector {
grid-column: 2;
font-size: 30px;
color: #444;
}
/* Filtre et Tri*/ /* Filtre et Tri*/
.filter-bar { .filter-bar {
margin-bottom: 30px; margin-bottom: 30px;

@ -51,20 +51,50 @@ document.addEventListener('DOMContentLoaded', () => {
const id1 = selectedCards[0].dataset.id; const id1 = selectedCards[0].dataset.id;
const id2 = selectedCards[1].dataset.id; const id2 = selectedCards[1].dataset.id;
const idUser = document.getElementById('user-data').dataset.userId;
if (type === 'reproduction') { if (type === 'reproduction') {
try {
const response = await fetch(`/emojis/fusion/${encodeURIComponent(id1)}/${encodeURIComponent(id2)}`, {
method: 'POST',
headers: {
'Accept': 'application/json'
}
});
window.location.href = `https://localhost:8000/reproduction/${encodeURIComponent(idUser)}/${encodeURIComponent(id1)}/${encodeURIComponent(id2)}`; if (!response.ok) {
throw new Error("Erreur serveur : " + response.status);
}
const data = await response.json();
alert(`Succès : ${data.message} (ID : ${data.childId})`);
// Tu peux aussi mettre à jour le DOM ici avec le nouvel enfant
// ex: ajouter une carte, etc.
} catch (error) {
console.error("Erreur lors de la reproduction :", error);
alert("Une erreur est survenue lors de la reproduction.");
}
return; // on quitte ici return; // on quitte ici
} }
if (type === 'combat') { if (type === 'combat') {
window.location.href = `https://localhost:8000/combat/${encodeURIComponent(id1)}/${encodeURIComponent(id2)}`; fetch(`/emojis/fight/${id1}/${id2}`, { method: 'GET',
headers: {
return; // on quitte ici 'Accept': 'application/json'
}}).then(response => {
if (!response.ok) {
throw new Error(`Erreur HTTP ${response.status}`);
}
return response.json();
})
.then(data => {
console.log('Données reçues :', data);
})
.catch(error => {
console.error('Erreur lors de la requête :', error);
});
} }
@ -82,63 +112,6 @@ document.addEventListener('DOMContentLoaded', () => {
} }
} }
// Ouvre / Ferme la popup de hierachie de famille
async function toggleHierachiPopup(id) {
try {
const response = await fetch(`/emojis/${id}/getParents/`, {
method: 'GET',
headers: {
'Accept': 'application/json'
}
});
if (!response.ok) throw new Error("Erreur serveur : " + response.status);
const data = await response.json();
// Injection dynamique dans la popup
const parent1El = document.getElementById(`parent1-${id}`);
if (data.codeParent1 && data.codeParent1.includes('vercel')) {
parent1El.innerHTML = `<img src="${data.codeParent1}" alt="Parent 1" width="48" height="48">`;
} else {
parent1El.innerText = data.codeParent1 || '❓';
}
const parent2El = document.getElementById(`parent2-${id}`);
if (data.codeParent2 && data.codeParent2.includes('vercel')) {
parent2El.innerHTML = `<img src="${data.codeParent2}" alt="Parent 2" width="48" height="48">`;
} else {
parent2El.innerText = data.codeParent2 || '❓';
}
const childEl = document.getElementById(`child-${id}`);
if (data.codeEnfant && data.codeEnfant.includes('vercel')) {
childEl.innerHTML = `<img src="${data.codeEnfant}" alt="Emoji fusionné" width="64" height="64">`;
} else {
childEl.innerText = data.codeEnfant || '❓';
}
document.getElementById(`name-parent1-${id}`).innerText = data.nameParent1 || 'inconnu';
document.getElementById(`name-parent2-${id}`).innerText = data.nameParent2 || 'inconnu';
document.getElementById(`name-child-${id}`).innerText = data.nameEnfant || 'inconnu';
console.log("Parents récupérés :", data);
// Affichage plein écran
const popup = document.getElementById(`popup-hiera-${id}`);
if (popup) popup.style.display = 'block';
} catch (error) {
console.error("Erreur lors de la récupération des parents :", error);
alert("Une erreur est survenue lors de l'affichage de la hiérarchie.");
}
}
function closeHierarchyPopup(id) {
const popup = document.getElementById(`popup-hiera-${id}`);
if (popup) popup.style.display = 'none';
}
// Fermer les autres popups en cliquant ailleurs // Fermer les autres popups en cliquant ailleurs
document.addEventListener('click', function(e) { document.addEventListener('click', function(e) {
document.querySelectorAll('.popup').forEach(p => { document.querySelectorAll('.popup').forEach(p => {
@ -146,16 +119,6 @@ document.addEventListener('DOMContentLoaded', () => {
p.style.display = 'none'; p.style.display = 'none';
} }
}); });
// Partie pour fermer la popup de hiérarchie
document.querySelectorAll('.close-btn').forEach(btn => {
btn.addEventListener('click', (e) => {
const id = btn.dataset.id; // On récupère l'id depuis l'attribut data-id
const popup = document.getElementById(`popup-hiera-${id}`);
if (popup) popup.style.display = 'none';
e.stopPropagation(); // Empêche la propagation du clic
});
});
}); });
// Fonction pour appliquer la recherche, les filtres et le tri // Fonction pour appliquer la recherche, les filtres et le tri
@ -181,7 +144,7 @@ document.addEventListener('DOMContentLoaded', () => {
}); });
if (sortBy !== 'none') { if (sortBy !== 'none') {
const container = document.getElementById('collection-container'); const container = document.getElementById('collection-container'); // ✅ corrigé
const visibleCards = cards.filter(c => c.style.display !== 'none'); const visibleCards = cards.filter(c => c.style.display !== 'none');
visibleCards.sort((a, b) => { visibleCards.sort((a, b) => {
@ -207,18 +170,6 @@ document.addEventListener('DOMContentLoaded', () => {
}); });
}); });
// Appel Fonctionnalité de popup de hierachie de famille
document.querySelectorAll('.detail-icon-hierarchy').forEach(icon => {
icon.addEventListener('click', (e) => {
const card = icon.closest('.emoji-card');
const id = card?.dataset.id;
if (id) {
toggleHierachiPopup(id);
}
e.stopPropagation(); // évite que ça sélectionne la carte
});
});
// Appliquer l'écouteur à toutes les cartes (base + collection) // Appliquer l'écouteur à toutes les cartes (base + collection)
document.querySelectorAll('.emoji-container').forEach(container => { document.querySelectorAll('.emoji-container').forEach(container => {
container.addEventListener('click', (e) => { container.addEventListener('click', (e) => {

@ -3,7 +3,7 @@ document.addEventListener('DOMContentLoaded', () => {
const right = document.querySelector('.right-emoji'); const right = document.querySelector('.right-emoji');
const winnerText = document.getElementById('winner-text'); const winnerText = document.getElementById('winner-text');
fetch(`https://localhost:8000/emojis/fight/${id1}/${id2}`) fetch(`localhost:8000/emojis/fight/${id1}/${id2}`)
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
const { leftEmoji, rightEmoji, winner } = data; const { leftEmoji, rightEmoji, winner } = data;
@ -58,8 +58,4 @@ document.addEventListener('DOMContentLoaded', () => {
el.textContent = value; el.textContent = value;
} }
} }
document.getElementById('btn-retour').addEventListener('click', () => {
window.location.href = `https://localhost:8000/`;
});
}); });

@ -5,7 +5,7 @@ document.addEventListener('DOMContentLoaded', () => {
const childText = document.getElementById('child-text'); const childText = document.getElementById('child-text');
const heartGif = document.getElementById('heart-gif'); const heartGif = document.getElementById('heart-gif');
fetch(`https://localhost:8000/emojis/fusion/${id_user}/${id_left}/${id_right}`) fetch(`http://localhost:8000/emojis/fusion/${id_left}/${id_right}`)
.then(response => response.json()) .then(response => response.json())
.then(data => { .then(data => {
child_emoji=data['baby']; child_emoji=data['baby'];
@ -60,8 +60,4 @@ document.addEventListener('DOMContentLoaded', () => {
.catch(error => { .catch(error => {
console.error('Erreur:', error); console.error('Erreur:', error);
}); });
document.getElementById('btn-retour').addEventListener('click', () => {
window.location.href = `https://localhost:8000/`;
});
}); });

@ -130,28 +130,3 @@ body {
text-align: center; text-align: center;
display: none; display: none;
} }
/* Bouton de retour */
.btn-retour {
position: absolute;
top: 20px;
left: 50%;
transform: translateX(-50%);
padding: 10px 25px;
font-size: 1.1rem;
font-weight: bold;
background-color: #f2e6c9;
border: 2px solid #000;
border-radius: 8px;
cursor: pointer;
box-shadow: 2px 2px 0 #000;
transition: transform 0.2s ease;
z-index: 9999; /* pour quil soit toujours au-dessus */
}
.btn-retour:hover {
transform: translateX(-50%) scale(1.05);
background-color: #e0d1b3;
}

@ -152,28 +152,3 @@ body {
background-size: 100% 100%; background-size: 100% 100%;
z-index: -1; z-index: -1;
} }
/* Bouton de retour */
.btn-retour {
position: absolute;
top: 20px;
left: 50%;
transform: translateX(-50%);
padding: 10px 25px;
font-size: 1.1rem;
font-weight: bold;
background-color: #f2e6c9;
border: 2px solid #000;
border-radius: 8px;
cursor: pointer;
box-shadow: 2px 2px 0 #000;
transition: transform 0.2s ease;
z-index: 9999; /* pour quil soit toujours au-dessus */
}
.btn-retour:hover {
transform: translateX(-50%) scale(1.05);
background-color: #e0d1b3;
}

@ -1,98 +0,0 @@
<?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);
}
}

@ -3,7 +3,6 @@ namespace App\Controller;
use App\Entity\Emoji; use App\Entity\Emoji;
use App\Entity\Rarity; use App\Entity\Rarity;
use App\Service\EmojiService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
@ -13,27 +12,17 @@ use Symfony\Contracts\HttpClient\HttpClientInterface;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use App\Repository\EmojiRepository; use App\Repository\EmojiRepository;
use App\Entity\UserEmojis;
use App\Repository\UserRepository;
use App\Repository\UserEmojisRepository;
#[Route('/emojis', name: 'app_emoji_')] #[Route('/emojis', name: 'app_emoji_')]
class EmojiController extends AbstractController class EmojiController extends AbstractController
{ {
private RarityRepository $rarityRepository; private RarityRepository $rarityRepository;
private HttpClientInterface $httpClient; private HttpClientInterface $httpClient;
private EmojiService $emojiService;
private UserRepository $userRepository;
private UserEmojisRepository $userEmojisRepository;
public function __construct(RarityRepository $rarityRepository, HttpClientInterface $httpClient, EmojiService $emojiService, public function __construct(RarityRepository $rarityRepository, HttpClientInterface $httpClient)
UserRepository $userRepository, UserEmojisRepository $userEmojisRepository)
{ {
$this->rarityRepository = $rarityRepository; $this->rarityRepository = $rarityRepository;
$this->httpClient = $httpClient; $this->httpClient = $httpClient;
$this->emojiService = $emojiService;
$this->userRepository = $userRepository;
$this->userEmojisRepository = $userEmojisRepository;
} }
#[Route('/', name: 'emojis')] #[Route('/', name: 'emojis')]
@ -75,7 +64,7 @@ class EmojiController extends AbstractController
$emoji->setFightsWon(0); $emoji->setFightsWon(0);
// On récupère une instance de Rarity existante (par exemple, la première) // On récupère une instance de Rarity existante (par exemple, la première)
$rarity = $this->emojiService->generateRarity(); $rarity = $this->getRarity();
if (!$rarity) { if (!$rarity) {
throw new \RuntimeException('Aucun objet Rarity trouvé en base.'); throw new \RuntimeException('Aucun objet Rarity trouvé en base.');
} }
@ -91,6 +80,21 @@ class EmojiController extends AbstractController
return new Response(); return new Response();
} }
private function getRarity(): Rarity {
$rarity = $this->rarityRepository->findAll();
$rand = mt_rand() / mt_getrandmax();
$sum = 0.0;
foreach($rarity as $r) {
$sum += $r->getDropRate();
if($sum > $rand) {
return $r;
}
}
return $rarity[0];
}
// Renvoi l'url de l'image issue de la fusion de deux emojis. Fonctionne avec un code et un emoji directement // Renvoi l'url de l'image issue de la fusion de deux emojis. Fonctionne avec un code et un emoji directement
private function getFusionUrl(string $emoji1, string $emoji2): string private function getFusionUrl(string $emoji1, string $emoji2): string
{ {
@ -104,15 +108,8 @@ class EmojiController extends AbstractController
return sprintf('%s%s_%s?size=%d', $baseUrl, $encodedEmoji1, $encodedEmoji2, $size); return sprintf('%s%s_%s?size=%d', $baseUrl, $encodedEmoji1, $encodedEmoji2, $size);
} }
#[Route('/fusion/{userId}/{emoji1_id}/{emoji2_id}', name: 'fusion', methods: ['GET'], requirements: ['userId' => '\d+', 'emoji1_id' => '\d+', 'emoji2_id' => '\d+'])] #[Route('/fusion/{emoji1_id}/{emoji2_id}', name: 'fusion')]
public function reproduceEmoji(int $userId, int $emoji1_id, int $emoji2_id, EntityManagerInterface $entityManager, EmojiRepository $emojiRepository): JsonResponse { public function reproduceEmoji(int $emoji1_id, int $emoji2_id, EntityManagerInterface $entityManager, EmojiRepository $emojiRepository): JsonResponse {
$user = $this->userRepository->findOneBy(['id' => $userId]);
if (!$user) {
return new JsonResponse(['error' => 'User not found'], 404);
}
$emoji1 = $emojiRepository->find($emoji1_id); $emoji1 = $emojiRepository->find($emoji1_id);
$emoji2 = $emojiRepository->find($emoji2_id); $emoji2 = $emojiRepository->find($emoji2_id);
@ -180,33 +177,23 @@ class EmojiController extends AbstractController
$child->setFightsWon(0); $child->setFightsWon(0);
$child->setRarity($this->emojiService->generateRarity()); $child->setRarity($this->getRarity());
$child->setParent1($emoji1); $child->setParent1($emoji1);
$child->setParent2($emoji2); $child->setParent2($emoji2);
$entityManager->persist($child); $entityManager->persist($child);
$userEmoji = new UserEmojis();
$userEmoji->setUser($user);
$userEmoji->setEmoji($child);
$entityManager->persist($userEmoji);
$entityManager->flush(); $entityManager->flush();
return new JsonResponse([ return new JsonResponse([
'message' => 'Child created', 'message' => 'Child created',
'mommy' => $child->getParent1()->getCode(), 'childId' => $child->getId()
'daddy' => $child->getParent2()->getCode(),
'baby' => $child->getCode()
]); ]);
} }
#[Route('/fight/{idEmoji1}/{idEmoji2}', name: 'fight_emoji', methods: ['GET'], requirements: ['idEmoji1' => '\d+', 'idEmoji2' => '\d+'])] #[Route('/fight/{idEmoji1}/{idEmoji2}', name: 'fight_emoji')]
public function fightEmoji(int $idEmoji1, int $idEmoji2, EntityManagerInterface $entityManager, EmojiRepository $emojiRepository): JsonResponse public function fightEmoji(int $idEmoji1, int $idEmoji2, EntityManagerInterface $entityManager, EmojiRepository $emojiRepository): JsonResponse {
{
$emoji1 = $emojiRepository->find($idEmoji1); $emoji1 = $emojiRepository->find($idEmoji1);
$emoji2 = $emojiRepository->find($idEmoji2); $emoji2 = $emojiRepository->find($idEmoji2);
@ -217,6 +204,17 @@ class EmojiController extends AbstractController
$valEmoji1 = [$emoji1->getStrength(),$emoji1->getToughness(),$emoji1->getIntelligence(),$emoji1->getSpeed()]; $valEmoji1 = [$emoji1->getStrength(),$emoji1->getToughness(),$emoji1->getIntelligence(),$emoji1->getSpeed()];
$valEmoji2 = [$emoji2->getStrength(),$emoji2->getToughness(),$emoji2->getIntelligence(),$emoji2->getSpeed()]; $valEmoji2 = [$emoji2->getStrength(),$emoji2->getToughness(),$emoji2->getIntelligence(),$emoji2->getSpeed()];
$difference = $valEmoji1[$aleatoire] - $valEmoji2[$aleatoire]; $difference = $valEmoji1[$aleatoire] - $valEmoji2[$aleatoire];
// if($difference > 0){
// $emoji1->wonFight();
// $entityManager->persist($emoji1);
// $entityManager->remove($emoji2);
// } else {
// $emoji2->wonFight();
// $entityManager->persist($emoji2);
// $entityManager->remove($emoji1);
// }
// $entityManager->flush();
if ($difference > 0) { if ($difference > 0) {
$winner = $emoji1; $winner = $emoji1;
@ -229,17 +227,13 @@ class EmojiController extends AbstractController
} }
$winner->wonFight(); $winner->wonFight();
$userEmojiLoser = $this->userEmojisRepository->findOneBy(['emoji' => $loser]);
$entityManager->persist($winner); $entityManager->persist($winner);
$entityManager->remove($loser); $entityManager->remove($loser);
$entityManager->remove($userEmojiLoser);
$entityManager->flush(); $entityManager->flush();
return new JsonResponse([ return new JsonResponse([
'leftEmoji' => $emoji1->getCode(), 'emoji1' => $emoji1->getCode(),
'rightEmoji' => $emoji2->getCode(), 'emoji2' => $emoji2->getCode(),
'winner' => $wonFight 'winner' => $wonFight
]); ]);
} }
@ -260,38 +254,4 @@ class EmojiController extends AbstractController
$vic = $this->fightEmoji($e,$e2); $vic = $this->fightEmoji($e,$e2);
echo $vic->getName(); echo $vic->getName();
} }
#[Route('/{emojiID}/getParents/', name: 'get_parents_emoji', methods: ['GET'])]
public function getParentsEmoji(int $emojiID, EmojiRepository $emojiRepository): JsonResponse {
$emoji = $emojiRepository->find($emojiID);
if (!$emoji) {
return new JsonResponse(['error' => 'Emoji not found'], 404);
}
$codeParent1 = null;
$codeParent2 = null;
$nameParent1 = 'inconnu';
$nameParent2 = 'inconnu';
if ($emoji->getParent1()) {
$codeParent1 = $emoji->getParent1()->getCode();
$nameParent1 = $emoji->getParent1()->getName();
}
if ($emoji->getParent2()) {
$codeParent2 = $emoji->getParent2()->getCode();
$nameParent2 = $emoji->getParent2()->getName();
}
return new JsonResponse([
'codeParent1' => $codeParent1,
'nameParent1' => $nameParent1,
'codeParent2' => $codeParent2,
'nameParent2' => $nameParent2,
'codeEnfant' => $emoji->getCode(),
'nameEnfant' => $emoji->getName(),
]);
}
} }

@ -2,38 +2,188 @@
namespace App\Controller; namespace App\Controller;
use App\Service\EmojiService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
class HomeController extends AbstractController class HomeController extends AbstractController
{ {
private EmojiService $emojiService;
public function __construct(EmojiService $emojiService)
{
$this->emojiService = $emojiService;
}
#[Route('/', name: 'app_home')] #[Route('/', name: 'app_home')]
public function index(): Response public function index(): Response
{ {
$user = $this->getUser(); $emojisDeBase = [
[
'id' => 1,
'nom' => 'Bob',
'code' => '😊',
'force' => 12.5,
'robustesse' => 9.3,
'intelligence' => 7.8,
'vitesse' => 10.0,
'nbCombatGagne' => 3,
'rarete' => 3, // épique
],
[
'id' => 2,
'nom' => 'John',
'code' => '😭',
'force' => 5.1,
'robustesse' => 4.2,
'intelligence' => 3.3,
'vitesse' => 6.0,
'nbCombatGagne' => 1,
'rarete' => 1, // commun
],
[
'id' => 3,
'nom' => 'Rodolph',
'code' => '😁',
'force' => 20.0,
'robustesse' => 15.0,
'intelligence' => 18.0,
'vitesse' => 17.0,
'nbCombatGagne' => 10,
'rarete' => 5, // légendaire
],
[
'id' => 4,
'nom' => 'Sophie',
'code' => '😎',
'force' => 8.0,
'robustesse' => 7.5,
'intelligence' => 9.0,
'vitesse' => 8.5,
'nbCombatGagne' => 2,
'rarete' => 4, // mythique
]
];
if (!$user) { $emojisCrees = [
return $this->redirectToRoute('app_login'); [
} 'id' => 6,
'nom' => 'Benoit',
// Récupération des emojis 'code' => '🤖',
$allEmojis = $this->emojiService->getEmojisByUser($user); 'force' => 15.0,
'robustesse' => 12.0,
// Séparation : 4 premiers en base, le reste en créés 'intelligence' => 14.0,
$emojisDeBase = array_slice($allEmojis, 0, 4); 'vitesse' => 13.0,
$emojisCrees = array_slice($allEmojis, 4); 'nbCombatGagne' => 5,
'rarete' => 3, // épique
],
[
'id' => 7,
'nom' => 'Eric',
'code' => '🌟',
'force' => 18.0,
'robustesse' => 16.0,
'intelligence' => 17.0,
'vitesse' => 19.0,
'nbCombatGagne' => 8,
'rarete' => 5, // légendaire
],
[
'id' => 5,
'nom' => 'Alice',
'code' => '🥳',
'force' => 6.0,
'robustesse' => 5.0,
'intelligence' => 4.5,
'vitesse' => 6.5,
'nbCombatGagne' => 0,
'rarete' => 2, // rare
],
[
'id' => 8,
'nom' => 'Bobette',
'code' => '🤩',
'force' => 10.0,
'robustesse' => 9.0,
'intelligence' => 11.0,
'vitesse' => 12.0,
'nbCombatGagne' => 4,
'rarete' => 4, // mythique
],
[
'id' => 9,
'nom' => 'Charlie',
'code' => '😇',
'force' => 7.0,
'robustesse' => 6.0,
'intelligence' => 8.0,
'vitesse' => 7.5,
'nbCombatGagne' => 2,
'rarete' => 1, // commun
],
[
'id' => 10,
'nom' => 'Diana',
'code' => '😈',
'force' => 14.0,
'robustesse' => 13.0,
'intelligence' => 15.0,
'vitesse' => 16.0,
'nbCombatGagne' => 6,
'rarete' => 4, // mythique
],
[
'id' => 11,
'nom' => 'Ethan',
'code' => '🤯',
'force' => 9.0,
'robustesse' => 8.0,
'intelligence' => 10.0,
'vitesse' => 11.0,
'nbCombatGagne' => 3,
'rarete' => 3, // épique
],
[
'id' => 12,
'nom' => 'Fiona',
'code' => '🥺',
'force' => 4.0,
'robustesse' => 3.5,
'intelligence' => 5.0,
'vitesse' => 4.5,
'nbCombatGagne' => 1,
'rarete' => 1, // commun
],
[
'id' => 13,
'nom' => 'George',
'code' => '😜',
'force' => 11.0,
'robustesse' => 10.0,
'intelligence' => 12.0,
'vitesse' => 13.5,
'nbCombatGagne' => 2,
'rarete' => 3, // épique
],
[
'id' => 14,
'nom' => 'Hannah',
'code' => '😏',
'force' => 3.0,
'robustesse' => 2.5,
'intelligence' => 4.0,
'vitesse' => 3.5,
'nbCombatGagne' => 0,
'rarete' => 2, // rare
],
[
'id' => 15,
'nom' => 'Ian',
'code' => '😬',
'force' => 17.0,
'robustesse' => 14.0,
'intelligence' => 16.0,
'vitesse' => 18.0,
'nbCombatGagne' => 7,
'rarete' => 5, // légendaire
],
];
foreach ($emojisDeBase as &$emoji) { foreach ($emojisDeBase as &$emoji) {
$emoji['color'] = match ($emoji['rarity']) { $emoji['color'] = match ($emoji['rarete']) {
2 => 'green', 2 => 'green',
3 => 'purple', 3 => 'purple',
4 => 'red', 4 => 'red',
@ -43,7 +193,7 @@ class HomeController extends AbstractController
} }
foreach ($emojisCrees as &$emoji) { foreach ($emojisCrees as &$emoji) {
$emoji['color'] = match ($emoji['rarity']) { $emoji['color'] = match ($emoji['rarete']) {
2 => 'green', 2 => 'green',
3 => 'purple', 3 => 'purple',
4 => 'red', 4 => 'red',
@ -52,10 +202,10 @@ class HomeController extends AbstractController
}; };
} }
return $this->render('home/index.html.twig', [ return $this->render('home/index.html.twig', [
'user' => $user,
'emojisDeBase' => $emojisDeBase, 'emojisDeBase' => $emojisDeBase,
'emojisCrees' => $emojisCrees 'emojisCrees' => $emojisCrees,
]); ]);
} }
} }

@ -2,8 +2,6 @@
namespace App\Controller; namespace App\Controller;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
@ -11,40 +9,16 @@ use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
class LoginController extends AbstractController class LoginController extends AbstractController
{ {
private EntityManagerInterface $entityManager;
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
#[Route(path: '/login', name: 'app_login')] #[Route(path: '/login', name: 'app_login')]
public function login(AuthenticationUtils $authenticationUtils): Response public function login(AuthenticationUtils $authenticationUtils): Response
{ {
if ($this->getUser()) { if ($this->getUser()) {
$user = $this->getUser(); return $this->redirectToRoute('app_home');
$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(); $error = $authenticationUtils->getLastAuthenticationError();
$lastUsername = $authenticationUtils->getLastUsername(); $lastUsername = $authenticationUtils->getLastUsername();
return $this->render('auth/login.html.twig', [ return $this->render('auth/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
'last_username' => $lastUsername,
'error' => $error
]);
} }
#[Route(path: '/logout', name: 'app_logout')] #[Route(path: '/logout', name: 'app_logout')]

@ -5,7 +5,6 @@ namespace App\Controller;
use App\Entity\User; use App\Entity\User;
use App\Form\RegistrationFormType; use App\Form\RegistrationFormType;
use App\Security\LoginFormAuthenticator; use App\Security\LoginFormAuthenticator;
use App\Service\EmojiService;
use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
@ -17,14 +16,8 @@ use Symfony\Component\Security\Http\Authentication\UserAuthenticatorInterface;
class RegistrationController extends AbstractController class RegistrationController extends AbstractController
{ {
#[Route('/register', name: 'app_register')] #[Route('/register', name: 'app_register')]
public function register( public function register(Request $request, UserPasswordHasherInterface $userPasswordHasher, UserAuthenticatorInterface $userAuthenticator, LoginFormAuthenticator $authenticator, EntityManagerInterface $entityManager): Response
Request $request, {
UserPasswordHasherInterface $userPasswordHasher,
UserAuthenticatorInterface $userAuthenticator,
LoginFormAuthenticator $authenticator,
EntityManagerInterface $entityManager,
EmojiService $emojiService
): Response {
$user = new User(); $user = new User();
$form = $this->createForm(RegistrationFormType::class, $user); $form = $this->createForm(RegistrationFormType::class, $user);
$form->handleRequest($request); $form->handleRequest($request);
@ -41,8 +34,6 @@ class RegistrationController extends AbstractController
$entityManager->persist($user); $entityManager->persist($user);
$entityManager->flush(); $entityManager->flush();
$emojiService->addRandomStockEmojisToUser($user);
return $userAuthenticator->authenticateUser( return $userAuthenticator->authenticateUser(
$user, $user,
$authenticator, $authenticator,

@ -23,12 +23,11 @@ class ReproductionController extends AbstractController
// ]); // ]);
// } // }
#[Route('/reproduction/{idUser}/{id1}/{id2}', name: 'app_reproduction_with_params')] #[Route('/reproduction/{id1}/{id2}', name: 'app_reproduction_with_params')]
public function reproductionWithParams(int $idUser, int $id1, int $id2): Response public function reproductionWithParams(int $id1, int $id2): Response
{ {
return $this->render('reproduction/index.html.twig', [ return $this->render('reproduction/index.html.twig', [
'idUser' => $idUser,
'left_emoji' => $id1, 'left_emoji' => $id1,
'right_emoji' => $id2, 'right_emoji' => $id2,
]); ]);

@ -19,4 +19,41 @@ class UserController extends AbstractController
$this->entityManager = $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);
}
} }

@ -33,7 +33,8 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
#[ORM\Column] #[ORM\Column]
private ?string $password = null; private ?string $password = null;
#[ORM\OneToMany(targetEntity: UserEmojis::class, mappedBy: 'user')] #[ORM\ManyToMany(targetEntity: Emoji::class, inversedBy: 'users')]
#[ORM\JoinTable(name: 'posseder')]
private Collection $emojis; private Collection $emojis;
public function __construct() { public function __construct() {
@ -57,12 +58,19 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
return $this; return $this;
} }
/**
* A visual identifier that represents this user.
*
* @see UserInterface
*/
public function getUserIdentifier(): string public function getUserIdentifier(): string
{ {
return (string) $this->username; return (string) $this->username;
} }
/**
* @see UserInterface
*/
public function getRoles(): array public function getRoles(): array
{ {
$roles = $this->roles; $roles = $this->roles;
@ -79,6 +87,9 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
return $this; return $this;
} }
/**
* @see PasswordAuthenticatedUserInterface
*/
public function getPassword(): string public function getPassword(): string
{ {
return $this->password; return $this->password;

@ -1,52 +0,0 @@
<?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;
}
}

@ -1,48 +0,0 @@
<?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()
// ;
// }
}

@ -1,104 +0,0 @@
<?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();
}
}

@ -1,84 +0,0 @@
{% extends 'base.html.twig' %}
{% block stylesheets %}
<link rel="stylesheet" href="{{ asset('css/admin.css') }}">
{% endblock %}
{% block title %}Admin - Gestion des utilisateurs{% endblock %}
{% block body %}
<h1>🔐 Admin - Gestion des utilisateurs</h1>
<section>
<h2>👥 Liste des utilisateurs</h2>
<ul id="user-list"></ul>
</section>
<section>
<h2> Ajouter un utilisateur</h2>
<form id="add-user-form">
<input type="text" name="username" placeholder="Nom d'utilisateur" required>
<input type="password" name="password" placeholder="Mot de passe" required>
<select name="role">
<option value="ROLE_USER">Utilisateur</option>
<option value="ROLE_ADMIN">Administrateur</option>
</select>
<button type="submit">Ajouter</button>
</form>
</section>
<script>
async function fetchUsers() {
const response = await fetch('/admin/users');
const users = await response.json();
const list = document.getElementById('user-list');
list.innerHTML = '';
users.forEach(user => {
const item = document.createElement('li');
item.innerHTML = `
<strong>${user.username}</strong> - Rôles: ${user.roles.join(', ')}
<button onclick="deleteUser(${user.id})">🗑️ Supprimer</button>
`;
list.appendChild(item);
});
}
async function deleteUser(id) {
if (!confirm('Confirmer la suppression de cet utilisateur ?')) return;
const response = await fetch(`/admin/users/delete/${id}`, {
method: 'DELETE',
});
if (response.ok) {
alert('Utilisateur supprimé.');
fetchUsers();
} else {
alert('Erreur lors de la suppression.');
}
}
document.getElementById('add-user-form').addEventListener('submit', async function (e) {
e.preventDefault();
const form = e.target;
const username = form.username.value;
const password = form.password.value;
const role = form.role.value;
const response = await fetch('/admin/users/add', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password, roles: [role] }),
});
if (response.ok) {
alert('Utilisateur ajouté avec succès.');
form.reset();
fetchUsers();
} else {
const data = await response.json();
alert('Erreur: ' + (data.error || 'Inconnue'));
}
});
fetchUsers();
</script>
{% endblock %}

@ -4,7 +4,7 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Emoji Fight</title> <title>Emoji Fight</title>
<link rel="stylesheet" href="{{ asset('style/combat.css?v=1.5') }}" /> <link rel="stylesheet" href="{{ asset('style/combat.css') }}" />
</head> </head>
<body> <body>
@ -13,17 +13,13 @@
<div class="emoji right-emoji" data-content=""></div> <div class="emoji right-emoji" data-content=""></div>
</div> </div>
<div>
<button id="btn-retour" class="btn-retour">🏠 Retour à la collection</button>
</div>
<div id="winner-text"></div> <div id="winner-text"></div>
<script> <script>
const id1 = {{ idLeft }}; const id1 = {{ idLeft }};
const id2 = {{ idRight }}; const id2 = {{ idRight }};
</script> </script>
<script src="{{ asset('script/combat.js?v=1.4') }}"></script> <script src="{{ asset('script/combat.js') }}"></script>
</body> </body>
</html> </html>

@ -3,19 +3,17 @@
{% block title %}Accueil - Ma collection de créatures{% endblock %} {% block title %}Accueil - Ma collection de créatures{% endblock %}
{% block stylesheets %} {% block stylesheets %}
<link rel="stylesheet" href="{{ asset('css/home.css?v=1.4') }}"> <link rel="stylesheet" href="{{ asset('css/home.css') }}">
{% endblock %} {% endblock %}
{% block body %} {% block body %}
{% if app.user %} {% if app.user %}
<div class="logout-container"> <div class="logout-container">
<span style="margin-right: 20px; ">Connecté en tant que <strong>{{ app.user.username }}</strong></span> Connecté en tant que <strong>{{ app.user.username }}</strong>
<form action="{{ path('app_logout') }}" method="post" style="display: inline;"> <form action="{{ path('app_logout') }}" method="post" style="display: inline;">
<button type="submit" class="btn btn-logout">🚪Déconnexion</button> <button type="submit" class="btn btn-logout">🚪 Se déconnecter</button>
</form> </form>
</div> </div>
<div id="user-data" data-user-id="{{ user.id }}"></div>
{% endif %} {% endif %}
<h1>🧬 Ma collection de créatures 🐾</h1> <h1>🧬 Ma collection de créatures 🐾</h1>
@ -26,54 +24,23 @@
{% for emoji in emojisDeBase %} {% for emoji in emojisDeBase %}
<div class="emoji-card {{ emoji.color }}" <div class="emoji-card {{ emoji.color }}"
data-id="{{ emoji.id }}" data-id="{{ emoji.id }}"
data-name="{{ emoji.name }}" data-name="{{ emoji.nom }}"
data-color="{{ emoji.color }}" data-color="{{ emoji.color }}"
data-level="{{ emoji.fightsWon }}" data-level="{{ emoji.nbCombatGagne }}"
data-force="{{ emoji.strength }}" data-force="{{ emoji.force }}"
data-vitesse="{{ emoji.speed }}"> data-vitesse="{{ emoji.vitesse }}">
<div class="emoji-level">Level {{ emoji.fightsWon }}</div> <div class="emoji-level">Level {{ emoji.nbCombatGagne }}</div>
<div class="emoji">{{ emoji.code }}</div> <div class="emoji">{{ emoji.code }}</div>
<div class="emoji-name {{ emoji.color }}">{{ emoji.name }}</div> <div class="emoji-name {{ emoji.color }}">{{ emoji.nom }}</div>
<div class="detail-icon" data-id="{{ emoji.id }}"></div> <div class="detail-icon" data-id="{{ emoji.id }}"></div>
<div class="detail-icon-hierarchy" data-id="{{ emoji.id }}">👨‍👩‍👧‍👦</div>
<div class="popup" id="popup-{{ emoji.id }}"> <div class="popup" id="popup-{{ emoji.id }}">
<strong>Stats :</strong><br> <strong>Stats :</strong><br>
Force: {{ emoji.strength }}<br> Force: {{ emoji.force }}<br>
Robustesse: {{ emoji.toughness }}<br> Robustesse: {{ emoji.robustesse }}<br>
Intelligence: {{ emoji.intelligence }}<br> Intelligence: {{ emoji.intelligence }}<br>
Vitesse: {{ emoji.speed }} Vitesse: {{ emoji.vitesse }}
</div>
</div>
{% endfor %}
{% for emoji in emojisDeBase %}
<div class="hierarchy-modal" id="popup-hiera-{{ emoji.id }}">
<div class="hierarchy-overlay" data-id="{{ emoji.id }}"></div>
<div class="hierarchy-content">
<span class="close-btn" data-id="{{ emoji.id }}">&times;</span>
<div class="hierarchy-graph">
<div class="parent-block parent1">
<div class="emoji" id="parent1-{{ emoji.id }}"></div>
<div class="name" id="name-parent1-{{ emoji.id }}"></div>
</div>
<div class="arrows">
<div class="arrow">⬇️</div>
</div>
<div class="parent-block parent2">
<div class="emoji" id="parent2-{{ emoji.id }}"></div>
<div class="name" id="name-parent2-{{ emoji.id }}"></div>
</div>
<div class="child-block">
<div class="child" id="child-{{ emoji.id }}"></div>
<div class="name" id="name-child-{{ emoji.id }}"></div>
</div>
</div>
</div> </div>
</div> </div>
{% endfor %} {% endfor %}
@ -109,60 +76,23 @@
{% for emoji in emojisCrees %} {% for emoji in emojisCrees %}
<div class="emoji-card {{ emoji.color }}" <div class="emoji-card {{ emoji.color }}"
data-id="{{ emoji.id }}" data-id="{{ emoji.id }}"
data-name="{{ emoji.name }}" data-name="{{ emoji.nom }}"
data-color="{{ emoji.color }}" data-color="{{ emoji.color }}"
data-level="{{ emoji.fightsWon }}" data-level="{{ emoji.nbCombatGagne }}"
data-force="{{ emoji.strength }}" data-force="{{ emoji.force }}"
data-vitesse="{{ emoji.speed }}"> data-vitesse="{{ emoji.vitesse }}">
<div class="emoji-level">Level {{ emoji.fightsWon }}</div> <div class="emoji-level">Level {{ emoji.nbCombatGagne }}</div>
<div class="emoji"> <div class="emoji">{{ emoji.code }}</div>
{% if 'vercel' in emoji.code %} <div class="emoji-name {{ emoji.color }}">{{ emoji.nom }}</div>
<img src="{{ emoji.code }}" alt="{{ emoji.name }}" width="48" height="48" />
{% else %}
{{ emoji.code }}
{% endif %}
</div>
<div class="emoji-name {{ emoji.color }}">{{ emoji.name }}</div>
<div class="detail-icon" data-id="{{ emoji.id }}"></div> <div class="detail-icon" data-id="{{ emoji.id }}"></div>
<div class="detail-icon-hierarchy" data-id="{{ emoji.id }}">👨‍👩‍👧‍👦</div>
<div class="popup" id="popup-{{ emoji.id }}"> <div class="popup" id="popup-{{ emoji.id }}">
<strong>Stats :</strong><br> <strong>Stats :</strong><br>
Force: {{ emoji.strength }}<br> Force: {{ emoji.force }}<br>
Robustesse: {{ emoji.toughness }}<br> Robustesse: {{ emoji.robustesse }}<br>
Intelligence: {{ emoji.intelligence }}<br> Intelligence: {{ emoji.intelligence }}<br>
Vitesse: {{ emoji.speed }} Vitesse: {{ emoji.vitesse }}
</div>
</div>
{% endfor %}
{% for emoji in emojisCrees %}
<div class="hierarchy-modal" id="popup-hiera-{{ emoji.id }}">
<div class="hierarchy-overlay" data-id="{{ emoji.id }}"></div>
<div class="hierarchy-content">
<span class="close-btn" data-id="{{ emoji.id }}">&times;</span>
<div class="hierarchy-graph">
<div class="parent-block parent1">
<div class="emoji" id="parent1-{{ emoji.id }}"></div>
<div class="name" id="name-parent1-{{ emoji.id }}"></div>
</div>
<div class="arrows">
<div class="arrow">⬇️</div>
</div>
<div class="parent-block parent2">
<div class="emoji" id="parent2-{{ emoji.id }}"></div>
<div class="name" id="name-parent2-{{ emoji.id }}"></div>
</div>
<div class="child-block">
<div class="child" id="child-{{ emoji.id }}"></div>
<div class="name" id="name-child-{{ emoji.id }}"></div>
</div>
</div>
</div> </div>
</div> </div>
{% endfor %} {% endfor %}
@ -181,5 +111,5 @@
{% endblock %} {% endblock %}
{% block javascripts %} {% block javascripts %}
<script src="{{ asset('js/home.js?v=1.8') }}"></script> <script src="{{ asset('js/home.js?v=1.3') }}"></script>
{% endblock %} {% endblock %}

@ -4,7 +4,7 @@
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Emoji Reproduction</title> <title>Emoji Reproduction</title>
<link rel="stylesheet" href="{{ asset('style/reproduction.css?v=1.7') }}" /> <link rel="stylesheet" href="{{ asset('style/reproduction.css') }}" />
</head> </head>
<body> <body>
@ -14,18 +14,12 @@
</div> </div>
<div id="child-text"></div> <div id="child-text"></div>
<div id="heart-gif"></div> <div id="heart-gif"></div>
<div>
<button id="btn-retour" class="btn-retour">🏠 Retour à la collection</button>
</div>
<script> <script>
id_user={{ idUser }};
id_left={{ left_emoji }}; id_left={{ left_emoji }};
id_right={{ right_emoji }}; id_right={{ right_emoji }};
</script> </script>
<script src="{{ asset('script/reproduction.js?v=1.5') }}"></script> <script src="{{ asset('script/reproduction.js') }}"></script>
</body> </body>
</html> </html>

Loading…
Cancel
Save