Completed
Pull Request — master (#257)
by
unknown
01:56
created

locallib.php ➔ bigbluebuttonbn_get_join_url()   B

Complexity

Conditions 7
Paths 32

Size

Total Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
nc 32
nop 8
dl 0
loc 35
rs 8.4266
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
17
/**
18
 * Internal library of functions for module BigBlueButtonBN.
19
 *
20
 * @package   mod_bigbluebuttonbn
21
 * @copyright 2010 onwards, Blindside Networks Inc
22
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 * @author    Jesus Federico  (jesus [at] blindsidenetworks [dt] com)
24
 * @author    Fred Dixon  (ffdixon [at] blindsidenetworks [dt] com)
25
 */
26
27
use mod_bigbluebuttonbn\locallib;
28
use mod_bigbluebuttonbn\plugin;
29
use mod_bigbluebuttonbn\task;
30
31
defined('MOODLE_INTERNAL') || die;
32
33
global $CFG;
34
35
require_once(__DIR__ . '/lib.php');
36
37
/** @var BIGBLUEBUTTONBN_UPDATE_CACHE boolean set to true indicates that cache has to be updated */
38
const BIGBLUEBUTTONBN_UPDATE_CACHE = true;
39
/** @var BIGBLUEBUTTONBN_TYPE_ALL integer set to 0 defines an instance type that inclueds room and recordings */
40
const BIGBLUEBUTTONBN_TYPE_ALL = 0;
41
/** @var BIGBLUEBUTTONBN_TYPE_ROOM_ONLY integer set to 1 defines an instance type that inclueds only room */
42
const BIGBLUEBUTTONBN_TYPE_ROOM_ONLY = 1;
43
/** @var BIGBLUEBUTTONBN_TYPE_RECORDING_ONLY integer set to 2 defines an instance type that inclueds only recordings */
44
const BIGBLUEBUTTONBN_TYPE_RECORDING_ONLY = 2;
45
/** @var BIGBLUEBUTTONBN_ROLE_VIEWER string defines the bigbluebutton viewer role */
46
const BIGBLUEBUTTONBN_ROLE_VIEWER = 'viewer';
47
/** @var BIGBLUEBUTTONBN_ROLE_MODERATOR string defines the bigbluebutton moderator role */
48
const BIGBLUEBUTTONBN_ROLE_MODERATOR = 'moderator';
49
/** @var BIGBLUEBUTTON_EVENT_ACTIVITY_VIEWED string defines the bigbluebuttonbn activity_viewed event */
50
const BIGBLUEBUTTON_EVENT_ACTIVITY_VIEWED = 'activity_viewed';
51
/** @var BIGBLUEBUTTON_EVENT_ACTIVITY_MANAGEMENT_VIEWED string defines the bigbluebuttonbn activity_management_viewed event */
52
const BIGBLUEBUTTON_EVENT_ACTIVITY_MANAGEMENT_VIEWED = 'activity_management_viewed';
53
/** @var BIGBLUEBUTTON_EVENT_LIVE_SESSION string defines the bigbluebuttonbn live_session event */
54
const BIGBLUEBUTTON_EVENT_LIVE_SESSION = 'live_session';
55
/** @var BIGBLUEBUTTON_EVENT_MEETING_CREATED string defines the bigbluebuttonbn meeting_created event */
56
const BIGBLUEBUTTON_EVENT_MEETING_CREATED = 'meeting_created';
57
/** @var BIGBLUEBUTTON_EVENT_MEETING_ENDED string defines the bigbluebuttonbn meeting_ended event */
58
const BIGBLUEBUTTON_EVENT_MEETING_ENDED = 'meeting_ended';
59
/** @var BIGBLUEBUTTON_EVENT_MEETING_JOINED string defines the bigbluebuttonbn meeting_joined event */
60
const BIGBLUEBUTTON_EVENT_MEETING_JOINED = 'meeting_joined';
61
/** @var BIGBLUEBUTTON_EVENT_MEETING_LEFT string defines the bigbluebuttonbn meeting_left event */
62
const BIGBLUEBUTTON_EVENT_MEETING_LEFT = 'meeting_left';
63
/** @var BIGBLUEBUTTON_EVENT_RECORDING_DELETED string defines the bigbluebuttonbn recording_deleted event */
64
const BIGBLUEBUTTON_EVENT_RECORDING_DELETED = 'recording_deleted';
65
/** @var BIGBLUEBUTTON_EVENT_RECORDING_IMPORTED string defines the bigbluebuttonbn recording_imported event */
66
const BIGBLUEBUTTON_EVENT_RECORDING_IMPORTED = 'recording_imported';
67
/** @var BIGBLUEBUTTON_EVENT_RECORDING_PROTECTED string defines the bigbluebuttonbn recording_protected event */
68
const BIGBLUEBUTTON_EVENT_RECORDING_PROTECTED = 'recording_protected';
69
/** @var BIGBLUEBUTTON_EVENT_RECORDING_PUBLISHED string defines the bigbluebuttonbn recording_published event */
70
const BIGBLUEBUTTON_EVENT_RECORDING_PUBLISHED = 'recording_published';
71
/** @var BIGBLUEBUTTON_EVENT_RECORDING_UNPROTECTED string defines the bigbluebuttonbn recording_unprotected event */
72
const BIGBLUEBUTTON_EVENT_RECORDING_UNPROTECTED = 'recording_unprotected';
73
/** @var BIGBLUEBUTTON_EVENT_RECORDING_UNPUBLISHED string defines the bigbluebuttonbn recording_unpublished event */
74
const BIGBLUEBUTTON_EVENT_RECORDING_UNPUBLISHED = 'recording_unpublished';
75
/** @var BIGBLUEBUTTON_EVENT_RECORDING_EDITED string defines the bigbluebuttonbn recording_edited event */
76
const BIGBLUEBUTTON_EVENT_RECORDING_EDITED = 'recording_edited';
77
/** @var BIGBLUEBUTTON_EVENT_RECORDING_VIEWED string defines the bigbluebuttonbn recording_viewed event */
78
const BIGBLUEBUTTON_EVENT_RECORDING_VIEWED = 'recording_viewed';
79
/** @var BIGBLUEBUTTON_EVENT_MEETING_START string defines the bigbluebuttonbn meeting_start event */
80
const BIGBLUEBUTTON_EVENT_MEETING_START = 'meeting_start';
81
/** @var BIGBLUEBUTTON_CLIENTTYPE_FLASH integer that defines the bigbluebuttonbn default web client based on Adobe FLASH */
82
const BIGBLUEBUTTON_CLIENTTYPE_FLASH = 0;
83
/** @var BIGBLUEBUTTON_CLIENTTYPE_HTML5 integer that defines the bigbluebuttonbn default web client based on HTML5 */
84
const BIGBLUEBUTTON_CLIENTTYPE_HTML5 = 1;
85
/** @var BIGBLUEBUTTON_ORIGIN_BASE integer set to 0 defines that the user acceded the session from activity page */
86
const BIGBLUEBUTTON_ORIGIN_BASE = 0;
87
/** @var BIGBLUEBUTTON_ORIGIN_TIMELINE integer set to 1 defines that the user acceded the session from Timeline */
88
const BIGBLUEBUTTON_ORIGIN_TIMELINE = 1;
89
/** @var BIGBLUEBUTTON_ORIGIN_INDEX integer set to 2 defines that the user acceded the session from Index */
90
const BIGBLUEBUTTON_ORIGIN_INDEX = 2;
91
92
/**
93
 * Builds and retunrs a url for joining a bigbluebutton meeting.
94
 *
95
 * @param string $meetingid
96
 * @param string $username
97
 * @param string $pw
98
 * @param string $logouturl
99
 * @param string $configtoken
100
 * @param string $userid
101
 * @param string $clienttype
102
 * @param string $createtime
103
 *
104
 * @return string
105
 */
106
function bigbluebuttonbn_get_join_url(
107
    $meetingid,
108
    $username,
109
    $pw,
110
    $logouturl,
111
    $configtoken = null,
112
    $userid = null,
113
    $clienttype = BIGBLUEBUTTON_CLIENTTYPE_FLASH,
114
    $createtime = null
115
) {
116
    //check if guest and entered a custom username
117
    $username2=$username;
118
    if(!empty($_GET['usernamecustom'])&&isguestuser($USER)){
0 ignored issues
show
Bug introduced by
The variable $USER does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
119
        $username2=$_GET['usernamecustom'];
120
    }
121
    $data = ['meetingID' => $meetingid,
122
        'fullName' => $username2,
123
        'password' => $pw,
124
        'logoutURL' => $logouturl,
125
    ];
126
    // Choose between Adobe Flash or HTML5 Client.
127
    if ($clienttype == BIGBLUEBUTTON_CLIENTTYPE_HTML5) {
128
        $data['joinViaHtml5'] = 'true';
129
    }
130
    if (!is_null($configtoken)) {
131
        $data['configToken'] = $configtoken;
132
    }
133
    if (!is_null($userid)) {
134
        $data['userID'] = $userid;
135
    }
136
    if (!is_null($createtime)) {
137
        $data['createTime'] = $createtime;
138
    }
139
    return \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('join', $data);
140
}
141
142
/**
143
 * Creates a bigbluebutton meeting and returns the response in an array.
144
 *
145
 * @param array  $data
146
 * @param array  $metadata
147
 * @param string $pname
148
 * @param string $purl
149
 *
150
 * @return array
151
 */
152
function bigbluebuttonbn_get_create_meeting_array($data, $metadata = array(), $pname = null, $purl = null) {
153
    $createmeetingurl = \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('create', $data, $metadata);
154
    $method = 'GET';
155
    $payload = null;
156
    if (!is_null($pname) && !is_null($purl)) {
157
        $method = 'POST';
158
        $payload = "<?xml version='1.0' encoding='UTF-8'?><modules><module name='presentation'><document url='".
159
            $purl."' /></module></modules>";
160
    }
161
    $xml = bigbluebuttonbn_wrap_xml_load_file($createmeetingurl, $method, $payload);
162
    if ($xml) {
163
        $response = array('returncode' => $xml->returncode, 'message' => $xml->message, 'messageKey' => $xml->messageKey);
164
        if ($xml->meetingID) {
165
            $response += array('meetingID' => $xml->meetingID, 'attendeePW' => $xml->attendeePW,
166
                'moderatorPW' => $xml->moderatorPW, 'hasBeenForciblyEnded' => $xml->hasBeenForciblyEnded);
167
        }
168
        return $response;
169
    }
170
    return array('returncode' => 'FAILED', 'message' => 'unreachable', 'messageKey' => 'Server is unreachable');
171
}
172
173
/**
174
 * Fetch meeting info and wrap response in array.
175
 *
176
 * @param string $meetingid
177
 *
178
 * @return array
179
 */
180
function bigbluebuttonbn_get_meeting_info_array($meetingid) {
181
    $xml = bigbluebuttonbn_wrap_xml_load_file(
182
        \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('getMeetingInfo', ['meetingID' => $meetingid])
183
    );
184
    if ($xml && $xml->returncode == 'SUCCESS' && empty($xml->messageKey)) {
185
        // Meeting info was returned.
186
        return array('returncode' => $xml->returncode,
187
            'meetingID' => $xml->meetingID,
188
            'moderatorPW' => $xml->moderatorPW,
189
            'attendeePW' => $xml->attendeePW,
190
            'hasBeenForciblyEnded' => $xml->hasBeenForciblyEnded,
191
            'running' => $xml->running,
192
            'recording' => $xml->recording,
193
            'startTime' => $xml->startTime,
194
            'endTime' => $xml->endTime,
195
            'participantCount' => $xml->participantCount,
196
            'moderatorCount' => $xml->moderatorCount,
197
            'attendees' => $xml->attendees,
198
            'metadata' => $xml->metadata,
199
        );
200
    }
201
    if ($xml) {
202
        // Either failure or success without meeting info.
203
        return (array) $xml;
204
    }
205
    // If the server is unreachable, then prompts the user of the necessary action.
206
    return array('returncode' => 'FAILED', 'message' => 'unreachable', 'messageKey' => 'Server is unreachable');
207
}
208
209
/**
210
 * Helper function to retrieve recordings from a BigBlueButton server.
211
 *
212
 * @param string|array $meetingids   list of meetingIDs "mid1,mid2,mid3" or array("mid1","mid2","mid3")
213
 * @param string|array $recordingids list of $recordingids "rid1,rid2,rid3" or array("rid1","rid2","rid3") for filtering
214
 *
215
 * @return associative array with recordings indexed by recordID, each recording is a non sequential associative array
216
 */
217
function bigbluebuttonbn_get_recordings_array($meetingids, $recordingids = []) {
218
    $meetingidsarray = $meetingids;
219
    if (!is_array($meetingids)) {
220
        $meetingidsarray = explode(',', $meetingids);
221
    }
222
    // If $meetingidsarray is empty there is no need to go further.
223
    if (empty($meetingidsarray)) {
224
        return array();
225
    }
226
    $recordings = bigbluebuttonbn_get_recordings_array_fetch($meetingidsarray);
0 ignored issues
show
Bug introduced by
It seems like $meetingidsarray defined by $meetingids on line 218 can also be of type string; however, bigbluebuttonbn_get_recordings_array_fetch() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
227
    // Sort recordings.
228
    uasort($recordings, 'bigbluebuttonbn_recording_build_sorter');
229
    // Filter recordings based on recordingIDs.
230
    $recordingidsarray = $recordingids;
231
    if (!is_array($recordingids)) {
232
        $recordingidsarray = explode(',', $recordingids);
233
    }
234
    if (empty($recordingidsarray)) {
235
        // No recording ids, no need to filter.
236
        return $recordings;
237
    }
238
    return bigbluebuttonbn_get_recordings_array_filter($recordingidsarray, $recordings);
0 ignored issues
show
Bug introduced by
It seems like $recordingidsarray defined by $recordingids on line 230 can also be of type string; however, bigbluebuttonbn_get_recordings_array_filter() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
239
}
240
241
/**
242
 * Helper function to fetch recordings from a BigBlueButton server.
243
 *
244
 * @param array $meetingidsarray array with meeting ids in the form array("mid1","mid2","mid3")
245
 *
246
 * @return array (associative) with recordings indexed by recordID, each recording is a non sequential associative array
247
 */
248
function bigbluebuttonbn_get_recordings_array_fetch($meetingidsarray) {
249
    if ((defined('PHPUNIT_TEST') && PHPUNIT_TEST)
250
            || defined('BEHAT_SITE_RUNNING')
251
            || defined('BEHAT_TEST')
252
            || defined('BEHAT_UTIL')) {
253
        // Just return the fake recording.
254
        global $CFG;
255
        require_once($CFG->libdir . '/testing/generator/lib.php');
256
        require_once(__DIR__ . '/tests/generator/lib.php');
257
        return mod_bigbluebuttonbn_generator::bigbluebuttonbn_get_recordings_array_fetch($meetingidsarray);
258
    }
259
    $recordings = array();
260
    // Execute a paginated getRecordings request.
261
    $pagecount = 25;
262
    $pages = floor(count($meetingidsarray) / $pagecount) + 1;
263
    if (count($meetingidsarray) > 0 && count($meetingidsarray) % $pagecount == 0) {
264
        $pages--;
265
    }
266
    for ($page = 1; $page <= $pages; ++$page) {
267
        $mids = array_slice($meetingidsarray, ($page - 1) * $pagecount, $pagecount);
268
        $recordings += bigbluebuttonbn_get_recordings_array_fetch_page($mids);
269
    }
270
    return $recordings;
271
}
272
273
/**
274
 * Helper function to fetch one page of upto 25 recordings from a BigBlueButton server.
275
 *
276
 * @param array  $mids
277
 *
278
 * @return array
279
 */
280
function bigbluebuttonbn_get_recordings_array_fetch_page($mids) {
281
    $recordings = array();
282
    // Do getRecordings is executed using a method GET (supported by all versions of BBB).
283
    $url = \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('getRecordings', ['meetingID' => implode(',', $mids)]);
284
    $xml = bigbluebuttonbn_wrap_xml_load_file($url);
285
    if ($xml && $xml->returncode == 'SUCCESS' && isset($xml->recordings)) {
286
        // If there were meetings already created.
287
        foreach ($xml->recordings->recording as $recordingxml) {
288
            $recording = bigbluebuttonbn_get_recording_array_value($recordingxml);
289
            $recordings[$recording['recordID']] = $recording;
290
291
            // Check if there is childs.
292
            if (isset($recordingxml->breakoutRooms->breakoutRoom)) {
293
                foreach ($recordingxml->breakoutRooms->breakoutRoom as $breakoutroom) {
294
                    $url = \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url(
295
                        'getRecordings',
296
                        ['recordID' => implode(',', (array) $breakoutroom)]
297
                    );
298
                    $xml = bigbluebuttonbn_wrap_xml_load_file($url);
299
                    if ($xml && $xml->returncode == 'SUCCESS' && isset($xml->recordings)) {
300
                        // If there were meetings already created.
301
                        foreach ($xml->recordings->recording as $recordingxml) {
302
                            $recording = bigbluebuttonbn_get_recording_array_value($recordingxml);
303
                            $recordings[$recording['recordID']] = $recording;
304
                        }
305
                    }
306
                }
307
            }
308
        }
309
    }
310
    return $recordings;
311
}
312
313
/**
314
 * Helper function to remove a set of recordings from an array.
315
 *
316
 * @param array  $rids
317
 * @param array  $recordings
318
 *
319
 * @return array
320
 */
321
function bigbluebuttonbn_get_recordings_array_filter($rids, &$recordings) {
322
    foreach ($recordings as $key => $recording) {
323
        if (!in_array($recording['recordID'], $rids)) {
324
            unset($recordings[$key]);
325
        }
326
    }
327
    return $recordings;
328
}
329
330
/**
331
 * Helper function to retrieve imported recordings from the Moodle database.
332
 * The references are stored as events in bigbluebuttonbn_logs.
333
 *
334
 * @param string $courseid
335
 * @param string $bigbluebuttonbnid
336
 * @param bool   $subset
337
 *
338
 * @return associative array with imported recordings indexed by recordID, each recording
339
 * is a non sequential associative array that corresponds to the actual recording in BBB
340
 */
341
function bigbluebuttonbn_get_recordings_imported_array($courseid = 0, $bigbluebuttonbnid = null, $subset = true) {
342
    global $DB;
343
    $select = bigbluebuttonbn_get_recordings_imported_sql_select($courseid, $bigbluebuttonbnid, $subset);
344
    $recordsimported = $DB->get_records_select('bigbluebuttonbn_logs', $select);
345
    $recordsimportedarray = array();
346
    foreach ($recordsimported as $recordimported) {
347
        $meta = json_decode($recordimported->meta, true);
348
        $recording = $meta['recording'];
349
        // Override imported flag with actual ID.
350
        $recording['imported'] = $recordimported->id;
351
        if (isset($recordimported->protected)) {
352
            $recording['protected'] = (string) $recordimported->protected;
353
        }
354
        $recordsimportedarray[$recording['recordID']] = $recording;
355
    }
356
    return $recordsimportedarray;
357
}
358
359
/**
360
 * Helper function to retrive the default config.xml file.
361
 *
362
 * @return string
363
 */
364
function bigbluebuttonbn_get_default_config_xml() {
365
    $xml = bigbluebuttonbn_wrap_xml_load_file(
366
        \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('getDefaultConfigXML')
367
    );
368
    return $xml;
369
}
370
371
/**
372
 * Helper function to convert an xml recording object to an array in the format used by the plugin.
373
 *
374
 * @param object $recording
375
 *
376
 * @return array
377
 */
378
function bigbluebuttonbn_get_recording_array_value($recording) {
379
    // Add formats.
380
    $playbackarray = array();
381
    foreach ($recording->playback->format as $format) {
382
        $playbackarray[(string) $format->type] = array('type' => (string) $format->type,
383
            'url' => trim((string) $format->url), 'length' => (string) $format->length);
384
        // Add preview per format when existing.
385
        if ($format->preview) {
386
            $playbackarray[(string) $format->type]['preview'] = bigbluebuttonbn_get_recording_preview_images($format->preview);
387
        }
388
    }
389
    // Add the metadata to the recordings array.
390
    $metadataarray = bigbluebuttonbn_get_recording_array_meta(get_object_vars($recording->metadata));
391
    $recordingarray = array('recordID' => (string) $recording->recordID,
392
        'meetingID' => (string) $recording->meetingID, 'meetingName' => (string) $recording->name,
393
        'published' => (string) $recording->published, 'startTime' => (string) $recording->startTime,
394
        'endTime' => (string) $recording->endTime, 'playbacks' => $playbackarray);
395
    if (isset($recording->protected)) {
396
        $recordingarray['protected'] = (string) $recording->protected;
397
    }
398
    return $recordingarray + $metadataarray;
399
}
400
401
/**
402
 * Helper function to convert an xml recording preview images to an array in the format used by the plugin.
403
 *
404
 * @param object $preview
405
 *
406
 * @return array
407
 */
408
function bigbluebuttonbn_get_recording_preview_images($preview) {
409
    $imagesarray = array();
410
    foreach ($preview->images->image as $image) {
411
        $imagearray = array('url' => trim((string) $image));
412
        foreach ($image->attributes() as $attkey => $attvalue) {
413
            $imagearray[$attkey] = (string) $attvalue;
414
        }
415
        array_push($imagesarray, $imagearray);
416
    }
417
    return $imagesarray;
418
}
419
420
/**
421
 * Helper function to convert an xml recording metadata object to an array in the format used by the plugin.
422
 *
423
 * @param array $metadata
424
 *
425
 * @return array
426
 */
427
function bigbluebuttonbn_get_recording_array_meta($metadata) {
428
    $metadataarray = array();
429
    foreach ($metadata as $key => $value) {
430
        if (is_object($value)) {
431
            $value = '';
432
        }
433
        $metadataarray['meta_' . $key] = $value;
434
    }
435
    return $metadataarray;
436
}
437
438
/**
439
 * Helper function to sort an array of recordings. It compares the startTime in two recording objecs.
440
 *
441
 * @param object $a
442
 * @param object $b
443
 *
444
 * @return array
445
 */
446
function bigbluebuttonbn_recording_build_sorter($a, $b) {
447
    global $CFG;
448
    $resultless = !empty($CFG->bigbluebuttonbn_recordings_sortorder) ? -1 : 1;
449
    $resultmore = !empty($CFG->bigbluebuttonbn_recordings_sortorder) ? 1 : -1;
450
    if ($a['startTime'] < $b['startTime']) {
451
        return $resultless;
452
    }
453
    if ($a['startTime'] == $b['startTime']) {
454
        return 0;
455
    }
456
    return $resultmore;
457
}
458
459
/**
460
 * Perform deleteRecordings on BBB.
461
 *
462
 * @param string $recordids
463
 *
464
 * @return boolean
465
 */
466 View Code Duplication
function bigbluebuttonbn_delete_recordings($recordids) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
467
    $ids = explode(',', $recordids);
468
    foreach ($ids as $id) {
469
        $xml = bigbluebuttonbn_wrap_xml_load_file(
470
            \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('deleteRecordings', ['recordID' => $id])
471
        );
472
        if ($xml && $xml->returncode != 'SUCCESS') {
473
            return false;
474
        }
475
    }
476
    return true;
477
}
478
479
/**
480
 * Perform publishRecordings on BBB.
481
 *
482
 * @param string $recordids
483
 * @param string $publish
484
 */
