feat(core) : RBAC Task 6 - fixtures et CreateUserCommand branches sur les roles systeme
- AppFixtures : rattachement des users aux entites Role via RoleRepositoryInterface. Re-seed idempotent des roles systeme dans ensureSystemRole() pour compenser le purger Doctrine qui vide la table role avant load(), afin que "make db-reset && make fixtures" reste un workflow one-shot. - CreateUserCommand : flag --admin attache au role systeme admin + is_admin, sinon au role user. Gestion d'erreur explicite si les roles systeme sont absents (FAILURE + message pointant vers la migration). - CreateUserCommand devient final, descriptions traduites en francais. Ticket #343 - 6/7 : fixtures et command alignes sur le RBAC relationnel. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,9 @@ declare(strict_types=1);
|
||||
namespace App\Module\Core\Infrastructure\Console;
|
||||
|
||||
use App\Module\Core\Domain\Entity\User;
|
||||
use App\Module\Core\Domain\Repository\RoleRepositoryInterface;
|
||||
use App\Module\Core\Domain\Repository\UserRepositoryInterface;
|
||||
use App\Module\Core\Domain\Security\SystemRoles;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
@@ -17,13 +19,14 @@ use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||
|
||||
#[AsCommand(
|
||||
name: 'app:create-user',
|
||||
description: 'Create a new user',
|
||||
description: 'Cree un utilisateur rattache au role systeme admin ou user.',
|
||||
)]
|
||||
class CreateUserCommand extends Command
|
||||
final class CreateUserCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UserRepositoryInterface $userRepository,
|
||||
private readonly UserPasswordHasherInterface $passwordHasher,
|
||||
private readonly RoleRepositoryInterface $roleRepository,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
@@ -31,9 +34,9 @@ class CreateUserCommand extends Command
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('username', InputArgument::REQUIRED, 'Username')
|
||||
->addArgument('password', InputArgument::REQUIRED, 'Plain password')
|
||||
->addOption('admin', null, InputOption::VALUE_NONE, 'Grant ROLE_ADMIN')
|
||||
->addArgument('username', InputArgument::REQUIRED, 'Nom d\'utilisateur')
|
||||
->addArgument('password', InputArgument::REQUIRED, 'Mot de passe en clair')
|
||||
->addOption('admin', null, InputOption::VALUE_NONE, 'Rattache au role systeme admin + active is_admin')
|
||||
;
|
||||
}
|
||||
|
||||
@@ -43,19 +46,34 @@ class CreateUserCommand extends Command
|
||||
|
||||
$username = $input->getArgument('username');
|
||||
$plainPassword = $input->getArgument('password');
|
||||
$isAdmin = (bool) $input->getOption('admin');
|
||||
|
||||
$roleCode = $isAdmin ? SystemRoles::ADMIN_CODE : SystemRoles::USER_CODE;
|
||||
$role = $this->roleRepository->findByCode($roleCode);
|
||||
|
||||
if (null === $role) {
|
||||
$io->error(sprintf(
|
||||
'Le role systeme "%s" est introuvable. Lance "bin/console doctrine:migrations:migrate" pour le seeder.',
|
||||
$roleCode,
|
||||
));
|
||||
|
||||
return Command::FAILURE;
|
||||
}
|
||||
|
||||
$user = new User();
|
||||
$user->setUsername($username);
|
||||
$user->setPassword($this->passwordHasher->hashPassword($user, $plainPassword));
|
||||
|
||||
if ($input->getOption('admin')) {
|
||||
// TODO Task 6 : attacher l'entite Role "admin" en plus du flag is_admin.
|
||||
$user->setIsAdmin(true);
|
||||
}
|
||||
$user->setIsAdmin($isAdmin);
|
||||
$user->addRbacRole($role);
|
||||
|
||||
$this->userRepository->save($user);
|
||||
|
||||
$io->success(sprintf('User "%s" created%s.', $username, $input->getOption('admin') ? ' with ROLE_ADMIN' : ''));
|
||||
$io->success(sprintf(
|
||||
'Utilisateur "%s" cree, rattache au role systeme "%s"%s.',
|
||||
$username,
|
||||
$roleCode,
|
||||
$isAdmin ? ' (bypass is_admin actif)' : '',
|
||||
));
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
|
||||
@@ -4,36 +4,72 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Module\Core\Infrastructure\DataFixtures;
|
||||
|
||||
use App\Module\Core\Domain\Entity\Role;
|
||||
use App\Module\Core\Domain\Entity\User;
|
||||
use App\Module\Core\Domain\Repository\RoleRepositoryInterface;
|
||||
use App\Module\Core\Domain\Security\SystemRoles;
|
||||
use Doctrine\Bundle\FixturesBundle\Fixture;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
|
||||
|
||||
/**
|
||||
* Fixtures de base du module Core : 3 utilisateurs (1 admin + 2 standards)
|
||||
* rattaches aux roles systeme RBAC seedes par la migration Version20260414150034.
|
||||
*
|
||||
* Note : le purger Doctrine execute avant load() supprime l'ensemble des
|
||||
* entites managees, ce qui inclut la table role. On re-seede donc les roles
|
||||
* systeme de maniere idempotente avant de rattacher les utilisateurs, afin
|
||||
* que le workflow "make db-reset && make fixtures" reste one-shot.
|
||||
*/
|
||||
class AppFixtures extends Fixture
|
||||
{
|
||||
public function __construct(
|
||||
private readonly UserPasswordHasherInterface $passwordHasher,
|
||||
private readonly RoleRepositoryInterface $roleRepository,
|
||||
) {}
|
||||
|
||||
public function load(ObjectManager $manager): void
|
||||
{
|
||||
// TODO Task 6 : cette fixture sera refactoree pour attacher les entites Role RBAC.
|
||||
$adminRole = $this->ensureSystemRole($manager, SystemRoles::ADMIN_CODE, 'Administrateur');
|
||||
$userRole = $this->ensureSystemRole($manager, SystemRoles::USER_CODE, 'Utilisateur');
|
||||
|
||||
$admin = new User();
|
||||
$admin->setUsername('admin');
|
||||
$admin->setIsAdmin(true);
|
||||
$admin->setPassword($this->passwordHasher->hashPassword($admin, 'admin'));
|
||||
$admin->addRbacRole($adminRole);
|
||||
$manager->persist($admin);
|
||||
|
||||
$alice = new User();
|
||||
$alice->setUsername('alice');
|
||||
$alice->setPassword($this->passwordHasher->hashPassword($alice, 'alice'));
|
||||
$alice->addRbacRole($userRole);
|
||||
$manager->persist($alice);
|
||||
|
||||
$bob = new User();
|
||||
$bob->setUsername('bob');
|
||||
$bob->setPassword($this->passwordHasher->hashPassword($bob, 'bob'));
|
||||
$bob->addRbacRole($userRole);
|
||||
$manager->persist($bob);
|
||||
|
||||
$manager->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne le role systeme correspondant au code donne, en le creant
|
||||
* s'il n'existe pas encore (le purger Doctrine a pu vider la table role).
|
||||
*/
|
||||
private function ensureSystemRole(ObjectManager $manager, string $code, string $label): Role
|
||||
{
|
||||
$role = $this->roleRepository->findByCode($code);
|
||||
|
||||
if (null !== $role) {
|
||||
return $role;
|
||||
}
|
||||
|
||||
$role = new Role($code, $label, isSystem: true);
|
||||
$manager->persist($role);
|
||||
|
||||
return $role;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user