Passed
Push — master ( f437d8...92f70a )
by Julito
10:14
created

Chat::getContacts()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 0
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use ChamiloSession as Session;
5
6
/**
7
 * Class Chat.
8
 *
9
 * @todo ChamiloSession instead of $_SESSION
10
 *
11
 * @package chamilo.library.chat
12
 */
13
class Chat extends Model
14
{
15
    public $columns = [
16
        'id',
17
        'from_user',
18
        'to_user',
19
        'message',
20
        'sent',
21
        'recd',
22
    ];
23
    public $window_list = [];
24
25
    /**
26
     * The contructor sets the chat table name and the window_list attribute.
27
     */
28
    public function __construct()
29
    {
30
        parent::__construct();
31
        $this->table = Database::get_main_table(TABLE_MAIN_CHAT);
32
        $this->window_list = Session::read('window_list');
33
        Session::write('window_list', $this->window_list);
34
    }
35
36
    /**
37
     * Get user chat status.
38
     *
39
     * @return int 0 if disconnected, 1 if connected
40
     */
41
    public function getUserStatus()
42
    {
43
        $status = UserManager::get_extra_user_data_by_field(
44
            api_get_user_id(),
45
            'user_chat_status',
46
            false,
47
            true
48
        );
49
50
        return $status['user_chat_status'];
51
    }
52
53
    /**
54
     * Set user chat status.
55
     *
56
     * @param int $status 0 if disconnected, 1 if connected
57
     */
58
    public function setUserStatus($status)
59
    {
60
        UserManager::update_extra_field_value(
61
            api_get_user_id(),
62
            'user_chat_status',
63
            $status
64
        );
65
    }
66
67
    /**
68
     * @param int  $currentUserId
69
     * @param int  $userId
70
     * @param bool $latestMessages
71
     *
72
     * @return array
73
     */
74
    public function getLatestChat($currentUserId, $userId, $latestMessages)
75
    {
76
        $items = $this->getPreviousMessages(
77
            $currentUserId,
78
            $userId,
79
            0,
80
            $latestMessages
81
        );
82
83
        return array_reverse($items);
84
    }
85
86
    /**
87
     * @return string
88
     */
89
    public function getContacts()
90
    {
91
        $html = SocialManager::listMyFriendsBlock(
92
            api_get_user_id(),
93
            '',
94
            true
95
        );
96
97
        echo $html;
98
    }
99
100
    /**
101
     * @param array $chatHistory
102
     * @param int   $latestMessages
103
     *
104
     * @return mixed
105
     */
106
    public function getAllLatestChats($chatHistory, $latestMessages = 5)
107
    {
108
        $currentUserId = api_get_user_id();
109
110
        if (empty($chatHistory)) {
111
            return [];
112
        }
113
114
        $chats = [];
115
        foreach ($chatHistory as $userId => $time) {
116
            $total = $this->getCountMessagesExchangeBetweenUsers($userId, $currentUserId);
117
            $start = $total - $latestMessages;
118
            if ($start < 0) {
119
                $start = 0;
120
            }
121
            $items = $this->getMessages($userId, $currentUserId, $start, $latestMessages);
122
            $chats[$userId]['items'] = $items;
123
            $chats[$userId]['window_user_info'] = api_get_user_info($userId);
124
        }
125
126
        return $chats;
127
    }
128
129
    /**
130
     * Starts a chat session and returns JSON array of status and chat history.
131
     *
132
     * @return bool (prints output in JSON format)
133
     */
134
    public function startSession()
135
    {
136
        // ofaj
137
        // $chat = new Chat();
138
        // $chat->setUserStatus(1);
139
140
        $chatList = Session::read('openChatBoxes');
141
        $chats = $this->getAllLatestChats($chatList);
142
        $return = [
143
            'user_status' => $this->getUserStatus(),
144
            'me' => get_lang('Me'),
145
            'user_id' => api_get_user_id(),
146
            'items' => $chats,
147
        ];
148
        echo json_encode($return);
149
150
        return true;
151
    }
152
153
    /**
154
     * @param int $fromUserId
155
     * @param int $toUserId
156
     *
157
     * @return int
158
     */
159
    public function getCountMessagesExchangeBetweenUsers($fromUserId, $toUserId)
160
    {
161
        $row = Database::select(
162
            'count(*) as count',
163
            $this->table,
164
            [
165
                'where' => [
166
                    '(from_user = ? AND to_user = ?) OR (from_user = ? AND to_user = ?) ' => [
167
                        $fromUserId,
168
                        $toUserId,
169
                        $toUserId,
170
                        $fromUserId,
171
                    ],
172
                ],
173
            ],
174
            'first'
175
        );
176
177
        return (int) $row['count'];
178
    }
179
180
    /**
181
     * @param int $fromUserId
182
     * @param int $toUserId
183
     * @param int $visibleMessages
184
     * @param int $previousMessageCount messages to show
185
     *
186
     * @return array
187
     */
188
    public function getPreviousMessages(
189
        $fromUserId,
190
        $toUserId,
191
        $visibleMessages = 1,
192
        $previousMessageCount = 5,
193
        $orderBy = ''
194
    ) {
195
        $toUserId = (int) $toUserId;
196
        $fromUserId = (int) $fromUserId;
197
        $visibleMessages = (int) $visibleMessages;
198
        $previousMessageCount = (int) $previousMessageCount;
199
200
        $total = $this->getCountMessagesExchangeBetweenUsers($fromUserId, $toUserId);
201
        $show = $total - $visibleMessages;
202
203
        if ($show < $previousMessageCount) {
204
            $show = $previousMessageCount;
205
        }
206
        $from = $show - $previousMessageCount;
207
208
        if ($from < 0) {
209
            return [];
210
        }
211
212
        return $this->getMessages($fromUserId, $toUserId, $from, $previousMessageCount, $orderBy);
213
    }
214
215
    /**
216
     * @param int    $fromUserId
217
     * @param int    $toUserId
218
     * @param int    $start
219
     * @param int    $end
220
     * @param string $orderBy
221
     *
222
     * @return array
223
     */
224
    public function getMessages($fromUserId, $toUserId, $start, $end, $orderBy = '')
225
    {
226
        $toUserId = (int) $toUserId;
227
        $fromUserId = (int) $fromUserId;
228
        $start = (int) $start;
229
        $end = (int) $end;
230
231
        if (empty($toUserId) || empty($fromUserId)) {
232
            return [];
233
        }
234
235
        $orderBy = Database::escape_string($orderBy);
236
        if (empty($orderBy)) {
237
            $orderBy = 'ORDER BY id ASC';
238
        }
239
240
        $sql = "SELECT * FROM ".$this->table."
241
                WHERE 
242
                    (
243
                        to_user = $toUserId AND 
244
                        from_user = $fromUserId
245
                    )
246
                    OR
247
                    (
248
                        from_user = $toUserId AND 
249
                        to_user =  $fromUserId
250
                    )  
251
                $orderBy
252
                LIMIT $start, $end
253
                ";
254
        $result = Database::query($sql);
255
        $rows = Database::store_result($result);
256
        $fromUserInfo = api_get_user_info($fromUserId, true);
257
        $toUserInfo = api_get_user_info($toUserId, true);
258
        $users = [
259
            $fromUserId => $fromUserInfo,
260
            $toUserId => $toUserInfo,
261
        ];
262
        $items = [];
263
        $rows = array_reverse($rows);
264
        foreach ($rows as $chat) {
265
            $fromUserId = $chat['from_user'];
266
            $userInfo = $users[$fromUserId];
267
            $toUserInfo = $users[$toUserId];
268
269
            $items[$chat['id']] = [
270
                'id' => $chat['id'],
271
                'message' => Security::remove_XSS($chat['message']),
272
                'date' => api_strtotime($chat['sent'], 'UTC'),
273
                'recd' => $chat['recd'],
274
                'from_user_info' => $userInfo,
275
                'to_user_info' => $toUserInfo,
276
            ];
277
            $_SESSION['openChatBoxes'][$fromUserId] = api_strtotime($chat['sent'], 'UTC');
278
        }
279
280
        return $items;
281
    }
282
283
    /**
284
     * Refreshes the chat windows (usually called every x seconds through AJAX).
285
     */
286
    public function heartbeat()
287
    {
288
        $chatHistory = Session::read('chatHistory');
289
        $currentUserId = api_get_user_id();
290
291
        // update current chats
292
        if (!empty($chatHistory) && is_array($chatHistory)) {
293
            foreach ($chatHistory as $fromUserId => &$data) {
294
                $userInfo = api_get_user_info($fromUserId, true);
295
                $count = $this->getCountMessagesExchangeBetweenUsers($fromUserId, $currentUserId);
296
                $chatItems = $this->getLatestChat($fromUserId, $currentUserId, 5);
297
                $data['window_user_info'] = $userInfo;
298
                $data['items'] = $chatItems;
299
                $data['total_messages'] = $count;
300
            }
301
        }
302
303
        $sql = "SELECT * FROM ".$this->table."
304
                WHERE
305
                    to_user = '".$currentUserId."' AND recd = 0
306
                ORDER BY id ASC";
307
        $result = Database::query($sql);
308
309
        $chatList = [];
310
        while ($chat = Database::fetch_array($result, 'ASSOC')) {
311
            $chatList[$chat['from_user']][] = $chat;
312
        }
313
314
        foreach ($chatList as $fromUserId => $messages) {
315
            $userInfo = api_get_user_info($fromUserId, true);
316
            $count = $this->getCountMessagesExchangeBetweenUsers($fromUserId, $currentUserId);
317
            $chatItems = $this->getLatestChat($fromUserId, $currentUserId, 5);
318
319
            // Cleaning tsChatBoxes
320
            unset($_SESSION['tsChatBoxes'][$fromUserId]);
321
322
            foreach ($messages as $chat) {
323
                $_SESSION['openChatBoxes'][$fromUserId] = api_strtotime($chat['sent'], 'UTC');
324
            }
325
326
            $chatHistory[$fromUserId] = [
327
                'window_user_info' => $userInfo,
328
                'total_messages' => $count,
329
                'items' => $chatItems,
330
            ];
331
        }
332
333
        /*if (!empty($_SESSION['openChatBoxes'])) {
334
            foreach ($_SESSION['openChatBoxes'] as $userId => $time) {
335
                if (!isset($_SESSION['tsChatBoxes'][$userId])) {
336
                    $now = time() - $time;
337
                    $time = api_convert_and_format_date($time, DATE_TIME_FORMAT_SHORT_TIME_FIRST);
338
                    $message = sprintf(get_lang('SentAtX'), $time);
339
340
                    if ($now > 180) {
341
                        if (isset($chatHistory[$userId])) {
342
                            $chatHistory[$userId]['items'][] = $item;
343
                        }
344
                        $_SESSION['tsChatBoxes'][$userId] = 1;
345
                    }
346
                }
347
            }
348
        }*/
349
        Session::write('chatHistory', $chatHistory);
350
351
        $sql = "UPDATE ".$this->table."
352
                SET recd = 1
353
                WHERE to_user = '".$currentUserId."' AND recd = 0";
354
        Database::query($sql);
355
356
        echo json_encode(['items' => $chatHistory]);
357
    }
358
359
    /**
360
     * Saves into session the fact that a chat window exists with the given user.
361
     *
362
     * @param int $userId
363
     */
364
    public function saveWindow($userId)
365
    {
366
        $this->window_list[$userId] = true;
367
        Session::write('window_list', $this->window_list);
368
    }
369
370
    /**
371
     * Sends a message from one user to another user.
372
     *
373
     * @param int    $fromUserId  The ID of the user sending the message
374
     * @param int    $to_user_id  The ID of the user receiving the message
375
     * @param string $message     Message
376
     * @param bool   $printResult Optional. Whether print the result
377
     * @param bool   $sanitize    Optional. Whether sanitize the message
378
     */
379
    public function send(
380
        $fromUserId,
381
        $to_user_id,
382
        $message,
383
        $printResult = true,
384
        $sanitize = true
385
    ) {
386
        $relation = SocialManager::get_relation_between_contacts($fromUserId, $to_user_id);
387
388
        if ($relation == USER_RELATION_TYPE_FRIEND) {
389
            $now = api_get_utc_datetime();
390
            $user_info = api_get_user_info($to_user_id, true);
391
            $this->saveWindow($to_user_id);
392
            $_SESSION['openChatBoxes'][$to_user_id] = api_strtotime($now, 'UTC');
393
394
            if ($sanitize) {
395
                $messagesan = $this->sanitize($message);
396
            } else {
397
                $messagesan = $message;
398
            }
399
400
            if (!isset($_SESSION['chatHistory'][$to_user_id])) {
401
                $_SESSION['chatHistory'][$to_user_id] = [];
402
            }
403
            $item = [
404
                's' => '1',
405
                'f' => $fromUserId,
406
                'm' => $messagesan,
407
                'date' => api_strtotime($now, 'UTC'),
408
                'username' => get_lang('Me'),
409
            ];
410
            $_SESSION['chatHistory'][$to_user_id]['items'][] = $item;
411
            $_SESSION['chatHistory'][$to_user_id]['user_info']['user_name'] = $user_info['complete_name'];
412
            $_SESSION['chatHistory'][$to_user_id]['user_info']['online'] = $user_info['user_is_online'];
413
            $_SESSION['chatHistory'][$to_user_id]['user_info']['avatar'] = $user_info['avatar_small'];
414
            $_SESSION['chatHistory'][$to_user_id]['user_info']['user_id'] = $user_info['user_id'];
415
416
            unset($_SESSION['tsChatBoxes'][$to_user_id]);
417
418
            $params = [];
419
            $params['from_user'] = (int) $fromUserId;
420
            $params['to_user'] = (int) $to_user_id;
421
            $params['message'] = $message;
422
            $params['sent'] = api_get_utc_datetime();
423
424
            if (!empty($fromUserId) && !empty($to_user_id)) {
425
                $messageId = $this->save($params);
426
                if ($printResult) {
427
                    echo $messageId;
0 ignored issues
show
Bug introduced by
Are you sure $messageId of type false|integer can be used in echo? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

427
                    echo /** @scrutinizer ignore-type */ $messageId;
Loading history...
428
                    exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
429
                }
430
            }
431
        }
432
433
        if ($printResult) {
434
            echo '0';
435
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
436
        }
437
    }
438
439
    /**
440
     * Close a specific chat box (user ID taken from $_POST['chatbox']).
441
     *
442
     * @param $userId
443
     */
444
    public function closeWindow($userId)
445
    {
446
        if (empty($userId)) {
447
            return false;
448
        }
449
450
        $list = Session::read('openChatBoxes');
451
        if (isset($list[$userId])) {
452
            unset($list[$userId]);
453
            Session::write('openChatBoxes', $list);
454
        }
455
456
        $list = Session::read('chatHistory');
457
        if (isset($list[$userId])) {
458
            unset($list[$userId]);
459
            Session::write('chatHistory', $list);
460
        }
461
462
        return true;
463
    }
464
465
    /**
466
     * Close chat - disconnects the user.
467
     */
468
    public function close()
469
    {
470
        Session::erase('tsChatBoxes');
471
        Session::erase('openChatBoxes');
472
        Session::erase('chatHistory');
473
        Session::erase('window_list');
474
    }
475
476
    /**
477
     * Filter chat messages to avoid XSS or other JS.
478
     *
479
     * @param string $text Unfiltered message
480
     *
481
     * @return string Filtered message
482
     */
483
    public function sanitize($text)
484
    {
485
        $text = htmlspecialchars($text, ENT_QUOTES);
486
        $text = str_replace("\n\r", "\n", $text);
487
        $text = str_replace("\r\n", "\n", $text);
488
        $text = str_replace("\n", "<br>", $text);
489
490
        return $text;
491
    }
492
493
    /**
494
     * SET Disable Chat.
495
     *
496
     * @param bool $status to disable chat
497
     */
498
    public static function setDisableChat($status = true)
499
    {
500
        Session::write('disable_chat', $status);
501
    }
502
503
    /**
504
     * Disable Chat - disable the chat.
505
     *
506
     * @return bool - return true if setDisableChat status is true
507
     */
508
    public static function disableChat()
509
    {
510
        $status = Session::read('disable_chat');
511
        if (!empty($status)) {
512
            if ($status == true) {
513
                Session::write('disable_chat', null);
514
515
                return true;
516
            }
517
        }
518
519
        return false;
520
    }
521
522
    /**
523
     * @return bool
524
     */
525
    public function isChatBlockedByExercises()
526
    {
527
        $currentExercises = Session::read('current_exercises');
528
        if (!empty($currentExercises)) {
529
            foreach ($currentExercises as $attempt_status) {
530
                if ($attempt_status == true) {
531
                    return true;
532
                }
533
            }
534
        }
535
536
        return false;
537
    }
538
}
539