Passed
Push — dependabot/npm_and_yarn/microm... ( e84ba6...f2f212 )
by
unknown
10:03
created

MessageHelper::getGroupById()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CoreBundle\ServiceHelper;
8
9
use Chamilo\CoreBundle\Entity\Message;
10
use Chamilo\CoreBundle\Entity\MessageAttachment;
11
use Chamilo\CoreBundle\Entity\MessageRelUser;
12
use Chamilo\CoreBundle\Entity\User;
13
use Chamilo\CoreBundle\Entity\Usergroup;
14
use Chamilo\CoreBundle\Repository\MessageRepository;
15
use Chamilo\CoreBundle\Repository\Node\UserRepository;
16
use Chamilo\CoreBundle\Settings\SettingsManager;
17
use Doctrine\ORM\EntityManagerInterface;
18
use Symfony\Component\HttpFoundation\File\UploadedFile;
19
use Symfony\Component\HttpFoundation\RequestStack;
20
use Symfony\Component\Mailer\MailerInterface;
21
use Symfony\Component\Mime\Email;
22
23
class MessageHelper
24
{
25
    private $session;
26
27
    public function __construct(
28
        private readonly EntityManagerInterface $entityManager,
29
        private readonly MessageRepository      $messageRepository,
30
        private readonly UserRepository         $userRepository,
31
        private readonly RequestStack           $requestStack,
32
        private readonly AccessUrlHelper        $accessUrlHelper,
33
        private readonly SettingsManager        $settingsManager,
34
        private readonly MailerInterface        $mailer
35
    ) {
36
        if (php_sapi_name() !== 'cli') {
37
            $this->session = $this->requestStack->getSession();
38
        }
39
    }
40
41
    /**
42
     * Sends a simple message with optional attachments and notifications to HR users.
43
     */
44
    public function sendMessageSimple(
45
        int $receiverUserId,
46
        string $subject,
47
        string $message,
48
        int $senderId = 0,
49
        bool $sendCopyToDrhUsers = false,
50
        bool $uploadFiles = true,
51
        array $attachmentList = []
52
    ): ?int {
53
        $files = $_FILES ? $_FILES : [];
54
        if (false === $uploadFiles) {
55
            $files = [];
56
        }
57
58
        if (!empty($attachmentList)) {
59
            $files = $attachmentList;
60
        }
61
62
        $result = $this->sendMessage(
63
            $receiverUserId,
64
            $subject,
65
            $message,
66
            $files,
67
            [],
68
            0,
69
            0,
70
            0,
71
            $senderId
72
        );
73
74
        if ($sendCopyToDrhUsers) {
75
            $accessUrl = $this->accessUrlHelper->getCurrent();
76
            if ($accessUrl !== null) {
77
                $drhList = $this->userRepository->getDrhListFromUser($receiverUserId, $accessUrl->getId());
78
                if (!empty($drhList)) {
79
                    $receiverInfo = $this->userRepository->find($receiverUserId);
80
81
                    foreach ($drhList as $drhUser) {
82
                        $drhMessage = sprintf(
83
                                'Copy of message sent to %s',
84
                                $receiverInfo->getFirstname() . ' ' . $receiverInfo->getLastname()
85
                            ) . ' <br />' . $message;
86
87
                        $this->sendMessageSimple(
88
                            $drhUser->getId(),
89
                            $subject,
90
                            $drhMessage,
91
                            $senderId
92
                        );
93
                    }
94
                }
95
            }
96
        }
97
98
        return $result;
99
    }
100
101
    /**
102
     * Sends a message with attachments, forwards, and additional settings.
103
     */
104
    public function sendMessage(
105
        int $receiverUserId,
106
        string $subject,
107
        string $content,
108
        array $attachments = [],
109
        array $fileCommentList = [],
110
        int $groupId = 0,
111
        int $parentId = 0,
112
        int $editMessageId = 0,
113
        int $senderId = 0,
114
        int $forwardId = 0,
115
        bool $checkCurrentAudioId = false,
116
        bool $forceTitleWhenSendingEmail = false,
117
        ?int $msgType = null
118
    ): ?int {
119
120
        $sender = $this->userRepository->find($senderId);
121
        $receiver = $this->userRepository->find($receiverUserId);
122
123
        if (!$sender || !$receiver || !$receiver->isActive()) {
124
            return null;
125
        }
126
127
        $totalFileSize = 0;
128
        $attachmentList = $this->processAttachments($attachments, $fileCommentList, $totalFileSize);
129
130
        if ($totalFileSize > (int)  $this->settingsManager->getSetting('message.message_max_upload_filesize')) {
131
            throw new \Exception('Files size exceeds allowed limit.');
132
        }
133
134
        $parent = $this->messageRepository->find($parentId);
135
136
        if ($editMessageId) {
137
            $message = $this->messageRepository->find($editMessageId);
138
            if ($message) {
139
                $message->setTitle($subject);
140
                $message->setContent($content);
141
            }
142
        } else {
143
            $message = new Message();
144
            $message->setSender($sender)
145
                ->addReceiverTo($receiver)
146
                ->setTitle($subject)
147
                ->setContent($content)
148
                ->setGroup($groupId ? $this->getGroupById($groupId) : null)
149
                ->setParent($parent);
150
151
            if ($msgType !== null) {
152
                $message->setMsgType($msgType);
153
            }
154
        }
155
156
        $this->entityManager->persist($message);
157
        $this->entityManager->flush();
158
159
        if ($forwardId) {
160
            $this->forwardAttachments($forwardId, $message);
161
        }
162
163
        if ($checkCurrentAudioId) {
164
            $this->attachAudioMessage($message);
165
        }
166
167
        $this->saveAttachments($attachmentList, $message);
168
169
        $this->addSenderAsReceiver($message, $sender);
170
171
        if ($forceTitleWhenSendingEmail) {
172
            $this->sendEmailNotification($receiver, $sender, $subject, $content, $attachmentList);
173
        }
174
175
        return $message->getId();
176
    }
177
178
    /**
179
     * Processes attachments, calculates total file size, and returns the attachment list.
180
     */
181
    private function processAttachments(array $attachments, array $fileCommentList, &$totalFileSize): array
182
    {
183
        $attachmentList = [];
184
        foreach ($attachments as $index => $attachment) {
185
            $comment = $fileCommentList[$index] ?? '';
186
            $size = $attachment['size'] ?? 0;
187
188
            if (is_array($size)) {
189
                foreach ($size as $s) {
190
                    $totalFileSize += $s;
191
                }
192
            } else {
193
                $totalFileSize += $size;
194
            }
195
196
            $attachmentList[] = [
197
                'file' => $attachment,
198
                'comment' => $comment,
199
            ];
200
        }
201
        return $attachmentList;
202
    }
203
204
    /**
205
     * Forwards attachments from one message to another.
206
     */
207
    private function forwardAttachments(int $forwardId, Message $message): void
208
    {
209
        $forwardMessage = $this->messageRepository->find($forwardId);
210
        if ($forwardMessage) {
211
            foreach ($forwardMessage->getAttachments() as $attachment) {
212
                $message->addAttachment($attachment);
213
            }
214
            $this->entityManager->persist($message);
215
            $this->entityManager->flush();
216
        }
217
    }
218
219
    /**
220
     * Attaches an audio message from the current session to the message.
221
     */
222
    private function attachAudioMessage(Message $message): void
223
    {
224
        if ($this->session && $this->session->has('current_audio')) {
225
            $audio = $this->session->get('current_audio');
226
227
            if (!empty($audio['name'])) {
228
                $attachment = new MessageAttachment();
229
                $attachment->setFilename($audio['name'])
230
                    ->setComment('audio_message')
231
                    ->setMessage($message);
232
233
                $message->addAttachment($attachment);
234
235
                $this->entityManager->persist($attachment);
236
                $this->entityManager->flush();
237
            }
238
        }
239
    }
240
241
    /**
242
     * Saves the provided attachments and links them to the message.
243
     */
244
    private function saveAttachments(array $attachments, Message $message): void
245
    {
246
        foreach ($attachments as $attachment) {
247
            $file = $attachment['file'];
248
            $comment = $attachment['comment'] ?? '';
249
250
            if ($file instanceof UploadedFile && $file->getError() === UPLOAD_ERR_OK) {
251
                $attachmentEntity = new MessageAttachment();
252
                $attachmentEntity->setFilename($file->getClientOriginalName())
253
                    ->setSize($file->getSize())
254
                    ->setPath($file->getRealPath())
255
                    ->setMessage($message)
256
                    ->setComment($comment);
257
258
                $message->addAttachment($attachmentEntity);
259
                $this->entityManager->persist($attachmentEntity);
260
            }
261
        }
262
        $this->entityManager->flush();
263
    }
264
265
    /**
266
     * Adds the sender as a receiver in the message to keep track of the sent message.
267
     */
268
    private function addSenderAsReceiver(Message $message, User $sender): void
269
    {
270
        $messageRelUserRepository = $this->entityManager->getRepository(MessageRelUser::class);
271
        $existingRelation = $messageRelUserRepository->findOneBy([
272
            'message' => $message,
273
            'receiver' => $sender,
274
            'receiverType' => MessageRelUser::TYPE_SENDER
275
        ]);
276
277
        if (!$existingRelation) {
278
            $messageRelUserSender = new MessageRelUser();
279
            $messageRelUserSender->setMessage($message)
280
                ->setReceiver($sender)
281
                ->setReceiverType(MessageRelUser::TYPE_SENDER);
282
            $this->entityManager->persist($messageRelUserSender);
283
            $this->entityManager->flush();
284
        }
285
    }
286
287
    private function sendEmailNotification(User $receiver, User $sender, string $subject, string $content, array $attachmentList): void
288
    {
289
        if (empty($receiver->getEmail())) {
290
            throw new \Exception('The receiver does not have a valid email address.');
291
        }
292
293
        $email = (new Email())
294
            ->from($sender->getEmail())
295
            ->to($receiver->getEmail())
296
            ->subject($subject)
297
            ->text($content)
298
            ->html($content);
299
300
        foreach ($attachmentList as $attachment) {
301
            if ($attachment instanceof UploadedFile) {
302
                $email->attachFromPath($attachment->getRealPath(), $attachment->getClientOriginalName());
303
            }
304
        }
305
306
        try {
307
            $this->mailer->send($email);
308
        } catch (\Exception $e) {
309
            error_log('Failed to send email: ' . $e->getMessage());
310
        }
311
    }
312
    /**
313
     * Retrieves a user group by its ID.
314
     */
315
    private function getGroupById(int $groupId)
316
    {
317
        return $this->entityManager->getRepository(Usergroup::class)->find($groupId);
318
    }
319
}
320