Set requestor for accompanying period

This commit is contained in:
Julien Fastré 2021-05-10 15:59:34 +02:00
parent 3447117742
commit 4f3f16d9b0
10 changed files with 193 additions and 19 deletions

View File

@ -25,12 +25,19 @@ class AbstractCRUDController extends AbstractController
*
* @param string $id
* @return object
* @throw Symfony\Component\HttpKernel\Exception\NotFoundHttpException if the object is not found
*/
protected function getEntity($action, $id, Request $request): ?object
protected function getEntity($action, $id, Request $request): object
{
return $this->getDoctrine()
$e = $this->getDoctrine()
->getRepository($this->getEntityClass())
->find($id);
if (NULL === $e) {
throw $this->createNotFoundException(sprintf("The object %s for id %s is not found", $this->getEntityClass(), $id));
}
return $e;
}
/**

View File

@ -12,6 +12,8 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Chill\PersonBundle\Privacy\AccompanyingPeriodPrivacyEvent;
use Chill\PersonBundle\Entity\Person;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Symfony\Component\Serializer\Exception\RuntimeException;
class AccompanyingCourseApiController extends ApiController
{
@ -64,6 +66,50 @@ class AccompanyingCourseApiController extends ApiController
return $this->json($participation);
}
public function requestorApi($id, Request $request, string $_format): Response
{
/** @var AccompanyingPeriod $accompanyingPeriod */
$action = 'requestor';
$accompanyingPeriod = $this->getEntity($action, $id, $request);
// a requestor may be a person or a thirdParty
$this->checkACL($action, $request, $_format, $accompanyingPeriod);
$this->onPostCheckACL($action, $request, $_format, $accompanyingPeriod);
if (Request::METHOD_DELETE === $request->getMethod()) {
$accompanyingPeriod->setRequestor(NULL);
} elseif (Request::METHOD_POST === $request->getMethod()) {
$requestor = null;
$exceptions = [];
foreach ([Person::class, ThirdParty::class] as $class) {
try {
$requestor = $this->getSerializer()
->deserialize($request->getContent(), $class, $_format, []);
} catch (RuntimeException $e) {
$exceptions[] = $e;
}
}
if ($requestor === null) {
throw new BadRequestException('Could not find any person or requestor', 0, $exceptions[0]);
}
$accompanyingPeriod->setRequestor($requestor);
} else {
throw new BadRequestException('method not supported');
}
$errors = $this->validator->validate($accompanyingPeriod);
if ($errors->count() > 0) {
// only format accepted
return $this->json($errors);
}
$this->getDoctrine()->getManager()->flush();
return $this->json($accompanyingPeriod->getRequestor());
}
protected function onPostCheckACL(string $action, Request $request, string $_format, $entity): ?Response
{
$this->eventDispatcher->dispatch(

View File

@ -334,6 +334,18 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
Request::METHOD_POST => \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE,
Request::METHOD_DELETE=> \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE
]
],
'requestor' => [
'methods' => [
Request::METHOD_POST => true,
Request::METHOD_DELETE => true,
Request::METHOD_GET => false,
Request::METHOD_HEAD => false,
],
'roles' => [
Request::METHOD_POST => \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE,
Request::METHOD_DELETE=> \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE
]
]
]

View File

