MessageManager   F
last analyzed

Complexity

Total Complexity 205

Size/Duplication

Total Lines 1799
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 1003
dl 0
loc 1799
rs 1.588
c 0
b 0
f 0
wmc 205

30 Methods

Rating   Name   Duplication   Size   Complexity  
B getMessagesByParent() 0 38 7
A get_messages_by_group() 0 23 4
A get_messages_by_group_by_message() 0 28 6
A messageWasAlreadySent() 0 20 1
B getMessagesAboutUserToString() 0 49 6
A generate_message_form() 0 16 1
B getMessageGrid() 0 46 6
A calculate_children() 0 13 2
A generate_invitation_form() 0 10 1
A getSearchForm() 0 22 1
A sendNotificationOfNewRegisteredUser() 0 37 2
A cleanAudioMessage() 0 3 1
B failedSentMailErrors() 0 53 11
F send_message() 0 315 55
A get_message_by_id() 0 18 2
A getAllMessagesBetweenStudents() 0 25 4
C display_messages_for_group() 0 120 14
B send_message_simple() 0 62 7
A countLikesAndDislikes() 0 16 4
A sendMessageToAllUsersInCourse() 0 27 5
C saveMessageAttachmentFile() 0 75 13
A getAttachmentLinkList() 0 25 4
A sendMessageToAllAdminUsers() 0 8 2
A isUserOwner() 0 11 2
A processRelativeLinks() 0 8 1
A getLikesButton() 0 42 5
F display_message_for_group() 0 314 23
B sendNotificationOfNewRegisteredUserApproval() 0 69 6
A getUsersThatHadConversationWithUser() 0 25 4
A message_recursive_sort() 0 15 5

How to fix   Complexity   

Complex Class

Complex classes like MessageManager often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use MessageManager, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\Course;
6
use Chamilo\CoreBundle\Entity\Message;
7
use Chamilo\CoreBundle\Entity\MessageAttachment;
8
use Chamilo\CoreBundle\Entity\MessageRelUser;
9
use Chamilo\CoreBundle\Entity\SocialPost;
10
use Chamilo\CoreBundle\Entity\SocialPostFeedback;
11
use Chamilo\CoreBundle\Entity\User;
12
use Chamilo\CoreBundle\Framework\Container;
13
use ChamiloSession as Session;
14
use Doctrine\Common\Collections\Criteria;
15
use Symfony\Component\HttpFoundation\File\UploadedFile;
16
17
class MessageManager
18
{
19
    public static function getMessagesAboutUserToString(User $user, string $url = ''): string
20
    {
21
        $currentUserId = api_get_user_id();
22
        $messages = Container::getMessageRepository()->getMessageByUser($user, Message::MESSAGE_TYPE_CONVERSATION);
23
        $html = '';
24
        if (!empty($messages)) {
25
            foreach ($messages as $message) {
26
                $messageId = $message->getId();
27
                $tag = 'message_'.$messageId;
28
                $tagAccordion = 'accordion_'.$messageId;
29
                $tagCollapse = 'collapse_'.$messageId;
30
31
                $date = Display::dateToStringAgoAndLongDate($message->getSendDate());
32
                $localTime = api_get_local_time(
33
                    $message->getSendDate(),
34
                    null,
35
                    null,
36
                    false,
37
                    false
38
                );
39
                $sender = $message->getSender();
40
41
                $deleteLink = '';
42
                if (!empty($url) && $sender && $currentUserId === $sender->getId()) {
43
                    $deleteLink = '<button title="'.addslashes(get_lang('Delete message')).'"
44
                       onclick="event.stopPropagation(); if(confirm(\''.addslashes(api_htmlentities(get_lang('Are you sure you want to delete the selected message?'))).'\')) {
45
                       window.location.href=\''.$url.'&action=delete_message&message_id='.$messageId.'\';
46
                       } return false;"
47
                       class="ml-2 inline-flex items-center">'.
48
                        Display::returnPrimeIcon('trash', 'lg').'</button>';
49
                }
50
51
                $content = '<div class="custom-message">' . $message->getContent().'<br />'.$date.'<br />'.
52
                    get_lang('Author').': '.$sender->getUsername().
53
                    '<br /></div>';
54
55
                $html .= Display::panelCollapse(
56
                    $localTime.' '.UserManager::formatUserFullName($sender).' '.$message->getTitle().$deleteLink,
57
                    $content,
58
                    $tag,
59
                    null,
60
                    $tagAccordion,
61
                    $tagCollapse,
62
                    false
63
                );
64
            }
65
        }
66
67
        return $html;
68
    }
69
70
    /**
71
     * @param int    $senderId
72
     * @param int    $receiverId
73
     * @param string $subject
74
     * @param string $message
75
     *
76
     * @return bool
77
     */
78
    public static function messageWasAlreadySent($senderId, $receiverId, $subject, $message)
79
    {
80
        $tblMessage = Database::get_main_table(TABLE_MESSAGE);
81
        $senderId = (int) $senderId;
82
        $receiverId = (int) $receiverId;
83
        $subject = Database::escape_string($subject);
84
        $message = Database::escape_string($message);
85
86
        $sql = "SELECT m.id FROM $tblMessage m
87
                INNER JOIN message_rel_user mru on m.id = mru.message_id
88
                WHERE
89
                    m.user_sender_id = $senderId AND
90
                    mru.user_id = $receiverId AND
91
                    m.title = '$subject' AND
92
                    m.content = '$message' AND
93
                    m.msg_type = ".Message::MESSAGE_TYPE_INBOX."
94
                ";
95
        $result = Database::query($sql);
96
97
        return Database::num_rows($result) > 0;
98
    }
99
100
    /**
101
     * Sends a message to a user/group.
102
     *
103
     * @param int    $receiverUserId
104
     * @param string $subject
105
     * @param string $content
106
     * @param array  $attachments                files array($_FILES) (optional)
107
     * @param array  $fileCommentList            about attachment files (optional)
108
     * @param int    $group_id                   (optional)
109
     * @param int    $parent_id                  (optional)
110
     * @param int    $editMessageId              id for updating the message (optional)
111
     * @param int    $topic_id                   (optional) the default value is the current user_id
112
     * @param int    $sender_id
113
     * @param bool   $directMessage
114
     * @param int    $forwardId
115
     * @param bool   $checkCurrentAudioId
116
     * @param bool   $forceTitleWhenSendingEmail force the use of $title as subject instead of "You have a new message"
117
     *
118
     * @return bool
119
     */