485 View Code Duplication
function bigbluebuttonbn_publish_recordings($recordids, $publish = 'true') {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
486
    $ids = explode(',', $recordids);
487
    foreach ($ids as $id) {
488
        $xml = bigbluebuttonbn_wrap_xml_load_file(
489
            \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('publishRecordings', ['recordID' => $id, 'publish' => $publish])
490
        );
491
        if ($xml && $xml->returncode != 'SUCCESS') {
492
            return false;
493
        }
494
    }
495
    return true;
496
}
497
498
/**
499
 * Perform updateRecordings on BBB.
500
 *
501
 * @param string $recordids
502
 * @param array $params ['key'=>param_key, 'value']
503
 */
504 View Code Duplication
function bigbluebuttonbn_update_recordings($recordids, $params) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
505
    $ids = explode(',', $recordids);
506
    foreach ($ids as $id) {
507
        $xml = bigbluebuttonbn_wrap_xml_load_file(
508
            \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('updateRecordings', ['recordID' => $id] + (array) $params)
509
        );
510
        if ($xml && $xml->returncode != 'SUCCESS') {
511
            return false;
512
        }
513
    }
514
    return true;
515
}
516
517
/**
518
 * Perform end on BBB.
519
 *
520
 * @param string $meetingid
521
 * @param string $modpw
522
 */
523
function bigbluebuttonbn_end_meeting($meetingid, $modpw) {
524
    $xml = bigbluebuttonbn_wrap_xml_load_file(
525
        \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('end', ['meetingID' => $meetingid, 'password' => $modpw])
526
    );
527
    if ($xml) {
528
        // If the xml packet returned failure it displays the message to the user.
529
        return array('returncode' => $xml->returncode, 'message' => $xml->message, 'messageKey' => $xml->messageKey);
530
    }
531
    // If the server is unreachable, then prompts the user of the necessary action.
532
    return null;
533
}
534
535
/**
536
 * Perform api request on BBB.
537
 *
538
 * @return string
539
 */
540
function bigbluebuttonbn_get_server_version() {
541
    $xml = bigbluebuttonbn_wrap_xml_load_file(
542
        \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url()
543
    );
544
    if ($xml && $xml->returncode == 'SUCCESS') {
545
        return $xml->version;
546
    }
547
    return null;
548
}
549
550
/**
551
 * Perform api request on BBB and wraps the response in an XML object
552
 *
553
 * @param string $url
554
 * @param string $method
555
 * @param string $data
556
 * @param string $contenttype
557
 *
558
 * @return object
559
 */
560
function bigbluebuttonbn_wrap_xml_load_file($url, $method = 'GET', $data = null, $contenttype = 'text/xml') {
561
    if (extension_loaded('curl')) {
562
        $response = bigbluebuttonbn_wrap_xml_load_file_curl_request($url, $method, $data, $contenttype);
563
        if (!$response) {
564
            debugging('No response on wrap_simplexml_load_file', DEBUG_DEVELOPER);
565
            return null;
566
        }
567
        $previous = libxml_use_internal_errors(true);
568
        try {
569
            $xml = simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA | LIBXML_NOBLANKS);
570
            return $xml;
571
        } catch (Exception $e) {
572
            libxml_use_internal_errors($previous);
573
            $error = 'Caught exception: ' . $e->getMessage();
574
            debugging($error, DEBUG_DEVELOPER);
575
            return null;
576
        }
577
    }
578
    // Alternative request non CURL based.
579
    $previous = libxml_use_internal_errors(true);
580
    try {
581
        $response = simplexml_load_file($url, 'SimpleXMLElement', LIBXML_NOCDATA | LIBXML_NOBLANKS);
582
        return $response;
583
    } catch (Exception $e) {
584
        $error = 'Caught exception: ' . $e->getMessage();
585
        debugging($error, DEBUG_DEVELOPER);
586
        libxml_use_internal_errors($previous);
587
        return null;
588
    }
589
}
590
591
/**
592
 * Perform api request on BBB using CURL and wraps the response in an XML object
593
 *
594
 * @param string $url
595
 * @param string $method
596
 * @param string $data
597
 * @param string $contenttype
598
 *
599
 * @return object
600
 */
601
function bigbluebuttonbn_wrap_xml_load_file_curl_request($url, $method = 'GET', $data = null, $contenttype = 'text/xml') {
602
    global $CFG;
603
    require_once($CFG->libdir . '/filelib.php');
604
    $c = new curl();
605
    $c->setopt(array('SSL_VERIFYPEER' => true));
606
    if ($method == 'POST') {
607
        if (is_null($data) || is_array($data)) {
608
            return $c->post($url);
609
        }
610
        $options = array();
611
        $options['CURLOPT_HTTPHEADER'] = array(
612
            'Content-Type: ' . $contenttype,
613
            'Content-Length: ' . strlen($data),
614
            'Content-Language: en-US',
615
        );
616
617
        return $c->post($url, $data, $options);
618
    }
619
    if ($method == 'HEAD') {
620
        $c->head($url, array('followlocation' => true, 'timeout' => 1));
621
        return $c->get_info();
622
    }
623
    return $c->get($url);
624
}
625
626
/**
627
 * End the session associated with this instance (if it's running).
628
 *
629
 * @param object $bigbluebuttonbn
630
 *
631
 * @return void
632
 */
633
function bigbluebuttonbn_end_meeting_if_running($bigbluebuttonbn) {
634
    $meetingid = $bigbluebuttonbn->meetingid . '-' . $bigbluebuttonbn->course . '-' . $bigbluebuttonbn->id;
635
    if (bigbluebuttonbn_is_meeting_running($meetingid)) {
636
        bigbluebuttonbn_end_meeting($meetingid, $bigbluebuttonbn->moderatorpass);
637
    }
638
}
639
640
/**
641
 * Returns user roles in a context.
642
 *
643
 * @param object $context
644
 * @param integer $userid
645
 *
646
 * @return array $userroles
647
 */
648
function bigbluebuttonbn_get_user_roles($context, $userid) {
649
    global $DB;
650
    $userroles = get_user_roles($context, $userid);
651
    if ($userroles) {
652
        $where = '';
653
        foreach ($userroles as $userrole) {
654
            $where .= (empty($where) ? ' WHERE' : ' OR') . ' id=' . $userrole->roleid;
655
        }
656
        $userroles = $DB->get_records_sql('SELECT * FROM {role}' . $where);
657
    }
658
    return $userroles;
659
}
660
661
/**
662
 * Returns guest role wrapped in an array.
663
 *
664
 * @return array
665
 */
666
function bigbluebuttonbn_get_guest_role() {
667
    $guestrole = get_guest_role();
668
    return array($guestrole->id => $guestrole);
669
}
670
671
/**
672
 * Returns an array containing all the users in a context.
673
 *
674
 * @param context $context
675
 *
676
 * @return array $users
677
 */
678
function bigbluebuttonbn_get_users(context $context = null) {
679
    $users = (array) get_enrolled_users($context, '', 0, 'u.*', null, 0, 0, true);
680
    foreach ($users as $key => $value) {
681
        $users[$key] = fullname($value);
682
    }
683
    return $users;
684
}
685
686
/**
687
 * Returns an array containing all the users in a context wrapped for html select element.
688
 *
689
 * @param context_course $context
690
 * @param null $bbactivity
691
 * @return array $users
692
 * @throws coding_exception
693
 * @throws moodle_exception
694
 */
695
function bigbluebuttonbn_get_users_select(context_course $context, $bbactivity = null) {
696
    // CONTRIB-7972, check the group of current user and course group mode.
697
    $groups = null;
0 ignored issues
show
Unused Code introduced by
$groups is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
698
    $users = (array) get_enrolled_users($context, '', 0, 'u.*', null, 0, 0, true);
699
    $course = get_course($context->instanceid);
700
    $groupmode = groups_get_course_groupmode($course);
701
    if ($bbactivity) {
702
        list($bbcourse, $cm) = get_course_and_cm_from_instance($bbactivity->id, 'bigbluebuttonbn');
0 ignored issues
show
Unused Code introduced by
The assignment to $bbcourse is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
703
        $groupmode = groups_get_activity_groupmode($cm);
704
705
    }
706
    if ($groupmode == SEPARATEGROUPS && !has_capability('moodle/site:accessallgroups', $context)) {
707
        global $USER;
708
        $groups = groups_get_all_groups($course->id, $USER->id);
709
        $users = [];
710
        foreach ($groups as $g) {
711
            $users += (array) get_enrolled_users($context, '', $g->id, 'u.*', null, 0, 0, true);
712
        }
713
    }
714
    return array_map(
715
            function($u) {
716
                return array('id' => $u->id, 'name' => fullname($u));
717
            },
718
            $users);
719
}
720
721
/**
722
 * Returns an array containing all the roles in a context.
723
 *
724
 * @param context $context
725
 * @param bool $onlyviewableroles
726
 *
727
 * @return array $roles
728
 */
729
function bigbluebuttonbn_get_roles(context $context = null, bool $onlyviewableroles = true) {
730
    global $CFG;
731
732
    if ($onlyviewableroles == true && $CFG->branch >= 35) {
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...
733
        $roles = (array) get_viewable_roles($context);
734
        foreach ($roles as $key => $value) {
735
            $roles[$key] = $value;
736
        }
737
    } else {
738
        $roles = (array) role_get_names($context);
739
        foreach ($roles as $key => $value) {
740
            $roles[$key] = $value->localname;
741
        }
742
    }
743
744
    return $roles;
745
}
746
747
/**
748
 * Returns an array containing all the roles in a context wrapped for html select element.
749
 *
750
 * @param context $context
751
 * @param bool $onlyviewableroles
752
 *
753
 * @return array $users
754
 */
755
function bigbluebuttonbn_get_roles_select(context $context = null, bool $onlyviewableroles = true) {
756
    global $CFG;
757
758
    if ($onlyviewableroles == true && $CFG->branch >= 35) {
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...
759
        $roles = (array) get_viewable_roles($context);
760
        foreach ($roles as $key => $value) {
761
            $roles[$key] = array('id' => $key, 'name' => $value);
762
        }
763
    } else {
764
        $roles = (array) role_get_names($context);
765
        foreach ($roles as $key => $value) {
766
            $roles[$key] = array('id' => $value->id, 'name' => $value->localname);
767
        }
768
    }
769
770
    return $roles;
771
}
772
773
/**
774
 * Returns role that corresponds to an id.
775
 *
776
 * @param string|integer $id
777
 *
778
 * @return object $role
779
 */
780
function bigbluebuttonbn_get_role($id) {
781
    $roles = (array) role_get_names();
782
    if (is_numeric($id) && isset($roles[$id])) {
783
        return (object) $roles[$id];
784
    }
785
    foreach ($roles as $role) {
786
        if ($role->shortname == $id) {
787
            return $role;
788
        }
789
    }
790
}
791
792
/**
793
 * Returns an array to populate a list of participants used in mod_form.js.
794
 *
795
 * @param context $context
796
 * @param null|object $bbactivity
797
 * @return array $data
798
 */
799
function bigbluebuttonbn_get_participant_data($context, $bbactivity = null) {
800
    $data = array(
801
        'all' => array(
802
            'name' => get_string('mod_form_field_participant_list_type_all', 'bigbluebuttonbn'),
803
            'children' => []
804
        ),
805
    );
806
    $data['role'] = array(
807
        'name' => get_string('mod_form_field_participant_list_type_role', 'bigbluebuttonbn'),
808
        'children' => bigbluebuttonbn_get_roles_select($context, true)
809
      );
810
    $data['user'] = array(
811
        'name' => get_string('mod_form_field_participant_list_type_user', 'bigbluebuttonbn'),
812
        'children' => bigbluebuttonbn_get_users_select($context, $bbactivity),
0 ignored issues
show
Bug introduced by
It seems like $bbactivity defined by parameter $bbactivity on line 799 can also be of type object; however, bigbluebuttonbn_get_users_select() does only seem to accept null, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
813
    );
814
    return $data;
815
}
816
817
/**
818
 * Returns an array to populate a list of participants used in mod_form.php.
819
 *
820
 * @param object $bigbluebuttonbn
821
 * @param context $context
822
 *
823
 * @return array
824
 */
825
function bigbluebuttonbn_get_participant_list($bigbluebuttonbn, $context) {
826
    global $USER;
827
    if ($bigbluebuttonbn == null) {
828
        return bigbluebuttonbn_get_participant_rules_encoded(
829
            bigbluebuttonbn_get_participant_list_default($context, $USER->id)
830
        );
831
    }
832
    if (empty($bigbluebuttonbn->participants)) {
833
        $bigbluebuttonbn->participants = "[]";
834
    }
835
    $rules = json_decode($bigbluebuttonbn->participants, true);
836
    if (empty($rules)) {
837
        $rules = bigbluebuttonbn_get_participant_list_default($context, bigbluebuttonbn_instance_ownerid($bigbluebuttonbn));
838
    }
839
    return bigbluebuttonbn_get_participant_rules_encoded($rules);
840
}
841
842
/**
843
 * Returns an array to populate a list of participants used in mod_form.php with default values.
844
 *
845
 * @param context $context
846
 * @param integer $ownerid
847
 *
848
 * @return array
849
 */
850
function bigbluebuttonbn_get_participant_list_default($context, $ownerid = null) {
851
    $participantlist = array();
852
    $participantlist[] = array(
853
        'selectiontype' => 'all',
854
        'selectionid' => 'all',
855
        'role' => BIGBLUEBUTTONBN_ROLE_VIEWER,
856
    );
857
    $defaultrules = explode(',', \mod_bigbluebuttonbn\locallib\config::get('participant_moderator_default'));
858
    foreach ($defaultrules as $defaultrule) {
859
        if ($defaultrule == '0') {
860
            if (!empty($ownerid) && is_enrolled($context, $ownerid)) {
861
                $participantlist[] = array(
862
                    'selectiontype' => 'user',
863
                    'selectionid' => (string) $ownerid,
864
                    'role' => BIGBLUEBUTTONBN_ROLE_MODERATOR);
865
            }
866
            continue;
867
        }
868
        $participantlist[] = array(
869
            'selectiontype' => 'role',
870
            'selectionid' => $defaultrule,
871
            'role' => BIGBLUEBUTTONBN_ROLE_MODERATOR);
872
    }
873
    return $participantlist;
874
}
875
876
/**
877
 * Returns an array to populate a list of participants used in mod_form.php with bigbluebuttonbn values.
878
 *
879
 * @param array $rules
880
 *
881
 * @return array
882
 */
883
function bigbluebuttonbn_get_participant_rules_encoded($rules) {
884
    foreach ($rules as $key => $rule) {
885
        if ($rule['selectiontype'] !== 'role' || is_numeric($rule['selectionid'])) {
886
            continue;
887
        }
888
        $role = bigbluebuttonbn_get_role($rule['selectionid']);
889
        if ($role == null) {
890
            unset($rules[$key]);
891
            continue;
892
        }
893
        $rule['selectionid'] = $role->id;
894
        $rules[$key] = $rule;
895
    }
896
    return $rules;
897
}
898
899
/**
900
 * Returns an array to populate a list of participant_selection used in mod_form.php.
901
 *
902
 * @return array
903
 */
904
function bigbluebuttonbn_get_participant_selection_data() {
905
    return [
906
        'type_options' => [
907
            'all' => get_string('mod_form_field_participant_list_type_all', 'bigbluebuttonbn'),
908
            'role' => get_string('mod_form_field_participant_list_type_role', 'bigbluebuttonbn'),
909
            'user' => get_string('mod_form_field_participant_list_type_user', 'bigbluebuttonbn'),
910
        ],
911
        'type_selected' => 'all',
912
        'options' => ['all' => '---------------'],
913
        'selected' => 'all',
914
    ];
915
}
916
917
/**
918
 * Evaluate if a user in a context is moderator based on roles and participation rules.
919
 *
920
 * @param context $context
921
 * @param array $participantlist
922
 * @param integer $userid
923
 *
924
 * @return boolean
925
 */
