Completed
Push — 1.10.x ( 7ba96a...85aec4 )
by Angel Fernando Quiroz
109:18 queued 69:54
created

bbb::copyToRecordToLinkTool()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
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
556
                $record = [];
557
                $recordLink = get_lang('NoRecording');
558
559
                if (empty($meetingDB['video_url'])) {
560
                    $recordingParams = ['meetingId' => $mId];
561
                    $records = $this->api->getRecordingsWithXmlResponseArray($recordingParams);
562
563
                    if (!empty($records)) {
564
                        if (!isset($records['messageKey']) || $records['messageKey'] != 'noRecordings') {
565
                            $record = end($records);
566
567
                            if (!is_array($record) || !isset($record['recordId'])) {
568
                                continue;
569
                            }
570
571
                            $this->updateMeetingVideoUrl($meetingDB['id'], $record['playbackFormatUrl']);
572
573
                            if (!$this->isConferenceManager()) {
574
                                $record = [];
575
                            }
576
                        }
577
                    }
578
                } else {
579
                    $record['playbackFormatUrl'] = $meetingDB['video_url'];
580
                }
581
582
                $recordLink = Display::url(
583
                    get_lang('ViewRecord'),
584
                    $record['playbackFormatUrl'],
585
                    ['target' => '_blank']
586
                );
587
588
                if ($isAdminReport) {
589
                    $courseInfo = api_get_course_info_by_id($meetingDB['c_id']);
590
                    $this->forceCIdReq($courseInfo['code'], $meetingDB['session_id'], $meetingDB['group_id']);
591
                }
592
593
                $actionLinks = $this->getActionLinks($meetingDB, $record, $isGlobal, $isAdminReport);
594
                $item['show_links']  = $recordLink;
595
                $item['action_links'] = implode(PHP_EOL, $actionLinks);
596
            }
597
598
            $item['created_at'] = api_convert_and_format_date($meetingDB['created_at']);
599
            //created_at
600
            $meetingDB['created_at'] = $item['created_at']; //avoid overwrite in array_merge() below
601
602
            $item['publish_url'] = $this->publishUrl($meetingDB);
603
            $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...
604
605
            if ($meetingDB['status'] == 1) {
606
                $joinParams = array(
607
                    'meetingId' => $meetingDB['remote_id'],		//-- REQUIRED - A unique id for the meeting
608
                    'username' => $this->userCompleteName,	//-- REQUIRED - The name that will display for the user in the meeting
609
                    'password' => $pass,			//-- REQUIRED - The attendee or moderator password, depending on what's passed here
610
                    'createTime' => '',			//-- OPTIONAL - string. Leave blank ('') unless you set this correctly.
611
                    'userID' => '',			//	-- OPTIONAL - string
612
                    'webVoiceConf' => ''	//	-- OPTIONAL - string
613
                );
614
                $item['go_url'] = $this->protocol.$this->api->getJoinMeetingURL($joinParams);
615
            }
616
            $item = array_merge($item, $meetingDB, $meetingBBB);
617
618
            $item['course'] = $em->find('ChamiloCoreBundle:Course', $item['c_id']);
619
            $item['session'] = $em->find('ChamiloCoreBundle:Session', $item['session_id']);
620
621
            $newMeetingList[] = $item;
622
        }
623
624
        return $newMeetingList;
625
    }
626
627
    /**
628
     * Function disabled
629
     */
630 View Code Duplication
    public function publishMeeting($id)
631
    {
632
        //return BigBlueButtonBN::setPublishRecordings($id, 'true', $this->url, $this->salt);
633
        if (empty($id)) {
634
635
            return false;
636
        }
637
        $id = intval($id);
638
        Database::update($this->table, array('visibility' => 1), array('id = ? ' => $id));
639
640
        return true;
641
    }
642
643
    /**
644
     * Function disabled
645
     */
646 View Code Duplication
    public function unpublishMeeting($id)
647
    {
648
        //return BigBlueButtonBN::setPublishRecordings($id, 'false', $this->url, $this->salt);
649
        if (empty($id)) {
650
651
            return false;
652
        }
653
        $id = intval($id);
654
        Database::update($this->table, array('visibility' => 0), array('id = ?' => $id));
655
656
        return true;
657
    }
