Completed
Push — 1.10.x ( 1a78fc...c0a895 )
by Yannick
62:01 queued 21:27
created

bbb::forceCIdReq()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 3
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
/**
5
 * Class bbb
6
 * This script initiates a video conference session, calling the BigBlueButton
7
 * API
8
 * @package chamilo.plugin.bigbluebutton
9
 *
10
 * BigBlueButton-Chamilo connector class
11
 */
12
//namespace Chamilo\Plugin\BBB;
13
14
/**
15
 * Class bbb
16
 * @package Chamilo\Plugin\BBB
17
 */
18
class bbb
19
{
20
    public $url;
21
    public $salt;
22
    public $api;
23
    public $userCompleteName = '';
24
    public $protocol = 'http://';
25
    public $debug = false;
26
    public $logoutUrl = '';
27
    public $pluginEnabled = false;
28
    public $enableGlobalConference = false;
29
    public $isGlobalConference = false;
30
    public $groupSupport = false;
31
    private $courseCode;
32
    private $sessionId;
33
    private $groupId;
34
35
    /**
36
     * Constructor (generates a connection to the API and the Chamilo settings
37
     * required for the connection to the video conference server)
38
     * @param string $host
39
     * @param string $salt
40
     * @param bool $isGlobalConference
41
     */
42
    public function __construct($host = '', $salt = '', $isGlobalConference = false)
43
    {
44
        $this->courseCode = api_get_course_id();
45
        $this->sessionId = api_get_session_id();
46
        $this->groupId = api_get_group_id();
47
48
        // Initialize video server settings from global settings
49
        $plugin = BBBPlugin::create();
50
51
        $bbbPlugin = $plugin->get('tool_enable');
52
53
        $bbb_host = !empty($host) ? $host : $plugin->get('host');
54
        $bbb_salt = !empty($salt) ? $salt : $plugin->get('salt');
55
56
        $this->logoutUrl = $this->getListingUrl();
57
        $this->table = Database::get_main_table('plugin_bbb_meeting');
58
        $this->enableGlobalConference = $plugin->get('enable_global_conference');
59
        $this->isGlobalConference = (bool) $isGlobalConference;
60
61
        $columns = Database::listTableColumns($this->table);
62
        $this->groupSupport = isset($columns['group_id']) ? true : false;
63
64
        if ($this->groupSupport) {
65
            // Plugin check
66
            $this->groupSupport = (bool) $plugin->get('enable_conference_in_course_groups');
67
            if ($this->groupSupport) {
68
69
                // Platform check
70
                $bbbSetting = api_get_setting('bbb_enable_conference_in_course_groups');
71
                $bbbSetting = isset($bbbSetting['bbb']) ? $bbbSetting['bbb'] === 'true' : false;
72
73
                if ($bbbSetting) {
74
                    // Course check
75
                    $courseInfo = api_get_course_info();
76
77
                    if ($courseInfo) {
78
                        $this->groupSupport = api_get_course_setting('bbb_enable_conference_in_groups') === '1';
79
                    }
80
                }
81
            }
82
        }
83
84
        if ($bbbPlugin == true) {
85
            $userInfo = api_get_user_info();
86
            $this->userCompleteName = $userInfo['complete_name'];
87
            $this->salt = $bbb_salt;
88
            $info = parse_url($bbb_host);
89
            $this->url = $bbb_host.'/bigbluebutton/';
90
            if (isset($info['scheme'])) {
91
                $this->protocol = $info['scheme'].'://';
92
                $this->url = str_replace($this->protocol, '', $this->url);
93
            }
94
95
            // Setting BBB api
96
            define('CONFIG_SECURITY_SALT', $this->salt);
97
            define('CONFIG_SERVER_BASE_URL', $this->url);
98
99
            $this->api = new BigBlueButtonBN();
100
            $this->pluginEnabled = true;
101
        }
102
    }
103
104
    /**
105
     * Set forced the course, session or group IDs
106
     * @param string $courseCode
107
     * @param int $sessionId
108
     * @param int $groupId
109
     */
110
    public function forceCIdReq($courseCode, $sessionId = 0, $groupId = 0)
111
    {
112
        $this->courseCode = $courseCode;
113
        $this->sessionId = intval($sessionId);
114
        $this->groupId = intval($groupId);
115
    }
116
117
    /**
118
     * @return bool
119
     */
120
    public function isGlobalConferenceEnabled()
121
    {
122
        return (bool) $this->enableGlobalConference;
123
    }
124
125
    /**
126
     * @return bool
127
     */
128
    public function isGlobalConference()
129
    {
130
        if ($this->isGlobalConferenceEnabled() === false) {
131
132
            return false;
133
        }
134
135
        return (bool) $this->isGlobalConference;
136
    }
137
138
    /**
139
     * @return bool
140
     */
141
    public function hasGroupSupport()
142
    {
143
        return $this->groupSupport;
144
    }
145
146
    /**
147
     * Checks whether a user is teacher in the current course
148
     * @return bool True if the user can be considered a teacher in this course, false otherwise
149
     */
150
    public function isConferenceManager()
151
    {
152
        return api_is_course_admin() || api_is_coach() || api_is_platform_admin();
153
    }
154
155
    /**
156
     * See this file in you BBB to set up default values
157
     * @param   array $params Array of parameters that will be completed if not containing all expected variables
158
159
       /var/lib/tomcat6/webapps/bigbluebutton/WEB-INF/classes/bigbluebutton.properties
160
     *
161
       More record information:
162
       http://code.google.com/p/bigbluebutton/wiki/RecordPlaybackSpecification
163
164
       # Default maximum number of users a meeting can have.
165
        # Doesn't get enforced yet but is the default value when the create
166
        # API doesn't pass a value.
167
        defaultMaxUsers=20
168
169
        # Default duration of the meeting in minutes.
170
        # Current default is 0 (meeting doesn't end).
171
        defaultMeetingDuration=0
172
173
        # Remove the meeting from memory when the end API is called.
174
        # This allows 3rd-party apps to recycle the meeting right-away
175
        # instead of waiting for the meeting to expire (see below).
176
        removeMeetingWhenEnded=false
177
178
        # The number of minutes before the system removes the meeting from memory.
179
        defaultMeetingExpireDuration=1
180
181
        # The number of minutes the system waits when a meeting is created and when
182
        # a user joins. If after this period, a user hasn't joined, the meeting is
183
        # removed from memory.
184
        defaultMeetingCreateJoinDuration=5
185
     *
186
     * @return mixed
187
     */
188
    public function createMeeting($params)
189
    {
190
        $courseCode = api_get_course_id();
191
        $params['c_id'] = api_get_course_int_id();
192
        $params['session_id'] = api_get_session_id();
193
194
        if ($this->hasGroupSupport()) {
195
            $params['group_id'] = api_get_group_id();
196
        }
197
198
        $params['attendee_pw'] = isset($params['moderator_pw']) ? $params['moderator_pw'] : $courseCode;
199
        $attendeePassword =  $params['attendee_pw'];
200
        $params['moderator_pw'] = isset($params['moderator_pw']) ? $params['moderator_pw'] : $this->getModMeetingPassword();
201
        $moderatorPassword = $params['moderator_pw'];
202
203
        $params['record'] = api_get_course_setting('big_blue_button_record_and_store', $courseCode) == 1 ? true : false;
204
        $max = api_get_course_setting('big_blue_button_max_students_allowed', $courseCode);
205
        $max =  isset($max) ? $max : -1;
206
207
        $params['status'] = 1;
208
        // Generate a pseudo-global-unique-id to avoid clash of conferences on
209
        // the same BBB server with several Chamilo portals
210
        $params['remote_id'] = uniqid(true, true);
211
        // Each simultaneous conference room needs to have a different
212
        // voice_bridge composed of a 5 digits number, so generating a random one
213
        $params['voice_bridge'] = rand(10000, 99999);
214
215
        if ($this->debug) {
216
            error_log("enter create_meeting ".print_r($params, 1));
217
        }
218
219
        $params['created_at'] = api_get_utc_datetime();
220
        $id = Database::insert($this->table, $params);
221
222
        if ($id) {
223
            if ($this->debug) {
224
                error_log("create_meeting: $id ");
225
            }
226
227
            $meetingName = isset($params['meeting_name']) ? $params['meeting_name'] : $this->getCurrentVideoConferenceName();
228
            $welcomeMessage = isset($params['welcome_msg']) ? $params['welcome_msg'] : null;
229
            $record = isset($params['record']) && $params['record'] ? 'true' : 'false';
230
            $duration = isset($params['duration']) ? intval($params['duration']) : 0;
231
            // This setting currently limits the maximum conference duration,
232
            // to avoid lingering sessions on the video-conference server #6261
233
            $duration = 300;
234
235
            $bbbParams = array(
236
                'meetingId' => $params['remote_id'], 					// REQUIRED
237
                'meetingName' => $meetingName, 	// REQUIRED
238
                'attendeePw' => $attendeePassword, 					// Match this value in getJoinMeetingURL() to join as attendee.
239
                'moderatorPw' => $moderatorPassword, 					// Match this value in getJoinMeetingURL() to join as moderator.
240
                'welcomeMsg' => $welcomeMessage, 					// ''= use default. Change to customize.
241
                'dialNumber' => '', 					// The main number to call into. Optional.
242
                'voiceBridge' => $params['voice_bridge'], 					// PIN to join voice. Required.
243
                'webVoice' => '', 						// Alphanumeric to join voice. Optional.
244
                'logoutUrl' =>  $this->logoutUrl,
245
                'maxParticipants' => $max, 				// Optional. -1 = unlimitted. Not supported in BBB. [number]
246
                'record' => $record, 					// New. 'true' will tell BBB to record the meeting.
247
                'duration' => $duration, 				// Default = 0 which means no set duration in minutes. [number]
248
                //'meta_category' => '', 				// Use to pass additional info to BBB server. See API docs.
249
            );
250
251
            if ($this->debug) {
252
                error_log("create_meeting params: ".print_r($bbbParams,1));
253
            }
254
255
            $status = false;
256
            $meeting = null;
257
258
            while ($status === false) {
259
                $result = $this->api->createMeetingWithXmlResponseArray(
260
                    $bbbParams
261
                );
262
                if (isset($result) && strval($result['returncode']) == 'SUCCESS') {
263
                    if ($this->debug) {
264
                        error_log(
265
                            "create_meeting result: " . print_r($result, 1)
266
                        );
267
                    }
268
                    $meeting = $this->joinMeeting($meetingName, true);
269
270
                    return $meeting;
271
                }
272
            }
273
274
            return $this->logoutUrl;
275
        }
276
    }
277
278
    /**
279
     * Save a participant in a meeting room
280
     * @param int $meetingId
281
     * @param int $participantId
282
     * @return false|int The last inserted ID. Otherwise return false
283
     */
284
    public function saveParticipant($meetingId, $participantId)
285
    {
286
        return Database::insert(
287
            'plugin_bbb_room',
288
            [
289
                'meeting_id' => $meetingId,
290
                'participant_id' => $participantId,
291
                'in_at' => api_get_utc_datetime(),
292
                'out_at' => api_get_utc_datetime()
293
            ]
294
        );
295
    }
296
297
    /**
298
     * Tells whether the given meeting exists and is running
299
     * (using course code as name)
300
     * @param string $meetingName Meeting name (usually the course code)
301
     *
302
     * @return bool True if meeting exists, false otherwise
303
     * @assert ('') === false
304
     * @assert ('abcdefghijklmnopqrstuvwxyzabcdefghijklmno') === false
305
     */
306
    public function meetingExists($meetingName)
307
    {
308
        if (empty($meetingName)) {
309
310
            return false;
311
        }
312
313
        $courseId = api_get_course_int_id();
314
        $sessionId = api_get_session_id();
315
        $conditions =  array(
316
            'where' => array(
317
                'c_id = ? AND session_id = ? AND meeting_name = ? AND status = 1 ' =>
318
                    array($courseId, $sessionId, $meetingName)
319
            )
320
        );
321
322 View Code Duplication
        if ($this->hasGroupSupport()) {
323
            $groupId = api_get_group_id();
324
            $conditions =  array(
325
                'where' => array(
326
                    'c_id = ? AND session_id = ? AND meeting_name = ? AND group_id = ? AND status = 1 ' =>
327
                        array($courseId, $sessionId, $meetingName, $groupId)
328
                )
329
            );
330
        }
331
332
        $meetingData = Database::select(
333
            '*',
334
            $this->table,
335
            $conditions,
336
            'first'
337
        );
338
339
340
        if ($this->debug) {
341
            error_log("meeting_exists ".print_r($meetingData, 1));
342
        }
343
344
        if (empty($meetingData)) {
345
346
            return false;
347
        } else {
348
            return true;
349
        }
350
    }
351
352
    /**
353
     * Returns a meeting "join" URL
354
     * @param string The name of the meeting (usually the course code)
355
     * @return mixed The URL to join the meeting, or false on error
356
     * @todo implement moderator pass
357
     * @assert ('') === false
358
     * @assert ('abcdefghijklmnopqrstuvwxyzabcdefghijklmno') === false
359
     */
360
    public function joinMeeting($meetingName, $loop = false)
361
    {
362
        if (empty($meetingName)) {
363
            return false;
364
        }
365
366
        $pass = $this->getUserMeetingPassword();
367
368
        $meetingData = Database::select(
369
            '*',
370
            $this->table,
371
            array('where' => array('meeting_name = ? AND status = 1 ' => $meetingName)),
372
            'first'
373
        );
374
375
        if (empty($meetingData) || !is_array($meetingData)) {
376
            if ($this->debug) {
377
                error_log("meeting does not exist: $meetingName");
378
            }
379
380
            return false;
381
        }
382
383
        $params = array(
384
            'meetingId' => $meetingData['remote_id'],
385
            //  -- REQUIRED - The unique id for the meeting
386
            'password' => $this->getModMeetingPassword()
387
            //  -- REQUIRED - The moderator password for the meeting
388
        );
389
390
        $status = false;
391
        $meetingInfoExists = false;
392
        while ($status === false) {
393
394
            $meetingIsRunningInfo = $this->getMeetingInfo($params);
395 View Code Duplication
            if ($meetingIsRunningInfo === false) {
396
                //checking with the remote_id didn't work, so just in case and
397
                // to provide backwards support, check with the id
398
                $params = array(
399
                    'meetingId' => $meetingData['id'],
400
                    //  -- REQUIRED - The unique id for the meeting
401
                    'password' => $this->getModMeetingPassword()
402
                    //  -- REQUIRED - The moderator password for the meeting
403
                );
404
                $meetingIsRunningInfo = $this->getMeetingInfo($params);
405
            }
406
407
            if ($this->debug) {
408
                error_log(print_r($meetingIsRunningInfo, 1));
409
            }
410
411
            if (strval($meetingIsRunningInfo['returncode']) == 'SUCCESS' &&
412
                isset($meetingIsRunningInfo['meetingName']) &&
413
                !empty($meetingIsRunningInfo['meetingName'])
414
                //strval($meetingIsRunningInfo['running']) == 'true'
415
            ) {
416
                $meetingInfoExists = true;
417
            }
418
419
            if ($this->debug) {
420
                error_log(
421
                    "meeting is running: " . intval($meetingInfoExists)
422
                );
423
            }
424
425
            if ($meetingInfoExists) {
426
                $status = true;
427
            }
428
429
            if ($loop) {
430
                continue;
431
            } else {
432
                break;
433
            }
434
        }
435
436
        if ($meetingInfoExists) {
437
            $joinParams = array(
438
                'meetingId' => $meetingData['remote_id'],	//	-- REQUIRED - A unique id for the meeting
439
                'username' => $this->userCompleteName,	//-- REQUIRED - The name that will display for the user in the meeting
440
                'password' => $pass,			//-- REQUIRED - The attendee or moderator password, depending on what's passed here
441
                //'createTime' => api_get_utc_datetime(),			//-- OPTIONAL - string. Leave blank ('') unless you set this correctly.
442
                'userID' => api_get_user_id(),				//-- OPTIONAL - string
443
                'webVoiceConf' => ''	//	-- OPTIONAL - string
444
            );
445
            $url = $this->api->getJoinMeetingURL($joinParams);
446
            $url = $this->protocol.$url;
447
        } else {
448
            $url = $this->logoutUrl;
449
        }
450
        if ($this->debug) {
451
            error_log("return url :" . $url);
452
        }
453
454
        return $url;
455
    }
456
457
    /**
458
     * Get information about the given meeting
459
     * @param array ...?
460
     * @return mixed Array of information on success, false on error
461
     * @assert (array()) === false
462
     */
463
    public function getMeetingInfo($params)
464
    {
465
        try {
466
            $result = $this->api->getMeetingInfoWithXmlResponseArray($params);
467
            if ($result == null) {
468
                if ($this->debug) {
469
                    error_log("Failed to get any response. Maybe we can't contact the BBB server.");
470
                }
471
            } else {
472
                return $result;
473
            }
474
        } catch (Exception $e) {
475
            if ($this->debug) {
476
                error_log('Caught exception: ', $e->getMessage(), "\n");
477
            }
478
        }
479
480
        return false;
481
    }
482
483
    /**
484
     * Gets all the course meetings saved in the plugin_bbb_meeting table
485
     * @return array Array of current open meeting rooms
486
     */
487
    public function getMeetings($courseId = 0, $sessionId = 0, $groupId = 0, $isAdminReport = false)
488
    {
489
        $em = Database::getManager();
490
        $pass = $this->getUserMeetingPassword();
491
        $conditions = [];
492
493
        if ($courseId || $sessionId || $groupId) {
494
            $conditions =  array(
495
                'where' => array(
496
                    'c_id = ? AND session_id = ? ' => array($courseId, $sessionId),
497
                ),
498
            );
499
500 View Code Duplication
            if ($this->hasGroupSupport()) {
501
                $conditions =  array(
502
                    'where' => array(
503
                        'c_id = ? AND session_id = ? AND group_id = ? ' => array($courseId, $sessionId, $groupId)
504
                    )
505
                );
506
            }
507
        }
508
509
        $meetingList = Database::select(
510
            '*',
511
            $this->table,
512
            $conditions
513
        );
514
        $isGlobal = $this->isGlobalConference();
515
        $newMeetingList = array();
516
        $item = array();
517
        foreach ($meetingList as $meetingDB) {
518
            $meetingBBB = $this->getMeetingInfo(['meetingId' => $meetingDB['remote_id'], 'password' => $pass]);
519 View Code Duplication
            if ($meetingBBB === false) {
520
                //checking with the remote_id didn't work, so just in case and
521
                // to provide backwards support, check with the id
522
                $params = array(
523
                    'meetingId' => $meetingDB['id'],
524
                    //  -- REQUIRED - The unique id for the meeting
525
                    'password' => $pass
526
                    //  -- REQUIRED - The moderator password for the meeting
527
                );
528
                $meetingBBB = $this->getMeetingInfo($params);
529
            }
530
531
            if ($meetingDB['visibility'] == 0 && $this->isConferenceManager() === false) {
532
                continue;
533
            }
534
            $meetingBBB['end_url'] = $this->endUrl($meetingDB);
535
536
            if ((string)$meetingBBB['returncode'] == 'FAILED') {
537
                if ($meetingDB['status'] == 1 && $this->isConferenceManager()) {
538
                    $this->endMeeting($meetingDB['id']);
539
                }
540
            } else {
541
                $meetingBBB['add_to_calendar_url'] = $this->addToCalendarUrl($meetingDB);
542
            }
543
544
            if ($meetingDB['record'] == 1) {
545
                // backwards compatibility (when there was no remote ID)
546
                $mId = $meetingDB['remote_id'];
547
                if (empty($mId)) {
548
                    $mId = $meetingDB['id'];
549
                }
550
                if (empty($mId)) {
551
                    // if the id is still empty (should *never* occur as 'id' is
552
                    // the table's primary key), skip this conference
553
                    continue;
554
                }
555
                $recordingParams = array(
556
                    'meetingId' => $mId, //-- OPTIONAL - comma separate if multiple ids
557
                );
558
559
                //To see the recording list in your BBB server do: bbb-record --list
560
                $records = $this->api->getRecordingsWithXmlResponseArray($recordingParams);
561
562
                if ($isAdminReport) {
563
                    $courseInfo = api_get_course_info_by_id($meetingDB['c_id']);
564
                    $this->forceCIdReq($courseInfo['code'], $meetingDB['session_id'], $meetingDB['group_id']);
565
                }
566
567
                $record = [];
568
                $recordLink = get_lang('NoRecording');
569
570
                if (!empty($records)) {
571
                    if (!isset($records['messageKey']) || $records['messageKey'] != 'noRecordings') {
572
                        //if you get several recordings here and you used a
573
                        // previous version of Chamilo, you might want to
574
                        // only keep the last result for each chamilo conf
575
                        $record = end($records);
576
                        if (!is_array($record) || !isset($record['recordId'])) {
577
                            continue;
578
                        }
579
580
                        $recordLink = Display::url(
581
                            get_lang('ViewRecord')." [~".$record['playbackFormatLength']."']",
582
                            $record['playbackFormatUrl'],
583
                            array('target' => '_blank')
584
                        );
585
586
                        if (!$this->isConferenceManager()) {
587
                            $record = [];
588
                        }
589
                    }
590
                }
591
592
                $actionLinks = $this->getActionLinks($meetingDB, $record, $isGlobal, $isAdminReport);
593
                $item['show_links']  = $recordLink;
594
                $item['action_links'] = implode(PHP_EOL, $actionLinks);
595
            }
596
597
            $item['created_at'] = api_convert_and_format_date($meetingDB['created_at']);
598
            //created_at
599
            $meetingDB['created_at'] = $item['created_at']; //avoid overwrite in array_merge() below
600
601
            $item['publish_url'] = $this->publishUrl($meetingDB);
602
            $item['unpublish_url'] = $this->unPublishUrl($meetingBBB);
0 ignored issues
show
Security Bug introduced by
It seems like $meetingBBB can also be of type false; however, bbb::unPublishUrl() does only seem to accept array, did you maybe forget to handle an error condition?
Loading history...
603
604
            if ($meetingDB['status'] == 1) {
605
                $joinParams = array(
606
                    'meetingId' => $meetingDB['remote_id'],		//-- REQUIRED - A unique id for the meeting
607
                    'username' => $this->userCompleteName,	//-- REQUIRED - The name that will display for the user in the meeting
608
                    'password' => $pass,			//-- REQUIRED - The attendee or moderator password, depending on what's passed here
609
                    'createTime' => '',			//-- OPTIONAL - string. Leave blank ('') unless you set this correctly.
610
                    'userID' => '',			//	-- OPTIONAL - string
611
                    'webVoiceConf' => ''	//	-- OPTIONAL - string
612
                );
613
                $item['go_url'] = $this->protocol.$this->api->getJoinMeetingURL($joinParams);
614
            }
615
            $item = array_merge($item, $meetingDB, $meetingBBB);
616
617
            $item['course'] = $em->find('ChamiloCoreBundle:Course', $item['c_id']);
618
            $item['session'] = $em->find('ChamiloCoreBundle:Session', $item['session_id']);
619
620
            $newMeetingList[] = $item;
621
        }
622
623
        return $newMeetingList;
624
    }
625
626
    /**
627
     * Function disabled
628
     */
629 View Code Duplication
    public function publishMeeting($id)
630
    {
631
        //return BigBlueButtonBN::setPublishRecordings($id, 'true', $this->url, $this->salt);
632
        if (empty($id)) {
633
634
            return false;
635
        }
636
        $id = intval($id);
637
        Database::update($this->table, array('visibility' => 1), array('id = ? ' => $id));
638
639
        return true;
640
    }
641
642
    /**
643
     * Function disabled
644
     */
645 View Code Duplication
    public function unpublishMeeting($id)
646
    {
647
        //return BigBlueButtonBN::setPublishRecordings($id, 'false', $this->url, $this->salt);
648
        if (empty($id)) {
649
650
            return false;
651
        }
652
        $id = intval($id);
653
        Database::update($this->table, array('visibility' => 0), array('id = ?' => $id));
654
655
        return true;
656
    }
657
658
    /**
659
     * Closes a meeting (usually when the user click on the close button from
660
     * the conferences listing.
661
     * @param string The internal ID of the meeting (id field for this meeting)
662
     * @return void
663
     * @assert (0) === false
664
     */
665
    public function endMeeting($id)
666
    {
667
        if (empty($id)) {
668
669
            return false;
670
        }
671
        $meetingData = Database::select('*', $this->table, array('where' => array('id = ?' => array($id))), 'first');
672
        $pass = $this->getUserMeetingPassword();
673
674
        $endParams = array(
675
            'meetingId' => $meetingData['remote_id'],   // REQUIRED - We have to know which meeting to end.
676
            'password' => $pass,        // REQUIRED - Must match moderator pass for meeting.
677
        );
678
        $this->api->endMeetingWithXmlResponseArray($endParams);
679
        Database::update(
680
            $this->table,
681
            array('status' => 0, 'closed_at' => api_get_utc_datetime()),
682
            array('id = ? ' => $id)
683
        );
684
    }
685
686
    /**
687
     * Gets the password for a specific meeting for the current user
688
     * @return string A moderator password if user is teacher, or the course code otherwise
689
     */
690
    public function getUserMeetingPassword()
691
    {
692
        if ($this->isConferenceManager()) {
693
694
            return $this->getModMeetingPassword();
695
        } else {
696
697
            if ($this->isGlobalConference()) {
698
699
                return 'url_'.api_get_current_access_url_id();
700
            }
701
702
            return api_get_course_id();
703
        }
704
    }
705
706
    /**
707
     * Generated a moderator password for the meeting
708
     * @return string A password for the moderation of the videoconference
709
     */
710
    public function getModMeetingPassword()
711
    {
712
        if ($this->isGlobalConference()) {
713
714
            return 'url_'.api_get_current_access_url_id().'_mod';
715
        }
716
717
        return api_get_course_id().'mod';
718
    }
719
720
    /**
721
     * Get users online in the current course room
722
     * @return int The number of users currently connected to the videoconference
723
     * @assert () > -1
724
     */
725
    public function getUsersOnlineInCurrentRoom()
726
    {
727
        $courseId = api_get_course_int_id();
728
        $sessionId = api_get_session_id();
729
730
        $conditions = array(
731
            'where' => array(
732
                'c_id = ? AND session_id = ? AND status = 1 ' => array(
733
                    $courseId,
734
                    $sessionId,
735
                ),
736
            ),
737
        );
738
739 View Code Duplication
        if ($this->hasGroupSupport()) {
740
            $groupId = api_get_group_id();
741
            $conditions = array(
742
                'where' => array(
743
                    'c_id = ? AND session_id = ? AND group_id = ? AND status = 1 ' => array(
744
                        $courseId,
745
                        $sessionId,
746
                        $groupId
747
                    ),
748
                ),
749
            );
750
        }
751
        $meetingData = Database::select(
752
            '*',
753
            $this->table,
754
            $conditions,
755
            'first'
756
        );
757
758
        if (empty($meetingData)) {
759
            return 0;
760
        }
761
        $pass = $this->getModMeetingPassword();
762
        $info = $this->getMeetingInfo(array('meetingId' => $meetingData['remote_id'], 'password' => $pass));
763 View Code Duplication
        if ($info === false) {
764
            //checking with the remote_id didn't work, so just in case and
765
            // to provide backwards support, check with the id
766
            $params = array(
767
                'meetingId' => $meetingData['id'],
768
                //  -- REQUIRED - The unique id for the meeting
769
                'password' => $pass
770
                //  -- REQUIRED - The moderator password for the meeting
771
            );
772
            $info = $this->getMeetingInfo($params);
773
        }
774
775
        if (!empty($info) && isset($info['participantCount'])) {
776
            return $info['participantCount'];
777
778
        }
779
        return 0;
780
    }
781
782
    /**
783
     * Deletes a previous recording of a meeting
784
     * @param int integral ID of the recording
785
     * @return array ?
786
     * @assert () === false
787
     * @todo Also delete links and agenda items created from this recording
788
     */
789
    public function deleteRecord($id)
790
    {
791
        if (empty($id)) {
792
            return false;
793
        }
794
795
        $meetingData = Database::select(
796
            '*',
797
            $this->table,
798
            array('where' => array('id = ?' => array($id))),
799
            'first'
800
        );
801
802
        $recordingParams = array(
803
            /*
804
             * NOTE: Set the recordId below to a valid id after you have
805
             * created a recorded meeting, and received a real recordID
806
             * back from your BBB server using the
807
             * getRecordingsWithXmlResponseArray method.
808
             */
809
810
            // REQUIRED - We have to know which recording:
811
            'recordId' => $meetingData['remote_id'],
812
        );
813
814
        $result = $this->api->deleteRecordingsWithXmlResponseArray($recordingParams);
815
816
        if (!empty($result) && isset($result['deleted']) && $result['deleted'] == 'true') {
817
            Database::delete(
818
                $this->table,
819
                array('id = ?' => array($id))
820
            );
821
        }
822
823
        return $result;
824
    }
825
826
    /**
827
     * Creates a link in the links tool from the given videoconference recording
828
     * @param int ID of the item in the plugin_bbb_meeting table
829
     * @param string Hash identifying the recording, as provided by the API
830
     * @return mixed ID of the newly created link, or false on error
831
     * @assert (null, null) === false
832
     * @assert (1, null) === false
833
     * @assert (null, 'abcdefabcdefabcdefabcdef') === false
834
     */
835
    public function copyRecordToLinkTool($id)
836
    {
837
        if (empty($id)) {
838
            return false;
839
        }
840
        //$records =  BigBlueButtonBN::getRecordingsUrl($id);
841
        $meetingData = Database::select('*', $this->table, array('where' => array('id = ?' => array($id))), 'first');
842
843
        $records = $this->api->getRecordingsWithXmlResponseArray(array('meetingId' => $meetingData['remote_id']));
844
845
        if (!empty($records)) {
846
            if (isset($records['message']) && !empty($records['message'])) {
847
                if ($records['messageKey'] == 'noRecordings') {
848
                    $recordArray[] = get_lang('NoRecording');
849
                } else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
850
                    //$recordArray[] = $records['message'];
851
                }
852
                return false;
853
            } else {
854
                $record = $records[0];
855
                if (is_array($record) && isset($record['recordId'])) {
856
                    $url = $record['playbackFormatUrl'];
857
                    $link = new Link();
0 ignored issues
show
Bug introduced by
The call to Link::__construct() misses some required arguments starting with $id.
Loading history...
858
                    $params['url'] = $url;
859
                    $params['title'] = $meetingData['meeting_name'];
860
                    $id = $link->save($params);
861
                    return $id;
862
                }
863
            }
864
        }
865
866
        return false;
867
    }