926
function bigbluebuttonbn_is_moderator($context, $participantlist, $userid = null) {
927
    global $USER;
928
    if (!is_array($participantlist)) {
929
        return false;
930
    }
931
    if (empty($userid)) {
932
        $userid = $USER->id;
933
    }
934
    $userroles = bigbluebuttonbn_get_guest_role();
935
    if (!isguestuser()) {
936
        $userroles = bigbluebuttonbn_get_user_roles($context, $userid);
937
    }
938
    return bigbluebuttonbn_is_moderator_validator($participantlist, $userid, $userroles);
939
}
940
941
/**
942
 * Iterates participant list rules to evaluate if a user is moderator.
943
 *
944
 * @param array $participantlist
945
 * @param integer $userid
946
 * @param array $userroles
947
 *
948
 * @return boolean
949
 */
950
function bigbluebuttonbn_is_moderator_validator($participantlist, $userid, $userroles) {
951
    // Iterate participant rules.
952
    foreach ($participantlist as $participant) {
953
        if (bigbluebuttonbn_is_moderator_validate_rule($participant, $userid, $userroles)) {
954
            return true;
955
        }
956
    }
957
    return false;
958
}
959
960
/**
961
 * Evaluate if a user is moderator based on roles and a particular participation rule.
962
 *
963
 * @param object $participant
964
 * @param integer $userid
965
 * @param array $userroles
966
 *
967
 * @return boolean
968
 */
969
function bigbluebuttonbn_is_moderator_validate_rule($participant, $userid, $userroles) {
970
    if ($participant['role'] == BIGBLUEBUTTONBN_ROLE_VIEWER) {
971
        return false;
972
    }
973
    // Validation for the 'all' rule.
974
    if ($participant['selectiontype'] == 'all') {
975
        return true;
976
    }
977
    // Validation for a 'user' rule.
978
    if ($participant['selectiontype'] == 'user') {
979
        if ($participant['selectionid'] == $userid) {
980
            return true;
981
        }
982
        return false;
983
    }
984
    // Validation for a 'role' rule.
985
    $role = bigbluebuttonbn_get_role($participant['selectionid']);
986
    if ($role != null && array_key_exists($role->id, $userroles)) {
987
        return true;
988
    }
989
    return false;
990
}
991
992
/**
993
 * Helper returns error message key for the language file that corresponds to a bigbluebutton error key.
994
 *
995
 * @param string $messagekey
996
 * @param string $defaultkey
997
 *
998
 * @return string
999
 */
1000
function bigbluebuttonbn_get_error_key($messagekey, $defaultkey = null) {
1001
    if ($messagekey == 'checksumError') {
1002
        return 'index_error_checksum';
1003
    }
1004
    if ($messagekey == 'maxConcurrent') {
1005
        return 'view_error_max_concurrent';
1006
    }
1007
    return $defaultkey;
1008
}
1009
1010
/**
1011
 * Helper evaluates if a voicebridge number is unique.
1012
 *
1013
 * @param integer $instance
1014
 * @param integer $voicebridge
1015
 *
1016
 * @return string
1017
 */
1018
function bigbluebuttonbn_voicebridge_unique($instance, $voicebridge) {
1019
    global $DB;
1020
    if ($voicebridge == 0) {
1021
        return true;
1022
    }
1023
    $select = 'voicebridge = ' . $voicebridge;
1024
    if ($instance != 0) {
1025
        $select .= ' AND id <>' . $instance;
1026
    }
1027
    if (!$DB->get_records_select('bigbluebuttonbn', $select)) {
1028
        return true;
1029
    }
1030
    return false;
1031
}
1032
1033
/**
1034
 * Helper estimate a duration for the meeting based on the closingtime.
1035
 *
1036
 * @param integer $closingtime
1037
 *
1038
 * @return integer
1039
 */
1040
function bigbluebuttonbn_get_duration($closingtime) {
1041
    $duration = 0;
1042
    $now = time();
1043
    if ($closingtime > 0 && $now < $closingtime) {
1044
        $duration = ceil(($closingtime - $now) / 60);
1045
        $compensationtime = intval((int) \mod_bigbluebuttonbn\locallib\config::get('scheduled_duration_compensation'));
1046
        $duration = intval($duration) + $compensationtime;
1047
    }
1048
    return $duration;
1049
}
1050
1051
/**
1052
 * Helper return array containing the file descriptor for a preuploaded presentation.
1053
 *
1054
 * @param context $context
1055
 * @param string $presentation
1056
 * @param integer $id
1057
 *
1058
 * @return array
1059
 */
1060
function bigbluebuttonbn_get_presentation_array($context, $presentation, $id = null) {
1061
    global $CFG;
1062
    if (empty($presentation)) {
1063
        if ($CFG->bigbluebuttonbn_preuploadpresentation_enabled) {
1064
            // Item has not presentation but presentation is enabled..
1065
            // Check if exist some file by default in general mod setting ("presentationdefault").
1066
            $fs = get_file_storage();
1067
            $files = $fs->get_area_files(
1068
                context_system::instance()->id,
1069
                'mod_bigbluebuttonbn',
1070
                'presentationdefault',
1071
                0,
1072
                "filename",
1073
                false
1074
            );
1075
1076 View Code Duplication
            if (count($files) == 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1077
                // Not exist file by default in "presentationbydefault" setting.
1078
                return array('url' => null, 'name' => null, 'icon' => null, 'mimetype_description' => null);
1079
            }
1080
1081
            // Exists file in general setting to use as default for presentation. Cache image for temp public access.
1082
            $file = reset($files);
1083
            unset($files);
1084
            $pnoncevalue = null;
1085 View Code Duplication
            if (!is_null($id)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1086
                // Create the nonce component for granting a temporary public access.
1087
                $cache = cache::make_from_params(
1088
                    cache_store::MODE_APPLICATION,
1089
                    'mod_bigbluebuttonbn',
1090
                    'presentationdefault_cache'
1091
                );
1092
                $pnoncekey = sha1(context_system::instance()->id);
1093
                /* The item id was adapted for granting public access to the presentation once in order
1094
                 * to allow BigBlueButton to gather the file. */
1095
                $pnoncevalue = bigbluebuttonbn_generate_nonce();
1096
                $cache->set($pnoncekey, array('value' => $pnoncevalue, 'counter' => 0));
1097
            }
1098
1099
            $url = moodle_url::make_pluginfile_url(
1100
                $file->get_contextid(),
1101
                $file->get_component(),
1102
                $file->get_filearea(),
1103
                $pnoncevalue,
1104
                $file->get_filepath(),
1105
                $file->get_filename()
1106
            );
1107
            return (array('name' => $file->get_filename(), 'icon' => file_file_icon($file, 24),
1108
                'url' => $url->out(false), 'mimetype_description' => get_mimetype_description($file)));
1109
        }
1110
1111
        return array('url' => null, 'name' => null, 'icon' => null, 'mimetype_description' => null);
1112
    }
1113
    $fs = get_file_storage();
1114
    $files = $fs->get_area_files(
1115
        $context->id,
1116
        'mod_bigbluebuttonbn',
1117
        'presentation',
1118
        0,
1119
        'itemid, filepath, filename',
1120
        false
1121
    );
1122 View Code Duplication
    if (count($files) == 0) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1123
        return array('url' => null, 'name' => null, 'icon' => null, 'mimetype_description' => null);
1124
    }
1125
    $file = reset($files);
1126
    unset($files);
1127
    $pnoncevalue = null;
1128 View Code Duplication
    if (!is_null($id)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1129
        // Create the nonce component for granting a temporary public access.
1130
        $cache = cache::make_from_params(
1131
            cache_store::MODE_APPLICATION,
1132
            'mod_bigbluebuttonbn',
1133
            'presentation_cache'
1134
        );
1135
        $pnoncekey = sha1($id);
1136
        /* The item id was adapted for granting public access to the presentation once in order
1137
         * to allow BigBlueButton to gather the file. */
1138
        $pnoncevalue = bigbluebuttonbn_generate_nonce();
1139
        $cache->set($pnoncekey, array('value' => $pnoncevalue, 'counter' => 0));
1140
    }
1141
    $url = moodle_url::make_pluginfile_url(
1142
        $file->get_contextid(),
1143
        $file->get_component(),
1144
        $file->get_filearea(),
1145
        $pnoncevalue,
1146
        $file->get_filepath(),
1147
        $file->get_filename()
1148
    );
1149
    return array('name' => $file->get_filename(), 'icon' => file_file_icon($file, 24),
1150
        'url' => $url->out(false), 'mimetype_description' => get_mimetype_description($file));
1151
}
1152
1153
/**
1154
 * Helper generates a nonce used for the preuploaded presentation callback url.
1155
 *
1156
 * @return string
1157
 */
1158
function bigbluebuttonbn_generate_nonce() {
1159
    $mt = microtime();
1160
    $rand = mt_rand();
1161
    return md5($mt . $rand);
1162
}
1163
1164
/**
1165
 * Helper generates a random password.
1166
 *
1167
 * @param integer $length
1168
 * @param string $unique
1169
 *
1170
 * @return string
1171
 */
1172
function bigbluebuttonbn_random_password($length = 8, $unique = "") {
1173
    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
1174
    do {
1175
        $password = substr(str_shuffle($chars), 0, $length);
1176
    } while ($unique == $password);
1177
    return $password;
1178
}
1179
1180
/**
1181
 * Helper register a bigbluebuttonbn event.
1182
 *
1183
 * @param string $type
1184
 * @param object $bigbluebuttonbn
1185
 * @param array $options [timecreated, userid, other]
1186
 *
1187
 * @return void
1188
 */
1189
function bigbluebuttonbn_event_log($type, $bigbluebuttonbn, $options = []) {
1190
    global $DB;
1191
    if (!in_array($type, \mod_bigbluebuttonbn\event\events::$events)) {
1192
        // No log will be created.
1193
        return;
1194
    }
1195
    $course = $DB->get_record('course', array('id' => $bigbluebuttonbn->course), '*', MUST_EXIST);
1196
    $cm = get_coursemodule_from_instance('bigbluebuttonbn', $bigbluebuttonbn->id, $course->id, false, MUST_EXIST);
1197
    $context = context_module::instance($cm->id);
1198
    $params = array('context' => $context, 'objectid' => $bigbluebuttonbn->id);
1199
    if (array_key_exists('timecreated', $options)) {
1200
        $params['timecreated'] = $options['timecreated'];
1201
    }
1202
    if (array_key_exists('userid', $options)) {
1203
        $params['userid'] = $options['userid'];
1204
    }
1205
    if (array_key_exists('other', $options)) {
1206
        $params['other'] = $options['other'];
1207
    }
1208
    $event = call_user_func_array(
1209
        '\mod_bigbluebuttonbn\event\\' . $type . '::create',
1210
        array($params)
1211
    );
1212
    $event->add_record_snapshot('course_modules', $cm);
1213
    $event->add_record_snapshot('course', $course);
1214
    $event->add_record_snapshot('bigbluebuttonbn', $bigbluebuttonbn);
1215
    $event->trigger();
1216
}
1217
1218
/**
1219
 * Updates the meeting info cached object when a participant has joined.
1220
 *
1221
 * @param string $meetingid
1222
 * @param bool $ismoderator
1223
 *
1224
 * @return void
1225
 */
1226
function bigbluebuttonbn_participant_joined($meetingid, $ismoderator) {
1227
    $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'mod_bigbluebuttonbn', 'meetings_cache');
1228
    $result = $cache->get($meetingid);
1229
    $meetinginfo = json_decode($result['meeting_info']);
1230
    $meetinginfo->participantCount += 1;
1231
    if ($ismoderator) {
1232
        $meetinginfo->moderatorCount += 1;
1233
    }
1234
    $cache->set($meetingid, array('creation_time' => $result['creation_time'],
1235
        'meeting_info' => json_encode($meetinginfo)));
1236
}
1237
1238
/**
1239
 * Gets a meeting info object cached or fetched from the live session.
1240
 *
1241
 * @param string $meetingid
1242
 * @param boolean $updatecache
1243
 *
1244
 * @return array
1245
 */
1246
function bigbluebuttonbn_get_meeting_info($meetingid, $updatecache = false) {
1247
    $cachettl = (int) \mod_bigbluebuttonbn\locallib\config::get('waitformoderator_cache_ttl');
1248
    $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'mod_bigbluebuttonbn', 'meetings_cache');
1249
    $result = $cache->get($meetingid);
1250
    $now = time();
1251
    if (!$updatecache && !empty($result) && $now < ($result['creation_time'] + $cachettl)) {
1252
        // Use the value in the cache.
1253
        return (array) json_decode($result['meeting_info']);
1254
    }
1255
    // Ping again and refresh the cache.
1256
    $meetinginfo = (array) bigbluebuttonbn_wrap_xml_load_file(
1257
        \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('getMeetingInfo', ['meetingID' => $meetingid])
1258
    );
1259
    $cache->set($meetingid, array('creation_time' => time(), 'meeting_info' => json_encode($meetinginfo)));
1260
    return $meetinginfo;
1261
}
1262
1263
/**
1264
 * Perform isMeetingRunning on BBB.
1265
 *
1266
 * @param string $meetingid
1267
 * @param boolean $updatecache
1268
 *
1269
 * @return boolean
1270
 */
1271
function bigbluebuttonbn_is_meeting_running($meetingid, $updatecache = false) {
1272
    /* As a workaround to isMeetingRunning that always return SUCCESS but only returns true
1273
     * when at least one user is in the session, we use getMeetingInfo instead.
1274
     */
1275
    $meetinginfo = bigbluebuttonbn_get_meeting_info($meetingid, $updatecache);
1276
    return ($meetinginfo['returncode'] === 'SUCCESS');
1277
}
1278
1279
/**
1280
 * Publish an imported recording.
1281
 *
1282
 * @param string $id
1283
 * @param boolean $publish
1284
 *
1285
 * @return boolean
1286
 */
1287 View Code Duplication
function bigbluebuttonbn_publish_recording_imported($id, $publish = true) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1288
    global $DB;
1289
    // Locate the record to be updated.
1290
    $record = $DB->get_record('bigbluebuttonbn_logs', array('id' => $id));
1291
    $meta = json_decode($record->meta, true);
1292
    // Prepare data for the update.
1293
    $meta['recording']['published'] = ($publish) ? 'true' : 'false';
1294
    $record->meta = json_encode($meta);
1295
    // Proceed with the update.
1296
    $DB->update_record('bigbluebuttonbn_logs', $record);
1297
    return true;
1298
}
1299
1300
/**
1301
 * Delete an imported recording.
1302
 *
1303
 * @param string $id
1304
 *
1305
 * @return boolean
1306
 */
1307
function bigbluebuttonbn_delete_recording_imported($id) {
1308
    global $DB;
1309
    // Execute delete.
1310
    $DB->delete_records('bigbluebuttonbn_logs', array('id' => $id));
1311
    return true;
1312
}
1313
1314
/**
1315
 * Update an imported recording.
1316
 *
1317
 * @param string $id
1318
 * @param array $params ['key'=>param_key, 'value']
1319
 *
1320
 * @return boolean
1321
 */
1322
function bigbluebuttonbn_update_recording_imported($id, $params) {
1323
    global $DB;
1324
    // Locate the record to be updated.
1325
    $record = $DB->get_record('bigbluebuttonbn_logs', array('id' => $id));
1326
    $meta = json_decode($record->meta, true);
1327
    // Prepare data for the update.
1328
    $meta['recording'] = $params + $meta['recording'];
1329
    $record->meta = json_encode($meta);
1330
    // Proceed with the update.
1331
    if (!$DB->update_record('bigbluebuttonbn_logs', $record)) {
1332
        return false;
1333
    }
1334
    return true;
1335
}
1336
1337
/**
1338
 * Protect/Unprotect an imported recording.
1339
 *
1340
 * @param string $id
1341
 * @param boolean $protect
1342
 *
1343
 * @return boolean
1344
 */
1345 View Code Duplication
function bigbluebuttonbn_protect_recording_imported($id, $protect = true) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1346
    global $DB;
1347
    // Locate the record to be updated.
1348
    $record = $DB->get_record('bigbluebuttonbn_logs', array('id' => $id));
1349
    $meta = json_decode($record->meta, true);
1350
    // Prepare data for the update.
1351
    $meta['recording']['protected'] = ($protect) ? 'true' : 'false';
1352
    $record->meta = json_encode($meta);
1353
    // Proceed with the update.
1354
    $DB->update_record('bigbluebuttonbn_logs', $record);
1355
    return true;
1356
}
1357
1358
/**
1359
 * Sets a custom config.xml file for being used on create.
1360
 *
1361
 * @param string $meetingid
1362
 * @param string $configxml
1363
 *
1364
 * @return object
1365
 */
1366
function bigbluebuttonbn_set_config_xml($meetingid, $configxml) {
1367
    $urldefaultconfig = \mod_bigbluebuttonbn\locallib\config::get('server_url') . 'api/setConfigXML?';
1368
    $configxmlparams = bigbluebuttonbn_set_config_xml_params($meetingid, $configxml);
1369
    $xml = bigbluebuttonbn_wrap_xml_load_file(
1370
        $urldefaultconfig,
1371
        'POST',
1372
        $configxmlparams,
1373
        'application/x-www-form-urlencoded'
1374
    );
1375
    return $xml;
1376
}
1377
1378
/**
1379
 * Sets qs used with a custom config.xml file request.
1380
 *
1381
 * @param string $meetingid
1382
 * @param string $configxml
1383
 *
1384
 * @return string
1385
 */
1386
function bigbluebuttonbn_set_config_xml_params($meetingid, $configxml) {
1387
    $params = 'configXML=' . urlencode($configxml) . '&meetingID=' . urlencode($meetingid);
1388
    $sharedsecret = \mod_bigbluebuttonbn\locallib\config::get('shared_secret');
1389
    $configxmlparams = $params . '&checksum=' . sha1('setConfigXML' . $params . $sharedsecret);
1390
    return $configxmlparams;
1391
}
1392
1393
/**
1394
 * Sets a custom config.xml file for being used on create.
1395
 *
1396
 * @param string $meetingid
1397
 * @param string $configxml
1398
 *
1399
 * @return array
1400
 */
1401
function bigbluebuttonbn_set_config_xml_array($meetingid, $configxml) {
1402
    $configxml = bigbluebuttonbn_set_config_xml($meetingid, $configxml);
1403
    $configxmlarray = (array) $configxml;
1404
    if ($configxmlarray['returncode'] != 'SUCCESS') {
1405
        debugging('BigBlueButton was not able to set the custom config.xml file', DEBUG_DEVELOPER);
1406
        return '';
1407
    }
1408
    return $configxmlarray['configToken'];
1409
}
1410
1411
/**
1412
 * Helper function builds a row for the data used by the recording table.
1413
 *
1414
 * @param array $bbbsession
1415
 * @param array $recording
1416
 * @param array $tools
1417
 *
1418
 * @return array
1419
 */
