mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-10-02 11:29:41 +00:00
Compare commits
47 Commits
385-invita
...
285-cancel
Author | SHA1 | Date | |
---|---|---|---|
111f72d996 | |||
67c29728f3 | |||
0f62ddc3d6 | |||
db3833190e | |||
fbb4e8c784 | |||
a41414a460 | |||
a3c1aa4679 | |||
99b801fb8a | |||
4087911262 | |||
d6a50888e0 | |||
705f3b6f76 | |||
6f8b25f457 | |||
ffef8b70a3 | |||
43a3d5c902 | |||
197b17fa76 | |||
229d62e676 | |||
b51a7cfc57 | |||
5d40948a63 | |||
9c1df94796 | |||
24eb220e90 | |||
9a262a3f43 | |||
b421e0b0af | |||
20b82ddbfc | |||
a568d3c5a2 | |||
260a42c35a | |||
5b4f47bfaa | |||
60706ae75b | |||
b561b12213 | |||
f4369f0e3c | |||
afa755f5a5 | |||
cb2308f808 | |||
432650e081 | |||
4215a90b0e | |||
24daae6ee5 | |||
5ae26a46eb | |||
aec32b9bf8 | |||
5b59bef990 | |||
e70de780a7 | |||
a546ec1e6e | |||
a5417855f2 | |||
2234093971 | |||
be499bee07 | |||
55faeaec39 | |||
ac24df3f3c | |||
64dc458844 | |||
5f57b5eae3 | |||
95de2c863d |
@@ -1,6 +0,0 @@
|
|||||||
kind: Feature
|
|
||||||
body: Create invitation list in user menu
|
|
||||||
time: 2025-08-08T12:08:02.446361367+02:00
|
|
||||||
custom:
|
|
||||||
Issue: "385"
|
|
||||||
SchemaChange: No schema change
|
|
@@ -13,6 +13,7 @@ namespace Chill\CalendarBundle\Controller;
|
|||||||
|
|
||||||
use Chill\CalendarBundle\Entity\Calendar;
|
use Chill\CalendarBundle\Entity\Calendar;
|
||||||
use Chill\CalendarBundle\Form\CalendarType;
|
use Chill\CalendarBundle\Form\CalendarType;
|
||||||
|
use Chill\CalendarBundle\Form\CancelType;
|
||||||
use Chill\CalendarBundle\RemoteCalendar\Connector\RemoteCalendarConnectorInterface;
|
use Chill\CalendarBundle\RemoteCalendar\Connector\RemoteCalendarConnectorInterface;
|
||||||
use Chill\CalendarBundle\Repository\CalendarACLAwareRepositoryInterface;
|
use Chill\CalendarBundle\Repository\CalendarACLAwareRepositoryInterface;
|
||||||
use Chill\CalendarBundle\Security\Voter\CalendarVoter;
|
use Chill\CalendarBundle\Security\Voter\CalendarVoter;
|
||||||
@@ -30,6 +31,7 @@ use Chill\PersonBundle\Repository\PersonRepository;
|
|||||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
||||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||||
use Chill\ThirdPartyBundle\Entity\ThirdParty;
|
use Chill\ThirdPartyBundle\Entity\ThirdParty;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use http\Exception\UnexpectedValueException;
|
use http\Exception\UnexpectedValueException;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
@@ -60,6 +62,7 @@ class CalendarController extends AbstractController
|
|||||||
private readonly UserRepositoryInterface $userRepository,
|
private readonly UserRepositoryInterface $userRepository,
|
||||||
private readonly TranslatorInterface $translator,
|
private readonly TranslatorInterface $translator,
|
||||||
private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry,
|
private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry,
|
||||||
|
private readonly EntityManagerInterface $em,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -111,6 +114,55 @@ class CalendarController extends AbstractController
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Route(path: '/{_locale}/calendar/calendar/{id}/cancel', name: 'chill_calendar_calendar_cancel')]
|
||||||
|
public function cancelAction(Calendar $calendar, Request $request): Response
|
||||||
|
{
|
||||||
|
// Deal with sms being sent or not
|
||||||
|
// Communicate cancellation with the remote calendar.
|
||||||
|
|
||||||
|
$this->denyAccessUnlessGranted(CalendarVoter::EDIT, $calendar);
|
||||||
|
|
||||||
|
[$person, $accompanyingPeriod] = [$calendar->getPerson(), $calendar->getAccompanyingPeriod()];
|
||||||
|
|
||||||
|
$form = $this->createForm(CancelType::class, $calendar);
|
||||||
|
$form->add('submit', SubmitType::class);
|
||||||
|
|
||||||
|
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
|
||||||
|
$view = '@ChillCalendar/Calendar/cancelCalendarByAccompanyingCourse.html.twig';
|
||||||
|
$redirectRoute = $this->generateUrl('chill_calendar_calendar_list_by_period', ['id' => $accompanyingPeriod->getId()]);
|
||||||
|
} elseif ($person instanceof Person) {
|
||||||
|
$view = '@ChillCalendar/Calendar/cancelCalendarByPerson.html.twig';
|
||||||
|
$redirectRoute = $this->generateUrl('chill_calendar_calendar_list_by_person', ['id' => $person->getId()]);
|
||||||
|
} else {
|
||||||
|
throw new \RuntimeException('nor person or accompanying period');
|
||||||
|
}
|
||||||
|
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
|
||||||
|
$this->logger->notice('A calendar event has been cancelled', [
|
||||||
|
'by_user' => $this->getUser()->getUsername(),
|
||||||
|
'calendar_id' => $calendar->getId(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$calendar->setStatus($calendar::STATUS_CANCELED);
|
||||||
|
$calendar->setSmsStatus($calendar::SMS_CANCEL_PENDING);
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
$this->addFlash('success', $this->translator->trans('chill_calendar.calendar_canceled'));
|
||||||
|
|
||||||
|
return new RedirectResponse($redirectRoute);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render($view, [
|
||||||
|
'calendar' => $calendar,
|
||||||
|
'form' => $form->createView(),
|
||||||
|
'accompanyingCourse' => $accompanyingPeriod,
|
||||||
|
'person' => $person,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edit a calendar item.
|
* Edit a calendar item.
|
||||||
*/
|
*/
|
||||||
@@ -266,7 +318,7 @@ class CalendarController extends AbstractController
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->getUser() instanceof User) {
|
if (!$this->getUser() instanceof User) {
|
||||||
throw new UnauthorizedHttpException('you are not a user');
|
throw new UnauthorizedHttpException('you are not an user');
|
||||||
}
|
}
|
||||||
|
|
||||||
$view = '@ChillCalendar/Calendar/listByUser.html.twig';
|
$view = '@ChillCalendar/Calendar/listByUser.html.twig';
|
||||||
|
@@ -1,58 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Chill\CalendarBundle\Controller;
|
|
||||||
|
|
||||||
use Chill\CalendarBundle\Entity\Calendar;
|
|
||||||
use Chill\CalendarBundle\Repository\InviteRepository;
|
|
||||||
use Chill\DocGeneratorBundle\Repository\DocGeneratorTemplateRepositoryInterface;
|
|
||||||
use Chill\MainBundle\Entity\User;
|
|
||||||
use Chill\MainBundle\Pagination\PaginatorFactory;
|
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
|
||||||
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
|
|
||||||
use Symfony\Component\Routing\Annotation\Route;
|
|
||||||
|
|
||||||
class MyInvitationsController extends AbstractController
|
|
||||||
{
|
|
||||||
public function __construct(private readonly InviteRepository $inviteRepository, private readonly PaginatorFactory $paginator, private readonly DocGeneratorTemplateRepositoryInterface $docGeneratorTemplateRepository) {}
|
|
||||||
|
|
||||||
#[Route(path: '/{_locale}/calendar/invitations/my', name: 'chill_calendar_invitations_list_my')]
|
|
||||||
public function myInvitations(Request $request): Response
|
|
||||||
{
|
|
||||||
$this->denyAccessUnlessGranted('ROLE_USER');
|
|
||||||
|
|
||||||
$user = $this->getUser();
|
|
||||||
|
|
||||||
if (!$user instanceof User) {
|
|
||||||
throw new UnauthorizedHttpException('you are not a user');
|
|
||||||
}
|
|
||||||
|
|
||||||
$total = count($this->inviteRepository->findBy(['user' => $user]));
|
|
||||||
$paginator = $this->paginator->create($total);
|
|
||||||
|
|
||||||
$invitations = $this->inviteRepository->findBy(
|
|
||||||
['user' => $user],
|
|
||||||
['createdAt' => 'DESC'],
|
|
||||||
$paginator->getItemsPerPage(),
|
|
||||||
$paginator->getCurrentPageFirstItemNumber()
|
|
||||||
);
|
|
||||||
|
|
||||||
$view = '@ChillCalendar/Invitations/listByUser.html.twig';
|
|
||||||
|
|
||||||
return $this->render($view, [
|
|
||||||
'invitations' => $invitations,
|
|
||||||
'paginator' => $paginator,
|
|
||||||
'templates' => $this->docGeneratorTemplateRepository->findByEntity(Calendar::class),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -35,7 +35,7 @@ class LoadCancelReason extends Fixture implements FixtureGroupInterface
|
|||||||
$arr = [
|
$arr = [
|
||||||
['name' => CancelReason::CANCELEDBY_USER],
|
['name' => CancelReason::CANCELEDBY_USER],
|
||||||
['name' => CancelReason::CANCELEDBY_PERSON],
|
['name' => CancelReason::CANCELEDBY_PERSON],
|
||||||
['name' => CancelReason::CANCELEDBY_DONOTCOUNT],
|
['name' => CancelReason::CANCELEDBY_OTHER],
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($arr as $a) {
|
foreach ($arr as $a) {
|
||||||
|
@@ -18,14 +18,14 @@ use Doctrine\ORM\Mapping as ORM;
|
|||||||
#[ORM\Table(name: 'chill_calendar.cancel_reason')]
|
#[ORM\Table(name: 'chill_calendar.cancel_reason')]
|
||||||
class CancelReason
|
class CancelReason
|
||||||
{
|
{
|
||||||
final public const CANCELEDBY_DONOTCOUNT = 'CANCELEDBY_DONOTCOUNT';
|
final public const CANCELEDBY_OTHER = 'CANCELEDBY_OTHER';
|
||||||
|
|
||||||
final public const CANCELEDBY_PERSON = 'CANCELEDBY_PERSON';
|
final public const CANCELEDBY_PERSON = 'CANCELEDBY_PERSON';
|
||||||
|
|
||||||
final public const CANCELEDBY_USER = 'CANCELEDBY_USER';
|
final public const CANCELEDBY_USER = 'CANCELEDBY_USER';
|
||||||
|
|
||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::BOOLEAN)]
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::BOOLEAN, options: ['default' => true])]
|
||||||
private ?bool $active = null;
|
private bool $active = true;
|
||||||
|
|
||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 255)]
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 255)]
|
||||||
private ?string $canceledBy = null;
|
private ?string $canceledBy = null;
|
||||||
|
@@ -15,7 +15,7 @@ use Chill\CalendarBundle\Entity\CancelReason;
|
|||||||
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
|
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
@@ -28,7 +28,14 @@ class CancelReasonType extends AbstractType
|
|||||||
->add('active', CheckboxType::class, [
|
->add('active', CheckboxType::class, [
|
||||||
'required' => false,
|
'required' => false,
|
||||||
])
|
])
|
||||||
->add('canceledBy', TextType::class);
|
->add('canceledBy', ChoiceType::class, [
|
||||||
|
'choices' => [
|
||||||
|
'chill_calendar.canceled_by.user' => CancelReason::CANCELEDBY_USER,
|
||||||
|
'chill_calendar.canceled_by.person' => CancelReason::CANCELEDBY_PERSON,
|
||||||
|
'chill_calendar.canceled_by.other' => CancelReason::CANCELEDBY_OTHER,
|
||||||
|
],
|
||||||
|
'required' => true,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function configureOptions(OptionsResolver $resolver)
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
42
src/Bundle/ChillCalendarBundle/Form/CancelType.php
Normal file
42
src/Bundle/ChillCalendarBundle/Form/CancelType.php
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CalendarBundle\Form;
|
||||||
|
|
||||||
|
use Chill\CalendarBundle\Entity\Calendar;
|
||||||
|
use Chill\CalendarBundle\Entity\CancelReason;
|
||||||
|
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||||
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
class CancelType extends AbstractType
|
||||||
|
{
|
||||||
|
public function __construct(private readonly TranslatableStringHelperInterface $translatableStringHelper) {}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
$builder->add('cancelReason', EntityType::class, [
|
||||||
|
'class' => CancelReason::class,
|
||||||
|
'required' => true,
|
||||||
|
'choice_label' => fn (CancelReason $cancelReason) => $this->translatableStringHelper->localize($cancelReason->getName()),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver->setDefaults([
|
||||||
|
'data_class' => Calendar::class,
|
||||||
|
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@@ -30,13 +30,6 @@ class UserMenuBuilder implements LocalMenuBuilderInterface
|
|||||||
'order' => 9,
|
'order' => 9,
|
||||||
'icon' => 'tasks',
|
'icon' => 'tasks',
|
||||||
]);
|
]);
|
||||||
$menu->addChild('My invitations list', [
|
|
||||||
'route' => 'chill_calendar_invitations_list_my',
|
|
||||||
])
|
|
||||||
->setExtras([
|
|
||||||
'order' => 9,
|
|
||||||
'icon' => 'tasks',
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -21,6 +21,7 @@ namespace Chill\CalendarBundle\Messenger\Doctrine;
|
|||||||
use Chill\CalendarBundle\Entity\Calendar;
|
use Chill\CalendarBundle\Entity\Calendar;
|
||||||
use Chill\CalendarBundle\Messenger\Message\CalendarMessage;
|
use Chill\CalendarBundle\Messenger\Message\CalendarMessage;
|
||||||
use Chill\CalendarBundle\Messenger\Message\CalendarRemovedMessage;
|
use Chill\CalendarBundle\Messenger\Message\CalendarRemovedMessage;
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
use Doctrine\ORM\Event\PostPersistEventArgs;
|
use Doctrine\ORM\Event\PostPersistEventArgs;
|
||||||
use Doctrine\ORM\Event\PostRemoveEventArgs;
|
use Doctrine\ORM\Event\PostRemoveEventArgs;
|
||||||
use Doctrine\ORM\Event\PostUpdateEventArgs;
|
use Doctrine\ORM\Event\PostUpdateEventArgs;
|
||||||
@@ -31,6 +32,17 @@ class CalendarEntityListener
|
|||||||
{
|
{
|
||||||
public function __construct(private readonly MessageBusInterface $messageBus, private readonly Security $security) {}
|
public function __construct(private readonly MessageBusInterface $messageBus, private readonly Security $security) {}
|
||||||
|
|
||||||
|
private function getAuthenticatedUser(): User
|
||||||
|
{
|
||||||
|
$user = $this->security->getUser();
|
||||||
|
|
||||||
|
if (!$user instanceof User) {
|
||||||
|
throw new \LogicException('Expected an instance of User.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
|
||||||
public function postPersist(Calendar $calendar, PostPersistEventArgs $args): void
|
public function postPersist(Calendar $calendar, PostPersistEventArgs $args): void
|
||||||
{
|
{
|
||||||
if (!$calendar->preventEnqueueChanges) {
|
if (!$calendar->preventEnqueueChanges) {
|
||||||
@@ -38,7 +50,7 @@ class CalendarEntityListener
|
|||||||
new CalendarMessage(
|
new CalendarMessage(
|
||||||
$calendar,
|
$calendar,
|
||||||
CalendarMessage::CALENDAR_PERSIST,
|
CalendarMessage::CALENDAR_PERSIST,
|
||||||
$this->security->getUser()
|
$this->getAuthenticatedUser()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -50,7 +62,7 @@ class CalendarEntityListener
|
|||||||
$this->messageBus->dispatch(
|
$this->messageBus->dispatch(
|
||||||
new CalendarRemovedMessage(
|
new CalendarRemovedMessage(
|
||||||
$calendar,
|
$calendar,
|
||||||
$this->security->getUser()
|
$this->getAuthenticatedUser()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -58,12 +70,19 @@ class CalendarEntityListener
|
|||||||
|
|
||||||
public function postUpdate(Calendar $calendar, PostUpdateEventArgs $args): void
|
public function postUpdate(Calendar $calendar, PostUpdateEventArgs $args): void
|
||||||
{
|
{
|
||||||
if (!$calendar->preventEnqueueChanges) {
|
if ($calendar->getStatus() === $calendar::STATUS_CANCELED) {
|
||||||
|
$this->messageBus->dispatch(
|
||||||
|
new CalendarRemovedMessage(
|
||||||
|
$calendar,
|
||||||
|
$this->getAuthenticatedUser()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} elseif (!$calendar->preventEnqueueChanges) {
|
||||||
$this->messageBus->dispatch(
|
$this->messageBus->dispatch(
|
||||||
new CalendarMessage(
|
new CalendarMessage(
|
||||||
$calendar,
|
$calendar,
|
||||||
CalendarMessage::CALENDAR_UPDATE,
|
CalendarMessage::CALENDAR_UPDATE,
|
||||||
$this->security->getUser()
|
$this->getAuthenticatedUser()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -70,6 +70,8 @@ class CalendarRemovedMessage
|
|||||||
|
|
||||||
public function getRemoteId(): string
|
public function getRemoteId(): string
|
||||||
{
|
{
|
||||||
|
dump($this->remoteId);
|
||||||
|
|
||||||
return $this->remoteId;
|
return $this->remoteId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -41,7 +41,7 @@ class InviteRepository implements ObjectRepository
|
|||||||
/**
|
/**
|
||||||
* @return array|Invite[]
|
* @return array|Invite[]
|
||||||
*/
|
*/
|
||||||
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array
|
public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null)
|
||||||
{
|
{
|
||||||
return $this->entityRepository->findBy($criteria, $orderBy, $limit, $offset);
|
return $this->entityRepository->findBy($criteria, $orderBy, $limit, $offset);
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
Chill\CalendarBundle\Controller\:
|
Chill\CalendarBundle\Controller\:
|
||||||
autowire: true
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
resource: '../../../Controller'
|
resource: '../../../Controller'
|
||||||
tags: ['controller.service_arguments']
|
tags: ['controller.service_arguments']
|
||||||
|
@@ -1,229 +1,263 @@
|
|||||||
{# list used in context of person, accompanyingPeriod or user #}
|
{# list used in context of person or accompanyingPeriod #}
|
||||||
|
|
||||||
<div class="item-bloc">
|
{% if calendarItems|length > 0 %}
|
||||||
<div class="item-row main">
|
<div class="flex-table list-records context-accompanyingCourse">
|
||||||
<div class="item-col">
|
|
||||||
<div class="wrap-header">
|
|
||||||
<div class="wl-row">
|
|
||||||
<div class="wl-col title">
|
|
||||||
<p class="date-label">
|
|
||||||
{% if context == 'person' and calendar.context == 'accompanying_period' %}
|
|
||||||
<a href="{{ chill_path_add_return_path('chill_person_accompanying_course_index', {'accompanying_period_id': calendar.accompanyingPeriod.id}) }}" style="text-decoration: none;">
|
|
||||||
<span class="badge bg-primary">
|
|
||||||
<i class="fa fa-random"></i> {{ calendar.accompanyingPeriod.id }}
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
{% if calendar.endDate.diff(calendar.startDate).days >= 1 %}
|
|
||||||
{{ calendar.startDate|format_datetime('short', 'short') }}
|
|
||||||
- {{ calendar.endDate|format_datetime('short', 'short') }}
|
|
||||||
{% else %}
|
|
||||||
{{ calendar.startDate|format_datetime('short', 'short') }}
|
|
||||||
- {{ calendar.endDate|format_datetime('none', 'short') }}
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="duration short-message">
|
{% for calendar in calendarItems %}
|
||||||
<i class="fa fa-fw fa-hourglass-end"></i>
|
|
||||||
{{ calendar.duration|date('%H:%I') }}
|
<div class="item-bloc">
|
||||||
{% if false == calendar.sendSMS or null == calendar.sendSMS %}
|
<div class="item-row main">
|
||||||
<!-- no sms will be send -->
|
<div class="item-col">
|
||||||
{% else %}
|
<div class="wrap-header">
|
||||||
{% if calendar.smsStatus == 'sms_sent' %}
|
<div class="wl-row">
|
||||||
<span title="{{ 'SMS already sent'|trans }}" class="badge bg-info">
|
{% if calendar.status == 'canceled' %}
|
||||||
<i class="fa fa-check "></i>
|
<div class="badge rounded-pill bg-danger">
|
||||||
<i class="fa fa-envelope "></i>
|
<span>{{ 'chill_calendar.canceled'|trans }}: </span>
|
||||||
</span>
|
<span>{{ calendar.cancelReason.name|localize_translatable_string }}</span>
|
||||||
{% else %}
|
</div>
|
||||||
<span title="{{ 'Will send SMS'|trans }}" class="badge bg-info">
|
{% endif %}
|
||||||
<i class="fa fa-envelope "></i>
|
</div>
|
||||||
<i class="fa fa-hourglass-end "></i>
|
<div class="wl-row">
|
||||||
</span>
|
<div class="wl-col title">
|
||||||
{% endif %}
|
<p class="date-label">
|
||||||
{% endif %}
|
{% if calendar.status == 'canceled' %}
|
||||||
|
<del>
|
||||||
|
{% endif %}
|
||||||
|
{% if context == 'person' and calendar.context == 'accompanying_period' %}
|
||||||
|
<a href="{{ chill_path_add_return_path('chill_person_accompanying_course_index', {'accompanying_period_id': calendar.accompanyingPeriod.id}) }}" style="text-decoration: none;">
|
||||||
|
<span class="badge bg-primary">
|
||||||
|
<i class="fa fa-random"></i> {{ calendar.accompanyingPeriod.id }}
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if calendar.status == 'canceled' %}
|
||||||
|
<del>
|
||||||
|
{% endif %}
|
||||||
|
{% if calendar.endDate.diff(calendar.startDate).days >= 1 %}
|
||||||
|
{{ calendar.startDate|format_datetime('short', 'short') }}
|
||||||
|
- {{ calendar.endDate|format_datetime('short', 'short') }}
|
||||||
|
{% else %}
|
||||||
|
{{ calendar.startDate|format_datetime('short', 'short') }}
|
||||||
|
- {{ calendar.endDate|format_datetime('none', 'short') }}
|
||||||
|
{% endif %}
|
||||||
|
{% if calendar.status == 'canceled' %}
|
||||||
|
</del>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="duration short-message">
|
||||||
|
<i class="fa fa-fw fa-hourglass-end"></i>
|
||||||
|
{{ calendar.duration|date('%H:%I') }}
|
||||||
|
{% if false == calendar.sendSMS or null == calendar.sendSMS %}
|
||||||
|
<!-- no sms will be sent -->
|
||||||
|
{% else %}
|
||||||
|
{% if calendar.smsStatus == 'sms_sent' %}
|
||||||
|
<span title="{{ 'SMS already sent'|trans }}" class="badge bg-info">
|
||||||
|
<i class="fa fa-check "></i>
|
||||||
|
<i class="fa fa-envelope "></i>
|
||||||
|
</span>
|
||||||
|
{% else %}
|
||||||
|
<span title="{{ 'Will send SMS'|trans }}" class="badge bg-info">
|
||||||
|
<i class="fa fa-envelope "></i>
|
||||||
|
<i class="fa fa-hourglass-end "></i>
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
<div class="item-col">
|
||||||
</div>
|
<ul class="list-content">
|
||||||
</div>
|
{% if calendar.mainUser is not empty %}
|
||||||
|
<span class="badge-user">{{ calendar.mainUser|chill_entity_render_box({'at_date': calendar.startDate}) }}</span>
|
||||||
<div class="item-col">
|
|
||||||
<ul class="list-content">
|
|
||||||
{% if calendar.mainUser is not empty %}
|
|
||||||
<span class="badge-user">{{ calendar.mainUser|chill_entity_render_box({'at_date': calendar.startDate}) }}</span>
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if calendar.comment.comment is not empty
|
|
||||||
or calendar.users|length > 0
|
|
||||||
or calendar.thirdParties|length > 0
|
|
||||||
or calendar.users|length > 0 %}
|
|
||||||
<div class="item-row details separator">
|
|
||||||
<div class="item-col">
|
|
||||||
{% include '@ChillActivity/Activity/concernedGroups.html.twig' with {
|
|
||||||
'context': calendar.context == 'person' ? 'calendar_person' : 'calendar_accompanyingCourse',
|
|
||||||
'render': 'wrap-list',
|
|
||||||
'entity': calendar
|
|
||||||
} %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if calendar.comment.comment is not empty %}
|
|
||||||
<div class="item-row details separator">
|
|
||||||
<div class="item-col comment">
|
|
||||||
{{ calendar.comment|chill_entity_render_box( { 'limit_lines': 3, 'metadata': false } ) }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if calendar.location is not empty %}
|
|
||||||
<div class="item-row separator">
|
|
||||||
<div>
|
|
||||||
{% if calendar.location.address is not same as(null) and calendar.location.name is not empty %}
|
|
||||||
<i class="fa fa-map-marker"></i>{% endif %}
|
|
||||||
{% if calendar.location.name is not empty %}{{ calendar.location.name }}{% endif %}
|
|
||||||
{% if calendar.location.address is not same as(null) %}{{ calendar.location.address|chill_entity_render_box({'multiline': false, 'with_picto': (calendar.location.name is empty)}) }}{% else %}
|
|
||||||
<i class="fa fa-map-marker"></i>{% endif %}
|
|
||||||
{% if calendar.location.phonenumber1 is not empty %}<i
|
|
||||||
class="fa fa-phone"></i> {{ calendar.location.phonenumber1|chill_format_phonenumber }}{% endif %}
|
|
||||||
{% if calendar.location.phonenumber2 is not empty %}<i
|
|
||||||
class="fa fa-phone"></i> {{ calendar.location.phonenumber2|chill_format_phonenumber }}{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<div class="item-row separator column">
|
|
||||||
<div>
|
|
||||||
|
|
||||||
{{ include('@ChillCalendar/Calendar/_documents.twig.html') }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if calendar.activity is not null %}
|
|
||||||
<div class="item-row separator">
|
|
||||||
<div class="item-col">
|
|
||||||
<div class="wrap-list">
|
|
||||||
<div class="wl-row">
|
|
||||||
<div class="wl-col title"><h3>{{ 'Activity'|trans }}</h3></div>
|
|
||||||
<div class="wl-col list activity-linked">
|
|
||||||
<h2 class="badge-title">
|
|
||||||
<span class="title_label"></span>
|
|
||||||
<span class="title_action">
|
|
||||||
{{ calendar.activity.type.name | localize_translatable_string }}
|
|
||||||
|
|
||||||
{% if calendar.activity.emergency %}
|
|
||||||
<span class="badge bg-danger rounded-pill fs-6 float-end">{{ 'Emergency'|trans|upper }}</span>
|
|
||||||
{% endif %}
|
|
||||||
</span>
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
<ul class="record_actions">
|
|
||||||
<li class="cancel">
|
|
||||||
<span class="createdBy">
|
|
||||||
{{ 'Created by'|trans }}
|
|
||||||
<b>{{ calendar.activity.createdBy|chill_entity_render_string({'at_date': calendar.activity.createdAt}) }}</b>, {{ 'on'|trans }} {{ calendar.activity.createdAt|format_datetime('short', 'short') }}
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
{% if is_granted('CHILL_ACTIVITY_SEE', calendar.activity) %}
|
|
||||||
<li>
|
|
||||||
<a href="{{ chill_path_add_return_path('chill_activity_activity_show', {'id': calendar.activity.id}) }}" class="btn btn-sm btn-show" ></a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<div class="item-row separator">
|
{% if calendar.users|length > 0
|
||||||
<ul class="record_actions">
|
or calendar.thirdParties|length > 0
|
||||||
{% if is_granted('CHILL_CALENDAR_DOC_EDIT', calendar) %}
|
or calendar.users|length > 0 %}
|
||||||
{% if templates|length == 0 %}
|
<div class="item-row details separator">
|
||||||
<li>
|
<div class="item-col">
|
||||||
<a class="btn btn-create"
|
{% include '@ChillActivity/Activity/concernedGroups.html.twig' with {
|
||||||
href="{{ chill_path_add_return_path('chill_calendar_calendardoc_new', {'id': calendar.id }) }}">
|
'context': calendar.context == 'person' ? 'calendar_person' : 'calendar_accompanyingCourse',
|
||||||
{{ 'chill_calendar.Add a document'|trans }}
|
'render': 'wrap-list',
|
||||||
</a>
|
'entity': calendar
|
||||||
</li>
|
} %}
|
||||||
{% else %}
|
</div>
|
||||||
<li>
|
|
||||||
<div class="dropdown">
|
</div>
|
||||||
<button class="btn btn-create dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
|
||||||
{{ 'chill_calendar.Add a document'|trans }}
|
|
||||||
</button>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item"
|
|
||||||
href="{{ chill_path_add_return_path('chill_calendar_calendardoc_new', {'id': calendar.id }) }}">
|
|
||||||
{{ 'chill_calendar.Upload a document'|trans }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% for template in templates %}
|
|
||||||
<li>
|
|
||||||
<a class="dropdown-item"
|
|
||||||
href="{{ chill_path_add_return_path('chill_docgenerator_generate_from_template', {'template': template.id, 'entityClassName': 'Chill\\CalendarBundle\\Entity\\Calendar', 'entityId': calendar.id}) }}"
|
|
||||||
>
|
|
||||||
{{ template.name|localize_translatable_string }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if calendar.activity is null and (
|
|
||||||
(calendar.context == 'accompanying_period' and is_granted('CHILL_ACTIVITY_CREATE', calendar.accompanyingPeriod))
|
|
||||||
or
|
|
||||||
(calendar.context == 'person' and is_granted('CHILL_ACTIVITY_CREATE', calendar.person))
|
|
||||||
)
|
|
||||||
%}
|
|
||||||
<li>
|
|
||||||
<a class="btn btn-create"
|
|
||||||
href="{{ chill_path_add_return_path('chill_calendar_calendar_to_activity', { 'id': calendar.id }) }}">
|
|
||||||
{{ 'Transform to activity'|trans }}
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if (calendar.isInvited(app.user)) %}
|
{% if calendar.comment.comment is not empty %}
|
||||||
{% set invite = calendar.inviteForUser(app.user) %}
|
<div class="item-row details separator">
|
||||||
<li>
|
<div class="item-col comment">
|
||||||
<div invite-answer data-status="{{ invite.status|e('html_attr') }}"
|
{{ calendar.comment|chill_entity_render_box( { 'limit_lines': 3, 'metadata': false } ) }}
|
||||||
data-calendar-id="{{ calendar.id|e('html_attr') }}"></div>
|
</div>
|
||||||
</li>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if false %}
|
|
||||||
<li>
|
{% if calendar.location is not empty %}
|
||||||
<a href="{{ chill_path_add_return_path('chill_calendar_calendar_show', { 'id': calendar.id}) }}"
|
<div class="item-row separator">
|
||||||
class="btn btn-show "></a>
|
<div>
|
||||||
</li>
|
{% if calendar.location.address is not same as(null) and calendar.location.name is not empty %}
|
||||||
{% endif %}
|
<i class="fa fa-map-marker"></i>{% endif %}
|
||||||
{% if is_granted('CHILL_CALENDAR_CALENDAR_EDIT', calendar) %}
|
{% if calendar.location.name is not empty %}{{ calendar.location.name }}{% endif %}
|
||||||
<li>
|
{% if calendar.location.address is not same as(null) %}{{ calendar.location.address|chill_entity_render_box({'multiline': false, 'with_picto': (calendar.location.name is empty)}) }}{% else %}
|
||||||
<a href="{{ chill_path_add_return_path('chill_calendar_calendar_edit', { 'id': calendar.id }) }}"
|
<i class="fa fa-map-marker"></i>{% endif %}
|
||||||
class="btn btn-update "></a>
|
{% if calendar.location.phonenumber1 is not empty %}<i
|
||||||
</li>
|
class="fa fa-phone"></i> {{ calendar.location.phonenumber1|chill_format_phonenumber }}{% endif %}
|
||||||
{% endif %}
|
{% if calendar.location.phonenumber2 is not empty %}<i
|
||||||
{% if is_granted('CHILL_CALENDAR_CALENDAR_DELETE', calendar) %}
|
class="fa fa-phone"></i> {{ calendar.location.phonenumber2|chill_format_phonenumber }}{% endif %}
|
||||||
<li>
|
</div>
|
||||||
<a href="{{ chill_path_add_return_path('chill_calendar_calendar_delete', { 'id': calendar.id } ) }}"
|
</div>
|
||||||
class="btn btn-delete "></a>
|
{% endif %}
|
||||||
</li>
|
|
||||||
{% endif %}
|
{% if calendar.documents is not empty %}
|
||||||
</ul>
|
<div class="item-row separator column">
|
||||||
|
<div>
|
||||||
|
{{ include('@ChillCalendar/Calendar/_documents.twig.html') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if calendar.activity is not null %}
|
||||||
|
<div class="item-row separator">
|
||||||
|
<div class="item-col">
|
||||||
|
<div class="wrap-list">
|
||||||
|
<div class="wl-row">
|
||||||
|
<div class="wl-col title"><h3>{{ 'Activity'|trans }}</h3></div>
|
||||||
|
<div class="wl-col list activity-linked">
|
||||||
|
<h2 class="badge-title">
|
||||||
|
<span class="title_label"></span>
|
||||||
|
<span class="title_action">
|
||||||
|
{{ calendar.activity.type.name | localize_translatable_string }}
|
||||||
|
|
||||||
|
{% if calendar.activity.emergency %}
|
||||||
|
<span class="badge bg-danger rounded-pill fs-6 float-end">{{ 'Emergency'|trans|upper }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<ul class="record_actions">
|
||||||
|
<li class="cancel">
|
||||||
|
<span class="createdBy">
|
||||||
|
{{ 'Created by'|trans }}
|
||||||
|
<b>{{ calendar.activity.createdBy|chill_entity_render_string({'at_date': calendar.activity.createdAt}) }}</b>, {{ 'on'|trans }} {{ calendar.activity.createdAt|format_datetime('short', 'short') }}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
{% if is_granted('CHILL_ACTIVITY_SEE', calendar.activity) %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ chill_path_add_return_path('chill_activity_activity_show', {'id': calendar.activity.id}) }}" class="btn btn-sm btn-show" ></a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="item-row separator">
|
||||||
|
<ul class="record_actions">
|
||||||
|
{% if is_granted('CHILL_CALENDAR_DOC_EDIT', calendar) and calendar.status is not constant('STATUS_CANCELED', calendar) %}
|
||||||
|
{% if templates|length == 0 %}
|
||||||
|
<li>
|
||||||
|
<a class="btn btn-create"
|
||||||
|
href="{{ chill_path_add_return_path('chill_calendar_calendardoc_new', {'id': calendar.id }) }}">
|
||||||
|
{{ 'chill_calendar.Add a document'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li>
|
||||||
|
<div class="dropdown">
|
||||||
|
<button class="btn btn-create dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||||
|
{{ 'chill_calendar.Add a document'|trans }}
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li>
|
||||||
|
<a class="dropdown-item"
|
||||||
|
href="{{ chill_path_add_return_path('chill_calendar_calendardoc_new', {'id': calendar.id }) }}">
|
||||||
|
{{ 'chill_calendar.Upload a document'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% for template in templates %}
|
||||||
|
<li>
|
||||||
|
<a class="dropdown-item"
|
||||||
|
href="{{ chill_path_add_return_path('chill_docgenerator_generate_from_template', {'template': template.id, 'entityClassName': 'Chill\\CalendarBundle\\Entity\\Calendar', 'entityId': calendar.id}) }}"
|
||||||
|
>
|
||||||
|
{{ template.name|localize_translatable_string }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% if calendar.activity is null and (
|
||||||
|
(calendar.context == 'accompanying_period' and is_granted('CHILL_ACTIVITY_CREATE', calendar.accompanyingPeriod))
|
||||||
|
or
|
||||||
|
(calendar.context == 'person' and is_granted('CHILL_ACTIVITY_CREATE', calendar.person))
|
||||||
|
)
|
||||||
|
and calendar.status is not constant('STATUS_CANCELED', calendar)
|
||||||
|
%}
|
||||||
|
<li>
|
||||||
|
<a class="btn btn-create"
|
||||||
|
href="{{ chill_path_add_return_path('chill_calendar_calendar_to_activity', { 'id': calendar.id }) }}">
|
||||||
|
{{ 'Transform to activity'|trans }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if (calendar.isInvited(app.user)) %}
|
||||||
|
{% set invite = calendar.inviteForUser(app.user) %}
|
||||||
|
<li>
|
||||||
|
<div invite-answer data-status="{{ invite.status|e('html_attr') }}"
|
||||||
|
data-calendar-id="{{ calendar.id|e('html_attr') }}"></div>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if false %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ chill_path_add_return_path('chill_calendar_calendar_show', { 'id': calendar.id}) }}"
|
||||||
|
class="btn btn-show "></a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if is_granted('CHILL_CALENDAR_CALENDAR_EDIT', calendar) and calendar.status is not constant('STATUS_CANCELED', calendar) %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ chill_path_add_return_path('chill_calendar_calendar_edit', { 'id': calendar.id }) }}"
|
||||||
|
class="btn btn-update "></a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ chill_path_add_return_path('chill_calendar_calendar_cancel', { 'id': calendar.id } ) }}"
|
||||||
|
class="btn btn-remove">{{ 'Cancel'|trans }}</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if is_granted('CHILL_CALENDAR_CALENDAR_DELETE', calendar) %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ chill_path_add_return_path('chill_calendar_calendar_delete', { 'id': calendar.id } ) }}"
|
||||||
|
class="btn btn-delete "></a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if calendarItems|length < paginator.getTotalItems %}
|
||||||
|
{{ chill_pagination(paginator) }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -0,0 +1,29 @@
|
|||||||
|
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% set activeRouteKey = 'chill_calendar_calendar_list' %}
|
||||||
|
|
||||||
|
{% block title 'chill_calendar.cancel_calendar_item'|trans %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{{ form_start(form) }}
|
||||||
|
|
||||||
|
{{ form_row(form.cancelReason) }}
|
||||||
|
|
||||||
|
<ul class="record_actions sticky-form-buttons">
|
||||||
|
<li class="save">
|
||||||
|
<a
|
||||||
|
class="btn btn-cancel"
|
||||||
|
href="{{ chill_return_path_or('chill_calendar_calendar_list', { 'id': accompanyingCourse.id } )}}"
|
||||||
|
>
|
||||||
|
{{ 'Cancel'|trans|chill_return_path_label }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{{ form_widget(form.submit, { 'attr' : { 'class': 'btn btn-save' }, 'label': 'Save' } ) }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{{ form_end(form) }}
|
||||||
|
|
||||||
|
{% endblock %}
|
@@ -0,0 +1,29 @@
|
|||||||
|
{% extends "@ChillPerson/Person/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% set activeRouteKey = 'chill_calendar_calendar_list' %}
|
||||||
|
|
||||||
|
{% block title 'chill_calendar.cancel_calendar_item'|trans %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{{ form_start(form) }}
|
||||||
|
|
||||||
|
{{ form_row(form.cancelReason) }}
|
||||||
|
|
||||||
|
<ul class="record_actions sticky-form-buttons">
|
||||||
|
<li class="save">
|
||||||
|
<a
|
||||||
|
class="btn btn-cancel"
|
||||||
|
href="{{ chill_return_path_or('chill_calendar_calendar_list', { 'id': person.id } )}}"
|
||||||
|
>
|
||||||
|
{{ 'Cancel'|trans|chill_return_path_label }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{{ form_widget(form.submit, { 'attr' : { 'class': 'btn btn-save' }, 'label': 'Save' } ) }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{{ form_end(form) }}
|
||||||
|
|
||||||
|
{% endblock %}
|
@@ -34,18 +34,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if calendarItems|length > 0 %}
|
{{ include('@ChillCalendar/Calendar/_list.html.twig', {context: 'accompanying_course'}) }}
|
||||||
<div class="flex-table list-records context-accompanyingCourse">
|
|
||||||
{% for calendar in calendarItems %}
|
|
||||||
{{ include('@ChillCalendar/Calendar/_list.html.twig', {context: 'accompanying_course'}) }}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if calendarItems|length < paginator.getTotalItems %}
|
|
||||||
{{ chill_pagination(paginator) }}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<ul class="record_actions sticky-form-buttons">
|
<ul class="record_actions sticky-form-buttons">
|
||||||
|
@@ -33,17 +33,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if calendarItems|length > 0 %}
|
{{ include ('@ChillCalendar/Calendar/_list.html.twig', {context: 'person'}) }}
|
||||||
<div class="flex-table list-records context-person">
|
|
||||||
{% for calendar in calendarItems %}
|
|
||||||
{{ include ('@ChillCalendar/Calendar/_list.html.twig', {context: 'person'}) }}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if calendarItems|length < paginator.getTotalItems %}
|
|
||||||
{{ chill_pagination(paginator) }}
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<ul class="record_actions sticky-form-buttons">
|
<ul class="record_actions sticky-form-buttons">
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
{% block table_entities_thead_tr %}
|
{% block table_entities_thead_tr %}
|
||||||
<th>{{ 'Id'|trans }}</th>
|
<th>{{ 'Id'|trans }}</th>
|
||||||
<th>{{ 'Name'|trans }}</th>
|
<th>{{ 'Name'|trans }}</th>
|
||||||
<th>{{ 'canceledBy'|trans }}</th>
|
<th>{{ 'Canceled by'|trans }}</th>
|
||||||
<th>{{ 'active'|trans }}</th>
|
<th>{{ 'active'|trans }}</th>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -40,4 +40,4 @@
|
|||||||
</li>
|
</li>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% endembed %}
|
{% endembed %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@@ -1,40 +0,0 @@
|
|||||||
{% extends "@ChillMain/layout.html.twig" %}
|
|
||||||
|
|
||||||
{% set activeRouteKey = 'chill_calendar_invitations_list' %}
|
|
||||||
|
|
||||||
{% block title %}{{ 'My invitations list' |trans }}{% endblock title %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<h1>{{ 'invite.list.title'|trans }}</h1>
|
|
||||||
|
|
||||||
{% if invitations|length == 0 %}
|
|
||||||
<p class="chill-no-data-statement">
|
|
||||||
{{ "invite.list.none"|trans }}
|
|
||||||
</p>
|
|
||||||
{% else %}
|
|
||||||
<div class="flex-table list-records">
|
|
||||||
{% for invitation in invitations %}
|
|
||||||
{% set calendar = invitation.getCalendar %}
|
|
||||||
{{ include('@ChillCalendar/Calendar/_list.html.twig', {context: 'user'}) }}
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if invitations|length < paginator.getTotalItems %}
|
|
||||||
{{ chill_pagination(paginator) }}
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block js %}
|
|
||||||
{{ parent() }}
|
|
||||||
{{ encore_entry_script_tags('mod_answer') }}
|
|
||||||
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block css %}
|
|
||||||
{{ parent() }}
|
|
||||||
{{ encore_entry_link_tags('mod_answer') }}
|
|
||||||
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
|
|
||||||
{% endblock %}
|
|
@@ -19,6 +19,7 @@ declare(strict_types=1);
|
|||||||
namespace Chill\CalendarBundle\Service\ShortMessageNotification;
|
namespace Chill\CalendarBundle\Service\ShortMessageNotification;
|
||||||
|
|
||||||
use Chill\CalendarBundle\Entity\Calendar;
|
use Chill\CalendarBundle\Entity\Calendar;
|
||||||
|
use Chill\CalendarBundle\Entity\CancelReason;
|
||||||
use libphonenumber\PhoneNumberFormat;
|
use libphonenumber\PhoneNumberFormat;
|
||||||
use libphonenumber\PhoneNumberUtil;
|
use libphonenumber\PhoneNumberUtil;
|
||||||
use Symfony\Component\Notifier\Message\SmsMessage;
|
use Symfony\Component\Notifier\Message\SmsMessage;
|
||||||
@@ -57,7 +58,7 @@ class DefaultShortMessageForCalendarBuilder implements ShortMessageForCalendarBu
|
|||||||
$this->phoneUtil->format($person->getMobilenumber(), PhoneNumberFormat::E164),
|
$this->phoneUtil->format($person->getMobilenumber(), PhoneNumberFormat::E164),
|
||||||
$this->engine->render('@ChillCalendar/CalendarShortMessage/short_message.txt.twig', ['calendar' => $calendar]),
|
$this->engine->render('@ChillCalendar/CalendarShortMessage/short_message.txt.twig', ['calendar' => $calendar]),
|
||||||
);
|
);
|
||||||
} elseif (Calendar::SMS_CANCEL_PENDING === $calendar->getSmsStatus()) {
|
} elseif (Calendar::SMS_CANCEL_PENDING === $calendar->getSmsStatus() && (null === $calendar->getCancelReason() || CancelReason::CANCELEDBY_PERSON !== $calendar->getCancelReason()->getCanceledBy())) {
|
||||||
$toUsers[] = new SmsMessage(
|
$toUsers[] = new SmsMessage(
|
||||||
$this->phoneUtil->format($person->getMobilenumber(), PhoneNumberFormat::E164),
|
$this->phoneUtil->format($person->getMobilenumber(), PhoneNumberFormat::E164),
|
||||||
$this->engine->render('@ChillCalendar/CalendarShortMessage/short_message_canceled.txt.twig', ['calendar' => $calendar]),
|
$this->engine->render('@ChillCalendar/CalendarShortMessage/short_message_canceled.txt.twig', ['calendar' => $calendar]),
|
||||||
|
@@ -1,292 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Chill\CalendarBundle\Tests\Controller;
|
|
||||||
|
|
||||||
use Chill\CalendarBundle\Controller\MyInvitationsController;
|
|
||||||
use Chill\CalendarBundle\Entity\Calendar;
|
|
||||||
use Chill\CalendarBundle\Entity\Invite;
|
|
||||||
use Chill\CalendarBundle\Repository\InviteRepository;
|
|
||||||
use Chill\DocGeneratorBundle\Repository\DocGeneratorTemplateRepositoryInterface;
|
|
||||||
use Chill\MainBundle\Entity\User;
|
|
||||||
use Chill\MainBundle\Pagination\PaginatorFactory;
|
|
||||||
use Chill\MainBundle\Pagination\PaginatorInterface;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use Prophecy\PhpUnit\ProphecyTrait;
|
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
|
||||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
|
||||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
|
||||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
|
|
||||||
use Twig\Environment;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*
|
|
||||||
* @coversNothing
|
|
||||||
*/
|
|
||||||
final class MyInvitationsControllerTest extends TestCase
|
|
||||||
{
|
|
||||||
use ProphecyTrait;
|
|
||||||
|
|
||||||
private MyInvitationsController $controller;
|
|
||||||
|
|
||||||
protected function setUp(): void
|
|
||||||
{
|
|
||||||
// Create prophecies for dependencies
|
|
||||||
$inviteRepository = $this->prophesize(InviteRepository::class);
|
|
||||||
$paginatorFactory = $this->prophesize(PaginatorFactory::class);
|
|
||||||
$docGeneratorTemplateRepository = $this->prophesize(DocGeneratorTemplateRepositoryInterface::class);
|
|
||||||
|
|
||||||
// Create controller instance
|
|
||||||
$this->controller = new MyInvitationsController(
|
|
||||||
$inviteRepository->reveal(),
|
|
||||||
$paginatorFactory->reveal(),
|
|
||||||
$docGeneratorTemplateRepository->reveal()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Set up necessary services for AbstractController
|
|
||||||
$authorizationChecker = $this->prophesize(AuthorizationCheckerInterface::class);
|
|
||||||
$tokenStorage = $this->prophesize(TokenStorageInterface::class);
|
|
||||||
$twig = $this->prophesize(Environment::class);
|
|
||||||
|
|
||||||
// Use reflection to set the container
|
|
||||||
$reflection = new \ReflectionClass($this->controller);
|
|
||||||
$containerProperty = $reflection->getParentClass()->getProperty('container');
|
|
||||||
$containerProperty->setAccessible(true);
|
|
||||||
|
|
||||||
// Create a mock container
|
|
||||||
$container = $this->prophesize(\Psr\Container\ContainerInterface::class);
|
|
||||||
$container->has('security.authorization_checker')->willReturn(true);
|
|
||||||
$container->get('security.authorization_checker')->willReturn($authorizationChecker->reveal());
|
|
||||||
$container->has('security.token_storage')->willReturn(true);
|
|
||||||
$container->get('security.token_storage')->willReturn($tokenStorage->reveal());
|
|
||||||
$container->has('twig')->willReturn(true);
|
|
||||||
$container->get('twig')->willReturn($twig->reveal());
|
|
||||||
|
|
||||||
$containerProperty->setValue($this->controller, $container->reveal());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testMyInvitationsReturnsCorrectAmountOfInvitations(): void
|
|
||||||
{
|
|
||||||
// Create test user
|
|
||||||
$user = new User();
|
|
||||||
$user->setUsername('testuser');
|
|
||||||
|
|
||||||
// Create test invitations
|
|
||||||
$invite1 = new Invite();
|
|
||||||
$invite1->setUser($user);
|
|
||||||
$invite1->setStatus(Invite::PENDING);
|
|
||||||
|
|
||||||
$invite2 = new Invite();
|
|
||||||
$invite2->setUser($user);
|
|
||||||
$invite2->setStatus(Invite::ACCEPTED);
|
|
||||||
|
|
||||||
$invite3 = new Invite();
|
|
||||||
$invite3->setUser($user);
|
|
||||||
$invite3->setStatus(Invite::DECLINED);
|
|
||||||
|
|
||||||
$allInvitations = [$invite1, $invite2, $invite3];
|
|
||||||
$paginatedInvitations = [$invite1, $invite2]; // First page with 2 items per page
|
|
||||||
|
|
||||||
// Set up repository prophecies
|
|
||||||
$inviteRepository = $this->prophesize(InviteRepository::class);
|
|
||||||
$inviteRepository->findBy(['user' => $user])->willReturn($allInvitations);
|
|
||||||
$inviteRepository->findBy(
|
|
||||||
['user' => $user],
|
|
||||||
['createdAt' => 'DESC'],
|
|
||||||
2, // items per page
|
|
||||||
0 // offset
|
|
||||||
)->willReturn($paginatedInvitations);
|
|
||||||
|
|
||||||
// Set up paginator prophecies
|
|
||||||
$paginator = $this->prophesize(PaginatorInterface::class);
|
|
||||||
$paginator->getItemsPerPage()->willReturn(2);
|
|
||||||
$paginator->getCurrentPageFirstItemNumber()->willReturn(0);
|
|
||||||
|
|
||||||
$paginatorFactory = $this->prophesize(PaginatorFactory::class);
|
|
||||||
$paginatorFactory->create(3)->willReturn($paginator->reveal());
|
|
||||||
|
|
||||||
// Set up doc generator repository
|
|
||||||
$docGeneratorTemplateRepository = $this->prophesize(DocGeneratorTemplateRepositoryInterface::class);
|
|
||||||
$docGeneratorTemplateRepository->findByEntity(Calendar::class)->willReturn([]);
|
|
||||||
|
|
||||||
// Create controller with mocked dependencies
|
|
||||||
$controller = new MyInvitationsController(
|
|
||||||
$inviteRepository->reveal(),
|
|
||||||
$paginatorFactory->reveal(),
|
|
||||||
$docGeneratorTemplateRepository->reveal()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Set up authorization checker to return true for ROLE_USER
|
|
||||||
$authorizationChecker = $this->prophesize(AuthorizationCheckerInterface::class);
|
|
||||||
$authorizationChecker->isGranted('ROLE_USER', null)->willReturn(true);
|
|
||||||
|
|
||||||
// Set up token storage to return user
|
|
||||||
$token = $this->prophesize(TokenInterface::class);
|
|
||||||
$token->getUser()->willReturn($user);
|
|
||||||
$tokenStorage = $this->prophesize(TokenStorageInterface::class);
|
|
||||||
$tokenStorage->getToken()->willReturn($token->reveal());
|
|
||||||
|
|
||||||
// Set up twig to return a response
|
|
||||||
$twig = $this->prophesize(Environment::class);
|
|
||||||
$twig->render('@ChillCalendar/Invitations/listByUser.html.twig', [
|
|
||||||
'invitations' => $paginatedInvitations,
|
|
||||||
'paginator' => $paginator->reveal(),
|
|
||||||
'templates' => [],
|
|
||||||
])->willReturn('rendered content');
|
|
||||||
|
|
||||||
// Set up container
|
|
||||||
$container = $this->prophesize(\Psr\Container\ContainerInterface::class);
|
|
||||||
$container->has('security.authorization_checker')->willReturn(true);
|
|
||||||
$container->get('security.authorization_checker')->willReturn($authorizationChecker->reveal());
|
|
||||||
$container->has('security.token_storage')->willReturn(true);
|
|
||||||
$container->get('security.token_storage')->willReturn($tokenStorage->reveal());
|
|
||||||
$container->has('twig')->willReturn(true);
|
|
||||||
$container->get('twig')->willReturn($twig->reveal());
|
|
||||||
|
|
||||||
// Use reflection to set the container
|
|
||||||
$reflection = new \ReflectionClass($controller);
|
|
||||||
$containerProperty = $reflection->getParentClass()->getProperty('container');
|
|
||||||
$containerProperty->setAccessible(true);
|
|
||||||
$containerProperty->setValue($controller, $container->reveal());
|
|
||||||
|
|
||||||
// Create request
|
|
||||||
$request = new Request();
|
|
||||||
|
|
||||||
// Execute the action
|
|
||||||
$response = $controller->myInvitations($request);
|
|
||||||
|
|
||||||
// Assert that response is successful
|
|
||||||
self::assertInstanceOf(Response::class, $response);
|
|
||||||
self::assertSame(200, $response->getStatusCode());
|
|
||||||
self::assertSame('rendered content', $response->getContent());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testMyInvitationsPageLoads(): void
|
|
||||||
{
|
|
||||||
// Create test user
|
|
||||||
$user = new User();
|
|
||||||
$user->setUsername('testuser');
|
|
||||||
|
|
||||||
// Set up repository prophecies - no invitations
|
|
||||||
$inviteRepository = $this->prophesize(InviteRepository::class);
|
|
||||||
$inviteRepository->findBy(['user' => $user])->willReturn([]);
|
|
||||||
$inviteRepository->findBy(
|
|
||||||
['user' => $user],
|
|
||||||
['createdAt' => 'DESC'],
|
|
||||||
20, // default items per page
|
|
||||||
0 // offset
|
|
||||||
)->willReturn([]);
|
|
||||||
|
|
||||||
// Set up paginator prophecies
|
|
||||||
$paginator = $this->prophesize(PaginatorInterface::class);
|
|
||||||
$paginator->getItemsPerPage()->willReturn(20);
|
|
||||||
$paginator->getCurrentPageFirstItemNumber()->willReturn(0);
|
|
||||||
|
|
||||||
$paginatorFactory = $this->prophesize(PaginatorFactory::class);
|
|
||||||
$paginatorFactory->create(0)->willReturn($paginator->reveal());
|
|
||||||
|
|
||||||
// Set up doc generator repository
|
|
||||||
$docGeneratorTemplateRepository = $this->prophesize(DocGeneratorTemplateRepositoryInterface::class);
|
|
||||||
$docGeneratorTemplateRepository->findByEntity(Calendar::class)->willReturn([]);
|
|
||||||
|
|
||||||
// Create controller with mocked dependencies
|
|
||||||
$controller = new MyInvitationsController(
|
|
||||||
$inviteRepository->reveal(),
|
|
||||||
$paginatorFactory->reveal(),
|
|
||||||
$docGeneratorTemplateRepository->reveal()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Set up authorization checker to return true for ROLE_USER
|
|
||||||
$authorizationChecker = $this->prophesize(AuthorizationCheckerInterface::class);
|
|
||||||
$authorizationChecker->isGranted('ROLE_USER', null)->willReturn(true);
|
|
||||||
|
|
||||||
// Set up token storage to return user
|
|
||||||
$token = $this->prophesize(TokenInterface::class);
|
|
||||||
$token->getUser()->willReturn($user);
|
|
||||||
$tokenStorage = $this->prophesize(TokenStorageInterface::class);
|
|
||||||
$tokenStorage->getToken()->willReturn($token->reveal());
|
|
||||||
|
|
||||||
// Set up twig to return a response
|
|
||||||
$twig = $this->prophesize(Environment::class);
|
|
||||||
$twig->render('@ChillCalendar/Invitations/listByUser.html.twig', [
|
|
||||||
'invitations' => [],
|
|
||||||
'paginator' => $paginator->reveal(),
|
|
||||||
'templates' => [],
|
|
||||||
])->willReturn('empty page content');
|
|
||||||
|
|
||||||
// Set up container
|
|
||||||
$container = $this->prophesize(\Psr\Container\ContainerInterface::class);
|
|
||||||
$container->has('security.authorization_checker')->willReturn(true);
|
|
||||||
$container->get('security.authorization_checker')->willReturn($authorizationChecker->reveal());
|
|
||||||
$container->has('security.token_storage')->willReturn(true);
|
|
||||||
$container->get('security.token_storage')->willReturn($tokenStorage->reveal());
|
|
||||||
$container->has('twig')->willReturn(true);
|
|
||||||
$container->get('twig')->willReturn($twig->reveal());
|
|
||||||
|
|
||||||
// Use reflection to set the container
|
|
||||||
$reflection = new \ReflectionClass($controller);
|
|
||||||
$containerProperty = $reflection->getParentClass()->getProperty('container');
|
|
||||||
$containerProperty->setAccessible(true);
|
|
||||||
$containerProperty->setValue($controller, $container->reveal());
|
|
||||||
|
|
||||||
// Create request
|
|
||||||
$request = new Request();
|
|
||||||
|
|
||||||
// Execute the action
|
|
||||||
$response = $controller->myInvitations($request);
|
|
||||||
|
|
||||||
// Assert that page loads successfully
|
|
||||||
self::assertInstanceOf(Response::class, $response);
|
|
||||||
self::assertSame(200, $response->getStatusCode());
|
|
||||||
self::assertSame('empty page content', $response->getContent());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testMyInvitationsRequiresAuthentication(): void
|
|
||||||
{
|
|
||||||
// Create controller with minimal dependencies
|
|
||||||
$inviteRepository = $this->prophesize(InviteRepository::class);
|
|
||||||
$paginatorFactory = $this->prophesize(PaginatorFactory::class);
|
|
||||||
$docGeneratorTemplateRepository = $this->prophesize(DocGeneratorTemplateRepositoryInterface::class);
|
|
||||||
|
|
||||||
$controller = new MyInvitationsController(
|
|
||||||
$inviteRepository->reveal(),
|
|
||||||
$paginatorFactory->reveal(),
|
|
||||||
$docGeneratorTemplateRepository->reveal()
|
|
||||||
);
|
|
||||||
|
|
||||||
// Set up authorization checker to return false for ROLE_USER
|
|
||||||
$authorizationChecker = $this->prophesize(AuthorizationCheckerInterface::class);
|
|
||||||
$authorizationChecker->isGranted('ROLE_USER')->willReturn(false);
|
|
||||||
$authorizationChecker->isGranted('ROLE_USER', null)->willReturn(false);
|
|
||||||
|
|
||||||
// Set up container
|
|
||||||
$container = $this->prophesize(\Psr\Container\ContainerInterface::class);
|
|
||||||
$container->has('security.authorization_checker')->willReturn(true);
|
|
||||||
$container->get('security.authorization_checker')->willReturn($authorizationChecker->reveal());
|
|
||||||
|
|
||||||
// Use reflection to set the container
|
|
||||||
$reflection = new \ReflectionClass($controller);
|
|
||||||
$containerProperty = $reflection->getParentClass()->getProperty('container');
|
|
||||||
$containerProperty->setAccessible(true);
|
|
||||||
$containerProperty->setValue($controller, $container->reveal());
|
|
||||||
|
|
||||||
// Create request
|
|
||||||
$request = new Request();
|
|
||||||
|
|
||||||
// Expect AccessDeniedException
|
|
||||||
$this->expectException(\Symfony\Component\Security\Core\Exception\AccessDeniedException::class);
|
|
||||||
|
|
||||||
// Execute the action
|
|
||||||
$controller->myInvitations($request);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -31,8 +31,7 @@ Will send SMS: Un SMS de rappel sera envoyé
|
|||||||
Will not send SMS: Aucun SMS de rappel ne sera envoyé
|
Will not send SMS: Aucun SMS de rappel ne sera envoyé
|
||||||
SMS already sent: Un SMS a été envoyé
|
SMS already sent: Un SMS a été envoyé
|
||||||
|
|
||||||
canceledBy: supprimé par
|
Canceled by: Annulé par
|
||||||
Canceled by: supprimé par
|
|
||||||
Calendar configuration: Gestion des rendez-vous
|
Calendar configuration: Gestion des rendez-vous
|
||||||
|
|
||||||
crud:
|
crud:
|
||||||
@@ -44,6 +43,14 @@ crud:
|
|||||||
title_edit: Modifier le motif d'annulation
|
title_edit: Modifier le motif d'annulation
|
||||||
|
|
||||||
chill_calendar:
|
chill_calendar:
|
||||||
|
canceled: Annulé
|
||||||
|
cancel_reason: Raison d'annulation
|
||||||
|
cancel_calendar_item: Annuler rendez-vous
|
||||||
|
calendar_canceled: Le rendez-vous a été annulé
|
||||||
|
canceled_by:
|
||||||
|
user: Utilisateur
|
||||||
|
person: Usager
|
||||||
|
other: Autre
|
||||||
Document: Document d'un rendez-vous
|
Document: Document d'un rendez-vous
|
||||||
form:
|
form:
|
||||||
The main user is mandatory. He will organize the appointment.: L'utilisateur principal est obligatoire. Il est l'organisateur de l'événement.
|
The main user is mandatory. He will organize the appointment.: L'utilisateur principal est obligatoire. Il est l'organisateur de l'événement.
|
||||||
@@ -86,9 +93,6 @@ invite:
|
|||||||
declined: Refusé
|
declined: Refusé
|
||||||
pending: En attente
|
pending: En attente
|
||||||
tentative: Accepté provisoirement
|
tentative: Accepté provisoirement
|
||||||
list:
|
|
||||||
none: Il n'y aucun invitation
|
|
||||||
title: Mes invitations
|
|
||||||
|
|
||||||
# exports
|
# exports
|
||||||
Exports of calendar: Exports des rendez-vous
|
Exports of calendar: Exports des rendez-vous
|
||||||
|
@@ -20,9 +20,4 @@ use Doctrine\Persistence\ObjectRepository;
|
|||||||
interface DocGeneratorTemplateRepositoryInterface extends ObjectRepository
|
interface DocGeneratorTemplateRepositoryInterface extends ObjectRepository
|
||||||
{
|
{
|
||||||
public function countByEntity(string $entity): int;
|
public function countByEntity(string $entity): int;
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array|DocGeneratorTemplate[]
|
|
||||||
*/
|
|
||||||
public function findByEntity(string $entity, ?int $start = 0, ?int $limit = 50): array;
|
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,7 @@ use Symfony\Component\Routing\RouterInterface;
|
|||||||
/**
|
/**
|
||||||
* Create paginator instances.
|
* Create paginator instances.
|
||||||
*/
|
*/
|
||||||
class PaginatorFactory implements PaginatorFactoryInterface
|
final readonly class PaginatorFactory implements PaginatorFactoryInterface
|
||||||
{
|
{
|
||||||
final public const DEFAULT_CURRENT_PAGE_KEY = 'page';
|
final public const DEFAULT_CURRENT_PAGE_KEY = 'page';
|
||||||
|
|
||||||
@@ -29,16 +29,16 @@ class PaginatorFactory implements PaginatorFactoryInterface
|
|||||||
/**
|
/**
|
||||||
* the request stack.
|
* the request stack.
|
||||||
*/
|
*/
|
||||||
private readonly RequestStack $requestStack,
|
private RequestStack $requestStack,
|
||||||
/**
|
/**
|
||||||
* the router and generator for url.
|
* the router and generator for url.
|
||||||
*/
|
*/
|
||||||
private readonly RouterInterface $router,
|
private RouterInterface $router,
|
||||||
/**
|
/**
|
||||||
* the default item per page. This may be overriden by
|
* the default item per page. This may be overriden by
|
||||||
* the request or inside the paginator.
|
* the request or inside the paginator.
|
||||||
*/
|
*/
|
||||||
private readonly int $itemPerPage = 20,
|
private int $itemPerPage = 20,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user