Passed
Push — master ( 760dff...ab8d81 )
by Julito
07:06
created

MessageManager::getNumberOfMessages()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 10
nc 2
nop 1
dl 0
loc 18
rs 9.9332
c 0
b 0
f 0
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\MessageFeedback;
9
use Chamilo\CoreBundle\Entity\User;
10
use Chamilo\CoreBundle\Framework\Container;
11
use ChamiloSession as Session;
12
use Doctrine\Common\Collections\Criteria;
13
use Symfony\Component\HttpFoundation\File\UploadedFile;
14
15
/**
16
 * This class provides methods for messages management.
17
 * Include/require it in your code to use its features.
18
 */
19
class MessageManager
20
{
21
    /**
22
     * @param array $extraParams
23
     *
24
     * @return string
25
     */
26
    public static function getWhereConditions($extraParams)
27
    {
28
        $userId = api_get_user_id();
29
30
        $keyword = isset($extraParams['keyword']) && !empty($extraParams['keyword']) ? $extraParams['keyword'] : '';
31
        $type = isset($extraParams['type']) && !empty($extraParams['type']) ? $extraParams['type'] : '';
32
33
        if (empty($type)) {
34
            return '';
35
        }
36
37
        switch ($type) {
38
            case Message::MESSAGE_TYPE_INBOX:
39
                $statusList = [MESSAGE_STATUS_NEW, MESSAGE_STATUS_UNREAD];
40
                $userCondition = " user_receiver_id = $userId AND";
41
                break;
42
            case Message::MESSAGE_TYPE_OUTBOX:
43
                $statusList = [MESSAGE_STATUS_OUTBOX];
44
                $userCondition = " user_sender_id = $userId AND";
45
                break;
46
            case Message::MESSAGE_TYPE_PROMOTED:
47
                $statusList = [MESSAGE_STATUS_PROMOTED];
48
                $userCondition = " user_receiver_id = $userId AND";
49
                break;
50
        }
51
52
        if (empty($statusList)) {
53
            return '';
54
        }
55
56
        $keywordCondition = '';
57
        if (!empty($keyword)) {
58
            $keyword = Database::escape_string($keyword);
59
            $keywordCondition = " AND (title like '%$keyword%' OR content LIKE '%$keyword%') ";
60
        }
61
        $messageStatusCondition = implode("','", $statusList);
62
63
        return " $userCondition
64
                 msg_status IN ('$messageStatusCondition')
65
                 $keywordCondition";
66
    }
67
68
    /**
69
     * Gets information about some messages, used for the inbox sortable table.
70
     *
71
     * @param int    $from
72
     * @param int    $numberOfItems
73
     * @param string $column
74
     * @param string $direction
75
     * @param array  $extraParams
76
     *
77
     * @return array
78
     */
79
    public static function getMessageData(
80
        $from,
81
        $numberOfItems,
82
        $column,
83
        $direction,
84
        $extraParams = []
85
    ) {
86
        $from = (int) $from;
87
        $numberOfItems = (int) $numberOfItems;
88
        $column = (int) $column;
89
90
        // Forcing this order.
91
        if (!isset($direction)) {
92
            $column = 2;
93
            $direction = 'DESC';
94
        } else {
95
            if (!in_array($direction, ['ASC', 'DESC'])) {
96
                $direction = 'ASC';
97
            }
98
        }
99
100
        if (!in_array($column, [0, 1, 2])) {
101
            $column = 2;
102
        }
103
104
        $type = isset($extraParams['type']) && !empty($extraParams['type']) ? $extraParams['type'] : '';
105
106
        if (empty($type)) {
107
            return [];
108
        }
109
110
        $viewUrl = '';
111
        switch ($type) {
112
            case Message::MESSAGE_TYPE_OUTBOX:
113
            case Message::MESSAGE_TYPE_INBOX:
114
                $viewUrl = api_get_path(WEB_CODE_PATH).'messages/view_message.php';
115
                break;
116
            case Message::MESSAGE_TYPE_PROMOTED:
117
                $viewUrl = api_get_path(WEB_CODE_PATH).'social/view_promoted_message.php';
118
                break;
119
        }
120
        $viewUrl .= '?type='.$type;
121
122
        $whereConditions = self::getWhereConditions($extraParams);
123
124
        if (empty($whereConditions)) {
125
            return [];
126
        }
127
128
        $table = Database::get_main_table(TABLE_MESSAGE);
129
        $sql = "SELECT
130
                    id as col0,
131
                    title as col1,
132
                    send_date as col2,
133
                    msg_status as col3,
134
                    user_sender_id,
135
                    user_receiver_id
136
                FROM $table
137
                WHERE
138
                    $whereConditions
139
                ORDER BY col$column $direction
140
                LIMIT $from, $numberOfItems";
141
142
        $result = Database::query($sql);
143
        $messageList = [];
144
        $newMessageLink = api_get_path(WEB_CODE_PATH).'messages/new_message.php';
145
146
        $actions = $extraParams['actions'];
147
        $url = api_get_self();
148
        while ($row = Database::fetch_array($result, 'ASSOC')) {
149
            $messageId = $row['col0'];
150
            $title = $row['col1'];
151
            $sendDate = $row['col2'];
152
            $status = $row['col3'];
153
            $senderId = $row['user_sender_id'];
154
            $receiverId = $row['user_receiver_id'];
155
156
            $title = Security::remove_XSS($title, STUDENT, true);
157
            $title = cut($title, 80, true);
158
159
            $class = 'class = "read"';
160
            if (1 == $status) {
161
                $class = 'class = "unread"';
162
            }
163
164
            $userInfo = api_get_user_info($senderId);
165
            if (Message::MESSAGE_TYPE_OUTBOX == $type) {
166
                $userInfo = api_get_user_info($receiverId);
167
            }
168
            $message[3] = '';
169
            if (!empty($senderId) && !empty($userInfo)) {
170
                $message[1] = '<a '.$class.' href="'.$viewUrl.'&id='.$messageId.'">'.$title.'</a><br />';
171
                $message[1] .= $userInfo['complete_name_with_username'];
172
                if (in_array('reply', $actions)) {
173
                    $message[3] =
174
                        Display::url(
175
                            Display::returnFontAwesomeIcon('reply', 2),
176
                            $newMessageLink.'?re_id='.$messageId,
177
                            ['title' => get_lang('Reply to this message')]
178
                        );
179
                }
180
            } else {
181
                $message[1] = '<a '.$class.' href="'.$viewUrl.'&id='.$messageId.'">'.$title.'</a><br />';
182
                $message[1] .= get_lang('Unknown user');
183
                if (in_array('reply', $actions)) {
184
                    $message[3] =
185
                        Display::url(
186
                            Display::returnFontAwesomeIcon('reply', 2),
187
                            '#',
188
                            ['title' => get_lang('Reply to this message')]
189
                        );
190
                }
191
            }
192
193
            $message[0] = $messageId;
194
            $message[2] = api_convert_and_format_date($sendDate, DATE_TIME_FORMAT_LONG);
195
196
            // Actions
197
            if (in_array('edit', $actions)) {
198
                $message[3] .=
199
                    '&nbsp;&nbsp;'.
200
                    Display::url(
201
                        Display::returnFontAwesomeIcon('pencil', 2),
202
                        $newMessageLink.'?action=edit&id='.$messageId,
203
                        ['title' => get_lang('Forward message')]
204
                    );
205
            }
206
207
            // Actions
208
            if (in_array('forward', $actions)) {
209
                $message[3] .=
210
                    '&nbsp;&nbsp;'.
211
                    Display::url(
212
                        Display::returnFontAwesomeIcon('share', 2),
213
                        $newMessageLink.'?forward_id='.$messageId,
214
                        ['title' => get_lang('Forward message')]
215
                    );
216
            }
217
218
            if (in_array('delete', $actions)) {
219
                $message[3] .= '&nbsp;&nbsp;<a title="'.addslashes(
220
                    get_lang('Delete message')
221
                ).'" onclick="javascript:if(!confirm('."'".addslashes(
222
                    api_htmlentities(get_lang('ConfirmDelete message'))
223
                )."'".')) return false;" href="'.$url.'?action=deleteone&id='.$messageId.'">'.
224
                Display::returnFontAwesomeIcon('trash', 2).'</a>';
225
            }
226
227
            foreach ($message as $key => $value) {
228
                $message[$key] = api_xml_http_response_encode($value);
229
            }
230
            $messageList[] = $message;
231
        }
232
233
        return $messageList;
234
    }
235
236
    /**
237
     * @param array  $aboutUserInfo
238
     * @param array  $fromUserInfo
239
     * @param string $subject
240
     * @param string $content
241
     *
242
     * @return bool
243
     */
244
    public static function sendMessageAboutUser(
245
        $aboutUserInfo,
246
        $fromUserInfo,
247
        $subject,
248
        $content
249
    ) {
250
        if (empty($aboutUserInfo) || empty($fromUserInfo)) {
251
            return false;
252
        }
253
254
        if (empty($fromUserInfo['id']) || empty($aboutUserInfo['id'])) {
255
            return false;
256
        }
257
258
        $table = Database::get_main_table(TABLE_MESSAGE);
259
        $now = api_get_utc_datetime();
260
        $params = [
261
            'user_sender_id' => $fromUserInfo['id'],
262
            'user_receiver_id' => $aboutUserInfo['id'],
263
            'msg_status' => MESSAGE_STATUS_CONVERSATION,
264
            'send_date' => $now,
265
            'title' => $subject,
266
            'content' => $content,
267
            'group_id' => 0,
268
            'parent_id' => 0,
269
            'update_date' => $now,
270
        ];
271
        $id = Database::insert($table, $params);
272
273
        if ($id) {
274
            return true;
275
        }
276
277
        return false;
278
    }
279
280
    public static function getMessagesAboutUser(User $user): array
281
    {
282
        if (!empty($user)) {
283
            $table = Database::get_main_table(TABLE_MESSAGE);
284
            $sql = 'SELECT id FROM '.$table.'
285
                    WHERE
286
                      user_receiver_id = '.$user->getId().' AND
287
                      msg_status = '.MESSAGE_STATUS_CONVERSATION.'
288
                    ';
289
            $result = Database::query($sql);
290
            $messages = [];
291
            $repo = Database::getManager()->getRepository(Message::class);
292
            while ($row = Database::fetch_array($result)) {
293
                $message = $repo->find($row['id']);
294
                $messages[] = $message;
295
            }
296
297
            return $messages;
298
        }
299
300
        return [];
301
    }
302
303
    public static function getMessagesAboutUserToString(User $user): string
304
    {
305
        $messages = self::getMessagesAboutUser($user);
306
        $html = '';
307
        if (!empty($messages)) {
308
            /** @var Message $message */
309
            foreach ($messages as $message) {
310
                $tag = 'message_'.$message->getId();
311
                $tagAccordion = 'accordion_'.$message->getId();
312
                $tagCollapse = 'collapse_'.$message->getId();
313
                $date = Display::dateToStringAgoAndLongDate(
314
                    $message->getSendDate()
315
                );
316
                $localTime = api_get_local_time(
317
                    $message->getSendDate(),
318
                    null,
319
                    null,
320
                    false,
321
                    false
322
                );
323
                $senderId = $message->getUserSender()->getId();
324
                $senderInfo = api_get_user_info($senderId);
325
                $html .= Display::panelCollapse(
326
                    $localTime.' '.$senderInfo['complete_name'].' '.$message->getTitle(),
327
                    $message->getContent().'<br />'.$date.'<br />'.get_lang(
328
                        'Author'
329
                    ).': '.$senderInfo['complete_name_with_message_link'],
330
                    $tag,
331
                    null,
332
                    $tagAccordion,
333
                    $tagCollapse,
334
                    false
335
                );
336
            }
337
        }
338
339
        return $html;
340
    }
341
342
    /**
343
     * @param int    $senderId
344
     * @param int    $receiverId
345
     * @param string $subject
346
     * @param string $message
347
     *
348
     * @return bool
349
     */
350
    public static function messageWasAlreadySent($senderId, $receiverId, $subject, $message)
351
    {
352
        $table = Database::get_main_table(TABLE_MESSAGE);
353
        $senderId = (int) $senderId;
354
        $receiverId = (int) $receiverId;
355
        $subject = Database::escape_string($subject);
356
        $message = Database::escape_string($message);
357
358
        $sql = "SELECT * FROM $table
359
                WHERE
360
                    user_sender_id = $senderId AND
361
                    user_receiver_id = $receiverId AND
362
                    title = '$subject' AND
363
                    content = '$message' AND
364
                    (msg_status = ".MESSAGE_STATUS_UNREAD." OR msg_status = ".MESSAGE_STATUS_NEW.")
365
                ";
366
        $result = Database::query($sql);
367
368
        return Database::num_rows($result) > 0;
369
    }
370
371
    /**
372
     * Sends a message to a user/group.
373
     *
374
     * @param int    $receiverUserId
375
     * @param string $subject
376
     * @param string $content
377
     * @param array  $attachments                files array($_FILES) (optional)
378
     * @param array  $fileCommentList            about attachment files (optional)
379
     * @param int    $group_id                   (optional)
380
     * @param int    $parent_id                  (optional)
381
     * @param int    $editMessageId              id for updating the message (optional)
382
     * @param int    $topic_id                   (optional) the default value is the current user_id
383
     * @param int    $sender_id
384
     * @param bool   $directMessage
385
     * @param int    $forwardId
386
     * @param array  $smsParameters
387
     * @param bool   $checkCurrentAudioId
388
     * @param bool   $forceTitleWhenSendingEmail force the use of $title as subject instead of "You have a new message"
389
     * @param int    $status                     Message status
390
     *
391
     * @return bool
392
     */
393
    public static function send_message(
394
        $receiverUserId,
395
        $subject,
396
        $content,
397
        array $attachments = [],
398
        array $fileCommentList = [],
399
        $group_id = 0,
400
        $parent_id = 0,
401
        $editMessageId = 0,
402
        $topic_id = 0,
403
        $sender_id = 0,
404
        $directMessage = false,
405
        $forwardId = 0,
406
        $smsParameters = [],
407
        $checkCurrentAudioId = false,
408
        $forceTitleWhenSendingEmail = false,
409
        $status = 0
410
    ) {
411
        $group_id = (int) $group_id;
412
        $receiverUserId = (int) $receiverUserId;
413
        $parent_id = (int) $parent_id;
414
        $editMessageId = (int) $editMessageId;
415
        $topic_id = (int) $topic_id;
416
        $status = empty($status) ? MESSAGE_STATUS_UNREAD : (int) $status;
417
        $user_sender_id = empty($sender_id) ? api_get_user_id() : (int) $sender_id;
418
419
        if (empty($user_sender_id) || empty($receiverUserId)) {
420
            return false;
421
        }
422
423
        $userSender = api_get_user_entity($user_sender_id);
424
        if (null === $userSender) {
425
            Display::addFlash(Display::return_message(get_lang('This user doesn\'t exist'), 'warning'));
426
427
            return false;
428
        }
429
430
        $userRecipient = api_get_user_entity($receiverUserId);
431
432
        if (null === $userRecipient) {
433
            return false;
434
        }
435
436
        // Disabling messages for inactive users.
437
        if (!$userRecipient->getActive()) {
438
            return false;
439
        }
440
441
        $sendEmail = true;
442
        // Disabling messages depending the pausetraining plugin.
443
        $allowPauseFormation =
444
            'true' === api_get_plugin_setting('pausetraining', 'tool_enable') &&
445
            'true' === api_get_plugin_setting('pausetraining', 'allow_users_to_edit_pause_formation');
446
447
        if ($allowPauseFormation) {
448
            $extraFieldValue = new ExtraFieldValue('user');
449
            $disableEmails = $extraFieldValue->get_values_by_handler_and_field_variable(
450
                $receiverUserId,
451
                'disable_emails'
452
            );
453
454
            // User doesn't want email notifications but chamilo inbox still available.
455
            if (!empty($disableEmails) &&
456
                isset($disableEmails['value']) && 1 === (int) $disableEmails['value']
457
            ) {
458
                $sendEmail = false;
459
            }
460
461
            if ($sendEmail) {
462
                // Check if user pause his formation.
463
                $pause = $extraFieldValue->get_values_by_handler_and_field_variable(
464
                    $receiverUserId,
465
                    'pause_formation'
466
                );
467
                if (!empty($pause) && isset($pause['value']) && 1 === (int) $pause['value']) {
468
                    $startDate = $extraFieldValue->get_values_by_handler_and_field_variable(
469
                        $receiverUserId,
470
                        'start_pause_date'
471
                    );
472
                    $endDate = $extraFieldValue->get_values_by_handler_and_field_variable(
473
                        $receiverUserId,
474
                        'end_pause_date'
475
                    );
476
477
                    if (!empty($startDate) && isset($startDate['value']) && !empty($startDate['value']) &&
478
                        !empty($endDate) && isset($endDate['value']) && !empty($endDate['value'])
479
                    ) {
480
                        $now = time();
481
                        $start = api_strtotime($startDate['value']);
482
                        $end = api_strtotime($endDate['value']);
483
484
                        if ($now > $start && $now < $end) {
485
                            $sendEmail = false;
486
                        }
487
                    }
488
                }
489
            }
490
        }
491
492
        $totalFileSize = 0;
493
        $attachmentList = [];
494
        if (is_array($attachments)) {
495
            $counter = 0;
496
            foreach ($attachments as $attachment) {
497
                $attachment['comment'] = $fileCommentList[$counter] ?? '';
498
                $fileSize = $attachment['size'] ?? 0;
499
                if (is_array($fileSize)) {
500
                    foreach ($fileSize as $size) {
501
                        $totalFileSize += $size;
502
                    }
503
                } else {
504
                    $totalFileSize += $fileSize;
505
                }
506
                $attachmentList[] = $attachment;
507
                $counter++;
508
            }
509
        }
510
511
        if ($checkCurrentAudioId) {
512
            // Add the audio file as an attachment
513
            $audio = Session::read('current_audio');
514
            if (!empty($audio) && isset($audio['name']) && !empty($audio['name'])) {
515
                $audio['comment'] = 'audio_message';
516
                // create attachment from audio message
517
                $attachmentList[] = $audio;
518
            }
519
        }
520
521
        // Validating fields
522
        if (empty($subject) && empty($group_id)) {
523
            Display::addFlash(
524
                Display::return_message(
525
                    get_lang('You should write a subject'),
526
                    'warning'
527
                )
528
            );
529
530
            return false;
531
        } elseif ($totalFileSize > (int) api_get_setting('message_max_upload_filesize')) {
532
            $warning = sprintf(
533
                get_lang('Files size exceeds'),
534
                format_file_size(api_get_setting('message_max_upload_filesize'))
535
            );
536
537
            Display::addFlash(Display::return_message($warning, 'warning'));
538
539
            return false;
540
        }
541
542
        $em = Database::getManager();
543
        $repo = $em->getRepository(Message::class);
544
        $parent = null;
545
        if (!empty($parent_id)) {
546
            $parent = $repo->find($parent_id);
547
        }
548
549
        $message = null;
550
        // Just in case we replace the and \n and \n\r while saving in the DB
551
        if (!empty($receiverUserId) || !empty($group_id)) {
552
            // message for user friend
553
            //@todo it's possible to edit a message? yes, only for groups
554
            if (!empty($editMessageId)) {
555
                $message = $repo->find($editMessageId);
556
                if (null !== $message) {
557
                    $message->setContent($content);
558
                    $em->persist($message);
559
                    $em->flush();
560
                }
561
                $messageId = $editMessageId;
562
            } else {
563
                $message = new Message();
564
                $message
565
                    ->setUserSender($userSender)
566
                    ->setUserReceiver($userRecipient)
567
                    ->setMsgType($status)
568
                    ->setTitle($subject)
569
                    ->setContent($content)
570
                    ->setGroup(api_get_group_entity($group_id))
571
                    ->setParent($parent)
572
                ;
573
                $em->persist($message);
574
                $em->flush();
575
                $messageId = $message->getId();
576
            }
577
578
            // Forward also message attachments.
579
            if (!empty($forwardId)) {
580
                $forwardMessage = $repo->find($forwardId);
581
                if (null !== $forwardMessage) {
582
                    $forwardAttachments = $forwardMessage->getAttachments();
583
                    foreach ($forwardAttachments as $forwardAttachment) {
584
                        $message->addAttachment($forwardAttachment);
585
                    }
586
                    $em->persist($message);
587
                    $em->flush();
588
                }
589
            }
590
591
            // Save attachment file for inbox messages
592
            if (is_array($attachmentList)) {
593
                foreach ($attachmentList as $attachment) {
594
                    if (0 === $attachment['error']) {
595
                        self::saveMessageAttachmentFile(
596
                            $attachment,
597
                            $attachment['comment'] ?? '',
598
                            $message,
599
                        );
600
                    }
601
                }
602
            }
603
604
            if ($sendEmail) {
605
                $notification = new Notification();
606
                $sender_info = api_get_user_info($user_sender_id);
607
608
                // add file attachment additional attributes
609
                $attachmentAddedByMail = [];
610
                foreach ($attachmentList as $attachment) {
611
                    $attachmentAddedByMail[] = [
612
                        'path' => $attachment['tmp_name'],
613
                        'filename' => $attachment['name'],
614
                    ];
615
                }
616
617
                if (empty($group_id)) {
618
                    $type = Notification::NOTIFICATION_TYPE_MESSAGE;
619
                    if ($directMessage) {
620
                        $type = Notification::NOTIFICATION_TYPE_DIRECT_MESSAGE;
621
                    }
622
                    $notification->saveNotification(
623
                        $messageId,
624
                        $type,
625
                        [$receiverUserId],
626
                        $subject,
627
                        $content,
628
                        $sender_info,
629
                        $attachmentAddedByMail,
630
                        $smsParameters,
631
                        $forceTitleWhenSendingEmail
632
                    );
633
                } else {
634
                    $usergroup = new UserGroupModel();
635
                    $group_info = $usergroup->get($group_id);
636
                    $group_info['topic_id'] = $topic_id;
637
                    $group_info['msg_id'] = $messageId;
638
639
                    $user_list = $usergroup->get_users_by_group(
640
                        $group_id,
641
                        false,
642
                        [],
643
                        0,
644
                        1000
645
                    );
646
647
                    // Adding more sense to the message group
648
                    $subject = sprintf(get_lang('There is a new message in group %s'), $group_info['name']);
649
                    $new_user_list = [];
650
                    foreach ($user_list as $user_data) {
651
                        $new_user_list[] = $user_data['id'];
652
                    }
653
                    $group_info = [
654
                        'group_info' => $group_info,
655
                        'user_info' => $sender_info,
656
                    ];
657
                    $notification->saveNotification(
658
                        $messageId,
659
                        Notification::NOTIFICATION_TYPE_GROUP,
660
                        $new_user_list,
661
                        $subject,
662
                        $content,
663
                        $group_info,
664
                        $attachmentAddedByMail,
665
                        $smsParameters
666
                    );
667
                }
668
            }
669
670
            return $messageId;
671
        }
672
673
        return false;
674
    }
675
676
    /**
677
     * @param int    $receiverUserId
678
     * @param string $subject
679
     * @param string $message
680
     * @param int    $sender_id
681
     * @param bool   $sendCopyToDrhUsers send copy to related DRH users
682
     * @param bool   $directMessage
683
     * @param array  $smsParameters
684
     * @param bool   $uploadFiles        Do not upload files using the MessageManager class
685
     * @param array  $attachmentList
686
     *
687
     * @return bool
688
     */
689
    public static function send_message_simple(
690
        $receiverUserId,
691
        $subject,
692
        $message,
693
        $sender_id = 0,
694
        $sendCopyToDrhUsers = false,
695
        $directMessage = false,
696
        $smsParameters = [],
697
        $uploadFiles = true,
698
        $attachmentList = []
699
    ) {
700
        $files = $_FILES ? $_FILES : [];
701
        if (false === $uploadFiles) {
702
            $files = [];
703
        }
704
        // $attachmentList must have: tmp_name, name, size keys
705
        if (!empty($attachmentList)) {
706
            $files = $attachmentList;
707
        }
708
        $result = self::send_message(
709
            $receiverUserId,
710
            $subject,
711
            $message,
712
            $files,
713
            [],
714
            null,
715
            null,
716
            null,
717
            null,
718
            $sender_id,
719
            $directMessage,
720
            0,
721
            $smsParameters
722
        );
723
724
        if ($sendCopyToDrhUsers) {
725
            $userInfo = api_get_user_info($receiverUserId);
726
            $drhList = UserManager::getDrhListFromUser($receiverUserId);
727
            if (!empty($drhList)) {
728
                foreach ($drhList as $drhInfo) {
729
                    $message = sprintf(
730
                        get_lang('Copy of message sent to %s'),
731
                        $userInfo['complete_name']
732
                    ).' <br />'.$message;
733
734
                    self::send_message_simple(
735
                        $drhInfo['id'],
736
                        $subject,
737
                        $message,
738
                        $sender_id,
739
                        false,
740
                        $directMessage
741
                    );
742
                }
743
            }
744
        }
745
746
        return $result;
747
    }
748
749
    /**
750
     * @param int $user_receiver_id
751
     * @param int $id
752
     *
753
     * @return bool
754
     */
755
    public static function delete_message_by_user_receiver($user_receiver_id, $id)
756
    {
757
        $id = (int) $id;
758
        $user_receiver_id = (int) $user_receiver_id;
759
760
        if (empty($id) || empty($user_receiver_id)) {
761
            return false;
762
        }
763
764
        $em = Database::getManager();
765
        $repo = $em->getRepository(Message::class);
766
        $criteria = ['id' => $id, 'userReceiver' => $user_receiver_id];
767
        /** @var Message $message */
768
        $message = $repo->findOneBy($criteria);
769
770
        if (null === $message || ($message && MESSAGE_STATUS_OUTBOX === $message->getMsgType())) {
771
            return false;
772
        }
773
774
        $message->setMsgStatus(MESSAGE_STATUS_DELETED);
775
        $attachments = $message->getAttachments();
776
        if (!empty($attachments)) {
777
            $repo = Container::getMessageAttachmentRepository();
778
            foreach ($attachments as $file) {
779
                $repo->softDelete($file);
780
            }
781
        }
782
        $em->persist($message);
783
        $em->flush();
784
785
        /*
786
        // Delete attachment file.
787
        self::delete_message_attachment_file($id, $user_receiver_id);
788
        // Soft delete message.
789
        $query = "UPDATE $table
790
                  SET msg_status = ".MESSAGE_STATUS_DELETED."
791
                  WHERE
792
                    id = $id AND
793
                    user_receiver_id = $user_receiver_id ";
794
        Database::query($query);*/
795
796
        return true;
797
    }
798
799
    /**
800
     * Set status deleted.
801
     *
802
     * @author Isaac FLores Paz <[email protected]>
803
     *
804
     * @param  int
805
     * @param  int
806
     *
807
     * @return bool
808
     */
809
    public static function delete_message_by_user_sender($user_sender_id, $id)
810
    {
811
        $user_sender_id = (int) $user_sender_id;
812
        $id = (int) $id;
813
814
        if (empty($id) || empty($user_sender_id)) {
815
            return false;
816
        }
817
        $em = Database::getManager();
818
        $repo = $em->getRepository(Message::class);
819
        $criteria = ['id' => $id, 'userSender' => $user_sender_id];
820
        $message = $repo->findOneBy($criteria);
821
822
        /*$table = Database::get_main_table(TABLE_MESSAGE);
823
        $sql = "SELECT * FROM $table WHERE id = $id AND user_sender_id= $user_sender_id";
824
        $rs = Database::query($sql);*/
825
826
        if (null !== $message) {
827
            // delete attachment file
828
            //self::delete_message_attachment_file($id, $user_sender_id);
829
            $message->setMsgStatus(MESSAGE_STATUS_DELETED);
830
            self::softDeleteAttachments($message);
831
            $em->persist($message);
832
            $em->flush();
833
834
            return true;
835
        }
836
837
        return false;
838
    }
839
840
    public static function softDeleteAttachments(Message $message): void
841
    {
842
        $attachments = $message->getAttachments();
843
        if (!empty($attachments)) {
844
            $repo = Container::getMessageAttachmentRepository();
845
            foreach ($attachments as $file) {
846
                $repo->softDelete($file);
847
            }
848
        }
849
    }
850
851
    /**
852
     * Saves a message attachment files.
853
     *
854
     * @param array  $file    $_FILES['name']
855
     * @param string $comment a comment about the uploaded file
856
     */
857
    public static function saveMessageAttachmentFile($file, $comment, Message $message)
858
    {
859
        // Try to add an extension to the file if it hasn't one
860
        $type = $file['type'] ?? '';
861
        if (empty($type)) {
862
            $type = DocumentManager::file_get_mime_type($file['name']);
863
        }
864
        $new_file_name = add_ext_on_mime(stripslashes($file['name']), $type);
865
866
        // user's file name
867
        $fileName = $file['name'];
868
        if (!filter_extension($new_file_name)) {
869
            Display::addFlash(
870
                Display::return_message(
871
                    get_lang('File upload failed: this file extension or file type is prohibited'),
872
                    'error'
873
                )
874
            );
875
876
            return false;
877
        }
878
879
        $em = Database::getManager();
880
        $attachmentRepo = Container::getMessageAttachmentRepository();
881
882
        $attachment = new MessageAttachment();
883
        $attachment
884
            ->setSize($file['size'])
885
            ->setPath($fileName)
886
            ->setFilename($fileName)
887
            ->setComment($comment)
888
            ->setParent($message->getUserSender())
889
            ->setMessage($message)
890
        ;
891
892
        $request = Container::getRequest();
893
        $fileToUpload = null;
894
895
        // Search for files inside the $_FILES, when uploading several files from the form.
896
        if ($request->files->count()) {
897
            /** @var UploadedFile|null $fileRequest */
898
            foreach ($request->files->all() as $fileRequest) {
899
                if (null === $fileRequest) {
900
                    continue;
901
                }
902
                if ($fileRequest->getClientOriginalName() === $file['name']) {
903
                    $fileToUpload = $fileRequest;
904
                    break;
905
                }
906
            }
907
        }
908
909
        // If no found file, try with $file['content'].
910
        if (null === $fileToUpload && isset($file['content'])) {
911
            $handle = tmpfile();
912
            fwrite($handle, $file['content']);
913
            $meta = stream_get_meta_data($handle);
914
            $fileToUpload = new UploadedFile($meta['uri'], $fileName, $file['type'], null, true);
915
        }
916
917
        if (null !== $fileToUpload) {
918
            $em->persist($attachment);
919
            $attachmentRepo->addFile($attachment, $fileToUpload);
920
            $attachment->addUserLink($message->getUserSender());
921
            $attachment->addUserLink($message->getUserReceiver());
922
            $em->flush();
923
924
            return true;
925
        }
926
927
        return false;
928
    }
929
930
    /**
931
     * @param int $user_id
932
     * @param int $message_id
933
     * @param int $type
934
     *
935
     * @return bool
936
     */
937
    public static function update_message_status($user_id, $message_id, $type)
938
    {
939
        $user_id = (int) $user_id;
940
        $message_id = (int) $message_id;
941
        $type = (int) $type;
942
943
        if (empty($user_id) || empty($message_id)) {
944
            return false;
945
        }
946
947
        $table_message = Database::get_main_table(TABLE_MESSAGE);
948
        $sql = "UPDATE $table_message SET
949
                    msg_status = '$type'
950
                WHERE
951
                    user_receiver_id = ".$user_id." AND
952
                    id = '".$message_id."'";
953
        $result = Database::query($sql);
954
955
        return Database::affected_rows($result) > 0;
956
    }
957
958
    /**
959
     * get messages by group id.
960
     *
961
     * @param int $group_id group id
962
     *
963
     * @return array
964
     */
965
    public static function get_messages_by_group($group_id)
966
    {
967
        $group_id = (int) $group_id;
968
969
        if (empty($group_id)) {
970
            return false;
971
        }
972
973
        $table = Database::get_main_table(TABLE_MESSAGE);
974
        $sql = "SELECT * FROM $table
975
                WHERE
976
                    group_id= $group_id AND
977
                    msg_status NOT IN ('".MESSAGE_STATUS_OUTBOX."', '".MESSAGE_STATUS_DELETED."')
978
                ORDER BY id";
979
        $rs = Database::query($sql);
980
        $data = [];
981
        if (Database::num_rows($rs) > 0) {
982
            while ($row = Database::fetch_array($rs, 'ASSOC')) {
983
                $data[] = $row;
984
            }
985
        }
986
987
        return $data;
988
    }
989
990
    /**
991
     * get messages by group id.
992
     *
993
     * @param int $group_id
994
     * @param int $message_id
995
     *
996
     * @return array
997
     */
998
    public static function get_messages_by_group_by_message($group_id, $message_id)
999
    {
1000
        $group_id = (int) $group_id;
1001
1002
        if (empty($group_id)) {
1003
            return false;
1004
        }
1005
1006
        $table = Database::get_main_table(TABLE_MESSAGE);
1007
        $sql = "SELECT * FROM $table
1008
                WHERE
1009
                    group_id = $group_id AND
1010
                    msg_status NOT IN ('".MESSAGE_STATUS_OUTBOX."', '".MESSAGE_STATUS_DELETED."')
1011
                ORDER BY id ";
1012
1013
        $rs = Database::query($sql);
1014
        $data = [];
1015
        $parents = [];
1016
        if (Database::num_rows($rs) > 0) {
1017
            while ($row = Database::fetch_array($rs, 'ASSOC')) {
1018
                if ($message_id == $row['parent_id'] || in_array($row['parent_id'], $parents)) {
1019
                    $parents[] = $row['id'];
1020
                    $data[] = $row;
1021
                }
1022
            }
1023
        }
1024
1025
        return $data;
1026
    }
1027
1028
    /**
1029
     * Get messages by parent id optionally with limit.
1030
     *
1031
     * @param  int        parent id
1032
     * @param  int        group id (optional)
1033
     * @param  int        offset (optional)
1034
     * @param  int        limit (optional)
1035
     *
1036
     * @return array
1037
     */
1038
    public static function getMessagesByParent($parentId, $groupId = 0, $offset = 0, $limit = 0)
1039
    {
1040
        $table = Database::get_main_table(TABLE_MESSAGE);
1041
        $parentId = (int) $parentId;
1042
1043
        if (empty($parentId)) {
1044
            return [];
1045
        }
1046
1047
        $condition_group_id = '';
1048
        if (!empty($groupId)) {
1049
            $groupId = (int) $groupId;
1050
            $condition_group_id = " AND group_id = '$groupId' ";
1051
        }
1052
1053
        $condition_limit = '';
1054
        if ($offset && $limit) {
1055
            $offset = (int) $offset;
1056
            $limit = (int) $limit;
1057
            $offset = ($offset - 1) * $limit;
1058
            $condition_limit = " LIMIT $offset,$limit ";
1059
        }
1060
1061
        $sql = "SELECT * FROM $table
1062
                WHERE
1063
                    parent_id='$parentId' AND
1064
                    msg_status NOT IN (".MESSAGE_STATUS_OUTBOX.", ".MESSAGE_STATUS_WALL_DELETE.")
1065
                    $condition_group_id
1066
                ORDER BY send_date DESC $condition_limit ";
1067
        $rs = Database::query($sql);
1068
        $data = [];
1069
        if (Database::num_rows($rs) > 0) {
1070
            while ($row = Database::fetch_array($rs)) {
1071
                $data[$row['id']] = $row;
1072
            }
1073
        }
1074
1075
        return $data;
1076
    }
1077
1078
    /**
1079
     * Gets information about messages sent.
1080
     *
1081
     * @param int
1082
     * @param int
1083
     * @param string
1084
     * @param string
1085
     *
1086
     * @return array
1087
     */
1088
    public static function get_message_data_sent(
1089
        $from,
1090
        $numberOfItems,
1091
        $column,
1092
        $direction,
1093
        $extraParams = []
1094
    ) {
1095
        $from = (int) $from;
1096
        $numberOfItems = (int) $numberOfItems;
1097
        if (!isset($direction)) {
1098
            $column = 2;
1099
            $direction = 'DESC';
1100
        } else {
1101
            $column = (int) $column;
1102
            if (!in_array($direction, ['ASC', 'DESC'])) {
1103
                $direction = 'ASC';
1104
            }
1105
        }
1106
1107
        if (!in_array($column, [0, 1, 2])) {
1108
            $column = 2;
1109
        }
1110
        $table = Database::get_main_table(TABLE_MESSAGE);
1111
        $request = api_is_xml_http_request();
1112
        $keyword = isset($extraParams['keyword']) && !empty($extraParams['keyword']) ? $extraParams['keyword'] : '';
1113
        $keywordCondition = '';
1114
        if (!empty($keyword)) {
1115
            $keyword = Database::escape_string($keyword);
1116
            $keywordCondition = " AND (title like '%$keyword%' OR content LIKE '%$keyword%') ";
1117
        }
1118
1119
        $sql = "SELECT
1120
                    id as col0,
1121
                    title as col1,
1122
                    send_date as col2,
1123
                    user_receiver_id,
1124
                    msg_status,
1125
                    user_sender_id
1126
                FROM $table
1127
                WHERE
1128
                    user_sender_id = ".api_get_user_id()." AND
1129
                    msg_status = ".MESSAGE_STATUS_OUTBOX."
1130
                    $keywordCondition
1131
                ORDER BY col$column $direction
1132
                LIMIT $from, $numberOfItems";
1133
        $result = Database::query($sql);
1134
1135
        $message_list = [];
1136
        while ($row = Database::fetch_array($result, 'ASSOC')) {
1137
            $messageId = $row['col0'];
1138
            $title = $row['col1'];
1139
            $sendDate = $row['col2'];
1140
            $senderId = $row['user_sender_id'];
1141
1142
            if (true === $request) {
1143
                $message[0] = '<input type="checkbox" value='.$messageId.' name="out[]">';
1144
            } else {
1145
                $message[0] = $messageId;
1146
            }
1147
1148
            $class = 'class = "read"';
1149
            $title = Security::remove_XSS($title);
1150
            $userInfo = api_get_user_info($senderId);
1151
            if (true === $request) {
1152
                $message[1] = '<a onclick="show_sent_message('.$messageId.')" href="javascript:void(0)">'.
1153
                    $userInfo['complete_name_with_username'].'</a>';
1154
                $message[2] = '<a onclick="show_sent_message('.$messageId.')" href="javascript:void(0)">'.str_replace(
1155
                        "\\",
1156
                        "",
1157
                        $title
1158
                    ).'</a>';
1159
                //date stays the same
1160
                $message[3] = api_convert_and_format_date($sendDate, DATE_TIME_FORMAT_LONG);
1161
                $message[4] = '&nbsp;&nbsp;<a title="'.addslashes(
1162
                        get_lang('Delete message')
1163
                    ).'" onclick="delete_one_message_outbox('.$messageId.')" href="javascript:void(0)"  >'.
1164
                    Display::returnFontAwesomeIcon('trash', 2).'</a>';
1165
            } else {
1166
                $message[1] = '<a '.$class.' onclick="show_sent_message('.$messageId.')" href="../messages/view_message.php?id_send='.$messageId.'">'.$title.'</a><br />'.$userInfo['complete_name_with_username'];
1167
                $message[2] = api_convert_and_format_date($sendDate, DATE_TIME_FORMAT_LONG);
1168
                $message[3] = '<a title="'.addslashes(
1169
                        get_lang('Delete message')
1170
                    ).'" href="outbox.php?action=deleteone&id='.$messageId.'"  onclick="javascript:if(!confirm('."'".addslashes(
1171
                        api_htmlentities(get_lang('ConfirmDelete message'))
1172
                    )."'".')) return false;" >'.
1173
                    Display::returnFontAwesomeIcon('trash', 2).'</a>';
1174
            }
1175
1176
            $message_list[] = $message;
1177
        }
1178
1179
        return $message_list;
1180
    }
1181
1182
    /**
1183
     * Displays messages of a group with nested view.
1184
     *
1185
     * @param int $groupId
1186
     *
1187
     * @return string
1188
     */
1189
    public static function display_messages_for_group($groupId)
1190
    {
1191
        global $my_group_role;
1192
1193
        $rows = self::get_messages_by_group($groupId);
1194
        $topics_per_page = 10;
1195
        $html_messages = '';
1196
        $query_vars = ['id' => $groupId, 'topics_page_nr' => 0];
1197
1198
        if (is_array($rows) && count($rows) > 0) {
1199
            // prepare array for topics with its items
1200
            $topics = [];
1201
            $x = 0;
1202
            foreach ($rows as $index => $value) {
1203
                if (empty($value['parent_id'])) {
1204
                    $topics[$value['id']] = $value;
1205
                }
1206
            }
1207
1208
            $new_topics = [];
1209
1210
            foreach ($topics as $id => $value) {
1211
                $rows = null;
1212
                $rows = self::get_messages_by_group_by_message($groupId, $value['id']);
1213
                if (!empty($rows)) {
1214
                    $count = count(self::calculate_children($rows, $value['id']));
1215
                } else {
1216
                    $count = 0;
1217
                }
1218
                $value['count'] = $count;
1219
                $new_topics[$id] = $value;
1220
            }
1221
1222
            $array_html = [];
1223
            foreach ($new_topics as $index => $topic) {
1224
                $html = '';
1225
                // topics
1226
                $user_sender_info = api_get_user_info($topic['user_sender_id']);
1227
                $name = $user_sender_info['complete_name'];
1228
                $html .= '<div class="groups-messages">';
1229
                $html .= '<div class="row">';
1230
1231
                $items = $topic['count'];
1232
                $reply_label = (1 == $items) ? get_lang('Reply') : get_lang('Replies');
1233
                $label = '<i class="fa fa-envelope"></i> '.$items.' '.$reply_label;
1234
                $topic['title'] = trim($topic['title']);
1235
1236
                if (empty($topic['title'])) {
1237
                    $topic['title'] = get_lang('Untitled');
1238
                }
1239
1240
                $html .= '<div class="col-xs-8 col-md-10">';
1241
                $html .= Display::tag(
1242
                    'h4',
1243
                    Display::url(
1244
                        Security::remove_XSS($topic['title'], STUDENT, true),
1245
                        api_get_path(WEB_CODE_PATH).'social/group_topics.php?id='.$groupId.'&topic_id='.$topic['id']
1246
                    ),
1247
                    ['class' => 'title']
1248
                );
1249
                $actions = '';
1250
                if (GROUP_USER_PERMISSION_ADMIN == $my_group_role ||
1251
                    GROUP_USER_PERMISSION_MODERATOR == $my_group_role
1252
                ) {
1253
                    $actions = '<br />'.Display::url(
1254
                            get_lang('Delete'),
1255
                            api_get_path(
1256
                                WEB_CODE_PATH
1257
                            ).'social/group_topics.php?action=delete&id='.$groupId.'&topic_id='.$topic['id'],
1258
                            ['class' => 'btn btn-default']
1259
                        );
1260
                }
1261
1262
                $date = '';
1263
                if ($topic['send_date'] != $topic['update_date']) {
1264
                    if (!empty($topic['update_date'])) {
1265
                        $date .= '<i class="fa fa-calendar"></i> '.get_lang(
1266
                                'LastUpdate'
1267
                            ).' '.Display::dateToStringAgoAndLongDate($topic['update_date']);
1268
                    }
1269
                } else {
1270
                    $date .= '<i class="fa fa-calendar"></i> '.get_lang(
1271
                            'Created'
1272
                        ).' '.Display::dateToStringAgoAndLongDate($topic['send_date']);
1273
                }
1274
                $html .= '<div class="date">'.$label.' - '.$date.$actions.'</div>';
1275
                $html .= '</div>';
1276
1277
                $image = $user_sender_info['avatar'];
1278
1279
                $user_info = '<div class="author"><img class="img-responsive img-circle" src="'.$image.'" alt="'.$name.'"  width="64" height="64" title="'.$name.'" /></div>';
1280
                $user_info .= '<div class="name"><a href="'.api_get_path(
1281
                        WEB_PATH
1282
                    ).'main/social/profile.php?u='.$topic['user_sender_id'].'">'.$name.'&nbsp;</a></div>';
1283
1284
                $html .= '<div class="col-xs-4 col-md-2">';
1285
                $html .= $user_info;
1286
                $html .= '</div>';
1287
                $html .= '</div>';
1288
                $html .= '</div>';
1289
1290
                $array_html[] = [$html];
1291
            }
1292
1293
            // grids for items and topics  with paginations
1294
            $html_messages .= Display::return_sortable_grid(
1295
                'topics',
1296
                [],
1297
                $array_html,
1298
                [
1299
                    'hide_navigation' => false,
1300
                    'per_page' => $topics_per_page,
1301
                ],
1302
                $query_vars,
1303
                false,
1304
                [true, true, true, false],
1305
                false
1306
            );
1307
        }
1308
1309
        return $html_messages;
1310
    }
1311
1312
    /**
1313
     * Displays messages of a group with nested view.
1314
     *
1315
     * @param $groupId
1316
     * @param $topic_id
1317
     *
1318
     * @return string
1319
     */
1320
    public static function display_message_for_group($groupId, $topic_id)
1321
    {
1322
        global $my_group_role;
1323
        $main_message = self::get_message_by_id($topic_id);
1324
        if (empty($main_message)) {
1325
            return false;
1326
        }
1327
1328
        $webCodePath = api_get_path(WEB_CODE_PATH);
1329
        $iconCalendar = Display::returnFontAwesomeIcon('calendar');
1330
1331
        $langEdit = get_lang('Edit');
1332
        $langReply = get_lang('Reply');
1333
        $langLastUpdated = get_lang('LastUpdated');
1334
        $langCreated = get_lang('Created');
1335
1336
        $rows = self::get_messages_by_group_by_message($groupId, $topic_id);
1337
        $rows = self::calculate_children($rows, $topic_id);
1338
        $current_user_id = api_get_user_id();
1339
1340
        $items_per_page = 50;
1341
        $query_vars = ['id' => $groupId, 'topic_id' => $topic_id, 'topics_page_nr' => 0];
1342
1343
        // Main message
1344
        $links = '';
1345
        $main_content = '';
1346
        $html = '';
1347
        $items_page_nr = null;
1348
1349
        $user_sender_info = api_get_user_info($main_message['user_sender_id']);
1350
        $filesAttachments = self::getAttachmentLinkList($main_message['id'], 0);
1351
        $name = $user_sender_info['complete_name'];
1352
1353
        $topic_page_nr = isset($_GET['topics_page_nr']) ? (int) $_GET['topics_page_nr'] : null;
1354
1355
        $links .= '<div class="pull-right">';
1356
        $links .= '<div class="btn-group btn-group-sm">';
1357
1358
        if ((GROUP_USER_PERMISSION_ADMIN == $my_group_role || GROUP_USER_PERMISSION_MODERATOR == $my_group_role) ||
1359
            $main_message['user_sender_id'] == $current_user_id
1360
        ) {
1361
            $urlEdit = $webCodePath.'social/message_for_group_form.inc.php?'
1362
                .http_build_query(
1363
                    [
1364
                        'user_friend' => $current_user_id,
1365
                        'group_id' => $groupId,
1366
                        'message_id' => $main_message['id'],
1367
                        'action' => 'edit_message_group',
1368
                        'anchor_topic' => 'topic_'.$main_message['id'],
1369
                        'topics_page_nr' => $topic_page_nr,
1370
                        'items_page_nr' => $items_page_nr,
1371
                        'topic_id' => $main_message['id'],
1372
                    ]
1373
                );
1374
1375
            $links .= Display::toolbarButton(
1376
                $langEdit,
1377
                $urlEdit,
1378
                'pencil',
1379
                'default',
1380
                ['class' => 'ajax', 'data-title' => $langEdit, 'data-size' => 'lg'],
1381
                false
1382
            );
1383
        }
1384
1385
        $links .= self::getLikesButton($main_message['id'], $current_user_id, $groupId);
1386
1387
        $urlReply = $webCodePath.'social/message_for_group_form.inc.php?'
1388
            .http_build_query(
1389
                [
1390
                    'user_friend' => $current_user_id,
1391
                    'group_id' => $groupId,
1392
                    'message_id' => $main_message['id'],
1393
                    'action' => 'reply_message_group',
1394
                    'anchor_topic' => 'topic_'.$main_message['id'],
1395
                    'topics_page_nr' => $topic_page_nr,
1396
                    'topic_id' => $main_message['id'],
1397
                ]
1398
            );
1399
1400
        $links .= Display::toolbarButton(
1401
            $langReply,
1402
            $urlReply,
1403
            'commenting',
1404
            'default',
1405
            ['class' => 'ajax', 'data-title' => $langReply, 'data-size' => 'lg'],
1406
            false
1407
        );
1408
1409
        if (api_is_platform_admin()) {
1410
            $links .= Display::toolbarButton(
1411
                get_lang('Delete'),
1412
                'group_topics.php?action=delete&id='.$groupId.'&topic_id='.$topic_id,
1413
                'trash',
1414
                'default',
1415
                [],
1416
                false
1417
            );
1418
        }
1419
1420
        $links .= '</div>';
1421
        $links .= '</div>';
1422
1423
        $title = '<h4>'.Security::remove_XSS($main_message['title'], STUDENT, true).$links.'</h4>';
1424
1425
        $userPicture = $user_sender_info['avatar'];
1426
        $main_content .= '<div class="row">';
1427
        $main_content .= '<div class="col-md-2">';
1428
        $main_content .= '<div class="avatar-author">';
1429
        $main_content .= Display::img(
1430
            $userPicture,
1431
            $name,
1432
            ['width' => '60px', 'class' => 'img-responsive img-circle'],
1433
            false
1434
        );
1435
        $main_content .= '</div>';
1436
        $main_content .= '</div>';
1437
1438
        $date = '';
1439
        if ($main_message['send_date'] != $main_message['update_date']) {
1440
            if (!empty($main_message['update_date'])) {
1441
                $date = '<div class="date"> '
1442
                    ."$iconCalendar $langLastUpdated "
1443
                    .Display::dateToStringAgoAndLongDate($main_message['update_date'])
1444
                    .'</div>';
1445
            }
1446
        } else {
1447
            $date = '<div class="date"> '
1448
                ."$iconCalendar $langCreated "
1449
                .Display::dateToStringAgoAndLongDate($main_message['send_date'])
1450
                .'</div>';
1451
        }
1452
        $attachment = '<div class="message-attach">'
1453
            .(!empty($filesAttachments) ? implode('<br />', $filesAttachments) : '')
1454
            .'</div>';
1455
        $main_content .= '<div class="col-md-10">';
1456
        $user_link = Display::url(
1457
            $name,
1458
            $webCodePath.'social/profile.php?u='.$main_message['user_sender_id']
1459
        );
1460
        $main_content .= '<div class="message-content"> ';
1461
        $main_content .= '<div class="username">'.$user_link.'</div>';
1462
        $main_content .= $date;
1463
        $main_content .= '<div class="message">'.$main_message['content'].$attachment.'</div></div>';
1464
        $main_content .= '</div>';
1465
        $main_content .= '</div>';
1466
1467
        $html .= Display::div(
1468
            Display::div(
1469
                $title.$main_content,
1470
                ['class' => 'message-topic']
1471
            ),
1472
            ['class' => 'sm-groups-message']
1473
        );
1474
1475
        $topic_id = $main_message['id'];
1476
1477
        if (is_array($rows) && count($rows) > 0) {
1478
            $topics = $rows;
1479
            $array_html_items = [];
1480
1481
            foreach ($topics as $index => $topic) {
1482
                if (empty($topic['id'])) {
1483
                    continue;
1484
                }
1485
                $items_page_nr = isset($_GET['items_'.$topic['id'].'_page_nr'])
1486
                    ? (int) $_GET['items_'.$topic['id'].'_page_nr']
1487
                    : null;
1488
                $links = '';
1489
                $links .= '<div class="pull-right">';
1490
                $html_items = '';
1491
                $user_sender_info = api_get_user_info($topic['user_sender_id']);
1492
                $filesAttachments = self::getAttachmentLinkList($topic['id'], 0);
1493
                $name = $user_sender_info['complete_name'];
1494
1495
                $links .= '<div class="btn-group btn-group-sm">';
1496
                if (
1497
                    (GROUP_USER_PERMISSION_ADMIN == $my_group_role ||
1498
                        GROUP_USER_PERMISSION_MODERATOR == $my_group_role
1499
                    ) ||
1500
                    $topic['user_sender_id'] == $current_user_id
1501
                ) {
1502
                    $links .= Display::toolbarButton(
1503
                        $langEdit,
1504
                        $webCodePath.'social/message_for_group_form.inc.php?'
1505
                            .http_build_query(
1506
                                [
1507
                                    'user_friend' => $current_user_id,
1508
                                    'group_id' => $groupId,
1509
                                    'message_id' => $topic['id'],
1510
                                    'action' => 'edit_message_group',
1511
                                    'anchor_topic' => 'topic_'.$topic_id,
1512
                                    'topics_page_nr' => $topic_page_nr,
1513
                                    'items_page_nr' => $items_page_nr,
1514
                                    'topic_id' => $topic_id,
1515
                                ]
1516
                            ),
1517
                        'pencil',
1518
                        'default',
1519
                        ['class' => 'ajax', 'data-title' => $langEdit, 'data-size' => 'lg'],
1520
                        false
1521
                    );
1522
                }
1523
1524
                $links .= self::getLikesButton($topic['id'], $current_user_id, $groupId);
1525
1526
                $links .= Display::toolbarButton(
1527
                    $langReply,
1528
                    $webCodePath.'social/message_for_group_form.inc.php?'
1529
                        .http_build_query(
1530
                            [
1531
                                'user_friend' => $current_user_id,
1532
                                'group_id' => $groupId,
1533
                                'message_id' => $topic['id'],
1534
                                'action' => 'reply_message_group',
1535
                                'anchor_topic' => 'topic_'.$topic_id,
1536
                                'topics_page_nr' => $topic_page_nr,
1537
                                'items_page_nr' => $items_page_nr,
1538
                                'topic_id' => $topic_id,
1539
                            ]
1540
                        ),
1541
                    'commenting',
1542
                    'default',
1543
                    ['class' => 'ajax', 'data-title' => $langReply, 'data-size' => 'lg'],
1544
                    false
1545
                );
1546
                $links .= '</div>';
1547
                $links .= '</div>';
1548
1549
                $userPicture = $user_sender_info['avatar'];
1550
                $user_link = Display::url(
1551
                    $name,
1552
                    $webCodePath.'social/profile.php?u='.$topic['user_sender_id']
1553
                );
1554
                $html_items .= '<div class="row">';
1555
                $html_items .= '<div class="col-md-2">';
1556
                $html_items .= '<div class="avatar-author">';
1557
                $html_items .= Display::img(
1558
                    $userPicture,
1559
                    $name,
1560
                    ['width' => '60px', 'class' => 'img-responsive img-circle'],
1561
                    false
1562
                );
1563
                $html_items .= '</div>';
1564
                $html_items .= '</div>';
1565
1566
                $date = '';
1567
                if ($topic['send_date'] != $topic['update_date']) {
1568
                    if (!empty($topic['update_date'])) {
1569
                        $date = '<div class="date"> '
1570
                            ."$iconCalendar $langLastUpdated "
1571
                            .Display::dateToStringAgoAndLongDate($topic['update_date'])
1572
                            .'</div>';
1573
                    }
1574
                } else {
1575
                    $date = '<div class="date"> '
1576
                        ."$iconCalendar $langCreated "
1577
                        .Display::dateToStringAgoAndLongDate($topic['send_date'])
1578
                        .'</div>';
1579
                }
1580
                $attachment = '<div class="message-attach">'
1581
                    .(!empty($filesAttachments) ? implode('<br />', $filesAttachments) : '')
1582
                    .'</div>';
1583
                $html_items .= '<div class="col-md-10">'
1584
                    .'<div class="message-content">'
1585
                    .$links
1586
                    .'<div class="username">'.$user_link.'</div>'
1587
                    .$date
1588
                    .'<div class="message">'
1589
                    .Security::remove_XSS($topic['content'], STUDENT, true)
1590
                    .'</div>'.$attachment.'</div>'
1591
                    .'</div>'
1592
                    .'</div>';
1593
1594
                $base_padding = 20;
1595
1596
                if (0 == $topic['indent_cnt']) {
1597
                    $indent = $base_padding;
1598
                } else {
1599
                    $indent = (int) $topic['indent_cnt'] * $base_padding + $base_padding;
1600
                }
1601
1602
                $html_items = Display::div($html_items, ['class' => 'message-post', 'id' => 'msg_'.$topic['id']]);
1603
                $html_items = Display::div($html_items, ['class' => '', 'style' => 'margin-left:'.$indent.'px']);
1604
                $array_html_items[] = [$html_items];
1605
            }
1606
1607
            // grids for items with paginations
1608
            $options = ['hide_navigation' => false, 'per_page' => $items_per_page];
1609
            $visibility = [true, true, true, false];
1610
1611
            $style_class = [
1612
                'item' => ['class' => 'user-post'],
1613
                'main' => ['class' => 'user-list'],
1614
            ];
1615
            if (!empty($array_html_items)) {
1616
                $html .= Display::return_sortable_grid(
1617
                    'items_'.$topic['id'],
1618
                    [],
1619
                    $array_html_items,
1620
                    $options,
1621
                    $query_vars,
1622
                    null,
1623
                    $visibility,
1624
                    false,
1625
                    $style_class
1626
                );
1627
            }
1628
        }
1629
1630
        return $html;
1631
    }
1632
1633
    /**
1634
     * Add children to messages by id is used for nested view messages.
1635
     *
1636
     * @param array $rows rows of messages
1637
     *
1638
     * @return array $first_seed new list adding the item children
1639
     */
1640
    public static function calculate_children($rows, $first_seed)
1641
    {
1642
        $rows_with_children = [];
1643
        foreach ($rows as $row) {
1644
            $rows_with_children[$row["id"]] = $row;
1645
            $rows_with_children[$row["parent_id"]]["children"][] = $row["id"];
1646
        }
1647
        $rows = $rows_with_children;
1648
        $sorted_rows = [0 => []];
1649
        self::message_recursive_sort($rows, $sorted_rows, $first_seed);
1650
        unset($sorted_rows[0]);
1651
1652
        return $sorted_rows;
1653
    }
1654
1655
    /**
1656
     * Sort recursively the messages, is used for for nested view messages.
1657
     *
1658
     * @param array  original rows of messages
1659
     * @param array  list recursive of messages
1660
     * @param int   seed for calculate the indent
1661
     * @param int   indent for nested view
1662
     */
1663
    public static function message_recursive_sort(
1664
        $rows,
1665
        &$messages,
1666
        $seed = 0,
1667
        $indent = 0
1668
    ) {
1669
        if ($seed > 0 && isset($rows[$seed]["id"])) {
1670
            $messages[$rows[$seed]["id"]] = $rows[$seed];
1671
            $messages[$rows[$seed]["id"]]["indent_cnt"] = $indent;
1672
            $indent++;
1673
        }
1674
1675
        if (isset($rows[$seed]["children"])) {
1676
            foreach ($rows[$seed]["children"] as $child) {
1677
                self::message_recursive_sort($rows, $messages, $child, $indent);
1678
            }
1679
        }
1680
    }
1681
1682
    /**
1683
     * Get array of links (download) for message attachment files.
1684
     *
1685
     * @return array
1686
     */
1687
    public static function getAttachmentLinkList(Message $message)
1688
    {
1689
        $files = $message->getAttachments();
1690
        // get file attachments by message id
1691
        $list = [];
1692
        if ($files) {
0 ignored issues
show
introduced by
$files is of type Doctrine\Common\Collections\Collection, thus it always evaluated to true.
Loading history...
1693
            $attachIcon = Display::returnFontAwesomeIcon('paperclip');
1694
            $repo = Container::getMessageAttachmentRepository();
1695
            foreach ($files as $file) {
1696
                $size = format_file_size($file->getSize());
1697
                $comment = Security::remove_XSS($file->getComment());
1698
                $filename = Security::remove_XSS($file->getFilename());
1699
                $url = $repo->getResourceFileUrl($file);
1700
                $link = Display::url($filename, $url);
1701
                $comment = !empty($comment) ? '&nbsp;-&nbsp;<i>'.$comment.'</i>' : '';
1702
1703
                $attachmentLine = $attachIcon.'&nbsp;'.$link.'&nbsp;('.$size.')'.$comment;
1704
                /*if ('audio_message' === $file['comment']) {
1705
                    $attachmentLine = '<audio src="'.$archiveURL.$archiveFile.'"/>';
1706
                }*/
1707
                $list[] = $attachmentLine;
1708
            }
1709
        }
1710
1711
        return $list;
1712
    }
1713
1714
    /**
1715
     * Get message list by id.
1716
     *
1717
     * @param int $messageId
1718
     *
1719
     * @return array
1720
     */
1721
    public static function get_message_by_id($messageId)
1722
    {
1723
        $table = Database::get_main_table(TABLE_MESSAGE);
1724
        $messageId = (int) $messageId;
1725
        $sql = "SELECT * FROM $table
1726
                WHERE
1727
                    id = '$messageId' AND
1728
                    msg_status <> '".MESSAGE_STATUS_DELETED."' ";
1729
        $res = Database::query($sql);
1730
        $item = [];
1731
        if (Database::num_rows($res) > 0) {
1732
            $item = Database::fetch_array($res, 'ASSOC');
1733
        }
1734
1735
        return $item;
1736
    }
1737
1738
    /**
1739
     * @return string
1740
     */
1741
    public static function generate_message_form()
1742
    {
1743
        $form = new FormValidator('send_message');
1744
        $form->addText(
1745
            'subject',
1746
            get_lang('Subject'),
1747
            false,
1748
            ['id' => 'subject_id']
1749
        );
1750
        $form->addTextarea(
1751
            'content',
1752
            get_lang('Message'),
1753
            ['id' => 'content_id', 'rows' => '5']
1754
        );
1755
1756
        return $form->returnForm();
1757
    }
1758
1759
    /**
1760
     * @return string
1761
     */
1762
    public static function generate_invitation_form()
1763
    {
1764
        $form = new FormValidator('send_invitation');
1765
        $form->addTextarea(
1766
            'content',
1767
            get_lang('Add a personal message'),
1768
            ['id' => 'content_invitation_id', 'rows' => 5]
1769
        );
1770
1771
        return $form->returnForm();
1772
    }
1773
1774
    /**
1775
     * @param string $type
1776
     * @param string $keyword
1777
     * @param array  $actions
1778
     *
1779
     * @return string
1780
     */
1781
    public static function getMessageGrid($type, $keyword, $actions = [])
1782
    {
1783
        $html = '';
1784
        // display sortable table with messages of the current user
1785
        $table = new SortableTable(
1786
            'message_inbox',
1787
            ['MessageManager', 'getNumberOfMessages'],
1788
            ['MessageManager', 'getMessageData'],
1789
            2,
1790
            20,
1791
            'DESC'
1792
        );
1793
        $table->setDataFunctionParams(
1794
            ['keyword' => $keyword, 'type' => $type, 'actions' => $actions]
1795
        );
1796
        $table->set_header(0, '', false, ['style' => 'width:15px;']);
1797
        $table->set_header(1, get_lang('Messages'), false);
1798
        $table->set_header(2, get_lang('Date'), true, ['style' => 'width:180px;']);
1799
        $table->set_header(3, get_lang('Edit'), false, ['style' => 'width:120px;']);
1800
1801
        if (isset($_REQUEST['f']) && 'social' === $_REQUEST['f']) {
1802
            $parameters['f'] = 'social';
1803
            $table->set_additional_parameters($parameters);
1804
        }
1805
1806
        $defaultActions = [
1807
            'delete' => get_lang('Delete selected messages'),
1808
            'mark_as_unread' => get_lang('Mark as unread'),
1809
            'mark_as_read' => get_lang('Mark as read'),
1810
        ];
1811
1812
        if (!in_array('delete', $actions)) {
1813
            unset($defaultActions['delete']);
1814
        }
1815
        if (!in_array('mark_as_unread', $actions)) {
1816
            unset($defaultActions['mark_as_unread']);
1817
        }
1818
        if (!in_array('mark_as_read', $actions)) {
1819
            unset($defaultActions['mark_as_read']);
1820
        }
1821
1822
        $table->set_form_actions($defaultActions);
1823
1824
        $html .= $table->return_table();
1825
1826
        return $html;
1827
    }
1828
1829
    /**
1830
     * @param string $keyword
1831
     *
1832
     * @return string
1833
     */
1834
    public static function getPromotedMessagesGrid($keyword)
1835
    {
1836
        $actions = ['delete'];
1837
        $currentUserId = api_get_user_id();
1838
1839
        $success = get_lang('The selected messages have been deleted');
1840
        if (isset($_REQUEST['action'])) {
1841
            switch ($_REQUEST['action']) {
1842
                case 'delete':
1843
                    foreach ($_POST['id'] as $index => $messageId) {
1844
                        self::delete_message_by_user_receiver($currentUserId, $messageId);
1845
                    }
1846
                    Display::addFlash(Display::return_message(
1847
                        $success,
1848
                        'normal',
1849
                        false
1850
                    ));
1851
                    break;
1852
                case 'deleteone':
1853
                    self::delete_message_by_user_receiver($currentUserId, $_GET['id']);
1854
                    Display::addFlash(Display::return_message(
1855
                        $success,
1856
                        'confirmation',
1857
                        false
1858
                    ));
1859
                    break;
1860
            }
1861
1862
            header('Location: '.api_get_self());
1863
            exit;
1864
        }
1865
1866
        return self::getMessageGrid(Message::MESSAGE_TYPE_PROMOTED, $keyword, $actions);
1867
    }
1868
1869
    /**
1870
     * Get the data of the last received messages for a user.
1871
     *
1872
     * @param int $userId The user id
1873
     * @param int $lastId The id of the last received message
1874
     *
1875
     * @return Message[]
1876
     */
1877
    public static function getMessagesFromLastReceivedMessage($userId, $lastId = 0)
1878
    {
1879
        $userId = (int) $userId;
1880
        $lastId = (int) $lastId;
1881
1882
        if (empty($userId)) {
1883
            return [];
1884
        }
1885
1886
        $user = api_get_user_entity($userId);
1887
        $criteria = Criteria::create()
1888
            ->where(
1889
                Criteria::expr()->gt('id', $lastId)
1890
            )->andWhere(
1891
                Criteria::expr()->in('msgStatus', [MESSAGE_STATUS_UNREAD])
1892
            )->orderBy(['sendDate' => Criteria::DESC]);
1893
1894
        return $user->getSentMessages()->matching($criteria);
1895
1896
        /*$messagesTable = Database::get_main_table(TABLE_MESSAGE);
1897
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
1898
1899
        $sql = "SELECT m.*, u.user_id, u.lastname, u.firstname
1900
                FROM $messagesTable as m
1901
                INNER JOIN $userTable as u
1902
                ON m.user_sender_id = u.user_id
1903
                WHERE
1904
                    m.user_receiver_id = $userId AND
1905
                    m.msg_status = ".MESSAGE_STATUS_UNREAD."
1906
                    AND m.id > $lastId
1907
                ORDER BY m.send_date DESC";
1908
1909
        $result = Database::query($sql);
1910
1911
        $messages = [];
1912
        if (false !== $result) {
1913
            while ($row = Database::fetch_assoc($result)) {
1914
                $messages[] = $row;
1915
            }
1916
        }
1917
1918
        return $messages;*/
1919
    }
1920
1921
    /**
1922
     * Get the data of the last received messages for a user.
1923
     *
1924
     * @param int $userId The user id
1925
     * @param int $lastId The id of the last received message
1926
     *
1927
     * @return Message[]
1928
     */
1929
    public static function getReceivedMessages($userId, $lastId = 0)
1930
    {
1931
        $userId = (int) $userId;
1932
        $lastId = (int) $lastId;
1933
1934
        if (empty($userId)) {
1935
            return [];
1936
        }
1937
1938
        $user = api_get_user_entity($userId);
1939
        $criteria = Criteria::create()
1940
            ->where(
1941
            Criteria::expr()->gt('id', $lastId)
1942
            )->andWhere(
1943
            Criteria::expr()->in('msgStatus', [MESSAGE_STATUS_NEW, MESSAGE_STATUS_UNREAD])
1944
            )->orderBy(['sendDate' => Criteria::DESC]);
1945
1946
        return $user->getReceivedMessages()->matching($criteria);
1947
1948
        /*$messagesTable = Database::get_main_table(TABLE_MESSAGE);
1949
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
1950
        $sql = "SELECT m.*, u.user_id, u.lastname, u.firstname, u.picture_uri
1951
                FROM $messagesTable as m
1952
                INNER JOIN $userTable as u
1953
                ON m.user_sender_id = u.user_id
1954
                WHERE
1955
                    m.user_receiver_id = $userId AND
1956
                    m.msg_status IN (".MESSAGE_STATUS_NEW.", ".MESSAGE_STATUS_UNREAD.")
1957
                    AND m.id > $lastId
1958
                ORDER BY m.send_date DESC";
1959
        $result = Database::query($sql);
1960
        $messages = [];
1961
        if (false !== $result) {
1962
            while ($row = Database::fetch_assoc($result)) {
1963
                $messages[] = $row;
1964
            }
1965
        }
1966
1967
        return $messages;*/
1968
    }
1969
1970
    /**
1971
     * Get the data of the last received messages for a user.
1972
     *
1973
     * @param int $userId The user id
1974
     * @param int $lastId The id of the last received message
1975
     *
1976
     * @return array
1977
     */
1978
    public static function getSentMessages($userId, $lastId = 0)
1979
    {
1980
        $userId = (int) $userId;
1981
        $lastId = (int) $lastId;
1982
1983
        if (empty($userId)) {
1984
            return [];
1985
        }
1986
1987
        $user = api_get_user_entity($userId);
1988
        $criteria = Criteria::create()
1989
            ->where(
1990
                Criteria::expr()->gt('id', $lastId)
1991
            )->andWhere(
1992
                Criteria::expr()->in('msgStatus', [MESSAGE_STATUS_OUTBOX])
1993
            )->orderBy(['sendDate' => Criteria::DESC]);
1994
1995
        if ($user->getSentMessages()->count()) {
1996
            return $user->getSentMessages()->matching($criteria);
1997
        }
1998
1999
        return [];
2000
2001
        /*
2002
        $messagesTable = Database::get_main_table(TABLE_MESSAGE);
2003
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
2004
2005
        $sql = "SELECT m.*, u.user_id, u.lastname, u.firstname, u.picture_uri
2006
                FROM $messagesTable as m
2007
                INNER JOIN $userTable as u
2008
                ON m.user_receiver_id = u.user_id
2009
                WHERE
2010
                    m.user_sender_id = $userId
2011
                    AND m.msg_status = ".MESSAGE_STATUS_OUTBOX."
2012
                    AND m.id > $lastId
2013
                ORDER BY m.send_date DESC";
2014
2015
        $result = Database::query($sql);
2016
2017
        $messages = [];
2018
        if (false !== $result) {
2019
            while ($row = Database::fetch_assoc($result)) {
2020
                $pictureInfo = UserManager::get_user_picture_path_by_id($row['user_id'], 'web');
2021
                $row['pictureUri'] = $pictureInfo['dir'].$pictureInfo['file'];
2022
                $messages[] = $row;
2023
            }
2024
        }
2025
2026
        return $messages;*/
2027
    }
2028
2029
    /**
2030
     * Check whether a message has attachments.
2031
     *
2032
     * @param int $messageId The message id
2033
     *
2034
     * @return bool Whether the message has attachments return true. Otherwise return false
2035
     */
2036
    public static function hasAttachments($messageId)
2037
    {
2038
        $messageId = (int) $messageId;
2039
2040
        if (empty($messageId)) {
2041
            return false;
2042
        }
2043
2044
        $messageAttachmentTable = Database::get_main_table(TABLE_MESSAGE_ATTACHMENT);
2045
2046
        $conditions = [
2047
            'where' => [
2048
                'message_id = ?' => $messageId,
2049
            ],
2050
        ];
2051
2052
        $result = Database::select(
2053
            'COUNT(1) AS qty',
2054
            $messageAttachmentTable,
2055
            $conditions,
2056
            'first'
2057
        );
2058
2059
        if (!empty($result)) {
2060
            if ($result['qty'] > 0) {
2061
                return true;
2062
            }
2063
        }
2064
2065
        return false;
2066
    }
2067
2068
    /**
2069
     * @param int $messageId
2070
     *
2071
     * @return array|bool
2072
     */
2073
    public static function getAttachment($messageId)
2074
    {
2075
        $messageId = (int) $messageId;
2076
2077
        if (empty($messageId)) {
2078
            return false;
2079
        }
2080
2081
        $table = Database::get_main_table(TABLE_MESSAGE_ATTACHMENT);
2082
2083
        $conditions = [
2084
            'where' => [
2085
                'id = ?' => $messageId,
2086
            ],
2087
        ];
2088
2089
        $result = Database::select(
2090
            '*',
2091
            $table,
2092
            $conditions,
2093
            'first'
2094
        );
2095
2096
        if (!empty($result)) {
2097
            return $result;
2098
        }
2099
2100
        return false;
2101
    }
2102
2103
    /**
2104
     * @param string $url
2105
     *
2106
     * @return FormValidator
2107
     */
2108
    public static function getSearchForm($url)
2109
    {
2110
        $form = new FormValidator(
2111
            'search',
2112
            'post',
2113
            $url,
2114
            null,
2115
            [],
2116
            FormValidator::LAYOUT_INLINE
2117
        );
2118
2119
        $form->addElement(
2120
            'text',
2121
            'keyword',
2122
            false,
2123
            [
2124
                'aria-label' => get_lang('Search'),
2125
            ]
2126
        );
2127
        $form->addButtonSearch(get_lang('Search'));
2128
2129
        return $form;
2130
    }
2131
2132
    /**
2133
     * Send a notification to all admins when a new user is registered.
2134
     */
2135
    public static function sendNotificationOfNewRegisteredUser(User $user)
2136
    {
2137
        $tplMailBody = new Template(
2138
            null,
2139
            false,
2140
            false,
2141
            false,
2142
            false,
2143
            false,
2144
            false
2145
        );
2146
        $tplMailBody->assign('user', $user);
2147
        $tplMailBody->assign('is_western_name_order', api_is_western_name_order());
2148
        $tplMailBody->assign(
2149
            'manageUrl',
2150
            api_get_path(WEB_CODE_PATH).'admin/user_edit.php?user_id='.$user->getId()
2151
        );
2152
2153
        $layoutContent = $tplMailBody->get_template('mail/new_user_mail_to_admin.tpl');
2154
2155
        $emailsubject = '['.get_lang('The user has been registered').'] '.$user->getUsername();
2156
        $emailbody = $tplMailBody->fetch($layoutContent);
2157
2158
        $admins = UserManager::get_all_administrators();
2159
2160
        foreach ($admins as $admin_info) {
2161
            self::send_message(
2162
                $admin_info['user_id'],
2163
                $emailsubject,
2164
                $emailbody,
2165
                [],
2166
                [],
2167
                null,
2168
                null,
2169
                null,
2170
                null,
2171
                $user->getId()
2172
            );
2173
        }
2174
    }
2175
2176
    /**
2177
     * Send a notification to all admins when a new user is registered
2178
     * while the approval method is used for users registration.
2179
     */
2180
    public static function sendNotificationOfNewRegisteredUserApproval(User $user)
2181
    {
2182
        $tplMailBody = new Template(
2183
            null,
2184
            false,
2185
            false,
2186
            false,
2187
            false,
2188
            false,
2189
            false
2190
        );
2191
        $tplMailBody->assign('user', $user);
2192
        $tplMailBody->assign('is_western_name_order', api_is_western_name_order());
2193
        $userId = $user->getId();
2194
        $url_edit = Display::url(
2195
            api_get_path(WEB_CODE_PATH).'admin/user_edit.php?user_id='.$userId,
2196
            api_get_path(WEB_CODE_PATH).'admin/user_edit.php?user_id='.$userId
2197
        );
2198
        $tplMailBody->assign(
2199
            'manageUrl',
2200
            $url_edit
2201
        );
2202
        // Get extra field values for this user and reformat the array
2203
        $extraFieldValues = new ExtraFieldValue('user');
2204
        $userExtraFields = $extraFieldValues->getAllValuesByItem($userId);
2205
        $values = [];
2206
        foreach ($userExtraFields as $field => $value) {
2207
            $values[$value['variable']] = $value['value'];
2208
        }
2209
        $tplMailBody->assign(
2210
            'extra',
2211
            $values
2212
        );
2213
        $layoutContent = '';
2214
        $emailbody = '';
2215
        if (true == api_get_configuration_value('mail_template_system')) {
2216
            $mailTemplateManager = new MailTemplateManager();
2217
            $templateText = $mailTemplateManager->getTemplateByType('new_user_mail_to_admin_approval.tpl');
2218
            if (empty($templateText)) {
2219
            } else {
2220
                // custom procedure to load a template as a string (doesn't use cache so may slow down)
2221
                $template = $tplMailBody->twig->createTemplate($templateText);
2222
                $emailbody = $template->render($tplMailBody->params);
2223
            }
2224
        }
2225
        if (empty($emailbody)) {
2226
            $layoutContent = $tplMailBody->get_template('mail/new_user_mail_to_admin_approval.tpl');
2227
            $emailbody = $tplMailBody->fetch($layoutContent);
2228
        }
2229
2230
        $emailsubject = '['.get_lang('ApprovalForNewAccount').'] '.$user->getUsername();
2231
2232
        if (api_get_configuration_value('send_inscription_notification_to_general_admin_only')) {
2233
            $email = api_get_setting('emailAdministrator');
2234
            $firstname = api_get_setting('administratorSurname');
2235
            $lastname = api_get_setting('administratorName');
2236
            api_mail_html("$firstname $lastname", $email, $emailsubject, $emailbody);
2237
        } else {
2238
            $admins = UserManager::get_all_administrators();
2239
            foreach ($admins as $admin_info) {
2240
                self::send_message(
2241
                    $admin_info['user_id'],
2242
                    $emailsubject,
2243
                    $emailbody,
2244
                    [],
2245
                    [],
2246
                    null,
2247
                    null,
2248
                    null,
2249
                    null,
2250
                    $userId
2251
                );
2252
            }
2253
        }
2254
    }
2255
2256
    /**
2257
     * Get the error log from failed mailing
2258
     * This assumes a complex setup where you have a cron script regularly copying the mail queue log
2259
     * into app/cache/mail/mailq.
2260
     * This can be done with a cron command like (check the location of your mail log file first):.
2261
     *
2262
     * @example 0,30 * * * * root cp /var/log/exim4/mainlog /var/www/chamilo/app/cache/mail/mailq
2263
     *
2264
     * @return array|bool
2265
     */
2266
    public static function failedSentMailErrors()
2267
    {
2268
        $base = api_get_path(SYS_ARCHIVE_PATH).'mail/';
2269
        $mailq = $base.'mailq';
2270
2271
        if (!file_exists($mailq) || !is_readable($mailq)) {
2272
            return false;
2273
        }
2274
2275
        $file = fopen($mailq, 'r');
2276
        $i = 1;
2277
        while (!feof($file)) {
2278
            $line = fgets($file);
2279
2280
            if ('' == trim($line)) {
2281
                continue;
2282
            }
2283
2284
            // Get the mail code, something like 1WBumL-0002xg-FF
2285
            if (preg_match('/(.*)\s((.*)-(.*)-(.*))\s<(.*)$/', $line, $codeMatches)) {
2286
                $mail_queue[$i]['code'] = $codeMatches[2];
2287
            }
2288
2289
            $fullMail = $base.$mail_queue[$i]['code'];
2290
            $mailFile = fopen($fullMail, 'r');
2291
2292
            // Get the reason of mail fail
2293
            $iX = 1;
2294
            while (!feof($mailFile)) {
2295
                $mailLine = fgets($mailFile);
2296
                //if ($iX == 4 && preg_match('/(.*):\s(.*)$/', $mailLine, $matches)) {
2297
                if (2 == $iX &&
2298
                    preg_match('/(.*)(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\s(.*)/', $mailLine, $detailsMatches)
2299
                ) {
2300
                    $mail_queue[$i]['reason'] = $detailsMatches[3];
2301
                }
2302
                $iX++;
2303
            }
2304
2305
            fclose($mailFile);
2306
2307
            // Get the time of mail fail
2308
            if (preg_match('/^\s?(\d+)(\D+)\s+(.*)$/', $line, $timeMatches)) {
2309
                $mail_queue[$i]['time'] = $timeMatches[1].$timeMatches[2];
2310
            } elseif (preg_match('/^(\s+)((.*)@(.*))\s+(.*)$/', $line, $emailMatches)) {
2311
                $mail_queue[$i]['mail'] = $emailMatches[2];
2312
                $i++;
2313
            }
2314
        }
2315
2316
        fclose($file);
2317
2318
        return array_reverse($mail_queue);
2319
    }
2320
2321
    /**
2322
     * @param int $userId
2323
     *
2324
     * @return array
2325
     */
2326
    public static function getUsersThatHadConversationWithUser($userId)
2327
    {
2328
        $messagesTable = Database::get_main_table(TABLE_MESSAGE);
2329
        $userId = (int) $userId;
2330
2331
        $sql = "SELECT DISTINCT
2332
                    user_sender_id
2333
                FROM $messagesTable
2334
                WHERE
2335
                    user_receiver_id = ".$userId;
2336
        $result = Database::query($sql);
2337
        $users = Database::store_result($result);
2338
        $userList = [];
2339
        foreach ($users as $userData) {
2340
            $userId = $userData['user_sender_id'];
2341
            if (empty($userId)) {
2342
                continue;
2343
            }
2344
            $userInfo = api_get_user_info($userId);
2345
            if ($userInfo) {
2346
                $userList[$userId] = $userInfo;
2347
            }
2348
        }
2349
2350
        return $userList;
2351
    }
2352
2353
    /**
2354
     * @param int $userId
2355
     * @param int $otherUserId
2356
     *
2357
     * @return array
2358
     */
2359
    public static function getAllMessagesBetweenStudents($userId, $otherUserId)
2360
    {
2361
        $messagesTable = Database::get_main_table(TABLE_MESSAGE);
2362
        $userId = (int) $userId;
2363
        $otherUserId = (int) $otherUserId;
2364
2365
        if (empty($otherUserId) || empty($userId)) {
2366
            return [];
2367
        }
2368
2369
        $sql = "SELECT DISTINCT *
2370
                FROM $messagesTable
2371
                WHERE
2372
                    (user_receiver_id = $userId AND user_sender_id = $otherUserId) OR
2373
                    (user_receiver_id = $otherUserId AND user_sender_id = $userId)
2374
                ORDER BY send_date DESC
2375
            ";
2376
        $result = Database::query($sql);
2377
        $messages = Database::store_result($result);
2378
        $list = [];
2379
        foreach ($messages as $message) {
2380
            $list[] = $message;
2381
        }
2382
2383
        return $list;
2384
    }
2385
2386
    /**
2387
     * @param string $subject
2388
     * @param string $message
2389
     * @param Course $course
2390
     * @param int    $sessionId
2391
     *
2392
     * @return bool
2393
     */
2394
    public static function sendMessageToAllUsersInCourse($subject, $message, Course $course, $sessionId = 0)
2395
    {
2396
        $senderId = api_get_user_id();
2397
        if (empty($senderId)) {
2398
            return false;
2399
        }
2400
        if (empty($sessionId)) {
2401
            // Course students and teachers
2402
            $users = CourseManager::get_user_list_from_course_code($course->getCode());
2403
        } else {
2404
            // Course-session students and course session coaches
2405
            $users = CourseManager::get_user_list_from_course_code($course->getCode(), $sessionId);
2406
        }
2407
2408
        if (empty($users)) {
2409
            return false;
2410
        }
2411
2412
        foreach ($users as $userInfo) {
2413
            self::send_message_simple(
2414
                $userInfo['user_id'],
2415
                $subject,
2416
                $message,
2417
                $senderId,
2418
                false,
2419
                false,
2420
                [],
2421
                false
2422
            );
2423
        }
2424
    }
2425
2426
    /**
2427
     * Clean audio messages already added in the message tool.
2428
     */
2429
    public static function cleanAudioMessage()
2430
    {
2431
        Session::erase('current_audio');
2432
    }
2433
2434
    /**
2435
     * @param int    $senderId
2436
     * @param string $subject
2437
     * @param string $message
2438
     */
2439
    public static function sendMessageToAllAdminUsers(
2440
        $senderId,
2441
        $subject,
2442
        $message
2443
    ) {
2444
        $admins = UserManager::get_all_administrators();
2445
        foreach ($admins as $admin) {
2446
            self::send_message_simple($admin['user_id'], $subject, $message, $senderId);
2447
        }
2448
    }
2449
2450
    /**
2451
     * @param int $messageId
2452
     * @param int $userId
2453
     *
2454
     * @return array
2455
     */
2456
    public static function countLikesAndDislikes($messageId, $userId)
2457
    {
2458
        if (!api_get_configuration_value('social_enable_messages_feedback')) {
2459
            return [];
2460
        }
2461
2462
        $messageId = (int) $messageId;
2463
        $userId = (int) $userId;
2464
2465
        $em = Database::getManager();
2466
        $query = $em
2467
            ->createQuery('
2468
                SELECT SUM(l.liked) AS likes, SUM(l.disliked) AS dislikes FROM ChamiloCoreBundle:MessageFeedback l
2469
                WHERE l.message = :message
2470
            ')
2471
            ->setParameters(['message' => $messageId]);
2472
2473
        try {
2474
            $counts = $query->getSingleResult();
2475
        } catch (Exception $e) {
2476
            $counts = ['likes' => 0, 'dislikes' => 0];
2477
        }
2478
2479
        $userLike = $em
2480
            ->getRepository(MessageFeedback::class)
2481
            ->findOneBy(['message' => $messageId, 'user' => $userId]);
2482
2483
        return [
2484
            'likes' => (int) $counts['likes'],
2485
            'dislikes' => (int) $counts['dislikes'],
2486
            'user_liked' => $userLike ? $userLike->isLiked() : false,
2487
            'user_disliked' => $userLike ? $userLike->isDisliked() : false,
2488
        ];
2489
    }
2490
2491
    /**
2492
     * @param int $messageId
2493
     * @param int $userId
2494
     * @param int $groupId   Optional.
2495
     *
2496
     * @return string
2497
     */
2498
    public static function getLikesButton($messageId, $userId, $groupId = 0)
2499
    {
2500
        if (!api_get_configuration_value('social_enable_messages_feedback')) {
2501
            return '';
2502
        }
2503
2504
        $countLikes = self::countLikesAndDislikes($messageId, $userId);
2505
2506
        $class = $countLikes['user_liked'] ? 'btn-primary' : 'btn-default';
2507
2508
        $btnLike = Display::button(
2509
            'like',
2510
            Display::returnFontAwesomeIcon('thumbs-up', '', true)
2511
                .PHP_EOL.'<span>'.$countLikes['likes'].'</span>',
2512
            [
2513
                'title' => get_lang('Like'),
2514
                'class' => 'btn  social-like '.$class,
2515
                'data-status' => 'like',
2516
                'data-message' => $messageId,
2517
                'data-group' => $groupId,
2518
            ]
2519
        );
2520
2521
        $btnDislike = '';
2522
        if (false === api_get_configuration_value('disable_dislike_option')) {
2523
            $disabled = $countLikes['user_disliked'] ? 'btn-danger' : 'btn-default';
2524
2525
            $btnDislike = Display::button(
2526
                'like',
2527
                Display::returnFontAwesomeIcon('thumbs-down', '', true)
2528
                .PHP_EOL.'<span>'.$countLikes['dislikes'].'</span>',
2529
                [
2530
                    'title' => get_lang('Dislike'),
2531
                    'class' => 'btn social-like '.$disabled,
2532
                    'data-status' => 'dislike',
2533
                    'data-message' => $messageId,
2534
                    'data-group' => $groupId,
2535
                ]
2536
            );
2537
        }
2538
2539
        return $btnLike.PHP_EOL.$btnDislike;
2540
    }
2541
}
2542