bootstrap api and apply on accompanying period

This commit is contained in:
2021-05-06 00:14:36 +02:00
parent f02e33fda7
commit 07e0692783
16 changed files with 235 additions and 257 deletions

View File

@@ -8,33 +8,51 @@ use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Chill\PersonBundle\Privacy\AccompanyingPeriodPrivacyEvent;
use Chill\PersonBundle\Entity\Person;
class AccompanyingCourseApiController extends ApiController
{
public function participationApi($accompanyingPeriodId, Request $request)
protected EventDispatcherInterface $eventDispatcher;
protected ValidatorInterface $validator;
public function __construct(EventDispatcherInterface $eventDispatcher, $validator)
{
$this->eventDispatcher = $eventDispatcher;
$this->validator = $validator;
}
public function participationApi($id, Request $request, $_format)
{
/** @var AccompanyingPeriod $accompanyingPeriod */
$accompanyingPeriod = $this->getEntity($accompanyingPeriodId);
$person = $this->serializer->deserialize($request->getContent(), Person::class, $_format, []);
$accompanyingPeriod = $this->getEntity('participation', $id, $request);
$person = $this->getSerializer()
->deserialize($request->getContent(), Person::class, $_format, []);
if (NULL === $person) {
throw new BadRequestException('person id not found');
}
// TODO add acl
//
$this->onPostCheckACL('participation', $request, $accompanyingPeriod, $_format);
switch ($request->getMethod()) {
case Request::METHOD_POST:
$participation = $accompanyingCours->addPerson($person);
$participation = $accompanyingPeriod->addPerson($person);
break;
case Request::METHOD_DELETE:
$participation = $accompanyingCours->removePerson($person);
$participation = $accompanyingPeriod->removePerson($person);
$participation->setEndDate(new \DateTimeImmutable('now'));
break;
default:
throw new BadRequestException("This method is not supported");
}
$errors = $this->validator->validate($accompanyingCourse);
$errors = $this->validator->validate($accompanyingPeriod);
if ($errors->count() > 0) {
// only format accepted
@@ -44,5 +62,18 @@ class AccompanyingCourseApiController extends ApiController
$this->getDoctrine()->getManager()->flush();
return $this->json($participation);
}
}
protected function onPostCheckACL(string $action, Request $request, $entity, $_format): ?Response
{
$this->eventDispatcher->dispatch(
AccompanyingPeriodPrivacyEvent::ACCOMPANYING_PERIOD_PRIVACY_EVENT,
new AccompanyingPeriodPrivacyEvent($entity, [
'action' => $action,
'request' => $request->getMethod()
])
);
return null;
}
}

View File