120
    public static function send_message(
121
        $receiverUserId,
122
        $subject,
123
        $content,
124
        array $attachments = [],
125
        array $fileCommentList = [],
126
        $group_id = 0,
127
        $parent_id = 0,
128
        $editMessageId = 0,
129
        $topic_id = 0,
130
        $sender_id = 0,
131
        $directMessage = false,
132
        $forwardId = 0,
133
        $checkCurrentAudioId = false,
134
        $forceTitleWhenSendingEmail = false,
135
        $msgType = null,
136
        $baseUrl = null,
137
        $sendEmailNotification = true
138
    ) {
139
        $group_id = (int) $group_id;
140
        $receiverUserId = (int) $receiverUserId;
141
        $parent_id = (int) $parent_id;
142
        $editMessageId = (int) $editMessageId;
143
        $topic_id = (int) $topic_id;
144
        $user_sender_id = empty($sender_id) ? api_get_user_id() : (int) $sender_id;
145
146
        if (empty($user_sender_id) || empty($receiverUserId)) {
147
            return false;
148
        }
149
150
        $userSender = api_get_user_entity($user_sender_id);
151
        if (null === $userSender) {
152
            Display::addFlash(Display::return_message(get_lang('This user doesn\'t exist'), 'warning'));
153
154
            return false;
155
        }
156
157
        $userRecipient = api_get_user_entity($receiverUserId);
158
159
        if (null === $userRecipient) {
160
            return false;
161
        }
162
163
        // Disabling messages for inactive users.
164
        if (!$userRecipient->isActive()) {
165
            return false;
166
        }
167
168
        // Email notifications are enabled by default, but can be explicitly disabled (e.g., inbox copy after registration).
169
        $sendEmail = true;
170
        if (false === (bool) $sendEmailNotification) {
171
            $sendEmail = false;
172
        }
173
174
        // Disabling messages depending the pausetraining plugin (only relevant if email notifications are enabled).
175
        $allowPauseFormation =
176
            $sendEmail &&
177
            Container::getPluginHelper()->isPluginEnabled('PauseTraining') &&
178
            'true' === api_get_plugin_setting('PauseTraining', 'allow_users_to_edit_pause_formation');
179
180
        if ($allowPauseFormation) {
181
            $extraFieldValue = new ExtraFieldValue('user');
182
            $disableEmails = $extraFieldValue->get_values_by_handler_and_field_variable(
183
                $receiverUserId,
184
                'disable_emails'
185
            );
186
187
            // User doesn't want email notifications but chamilo inbox still available.
188
            if (!empty($disableEmails) &&
189
                isset($disableEmails['value']) && 1 === (int) $disableEmails['value']
190
            ) {
191
                $sendEmail = false;
192
            }
193
194
            if ($sendEmail) {
195
                // Check if user pause his formation.
196
                $pause = $extraFieldValue->get_values_by_handler_and_field_variable(
197
                    $receiverUserId,
198
                    'pause_formation'
199
                );
200
                if (!empty($pause) && isset($pause['value']) && 1 === (int) $pause['value']) {
201
                    $startDate = $extraFieldValue->get_values_by_handler_and_field_variable(
202
                        $receiverUserId,
203
                        'start_pause_date'
204
                    );
205
                    $endDate = $extraFieldValue->get_values_by_handler_and_field_variable(
206
                        $receiverUserId,
207
                        'end_pause_date'
208
                    );
209
210
                    if (!empty($startDate) && isset($startDate['value']) && !empty($startDate['value']) &&
211
                        !empty($endDate) && isset($endDate['value']) && !empty($endDate['value'])
212
                    ) {
213
                        $now = time();
214
                        $start = api_strtotime($startDate['value']);
215
                        $end = api_strtotime($endDate['value']);
216
217
                        if ($now > $start && $now < $end) {
218
                            $sendEmail = false;
219
                        }
220
                    }
221
                }
222
            }
223
        }
224
225
        $totalFileSize = 0;
226
        $attachmentList = [];
227
        if (is_array($attachments)) {
228
            $counter = 0;
229
            foreach ($attachments as $attachment) {
230
                $attachment['comment'] = $fileCommentList[$counter] ?? '';
231
                $fileSize = $attachment['size'] ?? 0;
232
                if (is_array($fileSize)) {
233
                    foreach ($fileSize as $size) {
234
                        $totalFileSize += $size;
235
                    }
236
                } else {
237
                    $totalFileSize += $fileSize;
238
                }
239
                $attachmentList[] = $attachment;
240
                $counter++;
241
            }
242
        }
243
244
        if ($checkCurrentAudioId) {
245
            // Add the audio file as an attachment
246
            $audio = Session::read('current_audio');
247
            if (!empty($audio) && isset($audio['name']) && !empty($audio['name'])) {
248
                $audio['comment'] = 'audio_message';
249
                // create attachment from audio message
250
                $attachmentList[] = $audio;
251
            }
252
        }
253
254
        // Validating fields
255
        if (empty($subject) && empty($group_id)) {
256
            Display::addFlash(
257
                Display::return_message(
258
                    get_lang('You should write a subject'),
259
                    'warning'
260
                )
261
            );
262
263
            return false;
264
        } elseif ($totalFileSize > (int) api_get_setting('message_max_upload_filesize')) {
265
            $warning = sprintf(
266
                get_lang('Files size exceeds'),
267
                format_file_size(api_get_setting('message_max_upload_filesize'))
268
            );
269
270
            Display::addFlash(Display::return_message($warning, 'warning'));
271
272
            return false;
273
        }
274
275
        $em = Database::getManager();
276
        $repo = $em->getRepository(Message::class);
277
        $parent = null;
278
        if (!empty($parent_id)) {
279
            $parent = $repo->find($parent_id);
280
        }
281
282
        // Just in case we replace the and \n and \n\r while saving in the DB
283
        if (!empty($receiverUserId) || !empty($group_id)) {
284
            // message for user friend
285
            //@todo it's possible to edit a message? yes, only for groups
286
            if (!empty($editMessageId)) {
287
                $message = $repo->find($editMessageId);
288
                if (null !== $message) {
289
                    $message->setTitle($subject);
290
                    $message->setContent($content);
291
                    $em->persist($message);
292
                    $em->flush();
293
                }
294
                $messageId = $editMessageId;
295
            } else {
296
                $group = Container::getUsergroupRepository()->find($group_id);
297
298
                $message = (new Message())
299
                    ->setSender($userSender)
300
                    ->addReceiverTo($userRecipient)
301
                    ->setTitle($subject)
302
                    ->setContent($content)
303
                    ->setGroup($group)
304
                    ->setParent($parent)
305
                ;
306
307
                if (isset($msgType)) {
308
                    $message->setMsgType($msgType);
309
                }
310
311
                $em->persist($message);
312
                $em->flush();
313
                $messageId = $message->getId();
314
            }
315
316
            // Forward also message attachments.
317
            if (!empty($forwardId)) {
318
                $forwardMessage = $repo->find($forwardId);
319
                if (null !== $forwardMessage) {
320
                    $forwardAttachments = $forwardMessage->getAttachments();
321
                    foreach ($forwardAttachments as $forwardAttachment) {
322
                        $message->addAttachment($forwardAttachment);
323
                    }
324
                    $em->persist($message);
325
                    $em->flush();
326
                }
327
            }
328
329
            // Save attachment file for inbox messages
330
            if (is_array($attachmentList)) {
331
                foreach ($attachmentList as $attachment) {
332
                    if (0 === ($attachment['error'] ?? 0)) {
333
                        self::saveMessageAttachmentFile(
334
                            $attachment,
335
                            $attachment['comment'] ?? '',
336
                            $message,
337
                        );
338
                    }
339
                }
340
            }
341
342
            // Add the sender as a receiver with TYPE_SENDER
343
            $messageRelUserRepository = $em->getRepository(MessageRelUser::class);
344
            $existingRelation = $messageRelUserRepository->findOneBy([
345
                'message' => $message,
346
                'receiver' => $userSender,
347
                'receiverType' => MessageRelUser::TYPE_SENDER
348
            ]);
349
350
            if (!$existingRelation) {
351
                $messageRelUserSender = new MessageRelUser();
352
                $messageRelUserSender->setMessage($message);
353
                $messageRelUserSender->setReceiver($userSender);
354
                $messageRelUserSender->setReceiverType(MessageRelUser::TYPE_SENDER);
355
                $em->persist($messageRelUserSender);
356
                $em->flush();
357
            }
358
359
            // Email notification (optional)
360
            if ($sendEmail) {
361
                $notification = new Notification();
362
                $sender_info = api_get_user_info($user_sender_id);
363
                $baseUrl = $baseUrl ?? api_get_path(WEB_PATH);
364
                $contentForEmail = self::processRelativeLinks($content, $baseUrl);
365
366
                // Add file attachment additional attributes
367
                $attachmentAddedByMail = [];
368
                foreach ($attachmentList as $attachment) {
369
                    $attachmentAddedByMail[] = [
370
                        'path' => $attachment['tmp_name'] ?? '',
371
                        'filename' => $attachment['name'] ?? '',
372
                    ];
373
                }
374
375
                if (empty($group_id)) {
376
                    $type = Notification::NOTIFICATION_TYPE_MESSAGE;
377
                    if ($directMessage) {
378
                        $type = Notification::NOTIFICATION_TYPE_DIRECT_MESSAGE;
379
                    }
380
                    $notification->saveNotification(
381
                        $messageId,
382
                        $type,
383
                        [$receiverUserId],
384
                        $subject,
385
                        $contentForEmail,
386
                        $sender_info,
387
                        $attachmentAddedByMail,
388
                        $forceTitleWhenSendingEmail,
389
                        $baseUrl
390
                    );
391
                } else {
392
                    $usergroup = new UserGroupModel();
393
                    $group_info = $usergroup->get($group_id);
394
                    $group_info['topic_id'] = $topic_id;
395
                    $group_info['msg_id'] = $messageId;
396
397
                    $user_list = $usergroup->get_users_by_group(
398
                        $group_id,
399
                        false,
400
                        [],
401
                        0,
402
                        1000
403
                    );
404
405
                    // Add more context for group message subject
406
                    $subjectGroup = sprintf(get_lang('There is a new message in group %s'), $group_info['title']);
407
                    $new_user_list = [];
408
                    foreach ($user_list as $user_data) {
409
                        $new_user_list[] = $user_data['id'];
410
                    }
411
412
                    $groupPayload = [
413
                        'group_info' => $group_info,
414
                        'user_info' => $sender_info,
415
                    ];
416
417
                    $notification->saveNotification(
418
                        $messageId,
419
                        Notification::NOTIFICATION_TYPE_GROUP,
420
                        $new_user_list,
421
                        $subjectGroup,
422
                        $contentForEmail,
423
                        $groupPayload,
424
                        $attachmentAddedByMail,
425
                        $forceTitleWhenSendingEmail,
426
                        $baseUrl
427
                    );
428
                }
429
            }
430
431
            return $messageId;
432
        }
433
434
        return false;
435
    }