868
869
    /**
870
     * Checks if the video conference server is running.
871
     * Function currently disabled (always returns 1)
872
     * @return bool True if server is running, false otherwise
873
     * @assert () === false
874
     */
875
    public function isServerRunning()
876
    {
877
        return true;
878
        //return BigBlueButtonBN::isServerRunning($this->protocol.$this->url);
879
    }
880
881
    /**
882
     * Get active session in the all platform
883
     */
884
    public function getActiveSessionsCount()
885
    {
886
        $meetingList = Database::select(
887
            'count(id) as count',
888
            $this->table,
889
            array('where' => array('status = ?' => array(1))),
890
            'first'
891
        );
892
893
        return $meetingList['count'];
894
    }
895
896
    /**
897
     * @param string $url
898
     */
899
    public function redirectToBBB($url)
900
    {
901
        if (file_exists(__DIR__ . '/../config.vm.php')) {
902
            // Using VM
903
            echo Display::url(get_lang('ClickToContinue'), $url);
904
            exit;
905
        } else {
906
            // Classic
907
            header("Location: $url");
908
            exit;
909
        }
910
    }
911
912
    /**
913
     * @return string
914
     */
915
    public function getUrlParams()
916
    {
917
        $courseInfo = api_get_course_info();
918
919
        if (empty($this->courseCode)) {
920
921
            if ($this->isGlobalConference()) {
922
                return 'global=1';
923
            }
924
925
            return '';
926
        }
927
928
        return http_build_query([
929
            'cidReq' => $this->courseCode,
930
            'id_session' => $this->sessionId,
931
            'gidReq' => $this->groupId
932
        ]);
933
    }
