Passed
Push — master ( 45d699...d5e463 )
by Julito
12:21
created

CourseChatUtils::exitChat()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 7
nc 2
nop 1
dl 0
loc 13
rs 10
c 0
b 0
f 0
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\Course;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Course. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
6
use Chamilo\CoreBundle\Entity\CourseRelUser;
7
use Chamilo\CoreBundle\Entity\Resource\ResourceLink;
8
use Chamilo\CoreBundle\Entity\Resource\ResourceNode;
9
use Chamilo\CoreBundle\Entity\Session;
10
use Chamilo\CoreBundle\Entity\SessionRelCourseRelUser;
11
use Chamilo\CoreBundle\Repository\ResourceNodeRepository;
12
use Chamilo\CoreBundle\Repository\ResourceRepository;
13
use Chamilo\CourseBundle\Entity\CChatConnected;
14
use Chamilo\CourseBundle\Entity\CChatConversation;
15
use Chamilo\UserBundle\Entity\User;
16
use Doctrine\Common\Collections\ArrayCollection;
17
use Doctrine\Common\Collections\Criteria;
18
use Michelf\MarkdownExtra;
19
use Symfony\Component\HttpFoundation\File\UploadedFile;
20
21
/**
22
 * Class CourseChat
23
 * Manage the chat for a course.
24
 */