436
437
    /**
438
     * Converts relative URLs in href and src attributes to absolute URLs.
439
     */
440
    private static function processRelativeLinks(string $content, string $baseUrl): string
441
    {
442
        return preg_replace_callback(
443
            '/(href|src)="(\/[^"]*)"/',
444
            function ($matches) use ($baseUrl) {
445
                return $matches[1] . '="' . rtrim($baseUrl, '/') . $matches[2] . '"';
446
            },
447
            $content
448
        );
449
    }
450
451
    /**
452
     * @param int    $receiverUserId
453
     * @param string $subject
454
     * @param string $message
455
     * @param int    $sender_id
456
     * @param bool   $sendCopyToDrhUsers send copy to related DRH users
457
     * @param bool   $directMessage
458
     * @param bool   $uploadFiles        Do not upload files using the MessageManager class
459
     * @param array  $attachmentList
460
     *
461
     * @return bool
462
     */
463
    public static function send_message_simple(
464
        $receiverUserId,
465
        $subject,
466
        $message,
467
        $sender_id = 0,
468
        $sendCopyToDrhUsers = false,
469
        $directMessage = false,
470
        $uploadFiles = true,
471
        $attachmentList = [],
472
        $sendEmailNotification = true
473
    ) {
474
        $files = $_FILES ? $_FILES : [];
475
        if (false === $uploadFiles) {
476
            $files = [];
477
        }
478
        // $attachmentList must have: tmp_name, name, size keys
479
        if (!empty($attachmentList)) {
480
            $files = $attachmentList;
481
        }
482
        $result = self::send_message(
483
            $receiverUserId,
484
            $subject,
485
            $message,
486
            $files,
487
            [],
488
            null,
489
            null,
490
            null,
491
            null,
492
            $sender_id,
493
            $directMessage,
494
            0,
495
            false,
496
            false,
497
            null,
498
            null,
499
            $sendEmailNotification
500
        );
501
502
        if ($sendCopyToDrhUsers) {
503
            $userInfo = api_get_user_info($receiverUserId);
504
            $drhList = UserManager::getDrhListFromUser($receiverUserId);
505
            if (!empty($drhList)) {
506
                foreach ($drhList as $drhInfo) {
507
                    $message = sprintf(
508
                            get_lang('Copy of message sent to %s'),
509
                            $userInfo['complete_name']
510
                        ).' <br />'.$message;
511
512
                    self::send_message_simple(
513
                        $drhInfo['id'],
514
                        $subject,
515
                        $message,
516
                        $sender_id,
517
                        false,
518
                        $directMessage
519
                    );
520
                }
521
            }
522
        }
523
524
        return $result;
525
    }
526
527
    /**
528
     * Saves a message attachment files.
529
     *
530
     * @param array  $file    $_FILES['name']
531
     * @param string $comment a comment about the uploaded file
532
     */
533
    public static function saveMessageAttachmentFile($file, $comment, Message $message)
534
    {
535
        // Try to add an extension to the file if it hasn't one
536
        $type = $file['type'] ?? '';
537
        if (empty($type)) {
538
            $type = DocumentManager::file_get_mime_type($file['name']);
539
        }
540
        $new_file_name = add_ext_on_mime(stripslashes($file['name']), $type);
541
542
        // user's file name
543
        $fileName = $file['name'];
544
        if (!filter_extension($new_file_name)) {
545
            Display::addFlash(
546
                Display::return_message(
547
                    get_lang('File upload failed: this file extension or file type is prohibited'),
548
                    'error'
549
                )
550
            );
551
552
            return false;
553
        }
554
555
        $em = Database::getManager();
556
        $attachmentRepo = Container::getMessageAttachmentRepository();
557
558
        $attachment = (new MessageAttachment())
559
            ->setSize($file['size'])
560
            ->setPath($fileName)
561
            ->setFilename($fileName)
562
            ->setComment($comment)
563
            ->setParent($message->getSender())
564
            ->setMessage($message)
565
        ;
566
567
        $request = Container::getRequest();
568
        $fileToUpload = null;
569
570
        // Search for files inside the $_FILES, when uploading several files from the form.
571
        if ($request->files->count()) {
572
            $allFiles = $request->files->all();
573
            $filesArray = array_key_exists('files', $allFiles) ? $allFiles['files'] : $allFiles;
574
            /** @var UploadedFile|null $fileRequest */
575
            foreach ($filesArray as $fileRequest) {
576
                if (null === $fileRequest) {
577
                    continue;
578
                }
579
                if ($fileRequest instanceof UploadedFile && $fileRequest->getClientOriginalName() === $file['name']) {
580
                    $fileToUpload = $fileRequest;
581
                    break;
582
                }
583
            }
584
        }
585
586
        // If no found file, try with $file['content'].
587
        if (null === $fileToUpload && isset($file['content'])) {
588
            $handle = tmpfile();
589
            fwrite($handle, $file['content']);
590
            $meta = stream_get_meta_data($handle);
591
            $fileToUpload = new UploadedFile($meta['uri'], $fileName, $file['type'], null, true);
592
        }
593
594
        if (null !== $fileToUpload) {
595
            $em->persist($attachment);
596
            $attachmentRepo->addFile($attachment, $fileToUpload);
597
            $attachment->addUserLink($message->getSender());
598
            $receivers = $message->getReceivers();
599
            foreach ($receivers as $receiver) {
600
                $attachment->addUserLink($receiver->getReceiver());
601
            }
602
            $em->flush();
603
604
            return true;
605
        }
606
607
        return false;
608
    }
609
610
    /**
611
     * get messages by group id.
612
     *
613
     * @param int $group_id group id
614
     *
615
     * @return array
616
     */
617
    public static function get_messages_by_group($group_id)
618
    {
619
        $group_id = (int) $group_id;
620
621
        if (empty($group_id)) {
622
            return false;
623
        }
624
625
        $table = Database::get_main_table(TABLE_MESSAGE);
626
        $sql = "SELECT * FROM $table
627
                WHERE
628
                    group_id= $group_id AND
629
                    msg_type = ".Message::MESSAGE_TYPE_GROUP."
630
                ORDER BY id";
631
        $rs = Database::query($sql);
632
        $data = [];
633
        if (Database::num_rows($rs) > 0) {
634
            while ($row = Database::fetch_assoc($rs)) {
635
                $data[] = $row;
636
            }
637
        }
638
639
        return $data;
640
    }
641
642
    /**
643
     * get messages by group id.
644
     *
645
     * @param int $group_id
646
     * @param int $message_id
647
     *
648
     * @return array
649
     */
650
    public static function get_messages_by_group_by_message($group_id, $message_id)
651
    {
652
        $group_id = (int) $group_id;
653
654
        if (empty($group_id)) {
655
            return false;
656
        }
657
658
        $table = Database::get_main_table(TABLE_MESSAGE);
659
        $sql = "SELECT * FROM $table
660
                WHERE
661
                    group_id = $group_id AND
662
                    msg_type = '".Message::MESSAGE_TYPE_GROUP."'
663
                ORDER BY id ";
664
665
        $rs = Database::query($sql);
666
        $data = [];
667
        $parents = [];
668
        if (Database::num_rows($rs) > 0) {
669
            while ($row = Database::fetch_assoc($rs)) {
670
                if ($message_id == $row['parent_id'] || in_array($row['parent_id'], $parents)) {
671
                    $parents[] = $row['id'];
672
                    $data[] = $row;
673
                }
674
            }
675
        }
676
677
        return $data;
678
    }