@@ -25,6 +25,7 @@ use Doctrine\Persistence\ObjectManager;
use Chill\MainBundle\DataFixtures\ORM\LoadPermissionsGroup;
use Chill\MainBundle\Entity\RoleScope;
use Chill\PersonBundle\Security\Authorization\PersonVoter;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
/**
* Add a role CHILL_PERSON_UPDATE & CHILL_PERSON_CREATE for all groups except administrative,
@@ -44,6 +45,7 @@ class LoadPersonACL extends AbstractFixture implements OrderedFixtureInterface
{
foreach (LoadPermissionsGroup::$refs as $permissionsGroupRef) {
$permissionsGroup = $this->getReference($permissionsGroupRef);
$scopeSocial = $this->getReference('scope_social');
//create permission group
switch ($permissionsGroup->getName()) {
@@ -51,6 +53,12 @@ class LoadPersonACL extends AbstractFixture implements OrderedFixtureInterface
case 'direction':
printf("Adding CHILL_PERSON_UPDATE & CHILL_PERSON_CREATE to %s permission group \n", $permissionsGroup->getName());
$permissionsGroup->addRoleScope(
(new RoleScope())
->setRole(AccompanyingPeriodVoter::SEE)
->setScope($scopeSocial)
);
$roleScopeUpdate = (new RoleScope())
->setRole('CHILL_PERSON_UPDATE')
->setScope(null);

View File

@@ -315,7 +315,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
[
'class' => \Chill\PersonBundle\Entity\AccompanyingPeriod::class,
'name' => 'accompanying_course',
'base_path' => '/api/1.0/accompanying_course',
'base_path' => '/api/1.0/person/accompanying-course',
'controller' => \Chill\PersonBundle\Controller\AccompanyingCourseApiController::class,
'actions' => [
'_entity' => [
@@ -323,7 +323,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac
Request::METHOD_GET => \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE
]
],
'/participation' => [
'participation' => [
'methods' => [
Request::METHOD_POST => true,
Request::METHOD_DELETE => true,

View File

@@ -118,7 +118,7 @@ class AccompanyingPeriod
*
* @ORM\OneToMany(targetEntity=AccompanyingPeriodParticipation::class,
* mappedBy="accompanyingPeriod",
* cascade={"persist", "remove", "merge", "detach"})
* cascade={"persist", "refresh", "remove", "merge", "detach"})
*/
private $participations;
@@ -348,7 +348,7 @@ class AccompanyingPeriod
*/
public function getParticipationsContainsPerson(Person $person): Collection
{
return $this->getParticipations()->filter(
return $this->getParticipations($person)->filter(
function(AccompanyingPeriodParticipation $participation) use ($person) {
if ($person === $participation->getPerson()) {
return $participation;
@@ -361,11 +361,11 @@ class AccompanyingPeriod
*
* "Open" means that the closed date is NULL
*/
public function getOpenParticipationsContainsPerson(Person $person): ?AccompanyingPeriodParticipation
public function getOpenParticipationContainsPerson(Person $person): ?AccompanyingPeriodParticipation
{
$collection = $this->getParticipationsContainsPerson()->filter(
$collection = $this->getParticipationsContainsPerson($person)->filter(
function(AccompanyingPeriodParticipation $participation) use ($person) {
if (NULL === $participation->getClosingDate()) {
if (NULL === $participation->getEndDate()) {
return $participation;
}
});
@@ -380,7 +380,7 @@ class AccompanyingPeriod
*/
public function containsPerson(Person $person): bool
{
return $this->participationsContainsPerson($person)->count() > 0;
return $this->getParticipationsContainsPerson($person)->count() > 0;
}
/**

View File

@@ -38,7 +38,7 @@ class AccompanyingPeriodNormalizer implements NormalizerInterface, NormalizerAwa
'remark' => $period->getRemark(),
'participations' => $this->normalizer->normalize($period->getParticipations(), $format),
'closingMotive' => $this->normalizer->normalize($period->getClosingMotive(), $format),
'user' => $period->getUser() ? $this->normalize($period->getUser(), $format) : null,
'user' => $period->getUser() ? $this->normalizer->normalize($period->getUser(), $format) : null,
'step' => $period->getStep(),
'origin' => $this->normalizer->normalize($period->getOrigin(), $format),
'intensity' => $period->getIntensity(),

View File

@@ -55,7 +55,7 @@ class PersonNormalizer implements
'id' => $person->getId(),
'firstName' => $person->getFirstName(),
'lastName' => $person->getLastName(),
'birthdate' => $person->getBirthdate(),
'birthdate' => $this->normalizer->normalize($person->getBirthdate()),
'center' => $this->normalizer->normalize($person->getCenter())
];
}

View File

@@ -36,7 +36,7 @@ use Symfony\Component\HttpFoundation\Request;
/**
* Test api for AccompanyingCourseControllerTest
*/
class AccompanyingCourseControllerTest extends WebTestCase
class AccompanyingCourseApiControllerTest extends WebTestCase
{
protected static EntityManagerInterface $em;
@@ -65,7 +65,7 @@ class AccompanyingCourseControllerTest extends WebTestCase
*/
public function testAccompanyingCourseShow(int $personId, AccompanyingPeriod $period)
{
$this->client->request(Request::METHOD_GET, sprintf('/fr/person/api/1.0/accompanying-course/%d/show.json', $period->getId()));
$c = $this->client->request(Request::METHOD_GET, sprintf('/api/1.0/person/accompanying-course/%d.json', $period->getId()));
$response = $this->client->getResponse();
$this->assertEquals(200, $response->getStatusCode(), "Test that the response of rest api has a status code ok (200)");
@@ -77,6 +77,14 @@ class AccompanyingCourseControllerTest extends WebTestCase
$this->assertGreaterThan(0, $data->participations);
}
public function testShow404()
{
$this->client->request(Request::METHOD_GET, sprintf('/api/1.0/person/accompanying-course/%d.json', 99999));
$response = $this->client->getResponse();
$this->assertEquals(404, $response->getStatusCode(), "Test that the response of rest api has a status code 'not found' (404)");
}
/**
*
* @dataProvider dataGenerateRandomAccompanyingCourse
@@ -85,26 +93,55 @@ class AccompanyingCourseControllerTest extends WebTestCase
{
$this->client->request(
Request::METHOD_POST,
sprintf('/fr/person/api/1.0/accompanying-course/%d/participation.json', $period->getId()),
sprintf('/api/1.0/person/accompanying-course/%d/participation.json', $period->getId()),
[], // parameters
[], // files
[], // server parameters
\json_encode([ 'id' => $personId ])
);
$response = $this->client->getResponse();
$data = \json_decode($response->getContent(), true);
$this->assertEquals(200, $response->getStatusCode(), "Test that the response of rest api has a status code ok (200)");
$this->client->request(Request::METHOD_GET, sprintf('/fr/person/api/1.0/accompanying-course/%d/show.json', $period->getId()));
$this->assertArrayHasKey('id', $data);
$this->assertArrayHasKey('startDate', $data);
$this->assertNotNull($data['startDate']);
// check by deownloading the accompanying cours
$this->client->request(Request::METHOD_GET, sprintf('/api/1.0/person/accompanying-course/%d.json', $period->getId()));
$response = $this->client->getResponse();
$data = \json_decode($response->getContent());
// check that the person id is contained
$participationsPersonsIds = \array_map(
function($participation) { return $participation->person->id; },
$data->participations);
$this->assertContains($personId, $participationsPersonsIds);
// check removing the participation
$this->client->request(
Request::METHOD_DELETE,
sprintf('/api/1.0/person/accompanying-course/%d/participation.json', $period->getId()),
[], // parameters
[], // files
[], // server parameters
\json_encode([ 'id' => $personId ])
);
$response = $this->client->getResponse();
$data = \json_decode($response->getContent(), true);
$this->assertEquals(200, $response->getStatusCode(), "Test that the response of rest api has a status code ok (200)");
$this->assertArrayHasKey('id', $data);
$this->assertArrayHasKey('startDate', $data);
$this->assertNotNull($data['startDate']);
$this->assertArrayHasKey('endDate', $data);
$this->assertNotNull($data['endDate']);
// set to variable for tear down
$this->personId = $personId;
$this->period = $period;
}
@@ -112,6 +149,7 @@ class AccompanyingCourseControllerTest extends WebTestCase
protected function tearDown()
{
// remove participation created during test 'testAccompanyingCourseAddParticipation'
// and if the test could not remove it
$testAddParticipationName = 'testAccompanyingCourseAddParticipation';
@@ -126,8 +164,10 @@ class AccompanyingCourseControllerTest extends WebTestCase
->findOneBy(['person' => $this->personId, 'accompanyingPeriod' => $this->period])
;
$em->remove($participation);
$em->flush();
if (NULL !== $participation) {
$em->remove($participation);
$em->flush();
}
}
public function dataGenerateRandomAccompanyingCourse()
@@ -139,9 +179,9 @@ class AccompanyingCourseControllerTest extends WebTestCase
// * one for getting the person, which will in turn provide his accompanying period;
// * one for getting the personId to populate to the data manager
//
// Ensure to keep always $maxGenerated to the double of $maxResults
$maxGenerated = 1;
$maxResults = 15 * 8;
// Ensure to keep always $maxGenerated to the double of $maxResults. x8 is a good compromize :)
$maxGenerated = 3;
$maxResults = $maxGenerated * 8;
static::bootKernel();
$em = static::$container->get(EntityManagerInterface::class);

View File

@@ -27,7 +27,6 @@ use Chill\PersonBundle\Entity\Person;
class AccompanyingPeriodTest extends \PHPUnit\Framework\TestCase
{
public function testClosingIsAfterOpeningConsistency()
{
$datetime1 = new \DateTime('now');
@@ -77,22 +76,24 @@ class AccompanyingPeriodTest extends \PHPUnit\Framework\TestCase
$this->assertFalse($period->isOpen());
}
public function testCanBeReOpened()
public function testPersonPeriod()
{
$person = new Person(\DateTime::createFromFormat('Y-m-d', '2010-01-01'));
$person->close($person->getAccompanyingPeriods()[0]
->setClosingDate(\DateTime::createFromFormat('Y-m-d', '2010-12-31')));
$firstAccompanygingPeriod = $person->getAccompanyingPeriodsOrdered()[0];
$this->assertTrue($firstAccompanygingPeriod->canBeReOpened());
$lastAccompanyingPeriod = (new AccompanyingPeriod(\DateTime::createFromFormat('Y-m-d', '2011-01-01')))
->setClosingDate(\DateTime::createFromFormat('Y-m-d', '2011-12-31'))
;
$person->addAccompanyingPeriod($lastAccompanyingPeriod);
$this->assertFalse($firstAccompanygingPeriod->canBeReOpened());
}
$person = new Person();
$period = new AccompanyingPeriod(new \DateTime());
$period->addPerson($person);
$this->assertEquals(1, $period->getParticipations()->count());
$this->assertTrue($period->containsPerson($person));
$participation = $period->getOpenParticipationContainsPerson($person);
$participations = $period->getParticipationsContainsPerson($person);
$this->assertNotNull($participation);
$this->assertEquals(1, $participations->count());
$period->removePerson($person);
$participation = $period->getOpenParticipationContainsPerson($person);
$this->assertNull($participation);
}
}

View File

@@ -45,3 +45,9 @@ services:
$dispatcher: '@Symfony\Contracts\EventDispatcher\EventDispatcherInterface'
$validator: '@Symfony\Component\Validator\Validator\ValidatorInterface'
tags: ['controller.service_arguments']
Chill\PersonBundle\Controller\AccompanyingCourseApiController:
arguments:
$eventDispatcher: '@Symfony\Contracts\EventDispatcher\EventDispatcherInterface'
$validator: '@Symfony\Component\Validator\Validator\ValidatorInterface'
tags: ['controller.service_arguments']