25
class CourseChatUtils
26
{
27
    private $groupId;
28
    private $courseId;
29
    private $sessionId;
30
    private $userId;
31
    private $resourceNode;
32
33
    /**
34
     * CourseChat constructor.
35
     *
36
     * @param int $courseId
37
     * @param int $userId
38
     * @param int $sessionId
39
     * @param int $groupId
40
     */
41
    public function __construct($courseId, $userId, $sessionId = 0, $groupId = 0, ResourceNode $resourceNode, ResourceRepository $repository)
42
    {
43
        $this->courseId = (int) $courseId;
44
        $this->userId = (int) $userId;
45
        $this->sessionId = (int) $sessionId;
46
        $this->groupId = (int) $groupId;
47
        $this->resourceNode = $resourceNode;
48
        $this->repository = $repository;
0 ignored issues
show
Bug Best Practice introduced by
The property repository does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
49
    }
50
51
    /**
52
     * Prepare a message. Clean and insert emojis.
53
     *
54
     * @param string $message The message to prepare
55
     *
56
     * @return string
57
     */
58
    public function prepareMessage($message)
59
    {
60
        if (empty($message)) {
61
            return '';
62
        }
63
64
        //Emojione\Emojione::$imagePathPNG = api_get_path(WEB_LIBRARY_PATH).'javascript/emojione/png/';
65
        //Emojione\Emojione::$ascii = true;
66
67
        $message = trim($message);
68
        $message = nl2br($message);
69
        // Security XSS
70
        $message = Security::remove_XSS($message);
71
        //search urls
72
        $message = preg_replace(
73
            '@((https?://)?([-\w]+\.[-\w\.]+)+\w(:\d+)?(/([-\w/_\.]*(\?\S+)?)?)*)@',
74
            '<a href="$1" target="_blank">$1</a>',
75
            $message
76
        );
77
        // add "http://" if not set
78
        $message = preg_replace(
79
            '/<a\s[^>]*href\s*=\s*"((?!https?:\/\/)[^"]*)"[^>]*>/i',
80
            '<a href="http://$1" target="_blank">',
81
            $message
82
        );
83
84
        // Parsing emojis
85
        //$message = Emojione\Emojione::toImage($message);
86
        // Parsing text to understand markdown (code highlight)
87
        $message = MarkdownExtra::defaultTransform($message);
88
89
        return $message;
90
    }
91
92
    /**
93
     * Save a chat message in a HTML file.
94
     *
95
     * @param string $message
96
     * @param int    $friendId
97
     *
98
     * @return bool
99
     */
100
    public function saveMessage($message, $friendId = 0)
101
    {
102
        if (empty($message)) {
103
            return false;
104
        }
105
        $friendId = (int) $friendId;
106
107
        $user = api_get_user_entity($this->userId);
108
        $courseInfo = api_get_course_info_by_id($this->courseId);
109
        $isMaster = api_is_course_admin();
110
        $date_now = date('Y-m-d');
111
        $timeNow = date('d/m/y H:i:s');
112
        $basename_chat = 'messages-'.$date_now;
113
114
        if ($this->groupId && !$friendId) {
115
            $basename_chat = 'messages-'.$date_now.'_gid-'.$this->groupId;
116
        } elseif ($this->sessionId && !$friendId) {
117
            $basename_chat = 'messages-'.$date_now.'_sid-'.$this->sessionId;
118
        } elseif ($friendId) {
119
            if ($this->userId < $friendId) {
120
                $basename_chat = 'messages-'.$date_now.'_uid-'.$this->userId.'-'.$friendId;
121
            } else {
122
                $basename_chat = 'messages-'.$date_now.'_uid-'.$friendId.'-'.$this->userId;
123
            }
124
        }
125
126
        $message = self::prepareMessage($message);
0 ignored issues
show
Bug Best Practice introduced by
The method CourseChatUtils::prepareMessage() is not static, but was called statically. ( Ignorable by Annotation )

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

126
        /** @scrutinizer ignore-call */ 
127
        $message = self::prepareMessage($message);
Loading history...
127
128
        $fileTitle = $basename_chat.'-log.html';
129
130
131
132
        $userPhoto = UserManager::getUserPicture($this->userId, USER_IMAGE_SIZE_MEDIUM);
133
134
        if ($isMaster) {
135
            $fileContent = '
136
                <div class="message-teacher">
137
                    <div class="content-message">
138
                        <div class="chat-message-block-name">'.UserManager::formatUserFullName($user).'</div>
139
                        <div class="chat-message-block-content">'.$message.'</div>
140
                        <div class="message-date">'.$timeNow.'</div>
141
                    </div>
142
                    <div class="icon-message"></div>
143
                    <img class="chat-image" src="'.$userPhoto.'">
144
                </div>
145
            ';
146
        } else {
147
            $fileContent = '
148
                <div class="message-student">
149
                    <img class="chat-image" src="'.$userPhoto.'">
150
                    <div class="icon-message"></div>
151
                    <div class="content-message">
152
                        <div class="chat-message-block-name">'.UserManager::formatUserFullName($user).'</div>
153
                        <div class="chat-message-block-content">'.$message.'</div>
154
                        <div class="message-date">'.$timeNow.'</div>
155
                    </div>
156
                </div>
157
            ';
158
        }
159
160
        $criteria = [
161
            'slug' => $fileTitle,
162
            'parent' => $this->resourceNode,
163
        ];
164
165
        $resourceNode = $this->repository->getResourceNodeRepository()->findOneBy($criteria);
166
        if ($resourceNode) {
167
            $resource = $this->repository->getResourceFromResourceNode($resourceNode->getId());
168
            if ($resource) {
169
                $content = $this->repository->getResourceNodeFileContent($resourceNode);
170
                $this->repository->updateResourceFileContent($resource, $content.$fileContent);
171
            }
172
        }
173
174
175
        /*fputs($fp, $fileContent);
176
        fclose($fp);
177
        $size = filesize($absoluteFilePath);
178
        update_existing_document($courseInfo, $doc_id, $size);
179
        item_property_update_on_folder($courseInfo, $basepath_chat, $this->userId);*/
180
181
        return true;
182
    }
183
184
    /**
185
     * Disconnect a user from course chats.
186
     *
187
     * @param int $userId
188
     */
189
    public static function exitChat($userId)
190
    {
191
        $listCourse = CourseManager::get_courses_list_by_user_id($userId);
192
193
        foreach ($listCourse as $course) {
194
            Database::getManager()
195
                ->createQuery('
196
                    DELETE FROM ChamiloCourseBundle:CChatConnected ccc
197
                    WHERE ccc.cId = :course AND ccc.userId = :user
198
                ')
199
                ->execute([
200
                    'course' => intval($course['real_id']),
201
                    'user' => intval($userId),
202
                ]);
203
        }
204
    }
205
206
    /**
207
     * Disconnect users who are more than 5 seconds inactive.
208
     */
209
    public function disconnectInactiveUsers()
210
    {
211
        $em = Database::getManager();
212
        $extraCondition = "AND ccc.toGroupId = {$this->groupId}";
213
        if (empty($this->groupId)) {
214
            $extraCondition = "AND ccc.sessionId = {$this->sessionId}";
215
        }
216
217
        $connectedUsers = $em
218
            ->createQuery("
219
                SELECT ccc FROM ChamiloCourseBundle:CChatConnected ccc
220
                WHERE ccc.cId = :course $extraCondition
221
            ")
222
            ->setParameter('course', $this->courseId)
223
            ->getResult();
224
225
        $now = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
226
        $cd_count_time_seconds = $now->getTimestamp();
227
        /** @var CChatConnected $connection */
228
        foreach ($connectedUsers as $connection) {
229
            $date_count_time_seconds = $connection->getLastConnection()->getTimestamp();
230
            if (0 !== strcmp($now->format('Y-m-d'), $connection->getLastConnection()->format('Y-m-d'))) {
231
                continue;
232
            }
233
234
            if (($cd_count_time_seconds - $date_count_time_seconds) <= 5) {
235
                continue;
236
            }
237
238
            $em
239
                ->createQuery('
240
                    DELETE FROM ChamiloCourseBundle:CChatConnected ccc
241
                    WHERE ccc.cId = :course AND ccc.userId = :user AND ccc.toGroupId = :group
242
                ')
243
                ->execute([
244
                    'course' => $this->courseId,
245
                    'user' => $connection->getUserId(),
246
                    'group' => $this->groupId,
247
                ]);
248
        }
249
    }
250
251
    /**
252
     * Keep registered to a user as connected.
253
     */
254
    public function keepUserAsConnected()
255
    {
256
        $em = Database::getManager();
257
        $extraCondition = null;
258
259
        if ($this->groupId) {
260
            $extraCondition = 'AND ccc.toGroupId = '.$this->groupId;
261
        } else {
262
            $extraCondition = 'AND ccc.sessionId = '.$this->sessionId;
263
        }
264
265
        $currentTime = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
266
267
        /** @var CChatConnected $connection */
268
        $connection = $em
269
            ->createQuery("
270
                SELECT ccc FROM ChamiloCourseBundle:CChatConnected ccc
271
                WHERE ccc.userId = :user AND ccc.cId = :course $extraCondition
272
            ")
273
            ->setParameters([
274
                'user' => $this->userId,
275
                'course' => $this->courseId,
276
            ])
277
            ->getOneOrNullResult();
278
279
        if ($connection) {
0 ignored issues
show
introduced by
$connection is of type Chamilo\CourseBundle\Entity\CChatConnected, thus it always evaluated to true.
Loading history...
280
            $connection->setLastConnection($currentTime);
281
            $em->persist($connection);
282
            $em->flush();
283
284
            return;
285
        }
286
287
        $connection = new CChatConnected();
288
        $connection
289
            ->setCId($this->courseId)
290
            ->setUserId($this->userId)
291
            ->setLastConnection($currentTime)
292
            ->setSessionId($this->sessionId)
293
            ->setToGroupId($this->groupId);
294
295
        $em->persist($connection);
296
        $em->flush();
297
    }
298
299
    /**
300
     * Get the emoji allowed on course chat.
301
     *
302
     * @return array
303
     */
304
    /*public static function getEmojiStrategy()
305
    {
306
        return require_once api_get_path(SYS_CODE_PATH).'chat/emoji_strategy.php';
307
    }*/
308
309
    /**
310
     * Get the emoji list to include in chat.
311
     *
312
     * @return array
313
     */
314
    public static function getEmojisToInclude()
315
    {
316
        return [
317
            ':bowtie:',
318
            ':smile:' |
0 ignored issues
show
Bug introduced by
Are you sure you want to use the bitwise | or did you mean ||?
Loading history...
319
            ':laughing:',
320
            ':blush:',
321
            ':smiley:',
322
            ':relaxed:',
323
            ':smirk:',
324
            ':heart_eyes:',
325
            ':kissing_heart:',
326
            ':kissing_closed_eyes:',
327
            ':flushed:',
328
            ':relieved:',
329
            ':satisfied:',
330
            ':grin:',
331
            ':wink:',
332
            ':stuck_out_tongue_winking_eye:',
333
            ':stuck_out_tongue_closed_eyes:',
334
            ':grinning:',
335
            ':kissing:',
336
            ':kissing_smiling_eyes:',
337
            ':stuck_out_tongue:',
338
            ':sleeping:',
339
            ':worried:',
340
            ':frowning:',
341
            ':anguished:',
342
            ':open_mouth:',
343
            ':grimacing:',
344
            ':confused:',
345
            ':hushed:',
346
            ':expressionless:',
347
            ':unamused:',
348
            ':sweat_smile:',
349
            ':sweat:',
350
            ':disappointed_relieved:',
351
            ':weary:',
352
            ':pensive:',
353
            ':disappointed:',
354
            ':confounded:',
355
            ':fearful:',
356
            ':cold_sweat:',
357
            ':persevere:',
358
            ':cry:',
359
            ':sob:',
360
            ':joy:',
361
            ':astonished:',
362
            ':scream:',
363
            ':neckbeard:',
364
            ':tired_face:',
365
            ':angry:',
366
            ':rage:',
367
            ':triumph:',
368
            ':sleepy:',
369
            ':yum:',
370
            ':mask:',
371
            ':sunglasses:',
372
            ':dizzy_face:',
373
            ':imp:',
374
            ':smiling_imp:',
375
            ':neutral_face:',
376
            ':no_mouth:',
377
            ':innocent:',
378
            ':alien:',
379
        ];
380
    }
381
382
    /**
383
     * Get the chat history file name.
384
     *
385
     * @param bool $absolute Optional. Whether get the base or the absolute file path
386
     * @param int  $friendId optional
387
     *
388
     * @return string
389
     */
390
    public function getFileName($absolute = false, $friendId = 0)
391
    {
392
        $date = date('Y-m-d');
393
        $base = 'messages-'.$date.'.log.html';
394
395
        if ($this->groupId && !$friendId) {
396
            $base = 'messages-'.$date.'_gid-'.$this->groupId.'.log.html';
397
        } elseif ($this->sessionId && !$friendId) {
398
            $base = 'messages-'.$date.'_sid-'.$this->sessionId.'.log.html';
399
        } elseif ($friendId) {
400
            if ($this->userId < $friendId) {
401
                $base = 'messages-'.$date.'_uid-'.$this->userId.'-'.$friendId.'.log.html';
402
            } else {
403
                $base = 'messages-'.$date.'_uid-'.$friendId.'-'.$this->userId.'.log.html';
404
            }
405
        }
406
407
        if (!$absolute) {
408
            return $base;
409
        }
410
411
        //$courseInfo = api_get_course_info_by_id($this->courseId);
412
413
        $document_path = '/document';
414
        $chatPath = $document_path.'/chat_files/';
415
416
        if ($this->groupId) {
417
            $group_info = GroupManager::get_group_properties($this->groupId);
418
            $chatPath = $document_path.$group_info['directory'].'/chat_files/';
419
        }
420
421
        return $chatPath.$base;
422
    }
423
424
    /**
425
     * Get the chat history.
426
     *
427
     * @param bool $reset
428
     * @param int  $friendId optional
429
     *
430
     * @return string
431
     */
432
    public function readMessages($reset = false, $friendId = 0)
0 ignored issues
show
Unused Code introduced by
The parameter $reset is not used and could be removed. ( Ignorable by Annotation )

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

432
    public function readMessages(/** @scrutinizer ignore-unused */ $reset = false, $friendId = 0)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
433
    {
434
        $courseInfo = api_get_course_info_by_id($this->courseId);
435
        $date_now = date('Y-m-d');
436
        $isMaster = (bool) api_is_course_admin();
437
        //$basepath_chat = '/chat_files';
438
        //$document_path = api_get_path(SYS_COURSE_PATH).$courseInfo['path'].'/document';
439
        if ($this->groupId) {
440
            $group_info = GroupManager:: get_group_properties($this->groupId);
441
            //$basepath_chat = $group_info['directory'].'/chat_files';
442
        }
443
444
        //$chat_path = $document_path.$basepath_chat.'/';
445
446
        $filename_chat = 'messages-'.$date_now.'-log.html';
447
448
        if ($this->groupId && !$friendId) {
449
            $filename_chat = 'messages-'.$date_now.'_gid-'.$this->groupId.'-log.html';
450
        } elseif ($this->sessionId && !$friendId) {
451
            $filename_chat = 'messages-'.$date_now.'_sid-'.$this->sessionId.'-log.html';
452
        } elseif ($friendId) {
453
            if ($this->userId < $friendId) {
454
                $filename_chat = 'messages-'.$date_now.'_uid-'.$this->userId.'-'.$friendId.'-log.html';
455
            } else {
456
                $filename_chat = 'messages-'.$date_now.'_uid-'.$friendId.'-'.$this->userId.'-log.html';
457
            }
458
        }
459
460
        $criteria = [
461
            'slug' => $filename_chat,
462
            'parent' => $this->resourceNode,
463
        ];
464
465
        $resourceNode = $this->repository->getResourceNodeRepository()->findOneBy($criteria);
466
467
        /** @var ResourceNode $resourceNode */
468
        //$resourceNode = $this->repository->findOneBy($criteria);
469
        //var_dump($filename_chat, $this->resourceNode->getId());exit;
470
471
        if (null === $resourceNode) {
472
            $em = Database::getManager();
473
            $resource = new CChatConversation();
474
            $resource->setName($filename_chat);
475
476
            $handle = tmpfile();
477
            fwrite($handle, '');
0 ignored issues
show
Bug introduced by
It seems like $handle can also be of type false; however, parameter $handle of fwrite() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

477
            fwrite(/** @scrutinizer ignore-type */ $handle, '');
Loading history...
478
            $meta = stream_get_meta_data($handle);
0 ignored issues
show
Bug introduced by
It seems like $handle can also be of type false; however, parameter $stream of stream_get_meta_data() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

478
            $meta = stream_get_meta_data(/** @scrutinizer ignore-type */ $handle);
Loading history...
479
            $file = new UploadedFile($meta['uri'], $filename_chat, 'text/html', null, true);
480
481
            $this->repository->addResourceToCourse(
482
                $resource,
483
                ResourceLink::VISIBILITY_PUBLISHED,
484
                api_get_user_entity(api_get_user_id()),
485
                api_get_course_entity(),
486
                api_get_session_entity(),
487
                api_get_group_entity(),
488
                $file
489
            );
490
            $em->flush();
491
492
            $resourceNode = $resource->getResourceNode();
493
        }
494
495
        if ($resourceNode->hasResourceFile()) {
496
            //$resourceFile = $resourceNode->getResourceFile();
497
            //$fileName = $this->getFilename($resourceFile);
498
            return $this->repository->getResourceNodeFileContent($resourceNode);
499
        }
500
501
        return '';
502
503
504
        $remove = 0;
0 ignored issues
show
Unused Code introduced by
$remove = 0 is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
505
        $content = [];
506
507
        if (file_exists($chat_path.$basename_chat.'.log.html')) {
508
            $content = file($chat_path.$basename_chat.'.log.html');
509
            $nbr_lines = sizeof($content);
510
            $remove = $nbr_lines - 100;
511
        }
512
513
        if ($remove < 0) {
514
            $remove = 0;
515
        }
516
517
        array_splice($content, 0, $remove);
518
519
        if (isset($_GET['origin']) && 'whoisonline' == $_GET['origin']) {
520
            //the caller
521
            $content[0] = get_lang('Chat call has been sent. Waiting for the approval of your partner.').'<br />'.$content[0];
522
        }
523
524
        $history = '<div id="content-chat">';
525
        foreach ($content as $this_line) {
526
            $history .= $this_line;
527
        }
528
        $history .= '</div>';
529
530
        if ($isMaster || $GLOBALS['is_session_general_coach']) {
531
            $history .= '
532
                <div id="clear-chat">
533
                    <button type="button" id="chat-reset" class="btn btn-danger btn-sm">
534
                        '.get_lang('Clear the chat').'
535
                    </button>
536
                </div>
537
            ';
538
        }
539
540
        return $history;
541
    }
542
543
    /**
544
     * Get the number of users connected in chat.
545
     *
546
     * @return int
547
     */
548
    public function countUsersOnline()
549
    {
550
        $date = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
551
        $date->modify('-5 seconds');
552
553
        if ($this->groupId) {
554
            $extraCondition = 'AND ccc.toGroupId = '.$this->groupId;
555
        } else {
556
            $extraCondition = 'AND ccc.sessionId = '.$this->sessionId;
557
        }
558
559
        $number = Database::getManager()
560
            ->createQuery("
561
                SELECT COUNT(ccc.userId) FROM ChamiloCourseBundle:CChatConnected ccc
562
                WHERE ccc.lastConnection > :date AND ccc.cId = :course $extraCondition
563
            ")
564
            ->setParameters([
565
                'date' => $date,
566
                'course' => $this->courseId,
567
            ])
568
            ->getSingleScalarResult();
569
570
        return (int) $number;
571
    }
572
573
    /**
574
     * Get the users online data.
575
     *
576
     * @return array
577
     */
578
    public function listUsersOnline()
579
    {
580
        $subscriptions = $this->getUsersSubscriptions();
581
        $usersInfo = [];
582
583
        if ($this->groupId) {
584
            /** @var User $groupUser */
585
            foreach ($subscriptions as $groupUser) {
586
                $usersInfo[] = $this->formatUser(
587
                    $groupUser,
588
                    $groupUser->getStatus()
589
                );
590
            }
591
        } else {
592
            /** @var CourseRelUser|SessionRelCourseRelUser $subscription */
593
            foreach ($subscriptions as $subscription) {
594
                $user = $subscription->getUser();
595
                $usersInfo[] = $this->formatUser(
596
                    $user,
597
                    $this->sessionId ? $user->getStatus() : $subscription->getStatus()
598
                );
599
            }
600
        }
601
602
        return $usersInfo;
603
    }
604
605
    /**
606
     * Format the user data to return it in the user list.
607
     *
608
     * @param int $status
609
     *
610
     * @return array
611
     */
612
    private function formatUser(User $user, $status)
613
    {
614
        return [
615
            'id' => $user->getId(),
616
            'firstname' => $user->getFirstname(),
617
            'lastname' => $user->getLastname(),
618
            'status' => $status,
619
            'image_url' => UserManager::getUserPicture($user->getId(), USER_IMAGE_SIZE_MEDIUM),
620
            'profile_url' => api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user->getId(),
621
            'complete_name' => UserManager::formatUserFullName($user),
622
            'username' => $user->getUsername(),
623
            'email' => $user->getEmail(),
624
            'isConnected' => $this->userIsConnected($user->getId()),
625
        ];
626
    }
627
628
    /**
629
     * Get the users subscriptions (SessionRelCourseRelUser array or CourseRelUser array) for chat.
630
     *
631
     * @return ArrayCollection
632
     */
633
    private function getUsersSubscriptions()
634
    {
635
        $em = Database::getManager();
636
637
        if ($this->groupId) {
638
            $students = $em
639
                ->createQuery(
640
                    'SELECT u FROM ChamiloUserBundle:User u
641
                    INNER JOIN ChamiloCourseBundle:CGroupRelUser gru
642
                        WITH u.id = gru.userId AND gru.cId = :course
643
                    WHERE u.id != :user AND gru.groupId = :group
644
                        AND u.active = true'
645
                )
646
                ->setParameters(['course' => $this->courseId, 'user' => $this->userId, 'group' => $this->groupId])
647
                ->getResult();
648
            $tutors = $em
649
                ->createQuery(
650
                    'SELECT u FROM ChamiloUserBundle:User u
651
                    INNER JOIN ChamiloCourseBundle:CGroupRelTutor grt
652
                        WITH u.id = grt.userId AND grt.cId = :course
653
                    WHERE u.id != :user AND grt.groupId = :group
654
                        AND u.active = true'
655
                )
656
                ->setParameters(['course' => $this->courseId, 'user' => $this->userId, 'group' => $this->groupId])
657
                ->getResult();
658
659
            return array_merge($tutors, $students);
0 ignored issues
show
Bug Best Practice introduced by
The expression return array_merge($tutors, $students) returns the type array which is incompatible with the documented return type Doctrine\Common\Collections\ArrayCollection.
Loading history...
660
        }
661
662
        /** @var Course $course */
663
        $course = $em->find('ChamiloCoreBundle:Course', $this->courseId);
664
665
        if ($this->sessionId) {
666
            /** @var Session $session */
667
            $session = $em->find('ChamiloCoreBundle:Session', $this->sessionId);
668
            $criteria = Criteria::create()->where(Criteria::expr()->eq('course', $course));
669
            $userIsCoach = api_is_course_session_coach($this->userId, $course->getId(), $session->getId());
670
671
            if (api_get_configuration_value('course_chat_restrict_to_coach')) {
672
                if ($userIsCoach) {
673
                    $criteria->andWhere(
674
                        Criteria::expr()->eq('status', Session::STUDENT)
675
                    );
676
                } else {
677
                    $criteria->andWhere(
678
                        Criteria::expr()->eq('status', Session::COACH)
679
                    );
680
                }
681
            }
682
683
            $criteria->orderBy(['status' => Criteria::DESC]);
684
685
            return $session
686
                ->getUserCourseSubscriptions()
687
                ->matching($criteria)
688
                ->filter(function (SessionRelCourseRelUser $sessionRelCourseRelUser) {
689
                    return $sessionRelCourseRelUser->getUser()->isActive();
690
                });
691
        }
692
693
        return $course
694
            ->getUsers()
695
            ->filter(function (CourseRelUser $courseRelUser) {
696
                return $courseRelUser->getUser()->isActive();
697
            });
698
    }
699
700
    /**
701
     * Check if a user is connected in course chat.
702
     *
703
     * @param int $userId
704
     *
705
     * @return int
706
     */
707
    private function userIsConnected($userId)
708
    {
709
        $date = new DateTime(api_get_utc_datetime(), new DateTimeZone('UTC'));
710
        $date->modify('-5 seconds');
711
712
        if ($this->groupId) {
713
            $extraCondition = 'AND ccc.toGroupId = '.$this->groupId;
714
        } else {
715
            $extraCondition = 'AND ccc.sessionId = '.$this->sessionId;
716
        }
717
718
        $number = Database::getManager()
719
            ->createQuery("
720
                SELECT COUNT(ccc.userId) FROM ChamiloCourseBundle:CChatConnected ccc
721
                WHERE ccc.lastConnection > :date AND ccc.cId = :course AND ccc.userId = :user $extraCondition
722
            ")
723
            ->setParameters([
724
                'date' => $date,
725
                'course' => $this->courseId,
726
                'user' => $userId,
727
            ])
728
            ->getSingleScalarResult();
729
730
        return (int) $number;
731
    }
732
}
733