679
680
    /**
681
     * Get messages by parent id optionally with limit.
682
     *
683
     * @param  int        parent id
684
     * @param  int        group id (optional)
685
     * @param  int        offset (optional)
686
     * @param  int        limit (optional)
687
     *
688
     * @return array
689
     */
690
    public static function getMessagesByParent($parentId, $groupId = 0, $offset = 0, $limit = 0)
691
    {
692
        $table = Database::get_main_table(TABLE_MESSAGE);
693
        $parentId = (int) $parentId;
694
695
        if (empty($parentId)) {
696
            return [];
697
        }
698
699
        $condition_group_id = '';
700
        if (!empty($groupId)) {
701
            $groupId = (int) $groupId;
702
            $condition_group_id = " AND group_id = '$groupId' ";
703
        }
704
705
        $condition_limit = '';
706
        if ($offset && $limit) {
707
            $offset = (int) $offset;
708
            $limit = (int) $limit;
709
            $offset = ($offset - 1) * $limit;
710
            $condition_limit = " LIMIT $offset,$limit ";
711
        }
712
713
        $sql = "SELECT * FROM $table
714
                WHERE
715
                    parent_id='$parentId' AND
716
                    msg_type = '".Message::MESSAGE_TYPE_GROUP."'
717
                    $condition_group_id
718
                ORDER BY send_date DESC $condition_limit ";
719
        $rs = Database::query($sql);
720
        $data = [];
721
        if (Database::num_rows($rs) > 0) {
722
            while ($row = Database::fetch_array($rs)) {
723
                $data[$row['id']] = $row;
724
            }
725
        }
726
727
        return $data;
728
    }
729
730
    /**
731
     * Displays messages of a group with nested view.
732
     *
733
     * @param int $groupId
734
     *
735
     * @return string
736
     */
737
    public static function display_messages_for_group($groupId)
738
    {
739
        global $my_group_role;
740
741
        $rows = self::get_messages_by_group($groupId);
742
        $topics_per_page = 10;
743
        $html_messages = '';
744
        $query_vars = ['id' => $groupId, 'topics_page_nr' => 0];
745
746
        if (is_array($rows) && count($rows) > 0) {
747
            // prepare array for topics with its items
748
            $topics = [];
749
            $x = 0;
750
            foreach ($rows as $index => $value) {
751
                if (empty($value['parent_id'])) {
752
                    $topics[$value['id']] = $value;
753
                }
754
            }
755
756
            $new_topics = [];
757
758
            foreach ($topics as $id => $value) {
759
                $rows = self::get_messages_by_group_by_message($groupId, $value['id']);
760
                if (!empty($rows)) {
761
                    $count = count(self::calculate_children($rows, $value['id']));
762
                } else {
763
                    $count = 0;
764
                }
765
                $value['count'] = $count;
766
                $new_topics[$id] = $value;
767
            }
768
769
            $array_html = [];
770
            foreach ($new_topics as $index => $topic) {
771
                $html = '';
772
                // topics
773
                $user_sender_info = api_get_user_info($topic['user_sender_id']);
774
                $name = $user_sender_info['complete_name'];
775
                $html .= '<div class="groups-messages">';
776
                $html .= '<div class="row">';
777
778
                $items = $topic['count'];
779
                $reply_label = (1 == $items) ? get_lang('Reply') : get_lang('Replies');
780
                $label = '<i class="fa fa-envelope"></i> '.$items.' '.$reply_label;
781
                $topic['title'] = trim($topic['title']);
782
783
                if (empty($topic['title'])) {
784
                    $topic['title'] = get_lang('Untitled');
785
                }
786
787
                $html .= '<div class="col-xs-8 col-md-10">';
788
                $html .= Display::tag(
789
                    'h4',
790
                    Display::url(
791
                        Security::remove_XSS($topic['title'], STUDENT, true),
792
                        api_get_path(WEB_CODE_PATH).'social/group_topics.php?id='.$groupId.'&topic_id='.$topic['id']
793
                    ),
794
                    ['class' => 'title']
795
                );
796
                $actions = '';
797
                if (GROUP_USER_PERMISSION_ADMIN == $my_group_role ||
798
                    GROUP_USER_PERMISSION_MODERATOR == $my_group_role
799
                ) {
800
                    $actions = '<br />'.Display::url(
801
                            get_lang('Delete'),
802
                            api_get_path(
803
                                WEB_CODE_PATH
804
                            ).'social/group_topics.php?action=delete&id='.$groupId.'&topic_id='.$topic['id'],
805
                            ['class' => 'btn btn--plain']
806
                        );
807
                }
808
809
                $date = '';
810
                if ($topic['send_date'] != $topic['update_date']) {
811
                    if (!empty($topic['update_date'])) {
812
                        $date .= '<i class="fa fa-calendar"></i> '.get_lang(
813
                                'LastUpdate'
814
                            ).' '.Display::dateToStringAgoAndLongDate($topic['update_date']);
815
                    }
816
                } else {
817
                    $date .= '<i class="fa fa-calendar"></i> '.get_lang(
818
                            'Created'
819
                        ).' '.Display::dateToStringAgoAndLongDate($topic['send_date']);
820
                }
821
                $html .= '<div class="date">'.$label.' - '.$date.$actions.'</div>';
822
                $html .= '</div>';
823
824
                $image = $user_sender_info['avatar'];
825
826
                $user_info = '<div class="author"><img class="img-responsive img-circle" src="'.$image.'" alt="'.$name.'"  width="64" height="64" title="'.$name.'" /></div>';
827
                $user_info .= '<div class="name"><a href="'.api_get_path(
828
                        WEB_PATH
829
                    ).'main/social/profile.php?u='.$topic['user_sender_id'].'">'.$name.'&nbsp;</a></div>';
830
831
                $html .= '<div class="col-xs-4 col-md-2">';
832
                $html .= $user_info;
833
                $html .= '</div>';
834
                $html .= '</div>';
835
                $html .= '</div>';
836
837
                $array_html[] = [$html];
838
            }
839
840
            // grids for items and topics  with paginations
841
            $html_messages .= Display::return_sortable_grid(
842
                'topics',
843
                [],
844
                $array_html,
845
                [
846
                    'hide_navigation' => false,
847
                    'per_page' => $topics_per_page,
848
                ],
849
                $query_vars,
850
                false,
851
                [true, true, true, false],
852
                false
853
            );
854
        }
855
856
        return $html_messages;
857
    }
858
859
    /**
860
     * Get message list by id.
861
     *
862
     * @param int $messageId
863
     *
864
     * @return array
865
     */
866
    public static function get_message_by_id($messageId)
867
    {
868
        $table = Database::get_main_table(TABLE_MESSAGE);
869
        $messageId = (int) $messageId;
870
        $sql = "SELECT * FROM $table
871
                WHERE
872
                    id = '$messageId' AND
873
                    msg_type <> 3";
874
875
        echo $sql;
876
877
        $res = Database::query($sql);
878
        $item = [];
879
        if (Database::num_rows($res) > 0) {
880
            $item = Database::fetch_assoc($res);
881
        }
882
883
        return $item;
884
    }
885
886
    /**
887
     * Displays messages of a group with nested view.
888
     *
889
     * @param $groupId
890
     * @param $topic_id
891
     *
892
     * @return string
893
     */
894
    public static function display_message_for_group($groupId, $topic_id)
