, * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ namespace Chill\ActivityBundle\Controller; use Chill\MainBundle\Security\Authorization\AuthorizationHelper; use Chill\PersonBundle\Entity\AccompanyingPeriod; use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Privacy\PrivacyEvent; use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Form\Form; use Symfony\Component\HttpFoundation\Request; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Security\Core\Role\Role; use Chill\ActivityBundle\Entity\Activity; use Chill\ActivityBundle\Form\ActivityType; use Symfony\Component\Serializer\SerializerInterface; /** * Class ActivityController * * @package Chill\ActivityBundle\Controller */ class ActivityController extends AbstractController { protected EventDispatcherInterface $eventDispatcher; protected AuthorizationHelper $authorizationHelper; protected LoggerInterface $logger; protected SerializerInterface $serializer; public function __construct( EventDispatcherInterface $eventDispatcher, AuthorizationHelper $authorizationHelper, LoggerInterface $logger, SerializerInterface $serializer ) { $this->eventDispatcher = $eventDispatcher; $this->authorizationHelper = $authorizationHelper; $this->logger = $logger; $this->serializer = $serializer; } /** * Lists all Activity entities. */ public function listAction(Request $request): Response { $em = $this->getDoctrine()->getManager(); $view = null; [$person, $accompanyingPeriod] = $this->getEntity($request); if ($person instanceof Person) { $reachableScopes = $this->authorizationHelper ->getReachableCircles($this->getUser(), new Role('CHILL_ACTIVITY_SEE'), $person->getCenter()); $activities = $em->getRepository('ChillActivityBundle:Activity')->findBy( ['person' => $person, 'scope' => $reachableScopes], ['date' => 'DESC'], ); $event = new PrivacyEvent($person, array( 'element_class' => Activity::class, 'action' => 'list' )); $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); $view = 'ChillActivityBundle:Activity:listPerson.html.twig'; } elseif ($accompanyingPeriod instanceof AccompanyingPeriod) { $activities = $em->getRepository('ChillActivityBundle:Activity')->findBy( ['accompanyingPeriod' => $accompanyingPeriod], ['date' => 'DESC'], ); $view = 'ChillActivityBundle:Activity:listAccompanyingCourse.html.twig'; } return $this->render($view, array( 'activities' => $activities, 'person' => $person, 'accompanyingCourse' => $accompanyingPeriod, )); } public function selectTypeAction(Request $request): Response { $em = $this->getDoctrine()->getManager(); $view = null; [$person, $accompanyingPeriod] = $this->getEntity($request); if ($accompanyingPeriod instanceof AccompanyingPeriod) { $view = 'ChillActivityBundle:Activity:selectTypeAccompanyingCourse.html.twig'; } elseif ($person instanceof Person) { $view = 'ChillActivityBundle:Activity:selectTypePerson.html.twig'; } $data = []; $activityTypeCategories = $em->getRepository(\Chill\ActivityBundle\Entity\ActivityTypeCategory::class) ->findBy(['active' => true], ['ordering' => 'ASC']); foreach ($activityTypeCategories as $activityTypeCategory) { $activityTypes = $em->getRepository(\Chill\ActivityBundle\Entity\ActivityType::class) ->findBy(['active' => true, 'category' => $activityTypeCategory], ['ordering' => 'ASC']); $data[] = [ 'activityTypeCategory' => $activityTypeCategory, 'activityTypes' => $activityTypes, ]; } if ($view === null) { throw $this->createNotFoundException('Template not found'); } return $this->render($view, [ 'person' => $person, 'accompanyingCourse' => $accompanyingPeriod, 'data' => $data, ]); } public function newAction(Request $request): Response { $em = $this->getDoctrine()->getManager(); [$person, $accompanyingPeriod] = $this->getEntity($request); if ($accompanyingPeriod instanceof AccompanyingPeriod) { $view = 'ChillActivityBundle:Activity:newAccompanyingCourse.html.twig'; } elseif ($person instanceof Person) { $view = 'ChillActivityBundle:Activity:newPerson.html.twig'; } $activityType_id = $request->get('activityType_id', 0); $activityType = $em->getRepository(\Chill\ActivityBundle\Entity\ActivityType::class) ->find($activityType_id); if (!$activityType instanceof \Chill\ActivityBundle\Entity\ActivityType || !$activityType->isActive()) { $params = $this->buildParamsToUrl($person, $accompanyingPeriod); return $this->redirectToRoute('chill_activity_activity_select_type', $params); } $entity = new Activity(); $entity->setUser($this->getUser()); if ($person instanceof Person) { $entity->setPerson($person); } if ($accompanyingPeriod instanceof AccompanyingPeriod) { $entity->setAccompanyingPeriod($accompanyingPeriod); } $entity->setType($activityType); $entity->setDate(new \DateTime('now')); // TODO revoir le Voter de Activity pour tenir compte qu'une activité peut appartenir a une période // $this->denyAccessUnlessGranted('CHILL_ACTIVITY_CREATE', $entity); $form = $this->createForm(ActivityType::class, $entity, [ 'center' => $entity->getCenter(), 'role' => new Role('CHILL_ACTIVITY_CREATE'), 'activityType' => $entity->getType(), ])->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $em->persist($entity); $em->flush(); $this->addFlash('success', $this->get('translator')->trans('Success : activity created!')); $params = $this->buildParamsToUrl($person, $accompanyingPeriod); $params['id'] = $entity->getId(); return $this->redirectToRoute('chill_activity_activity_show', $params); } if ($view === null) { throw $this->createNotFoundException('Template not found'); } $activity_array = $this->serializer->normalize($entity, 'json', ['groups' => 'read']); return $this->render($view, [ 'person' => $person, 'accompanyingCourse' => $accompanyingPeriod, 'entity' => $entity, 'form' => $form->createView(), 'activity_json' => $activity_array ]); } public function showAction(Request $request, $id): Response { $em = $this->getDoctrine()->getManager(); [$person, $accompanyingPeriod] = $this->getEntity($request); if ($accompanyingPeriod instanceof AccompanyingPeriod) { $view = 'ChillActivityBundle:Activity:showAccompanyingCourse.html.twig'; } elseif ($person instanceof Person) { $view = 'ChillActivityBundle:Activity:showPerson.html.twig'; } $entity = $em->getRepository('ChillActivityBundle:Activity')->find($id); if (!$entity) { throw $this->createNotFoundException('Unable to find Activity entity.'); } if (null !== $accompanyingPeriod) { $entity->personsAssociated = $entity->getPersonsAssociated(); $entity->personsNotAssociated = $entity->getPersonsNotAssociated(); } // TODO revoir le Voter de Activity pour tenir compte qu'une activité peut appartenir a une période // $this->denyAccessUnlessGranted('CHILL_ACTIVITY_SEE', $entity); $deleteForm = $this->createDeleteForm($id, $person, $accompanyingPeriod); // TODO /* $event = new PrivacyEvent($person, array( 'element_class' => Activity::class, 'element_id' => $entity->getId(), 'action' => 'show' )); $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); */ if ($view === null) { throw $this->createNotFoundException('Template not found'); } return $this->render($view, array( 'person' => $person, 'accompanyingCourse' => $accompanyingPeriod, 'entity' => $entity, 'delete_form' => $deleteForm->createView(), )); } /** * Displays a form to edit an existing Activity entity. * */ public function editAction($id, Request $request): Response { $em = $this->getDoctrine()->getManager(); [$person, $accompanyingPeriod] = $this->getEntity($request); if ($accompanyingPeriod instanceof AccompanyingPeriod) { $view = 'ChillActivityBundle:Activity:editAccompanyingCourse.html.twig'; } elseif ($person instanceof Person) { $view = 'ChillActivityBundle:Activity:editPerson.html.twig'; } $entity = $em->getRepository('ChillActivityBundle:Activity')->find($id); if (!$entity) { throw $this->createNotFoundException('Unable to find Activity entity.'); } // TODO // $this->denyAccessUnlessGranted('CHILL_ACTIVITY_UPDATE', $entity); $form = $this->createForm(ActivityType::class, $entity, [ 'center' => $entity->getCenter(), 'role' => new Role('CHILL_ACTIVITY_UPDATE'), 'activityType' => $entity->getType(), ])->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { $em->persist($entity); $em->flush(); $this->addFlash('success', $this->get('translator')->trans('Success : activity updated!')); $params = $this->buildParamsToUrl($person, $accompanyingPeriod); $params['id'] = $id; return $this->redirectToRoute('chill_activity_activity_show', $params); } $deleteForm = $this->createDeleteForm($id, $person, $accompanyingPeriod); /* * TODO $event = new PrivacyEvent($person, array( 'element_class' => Activity::class, 'element_id' => $entity->getId(), 'action' => 'edit' )); $this->eventDispatcher->dispatch(PrivacyEvent::PERSON_PRIVACY_EVENT, $event); */ if ($view === null) { throw $this->createNotFoundException('Template not found'); } $activity_array = $this->serializer->normalize($entity, 'json', ['groups' => 'read']); return $this->render($view, array( 'entity' => $entity, 'edit_form' => $form->createView(), 'delete_form' => $deleteForm->createView(), 'person' => $person, 'accompanyingCourse' => $accompanyingPeriod, 'activity_json' => $activity_array )); } /** * Deletes a Activity entity. * */ public function deleteAction(Request $request, $id) { $em = $this->getDoctrine()->getManager(); [$person, $accompanyingPeriod] = $this->getEntity($request); if ($accompanyingPeriod instanceof AccompanyingPeriod) { $view = 'ChillActivityBundle:Activity:confirm_deleteAccompanyingCourse.html.twig'; } elseif ($person instanceof Person) { $view = 'ChillActivityBundle:Activity:confirm_deletePerson.html.twig'; } /* @var $activity Activity */ $activity = $em->getRepository('ChillActivityBundle:Activity')->find($id); if (!$activity) { throw $this->createNotFoundException('Unable to find Activity entity.'); } // TODO // $this->denyAccessUnlessGranted('CHILL_ACTIVITY_DELETE', $activity); $form = $this->createDeleteForm($id, $person, $accompanyingPeriod); if ($request->getMethod() === Request::METHOD_DELETE) { $form->handleRequest($request); if ($form->isValid()) { $this->logger->notice("An activity has been removed", array( 'by_user' => $this->getUser()->getUsername(), 'activity_id' => $activity->getId(), 'person_id' => $activity->getPerson() ? $activity->getPerson()->getId() : null, 'comment' => $activity->getComment()->getComment(), 'scope_id' => $activity->getScope() ? $activity->getScope()->getId() : null, 'reasons_ids' => $activity->getReasons() ->map(function ($ar) { return $ar->getId(); }) ->toArray(), 'type_id' => $activity->getType()->getId(), 'duration' => $activity->getDurationTime() ? $activity->getDurationTime()->format('U') : null, 'date' => $activity->getDate()->format('Y-m-d'), 'attendee' => $activity->getAttendee() )); $em->remove($activity); $em->flush(); $this->addFlash('success', $this->get('translator') ->trans("The activity has been successfully removed.")); $params = $this->buildParamsToUrl($person, $accompanyingPeriod); return $this->redirectToRoute('chill_activity_activity_list', $params); } } if ($view === null) { throw $this->createNotFoundException('Template not found'); } return $this->render($view, array( 'activity' => $activity, 'delete_form' => $form->createView(), 'person' => $person, 'accompanyingCourse' => $accompanyingPeriod, )); } /** * Creates a form to delete a Activity entity by id. */ private function createDeleteForm(int $id, ?Person $person, ?AccompanyingPeriod $accompanyingPeriod): Form { $params = $this->buildParamsToUrl($person, $accompanyingPeriod); $params['id'] = $id; return $this->createFormBuilder() ->setAction($this->generateUrl('chill_activity_activity_delete', $params)) ->setMethod('DELETE') ->add('submit', SubmitType::class, array('label' => 'Delete')) ->getForm() ; } private function getEntity(Request $request): array { $em = $this->getDoctrine()->getManager(); $person = $accompanyingPeriod = null; if ($request->query->has('person_id')) { $person_id = $request->get('person_id'); $person = $em->getRepository(Person::class)->find($person_id); if ($person === null) { throw $this->createNotFoundException('Person not found'); } $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); } elseif ($request->query->has('accompanying_period_id')) { $accompanying_period_id = $request->get('accompanying_period_id'); $accompanyingPeriod = $em->getRepository(AccompanyingPeriod::class)->find($accompanying_period_id); if ($accompanyingPeriod === null) { throw $this->createNotFoundException('Accompanying Period not found'); } // TODO Add permission // $this->denyAccessUnlessGranted('CHILL_PERSON_SEE', $person); } else { throw $this->createNotFoundException("Person or Accompanying Period not found"); } return [ $person, $accompanyingPeriod ]; } private function buildParamsToUrl( ?Person $person, ?AccompanyingPeriod $accompanyingPeriod ): array { $params = []; if ($person) { $params['person_id'] = $person->getId(); } if ($accompanyingPeriod) { $params['accompanying_period_id'] = $accompanyingPeriod->getId(); } return $params; } }