934
935
    /**
936
     * @return string
937
     */
938
    public function getCurrentVideoConferenceName()
939
    {
940
        if ($this->isGlobalConference()) {
941
            return 'url_'.api_get_current_access_url_id();
942
        }
943
944
        if ($this->hasGroupSupport()) {
945
946
            return api_get_course_id().'-'.api_get_session_id().'-'.api_get_group_id();
947
        }
948
949
        return api_get_course_id().'-'.api_get_session_id();
950
    }
951
952
    /**
953
     * @return string
954
     */
955
    public function getConferenceUrl()
956
    {
957
        return api_get_path(WEB_PLUGIN_PATH).'bbb/start.php?launch=1&'.$this->getUrlParams();
958
    }
959
960
    /**
961
     * @return string
962
     */
963
    public function getListingUrl()
964
    {
965
        return api_get_path(WEB_PLUGIN_PATH).'bbb/listing.php?'.$this->getUrlParams();
966
    }
967
968
    /**
969
     * @param array $meeting
970
     * @return string
971
     */
972
    public function endUrl($meeting)
973
    {
974
        return api_get_path(WEB_PLUGIN_PATH).'bbb/listing.php?'.$this->getUrlParams().'&action=end&id='.$meeting['id'];
975
    }
976
977
    /**
978
     * @param array $meeting
979
     * @param array $record
980
     * @return string
981
     */