895
    {
896
        global $my_group_role;
897
        $main_message = self::get_message_by_id($topic_id);
898
        if (empty($main_message)) {
899
            return false;
900
        }
901
902
        $webCodePath = api_get_path(WEB_CODE_PATH);
903
        $iconCalendar = Display::returnFontAwesomeIcon('calendar');
904
905
        $langEdit = get_lang('Edit');
906
        $langReply = get_lang('Reply');
907
        $langLastUpdated = get_lang('Last updated');
908
        $langCreated = get_lang('Created');
909
910
        $rows = self::get_messages_by_group_by_message($groupId, $topic_id);
911
        $rows = self::calculate_children($rows, $topic_id);
912
        $current_user_id = api_get_user_id();
913
914
        $items_per_page = 50;
915
        $query_vars = ['id' => $groupId, 'topic_id' => $topic_id, 'topics_page_nr' => 0];
916
917
        // Main message
918
        $links = '';
919
        $main_content = '';
920
        $html = '';
921
        $items_page_nr = null;
922
923
        $user_sender_info = api_get_user_info($main_message['user_sender_id']);
924
        $files_attachments = self::getAttachmentLinkList($main_message['id'], 0);
925
        $name = $user_sender_info['complete_name'];
926
927
        $topic_page_nr = isset($_GET['topics_page_nr']) ? (int) $_GET['topics_page_nr'] : null;
928
929
        $links .= '<div class="pull-right">';
930
        $links .= '<div class="btn-group btn-group-sm">';
931
932
        if (($my_group_role == GROUP_USER_PERMISSION_ADMIN || $my_group_role == GROUP_USER_PERMISSION_MODERATOR) ||
933
            $main_message['user_sender_id'] == $current_user_id
934
        ) {
935
            $urlEdit = $webCodePath.'social/message_for_group_form.inc.php?'
936
                .http_build_query(
937
                    [
938
                        'user_friend' => $current_user_id,
939
                        'group_id' => $groupId,
940
                        'message_id' => $main_message['id'],
941
                        'action' => 'edit_message_group',
942
                        'anchor_topic' => 'topic_'.$main_message['id'],
943
                        'topics_page_nr' => $topic_page_nr,
944
                        'items_page_nr' => $items_page_nr,
945
                        'topic_id' => $main_message['id'],
946
                    ]
947
                );
948
949
            $links .= Display::toolbarButton(
950
                $langEdit,
951
                $urlEdit,
952
                'pencil',
953
                'default',
954
                ['class' => 'ajax', 'data-title' => $langEdit, 'data-size' => 'lg'],
955
                false
956
            );
957
        }
958
959
        $links .= self::getLikesButton($main_message['id'], $current_user_id, $groupId);
960
961
        $urlReply = $webCodePath.'social/message_for_group_form.inc.php?'
962
            .http_build_query(
963
                [
964
                    'user_friend' => $current_user_id,
965
                    'group_id' => $groupId,
966
                    'message_id' => $main_message['id'],
967
                    'action' => 'reply_message_group',
968
                    'anchor_topic' => 'topic_'.$main_message['id'],
969
                    'topics_page_nr' => $topic_page_nr,
970
                    'topic_id' => $main_message['id'],
971
                ]
972
            );
973
974
        $links .= Display::toolbarButton(
975
            $langReply,
976
            $urlReply,
977
            'commenting',
978
            'default',
979
            ['class' => 'ajax', 'data-title' => $langReply, 'data-size' => 'lg'],
980
            false
981
        );
982
983
        if (api_is_platform_admin()) {
984
            $links .= Display::toolbarButton(
985
                get_lang('Delete'),
986
                'group_topics.php?action=delete&id='.$groupId.'&topic_id='.$topic_id,
987
                'trash',
988
                'default',
989
                [],
990
                false
991
            );
992
        }
993
994
        $links .= '</div>';
995
        $links .= '</div>';
996
997
        $title = '<h4>'.Security::remove_XSS($main_message['title'], STUDENT, true).$links.'</h4>';
998
999
        $userPicture = $user_sender_info['avatar'];
1000
        $main_content .= '<div class="row">';
1001
        $main_content .= '<div class="col-md-2">';
1002
        $main_content .= '<div class="avatar-author">';
1003
        $main_content .= Display::img(
1004
            $userPicture,
1005
            $name,
1006
            ['width' => '60px', 'class' => 'img-responsive img-circle'],
1007
            false
1008
        );
1009
        $main_content .= '</div>';
1010
        $main_content .= '</div>';
1011
1012
        $date = '';
1013
        if ($main_message['send_date'] != $main_message['update_date']) {
1014
            if (!empty($main_message['update_date'])) {
1015
                $date = '<div class="date"> '
1016
                    ."$iconCalendar $langLastUpdated "
1017
                    .Display::dateToStringAgoAndLongDate($main_message['update_date'])
1018
                    .'</div>';
1019
            }
1020
        } else {
1021
            $date = '<div class="date"> '
1022
                ."$iconCalendar $langCreated "
1023
                .Display::dateToStringAgoAndLongDate($main_message['send_date'])
1024
                .'</div>';
1025
        }
1026
        $attachment = '<div class="message-attach">'
1027
            .(!empty($files_attachments) ? implode('<br />', $files_attachments) : '')
1028
            .'</div>';
1029
        $main_content .= '<div class="col-md-10">';
1030
        $user_link = Display::url(
1031
            $name,
1032
            $webCodePath.'social/profile.php?u='.$main_message['user_sender_id']
1033
        );
1034
        $main_content .= '<div class="message-content"> ';
1035
        $main_content .= '<div class="username">'.$user_link.'</div>';
1036
        $main_content .= $date;
1037
        $main_content .= '<div class="message">'
1038
            .Security::remove_XSS($main_message['content'], STUDENT, true)
1039
            .$attachment.'</div></div>';
1040
        $main_content .= '</div>';
1041
        $main_content .= '</div>';
1042
1043
        $html .= Display::div(
1044
            Display::div(
1045
                $title.$main_content,
1046
                ['class' => 'message-topic']
1047
            ),
1048
            ['class' => 'sm-groups-message']
1049
        );
1050
1051
        $topic_id = $main_message['id'];
1052
1053
        if (is_array($rows) && count($rows) > 0) {
1054
            $topics = $rows;
1055
            $array_html_items = [];
1056
1057
            foreach ($topics as $index => $topic) {
1058
                if (empty($topic['id'])) {
1059
                    continue;
1060
                }
1061
                $items_page_nr = isset($_GET['items_'.$topic['id'].'_page_nr'])
1062
                    ? (int) $_GET['items_'.$topic['id'].'_page_nr']
1063
                    : null;
1064
                $links = '';
1065
                $links .= '<div class="pull-right">';
1066
                $html_items = '';
1067
                $user_sender_info = api_get_user_info($topic['user_sender_id']);
1068
                $files_attachments = self::getAttachmentLinkList($topic['id'], 0);
1069
                $name = $user_sender_info['complete_name'];
1070
1071
                $links .= '<div class="btn-group btn-group-sm">';
1072
                if (
1073
                    ($my_group_role == GROUP_USER_PERMISSION_ADMIN ||
1074
                        $my_group_role == GROUP_USER_PERMISSION_MODERATOR
1075
                    ) ||
1076
                    $topic['user_sender_id'] == $current_user_id
1077
                ) {
1078
                    $links .= Display::toolbarButton(
1079
                        $langEdit,
1080
                        $webCodePath.'social/message_for_group_form.inc.php?'
1081
                        .http_build_query(
1082
                            [
1083
                                'user_friend' => $current_user_id,
1084
                                'group_id' => $groupId,
1085
                                'message_id' => $topic['id'],
1086
                                'action' => 'edit_message_group',
1087
                                'anchor_topic' => 'topic_'.$topic_id,
1088
                                'topics_page_nr' => $topic_page_nr,
1089
                                'items_page_nr' => $items_page_nr,
1090
                                'topic_id' => $topic_id,
1091
                            ]
1092
                        ),
1093
                        'pencil',
1094
                        'default',
1095
                        ['class' => 'ajax', 'data-title' => $langEdit, 'data-size' => 'lg'],
1096
                        false
1097
                    );
1098
                }
1099
1100
                $links .= self::getLikesButton($topic['id'], $current_user_id, $groupId);
1101
1102
                $links .= Display::toolbarButton(
1103
                    $langReply,
1104
                    $webCodePath.'social/message_for_group_form.inc.php?'
1105
                    .http_build_query(
1106
                        [
1107
                            'user_friend' => $current_user_id,
1108
                            'group_id' => $groupId,
1109
                            'message_id' => $topic['id'],
1110
                            'action' => 'reply_message_group',
1111
                            'anchor_topic' => 'topic_'.$topic_id,
1112
                            'topics_page_nr' => $topic_page_nr,
1113
                            'items_page_nr' => $items_page_nr,
1114
                            'topic_id' => $topic_id,
1115
                        ]
1116
                    ),
1117
                    'commenting',
1118
                    'default',
1119
                    ['class' => 'ajax', 'data-title' => $langReply, 'data-size' => 'lg'],
1120
                    false
1121
                );
1122
                $links .= '</div>';
1123
                $links .= '</div>';
1124
1125
                $userPicture = $user_sender_info['avatar'];
1126
                $user_link = Display::url(
1127
                    $name,
1128
                    $webCodePath.'social/profile.php?u='.$topic['user_sender_id']
1129
                );
1130
                $html_items .= '<div class="row">';
1131
                $html_items .= '<div class="col-md-2">';
1132
                $html_items .= '<div class="avatar-author">';
1133
                $html_items .= Display::img(
1134
                    $userPicture,
1135
                    $name,
1136
                    ['width' => '60px', 'class' => 'img-responsive img-circle'],
1137
                    false
1138
                );
1139
                $html_items .= '</div>';
1140
                $html_items .= '</div>';
1141
1142
                $date = '';
1143
                if ($topic['send_date'] != $topic['update_date']) {
1144
                    if (!empty($topic['update_date'])) {
1145
                        $date = '<div class="date"> '
1146
                            ."$iconCalendar $langLastUpdated "
1147
                            .Display::dateToStringAgoAndLongDate($topic['update_date'])
1148
                            .'</div>';
1149
                    }
1150
                } else {
1151
                    $date = '<div class="date"> '
1152
                        ."$iconCalendar $langCreated "
1153
                        .Display::dateToStringAgoAndLongDate($topic['send_date'])
1154
                        .'</div>';
1155
                }
1156
                $attachment = '<div class="message-attach">'
1157
                    .(!empty($files_attachments) ? implode('<br />', $files_attachments) : '')
1158
                    .'</div>';
1159
                $html_items .= '<div class="col-md-10">'
1160
                    .'<div class="message-content">'
1161
                    .$links
1162
                    .'<div class="username">'.$user_link.'</div>'
1163
                    .$date
1164
                    .'<div class="message">'
1165
                    .Security::remove_XSS($topic['content'], STUDENT, true)
1166
                    .'</div>'.$attachment.'</div>'
1167
                    .'</div>'
1168
                    .'</div>';
1169
1170
                $base_padding = 20;
1171
1172
                if ($topic['indent_cnt'] == 0) {
1173
                    $indent = $base_padding;
1174
                } else {
1175
                    $indent = (int) $topic['indent_cnt'] * $base_padding + $base_padding;
1176
                }
1177
1178
                $html_items = Display::div($html_items, ['class' => 'message-post', 'id' => 'msg_'.$topic['id']]);
1179
                $html_items = Display::div($html_items, ['class' => '', 'style' => 'margin-left:'.$indent.'px']);
1180
                $array_html_items[] = [$html_items];
1181
            }
1182
1183
            // grids for items with paginations
1184
            $options = ['hide_navigation' => false, 'per_page' => $items_per_page];
1185
            $visibility = [true, true, true, false];
1186
1187
            $style_class = [
1188
                'item' => ['class' => 'user-post'],
1189
                'main' => ['class' => 'user-list'],
1190
            ];
1191
            if (!empty($array_html_items)) {
1192
                $html .= Display::return_sortable_grid(
1193
                    'items_'.$topic['id'],
1194
                    [],
1195
                    $array_html_items,
1196
                    $options,
1197
                    $query_vars,
1198
                    null,
1199
                    $visibility,
1200
                    false,
1201
                    $style_class
1202
                );
1203
            }
1204
        }
1205
1206
1207
        return $html;
1208
    }
