From 58242917a50ec39071529953e77343fd3eb6dda0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Rapha=C3=ABl=20Gertz?= Date: Fri, 25 Oct 2019 16:33:24 +0200 Subject: [PATCH] Initial import --- Controller/DefaultController.php | 305 +++++++++++ DataFixtures/AirFixtures.php | 246 +++++++++ DependencyInjection/Configuration.php | 56 +++ DependencyInjection/RapsysAirExtension.php | 46 ++ Entity/Application.php | 187 +++++++ Entity/Group.php | 6 + Entity/Location.php | 304 +++++++++++ Entity/Session.php | 281 +++++++++++ Entity/Slot.php | 191 +++++++ Entity/Title.php | 7 + Entity/User.php | 85 ++++ Entity/Vote.php | 141 ++++++ Form/ApplicationType.php | 39 ++ Form/ContactType.php | 40 ++ RapsysAirBundle.php | 9 + Repository/ApplicationRepository.php | 26 + Repository/SessionRepository.php | 45 ++ Resources/config/doctrine/Application.orm.yml | 27 + Resources/config/doctrine/Group.orm.yml | 8 + Resources/config/doctrine/Location.orm.yml | 69 +++ Resources/config/doctrine/Session.orm.yml | 41 ++ Resources/config/doctrine/Slot.orm.yml | 24 + Resources/config/doctrine/Title.orm.yml | 8 + Resources/config/doctrine/User.orm.yml | 27 + Resources/config/doctrine/Vote.orm.yml | 23 + Resources/config/routing.yml | 17 + Resources/config/services.yml | 15 + Resources/public/css/reset.css | 45 ++ Resources/public/css/screen.css | 473 ++++++++++++++++++ Resources/public/ico/favicon.ico | Bin 0 -> 90022 bytes Resources/public/png/apple.png | Bin 0 -> 14257 bytes Resources/public/png/favicon.png | Bin 0 -> 15277 bytes Resources/public/png/logo.png | Bin 0 -> 4297 bytes Resources/public/svg/favicon.svg | 95 ++++ Resources/public/svg/logo.svg | 228 +++++++++ Resources/public/xcf/openair.xcf | Bin 0 -> 30224 bytes Resources/translations/messages.fr.yml | 60 +++ Resources/translations/validators.fr.yml | 11 + Resources/views/admin/index.html.twig | 57 +++ Resources/views/admin/index.html.twig.toto | 1 + Resources/views/admin/session.html.twig | 31 ++ Resources/views/base.html.twig | 78 +++ Resources/views/form/contact.html.twig | 34 ++ .../views/form/form_div_layout.html.twig | 417 +++++++++++++++ Resources/views/form/login.html.twig | 32 ++ Resources/views/form/recover.html.twig | 28 ++ Resources/views/form/recover_mail.html.twig | 30 ++ Resources/views/form/register.html.twig | 42 ++ Resources/views/mail/contact.html.twig | 43 ++ Resources/views/mail/generic.html.twig | 49 ++ Resources/views/mail/register.html.twig | 43 ++ Resources/views/page/index.html.twig | 7 + Tests/Controller/DefaultControllerTest.php | 17 + Twig/Base64Extension.php | 12 + Twig/Bb2htmlExtension.php | 64 +++ Twig/FileGetContentsExtension.php | 11 + 56 files changed, 4181 insertions(+) create mode 100644 Controller/DefaultController.php create mode 100644 DataFixtures/AirFixtures.php create mode 100644 DependencyInjection/Configuration.php create mode 100644 DependencyInjection/RapsysAirExtension.php create mode 100644 Entity/Application.php create mode 100644 Entity/Group.php create mode 100644 Entity/Location.php create mode 100644 Entity/Session.php create mode 100644 Entity/Slot.php create mode 100644 Entity/Title.php create mode 100644 Entity/User.php create mode 100644 Entity/Vote.php create mode 100644 Form/ApplicationType.php create mode 100644 Form/ContactType.php create mode 100644 RapsysAirBundle.php create mode 100644 Repository/ApplicationRepository.php create mode 100644 Repository/SessionRepository.php create mode 100644 Resources/config/doctrine/Application.orm.yml create mode 100644 Resources/config/doctrine/Group.orm.yml create mode 100644 Resources/config/doctrine/Location.orm.yml create mode 100644 Resources/config/doctrine/Session.orm.yml create mode 100644 Resources/config/doctrine/Slot.orm.yml create mode 100644 Resources/config/doctrine/Title.orm.yml create mode 100644 Resources/config/doctrine/User.orm.yml create mode 100644 Resources/config/doctrine/Vote.orm.yml create mode 100644 Resources/config/routing.yml create mode 100644 Resources/config/services.yml create mode 100644 Resources/public/css/reset.css create mode 100644 Resources/public/css/screen.css create mode 100644 Resources/public/ico/favicon.ico create mode 100644 Resources/public/png/apple.png create mode 100644 Resources/public/png/favicon.png create mode 100644 Resources/public/png/logo.png create mode 100644 Resources/public/svg/favicon.svg create mode 100644 Resources/public/svg/logo.svg create mode 100644 Resources/public/xcf/openair.xcf create mode 100644 Resources/translations/messages.fr.yml create mode 100644 Resources/translations/validators.fr.yml create mode 100644 Resources/views/admin/index.html.twig create mode 100644 Resources/views/admin/index.html.twig.toto create mode 100644 Resources/views/admin/session.html.twig create mode 100644 Resources/views/base.html.twig create mode 100644 Resources/views/form/contact.html.twig create mode 100644 Resources/views/form/form_div_layout.html.twig create mode 100644 Resources/views/form/login.html.twig create mode 100644 Resources/views/form/recover.html.twig create mode 100644 Resources/views/form/recover_mail.html.twig create mode 100644 Resources/views/form/register.html.twig create mode 100644 Resources/views/mail/contact.html.twig create mode 100644 Resources/views/mail/generic.html.twig create mode 100644 Resources/views/mail/register.html.twig create mode 100644 Resources/views/page/index.html.twig create mode 100644 Tests/Controller/DefaultControllerTest.php create mode 100644 Twig/Base64Extension.php create mode 100644 Twig/Bb2htmlExtension.php create mode 100644 Twig/FileGetContentsExtension.php diff --git a/Controller/DefaultController.php b/Controller/DefaultController.php new file mode 100644 index 0000000..31d4b89 --- /dev/null +++ b/Controller/DefaultController.php @@ -0,0 +1,305 @@ +get('translator'); + + //Set section + $section = $trans->trans('Contact'); + + //Set title + $title = $section.' - '.$trans->trans($this->getParameter('rapsys_air.title')); + + //Create the form according to the FormType created previously. + //And give the proper parameters + $form = $this->createForm('Rapsys\AirBundle\Form\ContactType', null, [ + // To set the action use $this->generateUrl('route_identifier') + 'action' => $this->generateUrl('rapsys_air_contact'), + 'method' => 'POST' + ]); + + if ($request->isMethod('POST')) { + // Refill the fields in case the form is not valid. + $form->handleRequest($request); + + if ($form->isValid()) { + //Get data + $data = $form->getData(); + + //Get contact name + $contactName = $this->getParameter('rapsys_air.contact_name'); + + //Get contact mail + $contactMail = $this->getParameter('rapsys_air.contact_mail'); + + //Get logo + $logo = $this->getParameter('rapsys_air.logo'); + + //Get title + $title = $trans->trans($this->getParameter('rapsys_air.title')); + + //Get subtitle + $subtitle = $trans->trans('Hi,').' '.$contactName; + + $message = \Swift_Message::newInstance() + ->setSubject($data['subject']) + ->setFrom([$data['mail'] => $data['name']]) + ->setTo([$contactMail => $contactName]) + ->setBody($data['message']) + ->addPart( + $this->renderView( + '@RapsysAir/mail/generic.html.twig', + [ + 'logo' => $logo, + 'title' => $title, + 'subtitle' => $subtitle, + 'home' => $this->get('router')->generate('rapsys_air_homepage', [], UrlGeneratorInterface::ABSOLUTE_URL), + 'subject' => $data['subject'], + 'contact_name' => $contactName, + 'message' => strip_tags($data['message']) + ] + ), + 'text/html' + ); + //Send message + if ($this->get('mailer')->send($message)) { + //Redirect to cleanup the form + return $this->redirectToRoute('rapsys_air_contact', ['sent' => 1]); + } + } + } + + //Render template + return $this->render('@RapsysAir/form/contact.html.twig', ['title' => $title, 'section' => $section, 'form' => $form->createView(), 'sent' => $request->query->get('sent', 0)]); + } + + public function indexAction() { + //Get translator + $trans = $this->get('translator'); + + //Set section + $section = $trans->trans('Index'); + + //Set title + $title = $section.' - '.$trans->trans($this->getParameter('rapsys_air.title')); + + return $this->render('@RapsysAir/page/index.html.twig', ['title' => $title, 'section' => $section]); + } + + public function adminAction(Request $request) { + $this->denyAccessUnlessGranted('ROLE_ADMIN', null, 'Unable to access this page!'); + + //Get translator + $trans = $this->get('translator'); + + //Set section + $section = $trans->trans('Admin'); + + //Set title + $title = $section.' - '.$trans->trans($this->getParameter('rapsys_air.title')); + + //Create the form according to the FormType created previously. + //And give the proper parameters + $form = $this->createForm('Rapsys\AirBundle\Form\ApplicationType', null, [ + // To set the action use $this->generateUrl('route_identifier') + 'action' => $this->generateUrl('rapsys_air_admin'), + 'method' => 'POST', + 'attr' => [ 'class' => 'form_col' ] + ]); + + //Get doctrine + $doctrine = $this->getDoctrine(); + + //Handle request + if ($request->isMethod('POST')) { + // Refill the fields in case the form is not valid. + $form->handleRequest($request); + + if ($form->isValid()) { + //Get data + $data = $form->getData(); + + //Get manager + $manager = $doctrine->getManager(); + + //Protect session fetching + try { + $session = $doctrine->getRepository(Session::class)->findOneByLocationSlotDate($data['location'], $data['slot'], $data['date']); + //Catch no session case + } catch (\Doctrine\ORM\NoResultException $e) { + //Create the session + $session = new Session(); + $session->setLocation($data['location']); + $session->setSlot($data['slot']); + $session->setDate($data['date']); + $session->setCreated(new \DateTime('now')); + $session->setUpdated(new \DateTime('now')); + $manager->persist($session); + //Flush to get the ids + #$manager->flush(); + } + + //Init application + $application = false; + + //Protect application fetching + try { + //TODO: handle admin case where we provide a user in extra + $application = $doctrine->getRepository(Application::class)->findOneBySessionUser($session, $this->getUser()); + + //Add error message to mail field + $form->get('slot')->addError(new FormError($trans->trans('Application already exists'))); + //Catch no application cases + //XXX: combine these catch when php 7.1 is available + } catch (\Doctrine\ORM\NoResultException $e) { + //Catch invalid argument because session is not already persisted + } catch(\Doctrine\ORM\ORMInvalidArgumentException $e) { + } + + //Create new application if none found + if (!$application) { + //Create the application + $application = new Application(); + $application->setSession($session); + //TODO: handle admin case where we provide a user in extra + $application->setUser($this->getUser()); + $application->setCreated(new \DateTime('now')); + $application->setUpdated(new \DateTime('now')); + $manager->persist($application); + + //Flush to get the ids + $manager->flush(); + + //Add notice in flash message + $this->addFlash('notice', $trans->trans('Application request the %date% for %location% on the slot %slot% saved', ['%location%' => $data['location']->getTitle(), '%slot%' => $data['slot']->getTitle(), '%date%' => $data['date']->format('Y-m-d')])); + + //Redirect to cleanup the form + return $this->redirectToRoute('rapsys_air_admin'); + } + } + } + + //Compute period + $period = new \DatePeriod( + //Start from first monday of week + new \DateTime('Monday this week'), + //Iterate on each day + new \DateInterval('P1D'), + //End with next sunday and 4 weeks + new \DateTime('Monday this week + 5 week') + ); + + //Fetch sessions + $sessions = $doctrine->getRepository(Session::class)->findByDatePeriod($period); + + //Init calendar + $calendar = []; + + //Init month + $month = null; + + //Iterate on each day + foreach($period as $date) { + //Init day in calendar + $calendar[$Ymd = $date->format('Ymd')] = [ + 'title' => $date->format('d'), + 'class' => [], + 'sessions' => [] + ]; + //Append month for first day of month + if ($month != $date->format('m')) { + $month = $date->format('m'); + $calendar[$Ymd]['title'] .= '/'.$month; + } + //Deal with today + if ($date->format('U') == ($today = strtotime('today'))) { + $calendar[$Ymd]['title'] .= '/'.$month; + $calendar[$Ymd]['current'] = true; + $calendar[$Ymd]['class'][] = 'current'; + } + //Disable passed days + if ($date->format('U') < $today) { + $calendar[$Ymd]['disabled'] = true; + $calendar[$Ymd]['class'][] = 'disabled'; + } + //Set next month days + if ($date->format('m') > date('m')) { + $calendar[$Ymd]['next'] = true; + $calendar[$Ymd]['class'][] = 'next'; + } + //Iterate on each session to find the one of the day + foreach($sessions as $session) { + if (($sessionYmd = $session->getDate()->format('Ymd')) == $Ymd) { + //Count number of application + $count = count($session->getApplications()); + + //Compute classes + $class = []; + if ($session->getApplication()) { + $class[] = 'granted'; + } elseif ($count == 0) { + $class[] = 'orphaned'; + } elseif ($count > 1) { + $class[] = 'disputed'; + } else { + $class[] = 'pending'; + } + + //Add the session + $calendar[$Ymd]['sessions'][$session->getSlot()->getId().$session->getLocation()->getId()] = [ + 'id' => $session->getId(), + 'title' => ($count > 1?'['.$count.'] ':'').$session->getSlot()->getTitle().' '.$session->getLocation()->getTitle(), + 'class' => $class + ]; + } + } + + //Sort sessions + ksort($calendar[$Ymd]['sessions']); + } + + return $this->render('@RapsysAir/admin/index.html.twig', ['title' => $title, 'section' => $section, 'form' => $form->createView(), 'calendar' => $calendar]); + } + + public function sessionAction(Request $request, $id) { + /*header('Content-Type: text/plain'); + var_dump($calendar); + exit;*/ + + //Get translator + $trans = $this->get('translator'); + + //Set section + $section = $trans->trans('Session %id%', ['%id%' => $id]); + + //Set title + $title = $section.' - '.$trans->trans($this->getParameter('rapsys_air.title')); + + //Create the form according to the FormType created previously. + //And give the proper parameters + /*$form = $this->createForm('Rapsys\AirBundle\Form\ApplicationType', null, [ + // To set the action use $this->generateUrl('route_identifier') + 'action' => $this->generateUrl('rapsys_air_admin'), + 'method' => 'POST', + 'attr' => [ 'class' => 'form_col' ] + ]);*/ + + //Get doctrine + $doctrine = $this->getDoctrine(); + + //Fetch session + $session = $doctrine->getRepository(Session::class)->findOneById($id); + + return $this->render('@RapsysAir/admin/session.html.twig', ['title' => $title, 'section' => $section, /*'form' => $form->createView(),*/ 'session' => $session]); + } +} diff --git a/DataFixtures/AirFixtures.php b/DataFixtures/AirFixtures.php new file mode 100644 index 0000000..cfaaa62 --- /dev/null +++ b/DataFixtures/AirFixtures.php @@ -0,0 +1,246 @@ +container = $container; + } + + /** + * {@inheritDoc} + */ + public function load(\Doctrine\Common\Persistence\ObjectManager $manager) { + $encoder = $this->container->get('security.password_encoder'); + + //Title tree + $titleTree = array( + 'M.' => 'Monsieur', + 'Mlle' => 'Mademoiselle', + 'Mme' => 'Madame' + ); + + //Create titles + $titles = array(); + foreach($titleTree as $shortData => $titleData) { + $title = new Title(); + $title->setShort($shortData); + $title->setTitle($titleData); + $title->setCreated(new \DateTime('now')); + $title->setUpdated(new \DateTime('now')); + $manager->persist($title); + $titles[$shortData] = $title; + unset($title); + } + + //Group tree + $groupTree = array( + 'ROLE_USER', + 'ROLE_ADMIN', + 'ROLE_SUPER' + ); + + //Create groups + $groups = array(); + foreach($groupTree as $groupData) { + $group = new Group($groupData); + $group->setCreated(new \DateTime('now')); + $group->setUpdated(new \DateTime('now')); + $manager->persist($group); + $groups[$groupData] = $group; + unset($group); + } + + //Flush to get the ids + $manager->flush(); + + //User tree + $userTree = array( + array( + 'short' => 'M.', + 'group' => 'ROLE_SUPER', + 'mail' => 'airlibre@rapsys.eu', + 'pseudonym' => 'Rapsys', + 'forename' => 'Raphaël', + 'surname' => 'Gertz', + 'password' => 'test' + ), + array( + 'short' => 'M.', + 'group' => 'ROLE_ADMIN', + 'mail' => 'rannou402@orange.fr', + 'pseudonym' => 'Mitch', + 'forename' => 'Michel', + 'surname' => 'Rannou', + 'password' => 'test' + ), + array( + 'short' => 'Mlle', + 'group' => 'ROLE_ADMIN', + 'mail' => 'roxmaps@gmail.com', + 'pseudonym' => 'Roxana', + 'forename' => 'Roxana', + 'surname' => 'Prado', + 'password' => 'test' + ), + array( + 'short' => 'M.', + 'group' => 'ROLE_ADMIN', + 'mail' => 'majid.ghedjatti@gmail.com', + 'pseudonym' => 'El Guerrillero', + 'forename' => 'Majid', + 'surname' => 'Ghedjatti', + 'password' => 'test' + ), + array( + 'short' => 'M.', + 'group' => 'ROLE_ADMIN', + 'mail' => 'denis.courvoisier@wanadoo.fr', + 'pseudonym' => 'Sined', + 'forename' => 'Denis', + 'surname' => 'Courvoisier', + 'password' => 'test' + ), + array( + 'short' => 'M.', + 'group' => 'ROLE_ADMIN', + 'mail' => 'kastango13@gmail.com', + 'pseudonym' => 'Kastrat', + 'forename' => 'Kastrat', + 'surname' => 'Hasaj', + 'password' => 'test' + ), + ); + + //Create users + $users = array(); + foreach($userTree as $userData) { + $user = new User(); + $user->setMail($userData['mail']); + $user->setPseudonym($userData['pseudonym']); + $user->setForename($userData['forename']); + $user->setSurname($userData['surname']); + $user->setPassword($encoder->encodePassword($user, $userData['password'])); + $user->setActive(true); + $user->setTitle($titles[$userData['short']]); + $user->addGroup($groups[$userData['group']]); + $user->setCreated(new \DateTime('now')); + $user->setUpdated(new \DateTime('now')); + $manager->persist($user); + $users[] = $user; + unset($user); + } + + //Flush to get the ids + $manager->flush(); + + //Location tree + $locationTree = [ + [ + 'title' => 'Esplanade du Trocadéro', + 'address' => '1 Avenue Hussein 1er de Jordanie', + #75016 pour meteo-france, accuweather supporte 75116 + 'zipcode' => '75116', + 'city' => 'Paris', + 'latitude' => 48.8619, + 'longitude' => 2.2888 + ], + [ + 'title' => 'Opéra Garnier', + 'address' => 'Place de l\'Opéra', + 'zipcode' => '75009', + 'city' => 'Paris', + 'latitude' => 48.871365, + 'longitude' => 2.332026 + ], + [ + 'title' => 'Marché Saint Honoré', + 'address' => '1 Passage des Jacobins', + 'zipcode' => '75001', + 'city' => 'Paris', + 'latitude' => 48.8668, + 'longitude' => 2.331659 + ], + [ + 'title' => 'Jardin Tino-Rossi', + 'address' => '2 Quai Saint-Bernard', + 'zipcode' => '75005', + 'city' => 'Paris', + 'latitude' => 48.847736, + 'longitude' => 2.360953 + ], + [ + 'title' => 'Palais de Tokyo', + 'address' => '13 Avenue du Président Wilson', + 'zipcode' => '75116', + 'city' => 'Paris', + 'latitude' => 48.864567, + 'longitude' => 2.296892 + ] + ]; + + //Create locations + $locations = array(); + foreach($locationTree as $locationData) { + $location = new Location(); + $location->setTitle($locationData['title']); + $location->setAddress($locationData['address']); + $location->setZipcode($locationData['zipcode']); + $location->setCity($locationData['city']); + $location->setLatitude($locationData['latitude']); + $location->setLongitude($locationData['longitude']); + $location->setCreated(new \DateTime('now')); + $location->setUpdated(new \DateTime('now')); + $manager->persist($location); + $locations[$locationData['title']] = $location; + unset($location); + } + + //Flush to get the ids + $manager->flush(); + + //Slot tree + $slotTree = [ + [ + 'begin' => '14:00:00 UTC', + 'end' => '19:00:00 UTC' + ], + [ + 'begin' => '19:00:00 UTC', + 'end' => '23:00:00 UTC' + ], + [ + 'begin' => '23:00:00 UTC', + 'end' => '02:00:00 UTC' + ] + ]; + + //Create slots + $slots = array(); + foreach($slotTree as $slotData) { + $slot = new Slot(); + $slot->setBegin(new \DateTime($slotData['begin'])); + $slot->setEnd(new \DateTime($slotData['end'])); + $slot->setCreated(new \DateTime('now')); + $slot->setUpdated(new \DateTime('now')); + $manager->persist($slot); + $slots[$slot->getId()] = $slot; + unset($slot); + } + + //Flush to get the ids + $manager->flush(); + } +} diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php new file mode 100644 index 0000000..13d24a7 --- /dev/null +++ b/DependencyInjection/Configuration.php @@ -0,0 +1,56 @@ + 'bundles/rapsysair/png/logo.png', + 'title' => 'Open Air', + 'contact_name' => 'Raphaël Gertz', + 'contact_mail' => 'airlibre@rapsys.eu', + ]; + + //Here we define the parameters that are allowed to configure the bundle. + //TODO: see https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php for default value and description + //TODO: see http://symfony.com/doc/current/components/config/definition.html + //XXX: use bin/console config:dump-reference to dump class infos + + //Here we define the parameters that are allowed to configure the bundle. + $treeBuilder + //Parameters + ->root('parameters') + ->addDefaultsIfNotSet() + ->children() + ->arrayNode('rapsys_air') + ->addDefaultsIfNotSet() + ->children() + ->scalarNode('logo')->defaultValue($defaults['logo'])->treatNullLike($defaults['logo'])->isRequired()->end() + ->scalarNode('title')->defaultValue($defaults['title'])->treatNullLike($defaults['title'])->isRequired()->end() + ->scalarNode('contact_name')->defaultValue($defaults['contact_name'])->treatNullLike($defaults['contact_name'])->isRequired()->end() + ->scalarNode('contact_mail')->defaultValue($defaults['contact_mail'])->treatNullLike($defaults['contact_mail'])->isRequired()->end() + ->end() + ->end() + ->end() + ->end(); + + return $treeBuilder; + } +} diff --git a/DependencyInjection/RapsysAirExtension.php b/DependencyInjection/RapsysAirExtension.php new file mode 100644 index 0000000..5a2bdff --- /dev/null +++ b/DependencyInjection/RapsysAirExtension.php @@ -0,0 +1,46 @@ +load('services.yml'); + + $configuration = new Configuration(); + $config = $this->processConfiguration($configuration, $configs); + + //Set default config in parameter + if (!$container->hasParameter($alias = $this->getAlias())) { + $container->setParameter($alias, $config[$alias]); + } else { + $config[$alias] = $container->getParameter($alias); + } + + //Transform the one level tree in flat parameters + foreach($config[$alias] as $k => $v) { + //Set is as parameters + $container->setParameter($alias.'.'.$k, $v); + } + } + + /** + * {@inheritdoc} + */ + public function getAlias() { + return 'rapsys_air'; + } +} diff --git a/Entity/Application.php b/Entity/Application.php new file mode 100644 index 0000000..c157132 --- /dev/null +++ b/Entity/Application.php @@ -0,0 +1,187 @@ +votes = new \Doctrine\Common\Collections\ArrayCollection(); + } + + /** + * Get id + * + * @return integer + */ + public function getId() + { + return $this->id; + } + + /** + * Set created + * + * @param \DateTime $created + * + * @return Application + */ + public function setCreated($created) + { + $this->created = $created; + + return $this; + } + + /** + * Get created + * + * @return \DateTime + */ + public function getCreated() + { + return $this->created; + } + + /** + * Set updated + * + * @param \DateTime $updated + * + * @return Application + */ + public function setUpdated($updated) + { + $this->updated = $updated; + + return $this; + } + + /** + * Get updated + * + * @return \DateTime + */ + public function getUpdated() + { + return $this->updated; + } + + /** + * Add vote + * + * @param \Rapsys\AirBundle\Entity\Vote $vote + * + * @return Application + */ + public function addVote(\Rapsys\AirBundle\Entity\Vote $vote) + { + $this->votes[] = $vote; + + return $this; + } + + /** + * Remove vote + * + * @param \Rapsys\AirBundle\Entity\Vote $vote + */ + public function removeVote(\Rapsys\AirBundle\Entity\Vote $vote) + { + $this->votes->removeElement($vote); + } + + /** + * Get votes + * + * @return \Doctrine\Common\Collections\Collection + */ + public function getVotes() + { + return $this->votes; + } + + /** + * Set session + * + * @param \Rapsys\AirBundle\Entity\Session $session + * + * @return Application + */ + public function setSession(\Rapsys\AirBundle\Entity\Session $session = null) + { + $this->session = $session; + + return $this; + } + + /** + * Get session + * + * @return \Rapsys\AirBundle\Entity\Session + */ + public function getSession() + { + return $this->session; + } + + /** + * Set user + * + * @param \Rapsys\AirBundle\Entity\User $user + * + * @return Application + */ + public function setUser(\Rapsys\AirBundle\Entity\User $user = null) + { + $this->user = $user; + + return $this; + } + + /** + * Get user + * + * @return \Rapsys\AirBundle\Entity\User + */ + public function getUser() + { + return $this->user; + } +} diff --git a/Entity/Group.php b/Entity/Group.php new file mode 100644 index 0000000..3ccf6ee --- /dev/null +++ b/Entity/Group.php @@ -0,0 +1,6 @@ +sessions = new \Doctrine\Common\Collections\ArrayCollection(); + } + + /** + * Get id + * + * @return integer + */ + public function getId() + { + return $this->id; + } + + /** + * Set title + * + * @param string $title + * + * @return Location + */ + public function setTitle($title) + { + $this->title = $title; + + return $this; + } + + /** + * Get title + * + * @return string + */ + public function getTitle() + { + return $this->title; + } + + /** + * Set address + * + * @param string $address + * + * @return Location + */ + public function setAddress($address) + { + $this->address = $address; + + return $this; + } + + /** + * Get address + * + * @return string + */ + public function getAddress() + { + return $this->address; + } + + /** + * Set zipcode + * + * @param string $zipcode + * + * @return Location + */ + public function setZipcode($zipcode) + { + $this->zipcode = $zipcode; + + return $this; + } + + /** + * Get zipcode + * + * @return string + */ + public function getZipcode() + { + return $this->zipcode; + } + + /** + * Set city + * + * @param string $city + * + * @return Location + */ + public function setCity($city) + { + $this->city = $city; + + return $this; + } + + /** + * Get city + * + * @return string + */ + public function getCity() + { + return $this->city; + } + + /** + * Set latitude + * + * @param string $latitude + * + * @return Location + */ + public function setLatitude($latitude) + { + $this->latitude = $latitude; + + return $this; + } + + /** + * Get latitude + * + * @return string + */ + public function getLatitude() + { + return $this->latitude; + } + + /** + * Set longitude + * + * @param string $longitude + * + * @return Location + */ + public function setLongitude($longitude) + { + $this->longitude = $longitude; + + return $this; + } + + /** + * Get longitude + * + * @return string + */ + public function getLongitude() + { + return $this->longitude; + } + + /** + * Set created + * + * @param \DateTime $created + * + * @return Location + */ + public function setCreated($created) + { + $this->created = $created; + + return $this; + } + + /** + * Get created + * + * @return \DateTime + */ + public function getCreated() + { + return $this->created; + } + + /** + * Set updated + * + * @param \DateTime $updated + * + * @return Location + */ + public function setUpdated($updated) + { + $this->updated = $updated; + + return $this; + } + + /** + * Get updated + * + * @return \DateTime + */ + public function getUpdated() + { + return $this->updated; + } + + /** + * Add session + * + * @param \Rapsys\AirBundle\Entity\Session $session + * + * @return Location + */ + public function addSession(\Rapsys\AirBundle\Entity\Session $session) + { + $this->sessions[] = $session; + + return $this; + } + + /** + * Remove session + * + * @param \Rapsys\AirBundle\Entity\Session $session + */ + public function removeSession(\Rapsys\AirBundle\Entity\Session $session) + { + $this->sessions->removeElement($session); + } + + /** + * Get sessions + * + * @return \Doctrine\Common\Collections\Collection + */ + public function getSessions() + { + return $this->sessions; + } +} + diff --git a/Entity/Session.php b/Entity/Session.php new file mode 100644 index 0000000..72d1f33 --- /dev/null +++ b/Entity/Session.php @@ -0,0 +1,281 @@ +applications = new \Doctrine\Common\Collections\ArrayCollection(); + } + + /** + * Get id + * + * @return integer + */ + public function getId() { + return $this->id; + } + + /** + * Set date + * + * @param \DateTime $date + * + * @return Session + */ + public function setDate($date) { + $this->date = $date; + + return $this; + } + + /** + * Get date + * + * @return \DateTime + */ + public function getDate() { + return $this->date; + } + + /** + * Set begin + * + * @param \DateTime $begin + * + * @return Session + */ + public function setBegin($begin) { + $this->begin = $begin; + + return $this; + } + + /** + * Get begin + * + * @return \DateTime + */ + public function getBegin() { + return $this->begin; + } + + /** + * Set end + * + * @param \DateTime $end + * + * @return Session + */ + public function setEnd($end) { + $this->end = $end; + + return $this; + } + + /** + * Get end + * + * @return \DateTime + */ + public function getEnd() { + return $this->end; + } + + /** + * Set created + * + * @param \DateTime $created + * + * @return Session + */ + public function setCreated($created) { + $this->created = $created; + + return $this; + } + + /** + * Get created + * + * @return \DateTime + */ + public function getCreated() { + return $this->created; + } + + /** + * Set updated + * + * @param \DateTime $updated + * + * @return Session + */ + public function setUpdated($updated) { + $this->updated = $updated; + + return $this; + } + + /** + * Get updated + * + * @return \DateTime + */ + public function getUpdated() { + return $this->updated; + } + + /** + * Add application + * + * @param \Rapsys\AirBundle\Entity\Application $application + * + * @return Session + */ + public function addApplication(\Rapsys\AirBundle\Entity\Application $application) { + $this->applications[] = $application; + + return $this; + } + + /** + * Remove application + * + * @param \Rapsys\AirBundle\Entity\Application $application + */ + public function removeApplication(\Rapsys\AirBundle\Entity\Application $application) { + $this->applications->removeElement($application); + } + + /** + * Get applications + * + * @return \Doctrine\Common\Collections\Collection + */ + public function getApplications() { + return $this->applications; + } + + /** + * Set location + * + * @param \Rapsys\AirBundle\Entity\Location $location + * + * @return Session + */ + public function setLocation(\Rapsys\AirBundle\Entity\Location $location = null) { + $this->location = $location; + + return $this; + } + + /** + * Get location + * + * @return \Rapsys\AirBundle\Entity\Location + */ + public function getLocation() { + return $this->location; + } + /** + * @var \Rapsys\AirBundle\Entity\Slot + */ + private $slot; + + + /** + * Set slot + * + * @param \Rapsys\AirBundle\Entity\Slot $slot + * + * @return Session + */ + public function setSlot(\Rapsys\AirBundle\Entity\Slot $slot = null) { + $this->slot = $slot; + + return $this; + } + + /** + * Get slot + * + * @return \Rapsys\AirBundle\Entity\Slot + */ + public function getSlot() { + return $this->slot; + } + + /** + * Set application + * + * @param \Rapsys\AirBundle\Entity\Application $application + * + * @return Session + */ + public function setApplication(\Rapsys\AirBundle\Entity\Application $application = null) { + $this->application = $application; + + return $this; + } + + /** + * Get application + * + * @return \Rapsys\AirBundle\Entity\Application + */ + public function getApplication() { + return $this->application; + } +} diff --git a/Entity/Slot.php b/Entity/Slot.php new file mode 100644 index 0000000..03bfd3f --- /dev/null +++ b/Entity/Slot.php @@ -0,0 +1,191 @@ +sessions = new \Doctrine\Common\Collections\ArrayCollection(); + } + + /** + * Get id + * + * @return integer + */ + public function getId() + { + return $this->id; + } + + /** + * Set begin + * + * @param \DateTime $begin + * + * @return Slot + */ + public function setBegin($begin) + { + $this->begin = $begin; + + return $this; + } + + /** + * Get begin + * + * @return \DateTime + */ + public function getBegin() + { + return $this->begin; + } + + /** + * Set end + * + * @param \DateTime $end + * + * @return Slot + */ + public function setEnd($end) + { + $this->end = $end; + + return $this; + } + + /** + * Get end + * + * @return \DateTime + */ + public function getEnd() + { + return $this->end; + } + + /** + * Set created + * + * @param \DateTime $created + * + * @return Slot + */ + public function setCreated($created) + { + $this->created = $created; + + return $this; + } + + /** + * Get created + * + * @return \DateTime + */ + public function getCreated() + { + return $this->created; + } + + /** + * Set updated + * + * @param \DateTime $updated + * + * @return Slot + */ + public function setUpdated($updated) + { + $this->updated = $updated; + + return $this; + } + + /** + * Get updated + * + * @return \DateTime + */ + public function getUpdated() + { + return $this->updated; + } + + /** + * Add session + * + * @param \Rapsys\AirBundle\Entity\Session $session + * + * @return Slot + */ + public function addSession(\Rapsys\AirBundle\Entity\Session $session) + { + $this->sessions[] = $session; + + return $this; + } + + /** + * Remove session + * + * @param \Rapsys\AirBundle\Entity\Session $session + */ + public function removeSession(\Rapsys\AirBundle\Entity\Session $session) + { + $this->sessions->removeElement($session); + } + + /** + * Get sessions + * + * @return \Doctrine\Common\Collections\Collection + */ + public function getSessions() + { + return $this->sessions; + } + + public function getTitle() { + return $this->begin->format('H:i').'-'.$this->end->format('H:i'); + } +} diff --git a/Entity/Title.php b/Entity/Title.php new file mode 100644 index 0000000..54a6a60 --- /dev/null +++ b/Entity/Title.php @@ -0,0 +1,7 @@ +votes[] = $vote; + + return $this; + } + + /** + * Remove vote + * + * @param \Rapsys\AirBundle\Entity\Vote $vote + */ + public function removeVote(\Rapsys\AirBundle\Entity\Vote $vote) { + $this->votes->removeElement($vote); + } + + /** + * Get votes + * + * @return \Doctrine\Common\Collections\Collection + */ + public function getVotes() { + return $this->votes; + } + + /** + * Add application + * + * @param \Rapsys\AirBundle\Entity\Application $application + * + * @return User + */ + public function addApplication(\Rapsys\AirBundle\Entity\Application $application) { + $this->applications[] = $application; + + return $this; + } + + /** + * Remove application + * + * @param \Rapsys\AirBundle\Entity\Application $application + */ + public function removeApplication(\Rapsys\AirBundle\Entity\Application $application) { + $this->applications->removeElement($application); + } + + /** + * Get applications + * + * @return \Doctrine\Common\Collections\Collection + */ + public function getApplications() { + return $this->applications; + } +} diff --git a/Entity/Vote.php b/Entity/Vote.php new file mode 100644 index 0000000..7b2fb53 --- /dev/null +++ b/Entity/Vote.php @@ -0,0 +1,141 @@ +id; + } + + /** + * Set created + * + * @param \DateTime $created + * + * @return Vote + */ + public function setCreated($created) + { + $this->created = $created; + + return $this; + } + + /** + * Get created + * + * @return \DateTime + */ + public function getCreated() + { + return $this->created; + } + + /** + * Set updated + * + * @param \DateTime $updated + * + * @return Vote + */ + public function setUpdated($updated) + { + $this->updated = $updated; + + return $this; + } + + /** + * Get updated + * + * @return \DateTime + */ + public function getUpdated() + { + return $this->updated; + } + + /** + * Set application + * + * @param \Rapsys\AirBundle\Entity\Application $application + * + * @return Vote + */ + public function setApplication(\Rapsys\AirBundle\Entity\Application $application = null) + { + $this->application = $application; + + return $this; + } + + /** + * Get application + * + * @return \Rapsys\AirBundle\Entity\Application + */ + public function getApplication() + { + return $this->application; + } + + /** + * Set user + * + * @param \Rapsys\AirBundle\Entity\User $user + * + * @return Vote + */ + public function setUser(\Rapsys\AirBundle\Entity\User $user = null) + { + $this->user = $user; + + return $this; + } + + /** + * Get user + * + * @return \Rapsys\AirBundle\Entity\User + */ + public function getUser() + { + return $this->user; + } +} diff --git a/Form/ApplicationType.php b/Form/ApplicationType.php new file mode 100644 index 0000000..8439d29 --- /dev/null +++ b/Form/ApplicationType.php @@ -0,0 +1,39 @@ +add('location', EntityType::class, array('class' => 'RapsysAirBundle:Location', 'choice_label' => 'title', 'attr' => array('placeholder' => 'Your location'), 'constraints' => array(new NotBlank(array('message' => 'Please provide your location'))))) + ->add('date', DateType::class, array('attr' => [ 'placeholder' => 'Your date', 'class' => 'date' ], 'html5' => true, 'input' => 'datetime', 'data' => new \DateTime('+7 day'), 'constraints' => array(new NotBlank(array('message' => 'Please provide your date')), new Date(array('message' => 'Your date doesn\'t seems to be valid'))))) + ->add('slot', EntityType::class, array('class' => 'RapsysAirBundle:Slot', 'choice_label' => 'title', 'attr' => array('placeholder' => 'Your slot'), 'constraints' => array(new NotBlank(array('message' => 'Please provide your slot'))))) + ->add('submit', SubmitType::class, array('label' => 'Send', 'attr' => array('class' => 'submit'))); + } + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver) { + $resolver->setDefaults(['error_bubbling' => true]); + } + + /** + * {@inheritdoc} + */ + public function getName() { + return 'rapsys_air_application'; + } +} diff --git a/Form/ContactType.php b/Form/ContactType.php new file mode 100644 index 0000000..e9a5ba1 --- /dev/null +++ b/Form/ContactType.php @@ -0,0 +1,40 @@ +add('name', TextType::class, array('attr' => array('placeholder' => 'Your name'), 'constraints' => array(new NotBlank(array('message' => 'Please provide your name'))))) + ->add('subject', TextType::class, array('attr' => array('placeholder' => 'Subject'), 'constraints' => array(new NotBlank(array('message' => 'Please provide your subject'))))) + ->add('mail', EmailType::class, array('attr' => array('placeholder' => 'Your mail address'), 'constraints' => array(new NotBlank(array('message' => 'Please provide a valid mail')), new Email(array('message' => 'Your mail doesn\'t seems to be valid'))))) + ->add('message', TextareaType::class, array('attr' => array('placeholder' => 'Your message here', 'cols' => 50, 'rows' => 15), 'constraints' => array(new NotBlank(array('message' => 'Please provide your message'))))) + ->add('submit', SubmitType::class, array('label' => 'Send', 'attr' => array('class' => 'submit'))); + } + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver) { + $resolver->setDefaults(['error_bubbling' => true]); + } + + /** + * {@inheritdoc} + */ + public function getName() { + return 'contact_form'; + } +} diff --git a/RapsysAirBundle.php b/RapsysAirBundle.php new file mode 100644 index 0000000..06f1b37 --- /dev/null +++ b/RapsysAirBundle.php @@ -0,0 +1,9 @@ +getEntityManager() + ->createQuery('SELECT a FROM RapsysAirBundle:Application a WHERE (a.session = :session AND a.user = :user)') + ->setParameter('session', $session) + ->setParameter('user', $user) + ->getSingleResult(); + + //Send result + return $ret; + } +} diff --git a/Repository/SessionRepository.php b/Repository/SessionRepository.php new file mode 100644 index 0000000..e295bfd --- /dev/null +++ b/Repository/SessionRepository.php @@ -0,0 +1,45 @@ +getEntityManager() + ->createQuery('SELECT s FROM RapsysAirBundle:Session s WHERE (s.location = :location AND s.slot = :slot AND s.date = :date)') + ->setParameter('location', $location) + ->setParameter('slot', $slot) + ->setParameter('date', $date) + ->getSingleResult(); + + //Send result + return $ret; + } + + /** + * Find sessions by date period + * + * @param $period The date period + */ + public function findByDatePeriod($period) { + //Fetch sessions + $ret = $this->getEntityManager() + ->createQuery('SELECT s FROM RapsysAirBundle:Session s WHERE s.date BETWEEN :begin AND :end') + ->setParameter('begin', $period->getStartDate()) + ->setParameter('end', $period->getEndDate()) + ->getResult(); + + //Send result + return $ret; + } +} diff --git a/Resources/config/doctrine/Application.orm.yml b/Resources/config/doctrine/Application.orm.yml new file mode 100644 index 0000000..aaf461f --- /dev/null +++ b/Resources/config/doctrine/Application.orm.yml @@ -0,0 +1,27 @@ +Rapsys\AirBundle\Entity\Application: + type: entity + repositoryClass: Rapsys\AirBundle\Repository\ApplicationRepository + table: applications + id: + id: + type: integer + generator: + strategy: AUTO + options: + unsigned: true + fields: + created: + type: datetime + updated: + type: datetime + manyToOne: + session: + targetEntity: Rapsys\AirBundle\Entity\Session + inversedBy: applications + user: + targetEntity: Rapsys\AirBundle\Entity\User + inversedBy: applications + oneToMany: + votes: + targetEntity: Rapsys\AirBundle\Entity\Vote + mappedBy: application diff --git a/Resources/config/doctrine/Group.orm.yml b/Resources/config/doctrine/Group.orm.yml new file mode 100644 index 0000000..57f70a9 --- /dev/null +++ b/Resources/config/doctrine/Group.orm.yml @@ -0,0 +1,8 @@ +Rapsys\AirBundle\Entity\Group: + type: entity + #repositoryClass: Rapsys\AirBundle\Repository\GroupRepository + table: groups + manyToMany: + users: + targetEntity: Rapsys\AirBundle\Entity\User + mappedBy: groups diff --git a/Resources/config/doctrine/Location.orm.yml b/Resources/config/doctrine/Location.orm.yml new file mode 100644 index 0000000..86d86db --- /dev/null +++ b/Resources/config/doctrine/Location.orm.yml @@ -0,0 +1,69 @@ +Rapsys\AirBundle\Entity\Location: + type: entity + #repositoryClass: Rapsys\AirBundle\Repository\LocationRepository + table: locations + id: + id: + type: integer + generator: + strategy: AUTO + options: + unsigned: true + fields: + title: + type: string + length: 24 + address: + type: string + length: 32 + zipcode: + type: string + length: 5 + city: + type: string + length: 64 + latitude: + type: decimal + precision: 8 + scale: 6 + longitude: + type: decimal + precision: 9 + scale: 6 + created: + type: datetime + updated: + type: datetime + oneToMany: + sessions: + targetEntity: Rapsys\AirBundle\Entity\Session + mappedBy: location + +# manyToOne: +# title: +# targetEntity: Rapsys\UserBundle\Entity\Title +# inversedBy: users +# manyToMany: +# groups: +# targetEntity: Rapsys\UserBundle\Entity\Group +# inversedBy: users +# joinTable: +# name: groups_users +# +# manyToOne: +# site: +# targetEntity: Rapsys\BlogBundle\Entity\Site +# inversedBy: articles +# author: +# targetEntity: Rapsys\BlogBundle\Entity\Author +# inversedBy: articles +# manyToMany: +# keywords: +# targetEntity: Rapsys\BlogBundle\Entity\Keyword +# inversedBy: articles +# joinTable: +# name: articles_keywords +# oneToMany: +# article_translations: +# targetEntity: Rapsys\BlogBundle\Entity\ArticleTranslation +# mappedBy: article diff --git a/Resources/config/doctrine/Session.orm.yml b/Resources/config/doctrine/Session.orm.yml new file mode 100644 index 0000000..9c89adb --- /dev/null +++ b/Resources/config/doctrine/Session.orm.yml @@ -0,0 +1,41 @@ +Rapsys\AirBundle\Entity\Session: + type: entity + repositoryClass: Rapsys\AirBundle\Repository\SessionRepository + table: sessions + id: + id: + type: integer + generator: + strategy: AUTO + options: + unsigned: true + fields: + date: + type: date + begin: + type: time + nullable: true + end: + type: time + nullable: true + created: + type: datetime + updated: + type: datetime + oneToOne: + application: + targetEntity: Rapsys\AirBundle\Entity\Application + manyToOne: + location: + targetEntity: Rapsys\AirBundle\Entity\Location + inversedBy: sessions + slot: + targetEntity: Rapsys\AirBundle\Entity\Slot + inversedBy: sessions + oneToMany: + applications: + targetEntity: Rapsys\AirBundle\Entity\Application + mappedBy: session + uniqueConstraints: + date_location_slot: + columns: [ date, location_id, slot_id ] diff --git a/Resources/config/doctrine/Slot.orm.yml b/Resources/config/doctrine/Slot.orm.yml new file mode 100644 index 0000000..c4ff511 --- /dev/null +++ b/Resources/config/doctrine/Slot.orm.yml @@ -0,0 +1,24 @@ +Rapsys\AirBundle\Entity\Slot: + type: entity + #repositoryClass: Rapsys\AirBundle\Repository\SlotRepository + table: slots + id: + id: + type: integer + generator: + strategy: AUTO + options: + unsigned: true + fields: + begin: + type: time + end: + type: time + created: + type: datetime + updated: + type: datetime + oneToMany: + sessions: + targetEntity: Rapsys\AirBundle\Entity\Session + mappedBy: slot diff --git a/Resources/config/doctrine/Title.orm.yml b/Resources/config/doctrine/Title.orm.yml new file mode 100644 index 0000000..d68aa60 --- /dev/null +++ b/Resources/config/doctrine/Title.orm.yml @@ -0,0 +1,8 @@ +Rapsys\AirBundle\Entity\Title: + type: entity + #repositoryClass: Rapsys\AirBundle\Repository\TitleRepository + table: titles + oneToMany: + users: + targetEntity: User + mappedBy: title diff --git a/Resources/config/doctrine/User.orm.yml b/Resources/config/doctrine/User.orm.yml new file mode 100644 index 0000000..4df938e --- /dev/null +++ b/Resources/config/doctrine/User.orm.yml @@ -0,0 +1,27 @@ +Rapsys\AirBundle\Entity\User: + type: entity + #repositoryClass: Rapsys\AirBundle\Repository\UserRepository + table: users + oneToMany: + votes: + targetEntity: Rapsys\AirBundle\Entity\Vote + mappedBy: user + applications: + targetEntity: Rapsys\AirBundle\Entity\Application + mappedBy: user +# manyToMany: +# groups: +# targetEntity: Group +# inversedBy: users +# joinTable: +# name: groups_users + associationOverride: + groups: + joinTable: + name: groups_users + joinColumns: + id: + name: user_id + inverseJoinColumns: + id: + name: group_id diff --git a/Resources/config/doctrine/Vote.orm.yml b/Resources/config/doctrine/Vote.orm.yml new file mode 100644 index 0000000..ee8e2ea --- /dev/null +++ b/Resources/config/doctrine/Vote.orm.yml @@ -0,0 +1,23 @@ +Rapsys\AirBundle\Entity\Vote: + type: entity + #repositoryClass: Rapsys\AirBundle\Repository\VoteRepository + table: votes + id: + id: + type: integer + generator: + strategy: AUTO + options: + unsigned: true + fields: + created: + type: datetime + updated: + type: datetime + manyToOne: + application: + targetEntity: Rapsys\AirBundle\Entity\Application + inversedBy: votes + user: + targetEntity: Rapsys\AirBundle\Entity\User + inversedBy: votes diff --git a/Resources/config/routing.yml b/Resources/config/routing.yml new file mode 100644 index 0000000..dd63f57 --- /dev/null +++ b/Resources/config/routing.yml @@ -0,0 +1,17 @@ +rapsys_air_homepage: + path: / + defaults: { _controller: RapsysAirBundle:Default:index } + +rapsys_air_admin: + path: /admin + defaults: { _controller: RapsysAirBundle:Default:admin } + +rapsys_air_contact: + path: /contact + defaults: { _controller: RapsysAirBundle:Default:contact } + +rapsys_air_session: + path: /admin/session/{id} + defaults: { _controller: RapsysAirBundle:Default:session } + requirements: + id: '\d+' diff --git a/Resources/config/services.yml b/Resources/config/services.yml new file mode 100644 index 0000000..9f2f696 --- /dev/null +++ b/Resources/config/services.yml @@ -0,0 +1,15 @@ +services: + rapsys_air.twig.file_get_contents: + class: Rapsys\AirBundle\Twig\FileGetContentsExtension + tags: [ twig.extension ] + rapsys_air.twig.base64: + class: Rapsys\AirBundle\Twig\Base64Extension + tags: [ twig.extension ] + rapsys_air.twig.bb2html: + class: Rapsys\AirBundle\Twig\Bb2htmlExtension + tags: [ twig.extension ] + Rapsys\AirBundle\DataFixtures\AirFixtures: + tags: [ doctrine.fixture.orm ] +# rapsys_air.example: +# class: Rapsys\AirBundle\Example +# arguments: ["@service_id", "plain_value", "%parameter%"] diff --git a/Resources/public/css/reset.css b/Resources/public/css/reset.css new file mode 100644 index 0000000..c59ac50 --- /dev/null +++ b/Resources/public/css/reset.css @@ -0,0 +1,45 @@ +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video, input, textarea, button, select, option { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; +} + +article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { + display: block; +} + +body { + line-height: 1; +} + +ol, ul { + list-style: none; +} + +blockquote, q { + quotes: none; +} + +blockquote:before, blockquote:after, q:before, q:after { + content: ''; + content: none; +} + +table { + border-collapse: collapse; + border-spacing: 0; +} diff --git a/Resources/public/css/screen.css b/Resources/public/css/screen.css new file mode 100644 index 0000000..5477726 --- /dev/null +++ b/Resources/public/css/screen.css @@ -0,0 +1,473 @@ +/* Reset link */ +a { + text-decoration: none; + color: #066; +} + +a:hover { + text-decoration: underline solid #00c3f9; +} + +h1::first-letter, +h2::first-letter, +h3::first-letter, +h4::first-letter, +h5::first-letter, +h6::first-letter, +a::first-letter { + color: #00c3f9; +} + +/* Default styling */ +h1 { + font-size: 2rem; + margin: 1.34rem 0; +} + +h2 { + font-size: 1.5rem; + margin: 1.245rem 0; +} + +h3 { + font-size: 1.17rem; + margin: 1.17rem 0; +} + +h4 { + font-size: 1rem; + margin: 1.33rem 0; +} + +h5 { + font-size: .83rem; + margin: 1.386rem 0; +} + +h6 { + font-size: .67rem; + margin: 1.561rem 0; +} + +p { +} + +body { + display: flex; + flex-flow: column wrap; + color: #066; +} + +/* Header */ +#header { + border: .1rem solid #00c3f9; + border-top: 0; + border-radius: 0 0 .5rem .5rem; + margin: .5rem; + margin-top: 0; + padding: .5rem; + left: 0; + right: 0; + display: flex; + justify-content: space-between; + min-width: 180px; +} + +#header h1 { + order: 0; + padding: 0; + margin: 0; + vertical-align: middle; + white-space: nowrap; +} + +#header h1 a { + display: flex; +} + +/*#header h2 { + order: 1; + font-size: 1.5rem; + margin: 0; + white-space: nowrap; +} + +#header h2:before { + content: ">\00a0"; +}*/ + +#header nav { + order: 3; + margin-left: auto; + display: flex; + flex-direction: row; + flex-wrap: wrap; + align-items: center; + justify-content: flex-end; +} + +#header nav h2 { + display: none; +} + +#header nav a { + text-align: center; + border-radius: .25rem; + padding: .375rem .5rem .25rem .5rem; + margin: 0 0 .1rem .5rem; + border: .1rem solid #00c3f9; + font-weight: bold; + background-color: #cff; +} + +/* Message */ +div.error::before, +div.error::after { + content: "⚠"; + line-height: 100%; + margin: auto 0; +} + +div.error { + display: flex; + flex-direction: row; + justify-content: space-between; + border: .05rem solid #c33333; + background-color: #f9c3c3; + color: #c33333; + font-size: .9rem; + padding: .2rem; + border-radius: .2rem; + text-align: center; +} + +div.flash { + margin: 0 .5rem .5rem; +} + +/*ul#error::before, +ul#error::after, +ul.error::before, +ul.error::after, +ul#notice::before, +ul#notice::after { + content: "⚠"; + padding: .1rem .5rem 0 .5rem; + position: absolute; +} + +ul#error::before, +ul#error::after { + padding-top: .2rem; +} + +ul#notice::before, +ul#notice::after { + content: "ℹ"; + padding-top: .3rem; +} + +ul#notice::after, +ul#error::after { + margin-left: 37.8rem; +} + +ul.error::after { + margin-left: 34rem; +} + +ul#notice, +ul#error, +ul.error { + display: flex; + flex-direction: column; + justify-content: center; + box-sizing: border-box; + text-align: center; + border: .05rem solid #c33333; + background-color: #f9c3c3; + color: #c33333; + font-size: .9rem; + padding: .2rem; + border-radius: .2rem; + width: 40rem; + margin: 0 auto .5rem auto; +} + +ul.error { + width: 36rem; + margin: .2rem 0 0 0; +} + +ul#notice { + border: .05rem solid #3333c3; + background-color: #c3c3f9; + color: #3333c3; +} + +ul.error { + margin-top: .2rem; +}*/ + +/* Content */ +#form, +#content, +#dashboard { + border: .1rem solid #00c3f9; + border-radius: .5rem; + margin: .5rem; + margin-top: 0; + overflow: hidden; + padding: .5rem; +} + +section h2 { + background-color: #cff; + border-bottom: .1rem solid #00c3f9; + margin: -.5rem -.5rem .5rem -.5rem; + padding: .5rem; + padding-bottom: .4rem; +} + +/* Form */ +form { + display: flex; + flex-direction: column; + border: .05rem solid #00c3f9; + border-radius: .2rem; + padding: .5rem; +} + +form section { + margin-bottom: 1rem; +} + +form section:only-child, +form section:last-child, +form section:last-of-type { + margin-bottom: .5rem; +} + +form section section, +form section section:only-child, +form section section:last-child, +form section section:last-of-type { + width: 50%; + margin-bottom: 0; +} + +form div { + display: flex; + flex-direction: row; + justify-content: space-around; + margin-bottom: .5rem; +} + +form div:only-child, +form div:last-child, +form div:last-of-type { + margin-bottom: 0; +} + +form section div.error { + margin: 0 1rem; +} + +form section section div.error { + margin: .25rem 0 0 0; +} + +label { + min-width: 5rem; + font-size: .9rem; + padding: .2rem 0; + text-align: right; + white-space: nowrap; +} + +button, +input, +select, +textarea { + box-sizing: border-box; + width: 100%; + padding: .1rem; + border: .05rem solid #00c3f9; + border-radius: .2rem; + font-size: .8rem; + color: #066; +} + +button.submit { + width: 25%; + min-width: 8rem; + margin: 0 auto; + padding: .2rem .1rem; +} + +/* Vertical form */ +.form_col { + margin-left: .5rem; + width: 10rem; +} + +.form_col div { + flex-direction: column; +} + +.form_col div.error { + flex-direction: row; +} + +.form_col label { + text-align: center; +} + +.form_col section section, +.form_col section section:only-child, +.form_col section section:last-child, +.form_col section section:last-of-type { + width: auto; +} + +.form_col div.date { + flex-direction: row; + justify-content: space-between; +} + +/* Dashboard */ +#dashboard .panel { + display: flex; + flex-direction: row; + flex-wrap: wrap; + place-content: space-between; +} + +#dashboard .grid { + display: table; + border: .05rem solid #00c3f9; + flex-grow: 1; + border-radius: .2rem; /* marche pas sur chrome */ + table-layout: fixed; + width: calc(100% - 12rem); + border-collapse: collapse; +} + +#dashboard .cell { + display: table-cell; + text-align: left; + border: .05rem solid #00c3f9; + font-size: initial; + height: 8rem; +} + +#dashboard dl.cell { + height: 3rem; +} + +#dashboard .cell h3 { + font-size: 1rem; + padding: .25rem; + margin: 0; +} + +#dashboard .cell dd { + text-align: center; +} + +#dashboard .seventh { + width: calc(100% / 7); +} + +#dashboard .disabled { + color: #acc; + background-color: #bee; +} + +#dashboard .current { + background-color: #cff; +} + +#dashboard .next { + background-color: #eff; +} + +#dashboard .session { + border-radius: .2rem; + border: .1rem solid #00c3f9; + font-size: .8rem; + padding: .2rem; + margin: 0 .1rem .1rem .1rem; + overflow-x: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +#dashboard .pending { + background-color: #ccc; +} + +#dashboard .granted { + background-color: #cff; + /*background-color: #33b679; + border-color: #33b679;*/ +} + +#dashboard .disputed { + background-color: #fcc; +} + +#dashboard .orphaned { + background-color: #fc9; +} + +/* Footer */ +#footer { + border: .1rem solid #00c3f9; + border-radius: .5rem; + margin: .5rem; + margin-top: 0; + padding: .5rem; + text-align: center; + font-size: .8rem; + display: flex; + justify-content: space-between; + background-color: #cff; +} + +#footer details { + font-weight: bold; +} + +#footer summary::after { + display: none; +} + +#footer summary::-webkit-details-marker { + display: none; +} + +/* viewport responsive hack */ +@media ( max-width: 650px ) { + #header { + flex-wrap: wrap; + } + + #dashboard .panel { + place-content: center; + flex-direction: column; + } + + #dashboard .grid { + width: 100%; + } + + #dashboard div.grid { + display: grid; + } + + .form_col { + margin: .5rem auto 0 auto; + } +} + diff --git a/Resources/public/ico/favicon.ico b/Resources/public/ico/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..fb6658823f2f2cf84fdbd5b3594550c51a3f8c41 GIT binary patch literal 90022 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 literal 0 HcmV?d00001 diff --git a/Resources/public/png/logo.png b/Resources/public/png/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..b57be8cffcaf2947823b272bc84927a963fb655c GIT binary patch literal 4297 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 literal 0 HcmV?d00001 diff --git a/Resources/public/svg/favicon.svg b/Resources/public/svg/favicon.svg new file mode 100644 index 0000000..1e196c6 --- /dev/null +++ b/Resources/public/svg/favicon.svg @@ -0,0 +1,95 @@ + + + + + Open Air Logo + + + + + + + + + + + + + image/svg+xml + + Open Air Logo + + + + + + + diff --git a/Resources/public/svg/logo.svg b/Resources/public/svg/logo.svg new file mode 100644 index 0000000..159107f --- /dev/null +++ b/Resources/public/svg/logo.svg @@ -0,0 +1,228 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + pen + + + A + ir + + diff --git a/Resources/public/xcf/openair.xcf b/Resources/public/xcf/openair.xcf new file mode 100644 index 0000000000000000000000000000000000000000..ebe102bf9656fddd8014a91f4693c3bf68e00a61 GIT binary patch literal 30224 zcmchgcYsvY`Tp;nt=Nsx*hOO@niw@EnqrHJNbkMF(xn$GMMV$`2nb3MRBWrFf+C2p z?3AU58VuMAh*AZCWp~QX?EXH_d+sclZ0(j|5X^2{bAJL{v+%5AKa^7 z(FpMm>CW1`-fBC%B5H-9CgU@2D6MW{)Q-i3E{vE?B`}x?TJ|B0~ z=i`t1d?KGEH~X)E4_W?fC&=0YDbzZsIG%UCs2duDqu20R|HivlXfplg0nfX%spnmP znF!-f^1Q3O%INBFEE&+(=sGbs}k4ybHWcSrlm*C^?Y>qPXhz?$!1DXqH$VjTA(xOlT-_u2(spn$i(P zhuHnd&(50c?{I|Ribb{jNOd@pAF0S{h(^3Ky-X~O*2A)#|Muob;;srjAv4uG-Ak2N zg?!06O5dTNrZd|6jaMB*g+k%1+HbYZ9GNQCP~jg~|fag%*@h1S60em28n>k(l=@FH@S8r}wPI_^Zl<06C?x zXlV)4N2VrBo6(3+)B;u|6!D|!NZA%*xO+V1^aJGEFTJZ~R&2~W$EzAIVqwIZFo6y# z6np0)yOj9va{|KD33#nZOKWKUO0(JoA0s;vvxZJ%T__(T4x&khNn<2h1}RTkT&%*8 zJjE=!%KNRCkaY?|VWcu(39q2sbw9$JgEUn#9rP&F(_?k*2OLJpN4$5DhYm5omn$j( zko6EUD6!_sadzOXiS#b^4$1=R$yCXefDB{cV)~&x-X~JFg8Kk1JsuVlruu%^H5_s!K4!g5&1-3|x+;?^!K1vu2S@W^gbSfC)PzO@WIK2T+v=j~}3y&FS z&L-khx)KUu!wtr}inA;c@u<7{>hwXeJ|MhA;^aD=EeLWzG149<##s>%n9Y9Yr4(36 zJme(0W{F8!F{MPuk662A^~E+qV?4qJ#opzaxWmX(cMLiR-Kth56cd%5Un*)TGD3YQ zkf@jjR*K?Vs1I83OogbF?R&NpJzP zE2Lr~CwabCRi)BUvK%V4jUkor6Zy$=5tB?wj3Y?6pD0Y8<0ax0>wf{#`AH=b$vVli zJRjLA&P`UQ5SgIdXg;Q+_zbV22F`#tHyKZ1wQ3}-LS8bIVtKt{%X4aT5~q5Vl`^c>Mp?o|9qdTuq<-xsM?&<^?uaRVkFL zOCp)Ag~>`;&1YoL3@PkQr)s`qK}rxI(^4m>V;3QdaSaPnl7^6wkRlLDR&XV!WK1aO zr)bf02#PdOVuf-)N&I~pEuE^WVP#6va&q99WO=}=w$h43z|GG*v|F?!+D~Rul`KAL zEuTIixyY1Jgo*bIypYwYjF^)=R2ypwII+0U!X#_CtkKF~>17#GlfsqjjLh;>r?hk($hLjC*r182QmaO7uP|vYhH(fP(+D|_0A^rN zi%_1fL5Eo#at2tvD#U4h${;r%1_jncrxQdW;Bo{8l{Hi)>wv1$W{Q^cik703h6vg} zBq?;baxF8prRJOU{{%Cy4Fg$Z11HzwPVE{eG$~V@9%-h2j&xaZTJZ|e{>1eXMy`d_ zk<7y!WQn7?lBh~fPzu9-im}UdstF|&OCp$f5i*IxP;!$w)^hT+T8opW7iNtR zt!ZURrbQ+Z=7bEEQYocMnq%~tFxY(LC)Ba((J4)Pon(lD1gzB(R;|j&ODJ+Gj3+`& zCb{Um)T1#{G>>#-Xf9?o8eI&SX5LZdXF^gS(HN^1|DC7C&qIQkBr-!|7ob&hpj9YH z<}-@uxTsU}=gL}WD#(XMoc7qqJY2KVP_i(knSdGDs>)oH#@%%&nV<0E1iwlZ>QEE^ z(|n|>Y4QzG5=vAjDG4PdlZy&2uJR5Yf5{E)hfbP4f5D5dzVR;8_)npFZO6V)_OFjN zu3sCAl$NYoxqKP1+kIityp5lK`tMC2f4E^?Su{-fig({x%HaCZziLAC+poX)Y|AGB z)0)-qzqfqZ+e_YLFmFF=)Y|X2e)HAmpKcCVB@)&pZ!Ug~iDKJLi?;u;?YpnP{Cvy5 zk7j>o>058S{^~2tLf?j3tlIVC_O0K3^~GnKKl%8>4^VG1q+#)E#V^0e2IiX^*X-H( zqf>;98#iFP%)rFA-cX%I&oSwJ_4{}B?%rYQ%-Rpu2cAe2+Fp9$`DYifllkJfNxS#% z+Od6`+>*`>>j*_4&QvaXZo&My>}5Xx>xcXH?5b64K?|?J!CHyWEqrF)oToq)J}r27 z|4(~%{_y>G-#BNby|jc-VWWgf`TV(0&wi2}&6acC-~W>{^@s&HwBp^s(nXR>-5F1? zquG4(*8Q?qF;bjqx~QyJzRY=VlIKhrF`!3>R;(Xi^!iCgZ&$M@>RCew)|-oo!lGyH zZGH7Qg{&f9`}hC6Pl3f|MU3DpuC(9VOWt_B_~of>>g5yH??O|5{%QA47g*w@@MrZe ze(k9)zoi+shGsjDh$%KIQuHFV5TSqcx*V31ZT=JcX&1;pr+XtCmK!9DVVTI!RdapW=e{8TP>x(loYrxF&SV4Zg;5%y_HMt8R zjf3vD?mAY~I;BwQsAjygj86JduwqI zNIOF-AesM)u);@l7Ej0#TXT_UM>+^yk7is(gU>lpq}+%|3X26@*1!3B@ik2HyW1H> zA#r}G!HP#g*%ewT9bu&(AQPP-(4x!ecDYFKj5DYpoS!*b&0K6QS%G=e#_cFn^#} z{8i4$TJ6s-oIm#pQGS;tID=ml;jvr^>vfd#*ek+Q9htlL%yKcVWq4-pQ%{<#oHc3} ziPB`Gw~e%yZ@Uis2-M>8-^_mrv>;!o|NRpZUb&k4&D}K!ktPx;B5# zY*&8&)grWXO-Cqd%g0?LLf>B)`sl+CJuv>h(?z)ZXa`*R-N%VA@s|cYIAQEPqkRZ_ zr~JZDmESpl1#RzCYl0(s@4ahuZb=QUm5>``9QOIku*O1*#KX6C2M|{f((GLtMpZ4ErU;_N?J3-kt4jbH=I~ zuV9m?Z6?L76qhEWh7TBU@d2VFbb+0aId&juDdY$B1Pt zx{d|d4{rtAgCkl>O}5BXpsrPo#9#c$yQYeDr2-)o`eju@<@L;#i%;EY6Lt03-tACDlz>m=flLN7pU*L&)eYh<#~#L9nx zPPnq@PkKrNZxa)kN1gvoQ`9g3SL&L|j{>);yBwG^i*s!DYMN=Q>ulhBzn` zh!lmevog@+s;$t6OQCQbD>Zo~m=L4MWptLJkqpx+W0EXtTVn*K?=D_v^0O4zt=2H( z!Lvq^97~uE8N)(tigp*5MoNjWQ={HWFNlpI4TuyYa+L^ta57w(;%=V%(Vr};7NbBrIwVR% z+YFF=Q{nt8Gbd`TQb5AiQZ=<@XcdRvcOPcm=y{ur>i7f`!c6-PQXsRSaw!@wUwB6xpr;DdGA<}Z zt5l*UUJ*wdh=*SZI2tFif+dLq_c0Ia0(9skV@k0GWh&Ci(}Zk*)74a`lcx&sV5!+t zrI@7klNRJvX}@d{N+og=SqkCU&l&@2Bgg~nnW||x({cI=Fj{$4I*|`W7;B1-RRtQS zYUwmRiZTP$4pk)z!F;e)eJ@d=Hnm!X^q5NK*c3G=%ab5tTbYc<1+b-RDiT#yNXw*! z@Hp%%T|*I#m<}Zf0fB|T`fycF6|fW4{A49g#c3v#K}l8lP|O^`eVMq!#ME@OAXcQo zl0w$LKv?k%X5<1tC6EASEfE#PW*jwz{8>{~Fr#GRSv8HtmfkMVG8M%v_TG$utAoHLjbJD2;qz&gjffc zAqY|9P>dLp!eu!W#*}1-tcy}sDdB1$Kb>RPpT;4WH#KVzkw=8B8xr)Sv!v3rrBhg8 zV-pBWzE{_n2tkDbtP0*GOAG^5UxkoNBSod#9U4iO(Rc%q6T-@jW{sUo)x0F%+v60g zIc>~f08_vYxHS``G#Y{DWIr&fkL_wB1e%u>HUNmR?u=9$r-GiT(G-aMDmf-E)4G9> zCkqsmOI5=}TR%$3q9mgs& z#X%2~hu$q-G-vuF6UKCJ_?PpKXR7|`ZHK|V1bDV^!R&jx-dH!pY`x2XIU#Bbfve^` zHT%h#j|{l=ET7@W@`BsokG)U>60f-eDHz$A>ViJ zJ$K(-^!pIg);FqR$k?>UCI6v`4DjYp9;s!5f=VNX4;wag$dJK<@3_}|QUVrp&0`|d>^I!6qbusa3~95`S=|Ni}Q`egvc*tbw~%H)TL z!Z_6&Gn$ISf_nY?_3PWWkKZS^DAV!;X8&!?TX*W-d!*I8bIhob(u}|Xs@JEesJGv{ zpjW2L+06bs^G>UGUB_Y6K$I##@7=ps&z?O(J#xE;dStrQBb0k{&iqTKK?5DNSI-_j zx_9r^t!rUdzgwpJ)wIXKQ~uJS2(BL8yLIi_rAueOb6%%VXTOWzHFK@tx^n-##*n&n z?$oJc#}0)Z{EmJnzjM0F-+h`p@tc2k>e!(}`*wc2{I;QXe*0vHj-5JnzJ{KXJfmUT zwr$$9E^O_$@!KZawTIIAPY|j?7dC6vvan^SRYmJIZQ2^)5-kbG{j+&N^H2-FWksvj zt=p))<5?;XUC}hJX{edsyu3xrmaSUD(xGEJ0bZH94IBH7LrwgqKGef4jM%0b1Lq}a*vM1Gav21t0uOul z9YA8=sB1+y-I6>%snyObt6RNYe!Z5xs)BE1r@j=nRRI7jQxC!@BzULpc z)dvkR`QsmW=om@*1NEJ2LH+wDPPQmskd-f&@4RR1ga;>0`Mo&Kgh9bmjKHD9 zxlV*%9dS9!@K|%R_GpIt(ERYDQ+tZwcRbos33~jA!E&RGMdFC!$EM8~t@2j2dIK@j zpOkxhTORS(NtrqOL6tYR2B@`W+KgFGKdSO(f%Uago|^Y0UK&?R?lb{zoZWSjt_lg>BijZFfJa9~5a{rXPD# zxorr4QA)ZL&58UY75OB^`XVL(FG&BeGDtBnDMAegbppH0e$WOHD7UIHuH~VD5P>Lw z9W#ew>5GQfi-T>yt7>I1p(G{(h>xo$IgY`F106ydg8C=~zfm|MKh=tmTK3@K=rT!S zM+rqN;#7UMsv-nsfiS9&2PvEYqiV|}6J(&2oHxc}u?Z2;jB|j+Mq@F-Mp0nU8IHa$ zLWx>H2FNwT7$8a3M#ad?Hv|VS*rMB)_L{IC2CbDAWMP-~=nnIc7G%K+USYsQ8F&!V zU{`%p<+PWT0%b9WD)A4*MA?MA$u3wFVtC}8e$ie5AzCaRK`dZEqG+4WPi#$iB|LtF z?nPw^vIGPe4}cUl)KUcQ@Po8nHHIDX%hUjN3fL$sks@JNz=t@9yMe^;I>#gpPPee4 zHHL;50%y9jaE*lsc~RkZduxPeKr)~C2!9OFkxd_~T?tSY|Aiw2rj|jK9R~;n|BcN^ zel!(<_#SNg1?VUOqC*7J)X>YU6XbVD$QOX1eC0*nrhr#@2r(2rOvf=Ar682mFe}BM{0<6<*mS%k#qtp`B5J|634WqNH*xERE(y{nAQn1#Sl^i?fozy8 zMJSRR%Z=<3L`w@$ZoPo68jh80tl_IxR zl7pTQGnZyB_d1|(x|nJ(Mfu*FA)8p}J@~gD`JU!g5S(1aLkud?f4)&8PB1)iqQ2o}MmYr1=rDfDs{sBXkz-QOE$R=}bW^2?L<9bY=A}DwsZ}n%`!wnAlBx zLxVEtTnLUBDH~;`B=U8-szwzQWt%!6xB$6o+%J(Yb-g&#f;^L56=sx^5{g)!WrT*e zdn*#9LGOBzz~tW(fPzm*l#V=Tp)xy7i_5addt4I3{b=WEp(IV-Uw zq06Exy~>TzFf*BB@S@7K$pdEr(MVaANxo83lx0E!&81$RC7T2!+jA=SCA(p*q8i&( zT`NJw@HSls8(3wv2(xn8HmZtXAS{;!lOdmnRGq5)R61UHfXU7_)1j(dvR}Z^sHI&# zyZX2`>$wPJC$EJP^hhZ_$c5ot2&fECh0tEi|wxs}VBOi~riAqNOJD9-AF zBO3ZZ#u~bOYO{@}%r^U$gePcGDLOgHP};JJswxE}8h|KEl^kXI$f8vGn}labECe`7 zn8ChFVN*~ggW88>oq!Yr?0j;Ba+J{{lT9utWJ+KhAeci8!Ing!y08(s4-{rL$_!T> zPe5d;#3iEQWc*=^8DerkvcMkcF*O2t6esfQ1n~eO3Gjh#hzxmt*-}*}1xp@*3?f}< zTgGY&HpIrfWCev_wTRKWj8Dj9C=J% ztRiSatAwhN3`R{5(kd_}Y!Q&Fj3+;hmkH1|TWZoZ^d+)W!Q!Y5Fhg)Ev<6il29yDQ zP6M;~Rnm3{DP&dw@Z}o3g>@BFOxIM#Ev>7Pc*q;fqEvWiL9!qSHu9>#mr3xlW}ymL z<(A}el=x~@%P3UlELf9%DOMz_v0TJ|oy1^+LXikknFenLK-B220x`{0?O}zet`USJ zbQErN@^l(6E)Z}>q>mFmOH{!M8DBM87itVCJ5~TvoPkA1YFG*~HI+iX;;A}<1PQrN zWA#g=c?u7tC?{2E@AgZm7!bE5`Nl!)SqIQ)FtW1u)cXZgsjp%gFf|ZyT1&vs2Fj}k z(nSO)5-HN-sx;WDXb^$nn*Na{B+FoMt96X-9Oyj#~caushhJN(v5A8`1ghPQ)BA>%w##f9Gfnz%Y; z);&=Q$frJd*wSQ833j6R_pIP_LB6f3l$}*XmloTmc`OoYlyJR}q4HNGl=h77h zG-le}J1Zzw3dY@IMh+W1uwPS^KkiaOYLgxY_3xwnhP@AEGd!|V`u1+2^06lTC@Dof zTdI7F5>Aem(yM!G%J&Sl{E=E)`u6V8wWIBpi;l{`z?h<*-8y$DWQN((@;~Kt>D2yY z5pEcP-3|hFx#W_&WzD=vD{_?>Oedt5MAPfSWgnKH%e>cGLq5Gl*Bsiq)S{#ga+U34I11kAaLiooe|i!bwD#B z)Z0#jw(q)59ox5S<7hB8Y23I`s8OcDsVp}8^P6?*fJ_mQ+N^2QCVrDp<4nVIARaiW zeaC<(YV&4(v%IF6KZaOi4xQf_QadrWYT2@d-=d&-<{t$jTpkeGv=*tLrQa&k`LN!UA;Sb&(R2)6#&b#lqkD3oW_|PQPoHl*tEH*G-6#f%oLxv6=X7Z>eE60w{ z)_Yv_o|>cW%Wpai8!nxgM9+lCk z5q-h4&%f{z?Y;fvTSh{Z4M(W+jrz)~EPp@x=QX_x!Bd}@KGQfwTlC_~#jh>aAU^%3 zK2vJTpHum(ufOpYJC~pQv##rS*USaaQuxvPO{3Lyn&fR;?t- z2cO9D>ysFSGwrK!+MIf~_wpl`dizK#GXYs9F8t`F-T}!CDx1<^>&X0X_5YI#6?+V4 z`42XSu(1_1LwGYrEDL}_2{VCNCxCr)3{7GJQSv}9so3bmVA&By5h?^y1d_<%Gfo`} zgjAVTP`j5Evz^%kzaeo_;sIr}Q5EA_dceV@APl0^iZpVyb`pn7mFZW7K!gB8&Qk{d zIRZOd31#t)Cinkt>^6*YGn2X%o3Tgysv<#)(%Gz)6eS^L1&@+V9g^~ z>=$P=RV9bazVS@pKYykA#%22Cv>)Yci&^G$WzRu^f08S`EU0e=yU%!tj=V^45K__= zGr?Sm^-eZLKsv!O*J^1_y2in;AR@tAwX{?jjF|Huq)b?cXDdDq494u*8W|EkFZO;` zo+3lxNCgrD!{ec3&rs*cNEcbPE);jB(~g;As;s4p`4JF0hjFOGsld#`f%jQ(fPAdf z4%VYC3SzL+;WT173#C1+GhhA*$!>OFE(j;uLd96d* z2w6>RP4l&fwiJ{&TTjpgJ6ouNbjCKb`Cx52G6#YN*2FG5ADAsuqpfv;4!Z^DnsW1U z(915Le3yiwJ_W#hFbagzo}YcXDl78`3`R*eI-;md9XtP*n<7)oB_dgJA=x>3I;y8F zJ$YT)_`2*Fb1H}0UBCeBn{P3P1b`@H;8H};Q8ST9rxHxTNAr7#$kN;>fz5DN)z zCRN2CKS;Es&RHUjd;}(Cp&(*p`9VOSdYytVn&7&FdpTAe@QKQCcX^_&dJY2tZKT?n zHqqde5IE1Givc)cUBC@AX`C8PzwxSm2J=JJVTqPalAW&_;!m(JXu#<-YtT^Epn;}3 zii8aGlN_J0@qa)j8`&g@B+>kr;3R8-hLX?dcda3X$0`DHNZgMR( zUo9?zB6$uO%DSmx!`SQ>39aX8E)_D*u%?x<=~zty7jT$alZ{PJ!HlB;bD{DFQ()ez zN%AI^BmEMOj6CjyWDaZgJ_O8&(`s=gsA}@w+w4gC21yh%XV00xaG|yst$&e3G3)7h z3!a;+@($T75OOgr&*9lcvsKu=sA!WsXemhz=VB3v^50m}?Ar=;MG zCGWHl;m_Gz51b9km;YUa21nJG;*x-uK_-%f)bFwwyS~ zpk*uGFPS64?~tSPkfX}OqeW}?<4Z)j@+iW40b!K@zdeI$ zMG+0h@yS@RoG|yC=0A(l_`e97HituW)7=F#7dby_SvGC{>`w7CTJ(}N-SR-m zM-aX^-*{%dRIEl_zS5}|<;z9lX_5_AV3!Er)Q4x+DGO*03!}5xD67qcJJnDYVDtVH z@oa4;roX+aCbS4EE}v`>r7Vw?W7kRZ7OQnF#Z}d4LY2hNrwyy|@ zt+)CXq%fopMfwWTk5`Ly!y8NJUXWst{w314Tet6+CW(J~b;&!5PdK&?(!W22v~By2 z&8M*3?EGV~Y{%c&x(_~r_64*bcI<8<+U3P&Jsv~b1np~RJ9p23w&S{2u~FvZ83Ba$ z9ke}Vc39bO@65yloKvj6{_gu9ckbCPTLpMHKhk7@P0oGS;vu=p)Gu7FvXo&9+C)6Wa?n3TUc?y8=1L3jdH z3Xetn%WurfeLv60VS)Jaq>KLEQX#Y<9LhF#~u_fY%G)OpEE2<}eMYE@8H+1%KMV@iJDpPYq;q zl3xRpS|;C}A&Q<%HpgZi%Zm58$pt3^zj{;N5opDL7FMrOU)!~3-Dhso348y^ zWMaPJ_OA`a_jkNJN2}W z65y0ldQ@7#h0q7ftkQush`xvZuv04n!&sCmdVGQ$MTAR5hH(Nm^1jbG@o%;k6N}!LVNkqbErU&RHkI5l{`>0*YGu}l+jG(8zo!zlU3&B z>G_KV;1v;iSh*!y3TrDR$u1W}4Fn@E@>}olI`YnxoJah<9HFPuW@2Z4Wa>T};9rA7jvX z_c%ZZnuAzq!WQ);LS;}1KZL421uBK->%_T?Gtg!vW<&`fk(5P%#w1GuO7augC`ArB zEQJyxDHZ1=LIj0Xk4WUp2)>C!k&{sS50(gJy^<8eg4D&zZ_$(zxqF4ovdcAMa5aQX z?;$VM^;6z7O7uU%H|n?$M)hCy5-W7&pyoj>rE(?A2zmnys8BtP3d6ZD{74eAdMO3` z!u*)s)i5hnUtKz;tC(_`_eh9r3G|p9f;x5=2gO-CO`M+Cx4Wd4g%5I0$(ou&b}JFp zi3?%{6I}y}ESDC3m0_8gVQs?rQzz%~e@2ffH;@4V+@YX{cyM8qTxM7iMMo@MMhk1~ ztA!YKfXPOnJ7jox<;7k~sh1jBzJiK%h=U0FZRPyZgZMme88N`z7;?(!j0wZ*q0;#` z(OF4|V>siEBLk^P4H`8JG$BE<;X)c-IKWqPJ&wFXVT^~@=y|OSqXOm>hE(|~Ot+TQ zSg7k&l_?l{{w71Q+@vWsvFHkhYACG7Zb~6doevC4WpzxPVW5zXqGxGl2MbjSyhGS( zQ>kLKQ9Ig=IAWpIOjQSj0a=pBD^mIv^G%Xx_(-BA<{GA(IM}f|n<9`|vyOFwZY6Qn z3K^2XkM$B!bsU;oV~?cFmCS!Zswlo$>|#ul!p%$RuEBH`1C%^oPlr@DQ?MA1xXPp} zN2qsDt)Phj3wan1;Yycmh{-a7oCQWpG@F-1Ls5FH0)YtGMpv%2(Q0e5uP$TG{n<%X zJ&aR0-5TW9E4zx0*K$a{vg%li;<9S%v97R~`wF1$_mmOV11uh<*94+3d-K79tpJ>t zeWd@T^n?UtKQ)?h2~Q!FwFnWi)cE8cKsC6`x2$3Gy zC~-nWDlt_+i4ZU4Au4(AWG_`|_@Gjj>~OfU&~oj>F;bPQrgSrMJa^Go46~CI;8Z~- z$0_%UoJK)68BC*xRhlw^QbJO&hllrK#4$?#JXXnG0&W1{uo%nSx=fN4`E-e|7y*Wu zfr*JsC{JgJR&JP|RuG`$FL;`$@bW-ps5wNgPy{d=ARD;O4$9%FVeArr0)t5kJy~~_ zY-R_Us~Gsg&;*x*M^!Q@@E}FSnIauG&h=!bno<11j#73Km@CpxldQ+p6;vhgRzWA; zoxy}NPM&B;u$IA%cny}w-2#pzOSk%r)?;fcwNElt4!L><-tw?TQqlNEsSt^V?kc8L zZUpEv8FvEJz`W(J3^k(8-zu;=91N?(xU|9G35J6A4&WPLEFD>*6IJwKOG~VT3t9M1 z>ndwdC#|awBTqSqlB*NByeWy*!1aSVXl^w6rI{$;Oo^g#PR{BKv!xIUXA@FJ+UBkR zUYEfVrA|bXXcST3dLPdz#Vnl%Cf3}BaK$1SC@AESVta6biZZD*-B@V66*~*b(iMOx zQ|+02WNvEo2>6$1Yb-mjD6m&XC9@1sq-XkM3Y&RK4^E0K*6c7y(C^bcdBC_e%W%ZBoIWDS z)`mG=mF^#LFx>73UEndVicIHYKw>cwCXLtfgL#aB1r92_aeZq(Y!jJLNi5Rs42Fvu zi=LUU0!?PjhDrlI+e_?a9urvx;#h%KT}}-`Opm3;nHDq?&+uaG6lx4>HX)TbzE{h% zJtac=sX()8<4|E!Rt-x-x)SXm%mhshtZ6Q@R}VSR4EZZBS%LZJw>)!Ak)%djXvh~; zHg6RvyT@TP_t*5$UT$Hq5!!2y!_*|r^h+Bh;#J9V&C5R17X#cRvJ&Y7o#|vR^PN^0 zHHvv#kvTfnkBj zwxVUc>*2MG99tEgc49;o0#5uiFIoHW00EmekRHs$Y79*>%8o{bh0nSWW1k^I-$1#> z&%OiJtQtndp3g98J>GXl{Q(nZzx?K#@4o%QGtsQu$H4X4JoY}&XkQnGT{ zlEuX@J-<*7R(qh!9}7^m?aG;7e)IXiKiUv0eSi7eZ@%{OBB)B5oib_S*w$xb>o+$p z`*G`6pKkgP0q-q)>-AS&cy|8Nvy`(-R_fS$@4mC^`E-{rE_`v<_HVz~{I3tn5VZ7- zS6_VYnK{&QNw9a{IeH|gy_=rQLj75X?K{7h%Jor`hsL?HXH0!`@bpM72@F$ui~iw;dhN)GwgP z_nx(O&yQQb++t?DyX5ufhS$HK4qfC>!5LRI=}*3BksSvQbxU_|aV(u`|HYek|A5&a zZ@`#$-kfw@A^k3%``gAnx+y0xr(;#8&aF~k4QhmOCgNt32co9U2rhnuK!sQ->_Uw!(o4`ORpzBBE3!h0z1Z+80H&e_(}7wb#5 zZvAS@zc$25-g|rc@r>w0d4JcbX-?v{Y2V>QhJ5)8!~wrnuUPuRS+ryMF*nuM@!=M& z+jY8GU+(|8^~=p4uaB-?zV!8LwAnuGmiinPZr-YGr*3BxvcpTi-2Bn{$m-=wULQe6 zIehsow>50stR>WD+HzlQ)K$xuy!O1Fj!<5BQ~leG+`Z^@ZMmn3dDXj1UVE`SQ{mxy zw>D@b=I(v!YlT1Vqbzm7sgQRZb8Caf&04kV+_P_g0HlT=2doQ6Fa__tx-Hus+H~wzG+<~G&s%{rBF&w70<>KP4V$)X+qp;IJBHuk zohj1mFFiZ=$x)1n-PbomVDJ7zM%{DbEhQ_K8ev*XQU2JXO{X4x1`WS+>}5UQdwcQA z&&``PZOUInIX}xX;g(TvzwyfR^JhQt$V4Ue?mh(;wA?xN!L|<@Vfv#FjXyz@W6?5T z=;(XzpFH5HS6^80lnD3O&6J$ZJ^KwFdH48-9=&fK&dhv#^8NP?VIkk!$&^1hW!j`? zuy*Rh58OAVkCi()kI$U8Kqfsn_RitmRNmQ1nGQB<;_n_gxRc7e$(||GX3t+Z-Gq-G z+P|a9`;NKqfrqC)IrrK5lc!BV_^^RR9Vp*36eAy>IcMREbH`#NQu_7mWGC`-?wK&@ zu^CSwm(MRorLw%pL%9d@tc#|%br1fdvt1}IcN8I6CZhE_Wb8x zdE=c?w@$cc)R6wYy0&jsSCng}Oq(_DxtABe{a%khh@}rKEtKWFyA_0IUwVD%ijtd7 z77JQhHMciyzSP@HI7ETzI6F&F@O0MqpbYAZk^h-YEI^S{aa4cDE!-E`MLh%EnjZE zNu#uWr*^GdG$S3p{!L05E&0zf9JiD z*oJ>?`D)wNOEgpbUdIKL9p0$nKk_t}9P{Y1m21jA*!1bw+jjP6Wk2ZOtW0@J>TdGS znm+8n(0#pSEQYd`$t^KZW2 zwf+?C!jEs&ksR>0ZS+`-bo(1lWRg5^#+bKP;Og+_J0(4IXNb3b=pFs9__=K0NO^9w9AT z)_wTNXJ2pIv3K#Wn4dqrw1|A_JE%G`xTXB)w3$!MTe#?z*Oy>TREB@^{mxx?g>dpSnhPtO^6bn1-RbDnwbCB!aYWp;dt;jh&r#^2QKLe}%x3GU$jtU2?aeL(`> zE0Ok3G55V&Xv}SAwH`MyxCcCc;i8vcd(#AM_!ymE&$)))@?-wxohEQAn>)&=S^Dlu z1Z>>2B{sduaSV)oCtuaP&%M*;y|{Gwn{U1{`+wFv(_DtMhaa%dQ?`xmU*LiKnlSp7Itor--whmUpW>=d= z_OEP)a1R+<@lLrYGdpc{*LxfSsnW+(1aM|9m`LEF+S6&mvG=$n4Oj8ek%w=l~ zCZqOLBjs^EqDuIZ!W-AN7mKu&uA$u#Kxq~lane$BltaWy9Y-cm-!LDBgw8`(Pz%L$ zkQ(cJ2Xn3&GUK^d-YTB;z#WY*4AHpzP8#*WXCFmZE-ik3F5m1P7=C>rBKLOv?Ay&7 z*1Ws;h51iDK56_tqlXVEx)c+37R=xA)uy$pmOeYU`SpLhx#gh2oQ><*^QIj2yuvqr z_~N7JdyikGHMJsiPD9RVweNUK4p;H{-+#6-{Pt~H{1bKU$v^*4c)D%-^n*2vuh3-o z>-vqFwrtN?U@vjLoADZJ_Imns+Q3cKzg~FVCBHk*-f` z-EH9LPSanR|HQ=ObX^GfzQIo|m@$d3)4%c#=k&Pau8HI3&6+ZHu%^2{qb58yW5#0> zM)l$9@ZhmiX3ZTx@vb|1sBU@gJ(FfEm^I|SVMQF_;=-8ihMV{_BpaPEssRu`Q&s7KqTe}#VNz89CQTL0%z_pYs*)IU-FU8sUJIo_YU zv~JSi3UxjIE=o2JWz}ojrdh-KXAzi0{iUndZ`njw_7a!0YuU6>{a-7HmoHxP!Kd50 zD74qLZN1Tw1#Ev+w7rRdVWEquh47uPgtOiSI=}`eOTAg|y$!oSQgp)~EmA z0nKjy`}Ixx&0V@`?WV7OTu?~6@4d8W$neqkjDP5{C+EMg_}w)dHh=qhclyb`!s~}W zF!`~WbDt|-x-$CFXCIC^8RHIyE@(Jt{7kypvoi)?n`4VLp7CcUdHwgdh%5i{fBh}u zTI|s4e|?L{p*;9EVtDW&YdhZ+Mm+S(vJta%Jr1uzAT3%$^mp(|YiNSB?$PP59a73t z=5x~ya+&tCxDXqtf z_>npu_kwlPnj%&mmYx`&bRLG)UiZayN2j_*lAqQHT)}cZ-dh=s`LP_cg!Pxb^G1CU z&^n5h*j!OVPM0pYTgKN8Eho%cdh~!i(u4x$2XdroRS=~nHGMiP46er0B&kV_CvS2i zMH8j`*`KHc=#0w?O>MS_89oM7roxnfTlYybScS?oae;2J+(NcxE8nvuWR{uuMpPW$ z#e8QPnO;NOHGmYpZuemCdC&6*C&Pi#G4_|U$?=dAu@)x~ni|9$5N N7A$^kYV#1({|BtTOI!c| literal 0 HcmV?d00001 diff --git a/Resources/translations/messages.fr.yml b/Resources/translations/messages.fr.yml new file mode 100644 index 0000000..40c37fe --- /dev/null +++ b/Resources/translations/messages.fr.yml @@ -0,0 +1,60 @@ +'Outdoor space reservation system': 'Système de réservation d''espace en plein air' +'Open Air': 'Air libre' +Navigation: Navigation +About: 'À propos' +Index: Accueil +Admin: Administration +Contact: Contact +'Raphaël Gertz all rights reserved': 'Raphaël Gertz tous droits réservés' +'Copyright 2018': 'Droit d''auteur 2018' +Send: Envoyer +Subject: Sujet +'Your name': 'Votre nom' +'Your mail address': 'Votre courriel' +'Your message has been sent': 'Votre message a bien été envoyé' +'Your message here': 'Votre message ici' +'Your password': 'Votre mot de passe' +Logout: Déconnection +Register: Enregistrement +Login: Identification +Recover: Récupération +Dashboard: Tableau de bord +'Hi, %name%': 'Salut, %name%' +'Subject:': 'Sujet :' +'Name': 'Nom' +'Message': 'Message' +'Title': 'Civilité' +'Your title': 'Votre civilité' +'Forename': 'Prénom' +'Your forename': 'Votre prénom' +'Surname': 'Nom' +'Your surname': 'Votre nom' +'Pseudonym': 'Pseudonyme' +'Your pseudonym': 'Votre pseudonyme' +'Mail': 'Courriel' +'Password': 'Mot de passe' +'Confirm password': 'Confirmation' +'Your password confirmation': 'Votre confirmation de mot de passe' +'Welcome to %title%': 'Bienvenue sur %title%' +'Thanks so much for joining us, from now on, you can reserve your %title% spaces.': 'Merci de nous avoir rejoint, à partir de maintenant, vous pouvez réserver vos espaces à l''%title%.' +'Your account has been created': 'Votre compte a bien été créé' +'Invalid credentials.': 'Identifiants invalides' +'Thanks so much for joining us, to recover your account you can follow this link: %url%': 'Merci de nous avoir rejoint, pour récupérer votre compte vous pouvez suivre ce lien : %url%' +'Your password is updated and an account recover message has been sent': 'Votre mot de passe est modifié et un message de récupération de compte a été envoyé' +'Unable to find account': 'Impossible de trouver le compte' +'Account already exists: %mail%': 'Le compte existe déjà : %mail%' +'Your recover account message has been sent': 'Votre message de récupération de compte a été envoyé' +'To recover your account click here': 'Pour récupérer votre compte cliquez ici' +'Recover account on %title%': 'Récupération de compte sur %title%' +'Account recovered on %title%': 'Compte récupéré sur %title%' +'Your account password has been changed, to recover your account you can follow this link: %url%': 'Votre mot de passe a été changé, pour récupérer votre compte vous pouvez suivre ce lien : %url%' +'Authentication request could not be processed due to a system problem.': 'Authentification impossible suite à un problème système' +Location: Emplacement +Your location: Votre emplacement +Date: Date +Your date: Votre date +Slot: Créneau +Your slot: Votre créneau +'Application request the %date% for %location% on the slot %slot% saved': 'Réservation le %date% pour %location% sur le créneau %slot% enregistrée' +#'Application request the %date% for %location% on the slot %slot% already exists': 'Réservation le %date% pour %location% sur le créneau %slot% déjà existante' +'Application already exists': 'Réservation déjà existante' diff --git a/Resources/translations/validators.fr.yml b/Resources/translations/validators.fr.yml new file mode 100644 index 0000000..e945217 --- /dev/null +++ b/Resources/translations/validators.fr.yml @@ -0,0 +1,11 @@ +'Please provide your name': 'Veuillez fournir votre nom' +'Please provide your mail': 'Veuillez fournir votre courriel' +'Please provide a valid mail': 'Veuillez fournir un courriel valide' +'Please provide your pseudonym': 'Veuillez fournir votre pseudonyme' +'Please provide your forename': 'Veuillez fournir votre prénom' +'Please provide your surname': 'Veuillez fournir votre nom' +'Please provide your password': 'Veuillez fournir votre mot de passe' +'Please provide your subject': 'Veuillez fournir votre sujet' +'Please provide your message': 'Veuillez fournir votre message' +'The password and confirmation must match': 'Le mot de passe doit correspondre à la confirmation' +'Your mail doesn''t seems to be valid': 'Votre courriel ne semble pas valable' diff --git a/Resources/views/admin/index.html.twig b/Resources/views/admin/index.html.twig new file mode 100644 index 0000000..687e217 --- /dev/null +++ b/Resources/views/admin/index.html.twig @@ -0,0 +1,57 @@ +{% extends '@RapsysAir/base.html.twig' %} +{% block content %} +
+