982
    public function addToCalendarUrl($meeting, $record = [])
983
    {
984
        $url = isset($record['playbackFormatUrl']) ? $record['playbackFormatUrl'] : '';
985
986
        return api_get_path(WEB_PLUGIN_PATH).'bbb/listing.php?'.$this->getUrlParams().'&action=add_to_calendar&id='.$meeting['id'].'&start='.api_strtotime($meeting['created_at']).'&url='.$url;
987
    }
988
989
    /**
990
     * @param array $meeting
991
     * @return string
992
     */
993
    public function publishUrl($meeting)
994
    {
995
        return api_get_path(WEB_PLUGIN_PATH).'bbb/listing.php?'.$this->getUrlParams().'&action=publish&id='.$meeting['id'];
996
    }
997
998
    /**
999
     * @param array $meeting
1000
     * @return string
1001
     */
1002
    public function unPublishUrl($meeting)
1003
    {
1004
        if (!isset($meeting['id'])) {
1005
            return null;
1006
        }
1007
1008
        return api_get_path(WEB_PLUGIN_PATH).'bbb/listing.php?'.$this->getUrlParams().'&action=unpublish&id='.$meeting['id'];
1009
    }
1010
1011
    /**
1012
     * @param array $meeting
1013
     * @return string
1014
     */
