MessageManager::send_message()   F
last analyzed

Complexity

Conditions 55
Paths > 20000

Size

Total Lines 315
Code Lines 188

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 55
eloc 188
nc 307304
nop 17
dl 0
loc 315
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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