{% trans %}Dashboard{% endtrans %}

+
+ {% if calendar is defined and calendar %} + + + + {% for date, day in calendar %} + + {% if loop.index % 7 == 0 and not loop.last %} + + + {% endif %} + {% endfor %} + + +
+

{{ day.title }}

+ {% if day.sessions is not empty %} + + {% endif %} +
+ {% endif %} +
+ {{ form_start(form) }} + +
{{ form_errors(form) }}
+ +
+ {{ form_row(form.location) }} + + {{ form_row(form.date) }} + + {{ form_row(form.slot) }} +
+ + {{ form_row(form.submit) }} + + {# Render CSRF token etc .#} +
+ {{ form_rest(form) }} +
+ + {{ form_end(form) }} +
+
+ {# dump(calendar) #} +
+{% endblock %} diff --git a/Resources/views/admin/index.html.twig.toto b/Resources/views/admin/index.html.twig.toto new file mode 100644 index 0000000..d529910 --- /dev/null +++ b/Resources/views/admin/index.html.twig.toto @@ -0,0 +1 @@ +|length > 21 ? session.title|slice(0, 21) ~ '...' : session.title diff --git a/Resources/views/admin/session.html.twig b/Resources/views/admin/session.html.twig new file mode 100644 index 0000000..ef61643 --- /dev/null +++ b/Resources/views/admin/session.html.twig @@ -0,0 +1,31 @@ +{% extends '@RapsysAir/base.html.twig' %} +{% block content %} +
+

{{ section }}

+
+
+
+

{% trans %}Location{% endtrans %}

+
{{ session.location.getTitle() }}
+
+
+

{% trans %}Date{% endtrans %}

+
{{ session.date.format('Y-m-d') }}
+
+
+

{% trans %}Slot{% endtrans %}

+
{{ session.slot.getTitle() }}
+
+
+

{% trans %}Application{% endtrans %}

+ {% if session.application is null %} +
{% trans %}None{% endtrans %}
+ {% else %} +
{{ session.application.getTitle() }}
+ {% endif %} +
+
+
+ {{ dump(session) }} +
+{% endblock %} diff --git a/Resources/views/base.html.twig b/Resources/views/base.html.twig new file mode 100644 index 0000000..a95e21a --- /dev/null +++ b/Resources/views/base.html.twig @@ -0,0 +1,78 @@ + + + + + {% block title %}{{ title }}{% endblock %} + + {% block stylesheet %} + {% stylesheet '//fonts.googleapis.com/css?family=Irish+Grover' '//fonts.googleapis.com/css?family=La+Belle+Aurore' '@RapsysAirBundle/Resources/public/css/{reset,screen}.css' %} + + {% endstylesheet %} + {% endblock %} + + + + + {% block body %} + + {% block header %} + + {% endblock %} + + {# pass an array argument to get the messages of those types (['warning', 'error']) #} + {% for label, messages in app.flashes %} + {% if messages %} +
+
    + {% for message in messages %} +
  • {{ message }}
  • + {% endfor %} +
+
+ {% endif %} + {% endfor %} + + {% block sidebar %}{% endblock %} + + {% block content %}
{% endblock %} + + {% block footer %} +
+   +
{% trans %}Raphaël Gertz all rights reserved{% endtrans %}{% trans %}Copyright 2018{% endtrans %}.
+   +
+ {% endblock %} + + {% endblock %} + diff --git a/Resources/views/form/contact.html.twig b/Resources/views/form/contact.html.twig new file mode 100644 index 0000000..b75b91b --- /dev/null +++ b/Resources/views/form/contact.html.twig @@ -0,0 +1,34 @@ +{% extends '@RapsysAir/base.html.twig' %} +{% block content %} +
+

{{ section }}

+ {% if sent %} +

{% trans %}Your message has been sent{% endtrans %}

+ {% else %} +
+ {{ form_start(form) }} + +
{{ form_errors(form) }}
+ +
+ {{ form_row(form.subject) }} + + {{ form_row(form.name) }} + + {{ form_row(form.mail) }} + + {{ form_row(form.message) }} +
+ + {{ form_row(form.submit) }} + + {# Render CSRF token etc .#} +
+ {{ form_rest(form) }} +
+ + {{ form_end(form) }} +
+ {% endif %} +
+{% endblock %} diff --git a/Resources/views/form/form_div_layout.html.twig b/Resources/views/form/form_div_layout.html.twig new file mode 100644 index 0000000..7f73c51 --- /dev/null +++ b/Resources/views/form/form_div_layout.html.twig @@ -0,0 +1,417 @@ +{# Widgets #} + +{%- block form_widget -%} + {% if compound %} + {{- block('form_widget_compound') -}} + {% else %} + {{- block('form_widget_simple') -}} + {% endif %} +{%- endblock form_widget -%} + +{%- block form_widget_simple -%} + {%- set type = type|default('text') -%} + +{%- endblock form_widget_simple -%} + +{%- block form_widget_compound -%} +
+ {%- if form is rootform -%} + {{ form_errors(form) }} + {%- endif -%} + {{- block('form_rows') -}} + {{- form_rest(form) -}} +
+{%- endblock form_widget_compound -%} + +{%- block collection_widget -%} + {% if prototype is defined %} + {%- set attr = attr|merge({'data-prototype': form_row(prototype) }) -%} + {% endif %} + {{- block('form_widget') -}} +{%- endblock collection_widget -%} + +{%- block textarea_widget -%} + +{%- endblock textarea_widget -%} + +{%- block choice_widget -%} + {% if expanded %} + {{- block('choice_widget_expanded') -}} + {% else %} + {{- block('choice_widget_collapsed') -}} + {% endif %} +{%- endblock choice_widget -%} + +{%- block choice_widget_expanded -%} +
+ {%- for child in form %} + {{- form_widget(child) -}} + {{- form_label(child, null, {translation_domain: choice_translation_domain}) -}} + {% endfor -%} +
+{%- endblock choice_widget_expanded -%} + +{%- block choice_widget_collapsed -%} + {%- if required and placeholder is none and not placeholder_in_choices and not multiple and (attr.size is not defined or attr.size <= 1) -%} + {% set required = false %} + {%- endif -%} + +{%- endblock choice_widget_collapsed -%} + +{%- block choice_widget_options -%} + {% for group_label, choice in options %} + {%- if choice is iterable -%} + + {% set options = choice %} + {{- block('choice_widget_options') -}} + + {%- else -%} + + {%- endif -%} + {% endfor %} +{%- endblock choice_widget_options -%} + +{%- block checkbox_widget -%} + +{%- endblock checkbox_widget -%} + +{%- block radio_widget -%} + +{%- endblock radio_widget -%} + +{%- block datetime_widget -%} + {% if widget == 'single_text' %} + {{- block('form_widget_simple') -}} + {%- else -%} +
+ {{- form_errors(form.date) -}} + {{- form_errors(form.time) -}} + {{- form_widget(form.date) -}} + {{- form_widget(form.time) -}} +
+ {%- endif -%} +{%- endblock datetime_widget -%} + +{%- block date_widget -%} + {%- if widget == 'single_text' -%} + {{ block('form_widget_simple') }} + {%- else -%} +
+ {{- date_pattern|replace({ + '{{ year }}': form_widget(form.year), + '{{ month }}': form_widget(form.month), + '{{ day }}': form_widget(form.day), + })|raw -}} +
+ {%- endif -%} +{%- endblock date_widget -%} + +{%- block time_widget -%} + {%- if widget == 'single_text' -%} + {{ block('form_widget_simple') }} + {%- else -%} + {%- set vars = widget == 'text' ? { 'attr': { 'size': 1 }} : {} -%} +
+ {{ form_widget(form.hour, vars) }}{% if with_minutes %}:{{ form_widget(form.minute, vars) }}{% endif %}{% if with_seconds %}:{{ form_widget(form.second, vars) }}{% endif %} +
+ {%- endif -%} +{%- endblock time_widget -%} + +{%- block dateinterval_widget -%} + {%- if widget == 'single_text' -%} + {{- block('form_widget_simple') -}} + {%- else -%} +
+ {{- form_errors(form) -}} + + + + {%- if with_years %}{% endif -%} + {%- if with_months %}{% endif -%} + {%- if with_weeks %}{% endif -%} + {%- if with_days %}{% endif -%} + {%- if with_hours %}{% endif -%} + {%- if with_minutes %}{% endif -%} + {%- if with_seconds %}{% endif -%} + + + + + {%- if with_years %}{% endif -%} + {%- if with_months %}{% endif -%} + {%- if with_weeks %}{% endif -%} + {%- if with_days %}{% endif -%} + {%- if with_hours %}{% endif -%} + {%- if with_minutes %}{% endif -%} + {%- if with_seconds %}{% endif -%} + + + + {%- if with_invert %}{{ form_widget(form.invert) }}{% endif -%} +
+ {%- endif -%} +{%- endblock dateinterval_widget -%} + +{%- block number_widget -%} + {# type="number" doesn't work with floats #} + {%- set type = type|default('text') -%} + {{ block('form_widget_simple') }} +{%- endblock number_widget -%} + +{%- block integer_widget -%} + {%- set type = type|default('number') -%} + {{ block('form_widget_simple') }} +{%- endblock integer_widget -%} + +{%- block money_widget -%} + {{ money_pattern|replace({ '{{ widget }}': block('form_widget_simple') })|raw }} +{%- endblock money_widget -%} + +{%- block url_widget -%} + {%- set type = type|default('url') -%} + {{ block('form_widget_simple') }} +{%- endblock url_widget -%} + +{%- block search_widget -%} + {%- set type = type|default('search') -%} + {{ block('form_widget_simple') }} +{%- endblock search_widget -%} + +{%- block percent_widget -%} + {%- set type = type|default('text') -%} + {{ block('form_widget_simple') }} % +{%- endblock percent_widget -%} + +{%- block password_widget -%} + {%- set type = type|default('password') -%} + {{ block('form_widget_simple') }} +{%- endblock password_widget -%} + +{%- block hidden_widget -%} + {%- set type = type|default('hidden') -%} + {{ block('form_widget_simple') }} +{%- endblock hidden_widget -%} + +{%- block email_widget -%} + {%- set type = type|default('email') -%} + {{ block('form_widget_simple') }} +{%- endblock email_widget -%} + +{%- block range_widget -%} + {% set type = type|default('range') %} + {{- block('form_widget_simple') -}} +{%- endblock range_widget %} + +{%- block button_widget -%} + {%- if label is empty -%} + {%- if label_format is not empty -%} + {% set label = label_format|replace({ + '%name%': name, + '%id%': id, + }) %} + {%- elseif label is same as(false) -%} + {% set translation_domain = false %} + {%- else -%} + {% set label = name|humanize %} + {%- endif -%} + {%- endif -%} + +{%- endblock button_widget -%} + +{%- block submit_widget -%} + {%- set type = type|default('submit') -%} + {{ block('button_widget') }} +{%- endblock submit_widget -%} + +{%- block reset_widget -%} + {%- set type = type|default('reset') -%} + {{ block('button_widget') }} +{%- endblock reset_widget -%} + +{%- block tel_widget -%} + {%- set type = type|default('tel') -%} + {{ block('form_widget_simple') }} +{%- endblock tel_widget -%} + +{%- block color_widget -%} + {%- set type = type|default('color') -%} + {{ block('form_widget_simple') }} +{%- endblock color_widget -%} + +{# Labels #} + +{%- block form_label -%} + {% if label is not same as(false) -%} + {% if not compound -%} + {% set label_attr = label_attr|merge({'for': id}) %} + {%- endif -%} + {% if required -%} + {% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' required')|trim}) %} + {%- endif -%} + {% if label is empty -%} + {%- if label_format is not empty -%} + {% set label = label_format|replace({ + '%name%': name, + '%id%': id, + }) %} + {%- else -%} + {% set label = name|humanize %} + {%- endif -%} + {%- endif -%} + <{{ element|default('label') }}{% if label_attr %}{% with { attr: label_attr } %}{{ block('attributes') }}{% endwith %}{% endif %}> + {%- if translation_domain is same as(false) -%} + {{- label -}} + {%- else -%} + {{- label|trans({}, translation_domain) -}} + {%- endif -%} + + {%- endif -%} +{%- endblock form_label -%} + +{%- block button_label -%}{%- endblock -%} + +{# Rows #} + +{%- block repeated_row -%} + {# + No need to render the errors here, as all errors are mapped + to the first child (see RepeatedTypeValidatorExtension). + #} + {{- block('form_rows') -}} +{%- endblock repeated_row -%} + +{%- block form_row -%} +
+ {{- form_label(form) -}} +
+ {{- form_widget(form) -}} + {%- if errors|length > 0 -%} +
+ {{- form_errors(form) -}} +
+ {%- endif -%} +
+
+{%- endblock form_row -%} + +{%- block button_row -%} +
+ {{- form_widget(form) -}} +
+{%- endblock button_row -%} + +{%- block hidden_row -%} + {{ form_widget(form) }} +{%- endblock hidden_row -%} + +{# Misc #} + +{%- block form -%} + {{ form_start(form) }} + {{- form_widget(form) -}} + {{ form_end(form) }} +{%- endblock form -%} + +{%- block form_start -%} + {%- do form.setMethodRendered() -%} + {% set method = method|upper %} + {%- if method in ["GET", "POST"] -%} + {% set form_method = method %} + {%- else -%} + {% set form_method = "POST" %} + {%- endif -%} +
+ {%- if form_method != method -%} + + {%- endif -%} +{%- endblock form_start -%} + +{%- block form_end -%} + {%- if not render_rest is defined or render_rest -%} + {{ form_rest(form) }} + {%- endif -%} +
+{%- endblock form_end -%} + +{%- block form_errors -%} + {%- if errors|length > 0 -%} +
    + {%- for error in errors -%} +
  • {{ error.message }}
  • + {%- endfor -%} +
+ {%- endif -%} +{%- endblock form_errors -%} + +{%- block form_rest -%} + {% for child in form -%} + {% if not child.rendered %} + {{- form_row(child) -}} + {% endif %} + {%- endfor -%} + + {% if not form.methodRendered and form is rootform %} + {%- do form.setMethodRendered() -%} + {% set method = method|upper %} + {%- if method in ["GET", "POST"] -%} + {% set form_method = method %} + {%- else -%} + {% set form_method = "POST" %} + {%- endif -%} + + {%- if form_method != method -%} + + {%- endif -%} + {% endif -%} +{% endblock form_rest %} + +{# Support #} + +{%- block form_rows -%} + {% for child in form %} + {{- form_row(child) -}} + {% endfor %} +{%- endblock form_rows -%} + +{%- block widget_attributes -%} + id="{{ id }}" name="{{ full_name }}" + {%- if disabled %} disabled="disabled"{% endif -%} + {%- if required %} required="required"{% endif -%} + {{ block('attributes') }} +{%- endblock widget_attributes -%} + +{%- block widget_container_attributes -%} + {%- if id is not empty %}id="{{ id }}"{% endif -%} + {{ block('attributes') }} +{%- endblock widget_container_attributes -%} + +{%- block button_attributes -%} + id="{{ id }}" name="{{ full_name }}"{% if disabled %} disabled="disabled"{% endif -%} + {{ block('attributes') }} +{%- endblock button_attributes -%} + +{% block attributes -%} + {%- for attrname, attrvalue in attr -%} + {{- " " -}} + {%- if attrname in ['placeholder', 'title'] -%} + {{- attrname }}="{{ translation_domain is same as(false) ? attrvalue : attrvalue|trans({}, translation_domain) }}" + {%- elseif attrvalue is same as(true) -%} + {{- attrname }}="{{ attrname }}" + {%- elseif attrvalue is not same as(false) -%} + {{- attrname }}="{{ attrvalue }}" + {%- endif -%} + {%- endfor -%} +{%- endblock attributes -%} diff --git a/Resources/views/form/login.html.twig b/Resources/views/form/login.html.twig new file mode 100644 index 0000000..d680b2d --- /dev/null +++ b/Resources/views/form/login.html.twig @@ -0,0 +1,32 @@ +{% extends '@RapsysAir/base.html.twig' %} +{% block content %} +
+

{% trans %}Login{% endtrans %}

+
+ {{ form_start(form) }} + +
{{ form_errors(form) }}
+ +
+ {{ form_row(form.mail) }} + + {{ form_row(form.password) }} + + {% if error %} + + {% endif %} +
+ + {{ form_row(form.submit) }} + + {# Render CSRF token etc .#} +
+ {{ form_rest(form) }} +
+ + {{ form_end(form) }} +
+
+{% endblock %} diff --git a/Resources/views/form/recover.html.twig b/Resources/views/form/recover.html.twig new file mode 100644 index 0000000..63f948d --- /dev/null +++ b/Resources/views/form/recover.html.twig @@ -0,0 +1,28 @@ +{% extends '@RapsysAir/base.html.twig' %} +{% block content %} +
+

{% trans %}Recover{% endtrans %}

+ {% if sent %} +

{% trans %}Your recover account message has been sent{% endtrans %}

+ {% else %} +
+ {{ form_start(form) }} + +
{{ form_errors(form) }}
+ +
+ {{ form_row(form.mail) }} +
+ + {{ form_row(form.submit) }} + + {# Render CSRF token etc .#} +
+ {{ form_rest(form) }} +
+ + {{ form_end(form) }} +
+ {% endif %} +
+{% endblock %} diff --git a/Resources/views/form/recover_mail.html.twig b/Resources/views/form/recover_mail.html.twig new file mode 100644 index 0000000..74b2dd7 --- /dev/null +++ b/Resources/views/form/recover_mail.html.twig @@ -0,0 +1,30 @@ +{% extends '@RapsysAir/base.html.twig' %} +{% block content %} +
+

{% trans %}Recover{% endtrans %}

+ {% if sent %} +

{% trans %}Your password is updated and an account recover message has been sent{% endtrans %}

+ {% elseif notfound %} +

{% trans %}Unable to find account{% endtrans %}

+ {% else %} +
+ {{ form_start(form) }} + +
{{ form_errors(form) }}
+ +
+ {{ form_row(form.password) }} +
+ + {{ form_row(form.submit) }} + + {# Render CSRF token etc .#} +
+ {{ form_rest(form) }} +
+ + {{ form_end(form) }} +
+ {% endif %} +
+{% endblock %} diff --git a/Resources/views/form/register.html.twig b/Resources/views/form/register.html.twig new file mode 100644 index 0000000..ca69b5e --- /dev/null +++ b/Resources/views/form/register.html.twig @@ -0,0 +1,42 @@ +{% extends '@RapsysAir/base.html.twig' %} +{% block content %} +
+

{{ title|trans }}

+ {% if sent %} +

{% trans %}Your account has been created{% endtrans %}

+ {% else %} +
+ {{ form_start(form) }} + +
{{ form_errors(form) }}
+ +
+ {{ form_row(form.mail) }} + + {{ form_row(form.password.first) }} + + {{ form_row(form.password.second) }} +
+ +
+ {{ form_row(form.title) }} + + {{ form_row(form.forename) }} + + {{ form_row(form.surname) }} + + {{ form_row(form.pseudonym) }} +
+ + {{ form_row(form.submit) }} + + {# Render CSRF token etc .#} +
+ {{ form_rest(form) }} +
+ + {{ form_end(form) }} +
+ {% endif %} +
+{% endblock %} diff --git a/Resources/views/mail/contact.html.twig b/Resources/views/mail/contact.html.twig new file mode 100644 index 0000000..7fe13ff --- /dev/null +++ b/Resources/views/mail/contact.html.twig @@ -0,0 +1,43 @@ + + + + + + {{ subject }} + + + + + + + + +
{{ title|trans }}

{{ title|trans }}

+ + + + + + +
  +

{% trans %}Hi,{% endtrans %} {{ contact_name }}

+

{% trans %}Subject:{% endtrans %} {{ subject }}

+

{{ message|nl2br }}

+
 
+ + + + + + + diff --git a/Resources/views/mail/generic.html.twig b/Resources/views/mail/generic.html.twig new file mode 100644 index 0000000..5e6da39 --- /dev/null +++ b/Resources/views/mail/generic.html.twig @@ -0,0 +1,49 @@ + + + + + + {{ title }} + + + + + + + + +
{{ title }}

{{ title }}

+ + + + + + +
  +

{{ subtitle }}

+ {% if subject %} +

{% trans %}Subject:{% endtrans %} {{ subject }}

+ {% endif %} + {% if raw is defined %} +

{{ raw|raw }}

+ {% else %} +

{{ message|nl2br }}

+ {% endif %} +
 
+ + + + + + + diff --git a/Resources/views/mail/register.html.twig b/Resources/views/mail/register.html.twig new file mode 100644 index 0000000..8a6c0d3 --- /dev/null +++ b/Resources/views/mail/register.html.twig @@ -0,0 +1,43 @@ + + + + + + {{ 'Welcome to %title%'|trans({'%title%': title}) }} + + + + + + + + +
{{ title|trans }}

{{ title|trans }}

+ + + + + + +
  +

{% trans %}Hi,{% endtrans %} {{ contact_name }}

+

{% trans %}Subject:{% endtrans %} {{ 'Welcome to %title%'|trans({'%title%': title|trans}) }}

+

{{ 'Thanks so much for joining us, from now you can reserver your %title% spaces.'|trans({'%title%': title|trans}) }}

+
 
+ + + + + + + diff --git a/Resources/views/page/index.html.twig b/Resources/views/page/index.html.twig new file mode 100644 index 0000000..f0997a7 --- /dev/null +++ b/Resources/views/page/index.html.twig @@ -0,0 +1,7 @@ +{% extends '@RapsysAir/base.html.twig' %} +{% block content %} +
+

{{ section }}

+

{% trans %}Outdoor space reservation system{% endtrans %}

+
+{% endblock %} diff --git a/Tests/Controller/DefaultControllerTest.php b/Tests/Controller/DefaultControllerTest.php new file mode 100644 index 0000000..fed9e42 --- /dev/null +++ b/Tests/Controller/DefaultControllerTest.php @@ -0,0 +1,17 @@ +request('GET', '/'); + + $this->assertContains('Hello World', $client->getResponse()->getContent()); + } +} diff --git a/Twig/Base64Extension.php b/Twig/Base64Extension.php new file mode 100644 index 0000000..8272989 --- /dev/null +++ b/Twig/Base64Extension.php @@ -0,0 +1,12 @@ + array('type' => BBCODE_TYPE_ROOT), + 'code' => array( + 'type' => BBCODE_TYPE_OPTARG, + 'open_tag' => '
',
+								'close_tag' => '
', + 'default_arg' => '{CONTENT}' + ), + 'ul' => array( + 'type' => BBCODE_TYPE_NOARG, + 'open_tag' => '
    ', + 'close_tag' => '
', + 'childs' => 'li' + ), + 'li' => array( + 'type' => BBCODE_TYPE_NOARG, + 'open_tag' => '
  • ', + 'close_tag' => '
  • ', + 'parent' => 'ul', + 'childs' => 'url' + ), + 'url' => array( + 'type' => BBCODE_TYPE_OPTARG, + 'open_tag' => '', + 'close_tag' => '', + 'default_arg' => '{CONTENT}', + 'parent' => 'p,li' + ) + ) + ); + $text = nl2br(bbcode_parse($ctx, htmlspecialchars($text))); + if (preg_match_all('#\]*\>(.*?)\#s', $text, $matches) && !empty($matches[1])) { + foreach($matches[1] as $string) { + $text = str_replace($string, str_replace('
    ', '', $string), $text); + } + } + if (preg_match_all('#\]*\>(.*?)\#s', $text, $matches) && !empty($matches[1])) { + foreach($matches[1] as $string) { + $text = str_replace($string, str_replace('
    ', '', $string), $text); + } + } + $text = preg_replace( + array('#(
    (\r?\n?))*(
    (\r?\n?))*#', '#(
    (\r?\n?))*(
    (\r?\n?))*#', '#(
    (\r?\n?)){2,}#'), + array('

    \2\2

    ', '

    \2\2

    ', '

    \2

    '), + $text + ); + return $text; + }, + array('is_safe' => array('html')) + ) + ); + } +} diff --git a/Twig/FileGetContentsExtension.php b/Twig/FileGetContentsExtension.php new file mode 100644 index 0000000..ac4ab2a --- /dev/null +++ b/Twig/FileGetContentsExtension.php @@ -0,0 +1,11 @@ +