1 <?php 
declare(strict_types
=1); 
   4  * This file is part of the Rapsys AirBundle package. 
   6  * (c) Raphaël Gertz <symfony@rapsys.eu> 
   8  * For the full copyright and license information, please view the LICENSE 
   9  * file that was distributed with this source code. 
  12 namespace Rapsys\AirBundle\Controller
; 
  14 use Symfony\Bridge\Twig\Mime\TemplatedEmail
; 
  15 use Symfony\Component\Form\FormError
; 
  16 use Symfony\Component\HttpFoundation\Request
; 
  17 use Symfony\Component\HttpFoundation\Response
; 
  18 use Symfony\Component\Mailer\Exception\TransportExceptionInterface
; 
  19 use Symfony\Component\Mailer\MailerInterface
; 
  20 use Symfony\Component\Mime\Address
; 
  22 use Rapsys\AirBundle\Entity\Location
; 
  23 use Rapsys\AirBundle\Entity\Session
; 
  24 use Rapsys\AirBundle\Pdf\DisputePdf
; 
  29 class DefaultController 
extends AbstractController 
{ 
  33          * @desc Display the about informations 
  35          * @param Request $request The request instance 
  36          * @return Response The rendered view 
  38         public function about(Request 
$request): Response 
{ 
  40                 $this->context
['title'] = $this->translator
->trans('About'); 
  43                 $this->context
['description'] = $this->translator
->trans('Libre Air about'); 
  46                 $this->context
['keywords'] = [ 
  47                         $this->translator
->trans('about'), 
  48                         $this->translator
->trans('Libre Air') 
  52                 $response = $this->render('@RapsysAir/default/about.html.twig', $this->context
); 
  53                 $response->setEtag(md5($response->getContent())); 
  54                 $response->setPublic(); 
  55                 $response->isNotModified($request); 
  64          * @desc Send a contact mail to configured contact 
  66          * @param Request $request The request instance 
  67          * @param MailerInterface $mailer The mailer instance 
  69          * @return Response The rendered view or redirection 
  71         public function contact(Request 
$request, MailerInterface 
$mailer): Response 
{ 
  73                 $this->context
['title'] = $this->translator
->trans('Contact'); 
  76                 $this->context
['description'] = $this->translator
->trans('Contact Libre Air'); 
  79                 $this->context
['keywords'] = [ 
  80                         $this->translator
->trans('contact'), 
  81                         $this->translator
->trans('Libre Air'), 
  82                         $this->translator
->trans('outdoor'), 
  83                         $this->translator
->trans('Argentine Tango'), 
  84                         $this->translator
->trans('calendar') 
  87                 //Create the form according to the FormType created previously. 
  88                 //And give the proper parameters 
  89                 $form = $this->createForm('Rapsys\AirBundle\Form\ContactType', null, [ 
  90                         'action' => $this->generateUrl('rapsys_air_contact'), 
  94                 if ($request->isMethod('POST')) { 
  95                         // Refill the fields in case the form is not valid. 
  96                         $form->handleRequest($request); 
  98                         if ($form->isValid()) { 
 100                                 $data = $form->getData(); 
 103                                 $message = (new TemplatedEmail()) 
 105                                         ->from(new Address($data['mail'], $data['name'])) 
 107                                         ->to(new Address($this->context
['contact']['mail'], $this->context
['contact']['title'])) 
 109                                         ->subject($data['subject']) 
 111                                         //Set path to twig templates 
 112                                         ->htmlTemplate('@RapsysAir/mail/contact.html.twig') 
 113                                         ->textTemplate('@RapsysAir/mail/contact.text.twig') 
 118                                                         'subject' => $data['subject'], 
 119                                                         'message' => strip_tags($data['message']), 
 123                                 //Try sending message 
 124                                 //XXX: mail delivery may silently fail 
 127                                         $mailer->send($message); 
 129                                         //Redirect on the same route with sent=1 to cleanup form 
 130                                         return $this->redirectToRoute($request->get('_route'), ['sent' => 1]+
$request->get('_route_params')); 
 131                                 //Catch obvious transport exception 
 132                                 } catch(TransportExceptionInterface 
$e) { 
 133                                         if ($message = $e->getMessage()) { 
 134                                                 //Add error message mail unreachable 
 135                                                 $form->get('mail')->addError(new FormError($this->translator
->trans('Unable to contact: %mail%: %message%', ['%mail%' => $this->context
['contact']['mail'], '%message%' => $this->translator
->trans($message)]))); 
 137                                                 //Add error message mail unreachable 
 138                                                 $form->get('mail')->addError(new FormError($this->translator
->trans('Unable to contact: %mail%', ['%mail%' => $this->context
['contact']['mail']]))); 
 145                 return $this->render('@RapsysAir/form/contact.html.twig', ['form' => $form->createView(), 'sent' => $request->query
->get('sent', 0)]+
$this->context
); 
 151          * @desc Generate a dispute document 
 153          * @param Request $request The request instance 
 154          * @param MailerInterface $mailer The mailer instance 
 156          * @return Response The rendered view or redirection 
 158         public function dispute(Request 
$request, MailerInterface 
$mailer): Response 
{ 
 159                 //Prevent non-guest to access here 
 160                 $this->denyAccessUnlessGranted('ROLE_USER', null, $this->translator
->trans('Unable to access this page without role %role%!', ['%role%' => $this->translator
->trans('User')])); 
 163                 $this->context
['title'] = $this->translator
->trans('Dispute'); 
 166                 $this->context
['description'] = $this->translator
->trans('Libre Air dispute'); 
 169                 $this->context
['keywords'] = [ 
 170                         $this->translator
->trans('dispute'), 
 171                         $this->translator
->trans('Libre Air'), 
 172                         $this->translator
->trans('outdoor'), 
 173                         $this->translator
->trans('Argentine Tango'), 
 174                         $this->translator
->trans('calendar') 
 177                 //Create the form according to the FormType created previously. 
 178                 //And give the proper parameters 
 179                 $form = $this->createForm('Rapsys\AirBundle\Form\DisputeType', ['court' => 'Paris', 'abstract' => 'Pour constater cette prétendue infraction, les agents verbalisateurs ont pénétré dans un jardin privatif, sans visibilité depuis la voie publique, situé derrière un batiment privé, pour ce faire ils ont franchi au moins un grillage de chantier ou des potteaux métalliques séparant le terrain privé de la voie publique de l\'autre côté du batiment.'], [ 
 180                         'action' => $this->generateUrl('rapsys_air_dispute'), 
 184                 if ($request->isMethod('POST')) { 
 185                         // Refill the fields in case the form is not valid. 
 186                         $form->handleRequest($request); 
 188                         if ($form->isValid()) { 
 190                                 $data = $form->getData(); 
 193                                 if (!empty($data['offense']) && $data['offense'] == 'gathering') { 
 195                                         $output = DisputePdf
::genGathering($data['court'], $data['notice'], $data['agent'], $data['service'], $data['abstract'], $this->translator
->trans($this->getUser()->getCivility()->getTitle()), $this->getUser()->getForename(), $this->getUser()->getSurname()); 
 197                                 } elseif (!empty($data['offense'] && $data['offense'] == 'traffic')) { 
 199                                         $output = DisputePdf
::genTraffic($data['court'], $data['notice'], $data['agent'], $data['service'], $data['abstract'], $this->translator
->trans($this->getUser()->getCivility()->getTitle()), $this->getUser()->getForename(), $this->getUser()->getSurname()); 
 200                                 //Unsupported offense 
 202                                         header('Content-Type: text/plain'); 
 207                                 //Send common headers 
 208                                 header('Content-Type: application/pdf'); 
 210                                 //Send remaining headers 
 211                                 header('Cache-Control: private, max-age=0, must-revalidate'); 
 212                                 header('Pragma: public'); 
 214                                 //Send content-length 
 215                                 header('Content-Length: '.strlen($output)); 
 224 #                               $message = (new TemplatedEmail()) 
 226 #                                       ->from(new Address($data['mail'], $data['name'])) 
 228 #                                       //XXX: remove the debug set in vendor/symfony/mime/Address.php +46 
 229 #                                       ->to(new Address($this->config['contact']['mail'], $this->config['contact']['title'])) 
 231 #                                       ->subject($data['subject']) 
 233 #                                       //Set path to twig templates 
 234 #                                       ->htmlTemplate('@RapsysAir/mail/contact.html.twig') 
 235 #                                       ->textTemplate('@RapsysAir/mail/contact.text.twig') 
 240 #                                                       'subject' => $data['subject'], 
 241 #                                                       'message' => strip_tags($data['message']), 
 245 #                               //Try sending message 
 246 #                               //XXX: mail delivery may silently fail 
 249 #                                       $mailer->send($message); 
 251 #                                       //Redirect on the same route with sent=1 to cleanup form 
 252 #                                       return $this->redirectToRoute($request->get('_route'), ['sent' => 1]+$request->get('_route_params')); 
 253 #                               //Catch obvious transport exception 
 254 #                               } catch(TransportExceptionInterface $e) { 
 255 #                                       if ($message = $e->getMessage()) { 
 256 #                                               //Add error message mail unreachable 
 257 #                                               $form->get('mail')->addError(new FormError($this->translator->trans('Unable to contact: %mail%: %message%', ['%mail%' => $this->config['contact']['mail'], '%message%' => $this->translator->trans($message)]))); 
 259 #                                               //Add error message mail unreachable 
 260 #                                               $form->get('mail')->addError(new FormError($this->translator->trans('Unable to contact: %mail%', ['%mail%' => $this->config['contact']['mail']]))); 
 267                 return $this->render('@RapsysAir/default/dispute.html.twig', ['form' => $form->createView(), 'sent' => $request->query
->get('sent', 0)]+
$this->context
); 
 273          * @desc Display all granted sessions with an application or login form 
 275          * @param Request $request The request instance 
 276          * @return Response The rendered view 
 278         public function index(Request 
$request): Response 
{ 
 280                 $doctrine = $this->getDoctrine(); 
 283                 $this->context
['title'] = $this->translator
->trans('Argentine Tango in Paris'); 
 286                 $this->context
['description'] = $this->translator
->trans('Outdoor Argentine Tango session calendar in Paris'); 
 289                 $this->context
['keywords'] = [ 
 290                         $this->translator
->trans('Argentine Tango'), 
 291                         $this->translator
->trans('Paris'), 
 292                         $this->translator
->trans('outdoor'), 
 293                         $this->translator
->trans('calendar'), 
 294                         $this->translator
->trans('Libre Air') 
 298                 //XXX: only valid for home page 
 299                 $this->context
['facebook']['metas']['og:type'] = 'website'; 
 302                 $period = new \
DatePeriod( 
 303                         //Start from first monday of week 
 304                         new \
DateTime('Monday this week'), 
 305                         //Iterate on each day 
 306                         new \
DateInterval('P1D'), 
 307                         //End with next sunday and 4 weeks 
 309                                 $this->isGranted('IS_AUTHENTICATED_REMEMBERED')?'Monday this week + 3 week':'Monday this week + 2 week' 
 314                 $calendar = $doctrine->getRepository(Session
::class)->fetchCalendarByDatePeriod($this->translator
, $period, null, $request->get('session'), !$this->isGranted('IS_AUTHENTICATED_REMEMBERED'), $request->getLocale()); 
 317                 //XXX: we want to display all active locations anyway 
 318                 $locations = $doctrine->getRepository(Location
::class)->findTranslatedSortedByPeriod($this->translator
, $period); 
 321                 return $this->render('@RapsysAir/default/index.html.twig', ['calendar' => $calendar, 'locations' => $locations]+
$this->context
); 
 323                 //Set Cache-Control must-revalidate directive 
 324                 //TODO: add a javascript forced refresh after 1h ? or header refresh ? 
 325                 #$response->setPublic(true); 
 326                 #$response->setMaxAge(300); 
 327                 #$response->mustRevalidate(); 
 328                 ##$response->setCache(['public' => true, 'max_age' => 300]); 
 330                 //Return the response 
 335          * The organizer regulation page 
 337          * @desc Display the organizer regulation policy 
 339          * @param Request $request The request instance 
 340          * @return Response The rendered view 
 342         public function organizerRegulation(Request 
$request): Response 
{ 
 344                 $this->context
['title'] = $this->translator
->trans('Organizer regulation'); 
 347                 $this->context
['description'] = $this->translator
->trans('Libre Air organizer regulation'); 
 350                 $this->context
['keywords'] = [ 
 351                         $this->translator
->trans('organizer regulation'), 
 352                         $this->translator
->trans('Libre Air') 
 356                 $response = $this->render('@RapsysAir/default/organizer_regulation.html.twig', $this->context
); 
 359                 $response->setEtag(md5($response->getContent())); 
 360                 $response->setPublic(); 
 361                 $response->isNotModified($request); 
 368          * The terms of service page 
 370          * @desc Display the terms of service policy 
 372          * @param Request $request The request instance 
 373          * @return Response The rendered view 
 375         public function termsOfService(Request 
$request): Response 
{ 
 377                 $this->context
['title'] = $this->translator
->trans('Terms of service'); 
 380                 $this->context
['description'] = $this->translator
->trans('Libre Air terms of service'); 
 383                 $this->context
['keywords'] = [ 
 384                         $this->translator
->trans('terms of service'), 
 385                         $this->translator
->trans('Libre Air') 
 389                 $response = $this->render('@RapsysAir/default/terms_of_service.html.twig', $this->context
); 
 392                 $response->setEtag(md5($response->getContent())); 
 393                 $response->setPublic(); 
 394                 $response->isNotModified($request); 
 401          * The frequently asked questions page 
 403          * @desc Display the frequently asked questions 
 405          * @param Request $request The request instance 
 406          * @return Response The rendered view 
 408         public function frequentlyAskedQuestions(Request 
$request): Response 
{ 
 410                 $this->context
['title'] = $this->translator
->trans('Frequently asked questions'); 
 413                 $this->context
['description'] = $this->translator
->trans('Libre Air frequently asked questions'); 
 416                 $this->context
['keywords'] = [ 
 417                         $this->translator
->trans('frequently asked questions'), 
 418                         $this->translator
->trans('faq'), 
 419                         $this->translator
->trans('Libre Air') 
 423                 $response = $this->render('@RapsysAir/default/frequently_asked_questions.html.twig', $this->context
); 
 426                 $response->setEtag(md5($response->getContent())); 
 427                 $response->setPublic(); 
 428                 $response->isNotModified($request); 
 437          * @desc Display all user with a group listed as users 
 439          * @param Request $request The request instance 
 441          * @return Response The rendered view 
 443         public function userIndex(Request 
$request): Response 
{ 
 445                 $doctrine = $this->getDoctrine(); 
 448                 if ($this->isGranted('ROLE_ADMIN')) { 
 450                         $section = $this->translator
->trans('Libre Air users'); 
 453                         $this->context
['description'] = $this->translator
->trans('Libre Air user list'); 
 457                         $section = $this->translator
->trans('Libre Air organizers'); 
 460                         $this->context
['description'] = $this->translator
->trans('Libre Air organizers list'); 
 464                 $this->context
['keywords'] = [ 
 465                         $this->translator
->trans('users'), 
 466                         $this->translator
->trans('user list'), 
 467                         $this->translator
->trans('listing'), 
 468                         $this->translator
->trans('Libre Air') 
 472                 $title = $this->translator
->trans($this->config
['site']['title']).' - '.$section; 
 475                 $users = $doctrine->getRepository(User
::class)->findUserGroupedByTranslatedGroup($this->translator
); 
 478                 $period = new \
DatePeriod( 
 479                         //Start from first monday of week 
 480                         new \
DateTime('Monday this week'), 
 481                         //Iterate on each day 
 482                         new \
DateInterval('P1D'), 
 483                         //End with next sunday and 4 weeks 
 485                                 $this->isGranted('IS_AUTHENTICATED_REMEMBERED')?'Monday this week + 3 week':'Monday this week + 2 week' 
 490                 if ($this->isGranted('ROLE_ADMIN')) { 
 492                         $this->context
['groups'] = $users; 
 495                         //Only display senior organizers 
 496                         $this->context
['users'] = $users[$this->translator
->trans('Senior')]; 
 500                 //XXX: we want to display all active locations anyway 
 501                 $locations = $doctrine->getRepository(Location
::class)->findTranslatedSortedByPeriod($this->translator
, $period); 
 504                 return $this->render('@RapsysAir/user/index.html.twig', ['title' => $title, 'section' => $section, 'locations' => $locations]+
$this->context
); 
 508          * List all sessions for the user 
 510          * @desc Display all sessions for the user with an application or login form 
 512          * @param Request $request The request instance 
 513          * @param int $id The user id 
 515          * @return Response The rendered view 
 517         public function userView(Request 
$request, $id): Response 
{ 
 519                 $doctrine = $this->getDoctrine(); 
 522                 if (empty($user = $doctrine->getRepository(User
::class)->findOneById($id))) { 
 523                         throw $this->createNotFoundException($this->translator
->trans('Unable to find user: %id%', ['%id%' => $id])); 
 527                 $token = new UsernamePasswordToken($user, null, 'none', $user->getRoles()); 
 530                 $isGuest = $this->get('rapsys_user.access_decision_manager')->decide($token, ['ROLE_GUEST']); 
 532                 //Prevent access when not admin, user is not guest and not currently logged user 
 533                 if (!$this->isGranted('ROLE_ADMIN') && empty($isGuest) && $user != $this->getUser()) { 
 534                         throw $this->createAccessDeniedException($this->translator
->trans('Unable to access user: %id%', ['%id%' => $id])); 
 538                 $section = $user->getPseudonym(); 
 541                 $title = $this->translator
->trans($this->config
['site']['title']).' - '.$section; 
 544                 $this->context
['description'] = $this->translator
->trans('%pseudonym% outdoor Argentine Tango session calendar', [ '%pseudonym%' => $user->getPseudonym() ]); 
 547                 $this->context
['keywords'] = [ 
 548                         $user->getPseudonym(), 
 549                         $this->translator
->trans('outdoor'), 
 550                         $this->translator
->trans('Argentine Tango'), 
 551                         $this->translator
->trans('calendar') 
 555                 $period = new \
DatePeriod( 
 556                         //Start from first monday of week 
 557                         new \
DateTime('Monday this week'), 
 558                         //Iterate on each day 
 559                         new \
DateInterval('P1D'), 
 560                         //End with next sunday and 4 weeks 
 562                                 $this->isGranted('IS_AUTHENTICATED_REMEMBERED')?'Monday this week + 3 week':'Monday this week + 2 week' 
 567                 //TODO: highlight with current session route parameter 
 568                 $calendar = $doctrine->getRepository(Session
::class)->fetchUserCalendarByDatePeriod($this->translator
, $period, $isGuest?$id:null, $request->get('session'), $request->getLocale()); 
 571                 //XXX: we want to display all active locations anyway 
 572                 $locations = $doctrine->getRepository(Location
::class)->findTranslatedSortedByPeriod($this->translator
, $period, $id); 
 574                 //Create user form for admin or current user 
 575                 if ($this->isGranted('ROLE_ADMIN') || $user == $this->getUser()) { 
 576                         //Create SnippetType form 
 577                         $userForm = $this->createForm('Rapsys\AirBundle\Form\RegisterType', $user, [ 
 579                                 'action' => $this->generateUrl('rapsys_air_user_view', ['id' => $id]), 
 580                                 //Set the form attribute 
 581                                 'attr' => [ 'class' => 'col' ], 
 583                                 'civility_class' => Civility
::class, 
 585                                 'mail' => $this->isGranted('ROLE_ADMIN'), 
 590                         //Init user to context 
 591                         $this->context
['forms']['user'] = $userForm->createView(); 
 594                         if ($request->isMethod('POST')) { 
 595                                 //Refill the fields in case the form is not valid. 
 596                                 $userForm->handleRequest($request); 
 598                                 //Handle invalid form 
 599                                 if (!$userForm->isSubmitted() || !$userForm->isValid()) { 
 601                                         return $this->render('@RapsysAir/user/view.html.twig', ['id' => $id, 'title' => $title, 'section' => $section, 'calendar' => $calendar, 'locations' => $locations]+
$this->context
); 
 605                                 $data = $userForm->getData(); 
 608                                 $manager = $doctrine->getManager(); 
 611                                 $manager->persist($data); 
 613                                 //Flush to get the ids 
 617                                 $this->addFlash('notice', $this->translator
->trans('User %id% updated', ['%id%' => $id])); 
 619                                 //Extract and process referer 
 620                                 if ($referer = $request->headers
->get('referer')) { 
 621                                         //Create referer request instance 
 622                                         $req = Request
::create($referer); 
 625                                         $path = $req->getPathInfo(); 
 627                                         //Get referer query string 
 628                                         $query = $req->getQueryString(); 
 631                                         $path = str_replace($request->getScriptName(), '', $path); 
 633                                         //Try with referer path 
 636                                                 $oldContext = $this->router
->getContext(); 
 638                                                 //Force clean context 
 639                                                 //XXX: prevent MethodNotAllowedException because current context method is POST in onevendor/symfony/routing/Matcher/Dumper/CompiledUrlMatcherTrait.php+42 
 640                                                 $this->router
->setContext(new RequestContext()); 
 642                                                 //Retrieve route matching path 
 643                                                 $route = $this->router
->match($path); 
 646                                                 $this->router
->setContext($oldContext); 
 652                                                 $name = $route['_route']; 
 654                                                 //Remove route and controller from route defaults 
 655                                                 unset($route['_route'], $route['_controller']); 
 657                                                 //Check if user view route 
 658                                                 if ($name == 'rapsys_air_user_view' && !empty($route['id'])) { 
 660                                                         $route['id'] = $data->getId(); 
 664                                                         $route['user'] = $data->getId(); 
 668                                                 return $this->redirectToRoute($name, $route); 
 670                                         } catch(MethodNotAllowedException
|ResourceNotFoundException 
$e) { 
 671                                                 //Unset referer to fallback to default route 
 676                                 //Redirect to cleanup the form 
 677                                 return $this->redirectToRoute('rapsys_air', ['user' => $data->getId()]); 
 681                 //Create snippet forms for role_guest 
 682                 if ($this->isGranted('ROLE_ADMIN') || ($this->isGranted('ROLE_GUEST') && $user == $this->getUser())) { 
 683                         //Fetch all user snippet 
 684                         $snippets = $doctrine->getRepository(Snippet
::class)->findByLocaleUserId($request->getLocale(), $id); 
 686                         //Rekey by location id 
 687                         $snippets = array_reduce($snippets, function($carry, $item){$carry
[$item
->getLocation()->getId()] = $item
; return $carry
;}, []); 
 689                         //Init snippets to context 
 690                         $this->context
['forms']['snippets'] = []; 
 692                         //Iterate on locations 
 693                         foreach($locations as $locationId => $location) { 
 695                                 $snippet = new Snippet(); 
 698                                 $snippet->setLocale($request->getLocale()); 
 701                                 $snippet->setUser($user); 
 703                                 //Set default location 
 704                                 $snippet->setLocation($doctrine->getRepository(Location
::class)->findOneById($locationId)); 
 706                                 //With existing snippet 
 707                                 if (!empty($snippets[$locationId])) { 
 708                                         $snippet = $snippets[$locationId]; 
 709                                         $action = $this->generateUrl('rapsys_air_snippet_edit', ['id' => $snippet->getId()]); 
 712                                         $action = $this->generateUrl('rapsys_air_snippet_add', ['location' => $locationId]); 
 715                                 //Create SnippetType form 
 716                                 $form = $this->container
->get('form.factory')->createNamed('snipped_'.$request->getLocale().'_'.$locationId, 'Rapsys\AirBundle\Form\SnippetType', $snippet, [ 
 719                                         //Set the form attribute 
 723                                 //Add form to context 
 724                                 $this->context
['forms']['snippets'][$locationId] = $form->createView(); 
 729                 return $this->render('@RapsysAir/user/view.html.twig', ['id' => $id, 'title' => $title, 'section' => $section, 'calendar' => $calendar, 'locations' => $locations]+
$this->context
);