Passed
Push — master ( e157d2...b7d807 )
by Julito
12:22
created

MessageManager::get_user_id_by_email()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

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