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/Controller/AccompanyingCourseController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseController.php index 8134f6938..6786cb05f 100644 --- a/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseController.php +++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingCourseController.php @@ -6,6 +6,7 @@ use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation; use Chill\PersonBundle\Privacy\AccompanyingPeriodPrivacyEvent; use Chill\PersonBundle\Entity\Person; +use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter; use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\JsonResponse; @@ -42,6 +43,41 @@ class AccompanyingCourseController extends Controller $this->dispatcher = $dispatcher; $this->validator = $validator; } + + /** + * @Route("/{_locale}/person/parcours/new", name="chill_person_accompanying_course_new") + */ + public function newAction(Request $request): Response + { + $period = new AccompanyingPeriod(); + $em = $this->getDoctrine()->getManager(); + + if ($request->query->has('person_id')) { + $personIds = $request->query->get('person_id'); + + if (FALSE === \is_array($personIds)) { + throw new BadRequestException("person_id parameter should be an array"); + } + + foreach ($personIds as $personId) { + $person = $em->getRepository(Person::class)->find($personId); + if (NULL !== $person) { + $period->addPerson($person); + } + } + } + + $this->denyAccessUnlessGranted(AccompanyingPeriodVoter::SEE, $period); + + $em->persist($period); + $em->flush(); + + return $this->redirectToRoute('chill_person_accompanying_course_show', [ + 'accompanying_period_id' => $period->getId() + ]); + + } + /** * Homepage of Accompanying Course section * @@ -86,83 +122,4 @@ class AccompanyingCourseController extends Controller ]); } - /** - * Get API Data for showing endpoint - * - * @Route( - * "/{_locale}/person/api/1.0/accompanying-course/{accompanying_period_id}/show.{_format}", - * name="chill_person_accompanying_course_api_show" - * ) - * @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"}) - */ - public function showAPI(AccompanyingPeriod $accompanyingCourse, $_format): Response - { - // TODO check ACL on AccompanyingPeriod - - $this->dispatcher->dispatch( - AccompanyingPeriodPrivacyEvent::ACCOMPANYING_PERIOD_PRIVACY_EVENT, - new AccompanyingPeriodPrivacyEvent($accompanyingCourse, [ - 'action' => 'showApi' - ]) - ); - - //$accompanyingCourse->getRequestorPerson(); - //$accompanyingCourse->getRequestorThirdParty(); - //$accompanyingCourse->isRequestorAnonymous(); - //dump($accompanyingCourse); die; - - switch ($_format) { - case 'json': - return $this->json($accompanyingCourse); - default: - throw new BadRequestException('Unsupported format'); - } - - } - - /** - * Get API Data for showing endpoint - * - * @Route( - * "/{_locale}/person/api/1.0/accompanying-course/{accompanying_period_id}/participation.{_format}", - * name="chill_person_accompanying_course_api_add_participation", - * methods={"POST","DELETE"}, - * format="json", - * requirements={ - * "_format": "json", - * } - * ) - * @ParamConverter("accompanyingCourse", options={"id": "accompanying_period_id"}) - */ - public function participationAPI(Request $request, AccompanyingPeriod $accompanyingCourse, $_format): Response - { - switch ($_format) { - case 'json': - $person = $this->serializer->deserialize($request->getContent(), Person::class, $_format, [ - - ]); - break; - default: - throw new BadRequestException('Unsupported format'); - } - - if (NULL === $person) { - throw new BadRequestException('person id not found'); - } - - // TODO add acl - $participation = ($request->getMethod() === 'POST') ? - $accompanyingCourse->addPerson($person) : $accompanyingCourse->removePerson($person); - - $errors = $this->validator->validate($accompanyingCourse); - - if ($errors->count() > 0) { - // only format accepted - return $this->json($errors); - } - - $this->getDoctrine()->getManager()->flush(); - - return $this->json($participation); - } } 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/Entity/AccompanyingPeriod.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php index 716edd118..69d461319 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod.php @@ -266,8 +266,8 @@ class AccompanyingPeriod * @param \DateTime $dateOpening * @uses AccompanyingPeriod::setClosingDate() */ - public function __construct(\DateTime $dateOpening) { - $this->setOpeningDate($dateOpening); + public function __construct(\DateTime $dateOpening = null) { + $this->setOpeningDate($dateOpening ?? new \DateTime('now')); $this->participations = new ArrayCollection(); $this->scopes = new ArrayCollection(); $this->socialIssues = new ArrayCollection(); diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Resource.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Resource.php index 74620b7b2..cf796722a 100644 --- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Resource.php +++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/Resource.php @@ -25,13 +25,14 @@ namespace Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment; use Chill\PersonBundle\Entity\Person; +use Chill\PersonBundle\Repository\AccompanyingPeriod\ResourceRepository; use Chill\ThirdPartyBundle\Entity\ThirdParty; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Serializer\Annotation\DiscriminatorMap; use Symfony\Component\Serializer\Annotation\Groups; /** - * @ORM\Entity + * @ORM\Entity(repositoryClass=ResourceRepository::class) * @ORM\Table(name="chill_person_accompanying_period_resource") * @DiscriminatorMap(typeProperty="type", mapping={ * "accompanying_period_resource"=Resource::class diff --git a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/ResourceRepository.php b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/ResourceRepository.php index 4f625b59c..c32f74762 100644 --- a/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/ResourceRepository.php +++ b/src/Bundle/ChillPersonBundle/Repository/AccompanyingPeriod/ResourceRepository.php @@ -23,8 +23,9 @@ namespace Chill\PersonBundle\Repository\AccompanyingPeriod; use Chill\PersonBundle\Entity\AccompanyingPeriod\Resource; -use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; +use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; +use Doctrine\Persistence\ManagerRegistry; /** * @method Resource|null find($id, $lockMode = null, $lockVersion = null) @@ -32,12 +33,12 @@ use Doctrine\ORM\EntityRepository; * @method Resource[] findAll() * @method Resource[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) */ -final class ResourceRepository +final class ResourceRepository extends ServiceEntityRepository { private EntityRepository $repository; - public function __construct(EntityManagerInterface $entityManager) + public function __construct(ManagerRegistry $registry) { - $this->repository = $entityManager->getRepository(Resource::class); + parent::__construct($registry, Resource::class); } } diff --git a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/banner.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/banner.html.twig index 8416c1e06..c8d566e84 100644 --- a/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/banner.html.twig +++ b/src/Bundle/ChillPersonBundle/Resources/views/AccompanyingCourse/banner.html.twig @@ -22,8 +22,10 @@
- ouvert le {{ accompanyingCourse.openingDate|format_date('short') }}
- par Soline Maillet | SIPAS
+ {{ 'Started on %date%'|trans({'%date%': accompanyingCourse.openingDate|format_date('short') } ) }}
+ {% if accompanyingCourse.user is not null %}
+ par {{ accompanyingCourse.user.usernameCanonical }}
+ {% endif %}