Passed
Push — master ( 702f24...55adc1 )
by Yannick
09:28
created

Bbb::getMaxUsersLimit()   C

Complexity

Conditions 12
Paths 150

Size

Total Lines 54
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 32
nc 150
nop 0
dl 0
loc 54
rs 6.55
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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:

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\ConferenceActivity;
6
use Chamilo\CoreBundle\Entity\ConferenceMeeting;
7
use Chamilo\CoreBundle\Entity\ConferenceRecording;
8
use Chamilo\CoreBundle\Enums\ActionIcon;
9
use Chamilo\CoreBundle\Enums\ObjectIcon;
10
use Chamilo\CoreBundle\Enums\StateIcon;
11
use Chamilo\CoreBundle\Repository\ConferenceActivityRepository;
12
use Chamilo\CoreBundle\Repository\ConferenceMeetingRepository;
13
use Chamilo\CoreBundle\Repository\ConferenceRecordingRepository;
14
use Chamilo\UserBundle\Entity\User;
15
16
/**
17
 * Class Bbb
18
 * This script initiates a video conference session, calling the BigBlueButton
19
 * API BigBlueButton-Chamilo connector class
20
 */
21
class Bbb
22
{
23
    public $url;
24
    public $salt;
25
    public $api;
26
    public $userCompleteName = '';
27
    public $protocol = 'http://';
28
    public $debug = false;
29
    public $logoutUrl = '';
30
    public $pluginEnabled = false;
31
    public $enableGlobalConference = false;
32
    public $enableGlobalConferencePerUser = false;
33
    public $isGlobalConference = false;
34
    public $groupSupport = false;
35
    public $userSupport = false;
36
    public $accessUrl = 1;
37
    public $userId = 0;
38
    public $plugin;
39
    private $courseCode;
40
    private $courseId;
41
    private $sessionId;
42
    private $groupId;
43
    private $maxUsersLimit;
44
45
    /**
46
     * Constructor (generates a connection to the API and the Chamilo settings
47
     * required for the connection to the video conference server)
48
     *
49
     * @param string $host
50
     * @param string $salt
51
     * @param bool   $isGlobalConference
52
     * @param int    $isGlobalPerUser
53
     */
54
    public function __construct(
55
        $host = '',
56
        $salt = '',
57
        $isGlobalConference = false,
58
        $isGlobalPerUser = 0
59
    ) {
60
        $this->courseCode = api_get_course_id();
61
        $this->courseId = api_get_course_int_id();
62
        $this->sessionId = api_get_session_id();
63
        $this->groupId = api_get_group_id();
64
65
        // Initialize video server settings from global settings
66
        $this->plugin = BbbPlugin::create();
67
        $bbbPluginEnabled = $this->plugin->get('tool_enable');
68
69
        $bbb_host = !empty($host) ? $host : $this->plugin->get('host');
70
        $bbb_salt = !empty($salt) ? $salt : $this->plugin->get('salt');
71
72
        $this->table = Database::get_main_table('conference_meeting');
73
        $this->enableGlobalConference = $this->plugin->get('enable_global_conference') === 'true';
74
        $this->isGlobalConference = (bool) $isGlobalConference;
75
76
        $columns = Database::listTableColumns($this->table);
77
        $this->groupSupport = isset($columns['group_id']) ? true : false;
78
        $this->userSupport = isset($columns['user_id']) ? true : false;
79
        $this->accessUrl = api_get_current_access_url_id();
80
81
        $this->enableGlobalConferencePerUser = false;
82
        if ($this->userSupport && !empty($isGlobalPerUser)) {
83
            $this->enableGlobalConferencePerUser = $this->plugin->get('enable_global_conference_per_user') === 'true';
84
            $this->userId = $isGlobalPerUser;
85
        }
86
87
        if ($this->groupSupport) {
88
            // Plugin check
89
            $this->groupSupport = $this->plugin->get('enable_conference_in_course_groups') === 'true' ? true : false;
90
            if ($this->groupSupport) {
91
                // Platform check
92
                $bbbSetting = api_get_plugin_setting('bbb', 'enable_conference_in_course_groups');
93
                $bbbSetting = isset($bbbSetting['bbb']) ? $bbbSetting['bbb'] === 'true' : false;
94
95
                if ($bbbSetting) {
96
                    // Course check
97
                    $courseInfo = api_get_course_info();
98
                    if ($courseInfo) {
99
                        $this->groupSupport = api_get_course_plugin_setting(
100
                                'bbb',
101
                                'bbb_enable_conference_in_groups',
102
                                $courseInfo
103
                            ) === '1';
104
                    }
105
                }
106
            }
107
        }
108
        $this->maxUsersLimit = $this->plugin->get('max_users_limit');
109
110
        if ($bbbPluginEnabled === 'true') {
111
            $userInfo = api_get_user_info();
112
            if (empty($userInfo) && !empty($isGlobalPerUser)) {
113
                // If we are following a link to a global "per user" conference
114
                // then generate a random guest name to join the conference
115
                // because there is no part of the process where we give a name
116
                //$this->userCompleteName = 'Guest'.rand(1000, 9999);
117
            } else {
118
                $this->userCompleteName = $userInfo['complete_name'];
119
            }
120
121
            if (api_is_anonymous()) {
122
                $this->userCompleteName = get_lang('Guest').'_'.rand(1000, 9999);
123
            }
124
125
            $this->salt = $bbb_salt;
126
            if (!empty($bbb_host)) {
127
                if (substr($bbb_host, -1, 1) !== '/') {
128
                    $bbb_host .= '/';
129
                }
130
                $this->url = $bbb_host;
131
                if (!preg_match('#/bigbluebutton/$#', $bbb_host)) {
132
                    $this->url = $bbb_host.'bigbluebutton/';
133
                }
134
            }
135
            $info = parse_url($bbb_host);
136
137
            if (isset($info['scheme'])) {
138
                $this->protocol = $info['scheme'].'://';
139
                $this->url = str_replace($this->protocol, '', $this->url);
140
                $urlWithProtocol = $bbb_host;
141
            } else {
142
                // We assume it's an http, if user wants to use https, the host *must* include the protocol.
143
                $this->protocol = 'http://';
144
                $urlWithProtocol = $this->protocol.$bbb_host;
145
            }
146
147
            // Setting BBB api
148
            define('CONFIG_SECURITY_SALT', $this->salt);
149
            define('CONFIG_SERVER_URL_WITH_PROTOCOL', $urlWithProtocol);
150
            define('CONFIG_SERVER_BASE_URL', $this->url);
151
            define('CONFIG_SERVER_PROTOCOL', $this->protocol);
152
153
            $this->api = new BigBlueButtonBN();
154
            $this->pluginEnabled = true;
155
            $this->logoutUrl = $this->getListingUrl();
156
        }
157
    }
158
159
    /**
160
     * @param int $courseId  Optional. Course ID.
161
     * @param int $sessionId Optional. Session ID.
162
     * @param int $groupId   Optional. Group ID.
163
     *
164
     * @return string
165
     */
166
    public function getListingUrl($courseId = 0, $sessionId = 0, $groupId = 0)
167
    {
168
        return api_get_path(WEB_PLUGIN_PATH).'Bbb/listing.php?'
169
            .$this->getUrlParams($courseId, $sessionId, $groupId);
170
    }
171
172
    /**
173
     * @param int $courseId  Optional. Course ID.
174
     * @param int $sessionId Optional. Session ID.
175
     * @param int $groupId   Optional. Group ID.
176
     *
177
     * @return string
178
     */
179
    public function getUrlParams($courseId = 0, $sessionId = 0, $groupId = 0)
180
    {
181
        if (empty($this->courseId) && !$courseId) {
182
            if ($this->isGlobalConferencePerUserEnabled()) {
183
                return 'global=1&user_id='.$this->userId;
184
            }
185
186
            if ($this->isGlobalConference()) {
187
                return 'global=1';
188
            }
189
190
            return '';
191
        }
192
193
        $defaultCourseId = (int) $this->courseId;
194
        if (!empty($courseId)) {
195
            $defaultCourseId = (int) $courseId;
196
        }
197
198
        return http_build_query(
199
            [
200
                'cid' => $defaultCourseId,
201
                'sid' => (int) $sessionId ?: $this->sessionId,
202
                'gid' => (int) $groupId ?: $this->groupId,
203
            ]
204
        );
205
    }
206
207
    /**
208
     * @return bool
209
     */
210
    public function isGlobalConferencePerUserEnabled()
211
    {
212
        return $this->enableGlobalConferencePerUser;
213
    }
214
215
    /**
216
     * @return bool
217
     */
218
    public function isGlobalConference()
219
    {
220
        if ($this->isGlobalConferenceEnabled() === false) {
221
            return false;
222
        }
223
224
        return (bool) $this->isGlobalConference;
225
    }
226
227
    /**
228
     * @return bool
229
     */
230
    public function isGlobalConferenceEnabled()
231
    {
232
        return $this->enableGlobalConference;
233
    }
234
235
    /**
236
     * @param array $userInfo
237
     *
238
     * @return bool
239
     */
240
    public static function showGlobalConferenceLink($userInfo)
241
    {
242
        if (empty($userInfo)) {
243
            return false;
244
        }
245
        $setting = api_get_plugin_setting('bbb', 'enable_global_conference');
246
        $settingLink = api_get_plugin_setting('bbb', 'enable_global_conference_link');
247
        if ($setting === 'true' && $settingLink === 'true') {
248
            //$content = Display::url(get_lang('LaunchVideoConferenceRoom'), $url);
249
            $allowedRoles = api_get_plugin_setting(
250
                'bbb',
251
                'global_conference_allow_roles'
252
            );
253
254
            if (api_is_platform_admin()) {
255
                $userInfo['status'] = PLATFORM_ADMIN;
256
            }
257
258
            $showGlobalLink = true;
259
            if (!empty($allowedRoles)) {
260
                if (!in_array($userInfo['status'], $allowedRoles)) {
261
                    $showGlobalLink = false;
262
                }
263
            }
264
265
            return $showGlobalLink;
266
        }
267
    }
268
269
    /**
270
     * Gets the global limit of users in a video-conference room.
271
     * This value can be overridden by course-specific values
272
     * @return  int Maximum number of users set globally
273
     */
274
    public function getMaxUsersLimit()
275
    {
276
        $limit = $this->maxUsersLimit;
277
        if ($limit <= 0) {
278
            $limit = 0;
279
        }
280
        $courseLimit = 0;
281
        $sessionLimit = 0;
282
283
        // Check course extra field
284
        if (!empty($this->courseId)) {
285
            $extraField = new ExtraField('course');
286
            $fieldIdList = $extraField->get_all(
287
                array('variable = ?' => 'plugin_bbb_course_users_limit')
288
            );
289
290
            if (!empty($fieldIdList)) {
291
                $fieldId = $fieldIdList[0]['id'] ?? null;
292
                if ($fieldId) {
293
                    $extraValue = new ExtraFieldValue('course');
294
                    $value = $extraValue->get_values_by_handler_and_field_id($this->courseId, $fieldId);
295
                    if (!empty($value['value'])) {
296
                        $courseLimit = (int) $value['value'];
297
                    }
298
                }
299
            }
300
        }
301
302
        // Check session extra field
303
        if (!empty($this->sessionId)) {
304
            $extraField = new ExtraField('session');
305
            $fieldIdList = $extraField->get_all(
306
                array('variable = ?' => 'plugin_bbb_session_users_limit')
307
            );
308
309
            if (!empty($fieldIdList)) {
310
                $fieldId = $fieldIdList[0]['id'] ?? null;
311
                if ($fieldId) {
312
                    $extraValue = new ExtraFieldValue('session');
313
                    $value = $extraValue->get_values_by_handler_and_field_id($this->sessionId, $fieldId);
314
                    if (!empty($value['value'])) {
315
                        $sessionLimit = (int) $value['value'];
316
                    }
317
                }
318
            }
319
        }
320
321
        if (!empty($sessionLimit)) {
322
            return $sessionLimit;
323
        } elseif (!empty($courseLimit)) {
324
            return $courseLimit;
325
        }
326
327
        return (int) $limit;
328
    }
329
330
    /**
331
     * Sets the global limit of users in a video-conference room.
332
     *
333
     * @param int Maximum number of users (globally)
334
     */
335
    public function setMaxUsersLimit($max)
336
    {
337
        if ($max < 0) {
338
            $max = 0;
339
        }
340
        $this->maxUsersLimit = (int) $max;
341
    }
342
343
    /**
344
     * See this file in you BBB to set up default values
345
     *
346
     * @param array $params Array of parameters that will be completed if not containing all expected variables
347
     *
348
     * /var/lib/tomcat6/webapps/bigbluebutton/WEB-INF/classes/bigbluebutton.properties
349
     *
350
     * More record information:
351
     * http://code.google.com/p/bigbluebutton/wiki/RecordPlaybackSpecification
352
     *
353
     * Default maximum number of users a meeting can have.
354
     * Doesn't get enforced yet but is the default value when the create
355
     * API doesn't pass a value.
356
     * defaultMaxUsers=20
357
     *
358
     * Default duration of the meeting in minutes.
359
     * Current default is 0 (meeting doesn't end).
360
     * defaultMeetingDuration=0
361
     *
362
     * Remove the meeting from memory when the end API is called.
363
     * This allows 3rd-party apps to recycle the meeting right-away
364
     * instead of waiting for the meeting to expire (see below).
365
     * removeMeetingWhenEnded=false
366
     *
367
     * The number of minutes before the system removes the meeting from memory.
368
     * defaultMeetingExpireDuration=1
369
     *
370
     * The number of minutes the system waits when a meeting is created and when
371
     * a user joins. If after this period, a user hasn't joined, the meeting is
372
     * removed from memory.
373
     * defaultMeetingCreateJoinDuration=5
374
     *
375
     * @return mixed
376
     */
377
    public function createMeeting($params)
378
    {
379
        $params['c_id'] = api_get_course_int_id();
380
        $params['session_id'] = api_get_session_id();
381
382
        if ($this->hasGroupSupport()) {
383
            $params['group_id'] = api_get_group_id();
384
        }
385
386
        if ($this->isGlobalConferencePerUserEnabled() && !empty($this->userId)) {
387
            $params['user_id'] = (int) $this->userId;
388
        }
389
390
        $params['attendee_pw'] = $params['attendee_pw'] ?? $this->getUserMeetingPassword();
391
        $attendeePassword = $params['attendee_pw'];
392
        $params['moderator_pw'] = $params['moderator_pw'] ?? $this->getModMeetingPassword();
393
        $moderatorPassword = $params['moderator_pw'];
394
395
        $params['record'] = api_get_course_plugin_setting('bbb', 'big_blue_button_record_and_store') == 1 ? 1 : 0;
396
        $max = api_get_course_plugin_setting('bbb', 'big_blue_button_max_students_allowed');
397
        $max = isset($max) ? $max : -1;
398
399
        $params['status'] = 1;
400
        // Generate a pseudo-global-unique-id to avoid clash of conferences on
401
        // the same BBB server with several Chamilo portals
402
        $params['remote_id'] = uniqid(true, true);
403
        // Each simultaneous conference room needs to have a different
404
        // voice_bridge composed of a 5 digits number, so generating a random one
405
        $params['voice_bridge'] = rand(10000, 99999);
406
        $params['created_at'] = api_get_utc_datetime();
407
        $params['access_url'] = $this->accessUrl;
408
409
        $em = Database::getManager();
410
        $meeting = new ConferenceMeeting();
411
412
        $meeting
413
            ->setCourse(api_get_course_entity($params['c_id']))
414
            ->setSession(api_get_session_entity($params['session_id']))
415
            ->setAccessUrl(api_get_url_entity($params['access_url']))
416
            ->setGroup($this->hasGroupSupport() ? api_get_group_entity($params['group_id']) : null)
417
            ->setUser($this->isGlobalConferencePerUserEnabled() ? api_get_user_entity($params['user_id']) : null)
418
            ->setRemoteId($params['remote_id'])
419
            ->setTitle($params['meeting_name'] ?? $this->getCurrentVideoConferenceName())
420
            ->setAttendeePw($attendeePassword)
421
            ->setModeratorPw($moderatorPassword)
422
            ->setRecord((bool) $params['record'])
423
            ->setStatus($params['status'])
424
            ->setVoiceBridge($params['voice_bridge'])
425
            ->setWelcomeMsg($params['welcome_msg'] ?? null)
426
            ->setVisibility(1)
427
            ->setHasVideoM4v(false)
428
            ->setServiceProvider('bbb');
429
430
        $em->persist($meeting);
431
        $em->flush();
432
433
        $id = $meeting->getId();
434
435
        Event::addEvent(
0 ignored issues
show
Bug introduced by
The method addEvent() does not exist on Event. ( Ignorable by Annotation )

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

435
        Event::/** @scrutinizer ignore-call */ 
436
               addEvent(

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
436
            'bbb_create_meeting',
437
            'meeting_id',
438
            $id,
439
            null,
440
            api_get_user_id(),
441
            api_get_course_int_id(),
442
            api_get_session_id()
443
        );
444
445
        $meetingName = $meeting->getTitle();
446
        $record = $meeting->isRecord() ? 'true' : 'false';
447
        $duration = 300;
448
        $meetingDuration = (int) $this->plugin->get('meeting_duration');
449
        if (!empty($meetingDuration)) {
450
            $duration = $meetingDuration;
451
        }
452
453
        $bbbParams = [
454
            'meetingId' => $meeting->getRemoteId(),
455
            'meetingName' => $meetingName,
456
            'attendeePw' => $attendeePassword,
457
            'moderatorPw' => $moderatorPassword,
458
            'welcomeMsg' => $meeting->getWelcomeMsg(),
459
            'dialNumber' => '',
460
            'voiceBridge' => $meeting->getVoiceBridge(),
461
            'webVoice' => '',
462
            'logoutUrl' => $this->logoutUrl . '&action=logout&remote_id=' . $meeting->getRemoteId(),
463
            'maxParticipants' => $max,
464
            'record' => $record,
465
            'duration' => $duration,
466
        ];
467
468
        $status = false;
469
        $finalMeetingUrl = null;
470
471
        while ($status === false) {
472
            $result = $this->api->createMeetingWithXmlResponseArray($bbbParams);
473
            if (isset($result) && strval($result['returncode']) === 'SUCCESS') {
474
                if ($this->plugin->get('allow_regenerate_recording') === 'true') {
475
                    $meeting->setInternalMeetingId($result['internalMeetingID']);
476
                    $em->flush();
477
                }
478
479
                return $this->joinMeeting($meetingName, true);
480
            }
481
        }
482
483
        return false;
484
    }
485
486
    /**
487
     * @return bool
488
     */
489
    public function hasGroupSupport()
490
    {
491
        return $this->groupSupport;
492
    }
493
494
    /**
495
     * Gets the password for a specific meeting for the current user
496
     *
497
     * @param string $courseCode
498
     *
499
     * @return string A moderator password if user is teacher, or the course code otherwise
500
     *
501
     */
502
    public function getUserMeetingPassword($courseCode = null)
503
    {
504
        if ($this->isGlobalConferencePerUserEnabled()) {
505
            return 'url_'.$this->userId.'_'.api_get_current_access_url_id();
506
        }
507
508
        if ($this->isGlobalConference()) {
509
            return 'url_'.api_get_current_access_url_id();
510
        }
511
512
        return empty($courseCode) ? api_get_course_id() : $courseCode;
513
    }
514
515
    /**
516
     * Generated a moderator password for the meeting.
517
     *
518
     * @param string $courseCode
519
     *
520
     * @return string A password for the moderation of the videoconference
521
     */
522
    public function getModMeetingPassword($courseCode = null)
523
    {
524
        if ($this->isGlobalConferencePerUserEnabled()) {
525
            return 'url_'.$this->userId.'_'.api_get_current_access_url_id().'_mod';
526
        }
527
528
        if ($this->isGlobalConference()) {
529
            return 'url_'.api_get_current_access_url_id().'_mod';
530
        }
531
532
        $courseCode = empty($courseCode) ? api_get_course_id() : $courseCode;
533
534
        return $courseCode.'mod';
535
    }
536
537
    /**
538
     * @return string
539
     */
540
    public function getCurrentVideoConferenceName()
541
    {
542
        if ($this->isGlobalConferencePerUserEnabled()) {
543
            return 'url_'.$this->userId.'_'.api_get_current_access_url_id();
544
        }
545
546
        if ($this->isGlobalConference()) {
547
            return 'url_'.api_get_current_access_url_id();
548
        }
549
550
        if ($this->hasGroupSupport()) {
551
            return api_get_course_id().'-'.api_get_session_id().'-'.api_get_group_id();
552
        }
553
554
        return api_get_course_id().'-'.api_get_session_id();
555
    }
556
557
    /**
558
     * Returns a meeting "join" URL
559
     *
560
     * @param string The name of the meeting (usually the course code)
561
     *
562
     * @return mixed The URL to join the meeting, or false on error
563
     * @todo implement moderator pass
564
     * @assert ('') === false
565
     * @assert ('abcdefghijklmnopqrstuvwxyzabcdefghijklmno') === false
566
     */
567
    public function joinMeeting($meetingName)
568
    {
569
        if ($this->debug) {
570
            error_log("joinMeeting: $meetingName");
571
        }
572
573
        if (empty($meetingName)) {
574
            return false;
575
        }
576
577
        $manager = $this->isConferenceManager();
578
        $pass = $manager ? $this->getModMeetingPassword() : $this->getUserMeetingPassword();
579
580
        $meetingData = Database::getManager()
581
            ->getRepository(ConferenceMeeting::class)
582
            ->findOneBy([
583
                'title' => $meetingName,
584
                'status' => 1,
585
                'accessUrl' => api_get_url_entity($this->accessUrl),
586
            ]);
587
588
        if (empty($meetingData)) {
589
            if ($this->debug) {
590
                error_log("meeting does not exist: $meetingName");
591
            }
592
593
            return false;
594
        }
595
596
        $params = [
597
            'meetingId' => $meetingData->getRemoteId(),
598
            'password' => $this->getModMeetingPassword(),
599
        ];
600
601
        $meetingInfoExists = false;
602
        $meetingIsRunningInfo = $this->getMeetingInfo($params);
603
        if ($this->debug) {
604
            error_log('Searching meeting with params:');
605
            error_log(print_r($params, 1));
606
            error_log('Result:');
607
            error_log(print_r($meetingIsRunningInfo, 1));
608
        }
609
610
        if ($meetingIsRunningInfo === false) {
611
            $params['meetingId'] = $meetingData->getId();
612
            $meetingIsRunningInfo = $this->getMeetingInfo($params);
613
            if ($this->debug) {
614
                error_log('Searching meetingId with params:');
615
                error_log(print_r($params, 1));
616
                error_log('Result:');
617
                error_log(print_r($meetingIsRunningInfo, 1));
618
            }
619
        }
620
621
        if (
622
            strval($meetingIsRunningInfo['returncode']) === 'SUCCESS' &&
623
            isset($meetingIsRunningInfo['meetingName']) &&
624
            !empty($meetingIsRunningInfo['meetingName'])
625
        ) {
626
            $meetingInfoExists = true;
627
        }
628
629
        if ($this->debug) {
630
            error_log("meeting is running: " . intval($meetingInfoExists));
631
        }
632
633
        if ($meetingInfoExists) {
634
            $joinParams = [
635
                'meetingId' => $meetingData->getRemoteId(),
636
                'username' => $this->userCompleteName,
637
                'password' => $pass,
638
                'userID' => api_get_user_id(),
639
                'webVoiceConf' => '',
640
            ];
641
            $url = $this->api->getJoinMeetingURL($joinParams);
642
            return $this->protocol . $url;
643
        }
644
645
        return false;
646
    }
647
648
649
    /**
650
     * Checks whether a user is teacher in the current course
651
     * @return bool True if the user can be considered a teacher in this course, false otherwise
652
     */
653
    public function isConferenceManager()
654
    {
655
        if (api_is_coach() || api_is_platform_admin(false, true)) {
656
            return true;
657
        }
658
659
        if ($this->isGlobalConferencePerUserEnabled()) {
660
            $currentUserId = api_get_user_id();
661
            if ($this->userId === $currentUserId) {
662
                return true;
663
            } else {
664
                return false;
665
            }
666
        }
667
668
        $courseInfo = api_get_course_info();
669
        $groupId = api_get_group_id();
670
        if (!empty($groupId) && !empty($courseInfo)) {
671
            $groupEnabled = api_get_course_plugin_setting('bbb', 'bbb_enable_conference_in_groups') === '1';
672
            if ($groupEnabled) {
673
                $studentCanStartConference = api_get_course_plugin_setting(
674
                        'bbb',
675
                        'big_blue_button_students_start_conference_in_groups'
676
                    ) === '1';
677
678
                if ($studentCanStartConference) {
679
                    $isSubscribed = GroupManager::is_user_in_group(
0 ignored issues
show
Bug introduced by
The method is_user_in_group() does not exist on GroupManager. ( Ignorable by Annotation )

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

679
                    /** @scrutinizer ignore-call */ 
680
                    $isSubscribed = GroupManager::is_user_in_group(

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
680
                        api_get_user_id(),
681
                        GroupManager::get_group_properties($groupId)
682
                    );
683
                    if ($isSubscribed) {
684
                        return true;
685
                    }
686
                }
687
            }
688
        }
689
690
        if (!empty($courseInfo)) {
691
            return api_is_course_admin();
692
        }
693
694
        return false;
695
    }
696
697
    /**
698
     * Get information about the given meeting
699
     *
700
     * @param array ...?
701
     *
702
     * @return mixed Array of information on success, false on error
703
     * @assert (array()) === false
704
     */
705
    public function getMeetingInfo($params)
706
    {
707
        try {
708
            $result = $this->api->getMeetingInfoWithXmlResponseArray($params);
709
            if ($result == null) {
710
                if ($this->debug) {
711
                    error_log("Failed to get any response. Maybe we can't contact the BBB server.");
712
                }
713
            }
714
715
            return $result;
716
        } catch (Exception $e) {
717
            if ($this->debug) {
718
                error_log('Caught exception: ', $e->getMessage(), "\n");
719
            }
720
        }
721
722
        return false;
723
    }
724
725
726
    /**
727
     * @param int $meetingId
728
     * @param int $userId
729
     *
730
     * @return array
731
     */
732
    public function getMeetingParticipantInfo($meetingId, $userId): array
733
    {
734
        $em = Database::getManager();
735
        /** @var ConferenceActivityRepository $repo */
736
        $repo = $em->getRepository(ConferenceActivity::class);
737
738
        $activity = $repo->createQueryBuilder('a')
739
            ->join('a.meeting', 'm')
740
            ->join('a.participant', 'u')
741
            ->where('m.id = :meetingId')
742
            ->andWhere('u.id = :userId')
743
            ->setParameter('meetingId', $meetingId)
744
            ->setParameter('userId', $userId)
745
            ->setMaxResults(1)
746
            ->getQuery()
747
            ->getOneOrNullResult();
748
749
        if (!$activity) {
750
            return [];
751
        }
752
753
        return [
754
            'id' => $activity->getId(),
755
            'meeting_id' => $activity->getMeeting()?->getId(),
756
            'participant_id' => $activity->getParticipant()?->getId(),
757
            'in_at' => $activity->getInAt()?->format('Y-m-d H:i:s'),
758
            'out_at' => $activity->getOutAt()?->format('Y-m-d H:i:s'),
759
            'close' => $activity->isClose(),
760
            'type' => $activity->getType(),
761
            'event' => $activity->getEvent(),
762
            'activity_data' => $activity->getActivityData(),
763
            'signature_file' => $activity->getSignatureFile(),
764
            'signed_at' => $activity->getSignedAt()?->format('Y-m-d H:i:s'),
765
        ];
766
    }
767
768
    /**
769
     * Save a participant in a meeting room
770
     *
771
     * @param int $meetingId
772
     * @param int $participantId
773
     *
774
     * @return false|int The last inserted ID. Otherwise return false
775
     */
776
    public function saveParticipant(int $meetingId, int $participantId): false|int
777
    {
778
        $em = Database::getManager();
779
780
        /** @var ConferenceActivityRepository $repo */
781
        $repo = $em->getRepository(ConferenceActivity::class);
782
783
        $meeting = $em->getRepository(ConferenceMeeting::class)->find($meetingId);
784
        $user = api_get_user_entity($participantId);
785
786
        if (!$meeting || !$user) {
787
            return false;
788
        }
789
790
        $existing = $repo->createQueryBuilder('a')
791
            ->where('a.meeting = :meeting')
792
            ->andWhere('a.participant = :participant')
793
            ->andWhere('a.close = :open')
794
            ->setParameter('meeting', $meeting)
795
            ->setParameter('participant', $user)
796
            ->setParameter('open', \BbbPlugin::ROOM_OPEN)
797
            ->getQuery()
798
            ->getResult();
799
800
        foreach ($existing as $activity) {
801
            if ($activity->getInAt() != $activity->getOutAt()) {
802
                $activity->setClose(\BbbPlugin::ROOM_CLOSE);
803
            } else {
804
                $activity->setOutAt(new \DateTime());
805
                $activity->setClose(\BbbPlugin::ROOM_CLOSE);
806
            }
807
            $em->persist($activity);
808
        }
809
810
        $newActivity = new ConferenceActivity();
811
        $newActivity->setMeeting($meeting);
812
        $newActivity->setParticipant($user);
813
        $newActivity->setInAt(new \DateTime());
814
        $newActivity->setOutAt(new \DateTime());
815
        $newActivity->setClose(\BbbPlugin::ROOM_OPEN);
816
817
        $em->persist($newActivity);
818
        $em->flush();
819
820
        return $newActivity->getId();
821
    }
822
823
    /**
824
     * Tells whether the given meeting exists and is running
825
     * (using course code as name)
826
     *
827
     * @param string $meetingName Meeting name (usually the course code)
828
     *
829
     * @return bool True if meeting exists, false otherwise
830
     * @assert ('') === false
831
     * @assert ('abcdefghijklmnopqrstuvwxyzabcdefghijklmno') === false
832
     */
833
    public function meetingExists($meetingName)
834
    {
835
        $meetingData = $this->getMeetingByName($meetingName);
836
837
        return !empty($meetingData);
838
    }
839
840
    /**
841
     * @param string $meetingName
842
     *
843
     * @return array
844
     */
845
    public function getMeetingByName($meetingName)
846
    {
847
        if (empty($meetingName)) {
848
            return [];
849
        }
850
851
        $courseEntity = api_get_course_entity();
852
        $sessionEntity = api_get_session_entity();
853
        $accessUrlEntity = api_get_url_entity($this->accessUrl);
854
855
        $criteria = [
856
            'course' => $courseEntity,
857
            'session' => $sessionEntity,
858
            'title' => $meetingName,
859
            'status' => 1,
860
            'accessUrl' => $accessUrlEntity,
861
        ];
862
863
        if ($this->hasGroupSupport()) {
864
            $groupEntity = api_get_group_entity(api_get_group_id());
865
            $criteria['group'] = $groupEntity;
866
        }
867
868
        $meeting = Database::getManager()
869
            ->getRepository(ConferenceMeeting::class)
870
            ->findOneBy($criteria);
871
872
        if ($this->debug) {
873
            error_log('meeting_exists '.print_r($meeting ? ['id' => $meeting->getId()] : [], 1));
0 ignored issues
show
Bug introduced by
Are you sure print_r($meeting ? array...>getId()) : array(), 1) of type string|true can be used in concatenation? ( Ignorable by Annotation )

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

873
            error_log('meeting_exists './** @scrutinizer ignore-type */ print_r($meeting ? ['id' => $meeting->getId()] : [], 1));
Loading history...
874
        }
875
876
        if (!$meeting) {
877
            return [];
878
        }
879
880
        return [
881
            'id' => $meeting->getId(),
882
            'c_id' => $meeting->getCourse()?->getId(),
883
            'session_id' => $meeting->getSession()?->getId(),
884
            'meeting_name' => $meeting->getTitle(),
885
            'status' => $meeting->getStatus(),
886
            'access_url' => $meeting->getAccessUrl()?->getId(),
887
            'group_id' => $meeting->getGroup()?->getIid(),
888
            'remote_id' => $meeting->getRemoteId(),
889
            'moderator_pw' => $meeting->getModeratorPw(),
890
            'attendee_pw' => $meeting->getAttendeePw(),
891
            'created_at' => $meeting->getCreatedAt()->format('Y-m-d H:i:s'),
892
            'closed_at' => $meeting->getClosedAt()?->format('Y-m-d H:i:s'),
893
            'visibility' => $meeting->getVisibility(),
894
            'video_url' => $meeting->getVideoUrl(),
895
            'has_video_m4v' => $meeting->isHasVideoM4v(),
896
            'record' => $meeting->isRecord(),
897
            'internal_meeting_id' => $meeting->getInternalMeetingId(),
898
        ];
899
    }
900
901
    /**
902
     * Gets a list from the database of all meetings attached to a course with the given status
903
     * @param int $courseId
904
     * @param int $sessionId
905
     * @param int $status 0 for closed meetings, 1 for open meetings
906
     *
907
     * @return array
908
     */
909
    public function getAllMeetingsInCourse($courseId, $sessionId, $status)
910
    {
911
        $em = Database::getManager();
912
        $courseEntity = api_get_course_entity($courseId);
913
        $sessionEntity = api_get_session_entity($sessionId);
914
915
        $meetings = $em->getRepository(ConferenceMeeting::class)->findBy([
916
            'course' => $courseEntity,
917
            'session' => $sessionEntity,
918
            'status' => $status,
919
        ]);
920
921
        $results = [];
922
        foreach ($meetings as $meeting) {
923
            $results[] = [
924
                'id' => $meeting->getId(),
925
                'c_id' => $meeting->getCourse()?->getId(),
926
                'session_id' => $meeting->getSession()?->getId(),
927
                'meeting_name' => $meeting->getTitle(),
928
                'status' => $meeting->getStatus(),
929
                'access_url' => $meeting->getAccessUrl()?->getId(),
930
                'group_id' => $meeting->getGroup()?->getIid(),
931
                'remote_id' => $meeting->getRemoteId(),
932
                'moderator_pw' => $meeting->getModeratorPw(),
933
                'attendee_pw' => $meeting->getAttendeePw(),
934
                'created_at' => $meeting->getCreatedAt()->format('Y-m-d H:i:s'),
935
                'closed_at' => $meeting->getClosedAt()?->format('Y-m-d H:i:s'),
936
                'visibility' => $meeting->getVisibility(),
937
                'video_url' => $meeting->getVideoUrl(),
938
                'has_video_m4v' => $meeting->isHasVideoM4v(),
939
                'record' => $meeting->isRecord(),
940
                'internal_meeting_id' => $meeting->getInternalMeetingId(),
941
            ];
942
        }
943
944
        return $results;
945
    }
946
947
    /**
948
     * Gets all the course meetings saved in the plugin_bbb_meeting table and
949
     * generate actionable links (join/close/delete/etc)
950
     *
951
     * @param int   $courseId
952
     * @param int   $sessionId
953
     * @param int   $groupId
954
     * @param bool  $isAdminReport Optional. Set to true then the report is for admins
955
     * @param array $dateRange     Optional
956
     *
957
     * @return array Array of current open meeting rooms
958
     * @throws Exception
959
     */
960
    public function getMeetings(
961
        $courseId = 0,
962
        $sessionId = 0,
963
        $groupId = 0,
964
        $isAdminReport = false,
965
        $dateRange = []
966
    ) {
967
        $em = Database::getManager();
968
        $repo = $em->getRepository(ConferenceMeeting::class);
969
        $manager = $this->isConferenceManager();
970
        $isGlobal = $this->isGlobalConference();
971
        $meetings = [];
972
973
        if (!empty($dateRange)) {
974
            $dateStart = (new \DateTime($dateRange['search_meeting_start']))->setTime(0, 0, 0);
975
            $dateEnd = (new \DateTime($dateRange['search_meeting_end']))->setTime(23, 59, 59);
976
            $meetings = $repo->findByDateRange($dateStart, $dateEnd);
977
        } elseif ($this->isGlobalConference()) {
978
            $meetings = $repo->findBy([
979
                'course' => null,
980
                'user' => api_get_user_entity($this->userId),
981
                'accessUrl' => api_get_url_entity($this->accessUrl),
982
            ]);
983
        } elseif ($this->isGlobalConferencePerUserEnabled()) {
984
            $meetings = $repo->findBy([
985
                'course' => api_get_course_entity($courseId),
986
                'session' => api_get_session_entity($sessionId),
987
                'user' => api_get_user_entity($this->userId),
988
                'accessUrl' => api_get_url_entity($this->accessUrl),
989
            ]);
990
        } else {
991
            $criteria = [
992
                'course' => api_get_course_entity($courseId),
993
                'session' => api_get_session_entity($sessionId),
994
                'accessUrl' => api_get_url_entity($this->accessUrl),
995
            ];
996
            if ($this->hasGroupSupport() && $groupId) {
997
                $criteria['group'] = api_get_group_entity($groupId);
998
            }
999
            $meetings = $repo->findBy($criteria, ['createdAt' => 'ASC']);
1000
        }
1001
1002
        $result = [];
1003
        foreach ($meetings as $meeting) {
1004
            $meetingArray = $this->convertMeetingToArray($meeting);
1005
            $recordLink = $this->plugin->get_lang('NoRecording');
1006
            $meetingBBB = $this->getMeetingInfo([
1007
                'meetingId' => $meeting->getRemoteId(),
1008
                'password' => $manager ? $meeting->getModeratorPw() : $meeting->getAttendeePw(),
1009
            ]);
1010
1011
            if (!$meetingBBB && $meeting->getId()) {
1012
                $meetingBBB = $this->getMeetingInfo([
1013
                    'meetingId' => $meeting->getId(),
1014
                    'password' => $manager ? $meeting->getModeratorPw() : $meeting->getAttendeePw(),
1015
                ]);
1016
            }
1017
1018
            if (!$meeting->isVisible() && !$manager) {
1019
                continue;
1020
            }
1021
1022
            $meetingBBB['end_url'] = $this->endUrl(['id' => $meeting->getId()]);
1023
            if (isset($meetingBBB['returncode']) && (string) $meetingBBB['returncode'] === 'FAILED') {
1024
                if ($meeting->getStatus() === 1 && $manager) {
1025
                    $this->endMeeting($meeting->getId(), $meeting->getCourse()?->getCode());
1026
                }
1027
            } else {
1028
                $meetingBBB['add_to_calendar_url'] = $this->addToCalendarUrl($meetingArray);
1029
            }
1030
1031
            if ($meeting->isRecord()) {
1032
                $recordings = $this->api->getRecordingsWithXmlResponseArray(['meetingId' => $meeting->getRemoteId()]);
1033
                if (!empty($recordings) && (!isset($recordings['messageKey']) || $recordings['messageKey'] !== 'noRecordings')) {
1034
                    $record = end($recordings);
1035
                    if (isset($record['playbackFormatUrl'])) {
1036
                        $recordLink = Display::url(
1037
                            $this->plugin->get_lang('ViewRecord'),
1038
                            $record['playbackFormatUrl'],
1039
                            ['target' => '_blank', 'class' => 'btn btn--plain']
1040
                        );
1041
                        $this->updateMeetingVideoUrl($meeting->getId(), $record['playbackFormatUrl']);
1042
                    }
1043
                }
1044
            }
1045
1046
            $actionLinks = $this->getActionLinks($meetingArray, $record ?? [], $isGlobal, $isAdminReport);
1047
1048
            $item = array_merge($meetingArray, [
1049
                'go_url' => '',
1050
                'show_links' => $recordLink,
1051
                'action_links' => implode(PHP_EOL, $actionLinks),
1052
                'publish_url' => $this->publishUrl(['id' => $meeting->getId()]),
1053
                'unpublish_url' => $this->unPublishUrl(['id' => $meeting->getId()]),
1054
            ]);
1055
1056
            if ($meeting->getStatus() === 1) {
1057
                $joinParams = [
1058
                    'meetingId' => $meeting->getRemoteId(),
1059
                    'username' => $this->userCompleteName,
1060
                    'password' => $manager ? $meeting->getModeratorPw() : $meeting->getAttendeePw(),
1061
                    'createTime' => '',
1062
                    'userID' => '',
1063
                    'webVoiceConf' => '',
1064
                ];
1065
                $item['go_url'] = $this->protocol.$this->api->getJoinMeetingURL($joinParams);
1066
            }
1067
1068
            $result[] = array_merge($item, $meetingBBB);
1069
        }
1070
1071
        return $result;
1072
    }
1073
1074
    private function convertMeetingToArray(ConferenceMeeting $meeting): array
1075
    {
1076
        return [
1077
            'id' => $meeting->getId(),
1078
            'remote_id' => $meeting->getRemoteId(),
1079
            'internal_meeting_id' => $meeting->getInternalMeetingId(),
1080
            'meeting_name' => $meeting->getTitle(),
1081
            'status' => $meeting->getStatus(),
1082
            'visibility' => $meeting->getVisibility(),
1083
            'created_at' => $meeting->getCreatedAt() instanceof \DateTime ? $meeting->getCreatedAt()->format('Y-m-d H:i:s') : '',
0 ignored issues
show
introduced by
$meeting->getCreatedAt() is always a sub-type of DateTime.
Loading history...
1084
            'closed_at' => $meeting->getClosedAt() instanceof \DateTime ? $meeting->getClosedAt()->format('Y-m-d H:i:s') : '',
1085
            'record' => $meeting->isRecord() ? 1 : 0,
1086
            'c_id' => $meeting->getCourse()?->getId() ?? 0,
1087
            'session_id' => $meeting->getSession()?->getId() ?? 0,
1088
            'group_id' => $meeting->getGroup()?->getIid() ?? 0,
1089
            'course' => $meeting->getCourse(),
1090
            'session' => $meeting->getSession(),
1091
            'title' => $meeting->getTitle(),
1092
        ];
1093
    }
1094
1095
    public function getMeetingsLight(
1096
        $courseId = 0,
1097
        $sessionId = 0,
1098
        $groupId = 0,
1099
        $dateRange = []
1100
    ): array {
1101
        $em = Database::getManager();
1102
        $repo = $em->getRepository(ConferenceMeeting::class);
1103
        $meetings = [];
1104
1105
        if (!empty($dateRange)) {
1106
            $dateStart = (new \DateTime($dateRange['search_meeting_start']))->setTime(0, 0, 0);
1107
            $dateEnd = (new \DateTime($dateRange['search_meeting_end']))->setTime(23, 59, 59);
1108
            $meetings = $repo->findByDateRange($dateStart, $dateEnd);
1109
        } else {
1110
            $criteria = [
1111
                'course' => api_get_course_entity($courseId),
1112
                'session' => api_get_session_entity($sessionId),
1113
                'accessUrl' => api_get_url_entity($this->accessUrl),
1114
            ];
1115
            if ($this->hasGroupSupport() && $groupId) {
1116
                $criteria['group'] = api_get_group_entity($groupId);
1117
            }
1118
            $meetings = $repo->findBy($criteria, ['createdAt' => 'DESC']);
1119
        }
1120
1121
        $result = [];
1122
        foreach ($meetings as $meeting) {
1123
            $meetingArray = $this->convertMeetingToArray($meeting);
1124
1125
            $item = array_merge($meetingArray, [
1126
                'go_url' => '',
1127
                'show_links' => $this->plugin->get_lang('NoRecording'),
1128
                'action_links' => '',
1129
                'publish_url' => $this->publishUrl(['id' => $meeting->getId()]),
1130
                'unpublish_url' => $this->unPublishUrl(['id' => $meeting->getId()]),
1131
            ]);
1132
1133
            $result[] = $item;
1134
        }
1135
1136
        return $result;
1137
    }
1138
1139
    /**
1140
     * @param array $meeting
1141
     *
1142
     * @return string
1143
     */
1144
    public function endUrl($meeting)
1145
    {
1146
        if (!isset($meeting['id'])) {
1147
            return '';
1148
        }
1149
1150
        return api_get_path(WEB_PLUGIN_PATH).'Bbb/listing.php?'.$this->getUrlParams().'&action=end&id='.$meeting['id'];
1151
    }
1152
1153
    /**
1154
     * Closes a meeting (usually when the user click on the close button from
1155
     * the conferences listing.
1156
     *
1157
     * @param string The internal ID of the meeting (id field for this meeting)
1158
     * @param string $courseCode
1159
     *
1160
     * @return void
1161
     * @assert (0) === false
1162
     */
1163
    public function endMeeting($id, $courseCode = null)
1164
    {
1165
        if (empty($id)) {
1166
            return false;
1167
        }
1168
1169
        $em = Database::getManager();
1170
1171
        /** @var ConferenceMeetingRepository $repo */
1172
        $repo = $em->getRepository(ConferenceMeeting::class);
1173
1174
        $meetingData = $repo->findOneAsArrayById((int) $id);
1175
        if (!$meetingData) {
1176
            return false;
1177
        }
1178
1179
        $manager = $this->isConferenceManager();
1180
        $pass = $manager ? $meetingData['moderatorPw'] : $meetingData['attendeePw'];
1181
1182
        Event::addEvent(
1183
            'bbb_end_meeting',
1184
            'meeting_id',
1185
            (int) $id,
1186
            null,
1187
            api_get_user_id(),
1188
            api_get_course_int_id(),
1189
            api_get_session_id()
1190
        );
1191
1192
        $endParams = [
1193
            'meetingId' => $meetingData['remoteId'],
1194
            'password' => $pass,
1195
        ];
1196
        $this->api->endMeetingWithXmlResponseArray($endParams);
1197
1198
        $repo->closeMeeting((int) $id, new \DateTime());
1199
1200
        /** @var ConferenceActivityRepository $activityRepo */
1201
        $activityRepo = $em->getRepository(ConferenceActivity::class);
1202
1203
        $activities = $activityRepo->findOpenWithSameInAndOutTime((int) $id);
1204
1205
        foreach ($activities as $activity) {
1206
            $activity->setOutAt(new \DateTime());
1207
            $activity->setClose(BbbPlugin::ROOM_CLOSE);
1208
            $em->persist($activity);
1209
        }
1210
1211
        $activityRepo->closeAllByMeetingId((int) $id);
1212
1213
        $em->flush();
1214
1215
        return true;
1216
    }
1217
1218
    /**
1219
     * @param array $meeting
1220
     * @param array $record
1221
     *
1222
     * @return string
1223
     */
1224
    public function addToCalendarUrl($meeting, $record = []): string
1225
    {
1226
        $url = isset($record['playbackFormatUrl']) ? $record['playbackFormatUrl'] : '';
1227
1228
        return api_get_path(WEB_PLUGIN_PATH).'Bbb/listing.php?'.$this->getUrlParams(
1229
            ).'&action=add_to_calendar&id='.$meeting['id'].'&start='.api_strtotime($meeting['created_at']).'&url='.$url;
1230
    }
1231
1232
    /**
1233
     * @param int    $meetingId
1234
     * @param string $videoUrl
1235
     *
1236
     * @return bool|int
1237
     */
1238
    public function updateMeetingVideoUrl(int $meetingId, string $videoUrl): void
1239
    {
1240
        $em = Database::getManager();
1241
        /** @var ConferenceMeetingRepository $repo */
1242
        $repo = $em->getRepository(ConferenceMeeting::class);
1243
        $repo->updateVideoUrl($meetingId, $videoUrl);
1244
    }
1245
1246
    /**
1247
     * Force the course, session and/or group IDs
1248
     *
1249
     * @param string $courseCode
1250
     * @param int    $sessionId
1251
     * @param int    $groupId
1252
     */
1253
    public function forceCIdReq($courseCode, $sessionId = 0, $groupId = 0)
1254
    {
1255
        $this->courseCode = $courseCode;
1256
        $this->sessionId = (int) $sessionId;
1257
        $this->groupId = (int) $groupId;
1258
    }
1259
1260
    /**
1261
     * @param array $meetingInfo
1262
     * @param array $recordInfo
1263
     * @param bool  $isGlobal
1264
     * @param bool  $isAdminReport
1265
     *
1266
     * @return array
1267
     */
1268
    private function getActionLinks(
1269
        $meetingInfo,
1270
        $recordInfo,
1271
        $isGlobal = false,
1272
        $isAdminReport = false
1273
    ) {
1274
        $isVisible = $meetingInfo['visibility'] != 0;
1275
        $linkVisibility = $isVisible
1276
            ? Display::url(
1277
                Display::getMdiIcon(StateIcon::ACTIVE, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('MakeInvisible')),
1278
                $this->unPublishUrl($meetingInfo)
1279
            )
1280
            : Display::url(
1281
                Display::getMdiIcon(StateIcon::INACTIVE, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('MakeVisible')),
1282
                $this->publishUrl($meetingInfo)
1283
            );
1284
1285
        $links = [];
1286
        if ($this->plugin->get('allow_regenerate_recording') === 'true' && $meetingInfo['record'] == 1) {
1287
            if (!empty($recordInfo)) {
1288
                $links[] = Display::url(
1289
                    Display::getMdiIcon(ActionIcon::REFRESH, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('RegenerateRecord')),
1290
                    $this->regenerateRecordUrl($meetingInfo, $recordInfo)
1291
                );
1292
            } else {
1293
                $links[] = Display::url(
1294
                    Display::getMdiIcon(ActionIcon::REFRESH, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('RegenerateRecord')),
1295
                    $this->regenerateRecordUrlFromMeeting($meetingInfo)
1296
                );
1297
            }
1298
        }
1299
1300
        if (empty($recordInfo)) {
1301
            if (!$isAdminReport) {
1302
                if ($meetingInfo['status'] == 0) {
1303
                    $links[] = Display::url(
1304
                        Display::getMdiIcon(ActionIcon::DELETE, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Delete')),
1305
                        $this->deleteRecordUrl($meetingInfo)
1306
                    );
1307
                    $links[] = $linkVisibility;
1308
                }
1309
1310
                return $links;
1311
            } else {
1312
                $links[] = Display::url(
1313
                    Display::getMdiIcon(ObjectIcon::HOME, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('GoToCourse')),
1314
                    $this->getListingUrl($meetingInfo['c_id'], $meetingInfo['session_id'], $meetingInfo['group_id'])
1315
                );
1316
1317
                return $links;
1318
            }
1319
        }
1320
1321
        if (!$isGlobal) {
1322
            $links[] = Display::url(
1323
                Display::getMdiIcon(ObjectIcon::LINK, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('UrlMeetingToShare')),
1324
                $this->copyToRecordToLinkTool($meetingInfo)
1325
            );
1326
            $links[] = Display::url(
1327
                Display::getMdiIcon(ObjectIcon::AGENDA, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('AddToCalendar')),
1328
                $this->addToCalendarUrl($meetingInfo, $recordInfo)
1329
            );
1330
        }
1331
1332
        $hide = $this->plugin->get('disable_download_conference_link') === 'true' ? true : false;
1333
1334
        if ($hide == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
1335
            if ($meetingInfo['has_video_m4v']) {
1336
                $links[] = Display::url(
1337
                    Display::getMdiIcon(ActionIcon::SAVE_FORM, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('DownloadFile')),
1338
                    $recordInfo['playbackFormatUrl'].'/capture.m4v',
1339
                    ['target' => '_blank']
1340
                );
1341
            } else {
1342
                $links[] = Display::url(
1343
                    Display::getMdiIcon(ActionIcon::SAVE_FORM, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('DownloadFile')),
1344
                    '#',
1345
                    [
1346
                        'id' => "btn-check-meeting-video-{$meetingInfo['id']}",
1347
                        'class' => 'check-meeting-video',
1348
                        'data-id' => $meetingInfo['id'],
1349
                    ]
1350
                );
1351
            }
1352
        }
1353
1354
1355
        if (!$isAdminReport) {
1356
            $links[] = Display::url(
1357
                Display::getMdiIcon(ActionIcon::DELETE, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('Delete')),
1358
                $this->deleteRecordUrl($meetingInfo)
1359
            );
1360
            $links[] = $linkVisibility;
1361
        } else {
1362
            $links[] = Display::url(
1363
                Display::getMdiIcon(ObjectIcon::HOME, 'ch-tool-icon', null, ICON_SIZE_SMALL, get_lang('GoToCourse')),
1364
                $this->getListingUrl($meetingInfo['c_id'], $meetingInfo['session_id'], $meetingInfo['group_id'])
1365
            );
1366
        }
1367
1368
1369
        return $links;
1370
    }
1371
1372
    /**
1373
     * @param array $meeting
1374
     *
1375
     * @return string
1376
     */
1377
    public function unPublishUrl($meeting)
1378
    {
1379
        if (!isset($meeting['id'])) {
1380
            return null;
1381
        }
1382
1383
        return api_get_path(WEB_PLUGIN_PATH).'Bbb/listing.php?'.$this->getUrlParams(
1384
            ).'&action=unpublish&id='.$meeting['id'];
1385
    }
1386
1387
    /**
1388
     * @param array $meeting
1389
     *
1390
     * @return string
1391
     */
1392
    public function publishUrl($meeting)
1393
    {
1394
        if (!isset($meeting['id'])) {
1395
            return '';
1396
        }
1397
1398
        return api_get_path(WEB_PLUGIN_PATH).'Bbb/listing.php?'.$this->getUrlParams(
1399
            ).'&action=publish&id='.$meeting['id'];
1400
    }
1401
1402
    /**
1403
     * @param array $meeting
1404
     * @param array $recordInfo
1405
     *
1406
     * @return string
1407
     */
1408
    public function regenerateRecordUrl($meeting, $recordInfo)
1409
    {
1410
        if ($this->plugin->get('allow_regenerate_recording') !== 'true') {
1411
            return '';
1412
        }
1413
1414
        if (!isset($meeting['id'])) {
1415
            return '';
1416
        }
1417
1418
        if (empty($recordInfo) || (!empty($recordInfo['recordId']) && !isset($recordInfo['recordId']))) {
1419
            return '';
1420
        }
1421
1422
        return api_get_path(WEB_PLUGIN_PATH).'Bbb/listing.php?'.$this->getUrlParams().
1423
            '&action=regenerate_record&id='.$meeting['id'].'&record_id='.$recordInfo['recordId'];
1424
    }
1425
1426
    /**
1427
     * @param array $meeting
1428
     *
1429
     * @return string
1430
     */
1431
    public function regenerateRecordUrlFromMeeting($meeting)
1432
    {
1433
        if ($this->plugin->get('allow_regenerate_recording') !== 'true') {
1434
            return '';
1435
        }
1436
1437
        if (!isset($meeting['id'])) {
1438
            return '';
1439
        }
1440
1441
        return api_get_path(WEB_PLUGIN_PATH).'Bbb/listing.php?'.$this->getUrlParams().
1442
            '&action=regenerate_record&id='.$meeting['id'];
1443
    }
1444
1445
    /**
1446
     * @param array $meeting
1447
     *
1448
     * @return string
1449
     */
1450
    public function deleteRecordUrl($meeting)
1451
    {
1452
        if (!isset($meeting['id'])) {
1453
            return '';
1454
        }
1455
1456
        return api_get_path(WEB_PLUGIN_PATH).'Bbb/listing.php?'.$this->getUrlParams(
1457
            ).'&action=delete_record&id='.$meeting['id'];
1458
    }
1459
1460
    /**
1461
     * @param array $meeting
1462
     *
1463
     * @return string
1464
     */
1465
    public function copyToRecordToLinkTool($meeting)
1466
    {
1467
        if (!isset($meeting['id'])) {
1468
            return '';
1469
        }
1470
1471
        return api_get_path(WEB_PLUGIN_PATH).
1472
            'Bbb/listing.php?'.$this->getUrlParams().'&action=copy_record_to_link_tool&id='.$meeting['id'];
1473
    }
1474
1475
    /**
1476
     * Function disabled
1477
     */
1478
    public function publishMeeting($id)
1479
    {
1480
        if (empty($id)) {
1481
            return false;
1482
        }
1483
1484
        $em = Database::getManager();
1485
        /** @var ConferenceMeetingRepository $repo */
1486
        $repo = $em->getRepository(ConferenceMeeting::class);
1487
1488
        $meeting = $repo->find($id);
1489
        if (!$meeting) {
1490
            return false;
1491
        }
1492
1493
        $meeting->setVisibility(1);
1494
        $em->flush();
1495
1496
        return true;
1497
    }
1498
1499
    /**
1500
     * Function disabled
1501
     */
1502
    public function unpublishMeeting($id)
1503
    {
1504
        if (empty($id)) {
1505
            return false;
1506
        }
1507
1508
        $em = Database::getManager();
1509
        /** @var ConferenceMeetingRepository $repo */
1510
        $repo = $em->getRepository(ConferenceMeeting::class);
1511
1512
        $meeting = $repo->find($id);
1513
        if (!$meeting) {
1514
            return false;
1515
        }
1516
1517
        $meeting->setVisibility(0);
1518
        $em->flush();
1519
1520
        return true;
1521
    }
1522
1523
    /**
1524
     * Get users online in the current course room.
1525
     *
1526
     * @return int The number of users currently connected to the videoconference
1527
     * @assert () > -1
1528
     */
1529
    public function getUsersOnlineInCurrentRoom()
1530
    {
1531
        $courseId = api_get_course_int_id();
1532
        $sessionId = api_get_session_id();
1533
1534
        $em = Database::getManager();
1535
        $repo = $em->getRepository(ConferenceMeeting::class);
1536
1537
        $qb = $repo->createQueryBuilder('m')
1538
            ->where('m.status = 1')
1539
            ->andWhere('m.accessUrl = :accessUrl')
1540
            ->setParameter('accessUrl', $this->accessUrl)
1541
            ->setMaxResults(1);
1542
1543
        if ($this->hasGroupSupport()) {
1544
            $groupId = api_get_group_id();
1545
            $qb->andWhere('m.course = :courseId')
1546
                ->andWhere('m.session = :sessionId')
1547
                ->andWhere('m.group = :groupId')
1548
                ->setParameter('courseId', $courseId)
1549
                ->setParameter('sessionId', $sessionId)
1550
                ->setParameter('groupId', $groupId);
1551
        } elseif ($this->isGlobalConferencePerUserEnabled()) {
1552
            $qb->andWhere('m.user = :userId')
1553
                ->setParameter('userId', $this->userId);
1554
        } else {
1555
            $qb->andWhere('m.course = :courseId')
1556
                ->andWhere('m.session = :sessionId')
1557
                ->setParameter('courseId', $courseId)
1558
                ->setParameter('sessionId', $sessionId);
1559
        }
1560
1561
        $meetingData = $qb->getQuery()->getOneOrNullResult();
1562
1563
        if (!$meetingData) {
1564
            return 0;
1565
        }
1566
        $pass = $meetingData->getModeratorPw();
1567
        $info = $this->getMeetingInfo([
1568
            'meetingId' => $meetingData->getRemoteId(),
1569
            'password' => $pass,
1570
        ]);
1571
        if ($info === false) {
1572
            $info = $this->getMeetingInfo([
1573
                'meetingId' => $meetingData->getId(),
1574
                'password' => $pass,
1575
            ]);
1576
        }
1577
1578
        if (!empty($info) && isset($info['participantCount'])) {
1579
            return (int) $info['participantCount'];
1580
        }
1581
1582
        return 0;
1583
    }
1584
1585
    /**
1586
     * @param int    $id
1587
     * @param string $recordId
1588
     *
1589
     * @return bool
1590
     */
1591
    public function regenerateRecording($id, $recordId = '')
1592
    {
1593
        if ($this->plugin->get('allow_regenerate_recording') !== 'true') {
1594
            return false;
1595
        }
1596
1597
        if (empty($id)) {
1598
            return false;
1599
        }
1600
1601
        $em = Database::getManager();
1602
        /** @var ConferenceMeetingRepository $repo */
1603
        $repo = $em->getRepository(ConferenceMeeting::class);
1604
1605
        $meetingData = $repo->findOneAsArrayById((int) $id);
1606
        if (!$meetingData) {
1607
            return false;
1608
        }
1609
1610
        Event::addEvent(
1611
            'bbb_regenerate_record',
1612
            'record_id',
1613
            (int) $recordId,
1614
            null,
1615
            api_get_user_id(),
1616
            api_get_course_int_id(),
1617
            api_get_session_id()
1618
        );
1619
1620
        /** @var ConferenceRecordingRepository $recordingRepo */
1621
        $recordingRepo = $em->getRepository(ConferenceRecordingRepository::class);
1622
        $recordings = $recordingRepo->findByMeetingRemoteId($meetingData['remoteId']);
1623
1624
        if (!empty($recordings) && isset($recordings['messageKey']) && $recordings['messageKey'] === 'noRecordings') {
1625
            if (!empty($meetingData['internalMeetingId'])) {
1626
                return $this->api->generateRecording(['recordId' => $meetingData['internalMeetingId']]);
1627
            }
1628
1629
            return false;
1630
        }
1631
1632
        if (!empty($recordings['records'])) {
1633
            foreach ($recordings['records'] as $record) {
1634
                if ($recordId == $record['recordId']) {
1635
                    return $this->api->generateRecording(['recordId' => $recordId]);
1636
                }
1637
            }
1638
        }
1639
1640
        return false;
1641
    }
1642
1643
    /**
1644
     * Deletes a recording of a meeting
1645
     *
1646
     * @param int $id ID of the recording
1647
     *
1648
     * @return bool
1649
     *
1650
     * @assert () === false
1651
     * @todo Also delete links and agenda items created from this recording
1652
     */
1653
    public function deleteRecording($id)
1654
    {
1655
        if (empty($id)) {
1656
            return false;
1657
        }
1658
1659
        $em = Database::getManager();
1660
1661
        /** @var ConferenceMeetingRepository $meetingRepo */
1662
        $meetingRepo = $em->getRepository(ConferenceMeeting::class);
1663
        $meetingData = $meetingRepo->findOneAsArrayById((int) $id);
1664
        if (!$meetingData) {
1665
            return false;
1666
        }
1667
1668
        Event::addEvent(
1669
            'bbb_delete_record',
1670
            'meeting_id',
1671
            $id,
1672
            null,
1673
            api_get_user_id(),
1674
            api_get_course_int_id(),
1675
            api_get_session_id()
1676
        );
1677
1678
        $delete = false;
1679
        $recordings = [];
1680
1681
        if (!empty($meetingData['remoteId'])) {
1682
            Event::addEvent(
1683
                'bbb_delete_record',
1684
                'remote_id',
1685
                $meetingData['remoteId'],
1686
                null,
1687
                api_get_user_id(),
1688
                api_get_course_int_id(),
1689
                api_get_session_id()
1690
            );
1691
1692
            /** @var ConferenceRecordingRepository $recordingRepo */
1693
            $recordingRepo = $em->getRepository(ConferenceRecording::class);
1694
            $recordings = $recordingRepo->findByMeetingRemoteId($meetingData['remoteId']);
1695
        }
1696
1697
        if (!empty($recordings) && isset($recordings['messageKey']) && $recordings['messageKey'] === 'noRecordings') {
1698
            $delete = true;
1699
        } elseif (!empty($recordings['records'])) {
1700
            $recordsToDelete = [];
1701
            foreach ($recordings['records'] as $record) {
1702
                $recordsToDelete[] = $record['recordId'];
1703
            }
1704
1705
            if (!empty($recordsToDelete)) {
1706
                $recordingParams = ['recordId' => implode(',', $recordsToDelete)];
1707
                Event::addEvent(
1708
                    'bbb_delete_record',
1709
                    'record_id_list',
1710
                    implode(',', $recordsToDelete),
1711
                    null,
1712
                    api_get_user_id(),
1713
                    api_get_course_int_id(),
1714
                    api_get_session_id()
1715
                );
1716
1717
                $result = $this->api->deleteRecordingsWithXmlResponseArray($recordingParams);
1718
1719
                if (!empty($result) && isset($result['deleted']) && $result['deleted'] === 'true') {
1720
                    $delete = true;
1721
                }
1722
            }
1723
        }
1724
1725
        if (!$delete) {
1726
            $delete = true;
1727
        }
1728
1729
        if ($delete) {
1730
            /** @var ConferenceActivityRepository $activityRepo */
1731
            $activityRepo = $em->getRepository(ConferenceActivity::class);
1732
            $activityRepo->closeAllByMeetingId((int) $id);
1733
1734
            $meeting = $meetingRepo->find((int) $id);
1735
            if ($meeting) {
1736
                $em->remove($meeting);
1737
            }
1738
1739
            $em->flush();
1740
        }
1741
1742
        return $delete;
1743
    }
1744
1745
    /**
1746
     * Creates a link in the links tool from the given videoconference recording
1747
     *
1748
     * @param int $id ID of the item in the plugin_bbb_meeting table
1749
     * @param string Hash identifying the recording, as provided by the API
1750
     *
1751
     * @return mixed ID of the newly created link, or false on error
1752
     * @assert (null, null) === false
1753
     * @assert (1, null) === false
1754
     * @assert (null, 'abcdefabcdefabcdefabcdef') === false
1755
     */
1756
    public function copyRecordingToLinkTool($id)
1757
    {
1758
        if (empty($id)) {
1759
            return false;
1760
        }
1761
1762
        $em = Database::getManager();
1763
        /** @var ConferenceMeetingRepository $repo */
1764
        $repo = $em->getRepository(ConferenceMeeting::class);
1765
1766
        $meetingData = $repo->findOneAsArrayById((int) $id);
1767
        if (!$meetingData || empty($meetingData['remoteId'])) {
1768
            return false;
1769
        }
1770
1771
        $records = $this->api->getRecordingsWithXmlResponseArray([
1772
            'meetingId' => $meetingData['remoteId']
1773
        ]);
1774
1775
        if (!empty($records)) {
1776
            if (isset($records['message']) && !empty($records['message'])) {
1777
                if ($records['messageKey'] == 'noRecordings') {
1778
                    return false;
1779
                }
1780
            } else {
1781
                $record = $records[0];
1782
                if (is_array($record) && isset($record['recordId'])) {
1783
                    $url = $record['playbackFormatUrl'];
1784
                    $link = new \Link();
1785
                    $params = [
1786
                        'url' => $url,
1787
                        'title' => $meetingData['title'],
1788
                    ];
1789
                    $id = $link->save($params);
1790
1791
                    return $id;
1792
                }
1793
            }
1794
        }
1795
1796
        return false;
1797
    }
1798
1799
    /**
1800
     * Checks if the video conference server is running.
1801
     * Function currently disabled (always returns 1)
1802
     * @return bool True if server is running, false otherwise
1803
     * @assert () === false
1804
     */
1805
    public function isServerRunning()
1806
    {
1807
        return true;
1808
        //return BigBlueButtonBN::isServerRunning($this->protocol.$this->url);
1809
    }
1810
1811
    /**
1812
     * Checks if the video conference plugin is properly configured
1813
     * @return bool True if plugin has a host and a salt, false otherwise
1814
     * @assert () === false
1815
     */
1816
    public function isServerConfigured()
1817
    {
1818
        $host = $this->plugin->get('host');
1819
1820
        if (empty($host)) {
1821
            return false;
1822
        }
1823
1824
        $salt = $this->plugin->get('salt');
1825
1826
        if (empty($salt)) {
1827
            return false;
1828
        }
1829
1830
        return true;
1831
        //return BigBlueButtonBN::isServerRunning($this->protocol.$this->url);
1832
    }
1833
1834
    /**
1835
     * Get active session in the all platform
1836
     */
1837
    public function getActiveSessionsCount(): int
1838
    {
1839
        $em = Database::getManager();
1840
        $qb = $em->createQueryBuilder();
1841
1842
        $qb->select('COUNT(m.id)')
1843
            ->from(ConferenceMeeting::class, 'm')
1844
            ->where('m.status = :status')
1845
            ->andWhere('m.accessUrl = :accessUrl')
1846
            ->setParameter('status', 1)
1847
            ->setParameter('accessUrl', $this->accessUrl);
1848
1849
        return (int) $qb->getQuery()->getSingleScalarResult();
1850
    }
1851
1852
    /**
1853
     * Get active session in the all platform
1854
     */
1855
    public function getActiveSessions(): array
1856
    {
1857
        $em = Database::getManager();
1858
        $repo = $em->getRepository(ConferenceMeeting::class);
1859
1860
        $qb = $repo->createQueryBuilder('m')
1861
            ->where('m.status = :status')
1862
            ->andWhere('m.accessUrl = :accessUrl')
1863
            ->setParameter('status', 1)
1864
            ->setParameter('accessUrl', $this->accessUrl);
1865
1866
        return $qb->getQuery()->getArrayResult();
1867
    }
1868
1869
    /**
1870
     * @param string $url
1871
     */
1872
    public function redirectToBBB($url)
1873
    {
1874
        if (file_exists(__DIR__.'/../config.vm.php')) {
1875
            // Using VM
1876
            echo Display::url($this->plugin->get_lang('ClickToContinue'), $url);
1877
            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...
1878
        } else {
1879
            // Classic
1880
            header("Location: $url");
1881
            exit;
1882
        }
1883
    }
1884
1885
    /**
1886
     * @return string
1887
     */
1888
    public function getConferenceUrl()
1889
    {
1890
        return api_get_path(WEB_PLUGIN_PATH).'Bbb/start.php?launch=1&'.$this->getUrlParams();
1891
    }
1892
1893
    /**
1894
     * Get the meeting info from DB by its name
1895
     *
1896
     * @param string $name
1897
     *
1898
     * @return array
1899
     */
1900
    public function findMeetingByName(string $name): ?array
1901
    {
1902
        $em = Database::getManager();
1903
        /** @var ConferenceMeetingRepository $repo */
1904
        $repo = $em->getRepository(ConferenceMeeting::class);
1905
1906
        $qb = $repo->createQueryBuilder('m')
1907
            ->where('m.title = :name')
1908
            ->setParameter('name', $name)
1909
            ->setMaxResults(1);
1910
1911
        $result = $qb->getQuery()->getArrayResult();
1912
1913
        return $result[0] ?? null;
1914
    }
1915
1916
    /**
1917
     * Get the meeting info from DB by its name
1918
     *
1919
     * @param int $id
1920
     *
1921
     * @return array
1922
     */
1923
    public function getMeeting(int $id): ?array
1924
    {
1925
        $em = Database::getManager();
1926
        /** @var ConferenceMeetingRepository $repo */
1927
        $repo = $em->getRepository(ConferenceMeeting::class);
1928
1929
        return $repo->findOneAsArrayById($id);
1930
    }
1931
1932
    /**
1933
     * Get the meeting info.
1934
     *
1935
     * @param int $id
1936
     *
1937
     * @return array
1938
     */
1939
    public function getMeetingByRemoteId(string $id): ?array
1940
    {
1941
        $em = Database::getManager();
1942
        /** @var ConferenceMeetingRepository $repo */
1943
        $repo = $em->getRepository(ConferenceMeeting::class);
1944
1945
        return $repo->findOneByRemoteIdAndAccessUrl($id, $this->accessUrl);
1946
    }
1947
1948
    /**
1949
     * @param int $meetingId
1950
     *
1951
     * @return array
1952
     */
1953
    public function findConnectedMeetingParticipants(int $meetingId): array
1954
    {
1955
        $em = Database::getManager();
1956
        /** @var ConferenceActivityRepository $repo */
1957
        $repo = $em->getRepository(ConferenceActivity::class);
1958
1959
        $activities = $repo->createQueryBuilder('a')
1960
            ->where('a.meeting = :meetingId')
1961
            ->andWhere('a.inAt IS NOT NULL')
1962
            ->setParameter('meetingId', $meetingId)
1963
            ->getQuery()
1964
            ->getResult();
1965
1966
        $participantIds = [];
1967
        $return = [];
1968
1969
        foreach ($activities as $activity) {
1970
            $participant = $activity->getParticipant();
1971
            $participantId = $participant?->getId();
1972
1973
            if (!$participantId || in_array($participantId, $participantIds)) {
1974
                continue;
1975
            }
1976
1977
            $participantIds[] = $participantId;
1978
1979
            $return[] = [
1980
                'id' => $activity->getId(),
1981
                'meeting_id' => $meetingId,
1982
                'participant' => api_get_user_entity($participantId),
1983
                'in_at' => $activity->getInAt()?->format('Y-m-d H:i:s'),
1984
                'out_at' => $activity->getOutAt()?->format('Y-m-d H:i:s'),
1985
            ];
1986
        }
1987
1988
        return $return;
1989
    }
1990
1991
    /**
1992
     * Check if the meeting has a capture.m4v video file. If exists then the has_video_m4v field is updated
1993
     *
1994
     * @param int $meetingId
1995
     *
1996
     * @return bool
1997
     */
1998
    public function checkDirectMeetingVideoUrl(int $meetingId): bool
1999
    {
2000
        $em = Database::getManager();
2001
        /** @var ConferenceMeetingRepository $repo */
2002
        $repo = $em->getRepository(ConferenceMeeting::class);
2003
2004
        $meetingInfo = $repo->findOneAsArrayById($meetingId);
2005
2006
        if (empty($meetingInfo) || !isset($meetingInfo['videoUrl'])) {
2007
            return false;
2008
        }
2009
2010
        $hasCapture = SocialManager::verifyUrl($meetingInfo['videoUrl'].'/capture.m4v');
2011
2012
        if ($hasCapture) {
2013
            $qb = $em->createQueryBuilder();
2014
            $qb->update(ConferenceMeeting::class, 'm')
2015
                ->set('m.hasVideoM4v', ':value')
2016
                ->where('m.id = :id')
2017
                ->setParameter('value', true)
2018
                ->setParameter('id', $meetingId)
2019
                ->getQuery()
2020
                ->execute();
2021
2022
            return true;
2023
        }
2024
2025
        return false;
2026
    }
2027
}
2028