Passed
Push — preprodparkur ( 33e132...955015 )
by
unknown
10:33
created

MessageManager::send_message()   F

Complexity

Conditions 37
Paths 15562

Size

Total Lines 274
Code Lines 170

Duplication

Lines 0
Ratio 0 %

Importance

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