Commit e58af519 authored by Olivier Valette's avatar Olivier Valette
Browse files

Initial commit

parents
.idea
.php_cs.cache
composer.lock
phpunit.xml
vendor/
<?php
/**
* This file is part of the DATAtourisme project.
*
* @author Conjecto <contact@conjecto.com>
*
* For the full copyright and license information, please view the LICENSE file that was distributed with this source code.
*
*/
$finder = PhpCsFixer\Finder::create()
->exclude('var/cache')
->in(array(__DIR__));
return PhpCsFixer\Config::create()
->setRules(array(
'@Symfony' => true
))
->setFinder($finder);
\ No newline at end of file
<?php
/*
* This file is part of the DATAtourisme project.
* 2022
* @author Conjecto <contact@conjecto.com>
* SPDX-License-Identifier: GPL-3.0-or-later
* For the full copyright and license information, please view the LICENSE file that was distributed with this source code.
*/
namespace Datatourisme\Bundle\WebAppBundle\Asset\VersionStrategy;
use Symfony\Component\Asset\VersionStrategy\VersionStrategyInterface;
class GulpBusterVersionStrategy implements VersionStrategyInterface
{
/**
* @var string
*/
private $manifestPath;
/**
* @var string
*/
private $format;
/**
* @var string[]
*/
private $hashes;
/**
* @param string $manifestPath
* @param string|null $format
*/
public function __construct($manifestPath, $format = null)
{
$this->manifestPath = $manifestPath;
$this->format = $format ?: '%s?%s';
}
public function getVersion($path)
{
if (!is_array($this->hashes)) {
$this->hashes = $this->loadManifest();
}
return isset($this->hashes[$path]) ? $this->hashes[$path] : '';
}
public function applyVersion($path)
{
$version = $this->getVersion($path);
if ('' === $version) {
return $path;
}
$versionized = sprintf($this->format, ltrim($path, '/'), $version);
if ($path && '/' === $path[0]) {
return '/'.$versionized;
}
return $versionized;
}
private function loadManifest()
{
return json_decode(file_get_contents($this->manifestPath), true);
}
}
\ No newline at end of file
CHANGELOG
===================
Ce fichier est basé sur [Keep a Changelog](http://keepachangelog.com/)
et le projet utilise [Semantic Versioning](http://semver.org/).
## En cours
=======
## [1.1.6] - 2019-12-12
### Modifications
- ajout d'une methode getRouteTitle aux notifications
## [1.1.5] - 2019-12-06
### Modifications
- ajout d'une methode isMailingGranted a MailerRecipientInterface pour gérer les inscription aux notifications
### Fixes
- Meilleur comportement responsif du header
## [1.1.4] - 2019-10-01
### Modifications
- lien hypetext : mise à jour de l'adresse du site datatourisme.fr en https://info.datatourisme.gouv.fr
## [1.1.3] - 2019-01-15
### Ajout
- Ajout de meta description
## [1.1.2] - 2018-07-13
### Fixes
- Language switcher on error pages
## [1.1.1] - 2018-07-12
### Fixes
- Ajout de traductions communes
- Ajout d'un argument de langue au lien vers les mentions légales
## [1.1.0] - 2018-06-19
### Ajout
- Gestion des traductions pour l'ensemble des composants
=======
## [1.0.9] - 2018-06-06
### Fixes
- Fix MomentExtension to use the current request locale + locale map
=======
## [1.0.8] - 2018-05-25
### Fixes
- hotfix : notification.html.twig check extra.description is defined
=======
## [1.0.7] - 2018-05-16
### Fixes
- hotfix : notification twig environment : reactivate auto escape !
=======
## [1.0.6] - 2018-05-15
### Modifications
- notification : add description in template
=======
## [1.0.5] - 2018-05-14
### Correction
- MailerHandler : fix count() check (raise WARNING in php 7.2)
=======
## [1.0.4] - 2018-04-25
### Modifications
- CSVWriter : changement de methode de définition des champs
- Footer : Modification du lien vers l'espace Framagit
=======
## [1.0.3] - 2018-04-10
### Correction
- Nom du package !!
=======
## [1.0.2] - 2018-04-10
### Correction
- Correction de la version de moment
=======
## [1.0.1] - 2018-04-10
### Modifications
- Modification de liens dans le footer
### Ajout
- Ajout de la classe utilitaire CSVWriter
=======
## [1.0.0] - 2018-03-01
### Modifications
- Symfony 3.4
- Add versioning-bundle
=======
## [0.1.1] - 2017-07-04
### Correction
- Les menus se superposaient dans une certaine fourchette de breakpoints CSS
- Correction SASS et JS de bootstrap notify
- Fix Moment.php
- Fix Selectize
### Modifications
- Les fonts sont désormais chargées en local et non plus depuis les CDN
### Ajouts
- AuthentificationEntryPoint : renvoi d'un code 401 en cas de requête AJAX
- Composant JS frameloader
- UserRepository abstrait, incluant la method findByRole
- Service Mailer permettant de gérer l'envoi groupé de mails
- Service de notification permettant l'envoi par mail + enregistrement en db via un channel monolog
- Composant Modal : ajout de l'option modal-fh
- Intégration des service d'abstraction Rundeck + Beanstalk
- Ajout d'un service de formatter Monolog
=======
## [0.1.0] - 2017-04-18
### Ajouts
- Thème SASS DATAtourisme
- Thèmes TWIG divers
- Trait d'entités
- Gestion d'upload de fichiers
- Éléments de formulaire
- CurrentPassword : validation du mot de passe de l'utilsiateur actuellement connecté
- DateRangePicker : Implémentation de Bootstrap Daterange picker
- Honeypot : Implémentation de la technique de Honeybot contre les bots
- ImagePreview : Champ d'upload d'image avec prévisualisation
- RoleType : Champ de sélection de rôles limité aux rôles accessibles par l'utilisateur
- StrongPassword : Champ de saisi de mot de passe compatible avec les contraintes de sécurité RGE
- UpdatePassword : Champ combinant CurrentPassword et StrongPassword
- Voter de menu
- UriPrefixVoter : utilise le début de l'URL pour déternier les éléments de menus actifs
- Pagination
- Service de gestion de liste filtrés/triable
- Securité
- Classe de Voter abstraite contenant les opérations utiles aux Voters des applications
- Composants Javascript :
- Modal ajax
- Bootstrap Datepicker
- Boostrap Notify
- ConditionalVisibility
- ImageUploadPreview
- Table filter + sortable
- Tooltips
- Extensions TWIG :
- MomentExtension : implémentation de Moment.php
- UserExtension : hasRole avec gestion de la hiérarchie des rôles
- WebAppExtension
- Validateurs :
- StrongPassword : validation de mot de passe fort compatible avec les contraintes de sécurité RGE
<?php
/*
* This file is part of the DATAtourisme project.
* 2022
* @author Conjecto <contact@conjecto.com>
* SPDX-License-Identifier: GPL-3.0-or-later
* For the full copyright and license information, please view the LICENSE file that was distributed with this source code.
*/
namespace Datatourisme\Bundle\WebAppBundle;
use Datatourisme\Bundle\WebAppBundle\DependencyInjection\Compiler\NotificationPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class DatatourismeWebAppBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new NotificationPass());
}
}
<?php
/*
* This file is part of the DATAtourisme project.
* 2022
* @author Conjecto <contact@conjecto.com>
* SPDX-License-Identifier: GPL-3.0-or-later
* For the full copyright and license information, please view the LICENSE file that was distributed with this source code.
*/
namespace Datatourisme\Bundle\WebAppBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Reference;
/**
* Class NotificationPass.
*/
class NotificationPass implements CompilerPassInterface
{
/**
* @param ContainerBuilder $container
*
* @throws InvalidArgumentException
*/
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('webapp.notification.registry')) {
return;
}
$definition = $container->getDefinition('webapp.notification.registry');
// Builds an array with fully-qualified type class names as keys and service IDs as values
$types = array();
foreach ($container->findTaggedServiceIds('notification.type') as $serviceId => $tag) {
$serviceDefinition = $container->getDefinition($serviceId);
$types[$serviceDefinition->getClass()] = new Reference($serviceId);
}
$definition->replaceArgument(1, $types);
}
}
<?php
/*
* This file is part of the DATAtourisme project.
* 2022
* @author Conjecto <contact@conjecto.com>
* SPDX-License-Identifier: GPL-3.0-or-later
* For the full copyright and license information, please view the LICENSE file that was distributed with this source code.
*/
namespace Datatourisme\Bundle\WebAppBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
/**
* This is the class that validates and merges configuration from your app/config files.
*
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/configuration.html}
*/
class Configuration implements ConfigurationInterface
{
/**
* {@inheritdoc}
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('datatourisme_webapp');
// Here you should define the parameters that are allowed to
// configure your bundle. See the documentation linked above for
// more information on that topic.
$this->addMailerSection($rootNode->children()->arrayNode('mailer'));
return $treeBuilder;
}
/**
* Mailer configuration.
*/
protected function addMailerSection(ArrayNodeDefinition $node)
{
$node
->children()
->arrayNode('sender')
->addDefaultsIfNotSet()
->children()
->scalarNode('name')->defaultValue('DATAtourisme')->end()
->scalarNode('address')->defaultValue('no-reply@datatourisme.com')->end()
->end()
->end()
->scalarNode('subject_template')->cannotBeEmpty()->end()
->arrayNode('emails')
->useAttributeAsKey('code')
->prototype('array')
->children()
->scalarNode('subject')->cannotBeEmpty()->end()
->scalarNode('template')->isRequired()->cannotBeEmpty()->end()
->booleanNode('enabled')->defaultTrue()->end()
->arrayNode('sender')
->children()
->scalarNode('name')->end()
->scalarNode('address')->end()
->end()
->end()
->end()
->end()
->end()
->end()
;
}
}
<?php
/*
* This file is part of the DATAtourisme project.
* 2022
* @author Conjecto <contact@conjecto.com>
* SPDX-License-Identifier: GPL-3.0-or-later
* For the full copyright and license information, please view the LICENSE file that was distributed with this source code.
*/
namespace Datatourisme\Bundle\WebAppBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\Yaml\Yaml;
/**
* This is the class that loads and manages your bundle configuration.
*
* @see http://symfony.com/doc/current/cookbook/bundles/extension.html
*/
class DatatourismeWebAppExtension extends Extension implements PrependExtensionInterface
{
/**
* {@inheritdoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$files = [
'services.yml',
'form.yml',
'security.yml',
'task-manager.yml',
'twig.yml',
'notification.yml',
];
foreach ($files as $file) {
$loader->load($file);
}
$this->loadMailerConfig($config['mailer'], $container);
}
/**
* Load mailer config.
*/
private function loadMailerConfig(array $config, ContainerBuilder $container)
{
$container->setParameter('datatourisme_web_app.mailer.sender_name', $config['sender']['name']);
$container->setParameter('datatourisme_web_app.mailer.sender_address', $config['sender']['address']);
$container->setParameter('datatourisme_web_app.mailer.emails', $config['emails']);
$container->setParameter('datatourisme_web_app.mailer.subject_template', @$config['subject_template']);
}
/**
* {@inheritdoc}
*/
public function prepend(ContainerBuilder $container)
{
$config = Yaml::parse(file_get_contents(__DIR__.'/../Resources/config/config.yml'));
foreach ($container->getExtensions() as $name => $extension) {
if (isset($config[$name])) {
$container->prependExtensionConfig($name, $config[$name]);
}
}
}
}
<?php
/*
* This file is part of the DATAtourisme project.
* 2022
* @author Conjecto <contact@conjecto.com>
* SPDX-License-Identifier: GPL-3.0-or-later
* For the full copyright and license information, please view the LICENSE file that was distributed with this source code.
*/
namespace Datatourisme\Bundle\WebAppBundle\Entity;
use Doctrine\ORM\Event\PreUpdateEventArgs;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
/**
* @ORM\HasLifecycleCallbacks
*/
trait UploadableTrait
{
/**
* @ORM\Column(name="file_path", type="string", nullable=true)
*
* @var string
*/
protected $filePath;
/**
* @ORM\Column(name="file_name", type="string", nullable=true)
*
* @var string
*/
protected $fileName;
/**
* @var File
*/
protected $file;
/**
* used to force file update when changing file.
*
* @var \DateTime
* @ORM\Column(type="datetime", nullable=true)
*/
protected $uploaded;
public function __clone()
{
$file = $this->getFile();
if (!empty($file)) {
$this->id = null;
$fs = new Filesystem();
$tmpFileName = sha1(uniqid(mt_rand(), true)).'.'.$file->getFileInfo()->getExtension();
$fs->copy($this->getTemplatesRootDir().'/'.$this->filePath, $this->getTemplatesRootDir().'/'.$tmpFileName);
$this->setFile(new File($this->getTemplatesRootDir().'/'.$tmpFileName), $this->getFileName());
}
}
/**
* @param string $filePath
*/
public function setFilePath($filePath)
{
$this->filePath = $filePath;
}
/**
* @return File
*/
public function getFile()
{
if (null !== $this->filePath && file_exists($this->getTemplatesRootDir().'/'.$this->filePath)) {
$this->file = new File($this->getTemplatesRootDir().'/'.$this->filePath);
}
return $this->file;
}
/**
* @return string
*/
public function getFilePath()
{
return $this->filePath;
}
/**
* @param string $fileName
*/
public function setFileName($fileName)
{
$this->fileName = $fileName;
$this->slugFileName();
}
/**
* @return string
*/
public function getFileName()
{
return $this->fileName;
}
/**
* @param File $file
* @param string $name
*/
public function setFile(File $file = null, $name = null)
{
if (!empty($file)) {
$this->uploaded = new \DateTime();
$this->file = $file;
if ($this->file instanceof UploadedFile) {
$this->filePath = sha1(uniqid(mt_rand(), true)).'.'.$this->file->guessClientExtension();
$this->fileName = $this->file->getClientOriginalName();
$this->slugFileName();
} else {
$this->filePath = $file->getFileInfo()->getFilename();
$this->fileName = ($name) ? $name : $file->getFileInfo()->getFilename();