Passed
Pull Request — 1.11.x (#4097)
by Angel Fernando Quiroz
12:30
created

MessageManager::send_message()   F

Complexity

Conditions 55
Paths > 20000

Size

Total Lines 321
Code Lines 200

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 55
eloc 200
nc 72960
nop 16
dl 0
loc 321
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\Message;
6
use Chamilo\UserBundle\Entity\User;
7
use ChamiloSession as Session;
8
9
/**
10
 * Class MessageManager.
11
 *
12
 * This class provides methods for messages management.
13
 * Include/require it in your code to use its features.
14
 */
15
class MessageManager
16
{
17
    const MESSAGE_TYPE_INBOX = 1;
18
    const MESSAGE_TYPE_OUTBOX = 2;
19
    const MESSAGE_TYPE_PROMOTED = 3;
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 ($cacheAvailable === true) {
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 self::MESSAGE_TYPE_INBOX:
97
                $statusList = [MESSAGE_STATUS_NEW, MESSAGE_STATUS_UNREAD];
98
                $userCondition = " user_receiver_id = $userId AND";
99
                break;
100
            case self::MESSAGE_TYPE_OUTBOX:
101
                $statusList = [MESSAGE_STATUS_OUTBOX];
102
                $userCondition = " user_sender_id = $userId AND";
103
                break;
104
            case self::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 int    $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
        // Forcing this order.
147
        if (!isset($direction)) {
148
            $column = 2;
149
            $direction = 'DESC';
150
        } else {
151
            $column = (int) $column;
152
            if (!in_array($direction, ['ASC', 'DESC'])) {
153
                $direction = 'ASC';
154
            }
155
        }
156
157
        if (!in_array($column, [0, 1, 2])) {
158
            $column = 2;
159
        }
160
161
        $type = isset($extraParams['type']) && !empty($extraParams['type']) ? $extraParams['type'] : '';
162
163
        if (empty($type)) {
164
            return [];
165
        }
166
167
        $viewUrl = '';
168
        switch ($type) {
169
            case self::MESSAGE_TYPE_OUTBOX:
170
            case self::MESSAGE_TYPE_INBOX:
171
                $viewUrl = api_get_path(WEB_CODE_PATH).'messages/view_message.php';
172
                break;
173
            case self::MESSAGE_TYPE_PROMOTED:
174
                $viewUrl = api_get_path(WEB_CODE_PATH).'social/view_promoted_message.php';
175
                break;
176
        }
177
        $viewUrl .= '?type='.$type;
178
179
        $whereConditions = self::getWhereConditions($extraParams);
180
181
        if (empty($whereConditions)) {
182
            return [];
183
        }
184
185
        $table = Database::get_main_table(TABLE_MESSAGE);
186
        $sql = "SELECT
187
                    id as col0,
188
                    title as col1,
189
                    send_date as col2,
190
                    msg_status as col3,
191
                    user_sender_id,
192
                    user_receiver_id
193
                FROM $table
194
                WHERE
195
                    $whereConditions
196
                ORDER BY col$column $direction
197
                LIMIT $from, $numberOfItems";
198
199
        $result = Database::query($sql);
200
        $messageList = [];
201
        $newMessageLink = api_get_path(WEB_CODE_PATH).'messages/new_message.php';
202
203
        $actions = $extraParams['actions'];
204
        $url = api_get_self();
205
        while ($row = Database::fetch_array($result, 'ASSOC')) {
206
            $messageId = $row['col0'];
207
            $title = $row['col1'];
208
            $sendDate = $row['col2'];
209
            $status = $row['col3'];
210
            $senderId = $row['user_sender_id'];
211
            $receiverId = $row['user_receiver_id'];
212
213
            $title = Security::remove_XSS($title, STUDENT, true);
214
            $title = cut($title, 80, true);
215
216
            $class = 'class = "read"';
217
            if (1 == $status) {
218
                $class = 'class = "unread"';
219
            }
220
221
            $userInfo = api_get_user_info($senderId);
222
            if ($type == self::MESSAGE_TYPE_OUTBOX) {
223
                $userInfo = api_get_user_info($receiverId);
224
            }
225
            $message[3] = '';
226
            if (!empty($senderId) && !empty($userInfo)) {
227
                $message[1] = '<a '.$class.' href="'.$viewUrl.'&id='.$messageId.'">'.$title.'</a><br />';
228
                $message[1] .= $userInfo['complete_name_with_username'];
229
                if (in_array('reply', $actions)) {
230
                    $message[3] =
231
                        Display::url(
232
                            Display::returnFontAwesomeIcon('reply', 2),
233
                            $newMessageLink.'?re_id='.$messageId,
234
                            ['title' => get_lang('ReplyToMessage')]
235
                        );
236
                }
237
            } else {
238
                $message[1] = '<a '.$class.' href="'.$viewUrl.'&id='.$messageId.'">'.$title.'</a><br />';
239
                $message[1] .= get_lang('UnknownUser');
240
                if (in_array('reply', $actions)) {
241
                    $message[3] =
242
                        Display::url(
243
                            Display::returnFontAwesomeIcon('reply', 2),
244
                            '#',
245
                            ['title' => get_lang('ReplyToMessage')]
246
                        );
247
                }
248
            }
249
250
            $message[0] = $messageId;
251
            $message[2] = api_convert_and_format_date($sendDate, DATE_TIME_FORMAT_LONG);
252
253
            // Actions
254
            if (in_array('edit', $actions)) {
255
                $message[3] .=
256
                    '&nbsp;&nbsp;'.
257
                    Display::url(
258
                        Display::returnFontAwesomeIcon('pencil', 2),
259
                        $newMessageLink.'?action=edit&id='.$messageId,
260
                        ['title' => get_lang('ForwardMessage')]
261
                    );
262
            }
263
264
            // Actions
265
            if (in_array('forward', $actions)) {
266
                $message[3] .=
267
                    '&nbsp;&nbsp;'.
268
                    Display::url(
269
                        Display::returnFontAwesomeIcon('share', 2),
270
                        $newMessageLink.'?forward_id='.$messageId,
271
                        ['title' => get_lang('ForwardMessage')]
272
                    );
273
            }
274
275
            if (in_array('delete', $actions)) {
276
                $message[3] .= '&nbsp;&nbsp;<a title="'.addslashes(
277
                    get_lang('DeleteMessage')
278
                ).'" onclick="javascript:if(!confirm('."'".addslashes(
279
                    api_htmlentities(get_lang('ConfirmDeleteMessage'))
280
                )."'".')) return false;" href="'.$url.'?action=deleteone&id='.$messageId.'">'.
281
                Display::returnFontAwesomeIcon('trash', 2).'</a>';
282
            }
283
284
            foreach ($message as $key => $value) {
285
                $message[$key] = api_xml_http_response_encode($value);
286
            }
287
            $messageList[] = $message;
288
        }
289
290
        return $messageList;
291
    }
292
293
    /**
294
     * @param array  $aboutUserInfo
295
     * @param array  $fromUserInfo
296
     * @param string $subject
297
     * @param string $content
298
     *
299
     * @return bool
300
     */
301
    public static function sendMessageAboutUser(
302
        $aboutUserInfo,
303
        $fromUserInfo,
304
        $subject,
305
        $content
306
    ) {
307
        if (empty($aboutUserInfo) || empty($fromUserInfo)) {
308
            return false;
309
        }
310
311
        if (empty($fromUserInfo['id']) || empty($aboutUserInfo['id'])) {
312
            return false;
313
        }
314
315
        $table = Database::get_main_table(TABLE_MESSAGE);
316
        $now = api_get_utc_datetime();
317
        $params = [
318
            'user_sender_id' => $fromUserInfo['id'],
319
            'user_receiver_id' => $aboutUserInfo['id'],
320
            'msg_status' => MESSAGE_STATUS_CONVERSATION,
321
            'send_date' => $now,
322
            'title' => $subject,
323
            'content' => $content,
324
            'group_id' => 0,
325
            'parent_id' => 0,
326
            'update_date' => $now,
327
        ];
328
        $id = Database::insert($table, $params);
329
330
        if ($id) {
331
            return true;
332
        }
333
334
        return false;
335
    }
336
337
    /**
338
     * @param array $aboutUserInfo
339
     *
340
     * @return array
341
     */
342
    public static function getMessagesAboutUser($aboutUserInfo)
343
    {
344
        if (!empty($aboutUserInfo)) {
345
            $table = Database::get_main_table(TABLE_MESSAGE);
346
            $sql = 'SELECT id FROM '.$table.'
347
                    WHERE
348
                      user_receiver_id = '.$aboutUserInfo['id'].' AND
349
                      msg_status = '.MESSAGE_STATUS_CONVERSATION.'
350
                    ';
351
            $result = Database::query($sql);
352
            $messages = [];
353
            $repo = Database::getManager()->getRepository('ChamiloCoreBundle:Message');
354
            while ($row = Database::fetch_array($result)) {
355
                $message = $repo->find($row['id']);
356
                $messages[] = $message;
357
            }
358
359
            return $messages;
360
        }
361
362
        return [];
363
    }
364
365
    /**
366
     * @param array $userInfo
367
     *
368
     * @return string
369
     */
370
    public static function getMessagesAboutUserToString($userInfo)
371
    {
372
        $messages = self::getMessagesAboutUser($userInfo);
373
        $html = '';
374
        if (!empty($messages)) {
375
            /** @var Message $message */
376
            foreach ($messages as $message) {
377
                $tag = 'message_'.$message->getId();
378
                $tagAccordion = 'accordion_'.$message->getId();
379
                $tagCollapse = 'collapse_'.$message->getId();
380
                $date = Display::dateToStringAgoAndLongDate(
381
                    $message->getSendDate()
382
                );
383
                $localTime = api_get_local_time(
384
                    $message->getSendDate(),
385
                    null,
386
                    null,
387
                    false,
388
                    false
389
                );
390
                $senderId = $message->getUserSenderId();
391
                $senderInfo = api_get_user_info($senderId);
392
                $html .= Display::panelCollapse(
393
                    $localTime.' '.$senderInfo['complete_name'].' '.$message->getTitle(),
394
                    $message->getContent().'<br />'.$date.'<br />'.get_lang(
395
                        'Author'
396
                    ).': '.$senderInfo['complete_name_with_message_link'],
397
                    $tag,
398
                    null,
399
                    $tagAccordion,
400
                    $tagCollapse,
401
                    false
402
                );
403
            }
404
        }
405
406
        return $html;
407
    }
408
409
    /**
410
     * @param int    $senderId
411
     * @param int    $receiverId
412
     * @param string $subject
413
     * @param string $message
414
     *
415
     * @return bool
416
     */
417
    public static function messageWasAlreadySent($senderId, $receiverId, $subject, $message)
418
    {
419
        $table = Database::get_main_table(TABLE_MESSAGE);
420
        $senderId = (int) $senderId;
421
        $receiverId = (int) $receiverId;
422
        $subject = Database::escape_string($subject);
423
        $message = Database::escape_string($message);
424
425
        $sql = "SELECT * FROM $table
426
                WHERE
427
                    user_sender_id = $senderId AND
428
                    user_receiver_id = $receiverId AND
429
                    title = '$subject' AND
430
                    content = '$message' AND
431
                    (msg_status = ".MESSAGE_STATUS_UNREAD." OR msg_status = ".MESSAGE_STATUS_NEW.")
432
                ";
433
        $result = Database::query($sql);
434
435
        return Database::num_rows($result) > 0;
436
    }
437
438
    /**
439
     * Sends a message to a user/group.
440
     *
441
     * @param int    $receiverUserId
442
     * @param string $subject
443
     * @param string $content
444
     * @param array  $attachments                files array($_FILES) (optional)
445
     * @param array  $fileCommentList            about attachment files (optional)
446
     * @param int    $group_id                   (optional)
447
     * @param int    $parent_id                  (optional)
448
     * @param int    $editMessageId              id for updating the message (optional)
449
     * @param int    $topic_id                   (optional) the default value is the current user_id
450
     * @param int    $sender_id
451
     * @param bool   $directMessage
452
     * @param int    $forwardId
453
     * @param array  $smsParameters
454
     * @param bool   $checkCurrentAudioId
455
     * @param bool   $forceTitleWhenSendingEmail force the use of $title as subject instead of "You have a new message"
456
     * @param int    $status                     Message status
457
     *
458
     * @return bool
459
     */
460
    public static function send_message(
461
        $receiverUserId,
462
        $subject,
463
        $content,
464
        array $attachments = [],
465
        array $fileCommentList = [],
466
        $group_id = 0,
467
        $parent_id = 0,
468
        $editMessageId = 0,
469
        $topic_id = 0,
470
        $sender_id = 0,
471
        $directMessage = false,
472
        $forwardId = 0,
473
        $smsParameters = [],
474
        $checkCurrentAudioId = false,
475
        $forceTitleWhenSendingEmail = false,
476
        $status = 0
477
    ) {
478
        $group_id = (int) $group_id;
479
        $receiverUserId = (int) $receiverUserId;
480
        $parent_id = (int) $parent_id;
481
        $editMessageId = (int) $editMessageId;
482
        $topic_id = (int) $topic_id;
483
        $status = empty($status) ? MESSAGE_STATUS_UNREAD : (int) $status;
484
485
        $sendEmail = true;
486
        if (!empty($receiverUserId)) {
487
            $receiverUserInfo = api_get_user_info($receiverUserId);
488
            if (empty($receiverUserInfo)) {
489
                return false;
490
            }
491
492
            // Disabling messages for inactive users.
493
            if (0 == $receiverUserInfo['active']) {
494
                return false;
495
            }
496
497
            // Disabling messages depending the pausetraining plugin.
498
            $allowPauseFormation =
499
                'true' === api_get_plugin_setting('pausetraining', 'tool_enable') &&
500
                'true' === api_get_plugin_setting('pausetraining', 'allow_users_to_edit_pause_formation');
501
502
            if ($allowPauseFormation) {
503
                $extraFieldValue = new ExtraFieldValue('user');
504
                $disableEmails = $extraFieldValue->get_values_by_handler_and_field_variable(
505
                    $receiverUserId,
506
                    'disable_emails'
507
                );
508
509
                // User doesn't want email notifications but chamilo inbox still available.
510
                if (!empty($disableEmails) &&
511
                    isset($disableEmails['value']) && 1 === (int) $disableEmails['value']
512
                ) {
513
                    $sendEmail = false;
514
                }
515
516
                if ($sendEmail) {
517
                    // Check if user pause his formation.
518
                    $pause = $extraFieldValue->get_values_by_handler_and_field_variable(
519
                        $receiverUserId,
520
                        'pause_formation'
521
                    );
522
                    if (!empty($pause) && isset($pause['value']) && 1 === (int) $pause['value']) {
523
                        $startDate = $extraFieldValue->get_values_by_handler_and_field_variable(
524
                            $receiverUserInfo['user_id'],
525
                            'start_pause_date'
526
                        );
527
                        $endDate = $extraFieldValue->get_values_by_handler_and_field_variable(
528
                            $receiverUserInfo['user_id'],
529
                            'end_pause_date'
530
                        );
531
532
                        if (
533
                            !empty($startDate) && isset($startDate['value']) && !empty($startDate['value']) &&
534
                            !empty($endDate) && isset($endDate['value']) && !empty($endDate['value'])
535
                        ) {
536
                            $now = time();
537
                            $start = api_strtotime($startDate['value']);
538
                            $end = api_strtotime($endDate['value']);
539
540
                            if ($now > $start && $now < $end) {
541
                                $sendEmail = false;
542
                            }
543
                        }
544
                    }
545
                }
546
            }
547
        }
548
549
        $user_sender_id = empty($sender_id) ? api_get_user_id() : (int) $sender_id;
550
        if (empty($user_sender_id)) {
551
            Display::addFlash(Display::return_message(get_lang('UserDoesNotExist'), 'warning'));
552
553
            return false;
554
        }
555
556
        $totalFileSize = 0;
557
        $attachmentList = [];
558
        if (is_array($attachments)) {
559
            $counter = 0;
560
            foreach ($attachments as $attachment) {
561
                $attachment['comment'] = isset($fileCommentList[$counter]) ? $fileCommentList[$counter] : '';
562
                $fileSize = isset($attachment['size']) ? $attachment['size'] : 0;
563
                if (is_array($fileSize)) {
564
                    foreach ($fileSize as $size) {
565
                        $totalFileSize += $size;
566
                    }
567
                } else {
568
                    $totalFileSize += $fileSize;
569
                }
570
                $attachmentList[] = $attachment;
571
                $counter++;
572
            }
573
        }
574
575
        if ($checkCurrentAudioId) {
576
            // Add the audio file as an attachment
577
            $audioId = Session::read('current_audio_id');
578
            if (!empty($audioId)) {
579
                $file = api_get_uploaded_file('audio_message', api_get_user_id(), $audioId);
580
                if (!empty($file)) {
581
                    $audioAttachment = [
582
                        'name' => basename($file),
583
                        'comment' => 'audio_message',
584
                        'size' => filesize($file),
585
                        'tmp_name' => $file,
586
                        'error' => 0,
587
                        'type' => DocumentManager::file_get_mime_type(basename($file)),
588
                    ];
589
                    // create attachment from audio message
590
                    $attachmentList[] = $audioAttachment;
591
                }
592
            }
593
        }
594
595
        // Validating fields
596
        if (empty($subject) && empty($group_id)) {
597
            Display::addFlash(
598
                Display::return_message(
599
                    get_lang('YouShouldWriteASubject'),
600
                    'warning'
601
                )
602
            );
603
604
            return false;
605
        } elseif ($totalFileSize > (int) api_get_setting('message_max_upload_filesize')) {
606
            $warning = sprintf(
607
                get_lang('FilesSizeExceedsX'),
608
                format_file_size(api_get_setting('message_max_upload_filesize'))
609
            );
610
611
            Display::addFlash(Display::return_message($warning, 'warning'));
612
613
            return false;
614
        }
615
616
        $now = api_get_utc_datetime();
617
        $table = Database::get_main_table(TABLE_MESSAGE);
618
619
        if (!empty($receiverUserId) || !empty($group_id)) {
620
            // message for user friend
621
            //@todo it's possible to edit a message? yes, only for groups
622
            if (!empty($editMessageId)) {
623
                $query = " UPDATE $table SET
624
                              update_date = '".$now."',
625
                              content = '".Database::escape_string($content)."'
626
                           WHERE id = '$editMessageId' ";
627
                Database::query($query);
628
                $messageId = $editMessageId;
629
            } else {
630
                $params = [
631
                    'user_sender_id' => $user_sender_id,
632
                    'user_receiver_id' => $receiverUserId,
633
                    'msg_status' => $status,
634
                    'send_date' => $now,
635
                    'title' => $subject,
636
                    'content' => $content,
637
                    'group_id' => $group_id,
638
                    'parent_id' => $parent_id,
639
                    'update_date' => $now,
640
                ];
641
                $messageId = Database::insert($table, $params);
642
            }
643
644
            // Forward also message attachments
645
            if (!empty($forwardId)) {
646
                $attachments = self::getAttachmentList($forwardId);
647
                foreach ($attachments as $attachment) {
648
                    if (!empty($attachment['file_source'])) {
649
                        $file = [
650
                            'name' => $attachment['filename'],
651
                            'tmp_name' => $attachment['file_source'],
652
                            'size' => $attachment['size'],
653
                            'error' => 0,
654
                            'comment' => $attachment['comment'],
655
                        ];
656
657
                        // Inject this array so files can be added when sending and email with the mailer
658
                        $attachmentList[] = $file;
659
                    }
660
                }
661
            }
662
663
            // Save attachment file for inbox messages
664
            if (is_array($attachmentList)) {
665
                foreach ($attachmentList as $attachment) {
666
                    if (0 == $attachment['error']) {
667
                        $comment = $attachment['comment'];
668
                        self::saveMessageAttachmentFile(
669
                            $attachment,
670
                            $comment,
671
                            $messageId,
672
                            null,
673
                            $receiverUserId,
674
                            $group_id
675
                        );
676
                    }
677
                }
678
            }
679
680
            // Save message in the outbox for user friend or group.
681
            if (empty($group_id) && MESSAGE_STATUS_UNREAD == $status) {
682
                $params = [
683
                    'user_sender_id' => $user_sender_id,
684
                    'user_receiver_id' => $receiverUserId,
685
                    'msg_status' => MESSAGE_STATUS_OUTBOX,
686
                    'send_date' => $now,
687
                    'title' => $subject,
688
                    'content' => $content,
689
                    'group_id' => $group_id,
690
                    'parent_id' => $parent_id,
691
                    'update_date' => $now,
692
                ];
693
                $outbox_last_id = Database::insert($table, $params);
694
695
                // save attachment file for outbox messages
696
                if (is_array($attachmentList)) {
697
                    foreach ($attachmentList as $attachment) {
698
                        if (0 == $attachment['error']) {
699
                            $comment = $attachment['comment'];
700
                            self::saveMessageAttachmentFile(
701
                                $attachment,
702
                                $comment,
703
                                $outbox_last_id,
704
                                $user_sender_id
705
                            );
706
                        }
707
                    }
708
                }
709
            }
710
711
            if ($sendEmail) {
712
                $notification = new Notification();
713
                $sender_info = api_get_user_info($user_sender_id);
714
715
                // add file attachment additional attributes
716
                $attachmentAddedByMail = [];
717
                foreach ($attachmentList as $attachment) {
718
                    $attachmentAddedByMail[] = [
719
                        'path' => $attachment['tmp_name'],
720
                        'filename' => $attachment['name'],
721
                    ];
722
                }
723
724
                if (empty($group_id)) {
725
                    $type = Notification::NOTIFICATION_TYPE_MESSAGE;
726
                    if ($directMessage) {
727
                        $type = Notification::NOTIFICATION_TYPE_DIRECT_MESSAGE;
728
                    }
729
                    $notification->saveNotification(
730
                        $messageId,
731
                        $type,
732
                        [$receiverUserId],
733
                        $subject,
734
                        $content,
735
                        $sender_info,
736
                        $attachmentAddedByMail,
737
                        $smsParameters,
738
                        $forceTitleWhenSendingEmail
739
                    );
740
                } else {
741
                    $usergroup = new UserGroup();
742
                    $group_info = $usergroup->get($group_id);
743
                    $group_info['topic_id'] = $topic_id;
744
                    $group_info['msg_id'] = $messageId;
745
746
                    $user_list = $usergroup->get_users_by_group(
747
                        $group_id,
748
                        false,
749
                        [],
750
                        0,
751
                        1000
752
                    );
753
754
                    // Adding more sense to the message group
755
                    $subject = sprintf(get_lang('ThereIsANewMessageInTheGroupX'), $group_info['name']);
756
                    $new_user_list = [];
757
                    foreach ($user_list as $user_data) {
758
                        $new_user_list[] = $user_data['id'];
759
                    }
760
                    $group_info = [
761
                        'group_info' => $group_info,
762
                        'user_info' => $sender_info,
763
                    ];
764
                    $notification->saveNotification(
765
                        $messageId,
766
                        Notification::NOTIFICATION_TYPE_GROUP,
767
                        $new_user_list,
768
                        $subject,
769
                        $content,
770
                        $group_info,
771
                        $attachmentAddedByMail,
772
                        $smsParameters
773
                    );
774
                }
775
            }
776
777
            return $messageId;
778
        }
779
780
        return false;
781
    }
782
783
    /**
784
     * @param int    $receiverUserId
785
     * @param int    $subject
786
     * @param string $message
787
     * @param int    $sender_id
788
     * @param bool   $sendCopyToDrhUsers send copy to related DRH users
789
     * @param bool   $directMessage
790
     * @param array  $smsParameters
791
     * @param bool   $uploadFiles        Do not upload files using the MessageManager class
792
     * @param array  $attachmentList
793
     *
794
     * @return bool
795
     */
796
    public static function send_message_simple(
797
        $receiverUserId,
798
        $subject,
799
        $message,
800
        $sender_id = 0,
801
        $sendCopyToDrhUsers = false,
802
        $directMessage = false,
803
        $smsParameters = [],
804
        $uploadFiles = true,
805
        $attachmentList = []
806
    ) {
807
        $files = $_FILES ? $_FILES : [];
808
        if (false === $uploadFiles) {
809
            $files = [];
810
        }
811
        // $attachmentList must have: tmp_name, name, size keys
812
        if (!empty($attachmentList)) {
813
            $files = $attachmentList;
814
        }
815
        $result = self::send_message(
816
            $receiverUserId,
817
            $subject,
818
            $message,
819
            $files,
820
            [],
821
            null,
822
            null,
823
            null,
824
            null,
825
            $sender_id,
826
            $directMessage,
827
            0,
828
            $smsParameters
829
        );
830
831
        if ($sendCopyToDrhUsers) {
832
            $userInfo = api_get_user_info($receiverUserId);
833
            $drhList = UserManager::getDrhListFromUser($receiverUserId);
834
            if (!empty($drhList)) {
835
                foreach ($drhList as $drhInfo) {
836
                    $message = sprintf(
837
                        get_lang('CopyOfMessageSentToXUser'),
838
                        $userInfo['complete_name']
839
                    ).' <br />'.$message;
840
841
                    self::send_message_simple(
842
                        $drhInfo['id'],
843
                        $subject,
844
                        $message,
845
                        $sender_id,
846
                        false,
847
                        $directMessage
848
                    );
849
                }
850
            }
851
        }
852
853
        return $result;
854
    }
855
856
    /**
857
     * @param int $user_receiver_id
858
     * @param int $id
859
     *
860
     * @return bool
861
     */
862
    public static function delete_message_by_user_receiver($user_receiver_id, $id)
863
    {
864
        $table = Database::get_main_table(TABLE_MESSAGE);
865
        $id = (int) $id;
866
        $user_receiver_id = (int) $user_receiver_id;
867
868
        if (empty($id) || empty($user_receiver_id)) {
869
            return false;
870
        }
871
872
        $sql = "SELECT * FROM $table
873
                WHERE
874
                    id = $id AND
875
                    user_receiver_id = $user_receiver_id AND
876
                    msg_status <> ".MESSAGE_STATUS_OUTBOX;
877
        $rs = Database::query($sql);
878
879
        if (Database::num_rows($rs) > 0) {
880
            // Delete attachment file.
881
            self::delete_message_attachment_file($id, $user_receiver_id);
882
            // Soft delete message.
883
            $query = "UPDATE $table
884
                      SET msg_status = ".MESSAGE_STATUS_DELETED."
885
                      WHERE
886
                        id = $id AND
887
                        user_receiver_id = $user_receiver_id ";
888
            Database::query($query);
889
890
            return true;
891
        }
892
893
        return false;
894
    }
895
896
    /**
897
     * Set status deleted.
898
     *
899
     * @author Isaac FLores Paz <[email protected]>
900
     *
901
     * @param  int
902
     * @param  int
903
     *
904
     * @return bool
905
     */
906
    public static function delete_message_by_user_sender($user_sender_id, $id)
907
    {
908
        $user_sender_id = (int) $user_sender_id;
909
        $id = (int) $id;
910
911
        if (empty($id) || empty($user_sender_id)) {
912
            return false;
913
        }
914
915
        $table = Database::get_main_table(TABLE_MESSAGE);
916
917
        $sql = "SELECT * FROM $table WHERE id = $id AND user_sender_id= $user_sender_id";
918
        $rs = Database::query($sql);
919
920
        if (Database::num_rows($rs) > 0) {
921
            // delete attachment file
922
            self::delete_message_attachment_file($id, $user_sender_id);
923
            // delete message
924
            $sql = "UPDATE $table
925
                    SET msg_status = '".MESSAGE_STATUS_DELETED."'
926
                    WHERE user_sender_id= $user_sender_id AND id= $id";
927
            Database::query($sql);
928
929
            return true;
930
        }
931
932
        return false;
933
    }
934
935
    /**
936
     * Saves a message attachment files.
937
     *
938
     * @param array $file_attach $_FILES['name']
939
     * @param  string    a comment about the uploaded file
940
     * @param  int        message id
941
     * @param  int        receiver user id (optional)
942
     * @param  int        sender user id (optional)
943
     * @param  int        group id (optional)
944
     */
945
    public static function saveMessageAttachmentFile(
946
        $file_attach,
947
        $file_comment,
948
        $message_id,
949
        $receiver_user_id = 0,
950
        $sender_user_id = 0,
951
        $group_id = 0
952
    ) {
953
        $table = Database::get_main_table(TABLE_MESSAGE_ATTACHMENT);
954
955
        // Try to add an extension to the file if it hasn't one
956
        $type = isset($file_attach['type']) ? $file_attach['type'] : '';
957
        if (empty($type)) {
958
            $type = DocumentManager::file_get_mime_type($file_attach['name']);
959
        }
960
        $new_file_name = add_ext_on_mime(stripslashes($file_attach['name']), $type);
961
962
        // user's file name
963
        $file_name = $file_attach['name'];
964
        if (!filter_extension($new_file_name)) {
965
            Display::addFlash(Display::return_message(get_lang('UplUnableToSaveFileFilteredExtension'), 'error'));
966
        } else {
967
            $new_file_name = uniqid('');
968
            if (!empty($receiver_user_id)) {
969
                $message_user_id = $receiver_user_id;
970
            } else {
971
                $message_user_id = $sender_user_id;
972
            }
973
974
            // User-reserved directory where photos have to be placed.*
975
            $userGroup = new UserGroup();
976
            if (!empty($group_id)) {
977
                $path_user_info = $userGroup->get_group_picture_path_by_id(
978
                    $group_id,
979
                    'system',
980
                    true
981
                );
982
            } else {
983
                $path_user_info['dir'] = UserManager::getUserPathById($message_user_id, 'system');
984
            }
985
986
            $path_message_attach = $path_user_info['dir'].'message_attachments/';
987
            // If this directory does not exist - we create it.
988
            if (!file_exists($path_message_attach)) {
989
                @mkdir($path_message_attach, api_get_permissions_for_new_directories(), true);
990
            }
991
992
            $new_path = $path_message_attach.$new_file_name;
993
            $fileCopied = false;
994
            if (isset($file_attach['tmp_name']) && !empty($file_attach['tmp_name'])) {
995
                if (is_uploaded_file($file_attach['tmp_name'])) {
996
                    @copy($file_attach['tmp_name'], $new_path);
997
                    $fileCopied = true;
998
                } else {
999
                    // 'tmp_name' can be set by the ticket or when forwarding a message
1000
                    if (file_exists($file_attach['tmp_name'])) {
1001
                        @copy($file_attach['tmp_name'], $new_path);
1002
                        $fileCopied = true;
1003
                    }
1004
                }
1005
            }
1006
1007
            if ($fileCopied) {
1008
                // Storing the attachments if any
1009
                $params = [
1010
                    'filename' => $file_name,
1011
                    'comment' => $file_comment,
1012
                    'path' => $new_file_name,
1013
                    'message_id' => $message_id,
1014
                    'size' => $file_attach['size'],
1015
                ];
1016
1017
                return Database::insert($table, $params);
1018
            }
1019
        }
1020
1021
        return false;
1022
    }
1023
1024
    /**
1025
     * Delete message attachment files (logically updating the row with a suffix _DELETE_id).
1026
     *
1027
     * @param  int    message id
1028
     * @param  int    message user id (receiver user id or sender user id)
1029
     * @param  int    group id (optional)
1030
     */
1031
    public static function delete_message_attachment_file(
1032
        $message_id,
1033
        $message_uid,
1034
        $group_id = 0
1035
    ) {
1036
        $message_id = (int) $message_id;
1037
        $message_uid = (int) $message_uid;
1038
        $table_message_attach = Database::get_main_table(TABLE_MESSAGE_ATTACHMENT);
1039
1040
        $sql = "SELECT * FROM $table_message_attach
1041
                WHERE message_id = '$message_id'";
1042
        $rs = Database::query($sql);
1043
        while ($row = Database::fetch_array($rs)) {
1044
            $path = $row['path'];
1045
            $attach_id = (int) $row['id'];
1046
            $new_path = $path.'_DELETED_'.$attach_id;
1047
1048
            if (!empty($group_id)) {
1049
                $userGroup = new UserGroup();
1050
                $path_user_info = $userGroup->get_group_picture_path_by_id(
1051
                    $group_id,
1052
                    'system',
1053
                    true
1054
                );
1055
            } else {
1056
                $path_user_info['dir'] = UserManager::getUserPathById(
1057
                    $message_uid,
1058
                    'system'
1059
                );
1060
            }
1061
1062
            $path_message_attach = $path_user_info['dir'].'message_attachments/';
1063
            if (is_file($path_message_attach.$path)) {
1064
                if (rename($path_message_attach.$path, $path_message_attach.$new_path)) {
1065
                    $sql = "UPDATE $table_message_attach
1066
                            SET path = '$new_path'
1067
                            WHERE id = $attach_id ";
1068
                    Database::query($sql);
1069
                }
1070
            }
1071
        }
1072
    }
1073
1074
    /**
1075
     * @param int $user_id
1076
     * @param int $message_id
1077
     * @param int $type
1078
     *
1079
     * @return bool
1080
     */
1081
    public static function update_message_status($user_id, $message_id, $type)
1082
    {
1083
        $user_id = (int) $user_id;
1084
        $message_id = (int) $message_id;
1085
        $type = (int) $type;
1086
1087
        if (empty($user_id) || empty($message_id)) {
1088
            return false;
1089
        }
1090
1091
        $table_message = Database::get_main_table(TABLE_MESSAGE);
1092
        $sql = "UPDATE $table_message SET
1093
                    msg_status = '$type'
1094
                WHERE
1095
                    user_receiver_id = ".$user_id." AND
1096
                    id = '".$message_id."'";
1097
        $result = Database::query($sql);
1098
1099
        return Database::affected_rows($result) > 0;
1100
    }
1101
1102
    /**
1103
     * get messages by group id.
1104
     *
1105
     * @param int $group_id group id
1106
     *
1107
     * @return array
1108
     */
1109
    public static function get_messages_by_group($group_id)
1110
    {
1111
        $group_id = (int) $group_id;
1112
1113
        if (empty($group_id)) {
1114
            return false;
1115
        }
1116
1117
        $table = Database::get_main_table(TABLE_MESSAGE);
1118
        $sql = "SELECT * FROM $table
1119
                WHERE
1120
                    group_id= $group_id AND
1121
                    msg_status NOT IN ('".MESSAGE_STATUS_OUTBOX."', '".MESSAGE_STATUS_DELETED."')
1122
                ORDER BY id";
1123
        $rs = Database::query($sql);
1124
        $data = [];
1125
        if (Database::num_rows($rs) > 0) {
1126
            while ($row = Database::fetch_array($rs, 'ASSOC')) {
1127
                $data[] = $row;
1128
            }
1129
        }
1130
1131
        return $data;
1132
    }
1133
1134
    /**
1135
     * get messages by group id.
1136
     *
1137
     * @param int $group_id
1138
     * @param int $message_id
1139
     *
1140
     * @return array
1141
     */
1142
    public static function get_messages_by_group_by_message($group_id, $message_id)
1143
    {
1144
        $group_id = (int) $group_id;
1145
1146
        if (empty($group_id)) {
1147
            return false;
1148
        }
1149
1150
        $table = Database::get_main_table(TABLE_MESSAGE);
1151
        $sql = "SELECT * FROM $table
1152
                WHERE
1153
                    group_id = $group_id AND
1154
                    msg_status NOT IN ('".MESSAGE_STATUS_OUTBOX."', '".MESSAGE_STATUS_DELETED."')
1155
                ORDER BY id ";
1156
1157
        $rs = Database::query($sql);
1158
        $data = [];
1159
        $parents = [];
1160
        if (Database::num_rows($rs) > 0) {
1161
            while ($row = Database::fetch_array($rs, 'ASSOC')) {
1162
                if ($message_id == $row['parent_id'] || in_array($row['parent_id'], $parents)) {
1163
                    $parents[] = $row['id'];
1164
                    $data[] = $row;
1165
                }
1166
            }
1167
        }
1168
1169
        return $data;
1170
    }
1171
1172
    /**
1173
     * Get messages by parent id optionally with limit.
1174
     *
1175
     * @param  int        parent id
1176
     * @param  int        group id (optional)
1177
     * @param  int        offset (optional)
1178
     * @param  int        limit (optional)
1179
     *
1180
     * @return array
1181
     */
1182
    public static function getMessagesByParent($parentId, $groupId = 0, $offset = 0, $limit = 0)
1183
    {
1184
        $table = Database::get_main_table(TABLE_MESSAGE);
1185
        $parentId = (int) $parentId;
1186
1187
        if (empty($parentId)) {
1188
            return [];
1189
        }
1190
1191
        $condition_group_id = '';
1192
        if (!empty($groupId)) {
1193
            $groupId = (int) $groupId;
1194
            $condition_group_id = " AND group_id = '$groupId' ";
1195
        }
1196
1197
        $condition_limit = '';
1198
        if ($offset && $limit) {
1199
            $offset = (int) $offset;
1200
            $limit = (int) $limit;
1201
            $offset = ($offset - 1) * $limit;
1202
            $condition_limit = " LIMIT $offset,$limit ";
1203
        }
1204
1205
        $sql = "SELECT * FROM $table
1206
                WHERE
1207
                    parent_id='$parentId' AND
1208
                    msg_status NOT IN (".MESSAGE_STATUS_OUTBOX.", ".MESSAGE_STATUS_WALL_DELETE.")
1209
                    $condition_group_id
1210
                ORDER BY send_date DESC $condition_limit ";
1211
        $rs = Database::query($sql);
1212
        $data = [];
1213
        if (Database::num_rows($rs) > 0) {
1214
            while ($row = Database::fetch_array($rs)) {
1215
                $data[$row['id']] = $row;
1216
            }
1217
        }
1218
1219
        return $data;
1220
    }
1221
1222
    /**
1223
     * Gets information about messages sent.
1224
     *
1225
     * @param int
1226
     * @param int
1227
     * @param string
1228
     * @param string
1229
     *
1230
     * @return array
1231
     */
1232
    public static function get_message_data_sent(
1233
        $from,
1234
        $numberOfItems,
1235
        $column,
1236
        $direction,
1237
        $extraParams = []
1238
    ) {
1239
        $from = (int) $from;
1240
        $numberOfItems = (int) $numberOfItems;
1241
        if (!isset($direction)) {
1242
            $column = 2;
1243
            $direction = 'DESC';
1244
        } else {
1245
            $column = (int) $column;
1246
            if (!in_array($direction, ['ASC', 'DESC'])) {
1247
                $direction = 'ASC';
1248
            }
1249
        }
1250
1251
        if (!in_array($column, [0, 1, 2])) {
1252
            $column = 2;
1253
        }
1254
        $table = Database::get_main_table(TABLE_MESSAGE);
1255
        $request = api_is_xml_http_request();
1256
        $keyword = isset($extraParams['keyword']) && !empty($extraParams['keyword']) ? $extraParams['keyword'] : '';
1257
        $keywordCondition = '';
1258
        if (!empty($keyword)) {
1259
            $keyword = Database::escape_string($keyword);
1260
            $keywordCondition = " AND (title like '%$keyword%' OR content LIKE '%$keyword%') ";
1261
        }
1262
1263
        $sql = "SELECT
1264
                    id as col0,
1265
                    title as col1,
1266
                    send_date as col2,
1267
                    user_receiver_id,
1268
                    msg_status,
1269
                    user_sender_id
1270
                FROM $table
1271
                WHERE
1272
                    user_sender_id = ".api_get_user_id()." AND
1273
                    msg_status = ".MESSAGE_STATUS_OUTBOX."
1274
                    $keywordCondition
1275
                ORDER BY col$column $direction
1276
                LIMIT $from, $numberOfItems";
1277
        $result = Database::query($sql);
1278
1279
        $message_list = [];
1280
        while ($row = Database::fetch_array($result, 'ASSOC')) {
1281
            $messageId = $row['col0'];
1282
            $title = $row['col1'];
1283
            $sendDate = $row['col2'];
1284
            $senderId = $row['user_sender_id'];
1285
1286
            if ($request === true) {
1287
                $message[0] = '<input type="checkbox" value='.$messageId.' name="out[]">';
1288
            } else {
1289
                $message[0] = $messageId;
1290
            }
1291
1292
            $class = 'class = "read"';
1293
            $title = Security::remove_XSS($title);
1294
            $userInfo = api_get_user_info($senderId);
1295
            if ($request === true) {
1296
                $message[1] = '<a onclick="show_sent_message('.$messageId.')" href="javascript:void(0)">'.
1297
                    $userInfo['complete_name_with_username'].'</a>';
1298
                $message[2] = '<a onclick="show_sent_message('.$messageId.')" href="javascript:void(0)">'.str_replace(
1299
                        "\\",
1300
                        "",
1301
                        $title
1302
                    ).'</a>';
1303
                //date stays the same
1304
                $message[3] = api_convert_and_format_date($sendDate, DATE_TIME_FORMAT_LONG);
1305
                $message[4] = '&nbsp;&nbsp;<a title="'.addslashes(
1306
                        get_lang('DeleteMessage')
1307
                    ).'" onclick="delete_one_message_outbox('.$messageId.')" href="javascript:void(0)"  >'.
1308
                    Display::returnFontAwesomeIcon('trash', 2).'</a>';
1309
            } else {
1310
                $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'];
1311
                $message[2] = api_convert_and_format_date($sendDate, DATE_TIME_FORMAT_LONG);
1312
                $message[3] = '<a title="'.addslashes(
1313
                        get_lang('DeleteMessage')
1314
                    ).'" href="outbox.php?action=deleteone&id='.$messageId.'"  onclick="javascript:if(!confirm('."'".addslashes(
1315
                        api_htmlentities(get_lang('ConfirmDeleteMessage'))
1316
                    )."'".')) return false;" >'.
1317
                    Display::returnFontAwesomeIcon('trash', 2).'</a>';
1318
            }
1319
1320
            $message_list[] = $message;
1321
        }
1322
1323
        return $message_list;
1324
    }
1325
1326
    /**
1327
     * display message box in the inbox.
1328
     *
1329
     * @param int $messageId
1330
     * @param int $type
1331
     *
1332
     * @todo replace numbers with letters in the $row array pff...
1333
     *
1334
     * @return string html with the message content
1335
     */
1336
    public static function showMessageBox($messageId, $type)
1337
    {
1338
        $messageId = (int) $messageId;
1339
1340
        if (empty($messageId) || empty($type)) {
1341
            return '';
1342
        }
1343
        $currentUserId = api_get_user_id();
1344
1345
        $table = Database::get_main_table(TABLE_MESSAGE);
1346
1347
        if (empty($type)) {
1348
            return '';
1349
        }
1350
1351
        switch ($type) {
1352
            case self::MESSAGE_TYPE_OUTBOX:
1353
                $status = MESSAGE_STATUS_OUTBOX;
1354
                $userCondition = " user_sender_id = $currentUserId AND ";
1355
                break;
1356
            case self::MESSAGE_TYPE_INBOX:
1357
                $status = MESSAGE_STATUS_NEW;
1358
                $userCondition = " user_receiver_id = $currentUserId AND ";
1359
1360
                $query = "UPDATE $table SET
1361
                          msg_status = '".MESSAGE_STATUS_NEW."'
1362
                          WHERE id = $messageId ";
1363
                Database::query($query);
1364
                break;
1365
            case self::MESSAGE_TYPE_PROMOTED:
1366
                $status = MESSAGE_STATUS_PROMOTED;
1367
                $userCondition = " user_receiver_id = $currentUserId AND ";
1368
                break;
1369
        }
1370
1371
        if (empty($userCondition)) {
1372
            return '';
1373
        }
1374
1375
        $query = "SELECT * FROM $table
1376
                  WHERE
1377
                    id = $messageId AND
1378
                    $userCondition
1379
                    msg_status = $status";
1380
        $result = Database::query($query);
1381
        $row = Database::fetch_array($result, 'ASSOC');
1382
1383
        if (empty($row)) {
1384
            return '';
1385
        }
1386
1387
        /* get previous message */
1388
        $query = "SELECT id FROM $table
1389
                  WHERE
1390
                  $userCondition
1391
                       id < $messageId
1392
                     order by id DESC limit 1 ";
1393
        $result = Database::query($query);
1394
        $rowPrevMessage = Database::fetch_array($result, 'ASSOC');
1395
        $idPrevMessage = (int) isset($rowPrevMessage['id']) ? $rowPrevMessage['id'] : 0;
1396
1397
        /* get next message */
1398
        $query = "SELECT id FROM $table
1399
                  WHERE
1400
                  $userCondition
1401
                       id > $messageId
1402
                     order by id ASC limit 1 ";
1403
        $result = Database::query($query);
1404
        $rowNextMessage = Database::fetch_array($result, 'ASSOC');
1405
        $idNextMessage = (int) isset($rowNextMessage['id']) ? $rowNextMessage['id'] : 0;
1406
1407
        $user_sender_id = $row['user_sender_id'];
1408
1409
        // get file attachments by message id
1410
        $files_attachments = self::getAttachmentLinkList($messageId, $type);
1411
1412
        $row['content'] = str_replace('</br>', '<br />', $row['content']);
1413
        $title = Security::remove_XSS($row['title'], STUDENT, true);
1414
        $content = Security::remove_XSS($row['content'], STUDENT, true);
1415
1416
        $name = get_lang('UnknownUser');
1417
        $fromUser = api_get_user_info($user_sender_id);
1418
        $userImage = '';
1419
        if (!empty($user_sender_id) && !empty($fromUser)) {
1420
            $name = $fromUser['complete_name_with_username'];
1421
            $userImage = Display::img(
1422
                $fromUser['avatar_small'],
1423
                $name,
1424
                ['title' => $name, 'class' => 'img-responsive img-circle', 'style' => 'max-width:35px'],
1425
                false
1426
            );
1427
        }
1428
1429
        $message_content = Display::page_subheader(str_replace("\\", '', $title));
1430
1431
        $receiverUserInfo = [];
1432
        if (!empty($row['user_receiver_id'])) {
1433
            $receiverUserInfo = api_get_user_info($row['user_receiver_id']);
1434
        }
1435
1436
        $message_content .= '<tr>';
1437
        if ('true' === api_get_setting('allow_social_tool')) {
1438
            $message_content .= '<div class="row">';
1439
            $message_content .= '<div class="col-md-12">';
1440
            $message_content .= '<ul class="list-message">';
1441
1442
            if (!empty($user_sender_id)) {
1443
                $message_content .= '<li>'.$userImage.'</li>';
1444
                $message_content .= '<li>';
1445
                $message_content .= Display::url(
1446
                    $name,
1447
                    api_get_path(WEB_PATH).'main/social/profile.php?u='.$user_sender_id
1448
                );
1449
            } else {
1450
                $message_content .= '<li>'.$name;
1451
            }
1452
1453
            switch ($type) {
1454
                case self::MESSAGE_TYPE_INBOX:
1455
                    $message_content .= '&nbsp;'.api_strtolower(get_lang('To')).'&nbsp;'.get_lang('Me');
1456
                    break;
1457
                case self::MESSAGE_TYPE_OUTBOX:
1458
                    if (!empty($receiverUserInfo)) {
1459
                        $message_content .= '&nbsp;'.api_strtolower(
1460
                                get_lang('To')
1461
                            ).'&nbsp;<b>'.$receiverUserInfo['complete_name_with_username'].'</b></li>';
1462
                    }
1463
                    break;
1464
                case self::MESSAGE_TYPE_PROMOTED:
1465
                    break;
1466
            }
1467
1468
            $message_content .= '&nbsp;<li>'.Display::dateToStringAgoAndLongDate($row['send_date']).'</li>';
1469
            $message_content .= '</ul>';
1470
            $message_content .= '</div>';
1471
            $message_content .= '</div>';
1472
        } else {
1473
            switch ($type) {
1474
                case self::MESSAGE_TYPE_INBOX:
1475
                    $message_content .= get_lang('From').':&nbsp;'.$name.'</b> '.api_strtolower(get_lang('To')).' <b>'.
1476
                        get_lang('Me').'</b>';
1477
                    break;
1478
                case self::MESSAGE_TYPE_OUTBOX:
1479
                    $message_content .= get_lang('From').':&nbsp;'.$name.'</b> '.api_strtolower(get_lang('To')).' <b>'.
1480
                        $receiverUserInfo['complete_name_with_username'].'</b>';
1481
                    break;
1482
            }
1483
        }
1484
1485
        $message_content .= '
1486
		        <hr style="color:#ddd" />
1487
		        <table width="100%">
1488
		            <tr>
1489
		              <td valign=top class="view-message-content">'.str_replace("\\", "", $content).'</td>
1490
		            </tr>
1491
		        </table>
1492
		        <div id="message-attach">'.(!empty($files_attachments) ? implode('<br />', $files_attachments) : '').'</div>
1493
		        <div style="padding: 15px 0px 5px 0px">';
1494
        $social_link = '';
1495
        if (isset($_GET['f']) && $_GET['f'] == 'social') {
1496
            $social_link = 'f=social';
1497
        }
1498
1499
        $eventLink = Display::url(
1500
            Display::return_icon('new_event.png', get_lang('New event')),
1501
            api_get_path(WEB_CODE_PATH).'calendar/agenda.php?action=add&type=personal&m='.$messageId
1502
        ).PHP_EOL;
1503
1504
        switch ($type) {
1505
            case self::MESSAGE_TYPE_OUTBOX:
1506
                $message_content .= '<a href="outbox.php?'.$social_link.'">'.
1507
                    Display::return_icon('back.png', get_lang('ReturnToOutbox')).'</a> &nbsp';
1508
                $message_content .= $eventLink;
1509
                $message_content .= '<a href="outbox.php?action=deleteone&id='.$messageId.'&'.$social_link.'" >'.
1510
                    Display::return_icon('delete.png', get_lang('DeleteMessage')).'</a>&nbsp';
1511
                break;
1512
            case self::MESSAGE_TYPE_INBOX:
1513
                $message_content .= '<a href="inbox.php?'.$social_link.'">'.
1514
                    Display::return_icon('icons/22/arrow_up.png', get_lang('ReturnToInbox')).'</a>&nbsp;';
1515
                $message_content .= '<a href="new_message.php?re_id='.$messageId.'&'.$social_link.'">'.
1516
                    Display::return_icon('message_reply.png', get_lang('ReplyToMessage')).'</a>&nbsp;';
1517
                $message_content .= $eventLink;
1518
                $message_content .= '<a href="inbox.php?action=deleteone&id='.$messageId.'&'.$social_link.'" >'.
1519
                    Display::return_icon('delete.png', get_lang('DeleteMessage')).'</a>&nbsp;';
1520
                if ($idPrevMessage != 0) {
1521
                    $message_content .= '<a title="'.get_lang('PrevMessage').'" href="view_message.php?type='.$type.'&id='.$idPrevMessage.'" ">'.Display::return_icon('icons/22/back.png', get_lang('ScormPrevious')).'</a> &nbsp';
1522
                }
1523
                if ($idNextMessage != 0) {
1524
                    $message_content .= '<a title="'.get_lang('NextMessage').'" href="view_message.php?type='.$type.'&id='.$idNextMessage.'">'.Display::return_icon('icons/22/move.png', get_lang('ScormNext')).'</a> &nbsp';
1525
                }
1526
                break;
1527
        }
1528
1529
        $message_content .= '</div>';
1530
1531
        return $message_content;
1532
    }
1533
1534
    /**
1535
     * get user id by user email.
1536
     *
1537
     * @param string $user_email
1538
     *
1539
     * @return int user id
1540
     */
1541
    public static function get_user_id_by_email($user_email)
1542
    {
1543
        $table = Database::get_main_table(TABLE_MAIN_USER);
1544
        $sql = 'SELECT user_id
1545
                FROM '.$table.'
1546
                WHERE email="'.Database::escape_string($user_email).'";';
1547
        $rs = Database::query($sql);
1548
        $row = Database::fetch_array($rs, 'ASSOC');
1549
        if (isset($row['user_id'])) {
1550
            return $row['user_id'];
1551
        }
1552
1553
        return null;
1554
    }
1555
1556
    /**
1557
     * Displays messages of a group with nested view.
1558
     *
1559
     * @param int $groupId
1560
     *
1561
     * @return string
1562
     */
1563
    public static function display_messages_for_group($groupId)
1564
    {
1565
        global $my_group_role;
1566
1567
        $rows = self::get_messages_by_group($groupId);
1568
        $topics_per_page = 10;
1569
        $html_messages = '';
1570
        $query_vars = ['id' => $groupId, 'topics_page_nr' => 0];
1571
1572
        if (is_array($rows) && count($rows) > 0) {
1573
            // prepare array for topics with its items
1574
            $topics = [];
1575
            $x = 0;
1576
            foreach ($rows as $index => $value) {
1577
                if (empty($value['parent_id'])) {
1578
                    $topics[$value['id']] = $value;
1579
                }
1580
            }
1581
1582
            $new_topics = [];
1583
1584
            foreach ($topics as $id => $value) {
1585
                $rows = null;
1586
                $rows = self::get_messages_by_group_by_message($groupId, $value['id']);
1587
                if (!empty($rows)) {
1588
                    $count = count(self::calculate_children($rows, $value['id']));
1589
                } else {
1590
                    $count = 0;
1591
                }
1592
                $value['count'] = $count;
1593
                $new_topics[$id] = $value;
1594
            }
1595
1596
            $array_html = [];
1597
            foreach ($new_topics as $index => $topic) {
1598
                $html = '';
1599
                // topics
1600
                $user_sender_info = api_get_user_info($topic['user_sender_id']);
1601
                $name = $user_sender_info['complete_name'];
1602
                $html .= '<div class="groups-messages">';
1603
                $html .= '<div class="row">';
1604
1605
                $items = $topic['count'];
1606
                $reply_label = ($items == 1) ? get_lang('GroupReply') : get_lang('GroupReplies');
1607
                $label = '<i class="fa fa-envelope"></i> '.$items.' '.$reply_label;
1608
                $topic['title'] = trim($topic['title']);
1609
1610
                if (empty($topic['title'])) {
1611
                    $topic['title'] = get_lang('Untitled');
1612
                }
1613
1614
                $html .= '<div class="col-xs-8 col-md-10">';
1615
                $html .= Display::tag(
1616
                    'h4',
1617
                    Display::url(
1618
                        Security::remove_XSS($topic['title'], STUDENT, true),
1619
                        api_get_path(WEB_CODE_PATH).'social/group_topics.php?id='.$groupId.'&topic_id='.$topic['id']
1620
                    ),
1621
                    ['class' => 'title']
1622
                );
1623
                $actions = '';
1624
                if ($my_group_role == GROUP_USER_PERMISSION_ADMIN ||
1625
                    $my_group_role == GROUP_USER_PERMISSION_MODERATOR
1626
                ) {
1627
                    $actions = '<br />'.Display::url(
1628
                            get_lang('Delete'),
1629
                            api_get_path(
1630
                                WEB_CODE_PATH
1631
                            ).'social/group_topics.php?action=delete&id='.$groupId.'&topic_id='.$topic['id'],
1632
                            ['class' => 'btn btn-default']
1633
                        );
1634
                }
1635
1636
                $date = '';
1637
                if ($topic['send_date'] != $topic['update_date']) {
1638
                    if (!empty($topic['update_date'])) {
1639
                        $date .= '<i class="fa fa-calendar"></i> '.get_lang(
1640
                                'LastUpdate'
1641
                            ).' '.Display::dateToStringAgoAndLongDate($topic['update_date']);
1642
                    }
1643
                } else {
1644
                    $date .= '<i class="fa fa-calendar"></i> '.get_lang(
1645
                            'Created'
1646
                        ).' '.Display::dateToStringAgoAndLongDate($topic['send_date']);
1647
                }
1648
                $html .= '<div class="date">'.$label.' - '.$date.$actions.'</div>';
1649
                $html .= '</div>';
1650
1651
                $image = $user_sender_info['avatar'];
1652
1653
                $user_info = '<div class="author"><img class="img-responsive img-circle" src="'.$image.'" alt="'.$name.'"  width="64" height="64" title="'.$name.'" /></div>';
1654
                $user_info .= '<div class="name"><a href="'.api_get_path(
1655
                        WEB_PATH
1656
                    ).'main/social/profile.php?u='.$topic['user_sender_id'].'">'.$name.'&nbsp;</a></div>';
1657
1658
                $html .= '<div class="col-xs-4 col-md-2">';
1659
                $html .= $user_info;
1660
                $html .= '</div>';
1661
                $html .= '</div>';
1662
                $html .= '</div>';
1663
1664
                $array_html[] = [$html];
1665
            }
1666
1667
            // grids for items and topics  with paginations
1668
            $html_messages .= Display::return_sortable_grid(
1669
                'topics',
1670
                [],
1671
                $array_html,
1672
                [
1673
                    'hide_navigation' => false,
1674
                    'per_page' => $topics_per_page,
1675
                ],
1676
                $query_vars,
1677
                false,
1678
                [true, true, true, false],
1679
                false
1680
            );
1681
        }
1682
1683
        return $html_messages;
1684
    }
1685
1686
    /**
1687
     * Displays messages of a group with nested view.
1688
     *
1689
     * @param $groupId
1690
     * @param $topic_id
1691
     *
1692
     * @return string
1693
     */
1694
    public static function display_message_for_group($groupId, $topic_id)
1695
    {
1696
        global $my_group_role;
1697
        $main_message = self::get_message_by_id($topic_id);
1698
        if (empty($main_message)) {
1699
            return false;
1700
        }
1701
1702
        $webCodePath = api_get_path(WEB_CODE_PATH);
1703
        $iconCalendar = Display::returnFontAwesomeIcon('calendar');
1704
1705
        $langEdit = get_lang('Edit');
1706
        $langReply = get_lang('Reply');
1707
        $langLastUpdated = get_lang('LastUpdated');
1708
        $langCreated = get_lang('Created');
1709
1710
        $rows = self::get_messages_by_group_by_message($groupId, $topic_id);
1711
        $rows = self::calculate_children($rows, $topic_id);
1712
        $current_user_id = api_get_user_id();
1713
1714
        $items_per_page = 50;
1715
        $query_vars = ['id' => $groupId, 'topic_id' => $topic_id, 'topics_page_nr' => 0];
1716
1717
        // Main message
1718
        $links = '';
1719
        $main_content = '';
1720
        $html = '';
1721
        $items_page_nr = null;
1722
1723
        $user_sender_info = api_get_user_info($main_message['user_sender_id']);
1724
        $files_attachments = self::getAttachmentLinkList($main_message['id'], 0);
1725
        $name = $user_sender_info['complete_name'];
1726
1727
        $topic_page_nr = isset($_GET['topics_page_nr']) ? (int) $_GET['topics_page_nr'] : null;
1728
1729
        $links .= '<div class="pull-right">';
1730
        $links .= '<div class="btn-group btn-group-sm">';
1731
1732
        if (($my_group_role == GROUP_USER_PERMISSION_ADMIN || $my_group_role == GROUP_USER_PERMISSION_MODERATOR) ||
1733
            $main_message['user_sender_id'] == $current_user_id
1734
        ) {
1735
            $urlEdit = $webCodePath.'social/message_for_group_form.inc.php?'
1736
                .http_build_query(
1737
                    [
1738
                        'user_friend' => $current_user_id,
1739
                        'group_id' => $groupId,
1740
                        'message_id' => $main_message['id'],
1741
                        'action' => 'edit_message_group',
1742
                        'anchor_topic' => 'topic_'.$main_message['id'],
1743
                        'topics_page_nr' => $topic_page_nr,
1744
                        'items_page_nr' => $items_page_nr,
1745
                        'topic_id' => $main_message['id'],
1746
                    ]
1747
                );
1748
1749
            $links .= Display::toolbarButton(
1750
                $langEdit,
1751
                $urlEdit,
1752
                'pencil',
1753
                'default',
1754
                ['class' => 'ajax', 'data-title' => $langEdit, 'data-size' => 'lg'],
1755
                false
1756
            );
1757
        }
1758
1759
        $links .= self::getLikesButton($main_message['id'], $current_user_id, $groupId);
1760
1761
        $urlReply = $webCodePath.'social/message_for_group_form.inc.php?'
1762
            .http_build_query(
1763
                [
1764
                    'user_friend' => $current_user_id,
1765
                    'group_id' => $groupId,
1766
                    'message_id' => $main_message['id'],
1767
                    'action' => 'reply_message_group',
1768
                    'anchor_topic' => 'topic_'.$main_message['id'],
1769
                    'topics_page_nr' => $topic_page_nr,
1770
                    'topic_id' => $main_message['id'],
1771
                ]
1772
            );
1773
1774
        $links .= Display::toolbarButton(
1775
            $langReply,
1776
            $urlReply,
1777
            'commenting',
1778
            'default',
1779
            ['class' => 'ajax', 'data-title' => $langReply, 'data-size' => 'lg'],
1780
            false
1781
        );
1782
1783
        if (api_is_platform_admin()) {
1784
            $links .= Display::toolbarButton(
1785
                get_lang('Delete'),
1786
                'group_topics.php?action=delete&id='.$groupId.'&topic_id='.$topic_id,
1787
                'trash',
1788
                'default',
1789
                [],
1790
                false
1791
            );
1792
        }
1793
1794
        $links .= '</div>';
1795
        $links .= '</div>';
1796
1797
        $title = '<h4>'.Security::remove_XSS($main_message['title'], STUDENT, true).$links.'</h4>';
1798
1799
        $userPicture = $user_sender_info['avatar'];
1800
        $main_content .= '<div class="row">';
1801
        $main_content .= '<div class="col-md-2">';
1802
        $main_content .= '<div class="avatar-author">';
1803
        $main_content .= Display::img(
1804
            $userPicture,
1805
            $name,
1806
            ['width' => '60px', 'class' => 'img-responsive img-circle'],
1807
            false
1808
        );
1809
        $main_content .= '</div>';
1810
        $main_content .= '</div>';
1811
1812
        $date = '';
1813
        if ($main_message['send_date'] != $main_message['update_date']) {
1814
            if (!empty($main_message['update_date'])) {
1815
                $date = '<div class="date"> '
1816
                    ."$iconCalendar $langLastUpdated "
1817
                    .Display::dateToStringAgoAndLongDate($main_message['update_date'])
1818
                    .'</div>';
1819
            }
1820
        } else {
1821
            $date = '<div class="date"> '
1822
                ."$iconCalendar $langCreated "
1823
                .Display::dateToStringAgoAndLongDate($main_message['send_date'])
1824
                .'</div>';
1825
        }
1826
        $attachment = '<div class="message-attach">'
1827
            .(!empty($files_attachments) ? implode('<br />', $files_attachments) : '')
1828
            .'</div>';
1829
        $main_content .= '<div class="col-md-10">';
1830
        $user_link = Display::url(
1831
            $name,
1832
            $webCodePath.'social/profile.php?u='.$main_message['user_sender_id']
1833
        );
1834
        $main_content .= '<div class="message-content"> ';
1835
        $main_content .= '<div class="username">'.$user_link.'</div>';
1836
        $main_content .= $date;
1837
        $main_content .= '<div class="message">'.$main_message['content'].$attachment.'</div></div>';
1838
        $main_content .= '</div>';
1839
        $main_content .= '</div>';
1840
1841
        $html .= Display::div(
1842
            Display::div(
1843
                $title.$main_content,
1844
                ['class' => 'message-topic']
1845
            ),
1846
            ['class' => 'sm-groups-message']
1847
        );
1848
1849
        $topic_id = $main_message['id'];
1850
1851
        if (is_array($rows) && count($rows) > 0) {
1852
            $topics = $rows;
1853
            $array_html_items = [];
1854
1855
            foreach ($topics as $index => $topic) {
1856
                if (empty($topic['id'])) {
1857
                    continue;
1858
                }
1859
                $items_page_nr = isset($_GET['items_'.$topic['id'].'_page_nr'])
1860
                    ? (int) $_GET['items_'.$topic['id'].'_page_nr']
1861
                    : null;
1862
                $links = '';
1863
                $links .= '<div class="pull-right">';
1864
                $html_items = '';
1865
                $user_sender_info = api_get_user_info($topic['user_sender_id']);
1866
                $files_attachments = self::getAttachmentLinkList($topic['id'], 0);
1867
                $name = $user_sender_info['complete_name'];
1868
1869
                $links .= '<div class="btn-group btn-group-sm">';
1870
                if (
1871
                    ($my_group_role == GROUP_USER_PERMISSION_ADMIN ||
1872
                        $my_group_role == GROUP_USER_PERMISSION_MODERATOR
1873
                    ) ||
1874
                    $topic['user_sender_id'] == $current_user_id
1875
                ) {
1876
                    $links .= Display::toolbarButton(
1877
                        $langEdit,
1878
                        $webCodePath.'social/message_for_group_form.inc.php?'
1879
                            .http_build_query(
1880
                                [
1881
                                    'user_friend' => $current_user_id,
1882
                                    'group_id' => $groupId,
1883
                                    'message_id' => $topic['id'],
1884
                                    'action' => 'edit_message_group',
1885
                                    'anchor_topic' => 'topic_'.$topic_id,
1886
                                    'topics_page_nr' => $topic_page_nr,
1887
                                    'items_page_nr' => $items_page_nr,
1888
                                    'topic_id' => $topic_id,
1889
                                ]
1890
                            ),
1891
                        'pencil',
1892
                        'default',
1893
                        ['class' => 'ajax', 'data-title' => $langEdit, 'data-size' => 'lg'],
1894
                        false
1895
                    );
1896
                }
1897
1898
                $links .= self::getLikesButton($topic['id'], $current_user_id, $groupId);
1899
1900
                $links .= Display::toolbarButton(
1901
                    $langReply,
1902
                    $webCodePath.'social/message_for_group_form.inc.php?'
1903
                        .http_build_query(
1904
                            [
1905
                                'user_friend' => $current_user_id,
1906
                                'group_id' => $groupId,
1907
                                'message_id' => $topic['id'],
1908
                                'action' => 'reply_message_group',
1909
                                'anchor_topic' => 'topic_'.$topic_id,
1910
                                'topics_page_nr' => $topic_page_nr,
1911
                                'items_page_nr' => $items_page_nr,
1912
                                'topic_id' => $topic_id,
1913
                            ]
1914
                        ),
1915
                    'commenting',
1916
                    'default',
1917
                    ['class' => 'ajax', 'data-title' => $langReply, 'data-size' => 'lg'],
1918
                    false
1919
                );
1920
                $links .= '</div>';
1921
                $links .= '</div>';
1922
1923
                $userPicture = $user_sender_info['avatar'];
1924
                $user_link = Display::url(
1925
                    $name,
1926
                    $webCodePath.'social/profile.php?u='.$topic['user_sender_id']
1927
                );
1928
                $html_items .= '<div class="row">';
1929
                $html_items .= '<div class="col-md-2">';
1930
                $html_items .= '<div class="avatar-author">';
1931
                $html_items .= Display::img(
1932
                    $userPicture,
1933
                    $name,
1934
                    ['width' => '60px', 'class' => 'img-responsive img-circle'],
1935
                    false
1936
                );
1937
                $html_items .= '</div>';
1938
                $html_items .= '</div>';
1939
1940
                $date = '';
1941
                if ($topic['send_date'] != $topic['update_date']) {
1942
                    if (!empty($topic['update_date'])) {
1943
                        $date = '<div class="date"> '
1944
                            ."$iconCalendar $langLastUpdated "
1945
                            .Display::dateToStringAgoAndLongDate($topic['update_date'])
1946
                            .'</div>';
1947
                    }
1948
                } else {
1949
                    $date = '<div class="date"> '
1950
                        ."$iconCalendar $langCreated "
1951
                        .Display::dateToStringAgoAndLongDate($topic['send_date'])
1952
                        .'</div>';
1953
                }
1954
                $attachment = '<div class="message-attach">'
1955
                    .(!empty($files_attachments) ? implode('<br />', $files_attachments) : '')
1956
                    .'</div>';
1957
                $html_items .= '<div class="col-md-10">'
1958
                    .'<div class="message-content">'
1959
                    .$links
1960
                    .'<div class="username">'.$user_link.'</div>'
1961
                    .$date
1962
                    .'<div class="message">'
1963
                    .Security::remove_XSS($topic['content'], STUDENT, true)
1964
                    .'</div>'.$attachment.'</div>'
1965
                    .'</div>'
1966
                    .'</div>';
1967
1968
                $base_padding = 20;
1969
1970
                if (0 == $topic['indent_cnt']) {
1971
                    $indent = $base_padding;
1972
                } else {
1973
                    $indent = (int) $topic['indent_cnt'] * $base_padding + $base_padding;
1974
                }
1975
1976
                $html_items = Display::div($html_items, ['class' => 'message-post', 'id' => 'msg_'.$topic['id']]);
1977
                $html_items = Display::div($html_items, ['class' => '', 'style' => 'margin-left:'.$indent.'px']);
1978
                $array_html_items[] = [$html_items];
1979
            }
1980
1981
            // grids for items with paginations
1982
            $options = ['hide_navigation' => false, 'per_page' => $items_per_page];
1983
            $visibility = [true, true, true, false];
1984
1985
            $style_class = [
1986
                'item' => ['class' => 'user-post'],
1987
                'main' => ['class' => 'user-list'],
1988
            ];
1989
            if (!empty($array_html_items)) {
1990
                $html .= Display::return_sortable_grid(
1991
                    'items_'.$topic['id'],
1992
                    [],
1993
                    $array_html_items,
1994
                    $options,
1995
                    $query_vars,
1996
                    null,
1997
                    $visibility,
1998
                    false,
1999
                    $style_class
2000
                );
2001
            }
2002
        }
2003
2004
        return $html;
2005
    }
2006
2007
    /**
2008
     * Add children to messages by id is used for nested view messages.
2009
     *
2010
     * @param array $rows rows of messages
2011
     *
2012
     * @return array $first_seed new list adding the item children
2013
     */
2014
    public static function calculate_children($rows, $first_seed)
2015
    {
2016
        $rows_with_children = [];
2017
        foreach ($rows as $row) {
2018
            $rows_with_children[$row["id"]] = $row;
2019
            $rows_with_children[$row["parent_id"]]["children"][] = $row["id"];
2020
        }
2021
        $rows = $rows_with_children;
2022
        $sorted_rows = [0 => []];
2023
        self::message_recursive_sort($rows, $sorted_rows, $first_seed);
2024
        unset($sorted_rows[0]);
2025
2026
        return $sorted_rows;
2027
    }
2028
2029
    /**
2030
     * Sort recursively the messages, is used for for nested view messages.
2031
     *
2032
     * @param array  original rows of messages
2033
     * @param array  list recursive of messages
2034
     * @param int   seed for calculate the indent
2035
     * @param int   indent for nested view
2036
     */
2037
    public static function message_recursive_sort(
2038
        $rows,
2039
        &$messages,
2040
        $seed = 0,
2041
        $indent = 0
2042
    ) {
2043
        if ($seed > 0 && isset($rows[$seed]["id"])) {
2044
            $messages[$rows[$seed]["id"]] = $rows[$seed];
2045
            $messages[$rows[$seed]["id"]]["indent_cnt"] = $indent;
2046
            $indent++;
2047
        }
2048
2049
        if (isset($rows[$seed]["children"])) {
2050
            foreach ($rows[$seed]["children"] as $child) {
2051
                self::message_recursive_sort($rows, $messages, $child, $indent);
2052
            }
2053
        }
2054
    }
2055
2056
    /**
2057
     * @param int $messageId
2058
     *
2059
     * @return array
2060
     */
2061
    public static function getAttachmentList($messageId)
2062
    {
2063
        $table = Database::get_main_table(TABLE_MESSAGE_ATTACHMENT);
2064
        $messageId = (int) $messageId;
2065
2066
        if (empty($messageId)) {
2067
            return [];
2068
        }
2069
2070
        $messageInfo = self::get_message_by_id($messageId);
2071
2072
        if (empty($messageInfo)) {
2073
            return [];
2074
        }
2075
2076
        $attachmentDir = UserManager::getUserPathById($messageInfo['user_receiver_id'], 'system');
2077
        $attachmentDir .= 'message_attachments/';
2078
2079
        $sql = "SELECT * FROM $table
2080
                WHERE message_id = '$messageId'";
2081
        $result = Database::query($sql);
2082
        $files = [];
2083
        while ($row = Database::fetch_array($result, 'ASSOC')) {
2084
            $row['file_source'] = '';
2085
            if (file_exists($attachmentDir.$row['path'])) {
2086
                $row['file_source'] = $attachmentDir.$row['path'];
2087
            }
2088
            $files[] = $row;
2089
        }
2090
2091
        return $files;
2092
    }
2093
2094
    /**
2095
     * Get array of links (download) for message attachment files.
2096
     *
2097
     * @param int $messageId
2098
     * @param int $type
2099
     *
2100
     * @return array
2101
     */
2102
    public static function getAttachmentLinkList($messageId, $type)
2103
    {
2104
        $files = self::getAttachmentList($messageId);
2105
        // get file attachments by message id
2106
        $list = [];
2107
        if ($files) {
2108
            $attachIcon = Display::return_icon('attachment.gif', '');
2109
            $archiveURL = api_get_path(WEB_CODE_PATH).'messages/download.php?type='.$type.'&file=';
2110
            foreach ($files as $row_file) {
2111
                $archiveFile = $row_file['path'];
2112
                $filename = $row_file['filename'];
2113
                $size = format_file_size($row_file['size']);
2114
                $comment = Security::remove_XSS($row_file['comment']);
2115
                $filename = Security::remove_XSS($filename);
2116
                $link = Display::url($filename, $archiveURL.$archiveFile);
2117
                $comment = !empty($comment) ? '&nbsp;-&nbsp;<i>'.$comment.'</i>' : '';
2118
2119
                $attachmentLine = $attachIcon.'&nbsp;'.$link.'&nbsp;('.$size.')'.$comment;
2120
                if ($row_file['comment'] === 'audio_message') {
2121
                    $attachmentLine = '<audio src="'.$archiveURL.$archiveFile.'"/>';
2122
                }
2123
                $list[] = $attachmentLine;
2124
            }
2125
        }
2126
2127
        return $list;
2128
    }
2129
2130
    /**
2131
     * Get message list by id.
2132
     *
2133
     * @param int $messageId
2134
     *
2135
     * @return array
2136
     */
2137
    public static function get_message_by_id($messageId)
2138
    {
2139
        $table = Database::get_main_table(TABLE_MESSAGE);
2140
        $messageId = (int) $messageId;
2141
        $sql = "SELECT * FROM $table
2142
                WHERE
2143
                    id = '$messageId' AND
2144
                    msg_status <> '".MESSAGE_STATUS_DELETED."' ";
2145
        $res = Database::query($sql);
2146
        $item = [];
2147
        if (Database::num_rows($res) > 0) {
2148
            $item = Database::fetch_array($res, 'ASSOC');
2149
        }
2150
2151
        return $item;
2152
    }
2153
2154
    /**
2155
     * @return string
2156
     */
2157
    public static function generate_message_form()
2158
    {
2159
        $form = new FormValidator('send_message');
2160
        $form->addText(
2161
            'subject',
2162
            get_lang('Subject'),
2163
            false,
2164
            ['id' => 'subject_id']
2165
        );
2166
        $form->addTextarea(
2167
            'content',
2168
            get_lang('Message'),
2169
            ['id' => 'content_id', 'rows' => '5']
2170
        );
2171
2172
        return $form->returnForm();
2173
    }
2174
2175
    /**
2176
     * @return string
2177
     */
2178
    public static function generate_invitation_form()
2179
    {
2180
        $form = new FormValidator('send_invitation');
2181
        $form->addTextarea(
2182
            'content',
2183
            get_lang('AddPersonalMessage'),
2184
            ['id' => 'content_invitation_id', 'rows' => 5]
2185
        );
2186
2187
        return $form->returnForm();
2188
    }
2189
2190
    /**
2191
     * @param string $type
2192
     * @param string $keyword
2193
     * @param array  $actions
2194
     *
2195
     * @return string
2196
     */
2197
    public static function getMessageGrid($type, $keyword, $actions = [])
2198
    {
2199
        $html = '';
2200
        // display sortable table with messages of the current user
2201
        $table = new SortableTable(
2202
            'message_inbox',
2203
            ['MessageManager', 'getNumberOfMessages'],
2204
            ['MessageManager', 'getMessageData'],
2205
            2,
2206
            20,
2207
            'DESC'
2208
        );
2209
        $table->setDataFunctionParams(
2210
            ['keyword' => $keyword, 'type' => $type, 'actions' => $actions]
2211
        );
2212
        $table->set_header(0, '', false, ['style' => 'width:15px;']);
2213
        $table->set_header(1, get_lang('Messages'), false);
2214
        $table->set_header(2, get_lang('Date'), true, ['style' => 'width:180px;']);
2215
        $table->set_header(3, get_lang('Modify'), false, ['style' => 'width:120px;']);
2216
2217
        if (isset($_REQUEST['f']) && $_REQUEST['f'] === 'social') {
2218
            $parameters['f'] = 'social';
2219
            $table->set_additional_parameters($parameters);
2220
        }
2221
2222
        $defaultActions = [
2223
            'delete' => get_lang('DeleteSelectedMessages'),
2224
            'mark_as_unread' => get_lang('MailMarkSelectedAsUnread'),
2225
            'mark_as_read' => get_lang('MailMarkSelectedAsRead'),
2226
        ];
2227
2228
        if (!in_array('delete', $actions)) {
2229
            unset($defaultActions['delete']);
2230
        }
2231
        if (!in_array('mark_as_unread', $actions)) {
2232
            unset($defaultActions['mark_as_unread']);
2233
        }
2234
        if (!in_array('mark_as_read', $actions)) {
2235
            unset($defaultActions['mark_as_read']);
2236
        }
2237
2238
        $table->set_form_actions($defaultActions);
2239
2240
        $html .= $table->return_table();
2241
2242
        return $html;
2243
    }
2244
2245
    /**
2246
     * @param string $keyword
2247
     *
2248
     * @return string
2249
     */
2250
    public static function inboxDisplay($keyword = '')
2251
    {
2252
        $success = get_lang('SelectedMessagesDeleted');
2253
        $success_read = get_lang('SelectedMessagesRead');
2254
        $success_unread = get_lang('SelectedMessagesUnRead');
2255
        $currentUserId = api_get_user_id();
2256
2257
        if (isset($_REQUEST['action'])) {
2258
            switch ($_REQUEST['action']) {
2259
                case 'mark_as_unread':
2260
                    if (is_array($_POST['id'])) {
2261
                        foreach ($_POST['id'] as $index => $messageId) {
2262
                            self::update_message_status(
2263
                                $currentUserId,
2264
                                $messageId,
2265
                                MESSAGE_STATUS_UNREAD
2266
                            );
2267
                        }
2268
                    }
2269
                    Display::addFlash(Display::return_message(
2270
                        $success_unread,
2271
                        'normal',
2272
                        false
2273
                    ));
2274
                    break;
2275
                case 'mark_as_read':
2276
                    if (is_array($_POST['id'])) {
2277
                        foreach ($_POST['id'] as $index => $messageId) {
2278
                            self::update_message_status(
2279
                                $currentUserId,
2280
                                $messageId,
2281
                                MESSAGE_STATUS_NEW
2282
                            );
2283
                        }
2284
                    }
2285
                    Display::addFlash(Display::return_message(
2286
                        $success_read,
2287
                        'normal',
2288
                        false
2289
                    ));
2290
                    break;
2291
                case 'delete':
2292
                    foreach ($_POST['id'] as $index => $messageId) {
2293
                        self::delete_message_by_user_receiver($currentUserId, $messageId);
2294
                    }
2295
                    Display::addFlash(Display::return_message(
2296
                        $success,
2297
                        'normal',
2298
                        false
2299
                    ));
2300
                    break;
2301
                case 'deleteone':
2302
                    $result = self::delete_message_by_user_receiver($currentUserId, $_GET['id']);
2303
                    if ($result) {
2304
                        Display::addFlash(
2305
                            Display::return_message(
2306
                                $success,
2307
                                'confirmation',
2308
                                false
2309
                            )
2310
                        );
2311
                    }
2312
                    break;
2313
            }
2314
            header('Location: '.api_get_self());
2315
            exit;
2316
        }
2317
2318
        $actions = ['reply', 'mark_as_unread', 'mark_as_read', 'forward', 'delete'];
2319
2320
        return self::getMessageGrid(self::MESSAGE_TYPE_INBOX, $keyword, $actions);
2321
    }
2322
2323
    /**
2324
     * @param string $keyword
2325
     *
2326
     * @return string
2327
     */
2328
    public static function getPromotedMessagesGrid($keyword)
2329
    {
2330
        $actions = ['delete'];
2331
        $currentUserId = api_get_user_id();
2332
2333
        $success = get_lang('SelectedMessagesDeleted');
2334
        if (isset($_REQUEST['action'])) {
2335
            switch ($_REQUEST['action']) {
2336
                case 'delete':
2337
                    foreach ($_POST['id'] as $index => $messageId) {
2338
                        self::delete_message_by_user_receiver($currentUserId, $messageId);
2339
                    }
2340
                    Display::addFlash(Display::return_message(
2341
                        $success,
2342
                        'normal',
2343
                        false
2344
                    ));
2345
                    break;
2346
                case 'deleteone':
2347
                    self::delete_message_by_user_receiver($currentUserId, $_GET['id']);
2348
                    Display::addFlash(Display::return_message(
2349
                        $success,
2350
                        'confirmation',
2351
                        false
2352
                    ));
2353
                    break;
2354
            }
2355
2356
            header('Location: '.api_get_self());
2357
            exit;
2358
        }
2359
2360
        $html = self::getMessageGrid(self::MESSAGE_TYPE_PROMOTED, $keyword, $actions);
2361
2362
        return $html;
2363
    }
2364
2365
    /**
2366
     * @param string $keyword
2367
     *
2368
     * @return string
2369
     */
2370
    public static function outBoxDisplay($keyword)
2371
    {
2372
        $actions = ['delete'];
2373
2374
        $success = get_lang('SelectedMessagesDeleted');
2375
        $currentUserId = api_get_user_id();
2376
        if (isset($_REQUEST['action'])) {
2377
            switch ($_REQUEST['action']) {
2378
                case 'delete':
2379
                    foreach ($_POST['id'] as $index => $messageId) {
2380
                        self::delete_message_by_user_sender($currentUserId, $messageId);
2381
                    }
2382
                    Display::addFlash(Display::return_message(
2383
                        $success,
2384
                        'normal',
2385
                        false
2386
                    ));
2387
2388
                    break;
2389
                case 'deleteone':
2390
                    self::delete_message_by_user_sender($currentUserId, $_GET['id']);
2391
                    Display::addFlash(Display::return_message(
2392
                        $success,
2393
                        'confirmation',
2394
                        false
2395
                    ));
2396
                    break;
2397
            }
2398
2399
            header('Location: '.api_get_self());
2400
            exit;
2401
        }
2402
2403
        $html = self::getMessageGrid(self::MESSAGE_TYPE_OUTBOX, $keyword, $actions);
2404
2405
        return $html;
2406
    }
2407
2408
    /**
2409
     * @param string $keyword
2410
     *
2411
     * @return string
2412
     */
2413
    public static function outbox_display($keyword = '')
2414
    {
2415
        Session::write('message_sent_search_keyword', $keyword);
2416
        $success = get_lang('SelectedMessagesDeleted').'&nbsp</b><br />
2417
                    <a href="outbox.php">'.get_lang('BackToOutbox').'</a>';
2418
2419
        $html = '';
2420
        if (isset($_REQUEST['action'])) {
2421
            switch ($_REQUEST['action']) {
2422
                case 'delete':
2423
                    $count = count($_POST['id']);
2424
                    if ($count != 0) {
2425
                        foreach ($_POST['id'] as $index => $messageId) {
2426
                            self::delete_message_by_user_receiver(
2427
                                api_get_user_id(),
2428
                                $messageId
2429
                            );
2430
                        }
2431
                    }
2432
                    $html .= Display::return_message(api_xml_http_response_encode($success), 'normal', false);
2433
                    break;
2434
                case 'deleteone':
2435
                    self::delete_message_by_user_receiver(api_get_user_id(), $_GET['id']);
2436
                    $html .= Display::return_message(api_xml_http_response_encode($success), 'normal', false);
2437
                    $html .= '<br/>';
2438
                    break;
2439
            }
2440
        }
2441
2442
        // display sortable table with messages of the current user
2443
        $table = new SortableTable(
2444
            'message_outbox',
2445
            ['MessageManager', 'getNumberOfMessages'],
2446
            ['MessageManager', 'getMessageData'],
2447
            2,
2448
            20,
2449
            'DESC'
2450
        );
2451
        $table->setDataFunctionParams(
2452
            ['keyword' => $keyword, 'type' => self::MESSAGE_TYPE_OUTBOX]
2453
        );
2454
2455
        $table->set_header(0, '', false, ['style' => 'width:15px;']);
2456
        $table->set_header(1, get_lang('Messages'), false);
2457
        $table->set_header(2, get_lang('Date'), true, ['style' => 'width:180px;']);
2458
        $table->set_header(3, get_lang('Modify'), false, ['style' => 'width:70px;']);
2459
2460
        $table->set_form_actions(['delete' => get_lang('DeleteSelectedMessages')]);
2461
        $html .= $table->return_table();
2462
2463
        return $html;
2464
    }
2465
2466
    /**
2467
     * Get the data of the last received messages for a user.
2468
     *
2469
     * @param int $userId The user id
2470
     * @param int $lastId The id of the last received message
2471
     *
2472
     * @return array
2473
     */
2474
    public static function getMessagesFromLastReceivedMessage($userId, $lastId = 0)
2475
    {
2476
        $userId = (int) $userId;
2477
        $lastId = (int) $lastId;
2478
2479
        if (empty($userId)) {
2480
            return [];
2481
        }
2482
2483
        $messagesTable = Database::get_main_table(TABLE_MESSAGE);
2484
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
2485
2486
        $sql = "SELECT m.*, u.user_id, u.lastname, u.firstname
2487
                FROM $messagesTable as m
2488
                INNER JOIN $userTable as u
2489
                ON m.user_sender_id = u.user_id
2490
                WHERE
2491
                    m.user_receiver_id = $userId AND
2492
                    m.msg_status = ".MESSAGE_STATUS_UNREAD."
2493
                    AND m.id > $lastId
2494
                ORDER BY m.send_date DESC";
2495
2496
        $result = Database::query($sql);
2497
2498
        $messages = [];
2499
        if ($result !== false) {
2500
            while ($row = Database::fetch_assoc($result)) {
2501
                $messages[] = $row;
2502
            }
2503
        }
2504
2505
        return $messages;
2506
    }
2507
2508
    /**
2509
     * Get the data of the last received messages for a user.
2510
     *
2511
     * @param int $userId The user id
2512
     * @param int $lastId The id of the last received message
2513
     *
2514
     * @return array
2515
     */
2516
    public static function getReceivedMessages($userId, $lastId = 0)
2517
    {
2518
        $userId = intval($userId);
2519
        $lastId = intval($lastId);
2520
2521
        if (empty($userId)) {
2522
            return [];
2523
        }
2524
        $messagesTable = Database::get_main_table(TABLE_MESSAGE);
2525
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
2526
        $sql = "SELECT m.*, u.user_id, u.lastname, u.firstname, u.picture_uri
2527
                FROM $messagesTable as m
2528
                INNER JOIN $userTable as u
2529
                ON m.user_sender_id = u.user_id
2530
                WHERE
2531
                    m.user_receiver_id = $userId AND
2532
                    m.msg_status IN (".MESSAGE_STATUS_NEW.", ".MESSAGE_STATUS_UNREAD.")
2533
                    AND m.id > $lastId
2534
                ORDER BY m.send_date DESC";
2535
2536
        $result = Database::query($sql);
2537
2538
        $messages = [];
2539
        if ($result !== false) {
2540
            while ($row = Database::fetch_assoc($result)) {
2541
                $pictureInfo = UserManager::get_user_picture_path_by_id($row['user_id'], 'web');
2542
                $row['pictureUri'] = $pictureInfo['dir'].$pictureInfo['file'];
2543
                $messages[] = $row;
2544
            }
2545
        }
2546
2547
        return $messages;
2548
    }
2549
2550
    /**
2551
     * Get the data of the last received messages for a user.
2552
     *
2553
     * @param int $userId The user id
2554
     * @param int $lastId The id of the last received message
2555
     *
2556
     * @return array
2557
     */
2558
    public static function getSentMessages($userId, $lastId = 0)
2559
    {
2560
        $userId = intval($userId);
2561
        $lastId = intval($lastId);
2562
2563
        if (empty($userId)) {
2564
            return [];
2565
        }
2566
2567
        $messagesTable = Database::get_main_table(TABLE_MESSAGE);
2568
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
2569
2570
        $sql = "SELECT m.*, u.user_id, u.lastname, u.firstname, u.picture_uri
2571
                FROM $messagesTable as m
2572
                INNER JOIN $userTable as u
2573
                ON m.user_receiver_id = u.user_id
2574
                WHERE
2575
                    m.user_sender_id = $userId
2576
                    AND m.msg_status = ".MESSAGE_STATUS_OUTBOX."
2577
                    AND m.id > $lastId
2578
                ORDER BY m.send_date DESC";
2579
2580
        $result = Database::query($sql);
2581
2582
        $messages = [];
2583
        if ($result !== false) {
2584
            while ($row = Database::fetch_assoc($result)) {
2585
                $pictureInfo = UserManager::get_user_picture_path_by_id($row['user_id'], 'web');
2586
                $row['pictureUri'] = $pictureInfo['dir'].$pictureInfo['file'];
2587
                $messages[] = $row;
2588
            }
2589
        }
2590
2591
        return $messages;
2592
    }
2593
2594
    /**
2595
     * Check whether a message has attachments.
2596
     *
2597
     * @param int $messageId The message id
2598
     *
2599
     * @return bool Whether the message has attachments return true. Otherwise return false
2600
     */
2601
    public static function hasAttachments($messageId)
2602
    {
2603
        $messageId = (int) $messageId;
2604
2605
        if (empty($messageId)) {
2606
            return false;
2607
        }
2608
2609
        $messageAttachmentTable = Database::get_main_table(TABLE_MESSAGE_ATTACHMENT);
2610
2611
        $conditions = [
2612
            'where' => [
2613
                'message_id = ?' => $messageId,
2614
            ],
2615
        ];
2616
2617
        $result = Database::select(
2618
            'COUNT(1) AS qty',
2619
            $messageAttachmentTable,
2620
            $conditions,
2621
            'first'
2622
        );
2623
2624
        if (!empty($result)) {
2625
            if ($result['qty'] > 0) {
2626
                return true;
2627
            }
2628
        }
2629
2630
        return false;
2631
    }
2632
2633
    /**
2634
     * @param int $messageId
2635
     *
2636
     * @return array|bool
2637
     */
2638
    public static function getAttachment($messageId)
2639
    {
2640
        $messageId = (int) $messageId;
2641
2642
        if (empty($messageId)) {
2643
            return false;
2644
        }
2645
2646
        $table = Database::get_main_table(TABLE_MESSAGE_ATTACHMENT);
2647
2648
        $conditions = [
2649
            'where' => [
2650
                'id = ?' => $messageId,
2651
            ],
2652
        ];
2653
2654
        $result = Database::select(
2655
            '*',
2656
            $table,
2657
            $conditions,
2658
            'first'
2659
        );
2660
2661
        if (!empty($result)) {
2662
            return $result;
2663
        }
2664
2665
        return false;
2666
    }
2667
2668
    /**
2669
     * @param string $url
2670
     *
2671
     * @return FormValidator
2672
     */
2673
    public static function getSearchForm($url)
2674
    {
2675
        $form = new FormValidator(
2676
            'search',
2677
            'post',
2678
            $url,
2679
            null,
2680
            [],
2681
            FormValidator::LAYOUT_INLINE
2682
        );
2683
2684
        $form->addElement(
2685
            'text',
2686
            'keyword',
2687
            false,
2688
            [
2689
                'aria-label' => get_lang('Search'),
2690
            ]
2691
        );
2692
        $form->addButtonSearch(get_lang('Search'));
2693
2694
        return $form;
2695
    }
2696
2697
    /**
2698
     * Send a notification to all admins when a new user is registered.
2699
     */
2700
    public static function sendNotificationOfNewRegisteredUser(User $user)
2701
    {
2702
        $tplMailBody = new Template(
2703
            null,
2704
            false,
2705
            false,
2706
            false,
2707
            false,
2708
            false,
2709
            false
2710
        );
2711
        $tplMailBody->assign('user', $user);
2712
        $tplMailBody->assign('is_western_name_order', api_is_western_name_order());
2713
        $tplMailBody->assign(
2714
            'manageUrl',
2715
            api_get_path(WEB_CODE_PATH).'admin/user_edit.php?user_id='.$user->getId()
2716
        );
2717
2718
        $layoutContent = $tplMailBody->get_template('mail/new_user_mail_to_admin.tpl');
2719
2720
        $emailsubject = '['.get_lang('UserRegistered').'] '.$user->getUsername();
2721
        $emailbody = $tplMailBody->fetch($layoutContent);
2722
2723
        $admins = UserManager::get_all_administrators();
2724
2725
        foreach ($admins as $admin_info) {
2726
            self::send_message(
2727
                $admin_info['user_id'],
2728
                $emailsubject,
2729
                $emailbody,
2730
                [],
2731
                [],
2732
                null,
2733
                null,
2734
                null,
2735
                null,
2736
                $user->getId()
2737
            );
2738
        }
2739
    }
2740
2741
    /**
2742
     * Send a notification to all admins when a new user is registered
2743
     * while the approval method is used for users registration.
2744
     */
2745
    public static function sendNotificationOfNewRegisteredUserApproval(User $user)
2746
    {
2747
        $tplMailBody = new Template(
2748
            null,
2749
            false,
2750
            false,
2751
            false,
2752
            false,
2753
            false,
2754
            false
2755
        );
2756
        $tplMailBody->assign('user', $user);
2757
        $tplMailBody->assign('is_western_name_order', api_is_western_name_order());
2758
        $userId = $user->getId();
2759
        $url_edit = Display::url(
2760
            api_get_path(WEB_CODE_PATH).'admin/user_edit.php?user_id='.$userId,
2761
            api_get_path(WEB_CODE_PATH).'admin/user_edit.php?user_id='.$userId
2762
        );
2763
        $tplMailBody->assign(
2764
            'manageUrl',
2765
            $url_edit
2766
        );
2767
        // Get extra field values for this user and reformat the array
2768
        $extraFieldValues = new ExtraFieldValue('user');
2769
        $userExtraFields = $extraFieldValues->getAllValuesByItem($userId);
2770
        $values = [];
2771
        foreach ($userExtraFields as $field => $value) {
2772
            $values[$value['variable']] = $value['value'];
2773
        }
2774
        $tplMailBody->assign(
2775
            'extra',
2776
            $values
2777
        );
2778
        $layoutContent = '';
2779
        $emailbody = '';
2780
        if (api_get_configuration_value('mail_template_system') == true) {
2781
            $mailTemplateManager = new MailTemplateManager();
2782
            $templateText = $mailTemplateManager->getTemplateByType('new_user_mail_to_admin_approval.tpl');
2783
            if (empty($templateText)) {
2784
            } else {
2785
                // custom procedure to load a template as a string (doesn't use cache so may slow down)
2786
                $template = $tplMailBody->twig->createTemplate($templateText);
2787
                $emailbody = $template->render($tplMailBody->params);
2788
            }
2789
        }
2790
        if (empty($emailbody)) {
2791
            $layoutContent = $tplMailBody->get_template('mail/new_user_mail_to_admin_approval.tpl');
2792
            $emailbody = $tplMailBody->fetch($layoutContent);
2793
        }
2794
2795
        $emailsubject = '['.get_lang('ApprovalForNewAccount').'] '.$user->getUsername();
2796
2797
        if (api_get_configuration_value('send_inscription_notification_to_general_admin_only')) {
2798
            $email = api_get_setting('emailAdministrator');
2799
            $firstname = api_get_setting('administratorSurname');
2800
            $lastname = api_get_setting('administratorName');
2801
            api_mail_html("$firstname $lastname", $email, $emailsubject, $emailbody);
2802
        } else {
2803
            $admins = UserManager::get_all_administrators();
2804
            foreach ($admins as $admin_info) {
2805
                self::send_message(
2806
                    $admin_info['user_id'],
2807
                    $emailsubject,
2808
                    $emailbody,
2809
                    [],
2810
                    [],
2811
                    null,
2812
                    null,
2813
                    null,
2814
                    null,
2815
                    $userId
2816
                );
2817
            }
2818
        }
2819
    }
2820
2821
    /**
2822
     * Get the error log from failed mailing
2823
     * This assumes a complex setup where you have a cron script regularly copying the mail queue log
2824
     * into app/cache/mail/mailq.
2825
     * This can be done with a cron command like (check the location of your mail log file first):.
2826
     *
2827
     * @example 0,30 * * * * root cp /var/log/exim4/mainlog /var/www/chamilo/app/cache/mail/mailq
2828
     *
2829
     * @return array|bool
2830
     */
2831
    public static function failedSentMailErrors()
2832
    {
2833
        $base = api_get_path(SYS_ARCHIVE_PATH).'mail/';
2834
        $mailq = $base.'mailq';
2835
2836
        if (!file_exists($mailq) || !is_readable($mailq)) {
2837
            return false;
2838
        }
2839
2840
        $file = fopen($mailq, 'r');
2841
        $i = 1;
2842
        while (!feof($file)) {
2843
            $line = fgets($file);
2844
2845
            if (trim($line) == '') {
2846
                continue;
2847
            }
2848
2849
            // Get the mail code, something like 1WBumL-0002xg-FF
2850
            if (preg_match('/(.*)\s((.*)-(.*)-(.*))\s<(.*)$/', $line, $codeMatches)) {
2851
                $mail_queue[$i]['code'] = $codeMatches[2];
2852
            }
2853
2854
            $fullMail = $base.$mail_queue[$i]['code'];
2855
            $mailFile = fopen($fullMail, 'r');
2856
2857
            // Get the reason of mail fail
2858
            $iX = 1;
2859
            while (!feof($mailFile)) {
2860
                $mailLine = fgets($mailFile);
2861
                //if ($iX == 4 && preg_match('/(.*):\s(.*)$/', $mailLine, $matches)) {
2862
                if ($iX == 2 &&
2863
                    preg_match('/(.*)(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\s(.*)/', $mailLine, $detailsMatches)
2864
                ) {
2865
                    $mail_queue[$i]['reason'] = $detailsMatches[3];
2866
                }
2867
                $iX++;
2868
            }
2869
2870
            fclose($mailFile);
2871
2872
            // Get the time of mail fail
2873
            if (preg_match('/^\s?(\d+)(\D+)\s+(.*)$/', $line, $timeMatches)) {
2874
                $mail_queue[$i]['time'] = $timeMatches[1].$timeMatches[2];
2875
            } elseif (preg_match('/^(\s+)((.*)@(.*))\s+(.*)$/', $line, $emailMatches)) {
2876
                $mail_queue[$i]['mail'] = $emailMatches[2];
2877
                $i++;
2878
            }
2879
        }
2880
2881
        fclose($file);
2882
2883
        return array_reverse($mail_queue);
2884
    }
2885
2886
    /**
2887
     * @param int      $userId
2888
     * @param datetime $startDate
2889
     * @param datetime $endDate
2890
     *
2891
     * @return array
2892
     */
2893
    public static function getUsersThatHadConversationWithUser($userId, $startDate = null, $endDate = null)
2894
    {
2895
        $messagesTable = Database::get_main_table(TABLE_MESSAGE);
2896
        $userId = (int) $userId;
2897
2898
        $sql = "SELECT DISTINCT
2899
                    user_sender_id
2900
                FROM $messagesTable
2901
                WHERE
2902
                    user_receiver_id = ".$userId;
2903
2904
        if ($startDate != null) {
2905
            $startDate = Database::escape_string($startDate);
2906
            $sql .= " AND send_date >= '".$startDate."'";
2907
        }
2908
2909
        if ($endDate != null) {
2910
            $endDate = Database::escape_string($endDate);
2911
            $sql .= " AND send_date <= '".$endDate."'";
2912
        }
2913
2914
        $result = Database::query($sql);
2915
        $users = Database::store_result($result);
2916
        $userList = [];
2917
        foreach ($users as $userData) {
2918
            $userId = $userData['user_sender_id'];
2919
            if (empty($userId)) {
2920
                continue;
2921
            }
2922
            $userInfo = api_get_user_info($userId);
2923
            if ($userInfo) {
2924
                $userList[$userId] = $userInfo;
2925
            }
2926
        }
2927
2928
        return $userList;
2929
    }
2930
2931
    /**
2932
     * @param int      $userId
2933
     * @param int      $otherUserId
2934
     * @param datetime $startDate
2935
     * @param datetime $endDate
2936
     *
2937
     * @return array
2938
     */
2939
    public static function getAllMessagesBetweenStudents($userId, $otherUserId, $startDate = null, $endDate = null)
2940
    {
2941
        $messagesTable = Database::get_main_table(TABLE_MESSAGE);
2942
        $userId = (int) $userId;
2943
        $otherUserId = (int) $otherUserId;
2944
2945
        if (empty($otherUserId) || empty($userId)) {
2946
            return [];
2947
        }
2948
2949
        $sql = "SELECT DISTINCT *
2950
                FROM $messagesTable
2951
                WHERE
2952
                    ((user_receiver_id = $userId AND user_sender_id = $otherUserId) OR
2953
                    (user_receiver_id = $otherUserId AND user_sender_id = $userId))
2954
            ";
2955
        if ($startDate != null) {
2956
            $startDate = Database::escape_string($startDate);
2957
            $sql .= " AND send_date >= '".$startDate."'";
2958
        }
2959
        if ($endDate != null) {
2960
            $endDate = Database::escape_string($endDate);
2961
            $sql .= " AND send_date <= '".$endDate."'";
2962
        }
2963
        $sql .= " ORDER BY send_date DESC";
2964
        $result = Database::query($sql);
2965
        $messages = Database::store_result($result);
2966
        $list = [];
2967
        foreach ($messages as $message) {
2968
            $list[] = $message;
2969
        }
2970
2971
        return $list;
2972
    }
2973
2974
    /**
2975
     * @param string $subject
2976
     * @param string $message
2977
     * @param array  $courseInfo
2978
     * @param int    $sessionId
2979
     *
2980
     * @return bool
2981
     */
2982
    public static function sendMessageToAllUsersInCourse($subject, $message, $courseInfo, $sessionId = 0)
2983
    {
2984
        if (empty($courseInfo)) {
2985
            return false;
2986
        }
2987
2988
        $senderId = api_get_user_id();
2989
        if (empty($senderId)) {
2990
            return false;
2991
        }
2992
        if (empty($sessionId)) {
2993
            // Course students and teachers
2994
            $users = CourseManager::get_user_list_from_course_code($courseInfo['code']);
2995
        } else {
2996
            // Course-session students and course session coaches
2997
            $users = CourseManager::get_user_list_from_course_code($courseInfo['code'], $sessionId);
2998
        }
2999
3000
        if (empty($users)) {
3001
            return false;
3002
        }
3003
3004
        foreach ($users as $userInfo) {
3005
            self::send_message_simple(
3006
                $userInfo['user_id'],
3007
                $subject,
3008
                $message,
3009
                $senderId,
3010
                false,
3011
                false,
3012
                [],
3013
                false
3014
            );
3015
        }
3016
    }
3017
3018
    /**
3019
     * Clean audio messages already added in the message tool.
3020
     */
3021
    public static function cleanAudioMessage()
3022
    {
3023
        $audioId = Session::read('current_audio_id');
3024
        if (!empty($audioId)) {
3025
            api_remove_uploaded_file_by_id('audio_message', api_get_user_id(), $audioId);
3026
            Session::erase('current_audio_id');
3027
        }
3028
    }
3029
3030
    /**
3031
     * @param int    $senderId
3032
     * @param string $subject
3033
     * @param string $message
3034
     */
3035
    public static function sendMessageToAllAdminUsers(
3036
        $senderId,
3037
        $subject,
3038
        $message
3039
    ) {
3040
        $admins = UserManager::get_all_administrators();
3041
        foreach ($admins as $admin) {
3042
            self::send_message_simple($admin['user_id'], $subject, $message, $senderId);
3043
        }
3044
    }
3045
3046
    /**
3047
     * @param int $messageId
3048
     * @param int $userId
3049
     *
3050
     * @return array
3051
     */
3052
    public static function countLikesAndDislikes($messageId, $userId)
3053
    {
3054
        if (!api_get_configuration_value('social_enable_messages_feedback')) {
3055
            return [];
3056
        }
3057
3058
        $messageId = (int) $messageId;
3059
        $userId = (int) $userId;
3060
3061
        $em = Database::getManager();
3062
        $query = $em
3063
            ->createQuery('
3064
                SELECT SUM(l.liked) AS likes, SUM(l.disliked) AS dislikes FROM ChamiloCoreBundle:MessageFeedback l
3065
                WHERE l.message = :message
3066
            ')
3067
            ->setParameters(['message' => $messageId]);
3068
3069
        try {
3070
            $counts = $query->getSingleResult();
3071
        } catch (Exception $e) {
3072
            $counts = ['likes' => 0, 'dislikes' => 0];
3073
        }
3074
3075
        $userLike = $em
3076
            ->getRepository('ChamiloCoreBundle:MessageFeedback')
3077
            ->findOneBy(['message' => $messageId, 'user' => $userId]);
3078
3079
        return [
3080
            'likes' => (int) $counts['likes'],
3081
            'dislikes' => (int) $counts['dislikes'],
3082
            'user_liked' => $userLike ? $userLike->isLiked() : false,
3083
            'user_disliked' => $userLike ? $userLike->isDisliked() : false,
3084
        ];
3085
    }
3086
3087
    /**
3088
     * @param int $messageId
3089
     * @param int $userId
3090
     * @param int $groupId   Optional.
3091
     *
3092
     * @return string
3093
     */
3094
    public static function getLikesButton($messageId, $userId, $groupId = 0)
3095
    {
3096
        if (!api_get_configuration_value('social_enable_messages_feedback')) {
3097
            return '';
3098
        }
3099
3100
        $countLikes = self::countLikesAndDislikes($messageId, $userId);
3101
3102
        $class = $countLikes['user_liked'] ? 'btn-primary' : 'btn-default';
3103
3104
        $btnLike = Display::button(
3105
            'like',
3106
            Display::returnFontAwesomeIcon('thumbs-up', '', true)
3107
                .PHP_EOL.'<span>'.$countLikes['likes'].'</span>',
3108
            [
3109
                'title' => get_lang('VoteLike'),
3110
                'class' => 'btn  social-like '.$class,
3111
                'data-status' => 'like',
3112
                'data-message' => $messageId,
3113
                'data-group' => $groupId,
3114
            ]
3115
        );
3116
3117
        $btnDislike = '';
3118
        if (api_get_configuration_value('disable_dislike_option') === false) {
3119
            $disabled = $countLikes['user_disliked'] ? 'btn-danger' : 'btn-default';
3120
3121
            $btnDislike = Display::button(
3122
                'like',
3123
                Display::returnFontAwesomeIcon('thumbs-down', '', true)
3124
                .PHP_EOL.'<span>'.$countLikes['dislikes'].'</span>',
3125
                [
3126
                    'title' => get_lang('VoteDislike'),
3127
                    'class' => 'btn social-like '.$disabled,
3128
                    'data-status' => 'dislike',
3129
                    'data-message' => $messageId,
3130
                    'data-group' => $groupId,
3131
                ]
3132
            );
3133
        }
3134
3135
        return $btnLike.PHP_EOL.$btnDislike;
3136
    }
3137
3138
    /**
3139
     * Execute the SQL necessary to know the number of messages in the database.
3140
     *
3141
     * @param int $userId The user for which we need the unread messages count
3142
     *
3143
     * @return int The number of unread messages in the database for the given user
3144
     */
3145
    public static function getCountNewMessagesFromDB($userId)
3146
    {
3147
        $userId = (int) $userId;
3148
3149
        if (empty($userId)) {
3150
            return 0;
3151
        }
3152
3153
        $table = Database::get_main_table(TABLE_MESSAGE);
3154
        $sql = "SELECT COUNT(id) as count
3155
                FROM $table
3156
                WHERE
3157
                    user_receiver_id = $userId AND
3158
                    msg_status = ".MESSAGE_STATUS_UNREAD;
3159
        $result = Database::query($sql);
3160
        $row = Database::fetch_assoc($result);
3161
3162
        return (int) $row['count'];
3163
    }
3164
3165
    public static function getMessagesCountForUser(int $userId): array
3166
    {
3167
        // Setting notifications
3168
        $countUnreadMessage = 0;
3169
3170
        if (api_get_setting('allow_message_tool') === 'true') {
3171
            // get count unread message and total invitations
3172
            $countUnreadMessage = MessageManager::getCountNewMessagesFromDB($userId);
3173
        }
3174
3175
        if (api_get_setting('allow_social_tool') === 'true') {
3176
            $numberOfNewMessagesOfFriend = SocialManager::get_message_number_invitation_by_user_id(
3177
                $userId
3178
            );
3179
            $usergroup = new UserGroup();
3180
            $groupPendingInvitations = $usergroup->get_groups_by_user(
3181
                $userId,
3182
                GROUP_USER_PERMISSION_PENDING_INVITATION
3183
            );
3184
3185
            if (!empty($groupPendingInvitations)) {
3186
                $groupPendingInvitations = count($groupPendingInvitations);
3187
            } else {
3188
                $groupPendingInvitations = 0;
3189
            }
3190
3191
            return [
3192
                'ms_friends' => $numberOfNewMessagesOfFriend,
3193
                'ms_groups' => $groupPendingInvitations,
3194
                'ms_inbox' => $countUnreadMessage,
3195
            ];
3196
        }
3197
3198
        return [];
3199
    }
3200
3201
    /**
3202
     * @throws Exception
3203
     */
3204
    public static function setDefaultValuesInFormFromMessageInfo(array $messageInfo, FormValidator $form)
3205
    {
3206
        $currentUserId = api_get_user_id();
3207
        $contentMatch = [];
3208
        preg_match('/<body>(.*?)<\/body>/s', $messageInfo['content'], $contentMatch);
3209
3210
        $defaults = [
3211
            'title' => $messageInfo['title'],
3212
            'content' => $contentMatch[1] ?? '',
3213
        ];
3214
3215
        if (api_get_configuration_value('agenda_collective_invitations')) {
3216
            $defaults['invitees'] = [];
3217
3218
            if ($currentUserId != $messageInfo['user_sender_id']) {
3219
                $senderInfo = api_get_user_info($messageInfo['user_sender_id']);
3220
                $form->getElement('invitees')->addOption(
3221
                    $senderInfo['complete_name_with_username'],
3222
                    $senderInfo['id']
3223
                );
3224
                $defaults['invitees'][] = $senderInfo['id'];
3225
            }
3226
3227
            $messageCopies = MessageManager::getCopiesFromMessageInfo($messageInfo);
3228
3229
            foreach ($messageCopies as $messageCopy) {
3230
                if ($currentUserId == $messageCopy->getUserReceiverId()) {
3231
                    continue;
3232
                }
3233
3234
                $receiverInfo = api_get_user_info($messageCopy->getUserReceiverId());
3235
                $form->getElement('invitees')->addOption(
3236
                    $receiverInfo['complete_name_with_username'],
3237
                    $receiverInfo['id']
3238
                );
3239
3240
                $defaults['invitees'][] = $receiverInfo['id'];
3241
            }
3242
        }
3243
3244
        $form->setDefaults($defaults);
3245
    }
3246
3247
    /**
3248
     * @throws Exception
3249
     *
3250
     * @return array<Message>
3251
     */
3252
    public static function getCopiesFromMessageInfo(array $messageInfo): array
3253
    {
3254
        $em = Database::getManager();
3255
        $messageRepo = $em->getRepository('ChamiloCoreBundle:Message');
3256
3257
        return $messageRepo->findBy(
3258
            [
3259
                'userSenderId' => $messageInfo['user_sender_id'],
3260
                'msgStatus' => MESSAGE_STATUS_OUTBOX,
3261
                'sendDate' => new DateTime($messageInfo['send_date'], new DateTimeZone('UTC')),
3262
                'title' => $messageInfo['title'],
3263
                'content' => $messageInfo['content'],
3264
                'groupId' => $messageInfo['group_id'],
3265
                'parentId' => $messageInfo['parent_id'],
3266
            ]
3267
        );
3268
    }
3269
}
3270