1209
1210
    /**
1211
     * Add children to messages by id is used for nested view messages.
1212
     *
1213
     * @param array $rows rows of messages
1214
     *
1215
     * @return array $first_seed new list adding the item children
1216
     */
1217
    public static function calculate_children($rows, $first_seed)
1218
    {
1219
        $rows_with_children = [];
1220
        foreach ($rows as $row) {
1221
            $rows_with_children[$row["id"]] = $row;
1222
            $rows_with_children[$row["parent_id"]]["children"][] = $row["id"];
1223
        }
1224
        $rows = $rows_with_children;
1225
        $sorted_rows = [0 => []];
1226
        self::message_recursive_sort($rows, $sorted_rows, $first_seed);
1227
        unset($sorted_rows[0]);
1228
1229
        return $sorted_rows;
1230
    }
1231
1232
    /**
1233
     * Sort recursively the messages, is used for for nested view messages.
1234
     *
1235
     * @param array  original rows of messages
1236
     * @param array  list recursive of messages
1237
     * @param int   seed for calculate the indent
1238
     * @param int   indent for nested view
1239
     */
1240
    public static function message_recursive_sort(
1241
        $rows,
1242
        &$messages,
1243
        $seed = 0,
1244
        $indent = 0
1245
    ) {
1246
        if ($seed > 0 && isset($rows[$seed]["id"])) {
1247
            $messages[$rows[$seed]["id"]] = $rows[$seed];
1248
            $messages[$rows[$seed]["id"]]["indent_cnt"] = $indent;
1249
            $indent++;
1250
        }
1251
1252
        if (isset($rows[$seed]["children"])) {
1253
            foreach ($rows[$seed]["children"] as $child) {
1254
                self::message_recursive_sort($rows, $messages, $child, $indent);
1255
            }
1256
        }
1257
    }
1258
1259
    /**
1260
     * Get array of links (download) for message attachment files.
1261
     *
1262
     * @return array
1263
     */
1264
    public static function getAttachmentLinkList(Message $message)
1265
    {
1266
        $files = $message->getAttachments();
1267
        // get file attachments by message id
1268
        $list = [];
1269
        if ($files) {
0 ignored issues
show
introduced by
$files is of type Doctrine\Common\Collections\Collection, thus it always evaluated to true.
Loading history...
1270
            $attachIcon = Display::getMdiIcon('paperclip');
1271
            $repo = Container::getMessageAttachmentRepository();
1272
            foreach ($files as $file) {
1273
                $size = format_file_size($file->getSize());
1274
                $comment = Security::remove_XSS($file->getComment());
1275
                $filename = Security::remove_XSS($file->getFilename());
1276
                $url = $repo->getResourceFileUrl($file);
1277
                $link = Display::url($filename, $url);
1278
                $comment = !empty($comment) ? '&nbsp;-&nbsp;<i>'.$comment.'</i>' : '';
1279
1280
                $attachmentLine = $attachIcon.'&nbsp;'.$link.'&nbsp;('.$size.')'.$comment;
1281
                /*if ('audio_message' === $file['comment']) {
1282
                    $attachmentLine = '<audio src="'.$archiveURL.$archiveFile.'"/>';
1283
                }*/
1284
                $list[] = $attachmentLine;
1285
            }
1286
        }
1287
1288
        return $list;
1289
    }
1290
1291
    /**
1292
     * @return string
1293
     */
1294
    public static function generate_message_form()
1295
    {
1296
        $form = new FormValidator('send_message');
1297
        $form->addText(
1298
            'subject',
1299
            get_lang('Subject'),
1300
            false,
1301
            ['id' => 'subject_id']
1302
        );
1303
        $form->addTextarea(
1304
            'content',
1305
            get_lang('Message'),
1306
            ['id' => 'content_id', 'rows' => '5']
1307
        );
1308
1309
        return $form->returnForm();
1310
    }
1311
1312
    /**
1313
     * @return string
1314
     */
1315
    public static function generate_invitation_form()
1316
    {
1317
        $form = new FormValidator('send_invitation');
1318
        $form->addTextarea(
1319
            'content',
1320
            get_lang('Add a personal message'),
1321
            ['id' => 'content_invitation_id', 'rows' => 5]
1322
        );
1323
1324
        return $form->returnForm();
1325
    }
1326
1327
    /**
1328
     * @param string $type
1329
     * @param string $keyword
1330
     * @param array  $actions
1331
     *
1332
     * @return string
1333
     */
1334
    public static function getMessageGrid($type, $keyword, $actions = [])