658
659
    /**
660
     * Closes a meeting (usually when the user click on the close button from
661
     * the conferences listing.
662
     * @param string The internal ID of the meeting (id field for this meeting)
663
     * @return void
664
     * @assert (0) === false
665
     */
666
    public function endMeeting($id)
667
    {
668
        if (empty($id)) {
669
670
            return false;
671
        }
672
        $meetingData = Database::select('*', $this->table, array('where' => array('id = ?' => array($id))), 'first');
673
        $pass = $this->getUserMeetingPassword();
674
675
        $endParams = array(
676
            'meetingId' => $meetingData['remote_id'],   // REQUIRED - We have to know which meeting to end.
677
            'password' => $pass,        // REQUIRED - Must match moderator pass for meeting.
678
        );
679
        $this->api->endMeetingWithXmlResponseArray($endParams);
680
        Database::update(
681
            $this->table,
682
            array('status' => 0, 'closed_at' => api_get_utc_datetime()),
683
            array('id = ? ' => $id)
684
        );
685
    }
686
687
    /**
688
     * Gets the password for a specific meeting for the current user
689
     * @return string A moderator password if user is teacher, or the course code otherwise
690
     */
691
    public function getUserMeetingPassword()
692
    {
693
        if ($this->isConferenceManager()) {
694
695
            return $this->getModMeetingPassword();
696
        } else {
697
698
            if ($this->isGlobalConference()) {
699
700
                return 'url_'.api_get_current_access_url_id();
701
            }
702
703
            return api_get_course_id();
704
        }
705
    }
706
707
    /**
708
     * Generated a moderator password for the meeting
709
     * @return string A password for the moderation of the videoconference
710
     */
711
    public function getModMeetingPassword()
712
    {
713
        if ($this->isGlobalConference()) {
714
715
            return 'url_'.api_get_current_access_url_id().'_mod';
716
        }
717
718
        return api_get_course_id().'mod';
719
    }
720
721
    /**
722
     * Get users online in the current course room
723
     * @return int The number of users currently connected to the videoconference
724
     * @assert () > -1
725
     */
726
    public function getUsersOnlineInCurrentRoom()
727
    {
728
        $courseId = api_get_course_int_id();
729
        $sessionId = api_get_session_id();
730
731
        $conditions = array(
732
            'where' => array(
733
                'c_id = ? AND session_id = ? AND status = 1 ' => array(
734
                    $courseId,
735
                    $sessionId,
736
                ),
737
            ),
738
        );
739
740 View Code Duplication
        if ($this->hasGroupSupport()) {
741
            $groupId = api_get_group_id();
742
            $conditions = array(
743
                'where' => array(
744
                    'c_id = ? AND session_id = ? AND group_id = ? AND status = 1 ' => array(
745
                        $courseId,
746
                        $sessionId,
747
                        $groupId
748
                    ),
749
                ),
750
            );
751
        }
752
        $meetingData = Database::select(
753
            '*',
754
            $this->table,
755
            $conditions,
756
            'first'
757
        );
758
759
        if (empty($meetingData)) {
760
            return 0;
761
        }
762
        $pass = $this->getModMeetingPassword();
763
        $info = $this->getMeetingInfo(array('meetingId' => $meetingData['remote_id'], 'password' => $pass));
764 View Code Duplication
        if ($info === false) {
765
            //checking with the remote_id didn't work, so just in case and
766
            // to provide backwards support, check with the id
767
            $params = array(
768
                'meetingId' => $meetingData['id'],
769
                //  -- REQUIRED - The unique id for the meeting
770
                'password' => $pass
771
                //  -- REQUIRED - The moderator password for the meeting
772
            );
773
            $info = $this->getMeetingInfo($params);
774
        }
775
776
        if (!empty($info) && isset($info['participantCount'])) {
777
            return $info['participantCount'];
778
779
        }
780
        return 0;
781
    }
782
783
    /**
784
     * Deletes a previous recording of a meeting
785
     * @param int integral ID of the recording
786
     * @return array ?
787
     * @assert () === false
788
     * @todo Also delete links and agenda items created from this recording
789
     */
790
    public function deleteRecord($id)
