Passed
Push — master ( 4ed902...760dff )
by Julito
11:06 queued 11s
created

MessageManager::sendMessageToAllUsersInCourse()   A

Complexity

Conditions 5
Paths 7

Size

Total Lines 28
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

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