Passed
Pull Request — 1.11.x (#4119)
by Angel Fernando Quiroz
11:41
created

MessageManager::send_message()   F

Complexity

Conditions 56
Paths > 20000

Size

Total Lines 328
Code Lines 204

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 204
c 0
b 0
f 0
dl 0
loc 328
rs 0
cc 56
nc 120064
nop 17

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