@ -515,9 +515,9 @@ class AccompanyingPeriod
return $this->requestorPerson;
}
public function setRequestorPerson(Person $requestorPerson): self
public function setRequestorPerson(Person $requestorPerson = null): self
{
$this->requestorPerson = ($this->requestorThirdParty === null) ? $requestorPerson : null;
$this->requestorPerson = $requestorPerson;
return $this;
}
@ -527,9 +527,9 @@ class AccompanyingPeriod
return $this->requestorThirdParty;
}
public function setRequestorThirdParty(ThirdParty $requestorThirdParty): self
public function setRequestorThirdParty(ThirdParty $requestorThirdParty = null): self
{
$this->requestorThirdParty = ($this->requestorPerson === null) ? $requestorThirdParty : null;
$this->requestorThirdParty = $requestorThirdParty;
return $this;
}
@ -542,6 +542,37 @@ class AccompanyingPeriod
return $this->requestorPerson ?? $this->requestorThirdParty;
}
/**
* Set a requestor
*
* The requestor is either an instance of ThirdParty, or an
* instance of Person
*
* @param $requestor Person|ThirdParty
* @return self
* @throw UnexpectedValueException if the requestor is not a Person or ThirdParty
*
*/
public function setRequestor($requestor): self
{
if ($requestor instanceof Person) {
$this->setRequestorThirdParty(NULL);
$this->setRequestorPerson($requestor);
} elseif ($requestor instanceof ThirdParty) {
$this->setRequestorThirdParty($requestor);
$this->setRequestorPerson(NULL);
} elseif (NULL === $requestor) {
$this->setRequestorPerson(NULL);
$this->setRequestorThirdParty(NULL);
} else {
throw new \UnexpectedValueException("requestor is not an instance of Person or ThirdParty");
}
return $this;
}
public function isRequestorAnonymous(): bool
{
return $this->requestorAnonymous;

View File

@ -83,16 +83,16 @@ class PersonNormalizer implements
public function denormalize($data, string $type, string $format = null, array $context = []): Person
{
if ($context[self::GET_PERSON] ?? true) {
$id = $data['id'] ?? null;
$id = $data['person_id'] ?? null;
if (NULL === $id) {
throw new RuntimeException("missing id into person object");
throw new RuntimeException("missing person_id into person object");
}
}
/** var Person $person */
$person = $this->repository->findOneById($id);
if (NULL === $person) {
return UnexpectedValueException("person id not found");
throw new UnexpectedValueException("person id not found");
}
return $person;

View File

@ -24,6 +24,7 @@ namespace Chill\PersonBundle\Tests\Entity;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
class AccompanyingPeriodTest extends \PHPUnit\Framework\TestCase
{
@ -104,4 +105,30 @@ class AccompanyingPeriodTest extends \PHPUnit\Framework\TestCase
$participation = $period->getOpenParticipationContainsPerson($person);
$this->assertNull($participation);
}
public function testRequestor()
{
$period = new AccompanyingPeriod(new \DateTime());
$person = new Person();
$thirdParty = new ThirdParty();
$this->assertNull($period->getRequestorThirdParty());
$this->assertNull($period->getRequestorPerson());
$this->assertNull($period->getRequestor());
$period->setRequestor($person);
$this->assertNull($period->getRequestorThirdParty());
$this->assertSame($person, $period->getRequestorPerson());
$this->assertSame($person, $period->getRequestor());
$period->setRequestor($thirdParty);
$this->assertNull($period->getRequestorPerson());
$this->assertSame($thirdParty, $period->getRequestorThirdParty());
$this->assertSame($thirdParty, $period->getRequestor());
$period->setRequestor(NULL);
$this->assertNull($period->getRequestorThirdParty());
$this->assertNull($period->getRequestorPerson());
$this->assertNull($period->getRequestor());
}
}

View File

@ -4,13 +4,18 @@ namespace Chill\ThirdPartyBundle\Repository;
use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\Query;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
/**
* ThirdPartyRepository
*
*/
class ThirdPartyRepository extends \Doctrine\ORM\EntityRepository
class ThirdPartyRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, ThirdParty::class);
}
/**
* count amongst parties associated to $centers, with $terms parameters
*

View File

@ -6,11 +6,24 @@ use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Exception\RuntimeException;
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Chill\ThirdPartyBundle\Repository\ThirdPartyRepository;
class ThirdPartyNormalizer implements NormalizerInterface, NormalizerAwareInterface
class ThirdPartyNormalizer implements NormalizerInterface, DenormalizerInterface, NormalizerAwareInterface
{
private ThirdPartyRepository $repository;
use NormalizerAwareTrait;
public function __construct(ThirdPartyRepository $repository)
{
$this->repository= $repository;
}
public function normalize($thirdParty, string $format = null, array $context = [])
{
/** @var $thirdParty ThirdParty */
@ -28,4 +41,30 @@ class ThirdPartyNormalizer implements NormalizerInterface, NormalizerAwareInterf
{
return $data instanceof ThirdParty;
}
public function denormalize($data, string $type, string $format = null, array $context = [])
{
$thirdParty = $context[AbstractNormalizer::OBJECT_TO_POPULATE] ?? NULL;
if (NULL === $thirdParty) {
$id = $data['thirdparty_id'] ?? NULL;
if (NULL === $id) {
throw new RuntimeException("mission thirdparty_id into body");
}
$thirdParty = $this->repository->findOneById($id);
if (NULL === $thirdParty) {
throw new UnexpectedValueException("thirdparty not found");
}
}
return $thirdParty;
}
public function supportsDenormalization($data, string $type, string $format = null)
{
return ThirdParty::class === $type;
}
}

View File

@ -1,2 +1,13 @@
---
services:
Chill\ThirdPartyBundle\Serializer\Normalizer\:
autowire: true
resource: '../Serializer/Normalizer/'
tags:
- { name: 'serializer.normalizer', priority: 64 }
Chill\ThirdPartyBundle\Repository\:
autowire: true
resource: '../Repository/'
tags:
- { name: 'doctrine.repository_service' }

View File

@ -1,5 +1 @@
services:
Chill\ThirdPartyBundle\Serializer\Normalizer\:
resource: '../../Serializer/Normalizer/'
tags:
- { name: 'serializer.normalizer', priority: 64 }