1420
function bigbluebuttonbn_get_recording_data_row($bbbsession, $recording, $tools = ['protect', 'publish', 'delete']) {
1421
    if (!bigbluebuttonbn_include_recording_table_row($bbbsession, $recording)) {
1422
        return;
1423
    }
1424
    $rowdata = new stdClass();
1425
    // Set recording_types.
1426
    $rowdata->playback = bigbluebuttonbn_get_recording_data_row_types($recording, $bbbsession);
1427
    // Set activity name.
1428
    $rowdata->recording = bigbluebuttonbn_get_recording_data_row_meta_activity($recording, $bbbsession);
1429
    // Set activity description.
1430
    $rowdata->description = bigbluebuttonbn_get_recording_data_row_meta_description($recording, $bbbsession);
1431
    if (bigbluebuttonbn_get_recording_data_preview_enabled($bbbsession)) {
1432
        // Set recording_preview.
1433
        $rowdata->preview = bigbluebuttonbn_get_recording_data_row_preview($recording);
1434
    }
1435
    // Set date.
1436
    $rowdata->date = bigbluebuttonbn_get_recording_data_row_date($recording);
1437
    // Set formatted date.
1438
    $rowdata->date_formatted = bigbluebuttonbn_get_recording_data_row_date_formatted($rowdata->date);
1439
    // Set formatted duration.
1440
    $rowdata->duration_formatted = $rowdata->duration = bigbluebuttonbn_get_recording_data_row_duration($recording);
1441
    // Set actionbar, if user is allowed to manage recordings.
1442
    if ($bbbsession['managerecordings']) {
1443
        $rowdata->actionbar = bigbluebuttonbn_get_recording_data_row_actionbar($recording, $tools);
1444
    }
1445
    return $rowdata;
1446
}
1447
1448
/**
1449
 * Helper function evaluates if a row for the data used by the recording table is editable.
1450
 *
1451
 * @param array $bbbsession
1452
 *
1453
 * @return boolean
1454
 */
1455
function bigbluebuttonbn_get_recording_data_row_editable($bbbsession) {
1456
    return ($bbbsession['managerecordings'] && ((double) $bbbsession['serverversion'] >= 1.0 || $bbbsession['bnserver']));
1457
}
1458
1459
/**
1460
 * Helper function evaluates if recording preview should be included.
1461
 *
1462
 * @param array $bbbsession
1463
 *
1464
 * @return boolean
1465
 */
1466
function bigbluebuttonbn_get_recording_data_preview_enabled($bbbsession) {
1467
    return ((double) $bbbsession['serverversion'] >= 1.0 && $bbbsession['bigbluebuttonbn']->recordings_preview == '1');
1468
}
1469
1470
/**
1471
 * Helper function converts recording date used in row for the data used by the recording table.
1472
 *
1473
 * @param array $recording
1474
 *
1475
 * @return integer
1476
 */
1477
function bigbluebuttonbn_get_recording_data_row_date($recording) {
1478
    if (!isset($recording['startTime'])) {
1479
        return 0;
1480
    }
1481
    return floatval($recording['startTime']);
1482
}
1483
1484
/**
1485
 * Helper function format recording date used in row for the data used by the recording table.
1486
 *
1487
 * @param integer $starttime
1488
 *
1489
 * @return string
1490
 */
1491
function bigbluebuttonbn_get_recording_data_row_date_formatted($starttime) {
1492
    global $USER;
1493
    $starttime = $starttime - ($starttime % 1000);
1494
    // Set formatted date.
1495
    $dateformat = get_string('strftimerecentfull', 'langconfig') . ' %Z';
1496
    return userdate($starttime / 1000, $dateformat, usertimezone($USER->timezone));
1497
}
1498
1499
/**
1500
 * Helper function converts recording duration used in row for the data used by the recording table.
1501
 *
1502
 * @param array $recording
1503
 *
1504
 * @return integer
1505
 */
1506
function bigbluebuttonbn_get_recording_data_row_duration($recording) {
1507
    foreach (array_values($recording['playbacks']) as $playback) {
1508
        // Ignore restricted playbacks.
1509
        if (array_key_exists('restricted', $playback) && strtolower($playback['restricted']) == 'true') {
1510
            continue;
1511
        }
1512
        // Take the lenght form the fist playback with an actual value.
1513
        if (!empty($playback['length'])) {
1514
            return intval($playback['length']);
1515
        }
1516
    }
1517
    return 0;
1518
}
1519
1520
/**
1521
 * Helper function builds recording actionbar used in row for the data used by the recording table.
1522
 *
1523
 * @param array $recording
1524
 * @param array $tools
1525
 *
1526
 * @return string
1527
 */
1528
function bigbluebuttonbn_get_recording_data_row_actionbar($recording, $tools) {
1529
    $actionbar = '';
1530
    foreach ($tools as $tool) {
1531
        $buttonpayload = bigbluebuttonbn_get_recording_data_row_actionbar_payload($recording, $tool);
1532
        if ($tool == 'protect') {
1533
            if (isset($recording['imported'])) {
1534
                $buttonpayload['disabled'] = 'disabled';
1535
            }
1536
            if (!isset($recording['protected'])) {
1537
                $buttonpayload['disabled'] = 'invisible';
1538
            }
1539
        }
1540
        $actionbar .= bigbluebuttonbn_actionbar_render_button($recording, $buttonpayload);
1541
    }
1542
    $head = html_writer::start_tag('div', array(
1543
        'id' => 'recording-actionbar-' . $recording['recordID'],
1544
        'data-recordingid' => $recording['recordID'],
1545
        'data-meetingid' => $recording['meetingID']));
1546
    $tail = html_writer::end_tag('div');
1547
    return $head . $actionbar . $tail;
1548
}
1549
1550
/**
1551
 * Helper function returns the corresponding payload for an actionbar button used in row
1552
 * for the data used by the recording table.
1553
 *
1554
 * @param array $recording
1555
 * @param array $tool
1556
 *
1557
 * @return array
1558
 */
1559
function bigbluebuttonbn_get_recording_data_row_actionbar_payload($recording, $tool) {
1560
    if ($tool == 'protect') {
1561
        $protected = 'false';
1562
        if (isset($recording['protected'])) {
1563
            $protected = $recording['protected'];
1564
        }
1565
        return bigbluebuttonbn_get_recording_data_row_action_protect($protected);
1566
    }
1567
    if ($tool == 'publish') {
1568
        return bigbluebuttonbn_get_recording_data_row_action_publish($recording['published']);
1569
    }
1570
    return array('action' => $tool, 'tag' => $tool);
1571
}
1572
1573
/**
1574
 * Helper function returns the payload for protect action button used in row
1575
 * for the data used by the recording table.
1576
 *
1577
 * @param string $protected
1578
 *
1579
 * @return array
1580
 */
1581
function bigbluebuttonbn_get_recording_data_row_action_protect($protected) {
1582
    if ($protected == 'true') {
1583
        return array('action' => 'unprotect', 'tag' => 'lock');
1584
    }
1585
    return array('action' => 'protect', 'tag' => 'unlock');
1586
}
1587
1588
/**
1589
 * Helper function returns the payload for publish action button used in row
1590
 * for the data used by the recording table.
1591
 *
1592
 * @param string $published
1593
 *
1594
 * @return array
1595
 */
1596
function bigbluebuttonbn_get_recording_data_row_action_publish($published) {
1597
    if ($published == 'true') {
1598
        return array('action' => 'unpublish', 'tag' => 'hide');
1599
    }
1600
    return array('action' => 'publish', 'tag' => 'show');
1601
}
1602
1603
/**
1604
 * Helper function builds recording preview used in row for the data used by the recording table.
1605
 *
1606
 * @param array $recording
1607
 *
1608
 * @return string
1609
 */
1610
function bigbluebuttonbn_get_recording_data_row_preview($recording) {
1611
    $options = array('id' => 'preview-' . $recording['recordID']);
1612
    if ($recording['published'] === 'false') {
1613
        $options['hidden'] = 'hidden';
1614
    }
1615
    $recordingpreview = html_writer::start_tag('div', $options);
1616
    foreach ($recording['playbacks'] as $playback) {
1617
        if (isset($playback['preview'])) {
1618
            $recordingpreview .= bigbluebuttonbn_get_recording_data_row_preview_images($playback);
1619
            break;
1620
        }
1621
    }
1622
    $recordingpreview .= html_writer::end_tag('div');
1623
    return $recordingpreview;
1624
}
1625
1626
/**
1627
 * Helper function builds element with actual images used in recording preview row based on a selected playback.
1628
 *
1629
 * @param array $playback
1630
 *
1631
 * @return string
1632
 */
1633
function bigbluebuttonbn_get_recording_data_row_preview_images($playback) {
1634
    global $CFG;
1635
    $recordingpreview  = html_writer::start_tag('div', array('class' => 'container-fluid'));
1636
    $recordingpreview .= html_writer::start_tag('div', array('class' => 'row'));
1637
    foreach ($playback['preview'] as $image) {
1638
        if ($CFG->bigbluebuttonbn_recordings_validate_url && !bigbluebuttonbn_is_valid_resource(trim($image['url']))) {
1639
            return '';
1640
        }
1641
        $recordingpreview .= html_writer::start_tag('div', array('class' => ''));
1642
        $recordingpreview .= html_writer::empty_tag(
1643
            'img',
1644
            array('src' => trim($image['url']) . '?' . time(), 'class' => 'recording-thumbnail pull-left')
1645
        );
1646
        $recordingpreview .= html_writer::end_tag('div');
1647
    }
1648
    $recordingpreview .= html_writer::end_tag('div');
1649
    $recordingpreview .= html_writer::start_tag('div', array('class' => 'row'));
1650
    $recordingpreview .= html_writer::tag(
1651
        'div',
1652
        get_string('view_recording_preview_help', 'bigbluebuttonbn'),
1653
        array('class' => 'text-center text-muted small')
1654
    );
1655
    $recordingpreview .= html_writer::end_tag('div');
1656
    $recordingpreview .= html_writer::end_tag('div');
1657
    return $recordingpreview;
1658
}
1659
1660
/**
1661
 * Helper function renders recording types to be used in row for the data used by the recording table.
1662
 *
1663
 * @param array $recording
1664
 * @param array $bbbsession
1665
 *
1666
 * @return string
1667
 */
1668
function bigbluebuttonbn_get_recording_data_row_types($recording, $bbbsession) {
1669
    $dataimported = 'false';
1670
    $title = '';
1671
    if (isset($recording['imported'])) {
1672
        $dataimported = 'true';
1673
        $title = get_string('view_recording_link_warning', 'bigbluebuttonbn');
1674
    }
1675
    $visibility = '';
1676
    if ($recording['published'] === 'false') {
1677
        $visibility = 'hidden ';
1678
    }
1679
    $id = 'playbacks-' . $recording['recordID'];
1680
    $recordingtypes = html_writer::start_tag('div', array('id' => $id, 'data-imported' => $dataimported,
1681
        'data-meetingid' => $recording['meetingID'], 'data-recordingid' => $recording['recordID'],
1682
        'title' => $title, $visibility => $visibility));
1683
    foreach ($recording['playbacks'] as $playback) {
1684
        $recordingtypes .= bigbluebuttonbn_get_recording_data_row_type($recording, $bbbsession, $playback);
1685
    }
1686
    $recordingtypes .= html_writer::end_tag('div');
1687
    return $recordingtypes;
1688
}
1689
1690
/**
1691
 * Helper function renders the link used for recording type in row for the data used by the recording table.
1692
 *
1693
 * @param array $recording
1694
 * @param array $bbbsession
1695
 * @param array $playback
1696
 *
1697
 * @return string
1698
 */
1699
function bigbluebuttonbn_get_recording_data_row_type($recording, $bbbsession, $playback) {
1700
    global $CFG, $OUTPUT;
1701
    if (!bigbluebuttonbn_include_recording_data_row_type($recording, $bbbsession, $playback)) {
1702
        return '';
1703
    }
1704
    $text = bigbluebuttonbn_get_recording_type_text($playback['type']);
1705
    $href = $CFG->wwwroot . '/mod/bigbluebuttonbn/bbb_view.php?action=play&bn=' . $bbbsession['bigbluebuttonbn']->id .
1706
        '&mid=' . $recording['meetingID'] . '&rid=' . $recording['recordID'] . '&rtype=' . $playback['type'];
1707
    if (!isset($recording['imported']) || !isset($recording['protected']) || $recording['protected'] === 'false') {
1708
        $href .= '&href=' . urlencode(trim($playback['url']));
1709
    }
1710
    $linkattributes = array(
1711
        'id' => 'recording-play-' . $playback['type'] . '-' . $recording['recordID'],
1712
        'class' => 'btn btn-sm btn-default',
1713
        'onclick' => 'M.mod_bigbluebuttonbn.recordings.recordingPlay(this);',
1714
        'data-action' => 'play',
1715
        'data-target' => $playback['type'],
1716
        'data-href' => $href,
1717
      );
1718
    if ($CFG->bigbluebuttonbn_recordings_validate_url && !bigbluebuttonbn_is_bn_server()
1719
            && !bigbluebuttonbn_is_valid_resource(trim($playback['url']))) {
1720
        $linkattributes['class'] = 'btn btn-sm btn-warning';
1721
        $linkattributes['title'] = get_string('view_recording_format_errror_unreachable', 'bigbluebuttonbn');
1722
        unset($linkattributes['data-href']);
1723
    }
1724
    return $OUTPUT->action_link('#', $text, null, $linkattributes) . '&#32;';
1725
}
1726
1727
/**
1728
 * Helper function to handle yet unknown recording types
1729
 *
1730
 * @param string $playbacktype : for now presentation, video, statistics, capture, notes, podcast
1731
 *
1732
 * @return string the matching language string or a capitalised version of the provided string
1733
 */
1734
function bigbluebuttonbn_get_recording_type_text($playbacktype) {
1735
    // Check first if string exists, and if it does'nt just default to the capitalised version of the string.
1736
    $text = ucwords($playbacktype);
1737
    $typestringid = 'view_recording_format_' . $playbacktype;
1738
    if (get_string_manager()->string_exists($typestringid, 'bigbluebuttonbn')) {
1739
        $text = get_string($typestringid, 'bigbluebuttonbn');
1740
    }
1741
    return $text;
1742
}
1743
1744
/**
1745
 * Helper function validates a remote resource.
1746
 *
1747
 * @param string $url
1748
 *
1749
 * @return boolean
1750
 */
1751
function bigbluebuttonbn_is_valid_resource($url) {
1752
    $urlhost = parse_url($url, PHP_URL_HOST);
1753
    $serverurlhost = parse_url(\mod_bigbluebuttonbn\locallib\config::get('server_url'), PHP_URL_HOST);
1754
    // Skip validation when the recording URL host is the same as the configured BBB server.
1755
    if ($urlhost == $serverurlhost) {
1756
        return true;
1757
    }
1758
    // Skip validation when the recording URL was already validated.
1759
    $validatedurls = bigbluebuttonbn_cache_get('recordings_cache', 'validated_urls', array());
0 ignored issues
show
Documentation introduced by
array() is of type array, but the function expects a integer|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1760
    if (array_key_exists($urlhost, $validatedurls)) {
1761
        return $validatedurls[$urlhost];
1762
    }
1763
    // Validate the recording URL.
1764
    $validatedurls[$urlhost] = true;
1765
    $curlinfo = bigbluebuttonbn_wrap_xml_load_file_curl_request($url, 'HEAD');
1766
    if (!isset($curlinfo['http_code']) || $curlinfo['http_code'] != 200) {
1767
        $error = "Resources hosted by " . $urlhost . " are unreachable. Server responded with code " . $curlinfo['http_code'];
1768
        debugging($error, DEBUG_DEVELOPER);
1769
        $validatedurls[$urlhost] = false;
1770
    }
1771
    bigbluebuttonbn_cache_set('recordings_cache', 'validated_urls', $validatedurls);
1772
    return $validatedurls[$urlhost];
1773
}
1774
1775
/**
1776
 * Helper function renders the name for meeting used in row for the data used by the recording table.
1777
 *
1778
 * @param array $recording
1779
 * @param array $bbbsession
1780
 *
1781
 * @return string
1782
 */
1783
function bigbluebuttonbn_get_recording_data_row_meeting($recording, $bbbsession) {
0 ignored issues
show
Unused Code introduced by
The parameter $bbbsession is not used and could be removed.

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

Loading history...
1784
    $payload = array();
1785
    $source = 'meetingName';
1786
    $metaname = trim($recording['meetingName']);
1787
    return bigbluebuttonbn_get_recording_data_row_text($recording, $metaname, $source, $payload);
1788
}
1789
1790
/**
1791
 * Helper function renders the name for recording used in row for the data used by the recording table.
1792
 *
1793
 * @param array $recording
1794
 * @param array $bbbsession
1795
 *
1796
 * @return string
1797
 */
1798
function bigbluebuttonbn_get_recording_data_row_meta_activity($recording, $bbbsession) {
1799
    $payload = array();
1800 View Code Duplication
    if (bigbluebuttonbn_get_recording_data_row_editable($bbbsession)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1801
        $payload = array('recordingid' => $recording['recordID'], 'meetingid' => $recording['meetingID'],
1802
            'action' => 'edit', 'tag' => 'edit',
1803
            'target' => 'name');
1804
    }
1805
    $oldsource = 'meta_contextactivity';
1806
    if (isset($recording[$oldsource])) {
1807
        $metaname = trim($recording[$oldsource]);
1808
        return bigbluebuttonbn_get_recording_data_row_text($recording, $metaname, $oldsource, $payload);
1809
    }
1810
    $newsource = 'meta_bbb-recording-name';
1811 View Code Duplication
    if (isset($recording[$newsource])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1812
        $metaname = trim($recording[$newsource]);
1813
        return bigbluebuttonbn_get_recording_data_row_text($recording, $metaname, $newsource, $payload);
1814
    }
1815
    $metaname = trim($recording['meetingName']);
1816
    return bigbluebuttonbn_get_recording_data_row_text($recording, $metaname, $newsource, $payload);
1817
}
1818
1819
/**
1820
 * Helper function renders the description for recording used in row for the data used by the recording table.
1821
 *
1822
 * @param array $recording
1823
 * @param array $bbbsession
1824
 *
1825
 * @return string
1826
 */
1827
function bigbluebuttonbn_get_recording_data_row_meta_description($recording, $bbbsession) {
1828
    $payload = array();
1829 View Code Duplication
    if (bigbluebuttonbn_get_recording_data_row_editable($bbbsession)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1830
        $payload = array('recordingid' => $recording['recordID'], 'meetingid' => $recording['meetingID'],
1831
            'action' => 'edit', 'tag' => 'edit',
1832
            'target' => 'description');
1833
    }
1834
    $oldsource = 'meta_contextactivitydescription';
1835 View Code Duplication
    if (isset($recording[$oldsource])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1836
        $metadescription = trim($recording[$oldsource]);
1837
        return bigbluebuttonbn_get_recording_data_row_text($recording, $metadescription, $oldsource, $payload);
1838
    }
1839
    $newsource = 'meta_bbb-recording-description';
1840 View Code Duplication
    if (isset($recording[$newsource])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
1841
        $metadescription = trim($recording[$newsource]);
1842
        return bigbluebuttonbn_get_recording_data_row_text($recording, $metadescription, $newsource, $payload);
1843
    }
1844
    return bigbluebuttonbn_get_recording_data_row_text($recording, '', $newsource, $payload);
1845
}
1846
1847
/**
1848
 * Helper function renders text element for recording used in row for the data used by the recording table.
1849
 *
1850
 * @param array $recording
1851
 * @param string $text
1852
 * @param string $source
1853
 * @param array $data
1854
 *
1855
 * @return string
1856
 */