1015
    public function deleteRecordUrl($meeting)
1016
    {
1017
        return api_get_path(WEB_PLUGIN_PATH).'bbb/listing.php?'.$this->getUrlParams().'&action=delete_record&id='.$meeting['id'];
1018
    }
1019
1020
    /**
1021
     * @param array $meeting
1022
     * @return string
1023
     */
1024
    public function copyToRecordToLinkTool($meeting)
1025
    {
1026
        return api_get_path(WEB_PLUGIN_PATH).'bbb/listing.php?'.$this->getUrlParams().'&action=copy_record_to_link_tool&id='.$meeting['id'];
1027
    }
1028
1029
    /**
1030
     * Get the meeting info from DB by its name
1031
     * @param string $name
1032
     * @return array
1033
     */
1034
    public function findMeetingByName($name)
1035
    {
1036
        $meetingData = Database::select(
1037
            '*',
1038
            'plugin_bbb_meeting',
1039
            array('where' => array('meeting_name = ? AND status = 1 ' => $name)),
1040
            'first'
1041
        );
1042
1043
        return $meetingData;
1044
    }
1045
1046
    /**
1047
     * @param int $meetingId
1048
     * @return array
1049
     */
1050
    public function findMeetingParticipants($meetingId)
1051
    {
1052
        $em = Database::getManager();
1053
        $meetingData = Database::select(
1054
            '*',
1055
            'plugin_bbb_room',
1056
            array('where' => array('meeting_id = ?' => intval($meetingId)))
1057
        );
1058
1059
        $return = [];
1060
1061
        foreach ($meetingData as $participantInfo) {
1062
            $return[] = [
1063
                'id' => $participantInfo['id'],
1064
                'meeting_id' => $participantInfo['meeting_id'],
1065
                'participant' => $em->find('ChamiloUserBundle:User', $participantInfo['participant_id']),
1066
                'in_at' => $participantInfo['in_at'],
1067
                'out_at' => $participantInfo['out_at']
1068
            ];
1069
        }
1070
1071
        return $return;
1072
    }
