Compare commits
31 Commits
raph_comba
...
main
@ -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`
|
@ -1,24 +1,24 @@
|
|||||||
# see https://symfony.com/doc/current/reference/configuration/framework.html
|
# see https://symfony.com/doc/current/reference/configuration/framework.html
|
||||||
framework:
|
framework:
|
||||||
secret: '%env(APP_SECRET)%'
|
secret: "%env(APP_SECRET)%"
|
||||||
#csrf_protection: true
|
#csrf_protection: true
|
||||||
http_method_override: false
|
http_method_override: false
|
||||||
|
|
||||||
# Enables session support. Note that the session will ONLY be started if you read or write from it.
|
# Enables session support. Note that the session will ONLY be started if you read or write from it.
|
||||||
# Remove or comment this section to explicitly disable session support.
|
# Remove or comment this section to explicitly disable session support.
|
||||||
session:
|
session:
|
||||||
handler_id: null
|
handler_id: null
|
||||||
cookie_secure: auto
|
cookie_secure: auto
|
||||||
cookie_samesite: lax
|
cookie_samesite: lax
|
||||||
storage_factory_id: session.storage.factory.native
|
storage_factory_id: session.storage.factory.native
|
||||||
|
|
||||||
#esi: true
|
#esi: true
|
||||||
#fragments: true
|
#fragments: true
|
||||||
php_errors:
|
php_errors:
|
||||||
log: true
|
log: true
|
||||||
|
|
||||||
when@test:
|
when@test:
|
||||||
framework:
|
framework:
|
||||||
test: true
|
test: true
|
||||||
session:
|
session:
|
||||||
storage_factory_id: session.storage.factory.mock_file
|
storage_factory_id: session.storage.factory.mock_file
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
framework:
|
framework:
|
||||||
router:
|
router:
|
||||||
utf8: true
|
utf8: true
|
||||||
|
|
||||||
# Configure how to generate URLs in non-HTTP contexts, such as CLI commands.
|
# Configure how to generate URLs in non-HTTP contexts, such as CLI commands.
|
||||||
# See https://symfony.com/doc/current/routing.html#generating-urls-in-commands
|
# See https://symfony.com/doc/current/routing.html#generating-urls-in-commands
|
||||||
#default_uri: http://localhost
|
#default_uri: http://localhost
|
||||||
|
|
||||||
when@prod:
|
when@prod:
|
||||||
framework:
|
framework:
|
||||||
router:
|
router:
|
||||||
strict_requirements: null
|
strict_requirements: null
|
||||||
|
@ -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,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,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\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,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,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,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