Passed
Push — master ( 330c05...96a327 )
by
unknown
14:46 queued 07:14
created

SendEventRemindersCommand::sendReminderMessage()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 10
c 1
b 0
f 0
nc 2
nop 6
dl 0
loc 17
rs 9.9332
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
declare(strict_types=1);
6
7
namespace Chamilo\CoreBundle\Command;
8
9
use Chamilo\CoreBundle\Entity\AgendaReminder;
10
use Chamilo\CoreBundle\Entity\Session;
11
use Chamilo\CoreBundle\Entity\User;
12
use Chamilo\CoreBundle\Repository\Node\CourseRepository;
13
use Chamilo\CoreBundle\ServiceHelper\MessageHelper;
14
use Chamilo\CoreBundle\Settings\SettingsManager;
15
use Chamilo\CourseBundle\Entity\CCalendarEvent;
16
use DateTime;
17
use DateTimeZone;
18
use Doctrine\ORM\EntityManagerInterface;
19
use Symfony\Component\Console\Command\Command;
20
use Symfony\Component\Console\Input\InputInterface;
21
use Symfony\Component\Console\Input\InputOption;
22
use Symfony\Component\Console\Output\OutputInterface;
23
use Symfony\Component\Console\Style\SymfonyStyle;
24
use Symfony\Contracts\Translation\TranslatorInterface;
25
26
use const PHP_EOL;
27
28
class SendEventRemindersCommand extends Command
29
{
30
    /**
31
     * @var string
32
     */
33
    protected static $defaultName = 'app:send-event-reminders';
34
35
    public function __construct(
36
        private readonly EntityManagerInterface $entityManager,
37
        private readonly SettingsManager $settingsManager,
38
        private readonly CourseRepository $courseRepository,
39
        private readonly TranslatorInterface $translator,
40
        private readonly MessageHelper $messageHelper
41
    ) {
42
        parent::__construct();
43
    }
44
45
    protected function configure(): void
46
    {
47
        $this
48
            ->setDescription('Send notification messages to users that have reminders from events in their agenda.')
49
            ->addOption('debug', null, InputOption::VALUE_NONE, 'Enable debug mode')
50
            ->setHelp('This command sends notifications to users who have pending reminders for calendar events.');
51
    }
52
53
    protected function execute(InputInterface $input, OutputInterface $output): int
54
    {
55
        $io = new SymfonyStyle($input, $output);
56
        $debug = $input->getOption('debug');
57
        $now = new DateTime('now', new DateTimeZone('UTC'));
58
        $initialSentRemindersCount = 0;
59
        $sentRemindersCount = 0;
60
61
        if ($debug) {
62
            error_log('Debug mode activated');
63
            $io->note('Debug mode activated');
64
        }
65
66
        $remindersRepo = $this->entityManager->getRepository(AgendaReminder::class);
67
        $reminders = $remindersRepo->findBy(['sent' => false]);
68
69
        if ($debug) {
70
            error_log('Total reminders fetched: '.\count($reminders));
71
        }
72
73
        $senderId = $this->settingsManager->getSetting('agenda.agenda_reminders_sender_id');
74
        $senderId = (int) $senderId ?: $this->getFirstAdminId();
75
76
        foreach ($reminders as $reminder) {
77
            /** @var CCalendarEvent $event */
78
            $event = $reminder->getEvent();
79
80
            if (null === $event) {
81
                if ($debug) {
82
                    error_log('No event found for reminder ID: '.$reminder->getId());
83
                }
84
85
                continue;
86
            }
87
88
            $eventType = $event->determineType();
89
            $notificationDate = clone $event->getStartDate();
90
            $notificationDate->sub($reminder->getDateInterval());
91
            if ($notificationDate > $now) {
92
                continue;
93
            }
94
95
            $eventDetails = $this->generateEventDetails($event);
96
97
            $initialSentRemindersCount = $sentRemindersCount;
98
99
            if ('personal' === $eventType) {
100
                $creator = $event->getResourceNode()->getCreator();
101
                if ($creator) {
102
                    $this->sendReminderMessage($creator, $event, $senderId, $debug, $io, $sentRemindersCount);
103
                }
104
105
                $resourceLinks = $event->getResourceNode()->getResourceLinks();
106
                if (!$resourceLinks->isEmpty()) {
107
                    foreach ($resourceLinks as $link) {
108
                        if ($user = $link->getUser()) {
109
                            $this->sendReminderMessage($user, $event, $senderId, $debug, $io, $sentRemindersCount);
110
                        }
111
                    }
112
                }
113
            } else {
114
                $resourceLink = $event->getResourceNode()->getResourceLinks()->first();
115
                if (!$resourceLink) {
116
                    if ($debug) {
117
                        error_log("No ResourceLink found for event ID: {$event->getIid()}");
118
                    }
119
120
                    continue;
121
                }
122
123
                switch ($eventType) {
124
                    case 'global':
125
                        foreach ($event->getResourceNode()->getResourceLinks() as $link) {
126
                            if ($user = $link->getUser()) {
127
                                $this->sendReminderMessage($user, $event, $senderId, $debug, $io, $sentRemindersCount);
128
                            }
129
                        }
130
                        break;
131
132
                    case 'course':
133
                        if ($course = $resourceLink->getCourse()) {
134
                            $users = $this->courseRepository->getSubscribedUsers($course)->getQuery()->getResult();
135
                            foreach ($users as $user) {
136
                                $this->sendReminderMessage($user, $event, $senderId, $debug, $io, $sentRemindersCount);
137
                            }
138
                        }
139
140
                        break;
141
142
                    case 'session':
143
                        if ($session = $resourceLink->getSession()) {
144
                            $course = $resourceLink->getCourse();
145
                            if (!$course) {
146
                                if ($debug) {
147
                                    error_log("No course found for resource link in session ID: {$session->getId()}");
148
                                }
149
                                break;
150
                            }
151
152
                            $usersToNotify = [];
153
                            $studentSubscriptions = $session->getSessionRelCourseRelUsersByStatus($course, Session::STUDENT);
154
                            foreach ($studentSubscriptions as $studentSubscription) {
155
                                $usersToNotify[$studentSubscription->getUser()->getId()] = $studentSubscription->getUser();
156
                            }
157
158
                            $coachSubscriptions = $session->getSessionRelCourseRelUsersByStatus($course, Session::COURSE_COACH);
159
                            foreach ($coachSubscriptions as $coachSubscription) {
160
                                $usersToNotify[$coachSubscription->getUser()->getId()] = $coachSubscription->getUser();
161
                            }
162
163
                            $generalCoaches = $session->getGeneralCoaches();
164
                            foreach ($generalCoaches as $generalCoach) {
165
                                $usersToNotify[$generalCoach->getId()] = $generalCoach;
166
                            }
167
168
                            foreach ($usersToNotify as $user) {
169
                                $this->sendReminderMessage($user, $event, $senderId, $debug, $io, $sentRemindersCount);
170
                            }
171
                        }
172
173
                        break;
174
                }
175
            }
176
177
            if ($sentRemindersCount > $initialSentRemindersCount) {
178
                $reminder->setSent(true);
179
                $this->entityManager->persist($reminder);
180
            }
181
        }
182
183
        $this->entityManager->flush();
184
185
        if ($sentRemindersCount > 0) {
186
            $io->success(\sprintf('%d event reminders have been sent successfully.', $sentRemindersCount));
187
        } else {
188
            $io->warning('No event reminders were sent.');
189
        }
190
191
        return Command::SUCCESS;
192
    }
193
194
    private function sendReminderMessage(User $user, CCalendarEvent $event, int $senderId, bool $debug, SymfonyStyle $io, int &$sentRemindersCount): void
195
    {
196
        $locale = $user->getLocale() ?: 'en';
197
        $this->translator->setLocale($locale);
198
199
        $messageSubject = $this->translator->trans('Reminder for event : %s', ['%s' => $event->getTitle()]);
200
        $messageContent = implode(PHP_EOL, $this->generateEventDetails($event));
201
202
        $this->messageHelper->sendMessageSimple($user->getId(), $messageSubject, $messageContent, $senderId);
203
204
        if ($debug) {
205
            error_log("Message sent to user ID: {$user->getId()} for event: {$event->getTitle()}");
206
            error_log("Message Subject: {$messageSubject}");
207
            error_log("Message Content: {$messageContent}");
208
        }
209
210
        $sentRemindersCount++;
211
    }
212
213
    private function getFirstAdminId(): int
214
    {
215
        $admin = $this->entityManager->getRepository(User::class)->findOneBy([]);
216
217
        return $admin && ($admin->hasRole('ROLE_ADMIN') || $admin->hasRole('ROLE_SUPER_ADMIN'))
218
            ? $admin->getId()
219
            : 1;
220
    }
221
222
    private function generateEventDetails(CCalendarEvent $event): array
223
    {
224
        $details = [];
225
        $details[] = \sprintf('<p><strong>%s</strong></p>', $event->getTitle());
226
227
        if ($event->isAllDay()) {
228
            $details[] = \sprintf('<p class="small">%s</p>', $this->translator->trans('All Day'));
229
        } else {
230
            $details[] = \sprintf(
231
                '<p class="small">%s</p>',
232
                $this->translator->trans('From %s', ['%s' => $event->getStartDate()->format('Y-m-d H:i:s')])
233
            );
234
235
            if ($event->getEndDate()) {
236
                $details[] = \sprintf(
237
                    '<p class="small">%s</p>',
238
                    $this->translator->trans('Until %s', ['%s' => $event->getEndDate()->format('Y-m-d H:i:s')])
239
                );
240
            }
241
        }
242
243
        if ($event->getContent()) {
244
            $cleanContent = strip_tags($event->getContent());
245
            $details[] = \sprintf('<p>%s</p>', $cleanContent);
246
        }
247
248
        return $details;
249
    }
250
}
251