From 616be5cc8a9a369057e460a0b04603096ffc4225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Mon, 13 Jun 2022 14:01:07 +0200 Subject: [PATCH] bootstrap fake sms from cli --- .../SendTestShortMessageOnCalendarCommand.php | 190 ++++++++++++++++++ .../ChillCalendarExtension.php | 6 + .../DependencyInjection/Configuration.php | 7 +- .../ChillCalendarBundle/Entity/Calendar.php | 27 ++- .../Repository/CalendarRepository.php | 39 ++++ .../Resources/config/services.yml | 8 + .../short_message.txt.twig | 1 + .../DefaultShortMessageForCalendarBuilder.php | 46 +++++ ...hortMessageForCalendarBuilderInterface.php | 15 ++ .../ChillMainExtension.php | 1 + .../ShortMessage/NullShortMessageSender.php | 10 + .../Service/ShortMessage/ShortMessage.php | 55 +++++ .../ShortMessageSenderInterface.php | 8 + .../ChillMainBundle/config/services.yaml | 1 + .../config/services/short_message.yaml | 5 + 15 files changed, 417 insertions(+), 2 deletions(-) create mode 100644 src/Bundle/ChillCalendarBundle/Command/SendTestShortMessageOnCalendarCommand.php create mode 100644 src/Bundle/ChillCalendarBundle/Resources/views/CalendarShortMessage/short_message.txt.twig create mode 100644 src/Bundle/ChillCalendarBundle/Service/ShortMessageNotification/DefaultShortMessageForCalendarBuilder.php create mode 100644 src/Bundle/ChillCalendarBundle/Service/ShortMessageNotification/ShortMessageForCalendarBuilderInterface.php create mode 100644 src/Bundle/ChillMainBundle/Service/ShortMessage/NullShortMessageSender.php create mode 100644 src/Bundle/ChillMainBundle/Service/ShortMessage/ShortMessage.php create mode 100644 src/Bundle/ChillMainBundle/Service/ShortMessage/ShortMessageSenderInterface.php create mode 100644 src/Bundle/ChillMainBundle/config/services/short_message.yaml diff --git a/src/Bundle/ChillCalendarBundle/Command/SendTestShortMessageOnCalendarCommand.php b/src/Bundle/ChillCalendarBundle/Command/SendTestShortMessageOnCalendarCommand.php new file mode 100644 index 000000000..d49f1615b --- /dev/null +++ b/src/Bundle/ChillCalendarBundle/Command/SendTestShortMessageOnCalendarCommand.php @@ -0,0 +1,190 @@ +personRepository = $personRepository; + $this->phoneNumberUtil = $phoneNumberUtil; + $this->phoneNumberHelper = $phoneNumberHelper; + $this->messageForCalendarBuilder = $messageForCalendarBuilder; + $this->messageSender = $messageSender; + $this->userRepository = $userRepository; + } + + + public function getName() + { + return 'chill:calendar:test-send-short-message'; + } + + protected function configure() + { + $this->setDescription('Test sending a SMS for a dummy calendar appointment'); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $calendar = new Calendar(); + $calendar->setSendSMS(true); + + /** @var QuestionHelper $helper */ + $helper = $this->getHelper('question'); + + // start date + $question = new Question("When will start the appointment ? (default: \"1 hour\") ", '1 hour'); + $startDate = new \DateTimeImmutable($helper->ask($input, $output, $question)); + + if (false === $startDate) { + throw new \UnexpectedValueException("could not create a date with this date and time"); + } + + $calendar->setStartDate($startDate); + + // end date + $question = new Question("How long will last the appointment ? (default: \"PT30M\") ", 'PT30M'); + $interval = new \DateInterval($helper->ask($input, $output, $question)); + + if (false === $interval) { + throw new \UnexpectedValueException("could not create the interval"); + } + + $calendar->setEndDate($calendar->getStartDate()->add($interval)); + + // a person + $question = new Question("Who will participate ? Give an id for a person. "); + $question + ->setValidator(function ($answer): Person { + if (!is_numeric($answer)) { + throw new \UnexpectedValueException('the answer must be numeric'); + } + + if (0 >= (int) $answer) { + throw new \UnexpectedValueException('the answer must be greater than zero'); + } + + $person = $this->personRepository->find((int) $answer); + + if (null === $person) { + throw new \UnexpectedValueException("The person is not found"); + } + + return $person; + }); + + $person = $helper->ask($input, $output, $question); + $calendar->addPerson($person); + + + // a main user + $question = new Question("Who will be the main user ? Give an id for a user. "); + $question + ->setValidator(function ($answer): User { + if (!is_numeric($answer)) { + throw new \UnexpectedValueException('the answer must be numeric'); + } + + if (0 >= (int) $answer) { + throw new \UnexpectedValueException('the answer must be greater than zero'); + } + + $user = $this->userRepository->find((int) $answer); + + if (null === $user) { + throw new \UnexpectedValueException("The user is not found"); + } + + return $user; + }); + + $user = $helper->ask($input, $output, $question); + $calendar->setMainUser($user); + + // phonenumber + $question = new Question("To which number are we going to send this fake message ?", + null !== $person->getMobilenumber() ? + $this->phoneNumberHelper->format($person->getMobilenumber()): + null + ); + + $question->setNormalizer(function ($answer): PhoneNumber { + if (null === $answer) { + throw new \UnexpectedValueException("The person is not found"); + } + + $phone = $this->phoneNumberUtil->parse($answer, 'BE'); + + if (!$this->phoneNumberUtil->isPossibleNumberForType($phone, PhoneNumberType::MOBILE)) { + throw new \UnexpectedValueException("Phone number si not a mobile"); + } + + return $phone; + }); + + $phone = $helper->ask($input, $output, $question); + + $messages = $this->messageForCalendarBuilder->buildMessageForCalendar($calendar); + + if (0 === count($messages)) { + $output->writeln('no message to send to this user'); + } + + foreach ($messages as $key => $message) { + $output->writeln("The short message for SMS ${key} will be: "); + $output->writeln($message->getContent()); + $message->setPhoneNumber($phone); + $this->messageSender->send($message); + } + + return 0; + } +} diff --git a/src/Bundle/ChillCalendarBundle/DependencyInjection/ChillCalendarExtension.php b/src/Bundle/ChillCalendarBundle/DependencyInjection/ChillCalendarExtension.php index 3246814e6..9d556e6d8 100644 --- a/src/Bundle/ChillCalendarBundle/DependencyInjection/ChillCalendarExtension.php +++ b/src/Bundle/ChillCalendarBundle/DependencyInjection/ChillCalendarExtension.php @@ -39,6 +39,12 @@ class ChillCalendarExtension extends Extension implements PrependExtensionInterf $loader->load('services/remote_calendar.yaml'); $container->setParameter('chill_calendar', $config); + + if ($config['short_messages']['enabled']) { + $container->setParameter('chill_calendar.short_messages', $config['short_messages']); + } else { + $container->setParameter('chill_calendar.short_messages', null); + } } public function prepend(ContainerBuilder $container) diff --git a/src/Bundle/ChillCalendarBundle/DependencyInjection/Configuration.php b/src/Bundle/ChillCalendarBundle/DependencyInjection/Configuration.php index bb3ab576d..8f8a18b97 100644 --- a/src/Bundle/ChillCalendarBundle/DependencyInjection/Configuration.php +++ b/src/Bundle/ChillCalendarBundle/DependencyInjection/Configuration.php @@ -26,7 +26,12 @@ class Configuration implements ConfigurationInterface $treeBuilder = new TreeBuilder('chill_calendar'); $rootNode = $treeBuilder->getRootNode('chill_calendar'); - $rootNode->children() + $rootNode + ->children() + ->arrayNode('short_messages') + ->canBeDisabled() + ->children()->end() + ->end() // end for short_messages ->arrayNode('remote_calendars_sync')->canBeEnabled() ->children() ->arrayNode('microsoft_graph')->canBeEnabled() diff --git a/src/Bundle/ChillCalendarBundle/Entity/Calendar.php b/src/Bundle/ChillCalendarBundle/Entity/Calendar.php index 25486459f..ebfb48dc5 100644 --- a/src/Bundle/ChillCalendarBundle/Entity/Calendar.php +++ b/src/Bundle/ChillCalendarBundle/Entity/Calendar.php @@ -52,6 +52,12 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface use TrackUpdateTrait; + public const SMS_CANCEL_PENDING = 'sms_cancel_pending'; + + public const SMS_PENDING = 'sms_pending'; + + public const SMS_SENT = 'sms_sent'; + public const STATUS_CANCELED = 'canceled'; public const STATUS_MOVED = 'moved'; @@ -169,7 +175,12 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface /** * @ORM\Column(type="boolean", nullable=true) */ - private ?bool $sendSMS; + private ?bool $sendSMS = null; + + /** + * @ORM\Column(type="text", nullable=false, options={"default": Calendar::SMS_PENDING}) + */ + private string $smsStatus = self::SMS_PENDING; /** * @ORM\Column(type="datetime_immutable", nullable=false) @@ -368,6 +379,11 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface return $this->sendSMS; } + public function getSmsStatus(): string + { + return $this->smsStatus; + } + public function getStartDate(): ?DateTimeImmutable { return $this->startDate; @@ -551,6 +567,11 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface return $this; } + public function setSmsStatus(string $smsStatus): void + { + $this->smsStatus = $smsStatus; + } + public function setStartDate(DateTimeImmutable $startDate): self { $this->startDate = $startDate; @@ -562,6 +583,10 @@ class Calendar implements TrackCreationInterface, TrackUpdateInterface { $this->status = $status; + if (self::STATUS_CANCELED === $status && $this->getSmsStatus() === self::SMS_SENT) { + $this->setSmsStatus(self::SMS_CANCEL_PENDING); + } + return $this; } } diff --git a/src/Bundle/ChillCalendarBundle/Repository/CalendarRepository.php b/src/Bundle/ChillCalendarBundle/Repository/CalendarRepository.php index 74d8c8ddb..937c18d05 100644 --- a/src/Bundle/ChillCalendarBundle/Repository/CalendarRepository.php +++ b/src/Bundle/ChillCalendarBundle/Repository/CalendarRepository.php @@ -13,8 +13,10 @@ namespace Chill\CalendarBundle\Repository; use Chill\CalendarBundle\Entity\Calendar; use Chill\PersonBundle\Entity\AccompanyingPeriod; +use DateTimeImmutable; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\EntityRepository; +use Doctrine\ORM\QueryBuilder; use Doctrine\Persistence\ObjectRepository; class CalendarRepository implements ObjectRepository @@ -67,6 +69,21 @@ class CalendarRepository implements ObjectRepository ); } + public function findByNotificationAvailable(DateTimeImmutable $startDate, DateTimeImmutable $endDate, ?int $limit = null, ?int $offset = null): array + { + $qb = $this->queryByNotificationAvailable($startDate, $endDate)->select('c'); + + if (null !== $limit) { + $qb->setMaxResults($limit); + } + + if (null !== $offset) { + $qb->setFirstResult($offset); + } + + return $qb->getQuery()->getResult(); + } + public function findOneBy(array $criteria): ?Calendar { return $this->repository->findOneBy($criteria); @@ -76,4 +93,26 @@ class CalendarRepository implements ObjectRepository { return Calendar::class; } + + private function queryByNotificationAvailable(DateTimeImmutable $startDate, DateTimeImmutable $endDate): QueryBuilder + { + $qb = $this->repository->createQueryBuilder('c'); + + $qb->where( + $qb->expr()->andX( + $qb->expr()->eq('c.sendSMS', "'TRUE'"), + $qb->expr()->gte('c.startDate', ':startDate'), + $qb->expr()->lt('c.startDate', ':endDate'), + $qb->expr()->in('c.smsStatus', ':statuses') + ) + ); + + $qb->setParameters([ + 'startDate' => $startDate, + 'endDate' => $endDate, + 'statuses' => [Calendar::SMS_PENDING, Calendar::SMS_CANCEL_PENDING], + ]); + + return $qb; + } } diff --git a/src/Bundle/ChillCalendarBundle/Resources/config/services.yml b/src/Bundle/ChillCalendarBundle/Resources/config/services.yml index 125db767a..7e316acf3 100644 --- a/src/Bundle/ChillCalendarBundle/Resources/config/services.yml +++ b/src/Bundle/ChillCalendarBundle/Resources/config/services.yml @@ -33,3 +33,11 @@ services: autoconfigure: true autowire: true resource: '../../Security/' + + Chill\CalendarBundle\Service\: + autoconfigure: true + autowire: true + resource: '../../Service/' + + Chill\CalendarBundle\Service\ShortMessageForCalendarBuilderInterface: + alias: Chill\CalendarBundle\Service\DefaultShortMessageForCalendarBuider diff --git a/src/Bundle/ChillCalendarBundle/Resources/views/CalendarShortMessage/short_message.txt.twig b/src/Bundle/ChillCalendarBundle/Resources/views/CalendarShortMessage/short_message.txt.twig new file mode 100644 index 000000000..1e5a0794b --- /dev/null +++ b/src/Bundle/ChillCalendarBundle/Resources/views/CalendarShortMessage/short_message.txt.twig @@ -0,0 +1 @@ +Votre travailleur social {{ calendar.mainUser.label }} vous rencontrera le {{ calendar.startDate|format_date('short') }} à {{ calendar.startDate|format_time('medium') }} - LIEU. {% if calendar.location is not null and calendar.location.phonenumber is not null %}En cas d’indisponibilité rappelez-nous au {{ calendar.location.phonenumber|chill_format_phonenumber }}.{% endif %} diff --git a/src/Bundle/ChillCalendarBundle/Service/ShortMessageNotification/DefaultShortMessageForCalendarBuilder.php b/src/Bundle/ChillCalendarBundle/Service/ShortMessageNotification/DefaultShortMessageForCalendarBuilder.php new file mode 100644 index 000000000..71c51640e --- /dev/null +++ b/src/Bundle/ChillCalendarBundle/Service/ShortMessageNotification/DefaultShortMessageForCalendarBuilder.php @@ -0,0 +1,46 @@ +config = $parameterBag->get('chill_calendar.short_messages'); + $this->engine = $engine; + } + + public function buildMessageForCalendar(Calendar $calendar): array + { + if (null === $this->config || true !== $calendar->getSendSMS()) { + return []; + } + + $toUsers = []; + + foreach ($calendar->getPersons() as $person) { + if (false === $person->getAcceptSMS() || null === $person->getAcceptSMS() || null === $person->getMobilenumber()) { + continue; + } + + $toUsers[] = new \Chill\MainBundle\Service\ShortMessage\ShortMessage( + $this->engine->render('@ChillCalendar/CalendarShortMessage/short_message.txt.twig', ['calendar' => $calendar]), + $person->getMobilenumber() + ); + } + + return $toUsers; + } +} diff --git a/src/Bundle/ChillCalendarBundle/Service/ShortMessageNotification/ShortMessageForCalendarBuilderInterface.php b/src/Bundle/ChillCalendarBundle/Service/ShortMessageNotification/ShortMessageForCalendarBuilderInterface.php new file mode 100644 index 000000000..327bb89b0 --- /dev/null +++ b/src/Bundle/ChillCalendarBundle/Service/ShortMessageNotification/ShortMessageForCalendarBuilderInterface.php @@ -0,0 +1,15 @@ +load('services/search.yaml'); $loader->load('services/serializer.yaml'); $loader->load('services/mailer.yaml'); + $loader->load('services/short_message.yaml'); $this->configureCruds($container, $config['cruds'], $config['apis'], $loader); } diff --git a/src/Bundle/ChillMainBundle/Service/ShortMessage/NullShortMessageSender.php b/src/Bundle/ChillMainBundle/Service/ShortMessage/NullShortMessageSender.php new file mode 100644 index 000000000..9e52766e3 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Service/ShortMessage/NullShortMessageSender.php @@ -0,0 +1,10 @@ +content = $content; + $this->phoneNumber = $phoneNumber; + } + + public function getContent(): string + { + return $this->content; + } + + public function getPhoneNumber(): PhoneNumber + { + return $this->phoneNumber; + } + + /** + * @param string $content + */ + public function setContent(string $content): void + { + $this->content = $content; + } + + /** + * @param PhoneNumber $phoneNumber + */ + public function setPhoneNumber(PhoneNumber $phoneNumber): void + { + $this->phoneNumber = $phoneNumber; + } + + +} diff --git a/src/Bundle/ChillMainBundle/Service/ShortMessage/ShortMessageSenderInterface.php b/src/Bundle/ChillMainBundle/Service/ShortMessage/ShortMessageSenderInterface.php new file mode 100644 index 000000000..91d534a83 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Service/ShortMessage/ShortMessageSenderInterface.php @@ -0,0 +1,8 @@ +