Ajout page profil V1
All checks were successful
Apply PHP CS Fixer / php-cs-fixer (push) Successful in 24s
CI / build-test (push) Successful in 1m29s
rector / Rector (push) Successful in 1m21s

This commit is contained in:
Melaine Gérard 2025-01-22 20:44:51 +01:00
parent 062c5f5895
commit 6b56a34c6d
10 changed files with 152 additions and 2 deletions

3
.env
View File

@ -40,4 +40,5 @@ MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0
MAILER_DSN=null://null MAILER_DSN=null://null
###< symfony/mailer ### ###< symfony/mailer ###
BASE_PREFIX=kumora BASE_PREFIX=kumora
DEFAULT_IMAGE=https://camelia-studio.org/v5/images/camelia_studio.png

View File

@ -5,13 +5,15 @@
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration # https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
parameters: parameters:
base.prefix: '%env(BASE_PREFIX)%' base.prefix: '%env(BASE_PREFIX)%'
default.image: '%env(DEFAULT_IMAGE)%'
services: services:
# default configuration for services in *this* file # default configuration for services in *this* file
_defaults: _defaults:
autowire: true # Automatically injects dependencies in your services. autowire: true # Automatically injects dependencies in your services.
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
bind:
string $defaultImage: '%default.image%'
# makes classes in src/ available to be used as services # makes classes in src/ available to be used as services
# this creates a service per class whose id is the fully-qualified class name # this creates a service per class whose id is the fully-qualified class name
App\: App\:

View File

@ -0,0 +1,36 @@
<?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 Version20250122192521 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('ALTER TABLE user ADD COLUMN fullname VARCHAR(255) NOT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TEMPORARY TABLE __temp__user AS SELECT id, email, roles, password, folder_role FROM "user"');
$this->addSql('DROP TABLE "user"');
$this->addSql('CREATE TABLE "user" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, email VARCHAR(255) NOT NULL, roles CLOB NOT NULL, password VARCHAR(255) NOT NULL, folder_role VARCHAR(255) NOT NULL)');
$this->addSql('INSERT INTO "user" (id, email, roles, password, folder_role) SELECT id, email, roles, password, folder_role FROM __temp__user');
$this->addSql('DROP TABLE __temp__user');
$this->addSql('CREATE UNIQUE INDEX UNIQ_IDENTIFIER_EMAIL ON "user" (email)');
}
}

View File

@ -34,6 +34,7 @@ class CreateUserCommand extends Command
protected function execute(InputInterface $input, OutputInterface $output): int protected function execute(InputInterface $input, OutputInterface $output): int
{ {
$io = new SymfonyStyle($input, $output); $io = new SymfonyStyle($input, $output);
$fullname = $io->ask('Nom de l\'utilisateur');
$email = $io->ask('Email de l\'utilisateur'); $email = $io->ask('Email de l\'utilisateur');
$password = $io->askHidden('Mot de passe de l\'utilisateur'); $password = $io->askHidden('Mot de passe de l\'utilisateur');
$isAdmin = $io->confirm('Est-ce un administrateur ?'); $isAdmin = $io->confirm('Est-ce un administrateur ?');
@ -46,6 +47,7 @@ class CreateUserCommand extends Command
return Command::FAILURE; return Command::FAILURE;
} }
$user = new User(); $user = new User();
$user->setFullname($fullname);
$user->setEmail($email); $user->setEmail($email);
$user->setPassword($this->passwordHasher->hashPassword($user, $password)); $user->setPassword($this->passwordHasher->hashPassword($user, $password));
$user->setRoles($isAdmin ? ['ROLE_ADMIN'] : ['ROLE_USER']); $user->setRoles($isAdmin ? ['ROLE_ADMIN'] : ['ROLE_USER']);

View File

@ -4,8 +4,23 @@ declare(strict_types=1);
namespace App\Controller; namespace App\Controller;
use App\Entity\User;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;
class ProfileController extends AbstractController class ProfileController extends AbstractController
{ {
#[Route('/profile', name: 'app_profile')]
#[IsGranted('ROLE_USER')]
public function index()
{
/**
* @var User $user
*/
$user = $this->getUser();
return $this->render('profile/index.html.twig', [
'user' => $user,
]);
}
} }

View File

@ -41,6 +41,9 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
#[ORM\Column(enumType: RoleEnum::class)] #[ORM\Column(enumType: RoleEnum::class)]
private ?RoleEnum $folder_role = null; private ?RoleEnum $folder_role = null;
#[ORM\Column(length: 255)]
private ?string $fullname = null;
public function getId(): ?int public function getId(): ?int
{ {
return $this->id; return $this->id;
@ -127,4 +130,16 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
return $this; return $this;
} }
public function getFullname(): ?string
{
return $this->fullname;
}
public function setFullname(string $fullname): static
{
$this->fullname = $fullname;
return $this;
}
} }

View File

@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
namespace App\Twig\Extension;
use App\Twig\Runtime\GravatarExtensionRuntime;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
use Twig\TwigFunction;
class GravatarExtension extends AbstractExtension
{
public function getFunctions(): array
{
return [
new TwigFunction('get_gravatar', [GravatarExtensionRuntime::class, 'getGravatar']),
];
}
}

View File

@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Twig\Runtime;
use Twig\Extension\RuntimeExtensionInterface;
class GravatarExtensionRuntime implements RuntimeExtensionInterface
{
public function __construct(private readonly string $defaultImage)
{
}
public function getGravatar(string $email): string
{
$hash = hash('sha256', strtolower(trim($email)));
return 'https://gravatar.com/avatar/' . $hash . '?s=2048&d=' . urlencode($this->defaultImage);
}
}

View File

@ -28,6 +28,9 @@
<a href="{{ path('app_admin_index') }}" class="block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent">Administration</a> <a href="{{ path('app_admin_index') }}" class="block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent">Administration</a>
</li> </li>
{% endif %} {% endif %}
<li>
<a href="{{ path('app_profile') }}" class="block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent">Profil</a>
</li>
<li> <li>
<a href="{{ path('app_logout') }}" class="block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent">Se déconnecter</a> <a href="{{ path('app_logout') }}" class="block py-2 px-3 text-gray-900 rounded hover:bg-gray-100 md:hover:bg-transparent md:border-0 md:hover:text-blue-700 md:p-0 dark:text-white md:dark:hover:text-blue-500 dark:hover:bg-gray-700 dark:hover:text-white md:dark:hover:bg-transparent">Se déconnecter</a>
</li> </li>

View File

@ -0,0 +1,35 @@
{% extends 'base.html.twig' %}
{% block title %}Le cloud de Camélia-Studio{% endblock %}
{% block body %}
<div class="container mx-auto px-16">
<div class="grid grid-cols-4 gap-8 mt-4">
<div class="border border-gray-500 rounded-lg">
<div class="p-4">
<img src="{{ get_gravatar('toto@titi.fr') }}" alt="Avatar de l'utilisateur" class="rounded-lg">
</div>
<div class="flex justify-center pb-2">
{{ user.fullname }}
</div>
<div class="border-t border-gray-500 py-2 pl-2">
<span class="font-bold">
Email :
</span> {{ user.email }}
</div>
<div class="border-t border-gray-500 py-2 pl-2">
<span class="font-bold">
Rôle :
</span> {{ user.roles[0] == 'ROLE_ADMIN' ? 'Administrateur' : 'Utilisateur' }}
</div>
<div class="border-t border-gray-500 py-2 pl-2">
<span class="font-bold">
Rôle de dossier :
</span> {{ user.folderRole.value }}
</div>
</div>
</div>
</div>
{% endblock %}