1335
    {
1336
        $html = '';
1337
        // display sortable table with messages of the current user
1338
        $table = new SortableTable(
1339
            'message_inbox',
1340
            ['MessageManager', 'getNumberOfMessages'],
1341
            ['MessageManager', 'getMessageData'],
1342
            2,
1343
            20,
1344
            'DESC'
1345
        );
1346
        $table->setDataFunctionParams(
1347
            ['keyword' => $keyword, 'type' => $type, 'actions' => $actions]
1348
        );
1349
        $table->set_header(0, '', false, ['style' => 'width:15px;']);
1350
        $table->set_header(1, get_lang('Messages'), false);
1351
        $table->set_header(2, get_lang('Date'), true, ['style' => 'width:180px;']);
1352
        $table->set_header(3, get_lang('Edit'), false, ['style' => 'width:120px;']);
1353
1354
        if (isset($_REQUEST['f']) && 'social' === $_REQUEST['f']) {
1355
            $parameters['f'] = 'social';
1356
            $table->set_additional_parameters($parameters);
1357
        }
1358
1359
        $defaultActions = [
1360
            'delete' => get_lang('Delete selected messages'),
1361
            'mark_as_unread' => get_lang('Mark as unread'),
1362
            'mark_as_read' => get_lang('Mark as read'),
1363
        ];
1364
1365
        if (!in_array('delete', $actions)) {
1366
            unset($defaultActions['delete']);
1367
        }
1368
        if (!in_array('mark_as_unread', $actions)) {
1369
            unset($defaultActions['mark_as_unread']);
1370
        }
1371
        if (!in_array('mark_as_read', $actions)) {
1372
            unset($defaultActions['mark_as_read']);
1373
        }
1374
1375
        $table->set_form_actions($defaultActions);
1376
1377
        $html .= $table->return_table();
1378
1379
        return $html;
1380
    }
1381
1382
    /**
1383
     * @param string $url
1384
     *
1385
     * @return FormValidator
1386
     */
1387
    public static function getSearchForm($url)
1388
    {
1389
        $form = new FormValidator(
1390
            'search',
1391
            'post',
1392
            $url,
1393
            null,
1394
            [],
1395
            FormValidator::LAYOUT_INLINE
1396
        );
1397
1398
        $form->addElement(
1399
            'text',
1400
            'keyword',
1401
            false,
1402
            [
1403
                'aria-label' => get_lang('Search'),
1404
            ]
1405
        );
1406
        $form->addButtonSearch(get_lang('Search'));
1407
1408
        return $form;
1409
    }
1410
1411
    /**
1412
     * Send a notification to all admins when a new user is registered.
1413
     */
1414
    public static function sendNotificationOfNewRegisteredUser(User $user)
1415
    {
1416
        $tplMailBody = new Template(
1417
            null,
1418
            false,
1419
            false,
1420
            false,
1421
            false,
1422
            false,
1423
            false
1424
        );
1425
        $tplMailBody->assign('user', $user);
1426
        $tplMailBody->assign('is_western_name_order', api_is_western_name_order());
1427
        $tplMailBody->assign(
1428
            'manageUrl',
1429
            api_get_path(WEB_CODE_PATH).'admin/user_edit.php?user_id='.$user->getId()
1430
        );
1431
1432
        $layoutContent = $tplMailBody->get_template('mail/new_user_mail_to_admin.tpl');
1433
1434
        $emailsubject = '['.get_lang('The user has been registered').'] '.$user->getUsername();
1435
        $emailbody = $tplMailBody->fetch($layoutContent);
1436
1437
        $admins = UserManager::get_all_administrators();
1438
1439
        foreach ($admins as $admin_info) {
1440
            self::send_message(
1441
                $admin_info['user_id'],
1442
                $emailsubject,
1443
                $emailbody,
1444
                [],
1445
                [],
1446
                null,
1447
                null,
1448
                null,
1449
                null,
1450
                $user->getId()
1451
            );
1452
        }
1453
    }
1454
1455
    /**
1456
     * Send a notification to all admins when a new user is registered
1457
     * while the approval method is used for users registration.
1458
     */
1459
    public static function sendNotificationOfNewRegisteredUserApproval(User $user)
1460
    {
1461
        $tplMailBody = new Template(
1462
            null,
1463
            false,
1464
            false,
1465
            false,
1466
            false,
1467
            false,
1468
            false
1469
        );
1470
        $tplMailBody->assign('user', $user);
1471
        $tplMailBody->assign('is_western_name_order', api_is_western_name_order());
1472
        $userId = $user->getId();
1473
        $url_edit = Display::url(
1474
            api_get_path(WEB_CODE_PATH).'admin/user_edit.php?user_id='.$userId,
1475
            api_get_path(WEB_CODE_PATH).'admin/user_edit.php?user_id='.$userId
1476
        );
1477
        $tplMailBody->assign(
1478
            'manageUrl',
1479
            $url_edit
1480
        );
1481
        // Get extra field values for this user and reformat the array
1482
        $extraFieldValues = new ExtraFieldValue('user');
1483
        $userExtraFields = $extraFieldValues->getAllValuesByItem($userId);
1484
        $values = [];
1485
        foreach ($userExtraFields as $field => $value) {
1486
            $values[$value['variable']] = $value['value'];
1487
        }
1488
        $tplMailBody->assign(
1489
            'extra',
1490
            $values
1491
        );
1492
        $layoutContent = '';
1493
        $emailbody = '';
1494
        $mailTemplateManager = new MailTemplateManager();
1495
        $templateText = $mailTemplateManager->getTemplateByType('new_user_mail_to_admin_approval.tpl');
1496
        if (empty($templateText)) {
1497
        } else {
1498
            // custom procedure to load a template as a string (doesn't use cache so may slow down)
1499
            $template = $tplMailBody->twig->createTemplate($templateText);
1500
            $emailbody = $template->render($tplMailBody->params);
1501
        }
1502
        if (empty($emailbody)) {
1503
            $layoutContent = $tplMailBody->get_template('mail/new_user_mail_to_admin_approval.tpl');
1504
            $emailbody = $tplMailBody->fetch($layoutContent);
1505
        }
1506
1507
        $emailsubject = '['.get_lang('Approval for new account').'] '.$user->getUsername();
1508
1509
        if ('true' === api_get_setting('admin.send_inscription_notification_to_general_admin_only')) {
1510
            $email = api_get_setting('emailAdministrator');
1511
            $firstname = api_get_setting('administratorSurname');
1512
            $lastname = api_get_setting('administratorName');
1513
            api_mail_html("$firstname $lastname", $email, $emailsubject, $emailbody);
1514
        } else {
1515
            $admins = UserManager::get_all_administrators();
1516
            foreach ($admins as $admin_info) {
1517
                self::send_message(
1518
                    $admin_info['user_id'],
1519
                    $emailsubject,
1520
                    $emailbody,
1521
                    [],
1522
                    [],
1523
                    null,
1524
                    null,
1525
                    null,
1526
                    null,
1527
                    $userId
1528
                );
1529
            }
1530
        }
1531
    }
1532
1533
    /**
1534
     * Get the error log from failed mailing
1535
     * This assumes a complex setup where you have a cron script regularly copying the mail queue log
1536
     * into var/cache/mail/mailq.
1537
     * This can be done with a cron command like (check the location of your mail log file first):.
1538
     *
1539
     * @example 0,30 * * * * root cp /var/log/exim4/mainlog /var/www/chamilo/var/cache/mail/mailq
1540
     *
1541
     * @return array|bool
1542
     */
1543
    public static function failedSentMailErrors()
1544
    {
1545
        $base = api_get_path(SYS_ARCHIVE_PATH).'mail/';
1546
        $mailq = $base.'mailq';
1547
1548
        if (!file_exists($mailq) || !is_readable($mailq)) {
1549
            return false;
1550
        }
1551
1552
        $file = fopen($mailq, 'r');
1553
        $i = 1;
1554
        while (!feof($file)) {
1555
            $line = fgets($file);
1556
1557
            if ('' == trim($line)) {
1558
                continue;
1559
            }
1560
1561
            // Get the mail code, something like 1WBumL-0002xg-FF
1562
            if (preg_match('/(.*)\s((.*)-(.*)-(.*))\s<(.*)$/', $line, $codeMatches)) {
1563
                $mail_queue[$i]['code'] = $codeMatches[2];
1564
            }
1565
1566
            $fullMail = $base.$mail_queue[$i]['code'];
1567
            $mailFile = fopen($fullMail, 'r');
1568
1569
            // Get the reason of mail fail
1570
            $iX = 1;
1571
            while (!feof($mailFile)) {
1572
                $mailLine = fgets($mailFile);
1573
                //if ($iX == 4 && preg_match('/(.*):\s(.*)$/', $mailLine, $matches)) {
1574
                if (2 == $iX &&
1575
                    preg_match('/(.*)(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\s(.*)/', $mailLine, $detailsMatches)
1576
                ) {
1577
                    $mail_queue[$i]['reason'] = $detailsMatches[3];
1578
                }
1579
                $iX++;
1580
            }
1581
1582
            fclose($mailFile);
1583
1584
            // Get the time of mail fail
1585
            if (preg_match('/^\s?(\d+)(\D+)\s+(.*)$/', $line, $timeMatches)) {
1586
                $mail_queue[$i]['time'] = $timeMatches[1].$timeMatches[2];
1587
            } elseif (preg_match('/^(\s+)((.*)@(.*))\s+(.*)$/', $line, $emailMatches)) {
1588
                $mail_queue[$i]['mail'] = $emailMatches[2];
1589
                $i++;
1590
            }
1591
        }
1592
1593
        fclose($file);
1594
1595
        return array_reverse($mail_queue);
1596
    }
