mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-08-20 14:43:49 +00:00
Merge remote-tracking branch 'origin/master' into issue520_reference_address_update
This commit is contained in:
@@ -16,9 +16,9 @@ use Chill\MainBundle\Serializer\Model\Collection;
|
||||
use Exception;
|
||||
use LogicException;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\Serializer\Exception\NotEncodableValueException;
|
||||
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
@@ -33,11 +33,11 @@ class ApiController extends AbstractCRUDController
|
||||
* Base method for handling api action.
|
||||
*
|
||||
* @param mixed $id
|
||||
* @param mixed $_format
|
||||
* @param string $_format
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function entityApi(Request $request, $id, $_format): Response
|
||||
public function entityApi(Request $request, $id, ?string $_format = 'json'): Response
|
||||
{
|
||||
switch ($request->getMethod()) {
|
||||
case Request::METHOD_GET:
|
||||
@@ -55,7 +55,7 @@ class ApiController extends AbstractCRUDController
|
||||
return $this->entityDelete('_entity', $request, $id, $_format);
|
||||
|
||||
default:
|
||||
throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException('This method is not implemented');
|
||||
throw new BadRequestHttpException('This method is not implemented');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ class ApiController extends AbstractCRUDController
|
||||
return $this->entityPostAction('_entity', $request, $_format);
|
||||
|
||||
default:
|
||||
throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException('This method is not implemented');
|
||||
throw new BadRequestHttpException('This method is not implemented');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ class ApiController extends AbstractCRUDController
|
||||
try {
|
||||
$entity = $this->deserialize($action, $request, $_format, $entity);
|
||||
} catch (NotEncodableValueException $e) {
|
||||
throw new BadRequestException('invalid json', 400, $e);
|
||||
throw new BadRequestHttpException('invalid json', 400, $e);
|
||||
}
|
||||
|
||||
$errors = $this->validate($action, $request, $_format, $entity);
|
||||
@@ -273,7 +273,7 @@ class ApiController extends AbstractCRUDController
|
||||
try {
|
||||
$postedData = $this->getSerializer()->deserialize($request->getContent(), $postedDataType, $_format, $postedDataContext);
|
||||
} catch (\Symfony\Component\Serializer\Exception\UnexpectedValueException $e) {
|
||||
throw new BadRequestException(sprintf('Unable to deserialize posted ' .
|
||||
throw new BadRequestHttpException(sprintf('Unable to deserialize posted ' .
|
||||
'data: %s', $e->getMessage()), 0, $e);
|
||||
}
|
||||
|
||||
@@ -290,7 +290,7 @@ class ApiController extends AbstractCRUDController
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new BadRequestException('this method is not supported');
|
||||
throw new BadRequestHttpException('this method is not supported');
|
||||
}
|
||||
|
||||
$errors = $this->validate($action, $request, $_format, $entity, [$postedData]);
|
||||
@@ -408,7 +408,7 @@ class ApiController extends AbstractCRUDController
|
||||
return $this->json($entity, Response::HTTP_OK, [], $context);
|
||||
}
|
||||
|
||||
throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException('This format is not implemented');
|
||||
throw new BadRequestHttpException('This format is not implemented');
|
||||
}
|
||||
|
||||
protected function entityPostAction($action, Request $request, string $_format): Response
|
||||
@@ -418,7 +418,7 @@ class ApiController extends AbstractCRUDController
|
||||
try {
|
||||
$entity = $this->deserialize($action, $request, $_format, $entity);
|
||||
} catch (NotEncodableValueException $e) {
|
||||
throw new BadRequestException('invalid json', 400, $e);
|
||||
throw new BadRequestHttpException('invalid json', 400, $e);
|
||||
}
|
||||
|
||||
$errors = $this->validate($action, $request, $_format, $entity);
|
||||
|
@@ -25,6 +25,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\Security\Core\Role\Role;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
@@ -1140,6 +1141,6 @@ class CRUDController extends AbstractController
|
||||
return $this->json($entity, Response::HTTP_OK, [], $context);
|
||||
}
|
||||
|
||||
throw new \Symfony\Component\HttpFoundation\Exception\BadRequestException('This format is not implemented');
|
||||
throw new BadRequestHttpException('This format is not implemented');
|
||||
}
|
||||
}
|
||||
|
@@ -11,6 +11,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\MainBundle\Command;
|
||||
|
||||
use Chill\MainBundle\Entity\Language;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
@@ -113,7 +114,7 @@ class LoadAndUpdateLanguagesCommand extends Command
|
||||
)
|
||||
);
|
||||
|
||||
$langageDB = $em->getRepository('ChillMainBundle:Language')->find($code);
|
||||
$langageDB = $em->getRepository(Language::class)->find($code);
|
||||
|
||||
if (!$excludeCode) {
|
||||
if (!$langageDB) {
|
||||
|
@@ -11,6 +11,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\MainBundle\Command;
|
||||
|
||||
use Chill\MainBundle\Entity\Country;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
@@ -87,7 +88,7 @@ class LoadCountriesCommand extends Command
|
||||
$em = $this->entityManager;
|
||||
|
||||
foreach ($countries as $country) {
|
||||
$countryStored = $em->getRepository('ChillMainBundle:Country')
|
||||
$countryStored = $em->getRepository(Country::class)
|
||||
->findOneBy(['countryCode' => $country->getCountryCode()]);
|
||||
|
||||
if (null === $countryStored) {
|
||||
|
@@ -43,7 +43,7 @@ class SetPasswordCommand extends Command
|
||||
public function _getUser($username)
|
||||
{
|
||||
return $this->entityManager
|
||||
->getRepository('ChillMainBundle:User')
|
||||
->getRepository(\Chill\MainBundle\Entity\User::class)
|
||||
->findOneBy(['username' => $username]);
|
||||
}
|
||||
|
||||
|
@@ -54,7 +54,7 @@ class CenterController extends AbstractController
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$center = $em->getRepository('ChillMainBundle:Center')->find($id);
|
||||
$center = $em->getRepository(\Chill\MainBundle\Entity\Center::class)->find($id);
|
||||
|
||||
if (!$center) {
|
||||
throw $this->createNotFoundException('Unable to find Center entity.');
|
||||
@@ -75,7 +75,7 @@ class CenterController extends AbstractController
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$entities = $em->getRepository('ChillMainBundle:Center')->findAll();
|
||||
$entities = $em->getRepository(\Chill\MainBundle\Entity\Center::class)->findAll();
|
||||
|
||||
return $this->render('@ChillMain/Center/index.html.twig', [
|
||||
'entities' => $entities,
|
||||
@@ -105,7 +105,7 @@ class CenterController extends AbstractController
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$center = $em->getRepository('ChillMainBundle:Center')->find($id);
|
||||
$center = $em->getRepository(\Chill\MainBundle\Entity\Center::class)->find($id);
|
||||
|
||||
if (!$center) {
|
||||
throw $this->createNotFoundException('Unable to find Center entity.');
|
||||
@@ -125,7 +125,7 @@ class CenterController extends AbstractController
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$center = $em->getRepository('ChillMainBundle:Center')->find($id);
|
||||
$center = $em->getRepository(\Chill\MainBundle\Entity\Center::class)->find($id);
|
||||
|
||||
if (!$center) {
|
||||
throw $this->createNotFoundException('Unable to find Center entity.');
|
||||
|
@@ -12,6 +12,7 @@ declare(strict_types=1);
|
||||
namespace Chill\MainBundle\Controller;
|
||||
|
||||
use Chill\MainBundle\CRUD\Controller\CRUDController;
|
||||
use Chill\MainBundle\Pagination\PaginatorInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class LocationController extends CRUDController
|
||||
@@ -29,4 +30,9 @@ class LocationController extends CRUDController
|
||||
{
|
||||
$query->where('e.availableForUsers = true'); //TODO not working
|
||||
}
|
||||
|
||||
protected function orderQuery(string $action, $query, Request $request, PaginatorInterface $paginator)
|
||||
{
|
||||
return $query->addOrderBy('e.name', 'DESC');
|
||||
}
|
||||
}
|
||||
|
@@ -22,6 +22,7 @@ use Chill\MainBundle\Pagination\PaginatorFactory;
|
||||
use Chill\MainBundle\Repository\NotificationRepository;
|
||||
use Chill\MainBundle\Security\Authorization\NotificationVoter;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
@@ -31,14 +32,19 @@ use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Core\Security;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
use function in_array;
|
||||
|
||||
/**
|
||||
* @Route("/{_locale}/notification")
|
||||
*/
|
||||
class NotificationController extends AbstractController
|
||||
{
|
||||
private LoggerInterface $chillLogger;
|
||||
|
||||
private EntityManagerInterface $em;
|
||||
|
||||
private LoggerInterface $logger;
|
||||
|
||||
private NotificationHandlerManager $notificationHandlerManager;
|
||||
|
||||
private NotificationRepository $notificationRepository;
|
||||
@@ -51,6 +57,8 @@ class NotificationController extends AbstractController
|
||||
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
LoggerInterface $chillLogger,
|
||||
LoggerInterface $logger,
|
||||
Security $security,
|
||||
NotificationRepository $notificationRepository,
|
||||
NotificationHandlerManager $notificationHandlerManager,
|
||||
@@ -58,6 +66,8 @@ class NotificationController extends AbstractController
|
||||
TranslatorInterface $translator
|
||||
) {
|
||||
$this->em = $em;
|
||||
$this->logger = $logger;
|
||||
$this->chillLogger = $chillLogger;
|
||||
$this->security = $security;
|
||||
$this->notificationRepository = $notificationRepository;
|
||||
$this->notificationHandlerManager = $notificationHandlerManager;
|
||||
@@ -150,6 +160,52 @@ class NotificationController extends AbstractController
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/{id}/access_key", name="chill_main_notification_grant_access_by_access_key")
|
||||
*/
|
||||
public function getAccessByAccessKey(Notification $notification, Request $request): Response
|
||||
{
|
||||
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_REMEMBERED');
|
||||
|
||||
if (!$this->security->getUser() instanceof User) {
|
||||
throw new AccessDeniedHttpException('You must be authenticated and a user to create a notification');
|
||||
}
|
||||
|
||||
foreach (['accessKey'/*, 'email'*/] as $param) {
|
||||
if (!$request->query->has($param)) {
|
||||
throw new BadRequestHttpException("Missing {$param} parameter");
|
||||
}
|
||||
}
|
||||
|
||||
if ($notification->getAccessKey() !== $request->query->getAlnum('accessKey')) {
|
||||
throw new AccessDeniedHttpException('access key is invalid');
|
||||
}
|
||||
|
||||
/*
|
||||
desactivated due to escaped '&' in email links
|
||||
if (!in_array($request->query->get('email'), $notification->getAddressesEmails(), true)) {
|
||||
return (new Response('The email address is no more associated with this notification'))
|
||||
->setStatusCode(Response::HTTP_FORBIDDEN);
|
||||
}
|
||||
*/
|
||||
|
||||
$notification->addAddressee($this->security->getUser());
|
||||
|
||||
$this->getDoctrine()->getManager()->flush();
|
||||
|
||||
$logMsg = '[Notification] a user is granted access to notification trough an access key';
|
||||
$context = [
|
||||
'notificationId' => $notification->getId(),
|
||||
'email' => $request->query->get('email'),
|
||||
'user' => $this->security->getUser()->getId(),
|
||||
];
|
||||
|
||||
$this->logger->info($logMsg, $context);
|
||||
$this->chillLogger->info($logMsg, $context);
|
||||
|
||||
return $this->redirectToRoute('chill_main_notification_show', ['id' => $notification->getId()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/inbox", name="chill_main_notification_my")
|
||||
*/
|
||||
|
@@ -87,7 +87,7 @@ class PermissionsGroupController extends AbstractController
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$permissionsGroup = $em->getRepository('ChillMainBundle:PermissionsGroup')->find($id);
|
||||
$permissionsGroup = $em->getRepository(\Chill\MainBundle\Entity\PermissionsGroup::class)->find($id);
|
||||
|
||||
if (!$permissionsGroup) {
|
||||
throw $this->createNotFoundException('Unable to find PermissionsGroup entity.');
|
||||
@@ -203,8 +203,8 @@ class PermissionsGroupController extends AbstractController
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$permissionsGroup = $em->getRepository('ChillMainBundle:PermissionsGroup')->find($pgid);
|
||||
$roleScope = $em->getRepository('ChillMainBundle:RoleScope')->find($rsid);
|
||||
$permissionsGroup = $em->getRepository(\Chill\MainBundle\Entity\PermissionsGroup::class)->find($pgid);
|
||||
$roleScope = $em->getRepository(\Chill\MainBundle\Entity\RoleScope::class)->find($rsid);
|
||||
|
||||
if (!$permissionsGroup) {
|
||||
throw $this->createNotFoundException('Unable to find PermissionsGroup entity.');
|
||||
@@ -269,7 +269,7 @@ class PermissionsGroupController extends AbstractController
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$permissionsGroup = $em->getRepository('ChillMainBundle:PermissionsGroup')->find($id);
|
||||
$permissionsGroup = $em->getRepository(\Chill\MainBundle\Entity\PermissionsGroup::class)->find($id);
|
||||
|
||||
if (!$permissionsGroup) {
|
||||
throw $this->createNotFoundException('Unable to find PermissionsGroup entity.');
|
||||
@@ -319,7 +319,7 @@ class PermissionsGroupController extends AbstractController
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$entities = $em->getRepository('ChillMainBundle:PermissionsGroup')->findAll();
|
||||
$entities = $em->getRepository(\Chill\MainBundle\Entity\PermissionsGroup::class)->findAll();
|
||||
|
||||
return $this->render('@ChillMain/PermissionsGroup/index.html.twig', [
|
||||
'entities' => $entities,
|
||||
@@ -349,7 +349,7 @@ class PermissionsGroupController extends AbstractController
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$permissionsGroup = $em->getRepository('ChillMainBundle:PermissionsGroup')->find($id);
|
||||
$permissionsGroup = $em->getRepository(\Chill\MainBundle\Entity\PermissionsGroup::class)->find($id);
|
||||
|
||||
if (!$permissionsGroup) {
|
||||
throw $this->createNotFoundException('Unable to find PermissionsGroup entity.');
|
||||
@@ -405,7 +405,7 @@ class PermissionsGroupController extends AbstractController
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$permissionsGroup = $em
|
||||
->getRepository('ChillMainBundle:PermissionsGroup')
|
||||
->getRepository(\Chill\MainBundle\Entity\PermissionsGroup::class)
|
||||
->find($id);
|
||||
|
||||
if (!$permissionsGroup) {
|
||||
@@ -469,7 +469,7 @@ class PermissionsGroupController extends AbstractController
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$roleScope = $em->getRepository('ChillMainBundle:RoleScope')
|
||||
$roleScope = $em->getRepository(\Chill\MainBundle\Entity\RoleScope::class)
|
||||
->findOneBy(['role' => $role, 'scope' => $scope]);
|
||||
|
||||
if (null === $roleScope) {
|
||||
|
@@ -54,7 +54,7 @@ class ScopeController extends AbstractController
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$scope = $em->getRepository('ChillMainBundle:Scope')->find($id);
|
||||
$scope = $em->getRepository(\Chill\MainBundle\Entity\Scope::class)->find($id);
|
||||
|
||||
if (!$scope) {
|
||||
throw $this->createNotFoundException('Unable to find Scope entity.');
|
||||
@@ -75,7 +75,7 @@ class ScopeController extends AbstractController
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$entities = $em->getRepository('ChillMainBundle:Scope')->findAll();
|
||||
$entities = $em->getRepository(\Chill\MainBundle\Entity\Scope::class)->findAll();
|
||||
|
||||
return $this->render('@ChillMain/Scope/index.html.twig', [
|
||||
'entities' => $entities,
|
||||
@@ -105,7 +105,7 @@ class ScopeController extends AbstractController
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$scope = $em->getRepository('ChillMainBundle:Scope')->find($id);
|
||||
$scope = $em->getRepository(\Chill\MainBundle\Entity\Scope::class)->find($id);
|
||||
|
||||
if (!$scope) {
|
||||
throw $this->createNotFoundException('Unable to find Scope entity.');
|
||||
@@ -125,7 +125,7 @@ class ScopeController extends AbstractController
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$scope = $em->getRepository('ChillMainBundle:Scope')->find($id);
|
||||
$scope = $em->getRepository(\Chill\MainBundle\Entity\Scope::class)->find($id);
|
||||
|
||||
if (!$scope) {
|
||||
throw $this->createNotFoundException('Unable to find Scope entity.');
|
||||
|
@@ -22,7 +22,6 @@ use Chill\MainBundle\Search\UnknowSearchNameException;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\Form\Extension\Core\Type\FormType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
@@ -122,7 +121,7 @@ class SearchController extends AbstractController
|
||||
|
||||
public function searchAction(Request $request, $_format)
|
||||
{
|
||||
$pattern = $request->query->get('q', '');
|
||||
$pattern = trim($request->query->get('q', ''));
|
||||
|
||||
if ('' === $pattern) {
|
||||
switch ($_format) {
|
||||
@@ -216,7 +215,7 @@ class SearchController extends AbstractController
|
||||
$types = $request->query->get('type', []);
|
||||
|
||||
if (count($types) === 0) {
|
||||
throw new BadRequestException('The request must contains at '
|
||||
throw new BadRequestHttpException('The request must contains at '
|
||||
. ' one type');
|
||||
}
|
||||
|
||||
|
@@ -61,7 +61,7 @@ class UserController extends CRUDController
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$user = $em->getRepository('ChillMainBundle:User')->find($uid);
|
||||
$user = $em->getRepository(\Chill\MainBundle\Entity\User::class)->find($uid);
|
||||
|
||||
if (!$user) {
|
||||
throw $this->createNotFoundException('Unable to find User entity.');
|
||||
@@ -118,13 +118,13 @@ class UserController extends CRUDController
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$user = $em->getRepository('ChillMainBundle:User')->find($uid);
|
||||
$user = $em->getRepository(\Chill\MainBundle\Entity\User::class)->find($uid);
|
||||
|
||||
if (!$user) {
|
||||
throw $this->createNotFoundException('Unable to find User entity.');
|
||||
}
|
||||
|
||||
$groupCenter = $em->getRepository('ChillMainBundle:GroupCenter')
|
||||
$groupCenter = $em->getRepository(\Chill\MainBundle\Entity\GroupCenter::class)
|
||||
->find($gcid);
|
||||
|
||||
if (!$groupCenter) {
|
||||
@@ -330,7 +330,7 @@ class UserController extends CRUDController
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$groupCenterManaged = $em->getRepository('ChillMainBundle:GroupCenter')
|
||||
$groupCenterManaged = $em->getRepository(\Chill\MainBundle\Entity\GroupCenter::class)
|
||||
->findOneBy([
|
||||
'center' => $groupCenter->getCenter(),
|
||||
'permissionsGroup' => $groupCenter->getPermissionsGroup(),
|
||||
|
@@ -25,7 +25,6 @@ use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\Form\Extension\Core\Type\FormType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
@@ -144,7 +143,7 @@ class WorkflowController extends AbstractController
|
||||
public function getAccessByAccessKey(EntityWorkflowStep $entityWorkflowStep, Request $request): Response
|
||||
{
|
||||
if (null === $accessKey = $request->query->get('accessKey', null)) {
|
||||
throw new BadRequestException('accessKey is missing');
|
||||
throw new BadRequestHttpException('accessKey is missing');
|
||||
}
|
||||
|
||||
if (!$this->getUser() instanceof User) {
|
||||
|
@@ -16,17 +16,20 @@ use DateTime;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||
|
||||
trait TrackCreationTrait
|
||||
{
|
||||
/**
|
||||
* @ORM\Column(type="datetime_immutable", nullable=true, options={"default": NULL})
|
||||
* @Serializer\Groups({"read"})
|
||||
*/
|
||||
private ?DateTimeImmutable $createdAt = null;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=User::class)
|
||||
* @ORM\JoinColumn(nullable=true)
|
||||
* @Serializer\Groups({"read"})
|
||||
*/
|
||||
private ?User $createdBy = null;
|
||||
|
||||
|
@@ -16,17 +16,20 @@ use DateTime;
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||
|
||||
trait TrackUpdateTrait
|
||||
{
|
||||
/**
|
||||
* @ORM\Column(type="datetime_immutable", nullable=true, options={"default": NULL})
|
||||
* @Serializer\Groups({"read"})
|
||||
*/
|
||||
private ?DateTimeImmutable $updatedAt = null;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity=User::class)
|
||||
* @ORM\JoinColumn(nullable=true)
|
||||
* @Serializer\Groups({"read"})
|
||||
*/
|
||||
private ?User $updatedBy = null;
|
||||
|
||||
|
@@ -140,6 +140,7 @@ class Address
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="Chill\MainBundle\Entity\PostalCode")
|
||||
* @ORM\JoinColumn(nullable=false)
|
||||
* @Groups({"write"})
|
||||
*/
|
||||
private ?PostalCode $postcode = null;
|
||||
@@ -480,8 +481,11 @@ class Address
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setStreet(string $street): self
|
||||
public function setStreet(?string $street): self
|
||||
{
|
||||
if (null === $street) {
|
||||
$street = '';
|
||||
}
|
||||
$this->street = $street;
|
||||
|
||||
return $this;
|
||||
@@ -515,8 +519,11 @@ class Address
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setStreetNumber(string $streetNumber): self
|
||||
public function setStreetNumber(?string $streetNumber): self
|
||||
{
|
||||
if (null === $streetNumber) {
|
||||
$streetNumber = '';
|
||||
}
|
||||
$this->streetNumber = $streetNumber;
|
||||
|
||||
return $this;
|
||||
|
@@ -18,6 +18,9 @@ use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
use function count;
|
||||
use function in_array;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
@@ -31,15 +34,34 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||
*/
|
||||
class Notification implements TrackUpdateInterface
|
||||
{
|
||||
/**
|
||||
* @ORM\Column(type="text", nullable=false)
|
||||
*/
|
||||
private string $accessKey;
|
||||
|
||||
private array $addedAddresses = [];
|
||||
|
||||
/**
|
||||
* @ORM\ManyToMany(targetEntity=User::class)
|
||||
* @ORM\JoinTable(name="chill_main_notification_addresses_user")
|
||||
* @Assert\Count(min="1", minMessage="notification.At least one addressee")
|
||||
*/
|
||||
private Collection $addressees;
|
||||
|
||||
/**
|
||||
* a list of destinee which will receive notifications.
|
||||
*
|
||||
* @var array|string[]
|
||||
* @ORM\Column(type="json")
|
||||
*/
|
||||
private array $addressesEmails = [];
|
||||
|
||||
/**
|
||||
* a list of emails adresses which were added to the notification.
|
||||
*
|
||||
* @var array|string[]
|
||||
*/
|
||||
private array $addressesEmailsAdded = [];
|
||||
|
||||
private ?ArrayCollection $addressesOnLoad = null;
|
||||
|
||||
/**
|
||||
@@ -111,6 +133,7 @@ class Notification implements TrackUpdateInterface
|
||||
$this->unreadBy = new ArrayCollection();
|
||||
$this->comments = new ArrayCollection();
|
||||
$this->setDate(new DateTimeImmutable());
|
||||
$this->accessKey = bin2hex(openssl_random_pseudo_bytes(24));
|
||||
}
|
||||
|
||||
public function addAddressee(User $addressee): self
|
||||
@@ -123,6 +146,14 @@ class Notification implements TrackUpdateInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addAddressesEmail(string $email)
|
||||
{
|
||||
if (!in_array($email, $this->addressesEmails, true)) {
|
||||
$this->addressesEmails[] = $email;
|
||||
$this->addressesEmailsAdded[] = $email;
|
||||
}
|
||||
}
|
||||
|
||||
public function addComment(NotificationComment $comment): self
|
||||
{
|
||||
if (!$this->comments->contains($comment)) {
|
||||
@@ -142,6 +173,30 @@ class Notification implements TrackUpdateInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Assert\Callback
|
||||
*
|
||||
* @param array $payload
|
||||
*/
|
||||
public function assertCountAddresses(ExecutionContextInterface $context, $payload): void
|
||||
{
|
||||
if (0 === (count($this->getAddressesEmails()) + count($this->getAddressees()))) {
|
||||
$context->buildViolation('notification.At least one addressee')
|
||||
->atPath('addressees')
|
||||
->addViolation();
|
||||
}
|
||||
}
|
||||
|
||||
public function getAccessKey(): string
|
||||
{
|
||||
return $this->accessKey;
|
||||
}
|
||||
|
||||
public function getAddedAddresses(): array
|
||||
{
|
||||
return $this->addedAddresses;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection|User[]
|
||||
*/
|
||||
@@ -155,6 +210,22 @@ class Notification implements TrackUpdateInterface
|
||||
return $this->addressees;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|string[]
|
||||
*/
|
||||
public function getAddressesEmails(): array
|
||||
{
|
||||
return $this->addressesEmails;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array|string[]
|
||||
*/
|
||||
public function getAddressesEmailsAdded(): array
|
||||
{
|
||||
return $this->addressesEmailsAdded;
|
||||
}
|
||||
|
||||
public function getComments(): Collection
|
||||
{
|
||||
return $this->comments;
|
||||
@@ -271,6 +342,14 @@ class Notification implements TrackUpdateInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeAddressesEmail(string $email)
|
||||
{
|
||||
if (in_array($email, $this->addressesEmails, true)) {
|
||||
$this->addressesEmails = array_filter($this->addressesEmails, static fn ($e) => $e !== $email);
|
||||
$this->addressesEmailsAdded = array_filter($this->addressesEmailsAdded, static fn ($e) => $e !== $email);
|
||||
}
|
||||
}
|
||||
|
||||
public function removeComment(NotificationComment $comment): self
|
||||
{
|
||||
$this->comments->removeElement($comment);
|
||||
|
@@ -160,6 +160,8 @@ class EntityWorkflowStep
|
||||
/**
|
||||
* get all the users which are allowed to apply a transition: those added manually, and
|
||||
* those added automatically bu using an access key.
|
||||
*
|
||||
* @psalm-suppress DuplicateArrayKey
|
||||
*/
|
||||
public function getAllDestUser(): Collection
|
||||
{
|
||||
|
@@ -12,12 +12,17 @@ declare(strict_types=1);
|
||||
namespace Chill\MainBundle\Form;
|
||||
|
||||
use Chill\MainBundle\Entity\Notification;
|
||||
use Chill\MainBundle\Form\Type\ChillCollectionType;
|
||||
use Chill\MainBundle\Form\Type\ChillTextareaType;
|
||||
use Chill\MainBundle\Form\Type\PickUserDynamicType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\EmailType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints\Email;
|
||||
use Symfony\Component\Validator\Constraints\NotBlank;
|
||||
use Symfony\Component\Validator\Constraints\NotNull;
|
||||
|
||||
class NotificationType extends AbstractType
|
||||
{
|
||||
@@ -30,9 +35,27 @@ class NotificationType extends AbstractType
|
||||
])
|
||||
->add('addressees', PickUserDynamicType::class, [
|
||||
'multiple' => true,
|
||||
'required' => false,
|
||||
])
|
||||
->add('message', ChillTextareaType::class, [
|
||||
'required' => false,
|
||||
])
|
||||
->add('addressesEmails', ChillCollectionType::class, [
|
||||
'label' => 'notification.dest by email',
|
||||
'help' => 'notification.dest by email help',
|
||||
'by_reference' => false,
|
||||
'allow_add' => true,
|
||||
'allow_delete' => true,
|
||||
'entry_type' => EmailType::class,
|
||||
'button_add_label' => 'notification.Add an email',
|
||||
'button_remove_label' => 'notification.Remove an email',
|
||||
'empty_collection_explain' => 'notification.Any email',
|
||||
'entry_options' => [
|
||||
'constraints' => [
|
||||
new NotNull(), new NotBlank(), new Email(['checkMX' => true]),
|
||||
],
|
||||
'label' => 'Email',
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
|
37
src/Bundle/ChillMainBundle/Form/Type/AddressDateType.php
Normal file
37
src/Bundle/ChillMainBundle/Form/Type/AddressDateType.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\MainBundle\Form\Type;
|
||||
|
||||
use Chill\MainBundle\Entity\Address;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class AddressDateType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder
|
||||
->add(
|
||||
'validFrom',
|
||||
ChillDateType::class,
|
||||
[
|
||||
'required' => true,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefault('data_class', Address::class);
|
||||
}
|
||||
}
|
@@ -11,6 +11,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\MainBundle\Form\Type;
|
||||
|
||||
use Chill\MainBundle\Entity\Country;
|
||||
use Chill\MainBundle\Form\Type\DataTransformer\ObjectToIdTransformer;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
@@ -50,13 +51,13 @@ class Select2CountryType extends AbstractType
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$transformer = new ObjectToIdTransformer($this->em, 'Chill\MainBundle\Entity\Country');
|
||||
$transformer = new ObjectToIdTransformer($this->em, Country::class);
|
||||
$builder->addModelTransformer($transformer);
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$countries = $this->em->getRepository('Chill\MainBundle\Entity\Country')->findAll();
|
||||
$countries = $this->em->getRepository(Country::class)->findAll();
|
||||
$choices = [];
|
||||
$preferredCountries = $this->parameterBag->get('chill_main.available_countries');
|
||||
$preferredChoices = [];
|
||||
|
@@ -11,6 +11,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Chill\MainBundle\Form\Type;
|
||||
|
||||
use Chill\MainBundle\Entity\Language;
|
||||
use Chill\MainBundle\Form\Type\DataTransformer\MultipleObjectsToIdTransformer;
|
||||
use Chill\MainBundle\Templating\TranslatableStringHelper;
|
||||
use Doctrine\Persistence\ObjectManager;
|
||||
@@ -50,13 +51,13 @@ class Select2LanguageType extends AbstractType
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$transformer = new MultipleObjectsToIdTransformer($this->em, 'Chill\MainBundle\Entity\Language');
|
||||
$transformer = new MultipleObjectsToIdTransformer($this->em, Language::class);
|
||||
$builder->addModelTransformer($transformer);
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$languages = $this->em->getRepository('Chill\MainBundle\Entity\Language')->findAll();
|
||||
$languages = $this->em->getRepository(Language::class)->findAll();
|
||||
$preferredLanguages = $this->parameterBag->get('chill_main.available_languages');
|
||||
$choices = [];
|
||||
$preferredChoices = [];
|
||||
|
@@ -73,6 +73,17 @@ class NotificationMailer
|
||||
* Send a email after a notification is persisted.
|
||||
*/
|
||||
public function postPersistNotification(Notification $notification, LifecycleEventArgs $eventArgs): void
|
||||
{
|
||||
$this->sendNotificationEmailsToAddresses($notification);
|
||||
$this->sendNotificationEmailsToAddressesEmails($notification);
|
||||
}
|
||||
|
||||
public function postUpdateNotification(Notification $notification, LifecycleEventArgs $eventArgs): void
|
||||
{
|
||||
$this->sendNotificationEmailsToAddressesEmails($notification);
|
||||
}
|
||||
|
||||
private function sendNotificationEmailsToAddresses(Notification $notification): void
|
||||
{
|
||||
foreach ($notification->getAddressees() as $addressee) {
|
||||
if (null === $addressee->getEmail()) {
|
||||
@@ -108,4 +119,31 @@ class NotificationMailer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function sendNotificationEmailsToAddressesEmails(Notification $notification): void
|
||||
{
|
||||
foreach ($notification->getAddressesEmailsAdded() as $emailAddress) {
|
||||
$email = new TemplatedEmail();
|
||||
$email
|
||||
->textTemplate('@ChillMain/Notification/email_non_system_notification_content_to_email.fr.md.twig')
|
||||
->context([
|
||||
'notification' => $notification,
|
||||
'dest' => $emailAddress,
|
||||
]);
|
||||
|
||||
$email
|
||||
->subject($notification->getTitle())
|
||||
->to($emailAddress);
|
||||
|
||||
try {
|
||||
$this->mailer->send($email);
|
||||
} catch (TransportExceptionInterface $e) {
|
||||
$this->logger->warning('[NotificationMailer] could not send an email notification', [
|
||||
'to' => $emailAddress,
|
||||
'error_message' => $e->getMessage(),
|
||||
'error_trace' => $e->getTraceAsString(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\MainBundle\Notification\EventListener;
|
||||
|
||||
use Chill\MainBundle\Notification\NotificationPersisterInterface;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpKernel\Event\TerminateEvent;
|
||||
use function count;
|
||||
|
||||
class PersistNotificationOnTerminateEventSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
private EntityManagerInterface $em;
|
||||
|
||||
private NotificationPersisterInterface $persister;
|
||||
|
||||
public function __construct(EntityManagerInterface $em, NotificationPersisterInterface $persister)
|
||||
{
|
||||
$this->em = $em;
|
||||
$this->persister = $persister;
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [
|
||||
'kernel.terminate' => [
|
||||
['onKernelTerminate', 1024], // we must ensure that the priority is before sending email
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function onKernelTerminate(TerminateEvent $event): void
|
||||
{
|
||||
if ($event->isMasterRequest()) {
|
||||
$this->persistNotifications();
|
||||
}
|
||||
}
|
||||
|
||||
private function persistNotifications(): void
|
||||
{
|
||||
if (0 < count($this->persister->getWaitingNotifications())) {
|
||||
foreach ($this->persister->getWaitingNotifications() as $notification) {
|
||||
$this->em->persist($notification);
|
||||
}
|
||||
|
||||
$this->em->flush();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\MainBundle\Notification;
|
||||
|
||||
use Chill\MainBundle\Entity\Notification;
|
||||
|
||||
class NotificationPersister implements NotificationPersisterInterface
|
||||
{
|
||||
private array $waitingNotifications = [];
|
||||
|
||||
/**
|
||||
* @return array|Notification[]
|
||||
*/
|
||||
public function getWaitingNotifications(): array
|
||||
{
|
||||
return $this->waitingNotifications;
|
||||
}
|
||||
|
||||
public function persist(Notification $notification): void
|
||||
{
|
||||
$this->waitingNotifications[] = $notification;
|
||||
}
|
||||
}
|
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\MainBundle\Notification;
|
||||
|
||||
use Chill\MainBundle\Entity\Notification;
|
||||
|
||||
/**
|
||||
* Store the notification.
|
||||
*
|
||||
* Those notification will be stored into database by the kernel. This
|
||||
* will also ensure that this happens outside of regular operations
|
||||
* operated by the entity manager.
|
||||
*/
|
||||
interface NotificationPersisterInterface
|
||||
{
|
||||
/**
|
||||
* @return array|Notification[]
|
||||
*/
|
||||
public function getWaitingNotifications(): array;
|
||||
|
||||
public function persist(Notification $notification): void;
|
||||
}
|
@@ -22,7 +22,7 @@ use libphonenumber\PhoneNumber;
|
||||
*/
|
||||
interface PhoneNumberHelperInterface
|
||||
{
|
||||
public function format(PhoneNumber $phoneNumber): string;
|
||||
public function format(?PhoneNumber $phoneNumber = null): string;
|
||||
|
||||
/**
|
||||
* Get type (mobile, landline, ...) for phone number.
|
||||
|
@@ -78,8 +78,12 @@ final class PhonenumberHelper implements PhoneNumberHelperInterface
|
||||
*
|
||||
* @throws NumberParseException
|
||||
*/
|
||||
public function format(PhoneNumber $phoneNumber): string
|
||||
public function format(?PhoneNumber $phoneNumber = null): string
|
||||
{
|
||||
if (null === $phoneNumber) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $this->phoneNumberUtil
|
||||
->formatOutOfCountryCallingNumber($phoneNumber, $this->config['default_carrier_code']);
|
||||
}
|
||||
|
@@ -56,17 +56,18 @@ final class NotificationRepository implements ObjectRepository
|
||||
if (null === $this->notificationByRelatedEntityAndUserAssociatedStatement) {
|
||||
$sql =
|
||||
'SELECT
|
||||
SUM((EXISTS (SELECT 1 AS c FROM chill_main_notification_addresses_unread cmnau WHERE user_id = 1812 and cmnau.notification_id = cmn.id))::int) AS unread,
|
||||
SUM((cmn.sender_id = 1812)::int) AS sent,
|
||||
SUM((EXISTS (SELECT 1 AS c FROM chill_main_notification_addresses_unread cmnau WHERE user_id = :userid and cmnau.notification_id = cmn.id))::int) AS unread,
|
||||
SUM((cmn.sender_id = :userid)::int) AS sent,
|
||||
COUNT(cmn.*) AS total
|
||||
FROM chill_main_notification cmn
|
||||
WHERE relatedentityclass = :relatedEntityClass AND relatedentityid = :relatedEntityId AND sender_id IS NOT NULL';
|
||||
|
||||
$this->notificationByRelatedEntityAndUserAssociatedStatement =
|
||||
$this->em->getConnection()->prepare($sql);
|
||||
}
|
||||
|
||||
$results = $this->notificationByRelatedEntityAndUserAssociatedStatement
|
||||
->executeQuery(['relatedEntityClass' => $relatedEntityClass, 'relatedEntityId' => $relatedEntityId]);
|
||||
->executeQuery(['relatedEntityClass' => $relatedEntityClass, 'relatedEntityId' => $relatedEntityId, 'userid' => $user->getId()]);
|
||||
|
||||
$result = $results->fetchAssociative();
|
||||
|
||||
|
@@ -16,6 +16,9 @@
|
||||
// Chill forms
|
||||
@import './scss/forms';
|
||||
|
||||
// Extend bootstrap accordion
|
||||
@import './scss/accordion';
|
||||
|
||||
// Chill record_actions
|
||||
@import './scss/record_actions';
|
||||
|
||||
|
@@ -0,0 +1,11 @@
|
||||
.accordion {
|
||||
// show a folded / label on accordion
|
||||
button[aria-expanded="true"] > span.folded,
|
||||
button[aria-expanded="false"] > span.unfolded { display: none; }
|
||||
button[aria-expanded="false"] > span.folded,
|
||||
button[aria-expanded="true"] > span.unfolded { display: inline; }
|
||||
|
||||
.accordion-item {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
}
|
@@ -8,30 +8,31 @@ window.addEventListener('DOMContentLoaded', function (e) {
|
||||
document.querySelectorAll('.notification_toggle_read_status')
|
||||
.forEach(function (el, i) {
|
||||
createApp({
|
||||
template: '<notification-read-toggle ' +
|
||||
':notificationId="notificationId" ' +
|
||||
':buttonClass="buttonClass" ' +
|
||||
':buttonNoText="buttonNoText" ' +
|
||||
':showUrl="showUrl" ' +
|
||||
':isRead="isRead"' +
|
||||
'@markRead="onMarkRead" @markUnread="onMarkUnread"' +
|
||||
'></notification-read-toggle>',
|
||||
template: `<notification-read-toggle
|
||||
:notificationId="notificationId"
|
||||
:buttonClass="buttonClass"
|
||||
:buttonNoText="buttonNoText"
|
||||
:showUrl="showUrl"
|
||||
:isRead="isRead"
|
||||
@markRead="onMarkRead"
|
||||
@markUnread="onMarkUnread">
|
||||
</notification-read-toggle>`,
|
||||
components: {
|
||||
NotificationReadToggle,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
notificationId: +el.dataset.notificationId,
|
||||
notificationId: el.dataset.notificationId,
|
||||
buttonClass: el.dataset.buttonClass,
|
||||
buttonNoText: 'false' === el.dataset.buttonText,
|
||||
showUrl: el.dataset.showButtonUrl,
|
||||
isRead: 1 === +el.dataset.notificationCurrentIsRead,
|
||||
isRead: 1 === Number.parseInt(el.dataset.notificationCurrentIsRead),
|
||||
container: el.dataset.container
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
getContainer() {
|
||||
return document.querySelectorAll('div.' + this.container);
|
||||
return document.querySelectorAll(`div.${this.container}`);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@@ -51,9 +51,7 @@ function loadDynamicPicker(element) {
|
||||
},
|
||||
methods: {
|
||||
addNewEntity(entity) {
|
||||
console.log('addNewEntity', entity);
|
||||
if (this.multiple) {
|
||||
console.log('adding multiple');
|
||||
if (!this.picked.some(el => {
|
||||
return el.type === entity.type && el.id === entity.id;
|
||||
})) {
|
||||
@@ -71,7 +69,6 @@ function loadDynamicPicker(element) {
|
||||
}
|
||||
},
|
||||
removeEntity(entity) {
|
||||
console.log('removeEntity', entity);
|
||||
this.picked = this.picked.filter(e => !(e.type === entity.type && e.id === entity.id));
|
||||
input.value = JSON.stringify(this.picked);
|
||||
},
|
||||
@@ -86,7 +83,6 @@ function loadDynamicPicker(element) {
|
||||
|
||||
|
||||
document.addEventListener('show-hide-show', function(e) {
|
||||
console.log('creation event caught')
|
||||
loadDynamicPicker(e.detail.container)
|
||||
})
|
||||
|
||||
@@ -94,17 +90,14 @@ document.addEventListener('show-hide-hide', function(e) {
|
||||
console.log('hiding event caught')
|
||||
e.detail.container.querySelectorAll('[data-module="pick-dynamic"]').forEach((el) => {
|
||||
let uniqId = el.dataset.uniqid;
|
||||
console.log(uniqId);
|
||||
if (appsOnPage.has(uniqId)) {
|
||||
appsOnPage.get(uniqId).unmount();
|
||||
console.log('App has been unmounted')
|
||||
appsOnPage.delete(uniqId);
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function(e) {
|
||||
console.log('loaded event', e)
|
||||
loadDynamicPicker(document)
|
||||
})
|
||||
|
||||
|
@@ -628,6 +628,10 @@ export default {
|
||||
newAddress = Object.assign(newAddress, {
|
||||
'addressReference': this.entity.selected.address.addressReference
|
||||
});
|
||||
} else {
|
||||
newAddress = Object.assign(newAddress, {
|
||||
'addressReference': null
|
||||
});
|
||||
}
|
||||
|
||||
if (this.validFrom) {
|
||||
|
@@ -8,12 +8,15 @@ import L from 'leaflet';
|
||||
import markerIconPng from 'leaflet/dist/images/marker-icon.png'
|
||||
import 'leaflet/dist/leaflet.css';
|
||||
|
||||
let map;
|
||||
let marker;
|
||||
|
||||
export default {
|
||||
name: 'AddressMap',
|
||||
props: ['entity'],
|
||||
data() {
|
||||
return {
|
||||
map: null,
|
||||
marker: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
center() {
|
||||
return this.entity.selected.addressMap.center;
|
||||
@@ -21,30 +24,33 @@ export default {
|
||||
},
|
||||
methods:{
|
||||
init() {
|
||||
map = L.map('address_map').setView([46.67059, -1.42683], 12);
|
||||
this.map = L.map('address_map').setView([46.67059, -1.42683], 12);
|
||||
|
||||
map.scrollWheelZoom.disable();
|
||||
this.map.scrollWheelZoom.disable();
|
||||
|
||||
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
}).addTo(map);
|
||||
}).addTo(this.map);
|
||||
|
||||
const markerIcon = L.icon({
|
||||
iconUrl: markerIconPng,
|
||||
iconAnchor: [12, 41],
|
||||
});
|
||||
|
||||
marker = L.marker([48.8589, 2.3469], {icon: markerIcon}).addTo(map);
|
||||
|
||||
this.marker = L.marker([48.8589, 2.3469], {icon: markerIcon});
|
||||
this.marker.addTo(this.map);
|
||||
},
|
||||
update() {
|
||||
//console.log('update map with : ', this.address.addressMap.center)
|
||||
marker.setLatLng(this.entity.addressMap.center);
|
||||
map.setView(this.entity.addressMap.center, 15);
|
||||
//console.log('update map with : ', this.entity.addressMap.center)
|
||||
if (this.marker && this.entity.addressMap.center) {
|
||||
this.marker.setLatLng(this.entity.addressMap.center);
|
||||
this.map.setView(this.entity.addressMap.center, 15);
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
this.init()
|
||||
this.init();
|
||||
this.update();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@@ -119,7 +119,7 @@ export default {
|
||||
},
|
||||
listenInputSearch(query) {
|
||||
//console.log('listenInputSearch', query, this.isAddressSelectorOpen);
|
||||
if (!this.entity.selected.writeNew.postcode) {
|
||||
if (!this.entity.selected.writeNew.postcode && 'id' in this.entity.selected.city) {
|
||||
if (query.length > 2) {
|
||||
this.isLoading = true;
|
||||
searchReferenceAddresses(query, this.entity.selected.city).then(
|
||||
|
@@ -106,6 +106,9 @@ export default {
|
||||
this.$emit('getReferenceAddresses', this.value);
|
||||
if (this.value.center) {
|
||||
this.updateMapCenter(this.value.center);
|
||||
if (this.value.center.coordinates) {
|
||||
this.entity.selected.postcode.coordinates = this.value.center.coordinates;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@@ -25,14 +25,14 @@
|
||||
{{ $t('my_accompanying_courses.tab') }}
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<!-- <li class="nav-item">
|
||||
<a class="nav-link"
|
||||
:class="{'active': activeTab === 'MyWorks'}"
|
||||
@click="selectTab('MyWorks')">
|
||||
{{ $t('my_works.tab') }}
|
||||
<tab-counter :count="state.works.count"></tab-counter>
|
||||
</a>
|
||||
</li>
|
||||
</li> -->
|
||||
<li class="nav-item">
|
||||
<a class="nav-link"
|
||||
:class="{'active': activeTab === 'MyEvaluations'}"
|
||||
@@ -135,7 +135,7 @@ export default {
|
||||
for (const m of [
|
||||
'MyNotifications',
|
||||
'MyAccompanyingCourses',
|
||||
'MyWorks',
|
||||
// 'MyWorks',
|
||||
'MyEvaluations',
|
||||
'MyTasks',
|
||||
'MyWorkflows',
|
||||
|
@@ -1,3 +1,4 @@
|
||||
// CURRENTLY NOT IN USE
|
||||
<template>
|
||||
<div class="accompanying_course_work">
|
||||
<div class="alert alert-light">{{ $t('my_works.description') }}</div>
|
||||
|
@@ -15,11 +15,11 @@ const appMessages = {
|
||||
description_warning: "Liste des tâches auxquelles je suis assigné et dont la date d'échéance est dépassée.",
|
||||
},
|
||||
my_accompanying_courses: {
|
||||
tab: "Mes parcours",
|
||||
description: "Liste des parcours d'accompagnement que l'on vient de m'attribuer.",
|
||||
tab: "Mes nouveaux parcours",
|
||||
description: "Liste des parcours d'accompagnement que l'on vient de m'attribuer depuis moins de 15 jours.",
|
||||
},
|
||||
my_notifications: {
|
||||
tab: "Mes notifications",
|
||||
tab: "Mes nouvelles notifications",
|
||||
description: "Liste des notifications reçues et non lues.",
|
||||
},
|
||||
my_workflows: {
|
||||
|
@@ -13,7 +13,7 @@ const isEmpty = (obj) => {
|
||||
const store = createStore({
|
||||
strict: debug,
|
||||
state: {
|
||||
works: {},
|
||||
// works: {},
|
||||
evaluations: {},
|
||||
tasks: {
|
||||
warning: {},
|
||||
@@ -26,9 +26,9 @@ const store = createStore({
|
||||
loading: false
|
||||
},
|
||||
getters: {
|
||||
isWorksLoaded(state) {
|
||||
return !isEmpty(state.works);
|
||||
},
|
||||
// isWorksLoaded(state) {
|
||||
// return !isEmpty(state.works);
|
||||
// },
|
||||
isEvaluationsLoaded(state) {
|
||||
return !isEmpty(state.evaluations);
|
||||
},
|
||||
@@ -49,7 +49,7 @@ const store = createStore({
|
||||
},
|
||||
counter(state) {
|
||||
return {
|
||||
works: state.works.count,
|
||||
// works: state.works.count,
|
||||
evaluations: state.evaluations.count,
|
||||
tasksWarning: state.tasks.warning.count,
|
||||
tasksAlert: state.tasks.alert.count,
|
||||
@@ -60,10 +60,10 @@ const store = createStore({
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
addWorks(state, works) {
|
||||
//console.log('addWorks', works);
|
||||
state.works = works;
|
||||
},
|
||||
// addWorks(state, works) {
|
||||
// //console.log('addWorks', works);
|
||||
// state.works = works;
|
||||
// },
|
||||
addEvaluations(state, evaluations) {
|
||||
//console.log('addEvaluations', evaluations);
|
||||
state.evaluations = evaluations;
|
||||
@@ -99,22 +99,22 @@ const store = createStore({
|
||||
switch (tab) {
|
||||
case 'MyCustoms':
|
||||
break;
|
||||
case 'MyWorks':
|
||||
if (!getters.isWorksLoaded) {
|
||||
commit('setLoading', true);
|
||||
const url = `/api/1.0/person/accompanying-period/work/my-near-end${'?'+ param}`;
|
||||
makeFetch('GET', url)
|
||||
.then((response) => {
|
||||
commit('addWorks', response);
|
||||
commit('setLoading', false);
|
||||
})
|
||||
.catch((error) => {
|
||||
commit('catchError', error);
|
||||
throw error;
|
||||
})
|
||||
;
|
||||
}
|
||||
break;
|
||||
// case 'MyWorks':
|
||||
// if (!getters.isWorksLoaded) {
|
||||
// commit('setLoading', true);
|
||||
// const url = `/api/1.0/person/accompanying-period/work/my-near-end${'?'+ param}`;
|
||||
// makeFetch('GET', url)
|
||||
// .then((response) => {
|
||||
// commit('addWorks', response);
|
||||
// commit('setLoading', false);
|
||||
// })
|
||||
// .catch((error) => {
|
||||
// commit('catchError', error);
|
||||
// throw error;
|
||||
// })
|
||||
// ;
|
||||
// }
|
||||
// break;
|
||||
case 'MyEvaluations':
|
||||
if (!getters.isEvaluationsLoaded) {
|
||||
commit('setLoading', true);
|
||||
|
@@ -210,10 +210,10 @@ export default {
|
||||
let
|
||||
type = this.type,
|
||||
data = {} ;
|
||||
|
||||
switch (type) {
|
||||
case 'person':
|
||||
data = this.$refs.castPerson.$data.person;
|
||||
console.log('person data are', data);
|
||||
break;
|
||||
|
||||
case 'thirdparty':
|
||||
@@ -235,8 +235,12 @@ export default {
|
||||
type = this.$refs.castNew.radioType;
|
||||
data = this.$refs.castNew.castDataByType();
|
||||
// console.log('type', type);
|
||||
data.civility = data.civility !== null ? {type: 'chill_main_civility', id: data.civility.id} : null;
|
||||
data.profession = data.profession !== null ? {type: 'third_party_profession', id: data.profession.id} : null;
|
||||
if (typeof data.civility !== 'undefined' && null !== data.civility) {
|
||||
data.civility = data.civility !== null ? {type: 'chill_main_civility', id: data.civility.id} : null;
|
||||
}
|
||||
if (typeof data.profession !== 'undefined' && null !== data.profession) {
|
||||
data.profession = data.profession !== null ? {type: 'third_party_profession', id: data.profession.id} : null;
|
||||
}
|
||||
// console.log('onthefly data', data);
|
||||
}
|
||||
} else {
|
||||
|
@@ -66,9 +66,18 @@ export default {
|
||||
translatedListOfTypes() {
|
||||
let trans = [];
|
||||
this.types.forEach(t => {
|
||||
trans.push(appMessages.fr.pick_entity[t].toLowerCase());
|
||||
if (this.$props.multiple) {
|
||||
trans.push(appMessages.fr.pick_entity[t].toLowerCase());
|
||||
} else {
|
||||
trans.push(appMessages.fr.pick_entity[t + '_one'].toLowerCase());
|
||||
}
|
||||
})
|
||||
return appMessages.fr.pick_entity.modal_title + trans.join(', ');
|
||||
|
||||
if (this.$props.multiple) {
|
||||
return appMessages.fr.pick_entity.modal_title + trans.join(', ');
|
||||
} else {
|
||||
return appMessages.fr.pick_entity.modal_title_one + trans.join(', ');
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -79,15 +88,10 @@ export default {
|
||||
);
|
||||
this.$refs.addPersons.resetSearch(); // to cast child method
|
||||
modal.showModal = false;
|
||||
console.log(this.picked)
|
||||
},
|
||||
removeEntity(entity) {
|
||||
console.log('remove entity', entity);
|
||||
this.$emit('removeEntity', entity);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
console.log(this.picked);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@@ -11,6 +11,10 @@ const appMessages = {
|
||||
user: 'Utilisateurs',
|
||||
person: 'Usagers',
|
||||
thirdparty: 'Tiers',
|
||||
modal_title_one: 'Indiquer un ',
|
||||
user_one: 'Utilisateur',
|
||||
thirdparty_one: 'Tiers',
|
||||
person_one: 'Usager',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -81,7 +81,7 @@ export default {
|
||||
/// [Option] showUrl is href for show page second button.
|
||||
// When passed, the component return a button-group with 2 buttons.
|
||||
isButtonGroup() {
|
||||
return !!this.showUrl
|
||||
return this.showUrl;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@@ -69,7 +69,7 @@ const messages = {
|
||||
person: "Usager"
|
||||
},
|
||||
holder: "Titulaire",
|
||||
years_old: "an | {n} an | {n} ans",
|
||||
years_old: "1 an | {n} an | {n} ans",
|
||||
residential_address: "Adresse de résidence",
|
||||
located_at: "réside chez"
|
||||
}
|
||||
|
@@ -1,54 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Symfony\Component\Config\Loader\LoaderInterface;
|
||||
use Symfony\Component\HttpKernel\Kernel;
|
||||
|
||||
class AppKernel extends Kernel
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCacheDir()
|
||||
{
|
||||
return sys_get_temp_dir() . '/ChillMainBundle/cache';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLogDir()
|
||||
{
|
||||
return sys_get_temp_dir() . '/ChillMainBundle/logs';
|
||||
}
|
||||
|
||||
public function registerBundles()
|
||||
{
|
||||
return [
|
||||
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
|
||||
new Chill\MainBundle\ChillMainBundle(),
|
||||
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
|
||||
new Symfony\Bundle\TwigBundle\TwigBundle(),
|
||||
new \Symfony\Bundle\AsseticBundle\AsseticBundle(),
|
||||
new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
|
||||
new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle(),
|
||||
new Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle(),
|
||||
new Symfony\Bundle\MonologBundle\MonologBundle(),
|
||||
new Knp\Bundle\MenuBundle\KnpMenuBundle(),
|
||||
new Symfony\Bundle\DebugBundle\DebugBundle(),
|
||||
];
|
||||
}
|
||||
|
||||
public function registerContainerConfiguration(LoaderInterface $loader)
|
||||
{
|
||||
$loader->load(__DIR__ . '/config/config_' . $this->getEnvironment() . '.yml');
|
||||
}
|
||||
}
|
@@ -1,2 +0,0 @@
|
||||
*
|
||||
!.gitignore
|
@@ -1,20 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use Composer\Autoload\ClassLoader;
|
||||
use Doctrine\Common\Annotations\AnnotationRegistry;
|
||||
|
||||
/** @var ClassLoader $loader */
|
||||
$loader = require __DIR__ . '/../../../../../vendor/autoload.php';
|
||||
|
||||
AnnotationRegistry::registerLoader([$loader, 'loadClass']);
|
||||
|
||||
return $loader;
|
@@ -1,42 +0,0 @@
|
||||
imports:
|
||||
- { resource: parameters.yml }
|
||||
|
||||
framework:
|
||||
secret: Not very secret
|
||||
router: { resource: "%kernel.root_dir%/config/routing.yml" }
|
||||
form: true
|
||||
csrf_protection: true
|
||||
session: ~
|
||||
default_locale: en
|
||||
translator: { fallback: en }
|
||||
profiler: { only_exceptions: false }
|
||||
templating:
|
||||
engines: ['twig']
|
||||
|
||||
# Doctrine Configuration
|
||||
doctrine:
|
||||
dbal:
|
||||
driver: pdo_pgsql
|
||||
host: "%database_host%"
|
||||
port: "%database_port%"
|
||||
dbname: "%database_name%"
|
||||
user: "%database_user%"
|
||||
password: "%database_password%"
|
||||
charset: UTF8
|
||||
|
||||
orm:
|
||||
auto_generate_proxy_classes: "%kernel.debug%"
|
||||
auto_mapping: true
|
||||
|
||||
# Assetic Configuration
|
||||
assetic:
|
||||
debug: "%kernel.debug%"
|
||||
use_controller: false
|
||||
bundles: [ ]
|
||||
#java: /usr/bin/java
|
||||
filters:
|
||||
cssrewrite: ~
|
||||
|
||||
chill_main:
|
||||
available_languages: [fr, en]
|
||||
available_countries: [FR]
|
@@ -1,51 +0,0 @@
|
||||
imports:
|
||||
- { resource: config.yml }
|
||||
|
||||
framework:
|
||||
test: ~
|
||||
session:
|
||||
storage_id: session.storage.filesystem
|
||||
|
||||
security:
|
||||
role_hierarchy:
|
||||
CHILL_MASTER_ROLE: [CHILL_INHERITED_ROLE_1]
|
||||
providers:
|
||||
chain_provider:
|
||||
chain :
|
||||
providers: [in_memory, users]
|
||||
in_memory:
|
||||
memory:
|
||||
users:
|
||||
admin: { password: "password", roles: 'ROLE_ADMIN' }
|
||||
users:
|
||||
entity:
|
||||
class: Chill\MainBundle\Entity\User
|
||||
property: username
|
||||
|
||||
encoders:
|
||||
Chill\MainBundle\Entity\User:
|
||||
algorithm: bcrypt
|
||||
Symfony\Component\Security\Core\User\User:
|
||||
algorithm: plaintext
|
||||
|
||||
firewalls:
|
||||
dev:
|
||||
pattern: ^/(_(profiler|wdt)|css|images|js)/
|
||||
security: false
|
||||
|
||||
|
||||
|
||||
default:
|
||||
anonymous: ~
|
||||
http_basic: ~
|
||||
form_login:
|
||||
csrf_parameter: _csrf_token
|
||||
csrf_token_id: authenticate
|
||||
|
||||
logout: ~
|
||||
|
||||
|
||||
access_control:
|
||||
- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
|
||||
- { path: ^/[a-z]*/admin, roles: ROLE_ADMIN }
|
||||
- { path: ^/, roles: ROLE_USER }
|
@@ -1,11 +0,0 @@
|
||||
parameters:
|
||||
database_host: chill__database
|
||||
database_port: 5432
|
||||
database_name: postgres
|
||||
database_user: postgres
|
||||
database_password: postgres
|
||||
locale: fr
|
||||
secret: ThisTokenIsNotSoSecretChangeIt
|
||||
debug_toolbar: true
|
||||
debug_redirects: false
|
||||
use_assetic_controller: true
|
@@ -1,11 +0,0 @@
|
||||
parameters:
|
||||
database_host: 127.0.0.1
|
||||
database_port: 5435
|
||||
database_name: chill
|
||||
database_user: chill
|
||||
database_password: chill
|
||||
locale: fr
|
||||
secret: ThisTokenIsNotSoSecretChangeIt
|
||||
debug_toolbar: true
|
||||
debug_redirects: false
|
||||
use_assetic_controller: true
|
@@ -1,34 +0,0 @@
|
||||
hello_bundle:
|
||||
resource: "@ChillMainBundle/config/routing.yml"
|
||||
|
||||
chill_main_dummy_0:
|
||||
path: /dummy
|
||||
defaults: { _controller: ChillMainBundle:Default:index }
|
||||
options:
|
||||
menus:
|
||||
dummy0:
|
||||
order: 50
|
||||
label: test0
|
||||
otherkey: othervalue
|
||||
dummy1:
|
||||
order: 50
|
||||
label: test dummy 1
|
||||
|
||||
chill_main_dummy_1:
|
||||
path: /dummy1
|
||||
defaults: { _controller: ChillMainBundle:Default:index }
|
||||
options:
|
||||
menus:
|
||||
dummy0:
|
||||
order: 50
|
||||
label: 'test1'
|
||||
helper: 'great helper'
|
||||
|
||||
chill_main_dummy_2:
|
||||
path: /dummy2/{param}
|
||||
defaults: {_controller: ChillMainBundle:Default:index }
|
||||
options:
|
||||
menus:
|
||||
dummy0:
|
||||
order: 50
|
||||
label: test2
|
@@ -1,27 +0,0 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Console\Application;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
use Symfony\Component\Debug\Debug;
|
||||
|
||||
// if you don't want to setup permissions the proper way, just uncomment the following PHP line
|
||||
// read https://symfony.com/doc/current/setup.html#checking-symfony-application-configuration-and-setup
|
||||
// for more information
|
||||
//umask(0000);
|
||||
|
||||
set_time_limit(0);
|
||||
|
||||
require __DIR__.'/autoload.php';
|
||||
|
||||
$input = new ArgvInput();
|
||||
$env = $input->getParameterOption(array('--env', '-e'), getenv('SYMFONY_ENV') ?: 'dev');
|
||||
$debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption(array('--no-debug', '')) && $env !== 'prod';
|
||||
|
||||
if ($debug) {
|
||||
Debug::enable();
|
||||
}
|
||||
|
||||
$kernel = new AppKernel($env, $debug);
|
||||
$application = new Application($kernel);
|
||||
$application->run($input);
|
@@ -217,6 +217,7 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block pick_entity_dynamic_widget %}
|
||||
{{ form_help(form)}}
|
||||
<input type="hidden" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %} data-input-uniqid="{{ form.vars['uniqid'] }}"/>
|
||||
<div data-module="pick-dynamic" data-types="{{ form.vars['types']|json_encode }}" data-multiple="{{ form.vars['multiple'] }}" data-uniqid="{{ form.vars['uniqid'] }}"></div>
|
||||
{% endblock %}
|
||||
|
@@ -47,6 +47,8 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{{ chill_pagination(paginator) }}
|
||||
|
||||
<ul class="record_actions">
|
||||
<li>
|
||||
<a href="{{ path('chill_crud_main_location_new') }}" class="btn btn-create">
|
||||
|
@@ -40,6 +40,11 @@
|
||||
{{ a|chill_entity_render_string }}
|
||||
</span>
|
||||
{% endfor %}
|
||||
{% for a in c.notification.addressesEmails %}
|
||||
<span class="badge-user" title="{{ 'notification.Email with access link'|trans|e('html_attr') }}">
|
||||
{{ a }}
|
||||
</span>
|
||||
{% endfor %}
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
@@ -61,17 +66,28 @@
|
||||
<div class="item-row">
|
||||
<div class="notification-content">
|
||||
{% if c.full_content is defined and c.full_content == true %}
|
||||
{{ c.notification.message|chill_markdown_to_html }}
|
||||
{% if c.notification.message is not empty %}
|
||||
{{ c.notification.message|chill_markdown_to_html }}
|
||||
{% else %}
|
||||
<p class="chill-no-data-statement">{{ 'Any comment'|trans }}</p>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{{ c.notification.message|u.truncate(250, '…', false)|chill_markdown_to_html }}
|
||||
<p class="read-more"><a href="{{ chill_path_add_return_path('chill_main_notification_show', {'id': c.notification.id}) }}">{{ 'Read more'|trans }}</a></p>
|
||||
{% if c.notification.message is not empty %}
|
||||
{{ c.notification.message|u.truncate(250, '…', false)|chill_markdown_to_html }}
|
||||
<p class="read-more"><a href="{{ chill_path_add_return_path('chill_main_notification_show', {'id': c.notification.id}) }}">{{ 'Read more'|trans }}</a></p>
|
||||
{% else %}
|
||||
<p class="chill-no-data-statement">{{ 'Any comment'|trans }}</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro actions(c) %}
|
||||
{% if c.action_button is not defined or c.action_button != false %}
|
||||
<div class="item-row separator">
|
||||
<div class="item-col item-meta">
|
||||
|
||||
|
||||
{% if c.notification.comments|length > 0 %}
|
||||
<div class="comment-counter">
|
||||
<span class="counter">
|
||||
@@ -79,16 +95,16 @@
|
||||
</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
</div>
|
||||
<div class="item-col">
|
||||
<ul class="record_actions">
|
||||
<li>
|
||||
{# Vue component #}
|
||||
<span class="notification_toggle_read_status"
|
||||
data-notification-id="{{ c.notification.id }}"
|
||||
data-notification-current-is-read="{{ c.notification.isReadBy(app.user) }}"
|
||||
data-container="notification-status"
|
||||
data-notification-id="{{ c.notification.id }}"
|
||||
data-notification-current-is-read="{{ c.notification.isReadBy(app.user) }}"
|
||||
data-container="notification-status"
|
||||
></span>
|
||||
</li>
|
||||
{% if is_granted('CHILL_MAIN_NOTIFICATION_UPDATE', c.notification) %}
|
||||
@@ -122,24 +138,25 @@
|
||||
<button type="button" class="accordion-button collapsed"
|
||||
data-bs-toggle="collapse" data-bs-target="#flush-collapse-{{ notification.id }}"
|
||||
aria-expanded="false" aria-controls="flush-collapse-{{ notification.id }}">
|
||||
|
||||
|
||||
{{ _self.title(_context) }}
|
||||
</button>
|
||||
{{ _self.header(_context) }}
|
||||
|
||||
|
||||
</div>
|
||||
<div id="flush-collapse-{{ notification.id }}"
|
||||
class="accordion-collapse collapse"
|
||||
aria-labelledby="flush-heading-{{ notification.id }}"
|
||||
data-bs-parent="#notification-fold">
|
||||
|
||||
|
||||
{{ _self.content(_context) }}
|
||||
|
||||
</div>
|
||||
{{ _self.actions(_context) }}
|
||||
{% else %}
|
||||
{{ _self.title(_context) }}
|
||||
{{ _self.header(_context) }}
|
||||
{{ _self.content(_context) }}
|
||||
{{ _self.actions(_context) }}
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
|
@@ -20,7 +20,9 @@
|
||||
|
||||
{{ form_row(form.title, { 'label': 'notification.subject'|trans }) }}
|
||||
{{ form_row(form.addressees, { 'label': 'notification.sent_to'|trans }) }}
|
||||
|
||||
|
||||
{{ form_row(form.addressesEmails) }}
|
||||
|
||||
{% include handler.template(notification) with handler.templateData(notification) %}
|
||||
|
||||
<div class="mb-3 row">
|
||||
|
@@ -21,6 +21,8 @@
|
||||
{{ form_row(form.title, { 'label': 'notification.subject'|trans }) }}
|
||||
{{ form_row(form.addressees, { 'label': 'notification.sent_to'|trans }) }}
|
||||
|
||||
{{ form_row(form.addressesEmails) }}
|
||||
|
||||
{% include handler.template(notification) with handler.templateData(notification) %}
|
||||
|
||||
<div class="mb-3 row">
|
||||
|
@@ -0,0 +1,20 @@
|
||||
{{ dest }},
|
||||
|
||||
{{ notification.sender.label }} a créé une notification pour vous:
|
||||
|
||||
> {{ notification.title }}
|
||||
>
|
||||
>
|
||||
{%- for line in notification.message|split("\n") %}
|
||||
> {{ line }}
|
||||
{%- if not loop.last %}
|
||||
>
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
|
||||
Vous pouvez cliquer sur ce lien pour obtenir un accès permanent à la notification:
|
||||
|
||||
{{ absolute_url(path('chill_main_notification_grant_access_by_access_key', {'_locale': 'fr', 'id': notification.id, 'accessKey': notification.accessKey, 'email': dest})) }}
|
||||
|
||||
--
|
||||
Le logiciel Chill
|
@@ -59,4 +59,10 @@
|
||||
|
||||
{{ chill_pagination(paginator) }}
|
||||
|
||||
{% endblock %}
|
||||
<ul class="record_actions sticky-form-buttons">
|
||||
<li>
|
||||
<a href="{{ path('chill_crud_admin_user_new') }}" class="btn btn-create">{{ 'Create'|trans }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
{% endblock %}
|
||||
|
@@ -2,7 +2,7 @@
|
||||
{{ 'workflow_'|trans }}
|
||||
</h2>
|
||||
|
||||
<div class="item-row col">
|
||||
<div class="item-row col" style="display: block;">
|
||||
{% include handler.template(entity_workflow) with handler.templateData(entity_workflow)|merge({
|
||||
'description': true,
|
||||
'breadcrumb': true,
|
||||
|
@@ -3,6 +3,7 @@
|
||||
{% block title 'workflow.Delete workflow ?'|trans %}
|
||||
|
||||
{% block display_content %}
|
||||
<div class="col-10 workflow">
|
||||
<h2>
|
||||
{{ handler.entityTitle(entityWorkflow) }}
|
||||
</h2>
|
||||
@@ -10,6 +11,7 @@
|
||||
{% include handler.template(entityWorkflow) with handler.templateData(entityWorkflow)|merge({
|
||||
'display_action': false
|
||||
}) %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
@@ -25,5 +27,5 @@
|
||||
'form' : delete_form
|
||||
} ) }}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@@ -36,33 +36,35 @@
|
||||
|
||||
{# Flash messages ! #}
|
||||
{% if app.session.flashbag.keys()|length > 0 %}
|
||||
<div class="col-8 mb-5 flash_message">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-10 mb-5 flash_message">
|
||||
|
||||
{% for flashMessage in app.session.flashbag.get('success') %}
|
||||
<div class="alert alert-success flash_message">
|
||||
<span>{{ flashMessage|raw }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% for flashMessage in app.session.flashbag.get('error') %}
|
||||
<div class="alert alert-danger flash_message">
|
||||
<span>{{ flashMessage|raw }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% for flashMessage in app.session.flashbag.get('notice') %}
|
||||
<div class="alert alert-warning flash_message">
|
||||
<span>{{ flashMessage|raw }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% for flashMessage in app.session.flashbag.get('success') %}
|
||||
<div class="alert alert-success flash_message">
|
||||
<span>{{ flashMessage|raw }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% for flashMessage in app.session.flashbag.get('error') %}
|
||||
<div class="alert alert-danger flash_message">
|
||||
<span>{{ flashMessage|raw }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% for flashMessage in app.session.flashbag.get('notice') %}
|
||||
<div class="alert alert-warning flash_message">
|
||||
<span>{{ flashMessage|raw }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% block content %}
|
||||
<div class="col-8 main_search">
|
||||
<h2>{{ 'Search'|trans }}</h2>
|
||||
|
||||
|
||||
<form action="{{ path('chill_main_search') }}" method="get">
|
||||
<input class="form-control form-control-lg" name="q" type="search" placeholder="{{ 'Search persons, ...'|trans }}" />
|
||||
<center>
|
||||
@@ -75,11 +77,11 @@
|
||||
</center>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
{# DISABLED {{ chill_widget('homepage', {} ) }} #}
|
||||
|
||||
|
||||
{% include '@ChillMain/Homepage/index.html.twig' %}
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
</div>
|
||||
|
@@ -45,15 +45,16 @@ class SearchUserApiProvider implements SearchApiInterface
|
||||
$query
|
||||
->setSelectKey('user')
|
||||
->setSelectJsonbMetadata("jsonb_build_object('id', u.id)")
|
||||
->setSelectPertinence('GREATEST(SIMILARITY(LOWER(UNACCENT(?)), u.label),
|
||||
->setSelectPertinence('3 + GREATEST(SIMILARITY(LOWER(UNACCENT(?)), u.label),
|
||||
SIMILARITY(LOWER(UNACCENT(?)), u.usernamecanonical))', [$pattern, $pattern])
|
||||
->setFromClause('users AS u')
|
||||
->setWhereClauses('
|
||||
u.enabled IS TRUE and (
|
||||
SIMILARITY(LOWER(UNACCENT(?)), u.usernamecanonical) > 0.15
|
||||
OR u.usernamecanonical LIKE \'%\' || LOWER(UNACCENT(?)) || \'%\'
|
||||
OR SIMILARITY(LOWER(UNACCENT(?)), LOWER(UNACCENT(u.label))) > 0.15
|
||||
OR u.label LIKE \'%\' || LOWER(UNACCENT(?)) || \'%\'
|
||||
', [$pattern, $pattern, $pattern, $pattern]);
|
||||
)', [$pattern, $pattern, $pattern, $pattern]);
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
@@ -59,7 +59,23 @@ class EntityWorkflowVoter extends Voter
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->security->isGranted($entityAttribute, $handler->getRelatedEntity($subject));
|
||||
$relatedEntity = $handler->getRelatedEntity($subject);
|
||||
|
||||
if (null === $relatedEntity) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->security->isGranted($entityAttribute, $relatedEntity)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach ($subject->getSteps() as $step) {
|
||||
if ($step->getAllDestUser()->contains($token->getUser())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
case self::DELETE:
|
||||
return $subject->getStep() === 'initial';
|
||||
|
@@ -71,6 +71,7 @@ class AddressNormalizer implements ContextAwareNormalizerInterface, NormalizerAw
|
||||
'id' => $address->getPostCode()->getId(),
|
||||
'name' => $address->getPostCode()->getName(),
|
||||
'code' => $address->getPostCode()->getCode(),
|
||||
'center' => $address->getPostcode()->getCenter(),
|
||||
],
|
||||
'country' => [
|
||||
'id' => $address->getPostCode()->getCountry()->getId(),
|
||||
|
@@ -44,14 +44,25 @@ class DateNormalizer implements ContextAwareNormalizerInterface, DenormalizerInt
|
||||
|
||||
switch ($type) {
|
||||
case DateTime::class:
|
||||
return DateTime::createFromFormat(DateTimeInterface::ISO8601, $data['datetime']);
|
||||
$result = DateTime::createFromFormat(DateTimeInterface::ISO8601, $data['datetime']);
|
||||
|
||||
break;
|
||||
|
||||
case DateTimeInterface::class:
|
||||
case DateTimeImmutable::class:
|
||||
return DateTimeImmutable::createFromFormat(DateTimeInterface::ISO8601, $data['datetime']);
|
||||
$result = DateTimeImmutable::createFromFormat(DateTimeInterface::ISO8601, $data['datetime']);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new UnexpectedValueException();
|
||||
}
|
||||
|
||||
throw new UnexpectedValueException();
|
||||
if (false === $result) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function normalize($date, $format = null, array $context = [])
|
||||
|
@@ -32,7 +32,7 @@ class PhonenumberNormalizer implements ContextAwareNormalizerInterface, Denormal
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $data
|
||||
* @param string|null $data
|
||||
* @param mixed $type
|
||||
* @param null|mixed $format
|
||||
*
|
||||
@@ -40,7 +40,7 @@ class PhonenumberNormalizer implements ContextAwareNormalizerInterface, Denormal
|
||||
*/
|
||||
public function denormalize($data, $type, $format = null, array $context = [])
|
||||
{
|
||||
if ('' === trim($data)) {
|
||||
if ('' === trim((string) $data)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@@ -83,9 +83,9 @@ abstract class AbstractExportTest extends WebTestCase
|
||||
$em = static::$kernel->getContainer()
|
||||
->get('doctrine.orm.entity_manager');
|
||||
|
||||
$centers = $em->getRepository('ChillMainBundle:Center')
|
||||
$centers = $em->getRepository(\Chill\MainBundle\Entity\Center::class)
|
||||
->findAll();
|
||||
$circles = $em->getRepository('ChillMainBundle:Scope')
|
||||
$circles = $em->getRepository(\Chill\MainBundle\Entity\Scope::class)
|
||||
->findAll();
|
||||
|
||||
if (count($centers) === 0) {
|
||||
|
@@ -161,7 +161,7 @@ final class UserControllerTest extends WebTestCase
|
||||
|
||||
$user = self::$kernel->getContainer()
|
||||
->get('doctrine.orm.entity_manager')
|
||||
->getRepository('ChillMainBundle:User')
|
||||
->getRepository(\Chill\MainBundle\Entity\User::class)
|
||||
->findOneBy(['username' => $username]);
|
||||
|
||||
$this->assertTrue($passwordEncoder->isPasswordValid($user, $password));
|
||||
|
@@ -88,6 +88,24 @@ final class NotificationTest extends KernelTestCase
|
||||
$this->assertNotContains($user1, $notification->getUnreadBy()->toArray());
|
||||
}
|
||||
|
||||
public function testAddressesEmail(): void
|
||||
{
|
||||
$notification = new Notification();
|
||||
|
||||
$notification->addAddressesEmail('test');
|
||||
$notification->addAddressesEmail('other');
|
||||
|
||||
$this->assertContains('test', $notification->getAddressesEmails());
|
||||
$this->assertContains('other', $notification->getAddressesEmails());
|
||||
$this->assertContains('test', $notification->getAddressesEmailsAdded());
|
||||
$this->assertContains('other', $notification->getAddressesEmailsAdded());
|
||||
|
||||
$notification->removeAddressesEmail('other');
|
||||
|
||||
$this->assertNotContains('other', $notification->getAddressesEmails());
|
||||
$this->assertNotContains('other', $notification->getAddressesEmailsAdded());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider generateNotificationData
|
||||
*/
|
||||
|
@@ -672,7 +672,7 @@ final class ExportManagerTest extends KernelTestCase
|
||||
$localUser = $user ?? self::$container->get(
|
||||
'doctrine.orm.entity_manager'
|
||||
)
|
||||
->getRepository('ChillMainBundle:User')
|
||||
->getRepository(\Chill\MainBundle\Entity\User::class)
|
||||
->findOneBy(['username' => 'center a_social']);
|
||||
$token = new UsernamePasswordToken($localUser, 'password', 'provider');
|
||||
$tokenStorage = new TokenStorage();
|
||||
|
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Notification\EventListener;
|
||||
|
||||
use Chill\MainBundle\Entity\Notification;
|
||||
use Chill\MainBundle\Notification\EventListener\PersistNotificationOnTerminateEventSubscriber;
|
||||
use Chill\MainBundle\Notification\NotificationPersister;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Prophecy\Argument;
|
||||
use Prophecy\PhpUnit\ProphecyTrait;
|
||||
use Symfony\Component\HttpKernel\Event\TerminateEvent;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @coversNothing
|
||||
*/
|
||||
final class PersistNotificationOnTerminateEventSubscriberTest extends TestCase
|
||||
{
|
||||
use ProphecyTrait;
|
||||
|
||||
public function testNotificationIsPersisted()
|
||||
{
|
||||
$persister = new NotificationPersister();
|
||||
$em = $this->prophesize(EntityManagerInterface::class);
|
||||
$em->persist(Argument::type(Notification::class))->shouldBeCalledTimes(1);
|
||||
$em->flush()->shouldBeCalledTimes(1);
|
||||
$event = $this->prophesize(TerminateEvent::class);
|
||||
$event->isMasterRequest()->willReturn(true);
|
||||
|
||||
$eventSubscriber = new PersistNotificationOnTerminateEventSubscriber($em->reveal(), $persister);
|
||||
|
||||
$notification = new Notification();
|
||||
$persister->persist($notification);
|
||||
|
||||
$eventSubscriber->onKernelTerminate($event->reveal());
|
||||
}
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Serializer\Normalizer;
|
||||
|
||||
use Chill\MainBundle\Serializer\Normalizer\PhonenumberNormalizer;
|
||||
use libphonenumber\PhoneNumber;
|
||||
use libphonenumber\PhoneNumberUtil;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Prophecy\Argument;
|
||||
use Prophecy\PhpUnit\ProphecyTrait;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @coversNothing
|
||||
*/
|
||||
final class PhonenumberNormalizerTest extends TestCase
|
||||
{
|
||||
use ProphecyTrait;
|
||||
|
||||
public function dataProviderNormalizePhonenumber()
|
||||
{
|
||||
$phonenumberUtil = PhoneNumberUtil::getInstance();
|
||||
|
||||
yield [$phonenumberUtil->parse('+32486123465'), 'docgen', ['docgen:expects' => PhoneNumber::class], '0486 12 34 65'];
|
||||
|
||||
yield [null, 'docgen', ['docgen:expects' => PhoneNumber::class], ''];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataProviderNormalizePhonenumber
|
||||
*
|
||||
* @param mixed $format
|
||||
* @param mixed $context
|
||||
* @param mixed $expected
|
||||
*/
|
||||
public function testNormalize(?Phonenumber $phonenumber, $format, $context, $expected)
|
||||
{
|
||||
$parameterBag = $this->prophesize(ParameterBagInterface::class);
|
||||
$parameterBag->get(Argument::exact('chill_main'))->willReturn(['phone_helper' => ['default_carrier_code' => 'BE']]);
|
||||
$normalizer = new PhonenumberNormalizer($parameterBag->reveal());
|
||||
|
||||
$this->assertEquals($expected, $normalizer->normalize($phonenumber, $format, $context));
|
||||
}
|
||||
}
|
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
if (!is_file($autoloadFile = __DIR__ . '/../vendor/autoload.php')) {
|
||||
throw new \LogicException('Could not find autoload.php in vendor/. Did you run "composer install --dev"?');
|
||||
}
|
||||
|
||||
require $autoloadFile;
|
@@ -62,7 +62,7 @@ class WorkflowTwigExtensionRuntime implements RuntimeExtensionInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{relatedEntityClass: string, relatedEntityId: int} $supplementaryRelated
|
||||
* @param array<array{relatedEntityClass: string, relatedEntityId: int}> $supplementaryRelated
|
||||
*
|
||||
* @throws \Symfony\Component\Serializer\Exception\ExceptionInterface
|
||||
* @throws \Twig\Error\LoaderError
|
||||
|
@@ -3,6 +3,11 @@ services:
|
||||
autowire: true
|
||||
autoconfigure: true
|
||||
|
||||
Chill\MainBundle\Notification\:
|
||||
resource: ../../Notification/
|
||||
autoconfigure: true
|
||||
autowire: true
|
||||
|
||||
Chill\MainBundle\Notification\Mailer:
|
||||
arguments:
|
||||
$logger: '@Psr\Log\LoggerInterface'
|
||||
@@ -17,12 +22,6 @@ services:
|
||||
arguments:
|
||||
$handlers: !tagged_iterator chill_main.notification_handler
|
||||
|
||||
Chill\MainBundle\Notification\NotificationPresence: ~
|
||||
|
||||
Chill\MainBundle\Notification\Templating\NotificationTwigExtension: ~
|
||||
|
||||
Chill\MainBundle\Notification\Templating\NotificationTwigExtensionRuntime: ~
|
||||
|
||||
Chill\MainBundle\Notification\Counter\NotificationByUserCounter:
|
||||
autoconfigure: true
|
||||
autowire: true
|
||||
@@ -61,6 +60,15 @@ services:
|
||||
# set the 'lazy' option to TRUE to only instantiate listeners when they are used
|
||||
lazy: true
|
||||
method: 'postPersistNotification'
|
||||
|
||||
-
|
||||
name: 'doctrine.orm.entity_listener'
|
||||
event: 'postUpdate'
|
||||
entity: 'Chill\MainBundle\Entity\Notification'
|
||||
# set the 'lazy' option to TRUE to only instantiate listeners when they are used
|
||||
lazy: true
|
||||
method: 'postUpdateNotification'
|
||||
|
||||
-
|
||||
name: 'doctrine.orm.entity_listener'
|
||||
event: 'postPersist'
|
||||
|
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\Migrations\Main;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20220413154743 extends AbstractMigration
|
||||
{
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_main_notification DROP adressesEmails');
|
||||
$this->addSql('ALTER TABLE chill_main_notification DROP accessKey');
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'add access keys and emails dest to notifications';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_main_notification ADD addressesEmails JSON NOT NULL DEFAULT \'[]\';');
|
||||
$this->addSql('ALTER TABLE chill_main_notification ADD accessKey TEXT DEFAULT NULL');
|
||||
$this->addSql('WITH randoms AS (select
|
||||
n.id,
|
||||
string_agg(substr(characters, (random() * length(characters) + 0.5)::integer, 1), \'\') as random_word
|
||||
from (values(\'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\')) as symbols(characters)
|
||||
-- length of word
|
||||
join generate_series(1, 16) on 1 = 1
|
||||
JOIN chill_main_notification n ON true
|
||||
GROUP BY n.id)
|
||||
UPDATE chill_main_notification SET accessKey = randoms.random_word FROM randoms WHERE chill_main_notification.id = randoms.id');
|
||||
$this->addSql('ALTER TABLE chill_main_notification ALTER accessKey DROP DEFAULT');
|
||||
$this->addSql('ALTER TABLE chill_main_notification ALTER accessKey SET NOT NULL');
|
||||
}
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\Migrations\Main;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20220413225830 extends AbstractMigration
|
||||
{
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER COLUMN postcode_id DROP NOT NULL');
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Set postal code in chill_main_address NOT NULL';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_main_address ALTER COLUMN postcode_id SET NOT NULL');
|
||||
}
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Chill is a software for social workers
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Chill\Migrations\Main;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20220413230159 extends AbstractMigration
|
||||
{
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_main_address DROP CONSTRAINT chill_custom_validfrom_before_validto');
|
||||
}
|
||||
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'in addresses, validfrom must be lower than validto';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE chill_main_address ADD CONSTRAINT chill_custom_validfrom_before_validto CHECK (validfrom <= COALESCE(validto, \'infinity\'::date))');
|
||||
}
|
||||
}
|
@@ -450,4 +450,10 @@ notification:
|
||||
subject: Objet
|
||||
see_comments_thread: Voir le fil de commentaires associé
|
||||
object_prefix: "[CHILL] notification - "
|
||||
dest by email: Lien d'accès par email
|
||||
Any email: Aucun email
|
||||
Add an email: Ajouter un email
|
||||
dest by email help: Les adresses email mentionnées ici recevront un lien d'accès. Un compte utilisateur sera toujours nécessaire.
|
||||
Remove an email: Supprimer l'adresse email
|
||||
Email with access link: Adresse email ayant reçu un lien d'accès
|
||||
|
||||
|
Reference in New Issue
Block a user