1857
function bigbluebuttonbn_get_recording_data_row_text($recording, $text, $source, $data) {
1858
    $htmltext = '<span>' . htmlentities($text) . '</span>';
1859
    if (empty($data)) {
1860
        return $htmltext;
1861
    }
1862
    $target = $data['action'] . '-' . $data['target'];
1863
    $id = 'recording-' . $target . '-' . $data['recordingid'];
1864
    $attributes = array('id' => $id, 'class' => 'quickeditlink col-md-20',
1865
        'data-recordingid' => $data['recordingid'], 'data-meetingid' => $data['meetingid'],
1866
        'data-target' => $data['target'], 'data-source' => $source);
1867
    $head = html_writer::start_tag('div', $attributes);
1868
    $tail = html_writer::end_tag('div');
1869
    $payload = array('action' => $data['action'], 'tag' => $data['tag'], 'target' => $data['target']);
1870
    $htmllink = bigbluebuttonbn_actionbar_render_button($recording, $payload);
1871
    return $head . $htmltext . $htmllink . $tail;
1872
}
1873
1874
/**
1875
 * Helper function render a button for the recording action bar
1876
 *
1877
 * @param array $recording
1878
 * @param array $data
1879
 *
1880
 * @return string
1881
 */
1882
function bigbluebuttonbn_actionbar_render_button($recording, $data) {
1883
    global $OUTPUT;
1884
    if (empty($data)) {
1885
        return '';
1886
    }
1887
    $target = $data['action'];
1888
    if (isset($data['target'])) {
1889
        $target .= '-' . $data['target'];
1890
    }
1891
    $id = 'recording-' . $target . '-' . $recording['recordID'];
1892
    $onclick = 'M.mod_bigbluebuttonbn.recordings.recording' . ucfirst($data['action']) . '(this); return false;';
1893
    if ((boolean) \mod_bigbluebuttonbn\locallib\config::get('recording_icons_enabled')) {
1894
        // With icon for $manageaction.
1895
        $iconattributes = array('id' => $id, 'class' => 'iconsmall');
1896
        $linkattributes = array(
1897
            'id' => $id,
1898
            'onclick' => $onclick,
1899
            'data-action' => $data['action'],
1900
        );
1901
        if (!isset($recording['imported'])) {
1902
            $linkattributes['data-links'] = bigbluebuttonbn_count_recording_imported_instances(
1903
                $recording['recordID']
1904
            );
1905
        }
1906
        if (isset($data['disabled'])) {
1907
            $iconattributes['class'] .= ' fa-' . $data['disabled'];
1908
            $linkattributes['class'] = 'disabled';
1909
            unset($linkattributes['onclick']);
1910
        }
1911
        $icon = new pix_icon(
1912
            'i/' . $data['tag'],
1913
            get_string('view_recording_list_actionbar_' . $data['action'], 'bigbluebuttonbn'),
1914
            'moodle',
1915
            $iconattributes
1916
        );
1917
        return $OUTPUT->action_icon('#', $icon, null, $linkattributes, false);
1918
    }
1919
    // With text for $manageaction.
1920
    $linkattributes = array('title' => get_string($data['tag']), 'class' => 'btn btn-xs btn-danger',
1921
        'onclick' => $onclick);
1922
    return $OUTPUT->action_link('#', get_string($data['action']), null, $linkattributes);
1923
}
1924
1925
/**
1926
 * Helper function builds the recording table.
1927
 *
1928
 * @param array $bbbsession
1929
 * @param array $recordings
1930
 * @param array $tools
1931
 *
1932
 * @return object
1933
 */
1934
function bigbluebuttonbn_get_recording_table($bbbsession, $recordings, $tools = ['protect', 'publish', 'delete']) {
1935
    global $DB;
1936
    // Declare the table.
1937
    $table = new html_table();
1938
    $table->data = array();
1939
    // Initialize table headers.
1940
    $table->head[] = get_string('view_recording_playback', 'bigbluebuttonbn');
1941
    $table->head[] = get_string('view_recording_name', 'bigbluebuttonbn');
1942
    $table->head[] = get_string('view_recording_description', 'bigbluebuttonbn');
1943
    if (bigbluebuttonbn_get_recording_data_preview_enabled($bbbsession)) {
1944
        $table->head[] = get_string('view_recording_preview', 'bigbluebuttonbn');
1945
    }
1946
    $table->head[] = get_string('view_recording_date', 'bigbluebuttonbn');
1947
    $table->head[] = get_string('view_recording_duration', 'bigbluebuttonbn');
1948
    $table->align = array('left', 'left', 'left', 'left', 'left', 'center');
1949
    $table->size = array('', '', '', '', '', '');
1950
    if ($bbbsession['managerecordings']) {
1951
        $table->head[] = get_string('view_recording_actionbar', 'bigbluebuttonbn');
1952
        $table->align[] = 'left';
1953
        $table->size[] = (count($tools) * 40) . 'px';
1954
    }
1955
    // Get the groups of the user.
1956
    $usergroups = groups_get_all_groups($bbbsession['course']->id, $bbbsession['userID']);
1957
1958
    // Build table content.
1959
    foreach ($recordings as $recording) {
1960
        $meetingid = $recording['meetingID'];
0 ignored issues
show
Unused Code introduced by
$meetingid is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1961
        $shortmeetingid = explode('-', $recording['meetingID']);
1962
        if (isset($shortmeetingid[0])) {
1963
            $meetingid = $shortmeetingid[0];
0 ignored issues
show
Unused Code introduced by
$meetingid is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1964
        }
1965
        // Check if the record belongs to a Visible Group type.
1966
        list($course, $cm) = get_course_and_cm_from_cmid($bbbsession['cm']->id);
0 ignored issues
show
Unused Code introduced by
The assignment to $course is unused. Consider omitting it like so list($first,,$third).

This checks looks for assignemnts to variables using the list(...) function, where not all assigned variables are subsequently used.

Consider the following code example.

<?php

function returnThreeValues() {
    return array('a', 'b', 'c');
}

list($a, $b, $c) = returnThreeValues();

print $a . " - " . $c;

Only the variables $a and $c are used. There was no need to assign $b.

Instead, the list call could have been.

list($a,, $c) = returnThreeValues();
Loading history...
1967
        $groupmode = groups_get_activity_groupmode($cm);
1968
        $displayrow = true;
1969
        if (($groupmode != VISIBLEGROUPS)
1970
                && !$bbbsession['administrator'] && !$bbbsession['moderator']) {
1971
            $groupid = explode('[', $recording['meetingID']);
1972
            if (isset($groupid[1])) {
1973
                // It is a group recording and the user is not moderator/administrator. Recording should not be included by default.
1974
                $displayrow = false;
1975
                $groupid = explode(']', $groupid[1]);
1976
                if (isset($groupid[0])) {
1977
                    foreach ($usergroups as $usergroup) {
1978
                        if ($usergroup->id == $groupid[0]) {
1979
                            // Include recording if the user is in the same group.
1980
                            $displayrow = true;
1981
                        }
1982
                    }
1983
                }
1984
            }
1985
        }
1986
        if ($displayrow) {
1987
            $rowdata = bigbluebuttonbn_get_recording_data_row($bbbsession, $recording, $tools);
1988
            if (!empty($rowdata)) {
1989
                $row = bigbluebuttonbn_get_recording_table_row($bbbsession, $recording, $rowdata);
1990
                array_push($table->data, $row);
1991
            }
1992
        }
1993
    }
1994
    return $table;
1995
}
1996
1997
/**
1998
 * Helper function builds the recording table row and insert into table.
1999
 *
2000
 * @param array $bbbsession
2001
 * @param array $recording
2002
 * @param object $rowdata
2003
 *
2004
 * @return object
2005
 */
2006
function bigbluebuttonbn_get_recording_table_row($bbbsession, $recording, $rowdata) {
2007
    $row = new html_table_row();
2008
    $row->id = 'recording-tr-' . $recording['recordID'];
2009
    $row->attributes['data-imported'] = 'false';
2010
    $texthead = '';
2011
    $texttail = '';
2012
    if (isset($recording['imported'])) {
2013
        $row->attributes['title'] = get_string('view_recording_link_warning', 'bigbluebuttonbn');
2014
        $row->attributes['data-imported'] = 'true';
2015
        $texthead = '<em>';
2016
        $texttail = '</em>';
2017
    }
2018
    $rowdata->date_formatted = str_replace(' ', '&nbsp;', $rowdata->date_formatted);
2019
    $row->cells = array();
2020
    $row->cells[] = $texthead . $rowdata->playback . $texttail;
2021
    $row->cells[] = $texthead . $rowdata->recording . $texttail;
2022
    $row->cells[] = $texthead . $rowdata->description . $texttail;
2023
    if (bigbluebuttonbn_get_recording_data_preview_enabled($bbbsession)) {
2024
        $row->cells[] = $rowdata->preview;
2025
    }
2026
    $row->cells[] = $texthead . $rowdata->date_formatted . $texttail;
2027
    $row->cells[] = $rowdata->duration_formatted;
2028
    if ($bbbsession['managerecordings']) {
2029
        $row->cells[] = $rowdata->actionbar;
2030
    }
2031
    return $row;
2032
}
2033
2034
/**
2035
 * Get the basic data to display in the table view
2036
 *
2037
 * @param array $bbbsession the current session
2038
 * @param array $enabledfeatures feature enabled for this activity
2039
 * @return associative array containing the recordings indexed by recordID, each recording is also a
2040
 * non sequential associative array itself that corresponds to the actual recording in BBB
2041
 */
2042
function bigbluebutton_get_recordings_for_table_view($bbbsession, $enabledfeatures) {
2043
    $bigbluebuttonbnid = null;
2044
    if ($enabledfeatures['showroom']) {
2045
        $bigbluebuttonbnid = $bbbsession['bigbluebuttonbn']->id;
2046
    }
2047
    // Get recordings.
2048
    $recordings = bigbluebuttonbn_get_recordings(
2049
        $bbbsession['course']->id, $bigbluebuttonbnid, $enabledfeatures['showroom'],
2050
        $bbbsession['bigbluebuttonbn']->recordings_deleted
2051
    );
2052
    if ($enabledfeatures['importrecordings']) {
2053
        // Get recording links.
2054
        $bigbluebuttonbnid = $bbbsession['bigbluebuttonbn']->id;
2055
        $recordingsimported = bigbluebuttonbn_get_recordings_imported_array(
2056
            $bbbsession['course']->id, $bigbluebuttonbnid, true
2057
        );
2058
        /* Perform aritmetic addition instead of merge so the imported recordings corresponding to existent
2059
         * recordings are not included. */
2060
        if ($bbbsession['bigbluebuttonbn']->recordings_imported) {
2061
            $recordings = $recordingsimported;
2062
        } else {
2063
            $recordings += $recordingsimported;
2064
        }
2065
    }
2066
    return $recordings;
2067
}
2068
2069
/**
2070
 * Helper function evaluates if recording row should be included in the table.
2071
 *
2072
 * @param array $bbbsession
2073
 * @param array $recording
2074
 *
2075
 * @return boolean
2076
 */
2077
function bigbluebuttonbn_include_recording_table_row($bbbsession, $recording) {
2078
    // Exclude unpublished recordings, only if user has no rights to manage them.
2079
    if ($recording['published'] != 'true' && !$bbbsession['managerecordings']) {
2080
        return false;
2081
    }
2082
    // Imported recordings are always shown as long as they are published.
2083
    if (isset($recording['imported'])) {
2084
        return true;
2085
    }
2086
    // Administrators and moderators are always allowed.
2087
    if ($bbbsession['administrator'] || $bbbsession['moderator']) {
2088
        return true;
2089
    }
2090
    // When groups are enabled, exclude those to which the user doesn't have access to.
2091
    if (isset($bbbsession['group']) && $recording['meetingID'] != $bbbsession['meetingid']) {
2092
        return false;
2093
    }
2094
    return true;
2095
}
2096
2097
/**
2098
 * Helper function triggers a send notification when the recording is ready.
2099
 *
2100
 * @param object $bigbluebuttonbn
2101
 *
2102
 * @return void
2103
 */
2104
function bigbluebuttonbn_send_notification_recording_ready($bigbluebuttonbn) {
2105
    \mod_bigbluebuttonbn\locallib\notifier::notify_recording_ready($bigbluebuttonbn);
2106
}
2107
2108
/**
2109
 * Helper function enqueues list of meeting events to be stored and processed as for completion.
2110
 *
2111
 * @param object $bigbluebuttonbn
2112
 * @param object $jsonobj
2113
 *
2114
 * @return void
2115
 */
2116
function bigbluebuttonbn_process_meeting_events($bigbluebuttonbn, $jsonobj) {
2117
    $meetingid = $jsonobj->{'meeting_id'};
2118
    $recordid = $jsonobj->{'internal_meeting_id'};
2119
    $attendees = $jsonobj->{'data'}->{'attendees'};
2120
    foreach ($attendees as $attendee) {
2121
        $userid = $attendee->{'ext_user_id'};
2122
        $overrides['meetingid'] = $meetingid;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$overrides was never initialized. Although not strictly required by PHP, it is generally a good practice to add $overrides = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
2123
        $overrides['userid'] = $userid;
0 ignored issues
show
Bug introduced by
The variable $overrides does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
2124
        $meta['recordid'] = $recordid;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$meta was never initialized. Although not strictly required by PHP, it is generally a good practice to add $meta = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
2125
        $meta['data'] = $attendee;
2126
        // Stores the log.
2127
        bigbluebuttonbn_log($bigbluebuttonbn, BIGBLUEBUTTON_LOG_EVENT_SUMMARY, $overrides, json_encode($meta));
2128
        // Enqueue a task for processing the completion.
2129
        bigbluebuttonbn_enqueue_completion_update($bigbluebuttonbn, $userid);
2130
    }
2131
}
2132
2133
/**
2134
 * Helper function enqueues one user for being validated as for completion.
2135
 *
2136
 * @param object $bigbluebuttonbn
2137
 * @param string $userid
2138
 *
2139
 * @return void
2140
 */
2141
function bigbluebuttonbn_enqueue_completion_update($bigbluebuttonbn, $userid) {
2142
    try {
2143
        // Create the instance of completion_update_state task.
2144
        $task = new \mod_bigbluebuttonbn\task\completion_update_state();
2145
        // Add custom data.
2146
        $data = array(
2147
            'bigbluebuttonbn' => $bigbluebuttonbn,
2148
            'userid' => $userid,
2149
        );
2150
        $task->set_custom_data($data);
2151
        // CONTRIB-7457: Task should be executed by a user, maybe Teacher as Student won't have rights for overriding.
2152
        // $ task -> set_userid ( $ user -> id );.
2153
        // Enqueue it.
2154
        \core\task\manager::queue_adhoc_task($task);
2155
    } catch (Exception $e) {
2156
        mtrace("Error while enqueuing completion_update_state task. " . (string) $e);
2157
    }
2158
}
2159
2160
/**
2161
 * Helper function enqueues completion trigger.
2162
 *
2163
 * @param object $bigbluebuttonbn
2164
 * @param string $userid
2165
 *
2166
 * @return void
2167
 */
2168
function bigbluebuttonbn_completion_update_state($bigbluebuttonbn, $userid) {
2169
    global $CFG;
2170
    require_once($CFG->libdir.'/completionlib.php');
2171
    list($course, $cm) = get_course_and_cm_from_instance($bigbluebuttonbn, 'bigbluebuttonbn');
2172
    $completion = new completion_info($course);
2173
    if (!$completion->is_enabled($cm)) {
2174
        mtrace("Completion not enabled");
2175
        return;
2176
    }
2177
    if (bigbluebuttonbn_get_completion_state($course, $cm, $userid, COMPLETION_AND)) {
2178
        mtrace("Completion succeeded for user $userid");
2179
        $completion->update_state($cm, COMPLETION_COMPLETE, $userid, true);
2180
    } else {
2181
        mtrace("Completion did not succeed for user $userid");
2182
    }
2183
}
2184
2185
/**
2186
 * Helper evaluates if the bigbluebutton server used belongs to blindsidenetworks domain.
2187
 *
2188
 * @return boolean
2189
 */
2190
function bigbluebuttonbn_is_bn_server() {
2191
    if (\mod_bigbluebuttonbn\locallib\config::get('bn_server')) {
2192
        return true;
2193
    }
2194
    $parsedurl = parse_url(\mod_bigbluebuttonbn\locallib\config::get('server_url'));
2195
    if (!isset($parsedurl['host'])) {
2196
        return false;
2197
    }
2198
    $h = $parsedurl['host'];
2199
    $hends = explode('.', $h);
2200
    $hendslength = count($hends);
2201
    return ($hends[$hendslength - 1] == 'com' && $hends[$hendslength - 2] == 'blindsidenetworks');
2202
}
2203
2204
/**
2205
 * Helper function returns a list of courses a user has access to, wrapped in an array that can be used
2206
 * by a html select.
2207
 *
2208
 * @param array $bbbsession
2209
 *
2210
 * @return array
2211
 */
2212
function bigbluebuttonbn_import_get_courses_for_select(array $bbbsession) {
2213
    if ($bbbsession['administrator']) {
2214
        $courses = get_courses('all', 'c.fullname ASC');
2215
        // It includes the name of the site as a course (category 0), so remove the first one.
2216
        unset($courses['1']);
2217
    } else {
2218
        $courses = enrol_get_users_courses($bbbsession['userID'], false, 'id,shortname,fullname');
2219
    }
2220
    $coursesforselect = [];
2221
    foreach ($courses as $course) {
2222
        $coursesforselect[$course->id] = $course->fullname . " (" . $course->shortname . ")";
2223
    }
2224
    return $coursesforselect;
2225
}
2226
2227
/**
2228
 * Helper function renders recording table.
2229
 *
2230
 * @param array $bbbsession
2231
 * @param array $recordings
2232
 * @param array $tools
2233
 *
2234
 * @return array
2235
 */
2236
function bigbluebuttonbn_output_recording_table($bbbsession, $recordings, $tools = ['protect', 'publish', 'delete']) {
2237
    if (isset($recordings) && !empty($recordings)) {
2238
        // There are recordings for this meeting.
2239
        $table = bigbluebuttonbn_get_recording_table($bbbsession, $recordings, $tools);
2240
    }
2241
    if (!isset($table) || !isset($table->data)) {
2242
        // Render a table with "No recordings".
2243
        return html_writer::div(
2244
            get_string('view_message_norecordings', 'bigbluebuttonbn'),
2245
            '',
2246
            array('id' => 'bigbluebuttonbn_recordings_table')
2247
        );
2248
    }
2249
    // Render the table.
2250
    return html_writer::div(html_writer::table($table), '', array('id' => 'bigbluebuttonbn_recordings_table'));
2251
}
2252
2253
/**
2254
 * Helper function to convert an html string to plain text.
2255
 *
2256
 * @param string $html
2257
 * @param integer $len
2258
 *
2259
 * @return string
2260
 */
2261
function bigbluebuttonbn_html2text($html, $len = 0) {
2262
    $text = strip_tags($html);
2263
    $text = str_replace('&nbsp;', ' ', $text);
2264
    $textlen = strlen($text);
2265
    $text = mb_substr($text, 0, $len);
2266
    if ($textlen > $len) {
2267
        $text .= '...';
2268
    }
2269
    return $text;
2270
}
2271
2272
/**
2273
 * Helper function to obtain the tags linked to a bigbluebuttonbn activity
2274
 *
2275
 * @param string $id
2276
 *
2277
 * @return string containing the tags separated by commas
2278
 */
2279
function bigbluebuttonbn_get_tags($id) {
2280
    if (class_exists('core_tag_tag')) {
2281
        return implode(',', core_tag_tag::get_item_tags_array('core', 'course_modules', $id));
2282
    }
2283
    return implode(',', tag_get_tags('bigbluebuttonbn', $id));
2284
}
2285
2286
/**
2287
 * Helper function to define the sql used for gattering the bigbluebuttonbnids whose meetingids should be included
2288
 * in the getRecordings request
2289
 *
2290
 * @param string $courseid
2291
 * @param string $bigbluebuttonbnid
2292
 * @param bool   $subset
2293
 *
2294
 * @return string containing the sql used for getting the target bigbluebuttonbn instances
2295
 */
