From 22aa4afc029f078500b1a72027a0fa92df66b5e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Wed, 19 May 2021 13:20:59 +0200 Subject: [PATCH] action: confirm accompanying period + create workflow --- .../AccompanyingCourseApiController.php | 33 ++++++- .../ChillPersonExtension.php | 45 ++++++++- .../AccompanyingCourseApiControllerTest.php | 93 +++++++++++++++---- .../Workflows/AccompanyingPeriodLifecycle.php | 27 ++++++ .../ChillPersonBundle/chill.api.specs.yaml | 24 +++++ .../config/services/controller.yaml | 1 + 6 files changed, 203 insertions(+), 20 deletions(-) create mode 100644 src/Bundle/ChillPersonBundle/Tests/Workflows/AccompanyingPeriodLifecycle.php diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php index 38f09b49e..0d8189b6a 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseApiController.php @@ -5,7 +5,6 @@ namespace Chill\PersonBundle\Controller; use Chill\MainBundle\CRUD\Controller\ApiController; use Symfony\Component\HttpFoundation\Request; 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; @@ -18,6 +17,7 @@ use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource; use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment; use Chill\PersonBundle\Entity\SocialWork\SocialIssue; use Chill\MainBundle\Entity\Scope; +use Symfony\Component\Workflow\Registry; class AccompanyingCourseApiController extends ApiController { @@ -25,10 +25,37 @@ class AccompanyingCourseApiController extends ApiController protected ValidatorInterface $validator; - public function __construct(EventDispatcherInterface $eventDispatcher, $validator) - { + private Registry $registry; + + public function __construct( + EventDispatcherInterface $eventDispatcher, + ValidatorInterface $validator, + Registry $registry + ) { $this->eventDispatcher = $eventDispatcher; $this->validator = $validator; + $this->registry = $registry; + } + + public function confirmApi($id, Request $request, $_format): Response + { + /** @var AccompanyingPeriod $accompanyingPeriod */ + $accompanyingPeriod = $this->getEntity('participation', $id, $request); + + $this->checkACL('confirm', $request, $_format, $accompanyingPeriod); +$workflow = $this->registry->get($accompanyingPeriod); + + if (FALSE === $workflow->can($accompanyingPeriod, 'confirm')) { + throw new BadRequestException('It is not possible to confirm this period'); + } + + $workflow->apply($accompanyingPeriod, 'confirm'); + + $this->getDoctrine()->getManager()->flush(); + + return $this->json($accompanyingPeriod, Response::HTTP_OK, [], [ + 'groups' => [ 'read' ] + ]); } public function participationApi($id, Request $request, $_format) diff --git a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php index 8941f5943..0d6346c01 100644 --- a/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php +++ b/src/Bundle/ChillPersonBundle/DependencyInjection/ChillPersonExtension.php @@ -1,5 +1,4 @@ * @@ -166,6 +165,7 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac $this->prependHomepageWidget($container); $this->prependDoctrineDQL($container); $this->prependCruds($container); + $this->prependWorkflows($container); //add person_fields parameter as global $chillPersonConfig = $container->getExtensionConfig($this->getAlias()); @@ -195,6 +195,39 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac )); } + protected function prependWorkflows(ContainerBuilder $container) + { + $container->prependExtensionConfig('framework', [ + 'workflows' => [ + 'accompanying_period_lifecycle' => [ + 'type' => 'state_machine', + 'audit_trail' => [ + 'enabled' => true + ], + 'marking_store' => [ + 'type' => 'method', + 'property' => 'step', + ], + 'supports' => [ + 'Chill\PersonBundle\Entity\AccompanyingPeriod' + ], + 'initial_marking' => 'DRAFT', + 'places' => [ + 'DRAFT', + 'CONFIRMED', + ], + 'transitions' => [ + 'confirm' => [ + 'from' => 'DRAFT', + 'to' => 'CONFIRMED' + ], + ], + ], + ] + ]); + + } + /** * Add a widget "add a person" on the homepage, automatically * @@ -406,6 +439,16 @@ class ChillPersonExtension extends Extension implements PrependExtensionInterfac ] ], + 'confirm' => [ + 'methods' => [ + Request::METHOD_POST => true, + Request::METHOD_GET => false, + Request::METHOD_HEAD => false, + ], + 'roles' => [ + Request::METHOD_POST => \Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter::SEE, + ] + ], ] ], [ diff --git a/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseApiControllerTest.php b/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseApiControllerTest.php index 716048966..a41e570a5 100644 --- a/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseApiControllerTest.php +++ b/src/Bundle/ChillPersonBundle/Tests/Controller/AccompanyingCourseApiControllerTest.php @@ -43,6 +43,10 @@ class AccompanyingCourseApiControllerTest extends WebTestCase { protected static EntityManagerInterface $em; + protected ?int $personId = NULL; + + protected ?AccompanyingPeriod $period = NULL; + /** * Setup before the first test of this class (see phpunit doc) */ @@ -302,6 +306,22 @@ class AccompanyingCourseApiControllerTest extends WebTestCase $this->assertNull($period->getRequestor()); } + /** + * @dataProvider dataGenerateNewAccompanyingCourse + */ + public function testConfirm(AccompanyingPeriod $period) + { + $this->client->request( + Request::METHOD_POST, + sprintf('/api/1.0/person/accompanying-course/%d/confirm.json', $period->getId()) + ); + + $this->assertEquals(200, $this->client->getResponse()->getStatusCode()); + + // add period to remove it in tear down + $this->period = $period; + } + /** * * @dataProvider dataGenerateRandomAccompanyingCourse @@ -439,25 +459,32 @@ class AccompanyingCourseApiControllerTest extends WebTestCase protected function tearDown() { - // remove participation created during test 'testAccompanyingCourseAddParticipation' - // and if the test could not remove it - - $testAddParticipationName = 'testAccompanyingCourseAddParticipation'; - - if ($testAddParticipationName !== \substr($this->getName(), 0, \strlen($testAddParticipationName))) { - return; - } - $em = static::$container->get(EntityManagerInterface::class); - $participation = $em - ->getRepository(AccompanyingPeriodParticipation::class) - ->findOneBy(['person' => $this->personId, 'accompanyingPeriod' => $this->period]) - ; + // remove participation if set + if ($this->personId && $this->period) { + $participation = $em + ->getRepository(AccompanyingPeriodParticipation::class) + ->findOneBy(['person' => $this->personId, 'accompanyingPeriod' => $this->period]) + ; - if (NULL !== $participation) { - $em->remove($participation); - $em->flush(); + if (NULL !== $participation) { + $em->remove($participation); + $em->flush(); + } + $this->personId = NULL; + $this->period = NULL; + } elseif ($this->period) { + $period = $em + ->getRepository(AccompanyingPeriod::class) + ->find($this->period->getId()) ; + + if ($period !== NULL) { + $em->remove($period); + $em->flush(); + } + + $this->period = null; } } @@ -550,4 +577,38 @@ class AccompanyingCourseApiControllerTest extends WebTestCase } } + public function dataGenerateNewAccompanyingCourse() + { + self::bootKernel(); + $em = self::$container->get(EntityManagerInterface::class); + + $period = new AccompanyingPeriod(new \DateTime('1 week ago')); + $user = $em->getRepository(User::class) + ->findOneByUsernameCanonical('center a_social'); + $period->setCreatedBy($user); + //$period->setCreatedAt(new \DateTime('yesterday')); + + $center = $em->getRepository(Center::class) + ->findOneBy(array('name' => 'Center A')); + + $personIds = $em->createQuery("SELECT p.id FROM ". + Person::class." p ". + " WHERE p.center = :center") + ->setParameter('center', $center) + ->setMaxResults(100) + ->getScalarResult(); + + // create a random order + shuffle($personIds); + + for ($i = 0; $i<2; $i++) { + $person = $em->getRepository(Person::class)->find(\array_pop($personIds)); + $period->addPerson($person); + } + + $em->persist($period); + $em->flush(); + + yield [ $period ]; + } } diff --git a/src/Bundle/ChillPersonBundle/Tests/Workflows/AccompanyingPeriodLifecycle.php b/src/Bundle/ChillPersonBundle/Tests/Workflows/AccompanyingPeriodLifecycle.php new file mode 100644 index 000000000..df86d79a6 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Tests/Workflows/AccompanyingPeriodLifecycle.php @@ -0,0 +1,27 @@ +get(Registry::class); + $period = new AccompanyingPeriod(new \DateTime('now')); + $workflow = $registry->get($period); + + $this->assertArrayHasKey('DRAFT', $workflow->getMarking($period)->getPlaces()); + $this->assertTrue($workflow->can($period, 'confirm')); + } + +} diff --git a/src/Bundle/ChillPersonBundle/chill.api.specs.yaml b/src/Bundle/ChillPersonBundle/chill.api.specs.yaml index ba6da70e7..a5636d93e 100644 --- a/src/Bundle/ChillPersonBundle/chill.api.specs.yaml +++ b/src/Bundle/ChillPersonBundle/chill.api.specs.yaml @@ -677,3 +677,27 @@ paths: description: "OK" 422: description: "object with validation errors" + + /1.0/person/accompanying-course/{id}/confirm.json: + post: + tags: + - person + summary: confirm an accompanying course + parameters: + - name: id + in: path + required: true + description: The accompanying period's id + schema: + type: integer + format: integer + minimum: 1 + responses: + 401: + description: "Unauthorized" + 404: + description: "Not found" + 200: + description: "OK" + 400: + description: "transition cannot be applyed" diff --git a/src/Bundle/ChillPersonBundle/config/services/controller.yaml b/src/Bundle/ChillPersonBundle/config/services/controller.yaml index 41a5ac719..fd5e1f952 100644 --- a/src/Bundle/ChillPersonBundle/config/services/controller.yaml +++ b/src/Bundle/ChillPersonBundle/config/services/controller.yaml @@ -51,4 +51,5 @@ services: arguments: $eventDispatcher: '@Symfony\Contracts\EventDispatcher\EventDispatcherInterface' $validator: '@Symfony\Component\Validator\Validator\ValidatorInterface' + $registry: '@Symfony\Component\Workflow\Registry' tags: ['controller.service_arguments']