3 namespace Rapsys\AirBundle\Controller
;
5 use Symfony\Component\HttpFoundation\Request
;
6 use Symfony\Component\HttpFoundation\Response
;
7 use Symfony\Component\Routing\RequestContext
;
8 use Symfony\Component\Routing\Exception\MethodNotAllowedException
;
9 use Symfony\Component\Routing\Exception\ResourceNotFoundException
;
10 use Rapsys\AirBundle\Entity\Application
;
11 use Rapsys\AirBundle\Entity\User
;
12 use Rapsys\AirBundle\Entity\Slot
;
13 use Rapsys\AirBundle\Entity\Session
;
14 use Rapsys\AirBundle\Entity\Location
;
16 class SessionController
extends DefaultController
{
20 * @desc Persist session and all required dependencies in database
22 * @param Request $request The request instance
24 * @return Response The rendered view or redirection
26 * @throws \RuntimeException When user has not at least guest role
28 public function edit(Request
$request, $id): Response
{
29 //Prevent non-guest to access here
30 $this->denyAccessUnlessGranted('ROLE_GUEST', null, $this->translator
->trans('Unable to access this page without role %role%!', ['%role%' => $this->translator
->trans('Guest')]));
32 //Reject non post requests
33 if (!$request->isMethod('POST')) {
34 throw new \
RuntimeException('Request method MUST be POST');
38 $doctrine = $this->getDoctrine();
41 $session = $doctrine->getRepository(Session
::class)->fetchOneById($id, $request->getLocale());
46 !$this->isGranted('ROLE_ADMIN') &&
48 $this->getUser()->getId() != $session['au_id'] &&
49 //or application without attributed user
50 $session['au_id'] !== null && !in_array($this->getUser()->getId(), explode("\n", $session['sau_id']))
52 //Prevent non admin and non attributed user access
53 throw $this->createAccessDeniedException();
57 $now = new \
DateTime('now');
59 //Create SessionType form
60 $form = $this->createForm('Rapsys\AirBundle\Form\SessionType', null, [
62 'action' => $this->generateUrl('rapsys_air_session_edit', [ 'id' => $id ]),
63 //Set the form attribute
66 'admin' => $this->isGranted('ROLE_ADMIN'),
67 //Set default user to current
68 'user' => $this->getUser()->getId(),
70 'begin' => $session['begin'],
72 'length' => $session['length'],
74 'raincancel' => ($this->isGranted('ROLE_ADMIN') || $this->getUser()->getId() == $session['au_id']) && $session['rainfall'] >= 2,
76 'cancel' => $this->isGranted('ROLE_ADMIN') || in_array($this->getUser()->getId(), explode("\n", $session['sau_id'])),
78 'modify' => $this->isGranted('ROLE_ADMIN') || $this->getUser()->getId() == $session['au_id'] && $session['stop'] >= $now && $this->isGranted('ROLE_REGULAR'),
80 'move' => $this->isGranted('ROLE_ADMIN') || $this->getUser()->getId() == $session['au_id'] && $session['stop'] >= $now && $this->isGranted('ROLE_SENIOR'),
82 'attribute' => $this->isGranted('ROLE_ADMIN') && $session['locked'] === null,
84 'session' => $session['id']
87 //Refill the fields in case of invalid form
88 $form->handleRequest($request);
91 #if (true) { $form->isValid();
92 //TODO: mettre une contrainte sur un des boutons submit, je sais pas encore comment
93 if (!$form->isValid()) {
95 $section = $this->translator
->trans('Session %id%', ['%id%' => $id]);
98 $title = $section.' - '.$this->translator
->trans($this->config
['site']['title']);
100 //Add session in context
101 $context['session'] = [
103 'title' => $this->translator
->trans('Session %id%', ['%id%' => $id]),
105 'id' => $session['l_id'],
106 'at' => $this->translator
->trans('at '.$session['l_title'])
110 return $this->render('@RapsysAir/session/edit.html.twig', ['title' => $title, 'section' => $section, 'form' => $form->createView()]+
$context+
$this->context
);
114 $manager = $doctrine->getManager();
117 $data = $form->getData();
120 $session = $doctrine->getRepository(Session
::class)->findOneById($id);
123 $user = $this->getUser();
125 //Replace with requested user for admin
126 if ($this->isGranted('ROLE_ADMIN') && !empty($data['user'])) {
127 $user = $doctrine->getRepository(User
::class)->findOneById($data['user']);
131 $datetime = new \
DateTime('now');
133 //Set canceled time at start minus one day
134 $canceled = (clone $session->getStart())->sub(new \
DateInterval('P1D'));
138 'raincancel' => $form->has('raincancel') && $form->get('raincancel')->isClicked(),
139 'modify' => $form->has('modify') && $form->get('modify')->isClicked(),
140 'move' => $form->has('move') && $form->get('move')->isClicked(),
141 'cancel' => $form->has('cancel') && $form->get('cancel')->isClicked(),
142 'forcecancel' => $form->has('forcecancel') && $form->get('forcecancel')->isClicked(),
143 'attribute' => $form->has('attribute') && $form->get('attribute')->isClicked(),
144 'autoattribute' => $form->has('autoattribute') && $form->get('autoattribute')->isClicked(),
145 'lock' => $form->has('lock') && $form->get('lock')->isClicked(),
148 //With raincancel and application and (rainfall or admin)
149 if ($action['raincancel'] && ($application = $session->getApplication()) && ($session->getRainfall() >= 2 || $this->isGranted('ROLE_ADMIN'))) {
150 //Cancel application at start minus one day
151 $application->setCanceled($canceled);
154 $application->setUpdated($datetime);
156 //Insufficient rainfall
158 if ($session->getRainfall() < 2) {
160 //XXX: magic cheat score 42
161 $application->setScore(42);
164 //Queue application save
165 $manager->persist($application);
167 //Add notice in flash message
168 $this->addFlash('notice', $this->translator
->trans('Application %id% updated', ['%id%' => $application->getId()]));
171 $session->setUpdated($datetime);
174 $manager->persist($session);
176 //Add notice in flash message
177 $this->addFlash('notice', $this->translator
->trans('Session %id% updated', ['%id%' => $id]));
179 } elseif ($action['modify']) {
181 $session->setBegin($data['begin']);
184 $session->setLength($data['length']);
187 $session->setUpdated($datetime);
190 $manager->persist($session);
192 //Add notice in flash message
193 $this->addFlash('notice', $this->translator
->trans('Session %id% updated', ['%id%' => $id]));
195 } elseif ($action['move']) {
197 $session->setLocation($doctrine->getRepository(Location
::class)->findOneById($data['location']));
200 $session->setUpdated($datetime);
203 $manager->persist($session);
205 //Add notice in flash message
206 $this->addFlash('notice', $this->translator
->trans('Session %id% updated', ['%id%' => $id]));
207 //With cancel or forcecancel
208 } elseif ($action['cancel'] || $action['forcecancel']) {
210 $application = $doctrine->getRepository(Application
::class)->findOneBySessionUser($session, $user);
212 //Not already canceled
213 if ($application->getCanceled() === null) {
215 $application->setCanceled($datetime);
217 //Check if application is session application and (canceled 24h before start or forcecancel (as admin))
218 #if ($session->getApplication() == $application && ($datetime < $canceled || $action['forcecancel'])) {
219 if ($session->getApplication() == $application && $action['forcecancel']) {
221 //XXX: magic cheat score 42
222 $application->setScore(42);
224 //Unattribute session
225 $session->setApplication(null);
228 $session->setUpdated($datetime);
231 $manager->persist($session);
233 //Add notice in flash message
234 $this->addFlash('notice', $this->translator
->trans('Session %id% updated', ['%id%' => $id]));
238 //Uncancel application
239 $application->setCanceled(null);
243 $application->setUpdated($datetime);
245 //Queue application save
246 $manager->persist($application);
248 //Add notice in flash message
249 $this->addFlash('notice', $this->translator
->trans('Application %id% updated', ['%id%' => $application->getId()]));
251 } elseif ($action['attribute']) {
253 $application = $doctrine->getRepository(Application
::class)->findOneBySessionUser($session, $user);
256 if ($application->getCanceled() !== null) {
257 //Uncancel application
258 $application->setCanceled(null);
262 //XXX: magic cheat score 42
263 $application->setScore(42);
266 $application->setUpdated($datetime);
268 //Queue application save
269 $manager->persist($application);
271 //Add notice in flash message
272 $this->addFlash('notice', $this->translator
->trans('Application %id% updated', ['%id%' => $application->getId()]));
274 //Unattribute session
275 $session->setApplication($application);
278 $session->setUpdated($datetime);
281 $manager->persist($session);
283 //Add notice in flash message
284 $this->addFlash('notice', $this->translator
->trans('Session %id% updated', ['%id%' => $id]));
286 } elseif ($action['autoattribute']) {
287 //Get best application
288 //XXX: best application may not issue result while grace time or bad behaviour
289 if (!empty($application = $doctrine->getRepository(Session
::class)->findBestApplicationById($id))) {
291 $session->setApplication($application);
294 $session->setUpdated($datetime);
297 $manager->persist($session);
299 //Add notice in flash message
300 $this->addFlash('notice', $this->translator
->trans('Session %id% auto attributed', ['%id%' => $id]));
303 //Add warning in flash message
304 $this->addFlash('warning', $this->translator
->trans('Session %id% not auto attributed', ['%id%' => $id]));
307 } elseif ($action['lock']) {
309 if ($session->getLocked() !== null) {
314 $session->setLocked(null);
318 if ($application = $session->getApplication()) {
320 //XXX: magic cheat score 42
321 $application->setScore(42);
324 $application->setUpdated($datetime);
326 //Queue application save
327 $manager->persist($application);
329 //Add notice in flash message
330 $this->addFlash('notice', $this->translator
->trans('Application %id% updated', ['%id%' => $application->getId()]));
333 //Unattribute session
334 $session->setApplication(null);
337 $session->setLocked($datetime);
341 # $applications = $doctrine->getRepository(Application::class)->findBySession($session);
344 # if (!empty($applications)) {
345 # //Iterate on each applications
346 # foreach($applications as $application) {
347 # //Cancel application
348 # $application->setCanceled($canceled);
351 # $application->setUpdated($datetime);
353 # //Queue application save
354 # $manager->persist($application);
356 # //Add notice in flash message
357 # $this->addFlash('notice', $this->translator->trans('Application %id% updated', ['%id%' => $application->getId()]));
362 $session->setUpdated($datetime);
365 $manager->persist($session);
367 //Add notice in flash message
368 $this->addFlash('notice', $this->translator
->trans('Session %id% updated', ['%id%' => $id]));
371 //Add warning in flash message
372 $this->addFlash('warning', $this->translator
->trans('Session %id% not updated', ['%id%' => $id]));
375 //Flush to get the ids
378 //Extract and process referer
379 if ($referer = $request->headers
->get('referer')) {
380 //Create referer request instance
381 $req = Request
::create($referer);
384 $path = $req->getPathInfo();
386 //Get referer query string
387 $query = $req->getQueryString();
390 $path = str_replace($request->getScriptName(), '', $path);
392 //Try with referer path
395 $oldContext = $this->router
->getContext();
397 //Force clean context
398 //XXX: prevent MethodNotAllowedException because current context method is POST in onevendor/symfony/routing/Matcher/Dumper/CompiledUrlMatcherTrait.php+42
399 $this->router
->setContext(new RequestContext());
401 //Retrieve route matching path
402 $route = $this->router
->match($path);
405 $this->router
->setContext($oldContext);
411 $name = $route['_route'];
413 //Remove route and controller from route defaults
414 unset($route['_route'], $route['_controller']);
417 return $this->redirectToRoute($name, $route);
419 } catch(MethodNotAllowedException
|ResourceNotFoundException
$e) {
420 //Unset referer to fallback to default route
425 //Redirect to cleanup the form
426 return $this->redirectToRoute('rapsys_air_session_view', ['id' => $id]);
432 * @desc Display all sessions with an application or login form
434 * @param Request $request The request instance
436 * @return Response The rendered view
438 public function index(Request
$request): Response
{
440 $doctrine = $this->getDoctrine();
443 $section = $this->translator
->trans('Sessions');
446 $this->context
['description'] = $this->translator
->trans('Libre Air session list');
449 $this->context
['keywords'] = [
450 $this->translator
->trans('sessions'),
451 $this->translator
->trans('session list'),
452 $this->translator
->trans('listing'),
453 $this->translator
->trans('Libre Air')
457 $title = $this->translator
->trans($this->config
['site']['title']).' - '.$section;
460 $period = new \
DatePeriod(
461 //Start from first monday of week
462 new \
DateTime('Monday this week'),
463 //Iterate on each day
464 new \
DateInterval('P1D'),
465 //End with next sunday and 4 weeks
467 $this->isGranted('IS_AUTHENTICATED_REMEMBERED')?'Monday this week + 4 week':'Monday this week + 2 week'
472 //TODO: highlight with current session route parameter
473 $calendar = $doctrine->getRepository(Session
::class)->fetchCalendarByDatePeriod($this->translator
, $period, null, $request->get('session'), !$this->isGranted('IS_AUTHENTICATED_REMEMBERED'));
476 //XXX: we want to display all active locations anyway
477 $locations = $doctrine->getRepository(Location
::class)->findTranslatedSortedByPeriod($this->translator
, $period);
480 return $this->render('@RapsysAir/session/index.html.twig', ['title' => $title, 'section' => $section, 'calendar' => $calendar, 'locations' => $locations]+
$this->context
);
486 * @desc Display session by id with an application or login form
488 * @param Request $request The request instance
489 * @param int $id The session id
491 * @return Response The rendered view
493 public function view(Request
$request, $id): Response
{
495 $doctrine = $this->getDoctrine();
498 if (empty($session = $doctrine->getRepository(Session
::class)->fetchOneById($id, $request->getLocale()))) {
499 throw $this->createNotFoundException($this->translator
->trans('Unable to find session: %id%', ['%id%' => $id]));
503 $section = $this->translator
->trans($session['l_title']);
505 //Set localization date formater
506 $intl = new \
IntlDateFormatter($request->getLocale(), \IntlDateFormatter
::GREGORIAN
, \IntlDateFormatter
::SHORT
);
509 $this->context
['description'] = $this->translator
->trans('Outdoor Argentine Tango session the %date%', [ '%date%' => $intl->format($session['start']) ]);
512 $this->context
['keywords'] = [
513 $this->translator
->trans('outdoor'),
514 $this->translator
->trans('Argentine Tango'),
517 //With granted session
518 if (!empty($session['au_id'])) {
519 $this->context
['keywords'][0] = $session['au_pseudonym'];
522 $title = $this->translator
->trans($this->config
['site']['title']).' - '.$section.' - '.$this->translator
->trans(!empty($session['au_id'])?'Session %id% by %pseudonym%':'Session %id%', ['%id%' => $id, '%pseudonym%' => $session['au_pseudonym']]);
524 //Create application form for role_guest
525 if ($this->isGranted('ROLE_GUEST')) {
526 //Create ApplicationType form
527 $applicationForm = $this->createForm('Rapsys\AirBundle\Form\ApplicationType', null, [
529 'action' => $this->generateUrl('rapsys_air_application_add'),
530 //Set the form attribute
531 'attr' => [ 'class' => 'col' ],
533 'admin' => $this->isGranted('ROLE_ADMIN'),
534 //Set default user to current
535 'user' => $this->getUser()->getId(),
536 //Set default slot to current
537 'slot' => $this->getDoctrine()->getRepository(Slot
::class)->findOneById($session['t_id']),
538 //Set default location to current
539 'location' => $this->getDoctrine()->getRepository(Location
::class)->findOneById($session['l_id']),
542 //Add form to context
543 $this->context
['forms']['application'] = $applicationForm->createView();
546 $now = new \
DateTime('now');
548 //Create SessionType form
549 $sessionForm = $this->createForm('Rapsys\AirBundle\Form\SessionType', null, [
551 'action' => $this->generateUrl('rapsys_air_session_edit', [ 'id' => $id ]),
552 //Set the form attribute
553 'attr' => [ 'class' => 'col' ],
555 'admin' => $this->isGranted('ROLE_ADMIN'),
556 //Set default user to current
557 'user' => $this->getUser()->getId(),
559 'begin' => $session['begin'],
561 'length' => $session['length'],
563 'raincancel' => ($this->isGranted('ROLE_ADMIN') || $this->getUser()->getId() == $session['au_id']) && $session['rainfall'] >= 2,
565 'cancel' => $this->isGranted('ROLE_ADMIN') || in_array($this->getUser()->getId(), explode("\n", $session['sau_id'])),
567 'modify' => $this->isGranted('ROLE_ADMIN') || $this->getUser()->getId() == $session['au_id'] && $session['stop'] >= $now && $this->isGranted('ROLE_REGULAR'),
569 'move' => $this->isGranted('ROLE_ADMIN') || $this->getUser()->getId() == $session['au_id'] && $session['stop'] >= $now && $this->isGranted('ROLE_SENIOR'),
571 'attribute' => $this->isGranted('ROLE_ADMIN') && $session['locked'] === null,
573 'session' => $session['id']
576 //Add form to context
577 $this->context
['forms']['session'] = $sessionForm->createView();
580 //Add session in context
581 $context['session'] = [
583 'date' => $session['date'],
584 'begin' => $session['begin'],
585 'start' => $session['start'],
586 'length' => $session['length'],
587 'stop' => $session['stop'],
588 'rainfall' => $session['rainfall'] !== null ? $session['rainfall'].' mm' : $session['rainfall'],
589 'rainrisk' => $session['rainrisk'] !== null ? ($session['rainrisk']*100).' %' : $session['rainrisk'],
590 'realfeel' => $session['realfeel'] !== null ? $session['realfeel'].' °C' : $session['realfeel'],
591 'realfeelmin' => $session['realfeelmin'] !== null ? $session['realfeelmin'].' °C' : $session['realfeelmin'],
592 'realfeelmax' => $session['realfeelmax'] !== null ? $session['realfeelmax'].' °C' : $session['realfeelmax'],
593 'temperature' => $session['temperature'] !== null ? $session['temperature'].' °C' : $session['temperature'],
594 'temperaturemin' => $session['temperaturemin'] !== null ? $session['temperaturemin'].' °C' : $session['temperaturemin'],
595 'temperaturemax' => $session['temperaturemax'] !== null ? $session['temperaturemax'].' °C' : $session['temperaturemax'],
596 'locked' => $session['locked'],
597 'created' => $session['created'],
598 'updated' => $session['updated'],
599 'title' => $this->translator
->trans('Session %id%', ['%id%' => $id]),
600 'application' => null,
602 'id' => $session['l_id'],
603 'at' => $this->translator
->trans('at '.$session['l_title']),
604 'short' => $this->translator
->trans($session['l_short']),
605 'title' => $this->translator
->trans($session['l_title']),
606 'address' => $session['l_address'],
607 'zipcode' => $session['l_zipcode'],
608 'city' => $session['l_city'],
609 'latitude' => $session['l_latitude'],
610 'longitude' => $session['l_longitude']
613 'id' => $session['t_id'],
614 'title' => $this->translator
->trans($session['t_title'])
617 'id' => $session['p_id'],
618 'description' => $session['p_description'],
619 'class' => $session['p_class'],
620 'contact' => $session['p_contact'],
621 'donate' => $session['p_donate'],
622 'link' => $session['p_link'],
623 'profile' => $session['p_profile']
625 'applications' => null
629 if (!empty($session['a_id'])) {
630 $context['session']['application'] = [
632 'id' => $session['au_id'],
633 'by' => $this->translator
->trans('by %pseudonym%', [ '%pseudonym%' => $session['au_pseudonym'] ]),
634 'title' => $session['au_pseudonym']
636 'id' => $session['a_id'],
637 'canceled' => $session['a_canceled'],
638 'title' => $this->translator
->trans('Application %id%', [ '%id%' => $session['a_id'] ]),
643 if (!empty($session['sa_id'])) {
644 //Extract applications id
645 $session['sa_id'] = explode("\n", $session['sa_id']);
646 //Extract applications score
647 //XXX: score may be null before grant or for bad behaviour, replace NULL with 'NULL' to avoid silent drop in mysql
648 $session['sa_score'] = array_map(function($v){return $v
==='NULL'?null:$v
;}, explode("\n", $session['sa_score']));
649 //Extract applications created
650 $session['sa_created'] = array_map(function($v){return new \
DateTime($v
);}, explode("\n", $session['sa_created']));
651 //Extract applications updated
652 $session['sa_updated'] = array_map(function($v){return new \
DateTime($v
);}, explode("\n", $session['sa_updated']));
653 //Extract applications canceled
654 //XXX: canceled is null before cancelation, replace NULL with 'NULL' to avoid silent drop in mysql
655 $session['sa_canceled'] = array_map(function($v){return $v
==='NULL'?null:new \
DateTime($v
);}, explode("\n", $session['sa_canceled']));
657 //Extract applications user id
658 $session['sau_id'] = explode("\n", $session['sau_id']);
659 //Extract applications user pseudonym
660 $session['sau_pseudonym'] = explode("\n", $session['sau_pseudonym']);
663 $context['session']['applications'] = [];
664 foreach($session['sa_id'] as $i => $sa_id) {
665 $context['session']['applications'][$sa_id] = [
667 'score' => $session['sa_score'][$i],
668 'created' => $session['sa_created'][$i],
669 'updated' => $session['sa_updated'][$i],
670 'canceled' => $session['sa_canceled'][$i]
672 if (!empty($session['sau_id'][$i])) {
673 $context['session']['applications'][$sa_id]['user'] = [
674 'id' => $session['sau_id'][$i],
675 'title' => $session['sau_pseudonym'][$i]
682 $period = new \
DatePeriod(
683 //Start from first monday of week
684 new \
DateTime('Monday this week'),
685 //Iterate on each day
686 new \
DateInterval('P1D'),
687 //End with next sunday and 4 weeks
689 $this->isGranted('IS_AUTHENTICATED_REMEMBERED')?'Monday this week + 4 week':'Monday this week + 2 week'
694 //XXX: we want to display all active locations anyway
695 $locations = $doctrine->getRepository(Location
::class)->findTranslatedSortedByPeriod($this->translator
, $period, $session['au_id']);
698 return $this->render('@RapsysAir/session/view.html.twig', ['title' => $title, 'section' => $section, 'locations' => $locations]+
$context+
$this->context
);