2296
function bigbluebuttonbn_get_recordings_sql_select($courseid, $bigbluebuttonbnid = null, $subset = true) {
2297
    if (empty($courseid)) {
2298
        $courseid = 0;
2299
    }
2300
    if (empty($bigbluebuttonbnid)) {
2301
        return "course = '{$courseid}'";
2302
    }
2303
    if ($subset) {
2304
        return "id = '{$bigbluebuttonbnid}'";
2305
    }
2306
    return "id <> '{$bigbluebuttonbnid}' AND course = '{$courseid}'";
2307
}
2308
2309
/**
2310
 * Helper function to define the sql used for gattering the bigbluebuttonbnids whose meetingids should be included
2311
 * in the getRecordings request considering only those that belong to deleted activities.
2312
 *
2313
 * @param string $courseid
2314
 * @param string $bigbluebuttonbnid
2315
 * @param bool   $subset
2316
 *
2317
 * @return string containing the sql used for getting the target bigbluebuttonbn instances
2318
 */
2319 View Code Duplication
function bigbluebuttonbn_get_recordings_deleted_sql_select($courseid = 0, $bigbluebuttonbnid = null, $subset = true) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2320
    $sql = "log = '" . BIGBLUEBUTTONBN_LOG_EVENT_DELETE . "' AND meta like '%has_recordings%' AND meta like '%true%'";
2321
    if (empty($courseid)) {
2322
        $courseid = 0;
2323
    }
2324
    if (empty($bigbluebuttonbnid)) {
2325
        return $sql . " AND courseid = {$courseid}";
2326
    }
2327
    if ($subset) {
2328
        return $sql . " AND bigbluebuttonbnid = '{$bigbluebuttonbnid}'";
2329
    }
2330
    return $sql . " AND courseid = {$courseid} AND bigbluebuttonbnid <> '{$bigbluebuttonbnid}'";
2331
}
2332
2333
/**
2334
 * Helper function to define the sql used for gattering the bigbluebuttonbnids whose meetingids should be included
2335
 * in the getRecordings request considering only those that belong to imported recordings.
2336
 *
2337
 * @param string $courseid
2338
 * @param string $bigbluebuttonbnid
2339
 * @param bool   $subset
2340
 *
2341
 * @return string containing the sql used for getting the target bigbluebuttonbn instances
2342
 */
2343 View Code Duplication
function bigbluebuttonbn_get_recordings_imported_sql_select($courseid = 0, $bigbluebuttonbnid = null, $subset = true) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2344
    $sql = "log = '" . BIGBLUEBUTTONBN_LOG_EVENT_IMPORT . "'";
2345
    if (empty($courseid)) {
2346
        $courseid = 0;
2347
    }
2348
    if (empty($bigbluebuttonbnid)) {
2349
        return $sql . " AND courseid = '{$courseid}'";
2350
    }
2351
    if ($subset) {
2352
        return $sql . " AND bigbluebuttonbnid = '{$bigbluebuttonbnid}'";
2353
    }
2354
    return $sql . " AND courseid = '{$courseid}' AND bigbluebuttonbnid <> '{$bigbluebuttonbnid}'";
2355
}
2356
2357
/**
2358
 * Helper function to get recordings and imported recordings together.
2359
 *
2360
 * @param string $courseid
2361
 * @param string $bigbluebuttonbnid
2362
 * @param bool   $subset
2363
 * @param bool   $includedeleted
2364
 *
2365
 * @return associative array containing the recordings indexed by recordID, each recording is also a
2366
 * non sequential associative array itself that corresponds to the actual recording in BBB
2367
 */
2368
function bigbluebuttonbn_get_allrecordings($courseid = 0, $bigbluebuttonbnid = null, $subset = true, $includedeleted = false) {
2369
    $recordings = bigbluebuttonbn_get_recordings($courseid, $bigbluebuttonbnid, $subset, $includedeleted);
2370
    $recordingsimported = bigbluebuttonbn_get_recordings_imported_array($courseid, $bigbluebuttonbnid, $subset);
2371
    return ($recordings + $recordingsimported);
2372
}
2373
2374
/**
2375
 * Helper function to retrieve recordings from the BigBlueButton. The references are stored as events
2376
 * in bigbluebuttonbn_logs.
2377
 *
2378
 * @param string $courseid
2379
 * @param string $bigbluebuttonbnid
2380
 * @param bool   $subset
2381
 * @param bool   $includedeleted
2382
 *
2383
 * @return associative array containing the recordings indexed by recordID, each recording is also a
2384
 * non sequential associative array itself that corresponds to the actual recording in BBB
2385
 */
2386
function bigbluebuttonbn_get_recordings($courseid = 0, $bigbluebuttonbnid = null, $subset = true, $includedeleted = false) {
2387
    global $DB;
2388
    $select = bigbluebuttonbn_get_recordings_sql_select($courseid, $bigbluebuttonbnid, $subset);
2389
    $bigbluebuttonbns = $DB->get_records_select_menu('bigbluebuttonbn', $select, null, 'id', 'id, meetingid');
2390
    /* Consider logs from deleted bigbluebuttonbn instances whose meetingids should be included in
2391
     * the getRecordings request. */
2392
    if ($includedeleted) {
2393
        $selectdeleted = bigbluebuttonbn_get_recordings_deleted_sql_select($courseid, $bigbluebuttonbnid, $subset);
2394
        $bigbluebuttonbnsdel = $DB->get_records_select_menu(
2395
            'bigbluebuttonbn_logs',
2396
            $selectdeleted,
2397
            null,
2398
            'bigbluebuttonbnid',
2399
            'bigbluebuttonbnid, meetingid'
2400
        );
2401
        if (!empty($bigbluebuttonbnsdel)) {
2402
            // Merge bigbluebuttonbnis from deleted instances, only keys are relevant.
2403
            // Artimetic merge is used in order to keep the keys.
2404
            $bigbluebuttonbns += $bigbluebuttonbnsdel;
2405
        }
2406
    }
2407
    // Gather the meetingids from bigbluebuttonbn logs that include a create with record=true.
2408
    if (empty($bigbluebuttonbns)) {
2409
        return array();
2410
    }
2411
    // Prepare select for loading records based on existent bigbluebuttonbns.
2412
    $sql = 'SELECT DISTINCT meetingid, bigbluebuttonbnid FROM {bigbluebuttonbn_logs} WHERE ';
2413
    $sql .= '(bigbluebuttonbnid=' . implode(' OR bigbluebuttonbnid=', array_keys($bigbluebuttonbns)) . ')';
2414
    // Include only Create events and exclude those with record not true.
2415
    $sql .= ' AND log = ? AND meta LIKE ? AND meta LIKE ?';
2416
    // Execute select for loading records based on existent bigbluebuttonbns.
2417
    $records = $DB->get_records_sql_menu($sql, array(BIGBLUEBUTTONBN_LOG_EVENT_CREATE, '%record%', '%true%'));
2418
    // Get actual recordings.
2419
    return bigbluebuttonbn_get_recordings_array(array_keys($records));
2420
}
2421
2422
/**
2423
 * Helper function iterates an array with recordings and unset those already imported.
2424
 *
2425
 * @param array $recordings
2426
 * @param integer $courseid
2427
 * @param integer $bigbluebuttonbnid
2428
 *
2429
 * @return array
2430
 */
2431
function bigbluebuttonbn_unset_existent_recordings_already_imported($recordings, $courseid, $bigbluebuttonbnid) {
2432
    $recordingsimported = bigbluebuttonbn_get_recordings_imported_array($courseid, $bigbluebuttonbnid, true);
2433
    foreach ($recordings as $key => $recording) {
2434
        if (isset($recordingsimported[$recording['recordID']])) {
2435
            unset($recordings[$key]);
2436
        }
2437
    }
2438
    return $recordings;
2439
}
2440
2441
/**
2442
 * Helper function to count the imported recordings for a recordingid.
2443
 *
2444
 * @param string $recordid
2445
 *
2446
 * @return integer
2447
 */
2448
function bigbluebuttonbn_count_recording_imported_instances($recordid) {
2449
    global $DB;
2450
    $sql = 'SELECT COUNT(DISTINCT id) FROM {bigbluebuttonbn_logs} WHERE log = ? AND meta LIKE ? AND meta LIKE ?';
2451
    return $DB->count_records_sql($sql, array(BIGBLUEBUTTONBN_LOG_EVENT_IMPORT, '%recordID%', "%{$recordid}%"));
2452
}
2453
2454
/**
2455
 * Helper function returns an array with all the instances of imported recordings for a recordingid.
2456
 *
2457
 * @param string $recordid
2458
 *
2459
 * @return array
2460
 */
2461
function bigbluebuttonbn_get_recording_imported_instances($recordid) {
2462
    global $DB;
2463
    $sql = 'SELECT * FROM {bigbluebuttonbn_logs} WHERE log = ? AND meta LIKE ? AND meta LIKE ?';
2464
    $recordingsimported = $DB->get_records_sql($sql, array(BIGBLUEBUTTONBN_LOG_EVENT_IMPORT, '%recordID%',
2465
        "%{$recordid}%"));
2466
    return $recordingsimported;
2467
}
2468
2469
/**
2470
 * Helper function to get how much callback events are logged.
2471
 *
2472
 * @param string $recordid
2473
 * @param string $callbacktype
2474
 *
2475
 * @return integer
2476
 */
2477
function bigbluebuttonbn_get_count_callback_event_log($recordid, $callbacktype = 'recording_ready') {
2478
    global $DB;
2479
    $sql = 'SELECT count(DISTINCT id) FROM {bigbluebuttonbn_logs} WHERE log = ? AND meta LIKE ? AND meta LIKE ?';
2480
    // Callback type added on version 2.4, validate recording_ready first or assume it on records with no callback.
2481
    if ($callbacktype == 'recording_ready') {
2482
        $sql .= ' AND (meta LIKE ? OR meta NOT LIKE ? )';
2483
        $count = $DB->count_records_sql($sql, array(BIGBLUEBUTTON_LOG_EVENT_CALLBACK, '%recordid%', "%$recordid%",
2484
            $callbacktype, 'callback'));
2485
        return $count;
2486
    }
2487
    $sql .= ' AND meta LIKE ?;';
2488
    $count = $DB->count_records_sql($sql, array(BIGBLUEBUTTON_LOG_EVENT_CALLBACK, '%recordid%', "%$recordid%", "%$callbacktype%"));
2489
    return $count;
2490
}
2491
2492
/**
2493
 * Helper function returns an array with the profiles (with features per profile) for the different types
2494
 * of bigbluebuttonbn instances.
2495
 *
2496
 * @return array
2497
 */
2498
function bigbluebuttonbn_get_instance_type_profiles() {
2499
    $instanceprofiles = array(
2500
        BIGBLUEBUTTONBN_TYPE_ALL => array('id' => BIGBLUEBUTTONBN_TYPE_ALL,
2501
            'name' => get_string('instance_type_default', 'bigbluebuttonbn'),
2502
            'features' => array('all')),
2503
        BIGBLUEBUTTONBN_TYPE_ROOM_ONLY => array('id' => BIGBLUEBUTTONBN_TYPE_ROOM_ONLY,
2504
            'name' => get_string('instance_type_room_only', 'bigbluebuttonbn'),
2505
            'features' => array('showroom', 'welcomemessage', 'voicebridge', 'waitformoderator', 'userlimit',
2506
                'recording', 'sendnotifications', 'preuploadpresentation', 'permissions', 'schedule', 'groups',
2507
                'modstandardelshdr', 'availabilityconditionsheader', 'tagshdr', 'competenciessection',
2508
                'clienttype', 'completionattendance', 'completionengagement', 'availabilityconditionsheader')),
2509
        BIGBLUEBUTTONBN_TYPE_RECORDING_ONLY => array('id' => BIGBLUEBUTTONBN_TYPE_RECORDING_ONLY,
2510
            'name' => get_string('instance_type_recording_only', 'bigbluebuttonbn'),
2511
            'features' => array('showrecordings', 'importrecordings', 'availabilityconditionsheader')),
2512
    );
2513
    return $instanceprofiles;
2514
}
2515
2516
/**
2517
 * Helper function returns an array with enabled features for an specific profile type.
2518
 *
2519
 * @param array $typeprofiles
2520
 * @param string $type
2521
 *
2522
 * @return array
2523
 */
2524
function bigbluebuttonbn_get_enabled_features($typeprofiles, $type = null) {
2525
    $enabledfeatures = array();
2526
    $features = $typeprofiles[BIGBLUEBUTTONBN_TYPE_ALL]['features'];
2527
    if (!is_null($type) && key_exists($type, $typeprofiles)) {
2528
        $features = $typeprofiles[$type]['features'];
2529
    }
2530
    $enabledfeatures['showroom'] = (in_array('all', $features) || in_array('showroom', $features));
2531
    // Evaluates if recordings are enabled for the Moodle site.
2532
    $enabledfeatures['showrecordings'] = false;
2533
    if (\mod_bigbluebuttonbn\locallib\config::recordings_enabled()) {
2534
        $enabledfeatures['showrecordings'] = (in_array('all', $features) || in_array('showrecordings', $features));
2535
    }
2536
    $enabledfeatures['importrecordings'] = false;
2537
    if (\mod_bigbluebuttonbn\locallib\config::importrecordings_enabled()) {
2538
        $enabledfeatures['importrecordings'] = (in_array('all', $features) || in_array('importrecordings', $features));
2539
    }
2540
    // Evaluates if clienttype is enabled for the Moodle site.
2541
    $enabledfeatures['clienttype'] = false;
2542
    if (\mod_bigbluebuttonbn\locallib\config::clienttype_enabled()) {
2543
        $enabledfeatures['clienttype'] = (in_array('all', $features) || in_array('clienttype', $features));
2544
    }
2545
    return $enabledfeatures;
2546
}
2547
2548
/**
2549
 * Helper function returns an array with the profiles (with features per profile) for the different types
2550
 * of bigbluebuttonbn instances that the user is allowed to create.
2551
 *
2552
 * @param boolean $room
2553
 * @param boolean $recording
2554
 *
2555
 * @return array
2556
 */
2557
function bigbluebuttonbn_get_instance_type_profiles_create_allowed($room, $recording) {
2558
    $profiles = bigbluebuttonbn_get_instance_type_profiles();
2559
    if (!$room) {
2560
        unset($profiles[BIGBLUEBUTTONBN_TYPE_ROOM_ONLY]);
2561
        unset($profiles[BIGBLUEBUTTONBN_TYPE_ALL]);
2562
    }
2563
    if (!$recording) {
2564
        unset($profiles[BIGBLUEBUTTONBN_TYPE_RECORDING_ONLY]);
2565
        unset($profiles[BIGBLUEBUTTONBN_TYPE_ALL]);
2566
    }
2567
    return $profiles;
2568
}
2569
2570
/**
2571
 * Helper function returns an array with the profiles (with features per profile) for the different types
2572
 * of bigbluebuttonbn instances.
2573
 *
2574
 * @param array $profiles
2575
 *
2576
 * @return array
2577
 */
2578
function bigbluebuttonbn_get_instance_profiles_array($profiles = []) {
2579
    $profilesarray = array();
2580
    foreach ($profiles as $key => $profile) {
2581
        $profilesarray[$profile['id']] = $profile['name'];
2582
    }
2583
    return $profilesarray;
2584
}
2585
2586
/**
2587
 * Helper function returns time in a formatted string.
2588
 *
2589
 * @param integer $time
2590
 *
2591
 * @return string
2592
 */
2593
function bigbluebuttonbn_format_activity_time($time) {
2594
    global $CFG;
2595
    require_once($CFG->dirroot.'/calendar/lib.php');
2596
    $activitytime = '';
2597
    if ($time) {
2598
        $activitytime = calendar_day_representation($time) . ' ' .
2599
        get_string('mod_form_field_notification_msg_at', 'bigbluebuttonbn') . ' ' .
2600
        calendar_time_representation($time);
2601
    }
2602
    return $activitytime;
2603
}
2604
2605
/**
2606
 * Helper function returns array with all the strings to be used in javascript.
2607
 *
2608
 * @return array
2609
 */
2610
function bigbluebuttonbn_get_strings_for_js() {
2611
    $locale = bigbluebuttonbn_get_locale();
2612
    $stringman = get_string_manager();
2613
    $strings = $stringman->load_component_strings('bigbluebuttonbn', $locale);
2614
    return $strings;
2615
}
2616
2617
/**
2618
 * Helper function returns the locale set by moodle.
2619
 *
2620
 * @return string
2621
 */
2622
function bigbluebuttonbn_get_locale() {
2623
    $lang = get_string('locale', 'core_langconfig');
2624
    return substr($lang, 0, strpos($lang, '.'));
2625
}
2626
2627
/**
2628
 * Helper function returns the locale code based on the locale set by moodle.
2629
 *
2630
 * @return string
2631
 */
2632
function bigbluebuttonbn_get_localcode() {
2633
    $locale = bigbluebuttonbn_get_locale();
2634
    return substr($locale, 0, strpos($locale, '_'));
2635
}
2636
2637
/**
2638
 * Helper function returns array with the instance settings used in views.
2639
 *
2640
 * @param string $id
2641
 * @param object $bigbluebuttonbnid
2642
 *
2643
 * @return array
2644
 */
2645
function bigbluebuttonbn_view_validator($id, $bigbluebuttonbnid) {
2646
    if ($id) {
2647
        return bigbluebuttonbn_view_instance_id($id);
2648
    }
2649
    if ($bigbluebuttonbnid) {
2650
        return bigbluebuttonbn_view_instance_bigbluebuttonbn($bigbluebuttonbnid);
2651
    }
2652
}
2653
2654
/**
2655
 * Helper function returns array with the instance settings used in views based on id.
2656
 *
2657
 * @param string $id
2658
 *
2659
 * @return array
2660
 */
2661 View Code Duplication
function bigbluebuttonbn_view_instance_id($id) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2662
    global $DB;
2663
    $cm = get_coursemodule_from_id('bigbluebuttonbn', $id, 0, false, MUST_EXIST);
2664
    $course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
2665
    $bigbluebuttonbn = $DB->get_record('bigbluebuttonbn', array('id' => $cm->instance), '*', MUST_EXIST);
2666
    return array('cm' => $cm, 'course' => $course, 'bigbluebuttonbn' => $bigbluebuttonbn);
2667
}
2668
2669
/**
2670
 * Helper function returns array with the instance settings used in views based on bigbluebuttonbnid.
2671
 *
2672
 * @param object $bigbluebuttonbnid
2673
 *
2674
 * @return array
2675
 */
2676 View Code Duplication
function bigbluebuttonbn_view_instance_bigbluebuttonbn($bigbluebuttonbnid) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2677
    global $DB;
2678
    $bigbluebuttonbn = $DB->get_record('bigbluebuttonbn', array('id' => $bigbluebuttonbnid), '*', MUST_EXIST);
2679
    $course = $DB->get_record('course', array('id' => $bigbluebuttonbn->course), '*', MUST_EXIST);
2680
    $cm = get_coursemodule_from_instance('bigbluebuttonbn', $bigbluebuttonbn->id, $course->id, false, MUST_EXIST);
2681
    return array('cm' => $cm, 'course' => $course, 'bigbluebuttonbn' => $bigbluebuttonbn);
2682
}
2683
2684
/**
2685
 * Helper function renders general settings if the feature is enabled.
2686
 *
2687
 * @param object $renderer
2688
 *
2689
 * @return void
2690
 */