1073
1074
    private function getActionLinks($meetingInfo, $recordInfo, $isGlobal = false, $isAdminReport = false)
1075
    {
1076
        $isVisible = $meetingInfo['visibility'] != 0;
1077
        $linkVisibility = $isVisible
1078
            ? Display::url(
1079
                Display::return_icon('visible.png', get_lang('MakeInvisible')),
1080
                $this->unPublishUrl($meetingInfo)
1081
            )
1082
            : Display::url(
1083
                Display::return_icon('invisible.png', get_lang('MakeVisible')),
1084
                $this->publishUrl($meetingInfo)
1085
            );
1086
1087
        $links = [];
1088
1089
        if (empty($recordInfo)) {
1090
            $links[] = $linkVisibility;
1091
1092
            return $links;
1093
        }
1094
1095
        if (!$isGlobal) {
1096
            $links[] = Display::url(
1097
                Display::return_icon('link.gif', get_lang('CopyToLinkTool')),
1098
                $this->copyToRecordToLinkTool($meetingInfo)
1099
            );
1100
            $links[] = Display::url(
1101
                Display::return_icon('agenda.png', get_lang('AddToCalendar')),
1102
                $this->addToCalendarUrl($meetingInfo, $recordInfo)
1103
            );
1104
        }
1105
1106
        $links[] = Display::url(
1107
            Display::return_icon('save.png', get_lang('DownloadFile')),
1108
            $recordInfo['playbackFormatUrl'] . '/capture.m4v',
1109
            ['target' => '_blank']
1110
        );
1111
1112
        if (!$isAdminReport) {
1113
            $links[] = Display::url(
1114
                Display::return_icon('delete.png', get_lang('Delete')),
1115
                $this->deleteRecordUrl($meetingInfo)
1116
            );
1117
        }
1118
1119
        $links[] = $linkVisibility;
1120
1121
        return $links;
1122
    }
1123
}
1124