feat: bpn as single source of truth for role and hotel code assignments

This commit is contained in:
Björn Fromme committed 2026-08-18 11:33:42 +02:00
1 parent 1fd0fbc21e
commit f0e850978b
17 files changed
+818 -198

No files matched your search

+24 -29
View File
@@ -2,7 +2,6 @@
namespace App\Form;
use App\Config\HouseCatalog;
use App\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
@@ -12,27 +11,20 @@ use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* The account settings of an administrative user - and nothing else.
*
* Roles and hotel codes are synced from BusPro on every login and are not editable here or
* anywhere else, so they are not fields: the edit page renders them as information. The one
* role decision left to a human, approving a nomination, is its own action with its own
* confirmation (see App\Controller\Admin\System\User\ApproveRoleController). Keeping all
* three apart is deliberate - a form field that cannot be submitted only looks broken.
*/
class UserType extends AbstractType
{
public function __construct(private readonly HouseCatalog $houseCatalog)
{
}
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('roles', MultiselectType::class, [
'label' => 'Rollen',
'required' => false,
'property_path' => 'assignedRoles',
'choices' => array_flip(User::ROLES),
'empty_label' => 'keine Rolle',
])
->add('superAdmin', CheckboxType::class, [
'label' => 'Superadmin',
'required' => false,
'help' => 'Setzt die Rolle Admin voraus.',
])
->add('disabled', CheckboxType::class, [
'label' => 'Account gesperrt',
'required' => false,
@@ -74,23 +66,26 @@ class UserType extends AbstractType
;
});
// hotel codes already assigned to the user may predate the catalog, so they are
// added as choices to keep them selectable instead of failing
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event): void {
// Super admin is an elevation of an existing role, never a grant of its own, so the
// field exists only for somebody who already holds ROLE_ADMIN - offering it to
// anyone else would only produce the violation from User::validateSuperAdmin().
// A flag already set without the role is the exception: it has to stay editable, or
// that user could not be saved at all until BusPro claims them an admin again.
$builder->addEventListener(FormEvents::PRE_SET_DATA, static function (FormEvent $event): void {
$user = $event->getData();
$choices = $this->houseCatalog->getCodeChoices();
foreach ($user instanceof User ? $user->getHotelCodes() : [] as $code) {
if (false === in_array($code, $choices, true)) {
$choices[$code] = $code;
}
if (false === $user instanceof User) {
return;
}
$event->getForm()->add('hotelCodes', MultiselectType::class, [
'label' => 'Häuser',
if (false === in_array('ROLE_ADMIN', $user->getAssignedRoles(), true) && false === $user->isSuperAdmin()) {
return;
}
$event->getForm()->add('superAdmin', CheckboxType::class, [
'label' => 'Superadmin',
'required' => false,
'choices' => $choices,
'empty_label' => 'keine Häuser',
'help' => 'Darf Rollen freischalten und Accounts verwalten.',
]);
});
}