2691
function bigbluebuttonbn_settings_general(&$renderer) {
2692
    // Configuration for BigBlueButton.
2693
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_general_shown()) {
2694
        $renderer->render_group_header('general');
2695
        $renderer->render_group_element(
2696
            'server_url',
2697
            $renderer->render_group_element_text('server_url', BIGBLUEBUTTONBN_DEFAULT_SERVER_URL)
2698
        );
2699
        $renderer->render_group_element(
2700
            'shared_secret',
2701
            $renderer->render_group_element_text('shared_secret', BIGBLUEBUTTONBN_DEFAULT_SHARED_SECRET)
2702
        );
2703
    }
2704
}
2705
2706
/**
2707
 * Helper function renders record settings if the feature is enabled.
2708
 *
2709
 * @param object $renderer
2710
 *
2711
 * @return void
2712
 */
2713
function bigbluebuttonbn_settings_record(&$renderer) {
2714
    // Configuration for 'recording' feature.
2715
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_record_meeting_shown()) {
2716
        $renderer->render_group_header('recording');
2717
        $renderer->render_group_element(
2718
            'recording_default',
2719
            $renderer->render_group_element_checkbox('recording_default', 1)
2720
        );
2721
        $renderer->render_group_element(
2722
            'recording_editable',
2723
            $renderer->render_group_element_checkbox('recording_editable', 1)
2724
        );
2725
        $renderer->render_group_element(
2726
            'recording_icons_enabled',
2727
            $renderer->render_group_element_checkbox('recording_icons_enabled', 1)
2728
        );
2729
2730
        // Add recording start to load and allow/hide stop/pause.
2731
        $renderer->render_group_element(
2732
            'recording_all_from_start_default',
2733
            $renderer->render_group_element_checkbox('recording_all_from_start_default', 0)
2734
        );
2735
        $renderer->render_group_element(
2736
            'recording_all_from_start_editable',
2737
            $renderer->render_group_element_checkbox('recording_all_from_start_editable', 0)
2738
        );
2739
        $renderer->render_group_element(
2740
            'recording_hide_button_default',
2741
            $renderer->render_group_element_checkbox('recording_hide_button_default', 0)
2742
        );
2743
        $renderer->render_group_element(
2744
            'recording_hide_button_editable',
2745
            $renderer->render_group_element_checkbox('recording_hide_button_editable', 0)
2746
        );
2747
    }
2748
}
2749
2750
/**
2751
 * Helper function renders import recording settings if the feature is enabled.
2752
 *
2753
 * @param object $renderer
2754
 *
2755
 * @return void
2756
 */
2757 View Code Duplication
function bigbluebuttonbn_settings_importrecordings(&$renderer) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
2758
    // Configuration for 'import recordings' feature.
2759
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_import_recordings_shown()) {
2760
        $renderer->render_group_header('importrecordings');
2761
        $renderer->render_group_element(
2762
            'importrecordings_enabled',
2763
            $renderer->render_group_element_checkbox('importrecordings_enabled', 0)
2764
        );
2765
        $renderer->render_group_element(
2766
            'importrecordings_from_deleted_enabled',
2767
            $renderer->render_group_element_checkbox('importrecordings_from_deleted_enabled', 0)
2768
        );
2769
    }
2770
}
2771
2772
/**
2773
 * Helper function renders show recording settings if the feature is enabled.
2774
 *
2775
 * @param object $renderer
2776
 *
2777
 * @return void
2778
 */
2779
function bigbluebuttonbn_settings_showrecordings(&$renderer) {
2780
    // Configuration for 'show recordings' feature.
2781
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_show_recordings_shown()) {
2782
        $renderer->render_group_header('recordings');
2783
        $renderer->render_group_element(
2784
            'recordings_html_default',
2785
            $renderer->render_group_element_checkbox('recordings_html_default', 1)
2786
        );
2787
        $renderer->render_group_element(
2788
            'recordings_html_editable',
2789
            $renderer->render_group_element_checkbox('recordings_html_editable', 0)
2790
        );
2791
        $renderer->render_group_element(
2792
            'recordings_deleted_default',
2793
            $renderer->render_group_element_checkbox('recordings_deleted_default', 1)
2794
        );
2795
        $renderer->render_group_element(
2796
            'recordings_deleted_editable',
2797
            $renderer->render_group_element_checkbox('recordings_deleted_editable', 0)
2798
        );
2799
        $renderer->render_group_element(
2800
            'recordings_imported_default',
2801
            $renderer->render_group_element_checkbox('recordings_imported_default', 0)
2802
        );
2803
        $renderer->render_group_element(
2804
            'recordings_imported_editable',
2805
            $renderer->render_group_element_checkbox('recordings_imported_editable', 1)
2806
        );
2807
        $renderer->render_group_element(
2808
            'recordings_preview_default',
2809
            $renderer->render_group_element_checkbox('recordings_preview_default', 1)
2810
        );
2811
        $renderer->render_group_element(
2812
            'recordings_preview_editable',
2813
            $renderer->render_group_element_checkbox('recordings_preview_editable', 0)
2814
        );
2815
        $renderer->render_group_element(
2816
            'recordings_sortorder',
2817
            $renderer->render_group_element_checkbox('recordings_sortorder', 0)
2818
        );
2819
        $renderer->render_group_element(
2820
            'recordings_validate_url',
2821
            $renderer->render_group_element_checkbox('recordings_validate_url', 1)
2822
        );
2823
    }
2824
}
2825
2826
/**
2827
 * Helper function renders wait for moderator settings if the feature is enabled.
2828
 *
2829
 * @param object $renderer
2830
 *
2831
 * @return void
2832
 */
2833
function bigbluebuttonbn_settings_waitmoderator(&$renderer) {
2834
    // Configuration for wait for moderator feature.
2835
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_wait_moderator_shown()) {
2836
        $renderer->render_group_header('waitformoderator');
2837
        $renderer->render_group_element(
2838
            'waitformoderator_default',
2839
            $renderer->render_group_element_checkbox('waitformoderator_default', 0)
2840
        );
2841
        $renderer->render_group_element(
2842
            'waitformoderator_editable',
2843
            $renderer->render_group_element_checkbox('waitformoderator_editable', 1)
2844
        );
2845
        $renderer->render_group_element(
2846
            'waitformoderator_ping_interval',
2847
            $renderer->render_group_element_text('waitformoderator_ping_interval', 10, PARAM_INT)
2848
        );
2849
        $renderer->render_group_element(
2850
            'waitformoderator_cache_ttl',
2851
            $renderer->render_group_element_text('waitformoderator_cache_ttl', 60, PARAM_INT)
2852
        );
2853
    }
2854
}
2855
2856
/**
2857
 * Helper function renders static voice bridge settings if the feature is enabled.
2858
 *
2859
 * @param object $renderer
2860
 *
2861
 * @return void
2862
 */
2863
function bigbluebuttonbn_settings_voicebridge(&$renderer) {
2864
    // Configuration for "static voice bridge" feature.
2865
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_static_voice_bridge_shown()) {
2866
        $renderer->render_group_header('voicebridge');
2867
        $renderer->render_group_element(
2868
            'voicebridge_editable',
2869
            $renderer->render_group_element_checkbox('voicebridge_editable', 0)
2870
        );
2871
    }
2872
}
2873
2874
/**
2875
 * Helper function renders preuploaded presentation settings if the feature is enabled.
2876
 *
2877
 * @param object $renderer
2878
 *
2879
 * @return void
2880
 */
2881
function bigbluebuttonbn_settings_preupload(&$renderer) {
2882
    // Configuration for "preupload presentation" feature.
2883
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_preupload_presentation_shown()) {
2884
        // This feature only works if curl is installed.
2885
        $preuploaddescripion = get_string('config_preuploadpresentation_description', 'bigbluebuttonbn');
2886
        if (!extension_loaded('curl')) {
2887
            $preuploaddescripion .= '<div class="form-defaultinfo">';
2888
            $preuploaddescripion .= get_string('config_warning_curl_not_installed', 'bigbluebuttonbn');
2889
            $preuploaddescripion .= '</div><br>';
2890
        }
2891
        $renderer->render_group_header('preuploadpresentation', null, $preuploaddescripion);
2892
        if (extension_loaded('curl')) {
2893
            $renderer->render_group_element(
2894
                'preuploadpresentation_enabled',
2895
                $renderer->render_group_element_checkbox('preuploadpresentation_enabled', 0)
2896
            );
2897
        }
2898
    }
2899
}
2900
2901
/**
2902
 * Helper function renders preuploaded presentation manage file if the feature is enabled.
2903
 * This allow to select a file for use as default in all BBB instances if preuploaded presetantion is enable.
2904
 *
2905
 * @param object $renderer
2906
 *
2907
 * @return void
2908
 */
2909
function bigbluebuttonbn_settings_preupload_manage_default_file(&$renderer) {
2910
    // Configuration for "preupload presentation" feature.
2911
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_preupload_presentation_shown()) {
2912
        if (extension_loaded('curl')) {
2913
            // This feature only works if curl is installed.
2914
            $renderer->render_filemanager_default_file_presentation("presentation_default");
2915
        }
2916
    }
2917
}
2918
2919
/**
2920
 * Helper function renders userlimit settings if the feature is enabled.
2921
 *
2922
 * @param object $renderer
2923
 *
2924
 * @return void
2925
 */
2926
function bigbluebuttonbn_settings_userlimit(&$renderer) {
2927
    // Configuration for "user limit" feature.
2928
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_user_limit_shown()) {
2929
        $renderer->render_group_header('userlimit');
2930
        $renderer->render_group_element(
2931
            'userlimit_default',
2932
            $renderer->render_group_element_text('userlimit_default', 0, PARAM_INT)
2933
        );
2934
        $renderer->render_group_element(
2935
            'userlimit_editable',
2936
            $renderer->render_group_element_checkbox('userlimit_editable', 0)
2937
        );
2938
    }
2939
}
2940
2941
/**
2942
 * Helper function renders duration settings if the feature is enabled.
2943
 *
2944
 * @param object $renderer
2945
 *
2946
 * @return void
2947
 */
2948
function bigbluebuttonbn_settings_duration(&$renderer) {
2949
    // Configuration for "scheduled duration" feature.
2950
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_scheduled_duration_shown()) {
2951
        $renderer->render_group_header('scheduled');
2952
        $renderer->render_group_element(
2953
            'scheduled_duration_enabled',
2954
            $renderer->render_group_element_checkbox('scheduled_duration_enabled', 1)
2955
        );
2956
        $renderer->render_group_element(
2957
            'scheduled_duration_compensation',
2958
            $renderer->render_group_element_text('scheduled_duration_compensation', 10, PARAM_INT)
2959
        );
2960
        $renderer->render_group_element(
2961
            'scheduled_pre_opening',
2962
            $renderer->render_group_element_text('scheduled_pre_opening', 10, PARAM_INT)
2963
        );
2964
    }
2965
}
2966
2967
/**
2968
 * Helper function renders participant settings if the feature is enabled.
2969
 *
2970
 * @param object $renderer
2971
 *
2972
 * @return void
2973
 */
2974
function bigbluebuttonbn_settings_participants(&$renderer) {
2975
    // Configuration for defining the default role/user that will be moderator on new activities.
2976
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_moderator_default_shown()) {
2977
        $renderer->render_group_header('participant');
2978
        // UI for 'participants' feature.
2979
        $roles = bigbluebuttonbn_get_roles(null, false);
2980
        $owner = array('0' => get_string('mod_form_field_participant_list_type_owner', 'bigbluebuttonbn'));
2981
        $renderer->render_group_element(
2982
            'participant_moderator_default',
2983
            $renderer->render_group_element_configmultiselect(
2984
                'participant_moderator_default',
2985
                array_keys($owner),
2986
                $owner + $roles // CONTRIB-7966: don't use array_merge here so it does not reindex the array.
2987
            )
2988
        );
2989
    }
2990
}
2991
2992
/**
2993
 * Helper function renders notification settings if the feature is enabled.
2994
 *
2995
 * @param object $renderer
2996
 *
2997
 * @return void
2998
 */
2999
function bigbluebuttonbn_settings_notifications(&$renderer) {
3000
    // Configuration for "send notifications" feature.
3001
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_send_notifications_shown()) {
3002
        $renderer->render_group_header('sendnotifications');
3003
        $renderer->render_group_element(
3004
            'sendnotifications_enabled',
3005
            $renderer->render_group_element_checkbox('sendnotifications_enabled', 1)
3006
        );
3007
    }
3008
}
3009
3010
/**
3011
 * Helper function renders client type settings if the feature is enabled.
3012
 *
3013
 * @param object $renderer
3014
 *
3015
 * @return void
3016
 */
3017
function bigbluebuttonbn_settings_clienttype(&$renderer) {
3018
    // Configuration for "clienttype" feature.
3019
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_clienttype_shown()) {
3020
        $renderer->render_group_header('clienttype');
3021
        $renderer->render_group_element(
3022
            'clienttype_editable',
3023
            $renderer->render_group_element_checkbox('clienttype_editable', 0)
3024
        );
3025
        // Web Client default.
3026
        $default = intval((int) \mod_bigbluebuttonbn\locallib\config::get('clienttype_default'));
3027
        $choices = array(BIGBLUEBUTTON_CLIENTTYPE_FLASH => get_string('mod_form_block_clienttype_flash', 'bigbluebuttonbn'),
3028
            BIGBLUEBUTTON_CLIENTTYPE_HTML5 => get_string('mod_form_block_clienttype_html5', 'bigbluebuttonbn'));
3029
        $renderer->render_group_element(
3030
            'clienttype_default',
3031
            $renderer->render_group_element_configselect(
3032
                'clienttype_default',
3033
                $default,
3034
                $choices
3035
            )
3036
        );
3037
    }
3038
}
3039
3040
/**
3041
 * Helper function renders general settings if the feature is enabled.
3042
 *
3043
 * @param object $renderer
3044
 *
3045
 * @return void
3046
 */
3047 View Code Duplication
function bigbluebuttonbn_settings_muteonstart(&$renderer) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3048
    // Configuration for BigBlueButton.
3049
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_muteonstart_shown()) {
3050
        $renderer->render_group_header('muteonstart');
3051
        $renderer->render_group_element(
3052
            'muteonstart_default',
3053
            $renderer->render_group_element_checkbox('muteonstart_default', 0)
3054
        );
3055
        $renderer->render_group_element(
3056
            'muteonstart_editable',
3057
            $renderer->render_group_element_checkbox('muteonstart_editable', 0)
3058
        );
3059
    }
3060
}
3061
3062
/**
3063
 * Helper function renders general settings if the feature is enabled.
3064
 *
3065
 * @param object $renderer
3066
 *
3067
 * @return void
3068
 */
3069
function bigbluebuttonbn_settings_locksettings(&$renderer) {
3070
    $renderer->render_group_header('locksettings');
3071
    // Configuration for various lock settings for meetings.
3072
    bigbluebuttonbn_settings_disablecam($renderer);
3073
    bigbluebuttonbn_settings_disablemic($renderer);
3074
    bigbluebuttonbn_settings_disableprivatechat($renderer);
3075
    bigbluebuttonbn_settings_disablepublicchat($renderer);
3076
    bigbluebuttonbn_settings_disablenote($renderer);
3077
    bigbluebuttonbn_settings_hideuserlist($renderer);
3078
    bigbluebuttonbn_settings_lockedlayout($renderer);
3079
    bigbluebuttonbn_settings_lockonjoin($renderer);
3080
    bigbluebuttonbn_settings_lockonjoinconfigurable($renderer);
3081
}
3082
3083
/**
3084
 * Helper function renders general settings if the feature is enabled.
3085
 *
3086
 * @param object $renderer
3087
 *
3088
 * @return void
3089
 */
3090
function bigbluebuttonbn_settings_disablecam(&$renderer) {
3091
    // Configuration for BigBlueButton.
3092
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_disablecam_shown()) {
3093
        $renderer->render_group_element(
3094
            'disablecam_default',
3095
            $renderer->render_group_element_checkbox('disablecam_default', 0)
3096
        );
3097
        $renderer->render_group_element(
3098
            'disablecam_editable',
3099
            $renderer->render_group_element_checkbox('disablecam_editable', 1)
3100
        );
3101
    }
3102
}
3103
3104
/**
3105
 * Helper function renders general settings if the feature is enabled.
3106
 *
3107
 * @param object $renderer
3108
 *
3109
 * @return void
3110
 */
3111
function bigbluebuttonbn_settings_disablemic(&$renderer) {
3112
    // Configuration for BigBlueButton.
3113
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_disablemic_shown()) {
3114
        $renderer->render_group_element(
3115
            'disablemic_default',
3116
            $renderer->render_group_element_checkbox('disablemic_default', 0)
3117
        );
3118
        $renderer->render_group_element(
3119
            'disablecam_editable',
3120
            $renderer->render_group_element_checkbox('disablemic_editable', 1)
3121
        );
3122
    }
3123
}
3124
3125
/**
3126
 * Helper function renders general settings if the feature is enabled.
3127
 *
3128
 * @param object $renderer
3129
 *
3130
 * @return void
3131
 */
3132
function bigbluebuttonbn_settings_disableprivatechat(&$renderer) {
3133
    // Configuration for BigBlueButton.
3134
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_disableprivatechat_shown()) {
3135
        $renderer->render_group_element(
3136
            'disableprivatechat_default',
3137
            $renderer->render_group_element_checkbox('disableprivatechat_default', 0)
3138
        );
3139
        $renderer->render_group_element(
3140
            'disableprivatechat_editable',
3141
            $renderer->render_group_element_checkbox('disableprivatechat_editable', 1)
3142
        );
3143
    }
3144
}
3145
3146
/**
3147
 * Helper function renders general settings if the feature is enabled.
3148
 *
3149
 * @param object $renderer
3150
 *
3151
 * @return void
3152
 */
3153
function bigbluebuttonbn_settings_disablepublicchat(&$renderer) {
3154
    // Configuration for BigBlueButton.
3155
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_disablepublicchat_shown()) {
3156
        $renderer->render_group_element(
3157
            'disablepublicchat_default',
3158
            $renderer->render_group_element_checkbox('disablepublicchat_default', 0)
3159
        );
3160
        $renderer->render_group_element(
3161
            'disablepublicchat_editable',
3162
            $renderer->render_group_element_checkbox('disablepublicchat_editable', 1)
3163
        );
3164
    }
3165
}
3166
3167
/**
3168
 * Helper function renders general settings if the feature is enabled.
3169
 *
3170
 * @param object $renderer
3171
 *
3172
 * @return void
3173
 */
3174
function bigbluebuttonbn_settings_disablenote(&$renderer) {
3175
    // Configuration for BigBlueButton.
3176
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_disablenote_shown()) {
3177
        $renderer->render_group_element(
3178
            'disablenote_default',
3179
            $renderer->render_group_element_checkbox('disablenote_default', 0)
3180
        );
3181
        $renderer->render_group_element(
3182
            'disablenote_editable',
3183
            $renderer->render_group_element_checkbox('disablenote_editable', 1)
3184
        );
3185
    }
3186
}
3187
3188
/**
3189
 * Helper function renders general settings if the feature is enabled.
3190
 *
3191
 * @param object $renderer
3192
 *
3193
 * @return void
3194
 */
3195
function bigbluebuttonbn_settings_hideuserlist(&$renderer) {
3196
    // Configuration for BigBlueButton.
3197
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_hideuserlist_shown()) {
3198
        $renderer->render_group_element(
3199
            'hideuserlist_default',
3200
            $renderer->render_group_element_checkbox('hideuserlist_default', 0)
3201
        );
3202
        $renderer->render_group_element(
3203
            'hideuserlist_editable',
3204
            $renderer->render_group_element_checkbox('hideuserlist_editable', 1)
3205
        );
3206
    }