791
    {
792
        if (empty($id)) {
793
            return false;
794
        }
795
796
        $meetingData = Database::select(
797
            '*',
798
            $this->table,
799
            array('where' => array('id = ?' => array($id))),
800
            'first'
801
        );
802
803
        $recordingParams = array(
804
            /*
805
             * NOTE: Set the recordId below to a valid id after you have
806
             * created a recorded meeting, and received a real recordID
807
             * back from your BBB server using the
808
             * getRecordingsWithXmlResponseArray method.
809
             */
810
811
            // REQUIRED - We have to know which recording:
812
            'recordId' => $meetingData['remote_id'],
813
        );
814
815
        $result = $this->api->deleteRecordingsWithXmlResponseArray($recordingParams);
816
817
        if (!empty($result) && isset($result['deleted']) && $result['deleted'] == 'true') {
818
            Database::delete(
819
                $this->table,
820
                array('id = ?' => array($id))
821
            );
822
        }
823
824
        return $result;
825
    }
826
827
    /**
828
     * Creates a link in the links tool from the given videoconference recording
829
     * @param int ID of the item in the plugin_bbb_meeting table
830
     * @param string Hash identifying the recording, as provided by the API
831
     * @return mixed ID of the newly created link, or false on error
832
     * @assert (null, null) === false
833
     * @assert (1, null) === false
834
     * @assert (null, 'abcdefabcdefabcdefabcdef') === false
835
     */
836
    public function copyRecordToLinkTool($id)
837
    {
838
        if (empty($id)) {
839
            return false;
840
        }
841
        //$records =  BigBlueButtonBN::getRecordingsUrl($id);
842
        $meetingData = Database::select('*', $this->table, array('where' => array('id = ?' => array($id))), 'first');
843
844
        $records = $this->api->getRecordingsWithXmlResponseArray(array('meetingId' => $meetingData['remote_id']));
845
846
        if (!empty($records)) {
847
            if (isset($records['message']) && !empty($records['message'])) {
848
                if ($records['messageKey'] == 'noRecordings') {
849
                    $recordArray[] = get_lang('NoRecording');
850
                } 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...
851
                    //$recordArray[] = $records['message'];
852
                }
853
                return false;
854
            } else {
855
                $record = $records[0];
856
                if (is_array($record) && isset($record['recordId'])) {
857
                    $url = $record['playbackFormatUrl'];
858
                    $link = new Link();
0 ignored issues
show
Bug introduced by
The call to Link::__construct() misses some required arguments starting with $id.
Loading history...
859
                    $params['url'] = $url;
860
                    $params['title'] = $meetingData['meeting_name'];
861
                    $id = $link->save($params);
862
                    return $id;
863
                }
864
            }
865
        }
866
867
        return false;
868
    }
869
870
    /**
871
     * Checks if the video conference server is running.
872
     * Function currently disabled (always returns 1)
873
     * @return bool True if server is running, false otherwise
874
     * @assert () === false
875
     */
876
    public function isServerRunning()
877
    {
878
        return true;
879
        //return BigBlueButtonBN::isServerRunning($this->protocol.$this->url);
880
    }
881
882
    /**
883
     * Get active session in the all platform
884
     */
885
    public function getActiveSessionsCount()
886
    {
887
        $meetingList = Database::select(
888
            'count(id) as count',
889
            $this->table,
890
            array('where' => array('status = ?' => array(1))),
891
            'first'
892
        );
893
894
        return $meetingList['count'];
895
    }
896
897
    /**
898
     * @param string $url
899
     */
900
    public function redirectToBBB($url)
901
    {
902
        if (file_exists(__DIR__ . '/../config.vm.php')) {
903
            // Using VM
904
            echo Display::url(get_lang('ClickToContinue'), $url);
905
            exit;
906
        } else {
907
            // Classic
908
            header("Location: $url");
909
            exit;
910
        }
911
    }
912
913
    /**
914
     * @return string
915
     */
916
    public function getUrlParams()
917
    {
918
        $courseInfo = api_get_course_info();
919
920
        if (empty($this->courseCode)) {
921
922
            if ($this->isGlobalConference()) {
923
                return 'global=1';
924
            }
925
926
            return '';
927
        }
928
929
        return http_build_query([
930
            'cidReq' => $this->courseCode,
931
            'id_session' => $this->sessionId,
932
            'gidReq' => $this->groupId
933
        ]);
934
    }
935
936
    /**
937
     * @return string
938
     */
939
    public function getCurrentVideoConferenceName()