1597
1598
    /**
1599
     * @param int $userId
1600
     *
1601
     * @return array
1602
     */
1603
    public static function getUsersThatHadConversationWithUser($userId)
1604
    {
1605
        $messagesTable = Database::get_main_table(TABLE_MESSAGE);
1606
        $userId = (int) $userId;
1607
1608
        $sql = "SELECT DISTINCT
1609
                    user_sender_id
1610
                FROM $messagesTable
1611
                WHERE
1612
                    user_receiver_id = ".$userId;
1613
        $result = Database::query($sql);
1614
        $users = Database::store_result($result);
1615
        $userList = [];
1616
        foreach ($users as $userData) {
1617
            $userId = $userData['user_sender_id'];
1618
            if (empty($userId)) {
1619
                continue;
1620
            }
1621
            $userInfo = api_get_user_info($userId);
1622
            if ($userInfo) {
1623
                $userList[$userId] = $userInfo;
1624
            }
1625
        }
1626
1627
        return $userList;
1628
    }
1629
1630
    /**
1631
     * @param int $userId
1632
     * @param int $otherUserId
1633
     *
1634
     * @return array
1635
     */
1636
    public static function getAllMessagesBetweenStudents($userId, $otherUserId)
1637
    {
1638
        $messagesTable = Database::get_main_table(TABLE_MESSAGE);
1639
        $userId = (int) $userId;
1640
        $otherUserId = (int) $otherUserId;
1641
1642
        if (empty($otherUserId) || empty($userId)) {
1643
            return [];
1644
        }
1645
1646
        $sql = "SELECT DISTINCT *
1647
                FROM $messagesTable
1648
                WHERE
1649
                    (user_receiver_id = $userId AND user_sender_id = $otherUserId) OR
1650
                    (user_receiver_id = $otherUserId AND user_sender_id = $userId)
1651
                ORDER BY send_date DESC
1652
            ";
1653
        $result = Database::query($sql);
1654
        $messages = Database::store_result($result);
1655
        $list = [];
1656
        foreach ($messages as $message) {
1657
            $list[] = $message;
1658
        }
1659
1660
        return $list;
1661
    }
1662
1663
    /**
1664
     * @param string $subject
1665
     * @param string $message
1666
     * @param Course $course
1667
     * @param int    $sessionId
1668
     *
1669
     * @return bool
1670
     */
1671
    public static function sendMessageToAllUsersInCourse($subject, $message, Course $course, $sessionId = 0)
1672
    {
1673
        $senderId = api_get_user_id();
1674
        if (empty($senderId)) {
1675
            return false;
1676
        }
1677
        if (empty($sessionId)) {
1678
            // Course students and teachers
1679
            $users = CourseManager::get_user_list_from_course_code($course->getCode());
1680
        } else {
1681
            // Course-session students and course session coaches
1682
            $users = CourseManager::get_user_list_from_course_code($course->getCode(), $sessionId);
1683
        }
1684
1685
        if (empty($users)) {
1686
            return false;
1687
        }
1688
1689
        foreach ($users as $userInfo) {
1690
            self::send_message_simple(
1691
                $userInfo['user_id'],
1692
                $subject,
1693
                $message,
1694
                $senderId,
1695
                false,
1696
                false,
1697
                false
1698
            );
1699
        }
1700
    }
1701
1702
    /**
1703
     * Clean audio messages already added in the message tool.
1704
     */
1705
    public static function cleanAudioMessage()
1706
    {
1707
        Session::erase('current_audio');
1708
    }
1709
1710
    /**
1711
     * @param int    $senderId
1712
     * @param string $subject
1713
     * @param string $message
1714
     */
1715
    public static function sendMessageToAllAdminUsers(
1716
        $senderId,
1717
        $subject,
1718
        $message
1719
    ) {
1720
        $admins = UserManager::get_all_administrators();
1721
        foreach ($admins as $admin) {
1722
            self::send_message_simple($admin['user_id'], $subject, $message, $senderId);
1723
        }
1724
    }
1725
1726
    /**
1727
     * @param int $messageId
1728
     * @param int $userId
1729
     *
1730
     * @return array
1731
     */
1732
    public static function countLikesAndDislikes($messageId, $userId): array
1733
    {
1734
        if ('true' !== api_get_setting('social.social_enable_messages_feedback')) {
1735
            return [];
1736
        }
1737
1738
        $user = Container::getUserRepository()->find($userId);
1739
        $socialPost = Container::getSocialPostRepository()->find($messageId);
1740
1741
        $userLike = $user->getSocialPostFeedbackBySocialPost($socialPost);
1742
1743
        return [
1744
            'likes' => $socialPost->getCountFeedbackLikes(),
1745
            'dislikes' => $socialPost->getCountFeedbackDislikes(),
1746
            'user_liked' => $userLike ? $userLike->isLiked() : false,
1747
            'user_disliked' => $userLike ? $userLike->isDisliked() : false,
1748
        ];
1749
    }
1750
1751
    /**
1752
     * @param int $messageId
1753
     * @param int $userId
1754
     * @param int $groupId   Optional.
1755
     *
1756
     * @return string
1757
     */
1758
    public static function getLikesButton($messageId, $userId, $groupId = 0)
1759
    {
1760
        if ('true' !== api_get_setting('social.social_enable_messages_feedback')) {
1761
            return '';
1762
        }
1763
1764
        $countLikes = self::countLikesAndDislikes($messageId, $userId);
1765
1766
        $class = $countLikes['user_liked'] ? 'btn--primary' : 'btn--plain';
1767
1768
        $btnLike = Display::button(
1769
            'like',
1770
            Display::getMdiIcon('thumb-up')
1771
                .PHP_EOL.'<span>'.$countLikes['likes'].'</span>',
1772
            [
1773
                'title' => get_lang('Like'),
1774
                'class' => 'btn  social-like '.$class,
1775
                'data-status' => 'like',
1776
                'data-message' => $messageId,
1777
                'data-group' => $groupId,
1778
            ]
1779
        );
1780
1781
        $btnDislike = '';
1782
        if ('true' !== api_get_setting('social.disable_dislike_option')) {
1783
            $disabled = $countLikes['user_disliked'] ? 'btn--danger' : 'btn--plain';
1784
1785
            $btnDislike = Display::button(
1786
                'like',
1787
                Display::getMdiIcon('thumb-down')
1788
                .PHP_EOL.'<span>'.$countLikes['dislikes'].'</span>',
1789
                [
1790
                    'title' => get_lang('Dislike'),
1791
                    'class' => 'btn social-like '.$disabled,
1792
                    'data-status' => 'dislike',
1793
                    'data-message' => $messageId,
1794
                    'data-group' => $groupId,
1795
                ]
1796
            );
1797
        }
1798
1799
        return $btnLike.PHP_EOL.$btnDislike;
1800
    }
1801
1802
    /**
1803
     * Reports whether the given user is sender or receiver of the given message
1804
     */
1805
    public static function isUserOwner(int $userId, int $messageId): bool
1806
    {
1807
        $table = Database::get_main_table(TABLE_MESSAGE);
1808
        $sql = "SELECT id FROM $table
1809
          WHERE id = $messageId
1810
            AND (user_receiver_id = $userId OR user_sender_id = $userId)";
1811
        $res = Database::query($sql);
1812
        if (Database::num_rows($res) === 1) {
1813
            return true;
1814
        }
1815
        return false;
1816
    }
1817
}
1818