diff --git a/.changes/unreleased/UX-20251030-153126.yaml b/.changes/unreleased/UX-20251030-153126.yaml new file mode 100644 index 000000000..8deaf7701 --- /dev/null +++ b/.changes/unreleased/UX-20251030-153126.yaml @@ -0,0 +1,6 @@ +kind: UX +body: Remove the label if there is only one scope and no scope picking field is displayed. +time: 2025-10-30T15:31:26.807444365+01:00 +custom: + Issue: "449" + SchemaChange: No schema change diff --git a/src/Bundle/ChillActivityBundle/Form/ActivityType.php b/src/Bundle/ChillActivityBundle/Form/ActivityType.php index 28c607acd..ba991f063 100644 --- a/src/Bundle/ChillActivityBundle/Form/ActivityType.php +++ b/src/Bundle/ChillActivityBundle/Form/ActivityType.php @@ -18,6 +18,7 @@ use Chill\ActivityBundle\Security\Authorization\ActivityVoter; use Chill\DocStoreBundle\Form\CollectionStoredObjectType; use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\Location; +use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Entity\User; use Chill\MainBundle\Form\Type\ChillDateType; use Chill\MainBundle\Form\Type\CommentType; @@ -47,6 +48,7 @@ use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Security; class ActivityType extends AbstractType { @@ -60,6 +62,7 @@ class ActivityType extends AbstractType protected array $timeChoices, protected SocialIssueRender $socialIssueRender, protected SocialActionRender $socialActionRender, + private readonly Security $security, ) { if (!$tokenStorage->getToken()->getUser() instanceof User) { throw new \RuntimeException('you should have a valid user'); @@ -87,10 +90,22 @@ class ActivityType extends AbstractType $activityType = $options['activityType']; if (null !== $options['data']->getPerson()) { + + $reachableScopes = array_values( + array_filter( + $this->authorizationHelper->getReachableScopes( + $this->security->getUser(), + ActivityVoter::CREATE === (string) $options['role'] ? ActivityVoter::CREATE_PERSON : (string) $options['role'], + $options['center'] + ), + static fn (Scope $s) => $s->isActive() + ) + ); + $builder->add('scope', ScopePickerType::class, [ - 'center' => $options['center'], - 'role' => ActivityVoter::CREATE === (string) $options['role'] ? ActivityVoter::CREATE_PERSON : (string) $options['role'], + 'reachable_scopes' => $reachableScopes, 'required' => true, + 'label' => count($reachableScopes) > 1 ? 'Scope' : false, ]); } diff --git a/src/Bundle/ChillDocStoreBundle/Form/PersonDocumentType.php b/src/Bundle/ChillDocStoreBundle/Form/PersonDocumentType.php index 0addd53cc..a639d7e1d 100644 --- a/src/Bundle/ChillDocStoreBundle/Form/PersonDocumentType.php +++ b/src/Bundle/ChillDocStoreBundle/Form/PersonDocumentType.php @@ -14,9 +14,11 @@ namespace Chill\DocStoreBundle\Form; use Chill\DocStoreBundle\Entity\Document; use Chill\DocStoreBundle\Entity\DocumentCategory; use Chill\DocStoreBundle\Entity\PersonDocument; +use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Form\Type\ChillDateType; use Chill\MainBundle\Form\Type\ChillTextareaType; use Chill\MainBundle\Form\Type\ScopePickerType; +use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface; use Chill\MainBundle\Security\Resolver\CenterResolverDispatcher; use Chill\MainBundle\Security\Resolver\ScopeResolverDispatcher; use Chill\MainBundle\Templating\TranslatableStringHelperInterface; @@ -27,10 +29,11 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Security\Core\Security; class PersonDocumentType extends AbstractType { - public function __construct(private readonly TranslatableStringHelperInterface $translatableStringHelper, private readonly ScopeResolverDispatcher $scopeResolverDispatcher, private readonly ParameterBagInterface $parameterBag, private readonly CenterResolverDispatcher $centerResolverDispatcher) {} + public function __construct(private readonly TranslatableStringHelperInterface $translatableStringHelper, private readonly Security $security, private readonly AuthorizationHelperInterface $authorizationHelper, private readonly ScopeResolverDispatcher $scopeResolverDispatcher, private readonly ParameterBagInterface $parameterBag, private readonly CenterResolverDispatcher $centerResolverDispatcher) {} public function buildForm(FormBuilderInterface $builder, array $options) { @@ -56,9 +59,19 @@ class PersonDocumentType extends AbstractType ]); if ($isScopeConcerned && $this->parameterBag->get('chill_main')['acl']['form_show_scopes']) { + $reachableScopes = array_values( + array_filter( + $this->authorizationHelper->getReachableScopes( + $this->security->getUser(), + $options['role'], + $this->centerResolverDispatcher->resolveCenter($document) + ), + static fn (Scope $s) => $s->isActive() + ) + ); $builder->add('scope', ScopePickerType::class, [ - 'center' => $this->centerResolverDispatcher->resolveCenter($document), - 'role' => $options['role'], + 'reachable_scopes' => $reachableScopes, + 'label' => count($reachableScopes) > 1 ? 'Scope' : false, ]); } } diff --git a/src/Bundle/ChillMainBundle/Form/Type/ScopePickerType.php b/src/Bundle/ChillMainBundle/Form/Type/ScopePickerType.php index 6f10626c6..bd0c1b35c 100644 --- a/src/Bundle/ChillMainBundle/Form/Type/ScopePickerType.php +++ b/src/Bundle/ChillMainBundle/Form/Type/ScopePickerType.php @@ -40,41 +40,39 @@ use Symfony\Component\Security\Core\Security; class ScopePickerType extends AbstractType { public function __construct( - private readonly AuthorizationHelperInterface $authorizationHelper, - private readonly Security $security, private readonly TranslatableStringHelperInterface $translatableStringHelper, ) {} public function buildForm(FormBuilderInterface $builder, array $options) { - $items = array_values( - array_filter( - $this->authorizationHelper->getReachableScopes( - $this->security->getUser(), - $options['role'], - $options['center'] - ), - static fn (Scope $s) => $s->isActive() - ) - ); + /* $items = array_values( + array_filter( + $this->authorizationHelper->getReachableScopes( + $this->security->getUser(), + $options['role'], + $options['center'] + ), + static fn (Scope $s) => $s->isActive() + ) + );*/ - if (0 === \count($items)) { + if (0 === \count($options['reachable_scopes'])) { throw new \RuntimeException('no scopes are reachable. This form should not be shown to user'); } - if (1 !== \count($items)) { + if (1 !== \count($options['reachable_scopes'])) { $builder->add('scope', EntityType::class, [ 'class' => Scope::class, 'placeholder' => 'Choose the circle', 'choice_label' => fn (Scope $c) => $this->translatableStringHelper->localize($c->getName()), - 'choices' => $items, + 'choices' => $options['reachable_scopes'], ]); $builder->setDataMapper(new ScopePickerDataMapper()); } else { $builder->add('scope', HiddenType::class, [ - 'data' => $items[0]->getId(), + 'data' => $options['reachable_scopes'][0]->getId(), ]); - $builder->setDataMapper(new ScopePickerDataMapper($items[0])); + $builder->setDataMapper(new ScopePickerDataMapper($options['reachable_scopes'][0])); } } @@ -86,11 +84,13 @@ class ScopePickerType extends AbstractType public function configureOptions(OptionsResolver $resolver) { $resolver - // create `center` option - ->setRequired('center') - ->setAllowedTypes('center', [Center::class, 'array', 'null']) - // create ``role` option - ->setRequired('role') - ->setAllowedTypes('role', ['string']); + ->setRequired('reachable_scopes') + ->setAllowedTypes('reachable_scopes', ['array']); + // create `center` option + // ->setRequired('center') + // ->setAllowedTypes('center', [Center::class, 'array', 'null']) + // create ``role` option + // ->setRequired('role') + // ->setAllowedTypes('role', ['string']); } } diff --git a/src/Bundle/ChillMainBundle/Tests/Form/Type/ScopePickerTypeTest.php b/src/Bundle/ChillMainBundle/Tests/Form/Type/ScopePickerTypeTest.php index 3d3813748..ea2a74a89 100644 --- a/src/Bundle/ChillMainBundle/Tests/Form/Type/ScopePickerTypeTest.php +++ b/src/Bundle/ChillMainBundle/Tests/Form/Type/ScopePickerTypeTest.php @@ -11,7 +11,6 @@ declare(strict_types=1); namespace Form\Type; -use Chill\MainBundle\Entity\Center; use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Entity\User; use Chill\MainBundle\Form\Type\ScopePickerType; @@ -42,8 +41,7 @@ final class ScopePickerTypeTest extends TypeTestCase public function estBuildOneScopeIsSuccessful() { $form = $this->factory->create(ScopePickerType::class, null, [ - 'center' => new Center(), - 'role' => 'ONE_SCOPE', + 'reachable_scopes' => [new Scope()], ]); $view = $form->createView(); @@ -54,8 +52,7 @@ final class ScopePickerTypeTest extends TypeTestCase public function testBuildThreeScopesIsSuccessful() { $form = $this->factory->create(ScopePickerType::class, null, [ - 'center' => new Center(), - 'role' => 'THREE_SCOPE', + 'reachable_scopes' => [new Scope(), new Scope(), new Scope()], ]); $view = $form->createView(); @@ -66,8 +63,7 @@ final class ScopePickerTypeTest extends TypeTestCase public function testBuildTwoScopesIsSuccessful() { $form = $this->factory->create(ScopePickerType::class, null, [ - 'center' => new Center(), - 'role' => 'TWO_SCOPE', + 'reachable_scopes' => [new Scope(), new Scope()], ]); $view = $form->createView(); diff --git a/src/Bundle/ChillPersonBundle/Service/DocGenerator/PersonContext.php b/src/Bundle/ChillPersonBundle/Service/DocGenerator/PersonContext.php index eb588cdaf..4debf2c88 100644 --- a/src/Bundle/ChillPersonBundle/Service/DocGenerator/PersonContext.php +++ b/src/Bundle/ChillPersonBundle/Service/DocGenerator/PersonContext.php @@ -167,10 +167,20 @@ final readonly class PersonContext implements PersonContextInterface } if ($this->isScopeNecessary($entity)) { + $reachableScopes = array_values( + array_filter( + $this->authorizationHelper->getReachableScopes( + $this->security->getUser(), + PersonDocumentVoter::CREATE, + $this->centerResolverManager->resolveCenters($entity) + ), + static fn (Scope $s) => $s->isActive() + ) + ); + $builder->add('scope', ScopePickerType::class, [ - 'center' => $this->centerResolverManager->resolveCenters($entity), - 'role' => PersonDocumentVoter::CREATE, - 'label' => 'Scope', + 'reachable_scopes' => $reachableScopes, + 'label' => count($reachableScopes) > 1 ? 'Scope' : false, ]); } } diff --git a/src/Bundle/ChillTaskBundle/Form/SingleTaskType.php b/src/Bundle/ChillTaskBundle/Form/SingleTaskType.php index 7e572e078..62b6a1c7a 100644 --- a/src/Bundle/ChillTaskBundle/Form/SingleTaskType.php +++ b/src/Bundle/ChillTaskBundle/Form/SingleTaskType.php @@ -11,11 +11,13 @@ declare(strict_types=1); namespace Chill\TaskBundle\Form; +use Chill\MainBundle\Entity\Scope; use Chill\MainBundle\Form\Type\ChillDateType; use Chill\MainBundle\Form\Type\ChillTextareaType; use Chill\MainBundle\Form\Type\DateIntervalType; use Chill\MainBundle\Form\Type\ScopePickerType; use Chill\MainBundle\Form\Type\UserPickerType; +use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface; use Chill\MainBundle\Security\Resolver\CenterResolverDispatcherInterface; use Chill\MainBundle\Security\Resolver\ScopeResolverDispatcher; use Chill\TaskBundle\Security\Authorization\TaskVoter; @@ -24,10 +26,18 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Security\Core\Security; +use Symfony\Contracts\Translation\TranslatorInterface; class SingleTaskType extends AbstractType { - public function __construct(private readonly ParameterBagInterface $parameterBag, private readonly CenterResolverDispatcherInterface $centerResolverDispatcher, private readonly ScopeResolverDispatcher $scopeResolverDispatcher) {} + public function __construct( + private readonly ParameterBagInterface $parameterBag, + private readonly CenterResolverDispatcherInterface $centerResolverDispatcher, + private readonly Security $security, + private readonly AuthorizationHelperInterface $authorizationHelper, + private readonly ScopeResolverDispatcher $scopeResolverDispatcher, + ) {} public function buildForm(FormBuilderInterface $builder, array $options) { @@ -62,11 +72,22 @@ class SingleTaskType extends AbstractType ]); if ($isScopeConcerned && $this->parameterBag->get('chill_main')['acl']['form_show_scopes']) { + $reachableScopes = array_values( + array_filter( + $this->authorizationHelper->getReachableScopes( + $this->security->getUser(), + $options['role'], + $center + ), + static fn (Scope $s) => $s->isActive() + ) + ); + $builder ->add('circle', ScopePickerType::class, [ - 'center' => $center, - 'role' => $options['role'], + 'reachable_scopes' => $reachableScopes, 'required' => true, + 'label' => count($reachableScopes) > 1 ? 'Scope' : false, ]); } }