940
    {
941
        if ($this->isGlobalConference()) {
942
            return 'url_'.api_get_current_access_url_id();
943
        }
944
945
        if ($this->hasGroupSupport()) {
946
947
            return api_get_course_id().'-'.api_get_session_id().'-'.api_get_group_id();
948
        }
949
950
        return api_get_course_id().'-'.api_get_session_id();
951
    }
952
953
    /**
954
     * @return string
955
     */
956
    public function getConferenceUrl()
957
    {
958
        return api_get_path(WEB_PLUGIN_PATH).'bbb/start.php?launch=1&'.$this->getUrlParams();
959
    }
960
961
    /**
962
     * @return string
963
     */
964
    public function getListingUrl()
965
    {
966
        return api_get_path(WEB_PLUGIN_PATH).'bbb/listing.php?'.$this->getUrlParams();
967
    }
968
969
    /**
970
     * @param array $meeting
971
     * @return string
972
     */
973
    public function endUrl($meeting)
974
    {
975
        return api_get_path(WEB_PLUGIN_PATH).'bbb/listing.php?'.$this->getUrlParams().'&action=end&id='.$meeting['id'];
976
    }
977
978
    /**
979
     * @param array $meeting
980
     * @param array $record
981
     * @return string
982
     */
983
    public function addToCalendarUrl($meeting, $record = [])
984
    {
985
        $url = isset($record['playbackFormatUrl']) ? $record['playbackFormatUrl'] : '';
986
987
        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;
988
    }
989
990
    /**
991
     * @param array $meeting
992
     * @return string
993
     */
994
    public function publishUrl($meeting)
995
    {
996
        return api_get_path(WEB_PLUGIN_PATH).'bbb/listing.php?'.$this->getUrlParams().'&action=publish&id='.$meeting['id'];
997
    }
998
999
    /**
1000
     * @param array $meeting
1001
     * @return string
1002
     */
1003
    public function unPublishUrl($meeting)
1004
    {
1005
        if (!isset($meeting['id'])) {
1006
            return null;
1007
        }
1008
1009
        return api_get_path(WEB_PLUGIN_PATH).'bbb/listing.php?'.$this->getUrlParams().'&action=unpublish&id='.$meeting['id'];
1010
    }
1011
1012
    /**
1013
     * @param array $meeting
1014
     * @return string
1015
     */
1016
    public function deleteRecordUrl($meeting)
1017
    {
1018
        return api_get_path(WEB_PLUGIN_PATH).'bbb/listing.php?'.$this->getUrlParams().'&action=delete_record&id='.$meeting['id'];
1019
    }
1020
1021
    /**
1022
     * @param array $meeting
1023
     * @return string
1024
     */
1025
    public function copyToRecordToLinkTool($meeting)
1026
    {
1027
        return api_get_path(WEB_PLUGIN_PATH).'bbb/listing.php?'.$this->getUrlParams().'&action=copy_record_to_link_tool&id='.$meeting['id'];
1028
    }
1029
1030
    /**
1031
     * Get the meeting info from DB by its name
1032
     * @param string $name
1033
     * @return array
1034
     */
1035
    public function findMeetingByName($name)
1036
    {
1037
        $meetingData = Database::select(
1038
            '*',
1039
            'plugin_bbb_meeting',
1040
            array('where' => array('meeting_name = ? AND status = 1 ' => $name)),
1041
            'first'
1042
        );
1043
1044
        return $meetingData;
1045
    }
1046
1047
    /**
1048
     * @param int $meetingId
1049
     * @return array
1050
     */
1051
    public function findMeetingParticipants($meetingId)
1052
    {
1053
        $em = Database::getManager();
1054
        $meetingData = Database::select(
1055
            '*',
1056
            'plugin_bbb_room',
1057
            array('where' => array('meeting_id = ?' => intval($meetingId)))
1058
        );
1059
1060
        $return = [];
1061
1062
        foreach ($meetingData as $participantInfo) {
1063
            $return[] = [
1064
                'id' => $participantInfo['id'],
1065
                'meeting_id' => $participantInfo['meeting_id'],
1066
                'participant' => $em->find('ChamiloUserBundle:User', $participantInfo['participant_id']),
1067
                'in_at' => $participantInfo['in_at'],
1068
                'out_at' => $participantInfo['out_at']
1069
            ];
1070
        }
1071
1072
        return $return;
1073
    }
