mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
Fixed: add scope to generated document ref #11
This commit is contained in:
parent
877535ca4d
commit
a8a206557b
@ -20,52 +20,72 @@ use Chill\DocStoreBundle\Entity\DocumentCategory;
|
|||||||
use Chill\DocStoreBundle\Entity\PersonDocument;
|
use Chill\DocStoreBundle\Entity\PersonDocument;
|
||||||
use Chill\DocStoreBundle\Entity\StoredObject;
|
use Chill\DocStoreBundle\Entity\StoredObject;
|
||||||
use Chill\DocStoreBundle\Repository\DocumentCategoryRepository;
|
use Chill\DocStoreBundle\Repository\DocumentCategoryRepository;
|
||||||
use Chill\MainBundle\Form\ScopeType;
|
use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter;
|
||||||
|
use Chill\MainBundle\Entity\Scope;
|
||||||
|
use Chill\MainBundle\Form\Type\ScopePickerType;
|
||||||
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
use Chill\MainBundle\Security\Authorization\AuthorizationHelper;
|
||||||
|
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
|
||||||
|
use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface;
|
||||||
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||||
use Chill\PersonBundle\Entity\Person;
|
use Chill\PersonBundle\Entity\Person;
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use Doctrine\ORM\EntityManagerInterface;
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use Doctrine\ORM\EntityRepository;
|
use Doctrine\ORM\EntityRepository;
|
||||||
|
use LogicException;
|
||||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\Security\Core\Security;
|
||||||
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
|
||||||
|
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
use function array_key_exists;
|
use function array_key_exists;
|
||||||
|
use function count;
|
||||||
|
|
||||||
class PersonContext implements DocGeneratorContextWithAdminFormInterface, DocGeneratorContextWithPublicFormInterface
|
class PersonContext implements DocGeneratorContextWithAdminFormInterface, DocGeneratorContextWithPublicFormInterface
|
||||||
{
|
{
|
||||||
|
private AuthorizationHelperInterface $authorizationHelper;
|
||||||
|
|
||||||
private BaseContextData $baseContextData;
|
private BaseContextData $baseContextData;
|
||||||
|
|
||||||
|
private CenterResolverManagerInterface $centerResolverManager;
|
||||||
|
|
||||||
private DocumentCategoryRepository $documentCategoryRepository;
|
private DocumentCategoryRepository $documentCategoryRepository;
|
||||||
|
|
||||||
private EntityManagerInterface $em;
|
private EntityManagerInterface $em;
|
||||||
|
|
||||||
private NormalizerInterface $normalizer;
|
private NormalizerInterface $normalizer;
|
||||||
|
|
||||||
|
private Security $security;
|
||||||
|
|
||||||
|
private bool $showScopes;
|
||||||
|
|
||||||
private TranslatableStringHelperInterface $translatableStringHelper;
|
private TranslatableStringHelperInterface $translatableStringHelper;
|
||||||
|
|
||||||
private TranslatorInterface $translator;
|
private TranslatorInterface $translator;
|
||||||
|
|
||||||
private AuthorizationHelper $authorizationHelper;
|
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
DocumentCategoryRepository $documentCategoryRepository,
|
AuthorizationHelperInterface $authorizationHelper,
|
||||||
NormalizerInterface $normalizer,
|
|
||||||
TranslatableStringHelperInterface $translatableStringHelper,
|
|
||||||
EntityManagerInterface $em,
|
|
||||||
TranslatorInterface $translator,
|
|
||||||
BaseContextData $baseContextData,
|
BaseContextData $baseContextData,
|
||||||
AuthorizationHelper $authorizationHelper
|
CenterResolverManagerInterface $centerResolverManager,
|
||||||
|
DocumentCategoryRepository $documentCategoryRepository,
|
||||||
|
EntityManagerInterface $em,
|
||||||
|
NormalizerInterface $normalizer,
|
||||||
|
ParameterBagInterface $parameterBag,
|
||||||
|
Security $security,
|
||||||
|
TranslatorInterface $translator,
|
||||||
|
TranslatableStringHelperInterface $translatableStringHelper
|
||||||
) {
|
) {
|
||||||
$this->documentCategoryRepository = $documentCategoryRepository;
|
|
||||||
$this->normalizer = $normalizer;
|
|
||||||
$this->translatableStringHelper = $translatableStringHelper;
|
|
||||||
$this->em = $em;
|
|
||||||
$this->baseContextData = $baseContextData;
|
|
||||||
$this->translator = $translator;
|
|
||||||
$this->authorizationHelper = $authorizationHelper;
|
$this->authorizationHelper = $authorizationHelper;
|
||||||
|
$this->centerResolverManager = $centerResolverManager;
|
||||||
|
$this->baseContextData = $baseContextData;
|
||||||
|
$this->documentCategoryRepository = $documentCategoryRepository;
|
||||||
|
$this->em = $em;
|
||||||
|
$this->normalizer = $normalizer;
|
||||||
|
$this->security = $security;
|
||||||
|
$this->showScopes = $parameterBag->get('chill_main')['acl']['form_show_scopes'];
|
||||||
|
$this->translator = $translator;
|
||||||
|
$this->translatableStringHelper = $translatableStringHelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function adminFormReverseTransform(array $data): array
|
public function adminFormReverseTransform(array $data): array
|
||||||
@ -112,6 +132,18 @@ class PersonContext implements DocGeneratorContextWithAdminFormInterface, DocGen
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Person $entity
|
||||||
|
*/
|
||||||
|
public function buildPublicForm(FormBuilderInterface $builder, DocGeneratorTemplate $template, $entity): void
|
||||||
|
{
|
||||||
|
$builder->add('scope', ScopePickerType::class, [
|
||||||
|
'center' => $this->centerResolverManager->resolveCenters($entity),
|
||||||
|
'role' => PersonDocumentVoter::CREATE,
|
||||||
|
'label' => 'Scope',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function getData(DocGeneratorTemplate $template, $entity, array $contextGenerationData = []): array
|
public function getData(DocGeneratorTemplate $template, $entity, array $contextGenerationData = []): array
|
||||||
{
|
{
|
||||||
if (!$entity instanceof Person) {
|
if (!$entity instanceof Person) {
|
||||||
@ -163,6 +195,14 @@ class PersonContext implements DocGeneratorContextWithAdminFormInterface, DocGen
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param Person $entity
|
||||||
|
*/
|
||||||
|
public function hasPublicForm(DocGeneratorTemplate $template, $entity): bool
|
||||||
|
{
|
||||||
|
return $this->isScopeNecessary($entity);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Person $entity
|
* @param Person $entity
|
||||||
*/
|
*/
|
||||||
@ -185,42 +225,36 @@ class PersonContext implements DocGeneratorContextWithAdminFormInterface, DocGen
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->showScopes()) {
|
if ($this->isScopeNecessary($entity)) {
|
||||||
|
$doc->setScope($contextGenerationData['scope']);
|
||||||
|
} elseif ($this->showScopes) {
|
||||||
|
// in this case, it should have only one scope possible, we get it through AuthorizationHelper::getReachableScopes
|
||||||
|
$scopes = $this->authorizationHelper->getReachableScopes(
|
||||||
|
$this->security->getUser(),
|
||||||
|
PersonDocumentVoter::CREATE,
|
||||||
|
$this->centerResolverManager->resolveCenters($entity)
|
||||||
|
);
|
||||||
|
|
||||||
$scopes = $this->authorizationHelper->getReachableScopes();
|
if (1 !== count($scopes)) {
|
||||||
|
throw new LogicException('at this step, it should have only one scope');
|
||||||
if (count($scopes > 1))
|
}
|
||||||
{
|
|
||||||
$scope = $this->getFormData();
|
|
||||||
$doc->setScope($scope);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
$doc->setScope($scopes[0]);
|
$doc->setScope($scopes[0]);
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->em->persist($doc);
|
$this->em->persist($doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function showScopes(){
|
private function isScopeNecessary(Person $person): bool
|
||||||
return $this->parameterBag->get('chill_main')['acl']['form_show_scopes'];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function buildPublicForm(FormBuilderInterface $builder, DocGeneratorTemplate $template, $entity): void
|
|
||||||
{
|
{
|
||||||
$builder->add('Center', ScopeType::class, [
|
if ($this->showScopes && 1 < $this->authorizationHelper->getReachableScopes(
|
||||||
'required' => true
|
$this->security->getUser(),
|
||||||
]);
|
PersonDocumentVoter::CREATE,
|
||||||
}
|
$this->centerResolverManager->resolveCenters($person)
|
||||||
|
)) {
|
||||||
public function hasPublicForm(DocGeneratorTemplate $template, $entity): bool
|
|
||||||
{
|
|
||||||
if ($this->showScopes()) {
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -0,0 +1,265 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Service\DocGenerator;
|
||||||
|
|
||||||
|
use Chill\DocGeneratorBundle\Entity\DocGeneratorTemplate;
|
||||||
|
use Chill\DocGeneratorBundle\Service\Context\BaseContextData;
|
||||||
|
use Chill\DocStoreBundle\Entity\DocumentCategory;
|
||||||
|
use Chill\DocStoreBundle\Entity\PersonDocument;
|
||||||
|
use Chill\DocStoreBundle\Entity\StoredObject;
|
||||||
|
use Chill\DocStoreBundle\Repository\DocumentCategoryRepository;
|
||||||
|
use Chill\DocStoreBundle\Security\Authorization\PersonDocumentVoter;
|
||||||
|
use Chill\MainBundle\Entity\Center;
|
||||||
|
use Chill\MainBundle\Entity\Scope;
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
|
use Chill\MainBundle\Security\Authorization\AuthorizationHelperInterface;
|
||||||
|
use Chill\MainBundle\Security\Resolver\CenterResolverManagerInterface;
|
||||||
|
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||||
|
use Chill\PersonBundle\Entity\Person;
|
||||||
|
use Chill\PersonBundle\Service\DocGenerator\PersonContext;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Prophecy\Argument;
|
||||||
|
use Prophecy\Exception\Prediction\FailedPredictionException;
|
||||||
|
use Prophecy\PhpUnit\ProphecyTrait;
|
||||||
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||||
|
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||||
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
use Symfony\Component\Security\Core\User\UserInterface;
|
||||||
|
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
|
||||||
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||||
|
use function count;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* @coversNothing
|
||||||
|
*/
|
||||||
|
final class PersonContextTest extends TestCase
|
||||||
|
{
|
||||||
|
use ProphecyTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that the build person context works in the case when 'form_show_scope' is false.
|
||||||
|
*/
|
||||||
|
public function testScopeDoNotShowScopeInForms()
|
||||||
|
{
|
||||||
|
$person = new Person();
|
||||||
|
$docGen = (new DocGeneratorTemplate())
|
||||||
|
->setName(['fr' => 'template']);
|
||||||
|
|
||||||
|
$parameter = new ParameterBag(['chill_main' => ['acl' => ['form_show_scopes' => false]]]);
|
||||||
|
$em = $this->prophesize(EntityManagerInterface::class);
|
||||||
|
$em->persist(Argument::type(PersonDocument::class))
|
||||||
|
->should(static function ($calls, $object, $method) {
|
||||||
|
if (1 !== count($calls)) {
|
||||||
|
throw new FailedPredictionException(sprintf('the persist should be called exactly once, %d receivved', count($calls)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var PersonDocument $personDocument */
|
||||||
|
$personDocument = $calls[0]->getArguments()[0];
|
||||||
|
|
||||||
|
if (null !== $personDocument->getScope()) {
|
||||||
|
throw new FailedPredictionException('the person document should not have any scope');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$personContext = $this->buildPersonContext(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
$em->reveal(),
|
||||||
|
null,
|
||||||
|
$parameter
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertFalse($personContext->hasPublicForm($docGen, $person));
|
||||||
|
|
||||||
|
$personContext->storeGenerated(
|
||||||
|
$docGen,
|
||||||
|
new StoredObject(),
|
||||||
|
$person,
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testScopeScopeMustBeShownInFormsAndUserAccessMultipleScope()
|
||||||
|
{
|
||||||
|
$person = new Person();
|
||||||
|
$docGen = (new DocGeneratorTemplate())
|
||||||
|
->setName(['fr' => 'template']);
|
||||||
|
$scope = new Scope();
|
||||||
|
|
||||||
|
$em = $this->prophesize(EntityManagerInterface::class);
|
||||||
|
$em->persist(Argument::type(PersonDocument::class))
|
||||||
|
->should(static function ($calls, $object, $method) use ($scope) {
|
||||||
|
if (1 !== count($calls)) {
|
||||||
|
throw new FailedPredictionException(sprintf('the persist should be called exactly once, %d receivved', count($calls)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var PersonDocument $personDocument */
|
||||||
|
$personDocument = $calls[0]->getArguments()[0];
|
||||||
|
|
||||||
|
if ($personDocument->getScope() !== $scope) {
|
||||||
|
throw new FailedPredictionException('the person document should show the exactly prepared scope');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class);
|
||||||
|
$authorizationHelper->getReachableScopes(Argument::type(UserInterface::class), PersonDocumentVoter::CREATE, Argument::type('array'))
|
||||||
|
->willReturn([$scope, new Scope()]);
|
||||||
|
|
||||||
|
$personContext = $this->buildPersonContext(
|
||||||
|
$authorizationHelper->reveal(),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
$em->reveal(),
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertTrue($personContext->hasPublicForm($docGen, $person));
|
||||||
|
|
||||||
|
$personContext->storeGenerated(
|
||||||
|
$docGen,
|
||||||
|
new StoredObject(),
|
||||||
|
$person,
|
||||||
|
['scope' => $scope]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testScopeScopeMustBeShownInFormsAndUserAccessOneScope()
|
||||||
|
{
|
||||||
|
$person = new Person();
|
||||||
|
$docGen = (new DocGeneratorTemplate())
|
||||||
|
->setName(['fr' => 'template']);
|
||||||
|
$scope = new Scope();
|
||||||
|
|
||||||
|
$em = $this->prophesize(EntityManagerInterface::class);
|
||||||
|
$em->persist(Argument::type(PersonDocument::class))
|
||||||
|
->should(static function ($calls, $object, $method) use ($scope) {
|
||||||
|
if (1 !== count($calls)) {
|
||||||
|
throw new FailedPredictionException(sprintf('the persist should be called exactly once, %d receivved', count($calls)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var PersonDocument $personDocument */
|
||||||
|
$personDocument = $calls[0]->getArguments()[0];
|
||||||
|
|
||||||
|
if ($personDocument->getScope() !== $scope) {
|
||||||
|
throw new FailedPredictionException('the person document should show the exactly prepared scope');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class);
|
||||||
|
$authorizationHelper->getReachableScopes(Argument::type(UserInterface::class), PersonDocumentVoter::CREATE, Argument::type('array'))
|
||||||
|
->willReturn([$scope]);
|
||||||
|
|
||||||
|
$personContext = $this->buildPersonContext(
|
||||||
|
$authorizationHelper->reveal(),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
$em->reveal(),
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertTrue($personContext->hasPublicForm($docGen, $person));
|
||||||
|
|
||||||
|
$personContext->storeGenerated(
|
||||||
|
$docGen,
|
||||||
|
new StoredObject(),
|
||||||
|
$person,
|
||||||
|
['scope' => $scope]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildPersonContext(
|
||||||
|
?AuthorizationHelperInterface $authorizationHelper = null,
|
||||||
|
?BaseContextData $baseContextData = null,
|
||||||
|
?CenterResolverManagerInterface $centerResolverManager = null,
|
||||||
|
?DocumentCategoryRepository $documentCategoryRepository = null,
|
||||||
|
?EntityManagerInterface $em = null,
|
||||||
|
?NormalizerInterface $normalizer = null,
|
||||||
|
?ParameterBagInterface $parameterBag = null,
|
||||||
|
?Security $security = null,
|
||||||
|
?TranslatorInterface $translator = null,
|
||||||
|
?TranslatableStringHelperInterface $translatableStringHelper = null
|
||||||
|
): PersonContext {
|
||||||
|
if (null === $authorizationHelper) {
|
||||||
|
$authorizationHelper = $this->prophesize(AuthorizationHelperInterface::class)->reveal();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $baseContextData) {
|
||||||
|
$baseContextData = $this->prophesize(BaseContextData::class)->reveal();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $centerResolverManager) {
|
||||||
|
$centerResolverManager = $this->prophesize(CenterResolverManagerInterface::class);
|
||||||
|
$centerResolverManager->resolveCenters(Argument::any(), Argument::any())
|
||||||
|
->willReturn([new Center()]);
|
||||||
|
$centerResolverManager = $centerResolverManager->reveal();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $documentCategoryRepository) {
|
||||||
|
$documentCategoryRepository = $this->prophesize(DocumentCategoryRepository::class);
|
||||||
|
$documentCategoryRepository->find(Argument::type('integer'))->willReturn(
|
||||||
|
new DocumentCategory(PersonDocument::class, 1)
|
||||||
|
);
|
||||||
|
$documentCategoryRepository = $documentCategoryRepository->reveal();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $em) {
|
||||||
|
$em = $this->prophesize(EntityManagerInterface::class)->reveal();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $normalizer) {
|
||||||
|
$normalizer = $this->prophesize(NormalizerInterface::class);
|
||||||
|
$normalizer->normalize(Argument::type(Person::class), 'docgen', Argument::any())
|
||||||
|
->willReturn(['type' => 'person']);
|
||||||
|
$normalizer = $normalizer->reveal();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $parameterBag) {
|
||||||
|
$parameterBag = new ParameterBag(['chill_main' => ['acl' => ['form_show_scopes' => true]]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $security) {
|
||||||
|
$security = $this->prophesize(Security::class);
|
||||||
|
$security->getUser()->willReturn(new User());
|
||||||
|
$security = $security->reveal();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $translator) {
|
||||||
|
$translator = $this->prophesize(TranslatorInterface::class)->reveal();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null === $translatableStringHelper) {
|
||||||
|
$translatableStringHelper = $this->prophesize(TranslatableStringHelperInterface::class);
|
||||||
|
// return only the 'fr' key
|
||||||
|
$translatableStringHelper->localize(Argument::type('array'))->will(static function ($args) {
|
||||||
|
return $args[0]['fr'];
|
||||||
|
});
|
||||||
|
$translatableStringHelper = $translatableStringHelper->reveal();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new PersonContext(
|
||||||
|
$authorizationHelper,
|
||||||
|
$baseContextData,
|
||||||
|
$centerResolverManager,
|
||||||
|
$documentCategoryRepository,
|
||||||
|
$em,
|
||||||
|
$normalizer,
|
||||||
|
$parameterBag,
|
||||||
|
$security,
|
||||||
|
$translator,
|
||||||
|
$translatableStringHelper
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user