From: Raphaël Gertz <git@rapsys.eu> Date: Fri, 25 Oct 2019 14:33:24 +0000 (+0200) Subject: Initial import X-Git-Tag: 0.0.1~2 X-Git-Url: https://git.rapsys.eu/.gitweb.cgi/airbundle/commitdiff_plain/f110b8ba20232e0ceeb67390f8e672431868d32d Initial import --- f110b8ba20232e0ceeb67390f8e672431868d32d 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 @@ +<?php + +namespace Rapsys\AirBundle\Controller; + +use Symfony\Bundle\FrameworkBundle\Controller\Controller; +use Symfony\Component\Routing\Generator\UrlGeneratorInterface; +use Symfony\Component\HttpFoundation\Request; +use Rapsys\AirBundle\Entity\Session; +use Rapsys\AirBundle\Entity\Application; +use Symfony\Component\Form\FormError; + +class DefaultController extends Controller { + public function contactAction(Request $request) { + //Get translator + $trans = $this->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 @@ +<?php + +namespace Rapsys\AirBundle\DataFixtures; + +use Rapsys\AirBundle\Entity\Title; +use Rapsys\AirBundle\Entity\Group; +use Rapsys\AirBundle\Entity\User; +use Rapsys\AirBundle\Entity\Location; +use Rapsys\AirBundle\Entity\Slot; + +class AirFixtures extends \Doctrine\Bundle\FixturesBundle\Fixture implements \Symfony\Component\DependencyInjection\ContainerAwareInterface { + /** + * @var ContainerInterface + */ + private $container; + + public function setContainer(\Symfony\Component\DependencyInjection\ContainerInterface $container = null) + { + $this->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/RapsysAirExtension.php b/DependencyInjection/RapsysAirExtension.php new file mode 100644 index 0000000..5a2bdff --- /dev/null +++ b/DependencyInjection/RapsysAirExtension.php @@ -0,0 +1,46 @@ +<?php + +namespace Rapsys\AirBundle\DependencyInjection; + +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\Config\FileLocator; +use Symfony\Component\HttpKernel\DependencyInjection\Extension; +use Symfony\Component\DependencyInjection\Loader; + +/** + * This is the class that loads and manages your bundle configuration. + * + * @link http://symfony.com/doc/current/cookbook/bundles/extension.html + */ +class RapsysAirExtension extends Extension { + /** + * {@inheritdoc} + */ + public function load(array $configs, ContainerBuilder $container) { + $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader->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 @@ +<?php + +namespace Rapsys\AirBundle\Entity; + +/** + * Application + */ +class Application +{ + /** + * @var integer + */ + private $id; + + /** + * @var \DateTime + */ + private $created; + + /** + * @var \DateTime + */ + private $updated; + + /** + * @var \Doctrine\Common\Collections\Collection + */ + private $votes; + + /** + * @var \Rapsys\AirBundle\Entity\Session + */ + private $session; + + /** + * @var \Rapsys\AirBundle\Entity\User + */ + private $user; + + /** + * Constructor + */ + public function __construct() + { + $this->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 @@ +<?php + +// src/Rapsys/AirBundle/Entity/Group.php +namespace Rapsys\AirBundle\Entity; + +class Group extends \Rapsys\UserBundle\Entity\Group {} diff --git a/Entity/Location.php b/Entity/Location.php new file mode 100644 index 0000000..4e9ceaf --- /dev/null +++ b/Entity/Location.php @@ -0,0 +1,304 @@ +<?php + +namespace Rapsys\AirBundle\Entity; + +/** + * Location + */ +class Location +{ + /** + * @var integer + */ + private $id; + + /** + * @var string + */ + private $title; + + /** + * @var string + */ + private $address; + + /** + * @var string + */ + private $zipcode; + + /** + * @var string + */ + private $city; + + /** + * @var string + */ + private $latitude; + + /** + * @var string + */ + private $longitude; + + /** + * @var \DateTime + */ + private $created; + + /** + * @var \DateTime + */ + private $updated; + + /** + * @var \Doctrine\Common\Collections\Collection + */ + private $sessions; + + /** + * Constructor + */ + public function __construct() + { + $this->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 @@ +<?php + +namespace Rapsys\AirBundle\Entity; + +/** + * Session + */ +class Session { + /** + * @var integer + */ + private $id; + + /** + * @var \DateTime + */ + private $date; + + /** + * @var \DateTime + */ + private $begin; + + /** + * @var \DateTime + */ + private $end; + + /** + * @var \DateTime + */ + private $created; + + /** + * @var \DateTime + */ + private $updated; + + /** + * @var \Doctrine\Common\Collections\Collection + */ + private $applications; + + /** + * @var \Rapsys\AirBundle\Entity\Location + */ + private $location; + + /** + * @var \Rapsys\AirBundle\Entity\Application + */ + private $application; + + /** + * Constructor + */ + public function __construct() { + $this->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 @@ +<?php + +namespace Rapsys\AirBundle\Entity; + +/** + * Slot + */ +class Slot +{ + /** + * @var integer + */ + private $id; + + /** + * @var \DateTime + */ + private $begin; + + /** + * @var \DateTime + */ + private $end; + + /** + * @var \DateTime + */ + private $created; + + /** + * @var \DateTime + */ + private $updated; + + /** + * @var \Doctrine\Common\Collections\Collection + */ + private $sessions; + + /** + * Constructor + */ + public function __construct() + { + $this->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 @@ +<?php + +// src/Rapsys/AirBundle/Entity/Title.php +namespace Rapsys\AirBundle\Entity; + +class Title extends \Rapsys\UserBundle\Entity\Title { +} diff --git a/Entity/User.php b/Entity/User.php new file mode 100644 index 0000000..473fd07 --- /dev/null +++ b/Entity/User.php @@ -0,0 +1,85 @@ +<?php + +// src/Rapsys/AirBundle/Entity/User.php +namespace Rapsys\AirBundle\Entity; + +class User extends \Rapsys\UserBundle\Entity\User { + /** + * @var \Doctrine\Common\Collections\Collection + */ + private $votes; + + /** + * @var \Doctrine\Common\Collections\Collection + */ + private $applications; + + /** + * Constructor + */ + public function __construct() { + parent::__construct(); + } + + /** + * Add vote + * + * @param \Rapsys\AirBundle\Entity\Vote $vote + * + * @return User + */ + 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; + } + + /** + * 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 @@ +<?php + +namespace Rapsys\AirBundle\Entity; + +/** + * Vote + */ +class Vote +{ + /** + * @var integer + */ + private $id; + + /** + * @var \DateTime + */ + private $created; + + /** + * @var \DateTime + */ + private $updated; + + /** + * @var \Rapsys\AirBundle\Entity\Application + */ + private $application; + + /** + * @var \Rapsys\AirBundle\Entity\User + */ + private $user; + + + /** + * Get id + * + * @return integer + */ + public function getId() + { + return $this->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 @@ +<?php + +namespace Rapsys\AirBundle\Form; + +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\Form\Extension\Core\Type\DateType; +use Symfony\Component\Form\Extension\Core\Type\SubmitType; +use Symfony\Component\Validator\Constraints\Date; +use Symfony\Component\Validator\Constraints\NotBlank; + +class ApplicationType extends AbstractType { + /** + * {@inheritdoc} + */ + public function buildForm(FormBuilderInterface $builder, array $options) { + return $builder + ->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 @@ +<?php + +namespace Rapsys\AirBundle\Form; + +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\Extension\Core\Type\TextareaType; +use Symfony\Component\Form\Extension\Core\Type\EmailType; +use Symfony\Component\Form\Extension\Core\Type\SubmitType; +use Symfony\Component\Validator\Constraints\Email; +use Symfony\Component\Validator\Constraints\NotBlank; + +class ContactType extends AbstractType { + /** + * {@inheritdoc} + */ + public function buildForm(FormBuilderInterface $builder, array $options) { + return $builder->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 @@ +<?php + +namespace Rapsys\AirBundle; + +use Symfony\Component\HttpKernel\Bundle\Bundle; + +class RapsysAirBundle extends Bundle +{ +} diff --git a/Repository/ApplicationRepository.php b/Repository/ApplicationRepository.php new file mode 100644 index 0000000..3112d14 --- /dev/null +++ b/Repository/ApplicationRepository.php @@ -0,0 +1,26 @@ +<?php + +namespace Rapsys\AirBundle\Repository; + +/** + * ApplicationRepository + */ +class ApplicationRepository extends \Doctrine\ORM\EntityRepository { + /** + * Find session by session and user + * + * @param $session The session + * @param $user The user + */ + public function findOneBySessionUser($session, $user) { + //Fetch article + $ret = $this->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 @@ +<?php + +namespace Rapsys\AirBundle\Repository; + +/** + * SessionRepository + */ +class SessionRepository extends \Doctrine\ORM\EntityRepository { + /** + * Find session by location, slot and date + * + * @param $location The location + * @param $slot The slot + * @param $date The datetime + */ + public function findOneByLocationSlotDate($location, $slot, $date) { + //Fetch session + $ret = $this->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 0000000..fb66588 Binary files /dev/null and b/Resources/public/ico/favicon.ico differ diff --git a/Resources/public/png/apple.png b/Resources/public/png/apple.png new file mode 100644 index 0000000..da559cf Binary files /dev/null and b/Resources/public/png/apple.png differ diff --git a/Resources/public/png/favicon.png b/Resources/public/png/favicon.png new file mode 100644 index 0000000..85f7b97 Binary files /dev/null and b/Resources/public/png/favicon.png differ diff --git a/Resources/public/png/logo.png b/Resources/public/png/logo.png new file mode 100644 index 0000000..b57be8c Binary files /dev/null and b/Resources/public/png/logo.png differ 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 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="210mm" + height="297mm" + viewBox="0 0 210 297" + version="1.1" + id="svg4570" + inkscape:version="0.92.3 (2405546, 2018-03-11)" + sodipodi:docname="openair.logo.svg"> + <title + id="title5131">Open Air Logo</title> + <defs + id="defs4564"> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient5174" + id="radialGradient5140" + cx="3.5708413" + cy="290.94611" + fx="3.5708413" + fy="290.94611" + r="3.5708413" + gradientTransform="matrix(0.96030384,0.85677319,-2.1146358,1.886651,616.04931,-259.20651)" + gradientUnits="userSpaceOnUse" /> + <linearGradient + inkscape:collect="always" + id="linearGradient5174"> + <stop + id="stop5166" + offset="0" + style="stop-color:#00c3f9;stop-opacity:0" /> + <stop + style="stop-color:#00c3f9;stop-opacity:0.33" + offset="0.40000001" + id="stop5168" /> + <stop + id="stop5172" + offset="1" + style="stop-color:#00c3f9;stop-opacity:1;" /> + </linearGradient> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="15.839192" + inkscape:cx="19.689661" + inkscape:cy="10.360728" + inkscape:document-units="mm" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="2560" + inkscape:window-height="1537" + inkscape:window-x="-4" + inkscape:window-y="-4" + inkscape:window-maximized="1" /> + <metadata + id="metadata4567"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title>Open Air Logo</dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Calque 1" + inkscape:groupmode="layer" + id="layer1"> + <path + inkscape:connector-curvature="0" + id="path5017" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:1.25;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:url(#radialGradient5140);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.11197994;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" + d="m 4.2394596,289.42973 c -0.7893188,-7.7e-4 -1.6132823,0.29881 -2.1442353,0.89641 -0.5268689,0.5976 -0.790304,1.41203 -0.790304,2.44326 0,1.02758 0.2634351,1.84019 0.790304,2.43778 0.530953,0.5976 1.2456986,0.89641 2.1442353,0.89641 0.8985367,0 1.6091981,-0.29881 2.1319828,-0.89641 0.5268689,-0.59759 0.790304,-1.4102 0.790304,-2.43778 0,-1.03123 -0.2634351,-1.84566 -0.790304,-2.44326 -0.5227847,-0.5976 -1.3463617,-0.89563 -2.1319828,-0.89641 z m 0,-0.8964 c 1.2824569,0 2.3076057,0.38444 3.0754463,1.1533 0.7678406,0.76523 1.1517608,1.7928 1.1517608,3.08277 0,1.2863 -0.3839202,2.3139 -1.1517608,3.08275 C 6.5470653,296.61738 5.5219165,297 4.2394596,297 2.9529184,297 1.9236856,296.61738 1.1517607,295.85215 0.38392027,295.08693 0,294.05936 0,292.7694 c 0,-1.28997 0.38392027,-2.31754 1.1517607,-3.08277 0.7719249,-0.76886 1.8011577,-1.1533 3.0876989,-1.1533 z" + sodipodi:nodetypes="acscscscascscscscs" + inkscape:export-xdpi="100.34" + inkscape:export-ydpi="100.34" /> + </g> +</svg> 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 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="210mm" + height="297mm" + viewBox="0 0 210 297" + version="1.1" + id="svg8" + sodipodi:docname="logo.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <defs + id="defs2"> + <linearGradient + inkscape:collect="always" + id="linearGradient5174"> + <stop + id="stop5166" + offset="0" + style="stop-color:#00c3f9;stop-opacity:0" /> + <stop + style="stop-color:#00c3f9;stop-opacity:0.33" + offset="0.40000001" + id="stop5168" /> + <stop + id="stop5172" + offset="1" + style="stop-color:#00c3f9;stop-opacity:1;" /> + </linearGradient> + <clipPath + clipPathUnits="userSpaceOnUse" + id="clipPath18"> + <path + d="M 3044.85,0 C 1363.23,0 0,203.461 0,454.441 0,705.41 1363.23,908.859 3044.85,908.859 4726.47,908.859 6089.69,705.41 6089.69,454.441 6089.69,203.461 4726.47,0 3044.85,0" + id="path20" /> + </clipPath> + <clipPath + clipPathUnits="userSpaceOnUse" + id="clipPath30"> + <path + d="M 0,3832 0,0 l 6089.69,0 0,3832 L 0,3832 Z" + id="path32" /> + </clipPath> + <clipPath + clipPathUnits="userSpaceOnUse" + id="clipPath80"> + <path + d="m 2788.36,2246.6 -256.48,0 c -3.06,0.66 -19.07,4.34 -19.07,4.34 -17.41,4.1 -33.17,8.18 -48.17,12.44 l -6.49,1.93 c -15.5,4.52 -30.45,9.28 -44.44,14.09 l -4.55,1.52 c -13.92,4.85 -28.16,10.26 -43.53,16.52 l -8.06,3.3 c -14.03,5.88 -27.59,11.99 -40.31,18.1 l -6.54,3.26 c -14.56,7.15 -27.3,13.83 -39.59,20.71 -11.57,6.57 -23.65,13.86 -36.94,22.42 l -5.91,3.79 c -11.33,7.43 -22.51,15.21 -33.21,23.16 l -5.56,4.17 c -11.98,9.07 -22.38,17.36 -31.8,25.43 l -1.19,1.03 c -9.72,8.35 -19.3,17.09 -29.29,26.74 l -3.52,3.35 c -8.91,8.76 -17.92,18.14 -26.74,27.89 l -4.06,4.54 c -9.19,10.33 -17.29,19.98 -24.77,29.48 l -1.68,2.18 c -8.07,10.36 -15.78,20.86 -22.89,31.21 l -1.03,1.46 c -6.93,10.11 -13.69,20.71 -21.23,33.28 l -1.86,3.11 c -6.58,11.16 -12.75,22.33 -18.31,33.13 l -1.27,2.53 c -11.68,22.94 -22.2,46.97 -31.59,72.27 l -0.64,1.7 c -4.41,12.01 -8.53,24.3 -12.26,36.52 l -0.6,1.99 c -11.33,37.51 -19.82,76.79 -25.31,117.56 -0.35,2.6 -0.55,5.25 -0.88,7.85 30.2,9.7 62.33,15.04 95.71,15.04 9.99,0 20.46,-0.6 32,-1.82 l 15.43,-1.64 1.44,15.45 c 15.75,169.23 79.48,321.07 167.3,405.86 -19.6,-51.67 -34.76,-105.27 -45.24,-160 -18.26,-95.59 -21.4,-190.06 -9.27,-280.74 5.48,-40.77 13.97,-80.05 25.31,-117.56 l 0.59,-1.99 c 3.73,-12.22 7.86,-24.51 12.27,-36.52 l 0.63,-1.7 c 9.39,-25.3 19.91,-49.33 31.6,-72.27 l 1.26,-2.53 c 5.56,-10.8 11.74,-21.97 18.31,-33.13 l 1.87,-3.11 c 7.53,-12.57 14.3,-23.17 21.22,-33.28 l 1.04,-1.46 c 7.11,-10.35 14.82,-20.85 22.89,-31.21 l 1.67,-2.18 c 7.49,-9.5 15.58,-19.15 24.77,-29.48 l 4.06,-4.54 c 8.82,-9.75 17.83,-19.13 26.75,-27.89 l 3.51,-3.35 c 9.99,-9.65 19.58,-18.39 29.29,-26.74 l 1.19,-1.03 c 9.42,-8.07 19.83,-16.36 31.8,-25.43 l 5.56,-4.17 c 10.71,-7.95 21.89,-15.73 33.21,-23.16 l 5.91,-3.79 c 13.29,-8.56 25.37,-15.85 36.95,-22.42 12.28,-6.88 25.03,-13.56 39.59,-20.71 l 6.53,-3.26 c 12.72,-6.11 26.28,-12.22 40.31,-18.1 l 8.06,-3.3 c 15.38,-6.26 29.61,-11.67 43.53,-16.52 l 4.55,-1.52 c 13.99,-4.81 28.95,-9.57 44.45,-14.09 l 6.47,-1.93 c 15.01,-4.26 30.77,-8.34 48.18,-12.44 0,0 16.02,-3.68 19.07,-4.34" + id="path82" /> + </clipPath> + <clipPath + clipPathUnits="userSpaceOnUse" + id="clipPath92"> + <path + d="m 4078.74,2296.83 c -70.64,7.85 -137.5,18.24 -200.68,31.03 150.52,95.28 244.88,262.64 244.88,443.38 0,245.43 -173.93,461.07 -413.56,512.75 l -7.73,1.66 -3.11,7.27 c -86.59,201.73 -254.36,351.23 -455.56,417.29 11.47,19.88 20.58,32.95 25.61,37.54 299.13,-1.39 568.3,-179.6 686.42,-454.83 l 3.12,-7.27 7.73,-1.66 c 239.62,-51.68 413.56,-267.32 413.56,-512.75 0,-202.21 -117.9,-387.97 -300.68,-474.41" + id="path94" /> + </clipPath> + <clipPath + clipPathUnits="userSpaceOnUse" + id="clipPath104"> + <path + d="m 3549.34,2246.6 -62.19,0 c -87.81,0 -171.3,4.24 -250.34,12.59 -23.74,5.79 -47.08,12.04 -69.74,19.01 -13.3,4.1 -26.3,8.41 -39.2,12.89 l -1.92,0.68 c -12.67,4.47 -25.13,9.11 -37.23,13.88 l -1.87,0.74 c -12.34,4.9 -24.42,9.97 -36.99,15.52 -116.98,51.84 -215.06,122.74 -292.07,211.34 -7.01,8.09 -13.8,16.3 -20.4,24.61 l -1.27,1.6 c -6.44,8.15 -12.67,16.4 -18.71,24.74 l -1.44,1.99 c -5.99,8.35 -11.81,16.78 -17.36,25.22 l -1.17,1.8 c -5.69,8.69 -11.2,17.48 -16.94,27.12 -47.66,80.21 -80.73,170.1 -98.31,267.17 l -0.3,1.63 c -1.73,9.67 -3.29,19.39 -4.89,30.48 l -0.24,1.59 c -1.34,9.5 -2.52,19 -3.58,28.53 l -0.38,3.54 c -1,9.47 -1.86,18.96 -2.58,28.51 l -0.25,3.42 c -0.68,9.61 -1.23,19.25 -1.63,28.84 l -0.08,2.66 c -0.4,9.98 -0.65,19.98 -0.73,30.57 -0.65,93.21 11.69,187.94 36.97,282.57 2.61,9.73 5.36,19.4 8.22,29.04 l 0.48,1.61 c 2.86,9.55 5.84,19.05 8.94,28.51 l 0.51,1.54 c 0.69,2.07 1.41,4.17 2.11,6.24 131.82,235.2 366.62,359.44 498.49,391.61 -19.1,-17.91 -37.78,-37.4 -55.88,-58.3 -74,-85.49 -135.6,-192.8 -178.13,-310.32 -3.67,-10.2 -6.95,-19.7 -10.11,-29.23 l -0.5,-1.54 c -3.11,-9.46 -6.09,-18.96 -8.95,-28.51 l -0.48,-1.61 c -2.87,-9.64 -5.61,-19.31 -8.22,-29.04 -25.28,-94.63 -37.62,-189.36 -36.96,-282.57 0.08,-10.59 0.32,-20.59 0.72,-30.57 l 0.09,-2.66 c 0.39,-9.59 0.95,-19.23 1.62,-28.84 l 0.25,-3.42 c 0.72,-9.55 1.59,-19.04 2.59,-28.51 l 0.38,-3.54 c 1.05,-9.53 2.23,-19.03 3.57,-28.53 l 0.24,-1.59 c 1.61,-11.09 3.16,-20.81 4.89,-30.48 l 0.31,-1.63 c 17.56,-97.07 50.65,-186.96 98.31,-267.17 5.74,-9.64 11.25,-18.43 16.93,-27.12 l 1.17,-1.8 c 5.56,-8.44 11.37,-16.87 17.37,-25.22 l 1.43,-1.99 c 6.05,-8.34 12.28,-16.59 18.72,-24.74 l 1.27,-1.6 c 6.59,-8.31 13.39,-16.52 20.4,-24.61 76.99,-88.6 175.08,-159.5 292.06,-211.34 12.56,-5.55 24.66,-10.62 36.99,-15.52 l 1.87,-0.74 c 12.11,-4.77 24.55,-9.41 37.25,-13.88 l 1.91,-0.68 c 12.89,-4.48 25.91,-8.79 39.21,-12.89 40.2,-12.38 82.15,-22.92 125.77,-31.6" + id="path106" /> + </clipPath> + <clipPath + clipPathUnits="userSpaceOnUse" + id="clipPath18-8"> + <path + d="M 3044.85,0 C 1363.23,0 0,203.461 0,454.441 0,705.41 1363.23,908.859 3044.85,908.859 4726.47,908.859 6089.69,705.41 6089.69,454.441 6089.69,203.461 4726.47,0 3044.85,0" + id="path20-1" /> + </clipPath> + <clipPath + clipPathUnits="userSpaceOnUse" + id="clipPath30-2"> + <path + d="M 0,3832 0,0 l 6089.69,0 0,3832 L 0,3832 Z" + id="path32-0" /> + </clipPath> + <clipPath + clipPathUnits="userSpaceOnUse" + id="clipPath80-2"> + <path + d="m 2788.36,2246.6 -256.48,0 c -3.06,0.66 -19.07,4.34 -19.07,4.34 -17.41,4.1 -33.17,8.18 -48.17,12.44 l -6.49,1.93 c -15.5,4.52 -30.45,9.28 -44.44,14.09 l -4.55,1.52 c -13.92,4.85 -28.16,10.26 -43.53,16.52 l -8.06,3.3 c -14.03,5.88 -27.59,11.99 -40.31,18.1 l -6.54,3.26 c -14.56,7.15 -27.3,13.83 -39.59,20.71 -11.57,6.57 -23.65,13.86 -36.94,22.42 l -5.91,3.79 c -11.33,7.43 -22.51,15.21 -33.21,23.16 l -5.56,4.17 c -11.98,9.07 -22.38,17.36 -31.8,25.43 l -1.19,1.03 c -9.72,8.35 -19.3,17.09 -29.29,26.74 l -3.52,3.35 c -8.91,8.76 -17.92,18.14 -26.74,27.89 l -4.06,4.54 c -9.19,10.33 -17.29,19.98 -24.77,29.48 l -1.68,2.18 c -8.07,10.36 -15.78,20.86 -22.89,31.21 l -1.03,1.46 c -6.93,10.11 -13.69,20.71 -21.23,33.28 l -1.86,3.11 c -6.58,11.16 -12.75,22.33 -18.31,33.13 l -1.27,2.53 c -11.68,22.94 -22.2,46.97 -31.59,72.27 l -0.64,1.7 c -4.41,12.01 -8.53,24.3 -12.26,36.52 l -0.6,1.99 c -11.33,37.51 -19.82,76.79 -25.31,117.56 -0.35,2.6 -0.55,5.25 -0.88,7.85 30.2,9.7 62.33,15.04 95.71,15.04 9.99,0 20.46,-0.6 32,-1.82 l 15.43,-1.64 1.44,15.45 c 15.75,169.23 79.48,321.07 167.3,405.86 -19.6,-51.67 -34.76,-105.27 -45.24,-160 -18.26,-95.59 -21.4,-190.06 -9.27,-280.74 5.48,-40.77 13.97,-80.05 25.31,-117.56 l 0.59,-1.99 c 3.73,-12.22 7.86,-24.51 12.27,-36.52 l 0.63,-1.7 c 9.39,-25.3 19.91,-49.33 31.6,-72.27 l 1.26,-2.53 c 5.56,-10.8 11.74,-21.97 18.31,-33.13 l 1.87,-3.11 c 7.53,-12.57 14.3,-23.17 21.22,-33.28 l 1.04,-1.46 c 7.11,-10.35 14.82,-20.85 22.89,-31.21 l 1.67,-2.18 c 7.49,-9.5 15.58,-19.15 24.77,-29.48 l 4.06,-4.54 c 8.82,-9.75 17.83,-19.13 26.75,-27.89 l 3.51,-3.35 c 9.99,-9.65 19.58,-18.39 29.29,-26.74 l 1.19,-1.03 c 9.42,-8.07 19.83,-16.36 31.8,-25.43 l 5.56,-4.17 c 10.71,-7.95 21.89,-15.73 33.21,-23.16 l 5.91,-3.79 c 13.29,-8.56 25.37,-15.85 36.95,-22.42 12.28,-6.88 25.03,-13.56 39.59,-20.71 l 6.53,-3.26 c 12.72,-6.11 26.28,-12.22 40.31,-18.1 l 8.06,-3.3 c 15.38,-6.26 29.61,-11.67 43.53,-16.52 l 4.55,-1.52 c 13.99,-4.81 28.95,-9.57 44.45,-14.09 l 6.47,-1.93 c 15.01,-4.26 30.77,-8.34 48.18,-12.44 0,0 16.02,-3.68 19.07,-4.34" + id="path82-9" /> + </clipPath> + <clipPath + clipPathUnits="userSpaceOnUse" + id="clipPath92-4"> + <path + d="m 4078.74,2296.83 c -70.64,7.85 -137.5,18.24 -200.68,31.03 150.52,95.28 244.88,262.64 244.88,443.38 0,245.43 -173.93,461.07 -413.56,512.75 l -7.73,1.66 -3.11,7.27 c -86.59,201.73 -254.36,351.23 -455.56,417.29 11.47,19.88 20.58,32.95 25.61,37.54 299.13,-1.39 568.3,-179.6 686.42,-454.83 l 3.12,-7.27 7.73,-1.66 c 239.62,-51.68 413.56,-267.32 413.56,-512.75 0,-202.21 -117.9,-387.97 -300.68,-474.41" + id="path94-6" /> + </clipPath> + <clipPath + clipPathUnits="userSpaceOnUse" + id="clipPath104-6"> + <path + d="m 3549.34,2246.6 -62.19,0 c -87.81,0 -171.3,4.24 -250.34,12.59 -23.74,5.79 -47.08,12.04 -69.74,19.01 -13.3,4.1 -26.3,8.41 -39.2,12.89 l -1.92,0.68 c -12.67,4.47 -25.13,9.11 -37.23,13.88 l -1.87,0.74 c -12.34,4.9 -24.42,9.97 -36.99,15.52 -116.98,51.84 -215.06,122.74 -292.07,211.34 -7.01,8.09 -13.8,16.3 -20.4,24.61 l -1.27,1.6 c -6.44,8.15 -12.67,16.4 -18.71,24.74 l -1.44,1.99 c -5.99,8.35 -11.81,16.78 -17.36,25.22 l -1.17,1.8 c -5.69,8.69 -11.2,17.48 -16.94,27.12 -47.66,80.21 -80.73,170.1 -98.31,267.17 l -0.3,1.63 c -1.73,9.67 -3.29,19.39 -4.89,30.48 l -0.24,1.59 c -1.34,9.5 -2.52,19 -3.58,28.53 l -0.38,3.54 c -1,9.47 -1.86,18.96 -2.58,28.51 l -0.25,3.42 c -0.68,9.61 -1.23,19.25 -1.63,28.84 l -0.08,2.66 c -0.4,9.98 -0.65,19.98 -0.73,30.57 -0.65,93.21 11.69,187.94 36.97,282.57 2.61,9.73 5.36,19.4 8.22,29.04 l 0.48,1.61 c 2.86,9.55 5.84,19.05 8.94,28.51 l 0.51,1.54 c 0.69,2.07 1.41,4.17 2.11,6.24 131.82,235.2 366.62,359.44 498.49,391.61 -19.1,-17.91 -37.78,-37.4 -55.88,-58.3 -74,-85.49 -135.6,-192.8 -178.13,-310.32 -3.67,-10.2 -6.95,-19.7 -10.11,-29.23 l -0.5,-1.54 c -3.11,-9.46 -6.09,-18.96 -8.95,-28.51 l -0.48,-1.61 c -2.87,-9.64 -5.61,-19.31 -8.22,-29.04 -25.28,-94.63 -37.62,-189.36 -36.96,-282.57 0.08,-10.59 0.32,-20.59 0.72,-30.57 l 0.09,-2.66 c 0.39,-9.59 0.95,-19.23 1.62,-28.84 l 0.25,-3.42 c 0.72,-9.55 1.59,-19.04 2.59,-28.51 l 0.38,-3.54 c 1.05,-9.53 2.23,-19.03 3.57,-28.53 l 0.24,-1.59 c 1.61,-11.09 3.16,-20.81 4.89,-30.48 l 0.31,-1.63 c 17.56,-97.07 50.65,-186.96 98.31,-267.17 5.74,-9.64 11.25,-18.43 16.93,-27.12 l 1.17,-1.8 c 5.56,-8.44 11.37,-16.87 17.37,-25.22 l 1.43,-1.99 c 6.05,-8.34 12.28,-16.59 18.72,-24.74 l 1.27,-1.6 c 6.59,-8.31 13.39,-16.52 20.4,-24.61 76.99,-88.6 175.08,-159.5 292.06,-211.34 12.56,-5.55 24.66,-10.62 36.99,-15.52 l 1.87,-0.74 c 12.11,-4.77 24.55,-9.41 37.25,-13.88 l 1.91,-0.68 c 12.89,-4.48 25.91,-8.79 39.21,-12.89 40.2,-12.38 82.15,-22.92 125.77,-31.6" + id="path106-1" /> + </clipPath> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient5174" + id="linearGradient5075" + x1="1.018965" + y1="285.02298" + x2="7.7508168" + y2="285.02298" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient5174" + id="radialGradient5140" + cx="3.5708413" + cy="290.94611" + fx="3.5708413" + fy="290.94611" + r="3.5708413" + gradientTransform="matrix(0.81002191,0.81002303,-1.7837077,1.7837053,519.6412,-230.90846)" + gradientUnits="userSpaceOnUse" /> + <radialGradient + inkscape:collect="always" + xlink:href="#linearGradient5174" + id="radialGradient5202" + cx="34.65731" + cy="290.9346" + fx="34.65731" + fy="290.9346" + r="3.534668" + gradientTransform="matrix(1,0,0,1.0913743,0,-26.583936)" + gradientUnits="userSpaceOnUse" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="2.8" + inkscape:cx="33.962344" + inkscape:cy="136.63132" + inkscape:document-units="mm" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="1666" + inkscape:window-height="1294" + inkscape:window-x="436" + inkscape:window-y="107" + inkscape:window-maximized="0" /> + <metadata + id="metadata5"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Calque 1" + inkscape:groupmode="layer" + id="layer1"> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:1.25;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#006666;fill-opacity:1;stroke:none;stroke-width:0.26458332;" + x="7.7265034" + y="294.79858" + id="text4105" + inkscape:export-xdpi="99.20594" + inkscape:export-ydpi="99.20594"><tspan + sodipodi:role="line" + id="tspan4103" + x="7.7265034" + y="294.79858" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;stroke-width:0.26458332;fill:#006666;fill-opacity:1;">pen</tspan></text> + <path + inkscape:connector-curvature="0" + id="path5017" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:1.25;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:url(#radialGradient5140);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill" + d="m 3.576009,287.79126 c -0.6657944,-7.3e-4 -1.3608126,0.2825 -1.808675,0.84749 -0.4444173,0.565 -0.666626,1.33498 -0.666626,2.30994 0,0.97152 0.2222087,1.73978 0.666626,2.30477 0.4478624,0.56499 1.0507541,0.84749 1.808675,0.84749 0.757921,0 1.3573676,-0.2825 1.7983398,-0.84749 0.4444173,-0.56499 0.666626,-1.33325 0.666626,-2.30477 0,-0.97496 -0.2222087,-1.74494 -0.666626,-2.30994 -0.4409722,-0.56499 -1.1356634,-0.84676 -1.7983398,-0.84749 z m 0,-0.84749 c 1.08176,0 1.946479,0.36346 2.5941569,1.09037 0.6476779,0.72347 0.9715169,1.69498 0.9715169,2.91455 0,1.21612 -0.323839,2.18764 -0.9715169,2.91455 -0.6476779,0.72347 -1.5123969,1.08521 -2.5941569,1.08521 -1.085205,0 -1.953369,-0.36174 -2.60449208,-1.08521 C 0.32383899,293.13977 2.1886081e-8,292.16826 2.1886081e-8,290.94869 2.1886081e-8,289.72912 0.32383899,288.75761 0.97151692,288.03414 1.62264,287.30723 2.490804,286.94377 3.576009,286.94377 Z" + sodipodi:nodetypes="acscscscascscscscs" + inkscape:export-xdpi="99.20594" + inkscape:export-ydpi="99.20594" /> + <rect + style="fill:url(#linearGradient5075);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:0, 1.09999998;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill" + id="rect5067" + width="6.7318516" + height="1.3363476" + x="1.018965" + y="284.3548" /> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:url(#radialGradient5202);fill-opacity:1.0;stroke:none;stroke-width:0.26458332" + x="31.039961" + y="294.79224" + id="text5152" + inkscape:export-xdpi="99.20594" + inkscape:export-ydpi="99.20594"><tspan + sodipodi:role="line" + id="tspan5150" + x="31.039961" + y="294.79224" + style="fill:url(#radialGradient5202);fill-opacity:1.0;stroke-width:0.26458332">A</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-weight:normal;font-size:10.58333302px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#006666;fill-opacity:1;stroke:none;stroke-width:0.26458332;" + x="38.277328" + y="294.79953" + id="text5156" + inkscape:export-xdpi="99.20594" + inkscape:export-ydpi="99.20594"><tspan + sodipodi:role="line" + id="tspan5154" + x="38.277328" + y="294.79953" + style="fill:#006666;fill-opacity:1;stroke-width:0.26458332;">ir</tspan></text> + </g> +</svg> diff --git a/Resources/public/xcf/openair.xcf b/Resources/public/xcf/openair.xcf new file mode 100644 index 0000000..ebe102b Binary files /dev/null and b/Resources/public/xcf/openair.xcf differ 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: <a href="%url%">%url%</a>': 'Merci de nous avoir rejoint, pour récupérer votre compte vous pouvez suivre ce lien : <a href="%url%">%url%</a>' +'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: <a href="%url%">%url%</a>': 'Votre mot de passe a été changé, pour récupérer votre compte vous pouvez suivre ce lien : <a href="%url%">%url%</a>' +'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 %} +<section id="dashboard"> + <h2>{% trans %}Dashboard{% endtrans %}</h2> + <div class="panel"> + {% if calendar is defined and calendar %} + <table class="grid"> + <tbody> + <tr> + {% for date, day in calendar %} + <td class="{{ ['cell', 'seventh']|merge(day.class)|join(' ') }}"> + <h3>{{ day.title }}</h3> + {% if day.sessions is not empty %} + <ul> + {% for session in day.sessions %} + <li class="{{ ['session']|merge(session.class)|join(' ') }}"> + <a href="{{ path('rapsys_air_session', {'id': session.id}) }}" title="{{ session.title }}">{{ session.title }}</a> + </li> + {% endfor %} + </ul> + {% endif %} + </td> + {% if loop.index % 7 == 0 and not loop.last %} + </tr> + <tr> + {% endif %} + {% endfor %} + </tr> + </tbody> + </table> + {% endif %} + <div> + {{ form_start(form) }} + + <header>{{ form_errors(form) }}</header> + + <section> + {{ form_row(form.location) }} + + {{ form_row(form.date) }} + + {{ form_row(form.slot) }} + </section> + + {{ form_row(form.submit) }} + + {# Render CSRF token etc .#} + <footer style="display:none"> + {{ form_rest(form) }} + </footer> + + {{ form_end(form) }} + </div> + </div> + {# dump(calendar) #} +</section> +{% 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 id="dashboard"> + <h2>{{ section }}</h2> + <div class="panel"> + <div class="grid"> + <dl class="cell"> + <dt><h3>{% trans %}Location{% endtrans %}</h3></dt> + <dd>{{ session.location.getTitle() }}</dd> + </dl> + <dl class="cell"> + <dt><h3>{% trans %}Date{% endtrans %}</h3></dt> + <dd>{{ session.date.format('Y-m-d') }}</dd> + </dl> + <dl class="cell"> + <dt><h3>{% trans %}Slot{% endtrans %}</h3></dt> + <dd>{{ session.slot.getTitle() }}</dd> + </dl> + <dl class="cell"> + <dt><h3>{% trans %}Application{% endtrans %}</h3></dt> + {% if session.application is null %} + <dd>{% trans %}None{% endtrans %}</dd> + {% else %} + <dd>{{ session.application.getTitle() }}</dd> + {% endif %} + </dl> + </div> + </div> + {{ dump(session) }} +</section> +{% 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 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="UTF-8" /> + <title>{% block title %}{{ title }}{% endblock %}</title> + <meta name="viewport" content="width=device-width, initial-scale=1" /> + {% 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' %} + <link href="{{ asset_url }}" type="text/css" rel="stylesheet" /> + {% endstylesheet %} + {% endblock %} + <!--{% block javascript %} + {% javascript '@RapsysAirBundle/Resources/public/js/*.js' %} + <script src="{{ asset_url }}"></script> + {% endjavascript %} + {% endblock %}--> + <link rel="icon" type="image/png" href="{{ asset('bundles/rapsysair/png/favicon.png') }}" sizes="192x192" /> + <link rel="shortcut icon" type="image/x-icon" href="{{ asset('bundles/rapsysair/ico/favicon.ico') }}" /> + </head> + {% block body %} + <body> + {% block header %} + <header id="header"> + {% block header_title %} + {% block blog_title %}<h1><a href="{{ path('rapsys_air_homepage') }}"><img src="{{ asset('bundles/rapsysair/png/logo.png') }}" alt="{% trans %}Open Air{% endtrans %}" /></a></h1>{% endblock %} + {% block header_nav %} + <nav> + <h2>{% trans %}Navigation{% endtrans %}</h2> + <a href="{{ path('rapsys_air_admin') }}">{% trans %}Admin{% endtrans %}</a> + <a href="{{ path('rapsys_air_contact') }}">{% trans %}Contact{% endtrans %}</a> + {% if is_granted('IS_AUTHENTICATED_REMEMBERED') %} + <a href="{{ path('rapsys_user_logout') }}">{% trans %}Logout{% endtrans %}</a> + {% else %} + <a href="{{ path('rapsys_user_register') }}">{% trans %}Register{% endtrans %}</a> + {% endif %} + </nav> + {% endblock %} + {% block blog_subtitle %}{% endblock %} + {% block blog_tagline %} + {% if tags is defined and tags %} + <ul> + {% for id, tag in tags %} + <li><h2><a href="#">Tag</a></h2></li> + {% endfor %} + </ul> + {% endif %} + {% endblock %} + {% endblock %} + </header> + {% endblock %} + + {# pass an array argument to get the messages of those types (['warning', 'error']) #} + {% for label, messages in app.flashes %} + {% if messages %} + <div class="flash {{label}}"> + <ul> + {% for message in messages %} + <li>{{ message }}</li> + {% endfor %} + </ul> + </div> + {% endif %} + {% endfor %} + + {% block sidebar %}<aside id="sidebar"></aside>{% endblock %} + + {% block content %}<section id="content"></section>{% endblock %} + + {% block footer %} + <footer id="footer"> + <span> </span> + <details><summary>{% trans %}Raphaël Gertz all rights reserved{% endtrans %}</summary><span>{% trans %}Copyright 2018{% endtrans %}.</span></details> + <span> </span> + </footer> + {% endblock %} + </body> + {% endblock %} +</html> 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 id="form"> + <h2><a href="{{ path('rapsys_air_contact') }}">{{ section }}</a></h2> + {% if sent %} + <p>{% trans %}Your message has been sent{% endtrans %}</p> + {% else %} + <div> + {{ form_start(form) }} + + <header>{{ form_errors(form) }}</header> + + <section> + {{ form_row(form.subject) }} + + {{ form_row(form.name) }} + + {{ form_row(form.mail) }} + + {{ form_row(form.message) }} + </section> + + {{ form_row(form.submit) }} + + {# Render CSRF token etc .#} + <footer style="display:none"> + {{ form_rest(form) }} + </footer> + + {{ form_end(form) }} + </div> + {% endif %} + </section> +{% 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') -%} + <input type="{{ type }}" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/> +{%- endblock form_widget_simple -%} + +{%- block form_widget_compound -%} + <div {{ block('widget_container_attributes') }}> + {%- if form is rootform -%} + {{ form_errors(form) }} + {%- endif -%} + {{- block('form_rows') -}} + {{- form_rest(form) -}} + </div> +{%- 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 -%} + <textarea {{ block('widget_attributes') }}>{{ value }}</textarea> +{%- 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 -%} + <div {{ block('widget_container_attributes') }}> + {%- for child in form %} + {{- form_widget(child) -}} + {{- form_label(child, null, {translation_domain: choice_translation_domain}) -}} + {% endfor -%} + </div> +{%- 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 -%} + <select {{ block('widget_attributes') }}{% if multiple %} multiple="multiple"{% endif %}> + {%- if placeholder is not none -%} + <option value=""{% if required and value is empty %} selected="selected"{% endif %}>{{ placeholder != '' ? (translation_domain is same as(false) ? placeholder : placeholder|trans({}, translation_domain)) }}</option> + {%- endif -%} + {%- if preferred_choices|length > 0 -%} + {% set options = preferred_choices %} + {{- block('choice_widget_options') -}} + {%- if choices|length > 0 and separator is not none -%} + <option disabled="disabled">{{ separator }}</option> + {%- endif -%} + {%- endif -%} + {%- set options = choices -%} + {{- block('choice_widget_options') -}} + </select> +{%- endblock choice_widget_collapsed -%} + +{%- block choice_widget_options -%} + {% for group_label, choice in options %} + {%- if choice is iterable -%} + <optgroup label="{{ choice_translation_domain is same as(false) ? group_label : group_label|trans({}, choice_translation_domain) }}"> + {% set options = choice %} + {{- block('choice_widget_options') -}} + </optgroup> + {%- else -%} + <option value="{{ choice.value }}"{% if choice.attr %}{% with { attr: choice.attr } %}{{ block('attributes') }}{% endwith %}{% endif %}{% if choice is selectedchoice(value) %} selected="selected"{% endif %}>{{ choice_translation_domain is same as(false) ? choice.label : choice.label|trans({}, choice_translation_domain) }}</option> + {%- endif -%} + {% endfor %} +{%- endblock choice_widget_options -%} + +{%- block checkbox_widget -%} + <input type="checkbox" {{ block('widget_attributes') }}{% if value is defined %} value="{{ value }}"{% endif %}{% if checked %} checked="checked"{% endif %} /> +{%- endblock checkbox_widget -%} + +{%- block radio_widget -%} + <input type="radio" {{ block('widget_attributes') }}{% if value is defined %} value="{{ value }}"{% endif %}{% if checked %} checked="checked"{% endif %} /> +{%- endblock radio_widget -%} + +{%- block datetime_widget -%} + {% if widget == 'single_text' %} + {{- block('form_widget_simple') -}} + {%- else -%} + <div {{ block('widget_container_attributes') }}> + {{- form_errors(form.date) -}} + {{- form_errors(form.time) -}} + {{- form_widget(form.date) -}} + {{- form_widget(form.time) -}} + </div> + {%- endif -%} +{%- endblock datetime_widget -%} + +{%- block date_widget -%} + {%- if widget == 'single_text' -%} + {{ block('form_widget_simple') }} + {%- else -%} + <div {{ block('widget_container_attributes') }}> + {{- date_pattern|replace({ + '{{ year }}': form_widget(form.year), + '{{ month }}': form_widget(form.month), + '{{ day }}': form_widget(form.day), + })|raw -}} + </div> + {%- endif -%} +{%- endblock date_widget -%} + +{%- block time_widget -%} + {%- if widget == 'single_text' -%} + {{ block('form_widget_simple') }} + {%- else -%} + {%- set vars = widget == 'text' ? { 'attr': { 'size': 1 }} : {} -%} + <div {{ block('widget_container_attributes') }}> + {{ form_widget(form.hour, vars) }}{% if with_minutes %}:{{ form_widget(form.minute, vars) }}{% endif %}{% if with_seconds %}:{{ form_widget(form.second, vars) }}{% endif %} + </div> + {%- endif -%} +{%- endblock time_widget -%} + +{%- block dateinterval_widget -%} + {%- if widget == 'single_text' -%} + {{- block('form_widget_simple') -}} + {%- else -%} + <div {{ block('widget_container_attributes') }}> + {{- form_errors(form) -}} + <table class="{{ table_class|default('') }}" role="presentation"> + <thead> + <tr> + {%- if with_years %}<th>{{ form_label(form.years) }}</th>{% endif -%} + {%- if with_months %}<th>{{ form_label(form.months) }}</th>{% endif -%} + {%- if with_weeks %}<th>{{ form_label(form.weeks) }}</th>{% endif -%} + {%- if with_days %}<th>{{ form_label(form.days) }}</th>{% endif -%} + {%- if with_hours %}<th>{{ form_label(form.hours) }}</th>{% endif -%} + {%- if with_minutes %}<th>{{ form_label(form.minutes) }}</th>{% endif -%} + {%- if with_seconds %}<th>{{ form_label(form.seconds) }}</th>{% endif -%} + </tr> + </thead> + <tbody> + <tr> + {%- if with_years %}<td>{{ form_widget(form.years) }}</td>{% endif -%} + {%- if with_months %}<td>{{ form_widget(form.months) }}</td>{% endif -%} + {%- if with_weeks %}<td>{{ form_widget(form.weeks) }}</td>{% endif -%} + {%- if with_days %}<td>{{ form_widget(form.days) }}</td>{% endif -%} + {%- if with_hours %}<td>{{ form_widget(form.hours) }}</td>{% endif -%} + {%- if with_minutes %}<td>{{ form_widget(form.minutes) }}</td>{% endif -%} + {%- if with_seconds %}<td>{{ form_widget(form.seconds) }}</td>{% endif -%} + </tr> + </tbody> + </table> + {%- if with_invert %}{{ form_widget(form.invert) }}{% endif -%} + </div> + {%- 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 -%} + <button type="{{ type|default('button') }}" {{ block('button_attributes') }}>{{ translation_domain is same as(false) ? label : label|trans({}, translation_domain) }}</button> +{%- 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 -%} + </{{ element|default('label') }}> + {%- 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 -%} + <div> + {{- form_label(form) -}} + <section> + {{- form_widget(form) -}} + {%- if errors|length > 0 -%} + <div class="error"> + {{- form_errors(form) -}} + </div> + {%- endif -%} + </section> + </div> +{%- endblock form_row -%} + +{%- block button_row -%} + <div> + {{- form_widget(form) -}} + </div> +{%- 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 -%} + <form name="{{ name }}" method="{{ form_method|lower }}"{% if action != '' %} action="{{ action }}"{% endif %}{% for attrname, attrvalue in attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}{% if multipart %} enctype="multipart/form-data"{% endif %}> + {%- if form_method != method -%} + <input type="hidden" name="_method" value="{{ method }}" /> + {%- endif -%} +{%- endblock form_start -%} + +{%- block form_end -%} + {%- if not render_rest is defined or render_rest -%} + {{ form_rest(form) }} + {%- endif -%} + </form> +{%- endblock form_end -%} + +{%- block form_errors -%} + {%- if errors|length > 0 -%} + <ul> + {%- for error in errors -%} + <li>{{ error.message }}</li> + {%- endfor -%} + </ul> + {%- 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 -%} + <input type="hidden" name="_method" value="{{ 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 %} + <section id="form"> + <h2><a href="{{ path('rapsys_user_login') }}">{% trans %}Login{% endtrans %}</a></h2> + <div> + {{ form_start(form) }} + + <header>{{ form_errors(form) }}</header> + + <section> + {{ form_row(form.mail) }} + + {{ form_row(form.password) }} + + {% if error %} + <div class="error"> + <ul><li><a href="{{ path('rapsys_user_recover') }}">{% trans %}To recover your account click here{% endtrans %}</a></li></ul> + </div> + {% endif %} + </section> + + {{ form_row(form.submit) }} + + {# Render CSRF token etc .#} + <footer style="display:none"> + {{ form_rest(form) }} + </footer> + + {{ form_end(form) }} + </div> + </section> +{% 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 %} + <section id="form"> + <h2><a href="{{ path('rapsys_user_recover') }}">{% trans %}Recover{% endtrans %}</a></h2> + {% if sent %} + <p>{% trans %}Your recover account message has been sent{% endtrans %}</p> + {% else %} + <div> + {{ form_start(form) }} + + <header>{{ form_errors(form) }}</header> + + <section> + {{ form_row(form.mail) }} + </section> + + {{ form_row(form.submit) }} + + {# Render CSRF token etc .#} + <footer style="display:none"> + {{ form_rest(form) }} + </footer> + + {{ form_end(form) }} + </div> + {% endif %} + </section> +{% 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 %} + <section id="form"> + <h2><a href="{{ path('rapsys_user_recover') }}">{% trans %}Recover{% endtrans %}</a></h2> + {% if sent %} + <p>{% trans %}Your password is updated and an account recover message has been sent{% endtrans %}</p> + {% elseif notfound %} + <p>{% trans %}Unable to find account{% endtrans %}</p> + {% else %} + <div> + {{ form_start(form) }} + + <header>{{ form_errors(form) }}</header> + + <section> + {{ form_row(form.password) }} + </section> + + {{ form_row(form.submit) }} + + {# Render CSRF token etc .#} + <footer style="display:none"> + {{ form_rest(form) }} + </footer> + + {{ form_end(form) }} + </div> + {% endif %} + </section> +{% 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 %} + <section id="form"> + <h2>{{ title|trans }}</h2> + {% if sent %} + <p>{% trans %}Your account has been created{% endtrans %}</p> + {% else %} + <div> + {{ form_start(form) }} + + <header>{{ form_errors(form) }}</header> + + <section> + {{ form_row(form.mail) }} + + {{ form_row(form.password.first) }} + + {{ form_row(form.password.second) }} + </section> + + <section> + {{ form_row(form.title) }} + + {{ form_row(form.forename) }} + + {{ form_row(form.surname) }} + + {{ form_row(form.pseudonym) }} + </section> + + {{ form_row(form.submit) }} + + {# Render CSRF token etc .#} + <footer style="display:none"> + {{ form_rest(form) }} + </footer> + + {{ form_end(form) }} + </div> + {% endif %} + </section> +{% 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 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + <meta name="viewport" content="width=device-width" /> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <title>{{ subject }}</title> + <style> + body {background:white;color:#066} + a {text-decoration:none;color:#066} + a:hover {text-decoration:underline} + table {width: 100%;border-radius: .5rem} + table.head {border:.1rem solid #00c3f9;text-align:center} + table.body {background:white;border:.1rem solid #00c3f9;margin:.5rem 0} + table.footer {border:.1rem solid #00c3f9;text-align:center;font-weight:bold} + table.footer summary:after {display:none} + table.footer summary::-webkit-details-marker {display:none} + </style> +</head> +<body> + <table class="head"> + <tr> + <td><a href="{{ url }}"><img src="data:image/png;base64, {{ logo|file_get_contents|base64_encode }}" alt="{{ title|trans }}" /></a></td> + <td><h1><a href="{{ url }}">{{ title|trans }}</a></h1></td> + </tr> + </table> + <table class="body"> + <tr> + <td> </td> + <td> + <h2>{% trans %}Hi,{% endtrans %} {{ contact_name }}</h2> + <h3>{% trans %}Subject:{% endtrans %} {{ subject }}</h3> + <p>{{ message|nl2br }}</p> + </td> + <td> </td> + </tr> + </table> + <table class="footer"> + <tr> + <td>{% trans %}Raphaël Gertz all rights reserved{% endtrans %} - {% trans %}Copyright 2018{% endtrans %}.</td> + </tr> + </table> +</body> +</html> 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 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + <meta name="viewport" content="width=device-width" /> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <title>{{ title }}</title> + <style> + body {background:white;color:#066} + a {text-decoration:none;color:#066} + a:hover {text-decoration:underline} + table {width: 100%;border-radius: .5rem} + table.head {border:.1rem solid #00c3f9;text-align:center} + table.body {background:white;border:.1rem solid #00c3f9;margin:.5rem 0} + table.footer {border:.1rem solid #00c3f9;text-align:center;font-weight:bold} + table.footer summary:after {display:none} + table.footer summary::-webkit-details-marker {display:none} + </style> +</head> +<body> + <table class="head"> + <tr> + <td><a href="{{ home }}"><img src="data:image/png;base64, {{ logo|file_get_contents|base64_encode }}" alt="{{ title }}" /></a></td> + <td><h1><a href="{{ home }}">{{ title }}</a></h1></td> + </tr> + </table> + <table class="body"> + <tr> + <td> </td> + <td> + <h2>{{ subtitle }}</h2> + {% if subject %} + <h3>{% trans %}Subject:{% endtrans %} {{ subject }}</h3> + {% endif %} + {% if raw is defined %} + <p>{{ raw|raw }}</p> + {% else %} + <p>{{ message|nl2br }}</p> + {% endif %} + </td> + <td> </td> + </tr> + </table> + <table class="footer"> + <tr> + <td>{% trans %}Raphaël Gertz all rights reserved{% endtrans %} - {% trans %}Copyright 2018{% endtrans %}.</td> + </tr> + </table> +</body> +</html> 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 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> +<head> + <meta name="viewport" content="width=device-width" /> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <title>{{ 'Welcome to %title%'|trans({'%title%': title}) }}</title> + <style> + body {background:white;color:#066} + a {text-decoration:none;color:#066} + a:hover {text-decoration:underline} + table {width: 100%;border-radius: .5rem} + table.head {border:.1rem solid #00c3f9;text-align:center} + table.body {background:white;border:.1rem solid #00c3f9;margin:.5rem 0} + table.footer {border:.1rem solid #00c3f9;text-align:center;font-weight:bold} + table.footer summary:after {display:none} + table.footer summary::-webkit-details-marker {display:none} + </style> +</head> +<body> + <table class="head"> + <tr> + <td><a href="{{ url }}"><img src="data:image/png;base64, {{ logo|file_get_contents|base64_encode }}" alt="{{ title|trans }}" /></a></td> + <td><h1><a href="{{ url }}">{{ title|trans }}</a></h1></td> + </tr> + </table> + <table class="body"> + <tr> + <td> </td> + <td> + <h2>{% trans %}Hi,{% endtrans %} {{ contact_name }}</h2> + <h3>{% trans %}Subject:{% endtrans %} {{ 'Welcome to %title%'|trans({'%title%': title|trans}) }}</h3> + <p>{{ 'Thanks so much for joining us, from now you can reserver your %title% spaces.'|trans({'%title%': title|trans}) }}</p> + </td> + <td> </td> + </tr> + </table> + <table class="footer"> + <tr> + <td>{% trans %}Raphaël Gertz all rights reserved{% endtrans %} - {% trans %}Copyright 2018{% endtrans %}.</td> + </tr> + </table> +</body> +</html> 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 id="content"> + <h2><a href="{{ path('rapsys_air_homepage') }}">{{ section }}</a></h2> + <p>{% trans %}Outdoor space reservation system{% endtrans %}</p> +</section> +{% 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 @@ +<?php + +namespace Rapsys\AirBundle\Tests\Controller; + +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; + +class DefaultControllerTest extends WebTestCase +{ + public function testIndex() + { + $client = static::createClient(); + + $crawler = $client->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 @@ +<?php +// src/Rapsys/AirBundle/Twig/Base64Extension.php +namespace Rapsys\AirBundle\Twig; + +class Base64Extension extends \Twig_Extension { + public function getFilters() { + return array( + new \Twig_SimpleFilter('base64_encode', 'base64_encode'), + new \Twig_SimpleFilter('base64_decode', 'base64_decode') + ); + } +} diff --git a/Twig/Bb2htmlExtension.php b/Twig/Bb2htmlExtension.php new file mode 100644 index 0000000..a9b3c8e --- /dev/null +++ b/Twig/Bb2htmlExtension.php @@ -0,0 +1,64 @@ +<?php +// src/Rapsys/AirBundle/Twig/Bb2htmlExtension.php +namespace Rapsys\AirBundle\Twig; + +class Bb2htmlExtension extends \Twig_Extension { + public function getFilters() { + return array( + new \Twig\TwigFilter( + 'bb2html', + function($text) { + $ctx = bbcode_create( + array( + '' => array('type' => BBCODE_TYPE_ROOT), + 'code' => array( + 'type' => BBCODE_TYPE_OPTARG, + 'open_tag' => '<pre class="{PARAM}">', + 'close_tag' => '</pre>', + 'default_arg' => '{CONTENT}' + ), + 'ul' => array( + 'type' => BBCODE_TYPE_NOARG, + 'open_tag' => '<ul>', + 'close_tag' => '</ul>', + 'childs' => 'li' + ), + 'li' => array( + 'type' => BBCODE_TYPE_NOARG, + 'open_tag' => '<li>', + 'close_tag' => '</li>', + 'parent' => 'ul', + 'childs' => 'url' + ), + 'url' => array( + 'type' => BBCODE_TYPE_OPTARG, + 'open_tag' => '<a href="{PARAM}">', + 'close_tag' => '</a>', + 'default_arg' => '{CONTENT}', + 'parent' => 'p,li' + ) + ) + ); + $text = nl2br(bbcode_parse($ctx, htmlspecialchars($text))); + if (preg_match_all('#\<pre[^>]*\>(.*?)\</pre\>#s', $text, $matches) && !empty($matches[1])) { + foreach($matches[1] as $string) { + $text = str_replace($string, str_replace('<br />', '', $string), $text); + } + } + if (preg_match_all('#\<ul[^>]*\>(.*?)\</ul\>#s', $text, $matches) && !empty($matches[1])) { + foreach($matches[1] as $string) { + $text = str_replace($string, str_replace('<br />', '', $string), $text); + } + } + $text = preg_replace( + array('#(<br />(\r?\n?))*<pre#s', '#</pre>(<br />(\r?\n?))*#', '#(<br />(\r?\n?))*<ul#s', '#</ul>(<br />(\r?\n?))*#', '#(<br />(\r?\n?)){2,}#'), + array('</p>\2<pre', '</pre>\2<p>', '</p>\2<ul', '</ul>\2<p>', '</p>\2<p>'), + $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 @@ +<?php +// src/Rapsys/AirBundle/Twig/FileGetContentsExtension.php +namespace Rapsys\AirBundle\Twig; + +class FileGetContentsExtension extends \Twig_Extension { + public function getFilters() { + return array( + new \Twig_SimpleFilter('file_get_contents', 'file_get_contents', array(false, null)) + ); + } +}