1074
1075
    /**
1076
     * @param array $meetingInfo
1077
     * @param array $recordInfo
1078
     * @param bool $isGlobal
1079
     * @param bool $isAdminReport
1080
     * @return array
1081
     */
1082
    private function getActionLinks($meetingInfo, $recordInfo, $isGlobal = false, $isAdminReport = false)
1083
    {
1084
        $isVisible = $meetingInfo['visibility'] != 0;
1085
        $linkVisibility = $isVisible
1086
            ? Display::url(
1087
                Display::return_icon('visible.png', get_lang('MakeInvisible')),
1088
                $this->unPublishUrl($meetingInfo)
1089
            )
1090
            : Display::url(
1091
                Display::return_icon('invisible.png', get_lang('MakeVisible')),
1092
                $this->publishUrl($meetingInfo)
1093
            );
1094
1095
        $links = [];
1096
1097
        if (empty($recordInfo)) {
1098
            $links[] = $linkVisibility;
1099
1100
            return $links;
1101
        }
1102
1103 View Code Duplication
        if (!$isGlobal) {
1104
            $links[] = Display::url(
1105
                Display::return_icon('link.gif', get_lang('CopyToLinkTool')),
1106
                $this->copyToRecordToLinkTool($meetingInfo)
1107
            );
1108
            $links[] = Display::url(
1109
                Display::return_icon('agenda.png', get_lang('AddToCalendar')),
1110
                $this->addToCalendarUrl($meetingInfo, $recordInfo)
1111
            );
1112
        }
1113
1114
        if ($meetingInfo['has_video_m4v']) {
1115
            $links[] = Display::url(
1116
                Display::return_icon('save.png', get_lang('DownloadFile')),
1117
                $recordInfo['playbackFormatUrl'] . '/capture.m4v',
1118
                ['target' => '_blank']
1119
            );
1120
        } else {
1121
            $links[] = Display::url(
1122
                Display::return_icon('save.png', get_lang('DownloadFile')),
1123
                '#',
1124
                [
1125
                    'id' => "btn-check-meeting-video-{$meetingInfo['id']}",
1126
                    'class' => 'check-meeting-video',
1127
                    'data-id' => $meetingInfo['id']
1128
                ]
1129
            );
1130
        }
1131
1132 View Code Duplication
        if (!$isAdminReport) {
1133
            $links[] = Display::url(
1134
                Display::return_icon('delete.png', get_lang('Delete')),
1135
                $this->deleteRecordUrl($meetingInfo)
1136
            );
1137
            $links[] = $linkVisibility;
1138
        } else {
1139
            $links[] = Display::url(
1140
                Display::return_icon('course_home.png', get_lang('GoToCourse')),
1141
                $this->getListingUrl()
1142
            );
1143
        }
1144
1145
        return $links;
1146
    }
1147
1148
    /**
1149
     * @param int $meetingId
1150
     * @param string $videoUrl
1151
     * @return bool|int
1152
     */
1153
    public function updateMeetingVideoUrl($meetingId, $videoUrl)
1154
    {
1155
        return Database::update(
1156
            'plugin_bbb_meeting',
1157
            ['video_url' => $videoUrl],
1158
            ['id = ?' => intval($meetingId)]
1159
        );
1160
    }
1161
1162
    /**
1163
     * Check if the meeting has a capture.m4v video file. If exists then the has_video_m4v field is updated
1164
     * @param int $meetingId
1165
     * @return bool
1166
     */
1167
    public function checkDirectMeetingVideoUrl($meetingId)
1168
    {
1169
        $meetingInfo = Database::select(
1170
            '*',
1171
            'plugin_bbb_meeting',
1172
            [
1173
                'where' => ['id = ?' => intval($meetingId)]
1174
            ],
1175
            'first'
1176
        );
1177
1178
        if (!isset($meetingInfo['video_url'])) {
1179
            return false;
1180
        }
1181
1182
        $hasCapture = SocialManager::verifyUrl($meetingInfo['video_url'] . '/capture.m4v');
1183
1184
        if ($hasCapture) {
1185
            return Database::update(
1186
                'plugin_bbb_meeting',
1187
                ['has_video_m4v' => true],
1188
                ['id = ?' => intval($meetingId)]
1189
            );
1190
        }
1191
1192
        return $hasCapture;
1193
    }
1194
}
1195