3207
}
3208
3209
/**
3210
 * Helper function renders general settings if the feature is enabled.
3211
 *
3212
 * @param object $renderer
3213
 *
3214
 * @return void
3215
 */
3216
function bigbluebuttonbn_settings_lockedlayout(&$renderer) {
3217
    // Configuration for BigBlueButton.
3218
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_lockedlayout_shown()) {
3219
        $renderer->render_group_element(
3220
            'lockedlayout_default',
3221
            $renderer->render_group_element_checkbox('lockedlayout_default', 0)
3222
        );
3223
        $renderer->render_group_element(
3224
            'lockedlayout_editable',
3225
            $renderer->render_group_element_checkbox('lockedlayout_editable', 1)
3226
        );
3227
    }
3228
}
3229
3230
/**
3231
 * Helper function renders general settings if the feature is enabled.
3232
 *
3233
 * @param object $renderer
3234
 *
3235
 * @return void
3236
 */
3237
function bigbluebuttonbn_settings_lockonjoin(&$renderer) {
3238
    // Configuration for BigBlueButton.
3239
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_lockonjoin_shown()) {
3240
        $renderer->render_group_element(
3241
            'lockonjoin_default',
3242
            $renderer->render_group_element_checkbox('lockonjoin_default', 0)
3243
        );
3244
        $renderer->render_group_element(
3245
            'lockonjoin_editable',
3246
            $renderer->render_group_element_checkbox('lockonjoin_editable', 1)
3247
        );
3248
    }
3249
}
3250
3251
/**
3252
 * Helper function renders general settings if the feature is enabled.
3253
 *
3254
 * @param object $renderer
3255
 *
3256
 * @return void
3257
 */
3258
function bigbluebuttonbn_settings_lockonjoinconfigurable(&$renderer) {
3259
    // Configuration for BigBlueButton.
3260
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_lockonjoinconfigurable_shown()) {
3261
        $renderer->render_group_element(
3262
            'lockonjoinconfigurable_default',
3263
            $renderer->render_group_element_checkbox('lockonjoinconfigurable_default', 0)
3264
        );
3265
        $renderer->render_group_element(
3266
            'lockonjoinconfigurable_editable',
3267
            $renderer->render_group_element_checkbox('lockonjoinconfigurable_editable', 1)
3268
        );
3269
    }
3270
}
3271
3272
/**
3273
 * Helper function renders default messages settings.
3274
 *
3275
 * @param object $renderer
3276
 *
3277
 * @return void
3278
 */
3279
function bigbluebuttonbn_settings_default_messages(&$renderer) {
3280
    $renderer->render_group_header('default_messages');
3281
    $renderer->render_group_element(
3282
        'welcome_default',
3283
        $renderer->render_group_element_textarea('welcome_default', '', PARAM_TEXT)
3284
    );
3285
}
3286
3287
/**
3288
 * Helper function renders extended settings if any of the features there is enabled.
3289
 *
3290
 * @param object $renderer
3291
 *
3292
 * @return void
3293
 */
3294
function bigbluebuttonbn_settings_extended(&$renderer) {
3295
    // Configuration for extended capabilities.
3296
    if (!(boolean) \mod_bigbluebuttonbn\settings\validator::section_settings_extended_shown()) {
3297
        return;
3298
    }
3299
    $renderer->render_group_header('extended_capabilities');
3300
    // UI for 'notify users when recording ready' feature.
3301
    $renderer->render_group_element(
3302
        'recordingready_enabled',
3303
        $renderer->render_group_element_checkbox('recordingready_enabled', 0)
3304
    );
3305
    // Configuration for extended BN capabilities should go here.
3306
}
3307
3308
/**
3309
 * Helper function renders experimental settings if any of the features there is enabled.
3310
 *
3311
 * @param object $renderer
3312
 *
3313
 * @return void
3314
 */
3315
function bigbluebuttonbn_settings_experimental(&$renderer) {
3316
    // Configuration for experimental features should go here.
3317
    $renderer->render_group_header('experimental_features');
3318
    // UI for 'register meeting events' feature.
3319
    $renderer->render_group_element(
3320
        'meetingevents_enabled',
3321
        $renderer->render_group_element_checkbox('meetingevents_enabled', 0)
3322
    );
3323
}
3324
3325
/**
3326
 * Helper function returns a sha1 encoded string that is unique and will be used as a seed for meetingid.
3327
 *
3328
 * @return string
3329
 */
3330
function bigbluebuttonbn_unique_meetingid_seed() {
3331
    global $DB;
3332
    do {
3333
        $encodedseed = sha1(bigbluebuttonbn_random_password(12));
3334
        $meetingid = (string) $DB->get_field('bigbluebuttonbn', 'meetingid', array('meetingid' => $encodedseed));
3335
    } while ($meetingid == $encodedseed);
3336
    return $encodedseed;
3337
}
3338
3339
/**
3340
 * Helper function renders the link used for recording type in row for the data used by the recording table.
3341
 *
3342
 * @param array $recording
3343
 * @param array $bbbsession
3344
 * @param array $playback
3345
 *
3346
 * @return boolean
3347
 */
3348
function bigbluebuttonbn_include_recording_data_row_type($recording, $bbbsession, $playback) {
3349
    // All types that are not restricted are included.
3350
    if (array_key_exists('restricted', $playback) && strtolower($playback['restricted']) == 'false') {
3351
        return true;
3352
    }
3353
    // All types that are not statistics are included.
3354
    if ($playback['type'] != 'statistics') {
3355
        return true;
3356
    }
3357
    // Exclude imported recordings.
3358
    if (isset($recording['imported'])) {
3359
        return false;
3360
    }
3361
    // Exclude non moderators.
3362
    if (!$bbbsession['administrator'] && !$bbbsession['moderator']) {
3363
        return false;
3364
    }
3365
    return true;
3366
}
3367
3368
/**
3369
 * Renders the general warning message.
3370
 *
3371
 * @param string $message
3372
 * @param string $type
3373
 * @param string $href
3374
 * @param string $text
3375
 * @param string $class
3376
 *
3377
 * @return string
3378
 */
3379
function bigbluebuttonbn_render_warning($message, $type = 'info', $href = '', $text = '', $class = '') {
3380
    global $OUTPUT;
3381
    $output = "\n";
3382
    // Evaluates if config_warning is enabled.
3383
    if (empty($message)) {
3384
        return $output;
3385
    }
3386
    $output .= $OUTPUT->box_start(
3387
        'box boxalignleft adminerror alert alert-' . $type . ' alert-block fade in',
3388
        'bigbluebuttonbn_view_general_warning'
3389
    ) . "\n";
3390
    $output .= '    ' . $message . "\n";
3391
    $output .= '  <div class="singlebutton pull-right">' . "\n";
3392
    if (!empty($href)) {
3393
        $output .= bigbluebuttonbn_render_warning_button($href, $text, $class);
3394
    }
3395
    $output .= '  </div>' . "\n";
3396
    $output .= $OUTPUT->box_end() . "\n";
3397
    return $output;
3398
}
3399
3400
/**
3401
 * Renders the general warning button.
3402
 *
3403
 * @param string $href
3404
 * @param string $text
3405
 * @param string $class
3406
 * @param string $title
3407
 *
3408
 * @return string
3409
 */
3410
function bigbluebuttonbn_render_warning_button($href, $text = '', $class = '', $title = '') {
3411
    if ($text == '') {
3412
        $text = get_string('ok', 'moodle');
3413
    }
3414
    if ($title == '') {
3415
        $title = $text;
3416
    }
3417
    if ($class == '') {
3418
        $class = 'btn btn-secondary';
3419
    }
3420
    $output = '  <form method="post" action="' . $href . '" class="form-inline">' . "\n";
3421
    $output .= '      <button type="submit" class="' . $class . '"' . "\n";
3422
    $output .= '          title="' . $title . '"' . "\n";
3423
    $output .= '          >' . $text . '</button>' . "\n";
3424
    $output .= '  </form>' . "\n";
3425
    return $output;
3426
}
3427
3428
/**
3429
 * Check if a BigBlueButtonBN is available to be used by the current user.
3430
 *
3431
 * @param  stdClass  $bigbluebuttonbn  BigBlueButtonBN instance
3432
 *
3433
 * @return boolean                     status if room available and current user allowed to join
3434
 */
3435
function bigbluebuttonbn_get_availability_status($bigbluebuttonbn) {
3436
    list($roomavailable) = bigbluebuttonbn_room_is_available($bigbluebuttonbn);
3437
    list($usercanjoin) = bigbluebuttonbn_user_can_join_meeting($bigbluebuttonbn);
3438
    return ($roomavailable && $usercanjoin);
3439
}
3440
3441
/**
3442
 * Helper for evaluating if scheduled activity is avaiable.
3443
 *
3444
 * @param  stdClass  $bigbluebuttonbn  BigBlueButtonBN instance
3445
 *
3446
 * @return array                       status (room available or not and possible warnings)
3447
 */
3448
function bigbluebuttonbn_room_is_available($bigbluebuttonbn) {
3449
    $open = true;
3450
    $closed = false;
3451
    $warnings = array();
3452
3453
    $timenow = time();
3454
    $timeopen = $bigbluebuttonbn->openingtime;
3455
    $timeclose = $bigbluebuttonbn->closingtime;
3456
    if (!empty($timeopen) && $timeopen > $timenow) {
3457
        $open = false;
3458
    }
3459
    if (!empty($timeclose) && $timenow > $timeclose) {
3460
        $closed = true;
3461
    }
3462
3463
    if (!$open || $closed) {
3464
        if (!$open) {
3465
            $warnings['notopenyet'] = userdate($timeopen);
3466
        }
3467
        if ($closed) {
3468
            $warnings['expired'] = userdate($timeclose);
3469
        }
3470
        return array(false, $warnings);
3471
    }
3472
3473
    return array(true, $warnings);
3474
}
3475
3476
/**
3477
 * Helper for evaluating if meeting can be joined.
3478
 *
3479
 * @param  stdClass $bigbluebuttonbn  BigBlueButtonBN instance
3480
 * @param  string   $mid
3481
 * @param  integer  $userid
3482
 *
3483
 * @return array    status (user allowed to join or not and possible message)
3484
 */
3485
function bigbluebuttonbn_user_can_join_meeting($bigbluebuttonbn, $mid = null, $userid = null) {
3486
    // By default, use a meetingid without groups.
3487
    if (empty($mid)) {
3488
        $mid = $bigbluebuttonbn->meetingid . '-' . $bigbluebuttonbn->course . '-' . $bigbluebuttonbn->id;
3489
    }
3490
    // When meeting is running, all authorized users can join right in.
3491
    if (bigbluebuttonbn_is_meeting_running($mid)) {
3492
        return array(true, get_string('view_message_conference_in_progress', 'bigbluebuttonbn'));
3493
    }
3494
    // When meeting is not running, see if the user can join.
3495
    $context = context_course::instance($bigbluebuttonbn->course);
3496
    $participantlist = bigbluebuttonbn_get_participant_list($bigbluebuttonbn, $context);
3497
    $isadmin = is_siteadmin($userid);
3498
    $ismoderator = bigbluebuttonbn_is_moderator($context, $participantlist, $userid);
3499
    // If user is administrator, moderator or if is viewer and no waiting is required, join allowed.
3500
    if ($isadmin || $ismoderator || !$bigbluebuttonbn->wait) {
3501
        return array(true, get_string('view_message_conference_room_ready', 'bigbluebuttonbn'));
3502
    }
3503
    // Otherwise, no join allowed.
3504
    return array(false, get_string('view_message_conference_wait_for_moderator', 'bigbluebuttonbn'));
3505
}
3506
3507
/**
3508
 * Helper for getting a value from a bigbluebuttonbn cache.
3509
 *
3510
 * @param  string   $name       BigBlueButtonBN cache
3511
 * @param  string   $key        Key to be retrieved
3512
 * @param  integer  $default    Default value in case key is not found or it is empty
3513
 *
3514
 * @return variable key value
3515
 */
3516
function bigbluebuttonbn_cache_get($name, $key, $default = null) {
3517
    $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'mod_bigbluebuttonbn', $name);
3518
    $result = $cache->get($key);
3519
    if (!empty($result)) {
3520
        return $result;
3521
    }
3522
    return $default;
3523
}
3524
3525
/**
3526
 * Helper for setting a value in a bigbluebuttonbn cache.
3527
 *
3528
 * @param  string   $name       BigBlueButtonBN cache
3529
 * @param  string   $key        Key to be created/updated
3530
 * @param  variable $value      Default value to be set
3531
 */
3532
function bigbluebuttonbn_cache_set($name, $key, $value) {
3533
    $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'mod_bigbluebuttonbn', $name);
3534
    $cache->set($key, $value);
3535
}
3536
3537
/**
3538
 * Helper for getting the owner userid of a bigbluebuttonbn instance.
3539
 *
3540
 * @param  stdClass $bigbluebuttonbn  BigBlueButtonBN instance
3541
 *
3542
 * @return integer ownerid (a valid user id or null if not registered/found)
3543
 */
3544
function bigbluebuttonbn_instance_ownerid($bigbluebuttonbn) {
3545
    global $DB;
3546
    $filters = array('bigbluebuttonbnid' => $bigbluebuttonbn->id, 'log' => 'Add');
3547
    $ownerid = (integer) $DB->get_field('bigbluebuttonbn_logs', 'userid', $filters);
3548
    return $ownerid;
3549
}
3550
3551
/**
3552
 * Helper evaluates if the bigbluebutton server used belongs to blindsidenetworks domain.
3553
 *
3554
 * @return boolean
3555
 */
3556
function bigbluebuttonbn_has_html5_client() {
3557
    $checkurl = \mod_bigbluebuttonbn\locallib\bigbluebutton::root() . "html5client/check";
3558
    $curlinfo = bigbluebuttonbn_wrap_xml_load_file_curl_request($checkurl, 'HEAD');
3559
    return (isset($curlinfo['http_code']) && $curlinfo['http_code'] == 200);
3560
}
3561
3562
/**
3563
 * Return the status of an activity [open|not_started|ended].
3564
 *
3565
 * @param array $bbbsession
3566
 * @return string
3567
 */
3568 View Code Duplication
function bigbluebuttonbn_view_get_activity_status(&$bbbsession) {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3569
    $now = time();
3570
    if (!empty($bbbsession['bigbluebuttonbn']->openingtime) && $now < $bbbsession['bigbluebuttonbn']->openingtime) {
3571
        // The activity has not been opened.
3572
        return 'not_started';
3573
    }
3574
    if (!empty($bbbsession['bigbluebuttonbn']->closingtime) && $now > $bbbsession['bigbluebuttonbn']->closingtime) {
3575
        // The activity has been closed.
3576
        return 'ended';
3577
    }
3578
    // The activity is open.
3579
    return 'open';
3580
}
3581
3582
/**
3583
 * Set session URLs.
3584
 *
3585
 * @param array $bbbsession
3586
 * @param int $id
3587
 * @return string
3588
 */
3589
function bigbluebuttonbn_view_session_config(&$bbbsession, $id) {
3590
    // Operation URLs.
3591
    $bbbsession['bigbluebuttonbnURL'] = plugin::necurl(
3592
        '/mod/bigbluebuttonbn/view.php',
3593
        ['id' => $bbbsession['cm']->id]
3594
    );
3595
    $bbbsession['logoutURL'] = plugin::necurl(
3596
        '/mod/bigbluebuttonbn/bbb_view.php',
3597
        ['action' => 'logout', 'id' => $id, 'bn' => $bbbsession['bigbluebuttonbn']->id]
3598
    );
3599
    $bbbsession['recordingReadyURL'] = plugin::necurl(
3600
        '/mod/bigbluebuttonbn/bbb_broker.php',
3601
        ['action' => 'recording_ready', 'bigbluebuttonbn' => $bbbsession['bigbluebuttonbn']->id]
3602
    );
3603
    $bbbsession['meetingEventsURL'] = plugin::necurl(
3604
        '/mod/bigbluebuttonbn/bbb_broker.php',
3605
        ['action' => 'meeting_events', 'bigbluebuttonbn' => $bbbsession['bigbluebuttonbn']->id]
3606
    );
3607
    $bbbsession['joinURL'] = plugin::necurl(
3608
        '/mod/bigbluebuttonbn/bbb_view.php',
3609
        ['action' => 'join', 'id' => $id, 'bn' => $bbbsession['bigbluebuttonbn']->id]
3610
    );
3611
3612
    // Check status and set extra values.
3613
    $activitystatus = bigbluebuttonbn_view_get_activity_status($bbbsession); // In locallib.
3614 View Code Duplication
    if ($activitystatus == 'ended') {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
3615
        $bbbsession['presentation'] = bigbluebuttonbn_get_presentation_array(
3616
            $bbbsession['context'],
3617
            $bbbsession['bigbluebuttonbn']->presentation
3618
        );
3619
    } else if ($activitystatus == 'open') {
3620
        $bbbsession['presentation'] = bigbluebuttonbn_get_presentation_array(
3621
            $bbbsession['context'],
3622
            $bbbsession['bigbluebuttonbn']->presentation,
3623
            $bbbsession['bigbluebuttonbn']->id
3624
        );
3625
    }
3626
3627
    return $activitystatus;
3628
}
3629
3630
/**
3631
 * Helper for preparing metadata used while creating the meeting.
3632
 *
3633
 * @param  array    $bbbsession
3634
 * @return array
3635
 */
3636
function bigbluebuttonbn_create_meeting_metadata(&$bbbsession) {
3637
    global $USER;
3638
    // Create standard metadata.
3639
    $metadata = [
3640
        'bbb-origin' => $bbbsession['origin'],
3641
        'bbb-origin-version' => $bbbsession['originVersion'],
3642
        'bbb-origin-server-name' => $bbbsession['originServerName'],
3643
        'bbb-origin-server-common-name' => $bbbsession['originServerCommonName'],
3644
        'bbb-origin-tag' => $bbbsession['originTag'],
3645
        'bbb-context' => $bbbsession['course']->fullname,
3646
        'bbb-context-id' => $bbbsession['course']->id,
3647
        'bbb-context-name' => trim(html_to_text($bbbsession['course']->fullname, 0)),
3648
        'bbb-context-label' => trim(html_to_text($bbbsession['course']->shortname, 0)),
3649
        'bbb-recording-name' => bigbluebuttonbn_html2text($bbbsession['meetingname'], 64),
3650
        'bbb-recording-description' => bigbluebuttonbn_html2text($bbbsession['meetingdescription'], 64),
3651
        'bbb-recording-tags' => bigbluebuttonbn_get_tags($bbbsession['cm']->id), // Same as $id.
3652
    ];
3653
    // Special metadata for recording processing.
3654
    if ((boolean) \mod_bigbluebuttonbn\locallib\config::get('recordingstatus_enabled')) {
3655
        $metadata["bn-recording-status"] = json_encode(
3656
            array(
3657
                'email' => array('"' . fullname($USER) . '" <' . $USER->email . '>'),
3658
                'context' => $bbbsession['bigbluebuttonbnURL'],
3659
            )
3660
        );
3661
    }
3662
    if ((boolean) \mod_bigbluebuttonbn\locallib\config::get('recordingready_enabled')) {
3663
        $metadata['bn-recording-ready-url'] = $bbbsession['recordingReadyURL'];
3664
    }
3665
    if ((boolean) \mod_bigbluebuttonbn\locallib\config::get('meetingevents_enabled')) {
3666
        $metadata['analytics-callback-url'] = $bbbsession['meetingEventsURL'];
3667
    }
3668
    return $metadata;
3669
}
3670