Completed
Pull Request — master (#339)
by
unknown
02:39
created

locallib.php ➔ bigbluebuttonbn_create_meeting_metadata()   B

Complexity

Conditions 6
Paths 24

Size

Total Lines 42

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
nc 24
nop 1
dl 0
loc 42
rs 8.6257
c 0
b 0
f 0
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
    $data = ['meetingID' => $meetingid,
117
        'fullName' => $username,
118
        'password' => $pw,
119
        'logoutURL' => $logouturl,
120
    ];
121
    // Choose between Adobe Flash or HTML5 Client.
122
    if ($clienttype == BIGBLUEBUTTON_CLIENTTYPE_HTML5) {
123
        $data['joinViaHtml5'] = 'true';
124
    }
125
    if (!is_null($configtoken)) {
126
        $data['configToken'] = $configtoken;
127
    }
128
    if (!is_null($userid)) {
129
        $data['userID'] = $userid;
130
    }
131
    if (!is_null($createtime)) {
132
        $data['createTime'] = $createtime;
133
    }
134
    return \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('join', $data);
135
}
136
137
/**
138
 * Creates a bigbluebutton meeting and returns the response in an array.
139
 *
140
 * @param array  $data
141
 * @param array  $metadata
142
 * @param string $pname
143
 * @param string $purl
144
 *
145
 * @return array
146
 */
147
function bigbluebuttonbn_get_create_meeting_array($data, $metadata = array(), $pname = null, $purl = null) {
148
    $createmeetingurl = \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('create', $data, $metadata);
149
    $method = 'GET';
150
    $payload = null;
151
    if (!is_null($pname) && !is_null($purl)) {
152
        $method = 'POST';
153
        $payload = "<?xml version='1.0' encoding='UTF-8'?><modules><module name='presentation'><document url='".
154
            $purl."' /></module></modules>";
155
    }
156
    $xml = bigbluebuttonbn_wrap_xml_load_file($createmeetingurl, $method, $payload);
157
    if ($xml) {
158
        $response = array('returncode' => $xml->returncode, 'message' => $xml->message, 'messageKey' => $xml->messageKey);
159
        if ($xml->meetingID) {
160
            $response += array('meetingID' => $xml->meetingID, 'attendeePW' => $xml->attendeePW,
161
                'moderatorPW' => $xml->moderatorPW, 'hasBeenForciblyEnded' => $xml->hasBeenForciblyEnded);
162
        }
163
        return $response;
164
    }
165
    return array('returncode' => 'FAILED', 'message' => 'unreachable', 'messageKey' => 'Server is unreachable');
166
}
167
168
/**
169
 * Fetch meeting info and wrap response in array.
170
 *
171
 * @param string $meetingid
172
 *
173
 * @return array
174
 */
175
function bigbluebuttonbn_get_meeting_info_array($meetingid) {
176
    $xml = bigbluebuttonbn_wrap_xml_load_file(
177
        \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('getMeetingInfo', ['meetingID' => $meetingid])
178
    );
179
    if ($xml && $xml->returncode == 'SUCCESS' && empty($xml->messageKey)) {
180
        // Meeting info was returned.
181
        return array('returncode' => $xml->returncode,
182
            'meetingID' => $xml->meetingID,
183
            'moderatorPW' => $xml->moderatorPW,
184
            'attendeePW' => $xml->attendeePW,
185
            'hasBeenForciblyEnded' => $xml->hasBeenForciblyEnded,
186
            'running' => $xml->running,
187
            'recording' => $xml->recording,
188
            'startTime' => $xml->startTime,
189
            'endTime' => $xml->endTime,
190
            'participantCount' => $xml->participantCount,
191
            'moderatorCount' => $xml->moderatorCount,
192
            'attendees' => $xml->attendees,
193
            'metadata' => $xml->metadata,
194
        );
195
    }
196
    if ($xml) {
197
        // Either failure or success without meeting info.
198
        return (array) $xml;
199
    }
200
    // If the server is unreachable, then prompts the user of the necessary action.
201
    return array('returncode' => 'FAILED', 'message' => 'unreachable', 'messageKey' => 'Server is unreachable');
202
}
203
204
/**
205
 * Helper function to retrieve recordings from a BigBlueButton server.
206
 *
207
 * @param string|array $meetingids   list of meetingIDs "mid1,mid2,mid3" or array("mid1","mid2","mid3")
208
 * @param string|array $recordingids list of $recordingids "rid1,rid2,rid3" or array("rid1","rid2","rid3") for filtering
209
 *
210
 * @return associative array with recordings indexed by recordID, each recording is a non sequential associative array
211
 */
212
function bigbluebuttonbn_get_recordings_array($meetingids, $recordingids = []) {
213
    $meetingidsarray = $meetingids;
214
    if (!is_array($meetingids)) {
215
        $meetingidsarray = explode(',', $meetingids);
216
    }
217
    // If $meetingidsarray is empty there is no need to go further.
218
    if (empty($meetingidsarray)) {
219
        return array();
220
    }
221
    $recordings = bigbluebuttonbn_get_recordings_array_fetch($meetingidsarray);
0 ignored issues
show
Bug introduced by
It seems like $meetingidsarray defined by $meetingids on line 213 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...
222
    // Sort recordings.
223
    uasort($recordings, 'bigbluebuttonbn_recording_build_sorter');
224
    // Filter recordings based on recordingIDs.
225
    $recordingidsarray = $recordingids;
226
    if (!is_array($recordingids)) {
227
        $recordingidsarray = explode(',', $recordingids);
228
    }
229
    if (empty($recordingidsarray)) {
230
        // No recording ids, no need to filter.
231
        return $recordings;
232
    }
233
    return bigbluebuttonbn_get_recordings_array_filter($recordingidsarray, $recordings);
0 ignored issues
show
Bug introduced by
It seems like $recordingidsarray defined by $recordingids on line 225 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...
234
}
235
236
/**
237
 * Helper function to fetch recordings from a BigBlueButton server.
238
 *
239
 * @param array $meetingidsarray array with meeting ids in the form array("mid1","mid2","mid3")
240
 *
241
 * @return array (associative) with recordings indexed by recordID, each recording is a non sequential associative array
242
 */
243
function bigbluebuttonbn_get_recordings_array_fetch($meetingidsarray) {
244
    if ((defined('PHPUNIT_TEST') && PHPUNIT_TEST)
245
            || defined('BEHAT_SITE_RUNNING')
246
            || defined('BEHAT_TEST')
247
            || defined('BEHAT_UTIL')) {
248
        // Just return the fake recording.
249
        global $CFG;
250
        require_once($CFG->libdir . '/testing/generator/lib.php');
251
        require_once(__DIR__ . '/tests/generator/lib.php');
252
        return mod_bigbluebuttonbn_generator::bigbluebuttonbn_get_recordings_array_fetch($meetingidsarray);
253
    }
254
    $recordings = array();
255
    // Execute a paginated getRecordings request.
256
    $pagecount = 25;
257
    $pages = floor(count($meetingidsarray) / $pagecount) + 1;
258
    if (count($meetingidsarray) > 0 && count($meetingidsarray) % $pagecount == 0) {
259
        $pages--;
260
    }
261
    for ($page = 1; $page <= $pages; ++$page) {
262
        $mids = array_slice($meetingidsarray, ($page - 1) * $pagecount, $pagecount);
263
        $recordings += bigbluebuttonbn_get_recordings_array_fetch_page($mids);
264
    }
265
    return $recordings;
266
}
267
268
/**
269
 * Helper function to fetch one page of upto 25 recordings from a BigBlueButton server.
270
 *
271
 * @param array  $mids
272
 *
273
 * @return array
274
 */
275
function bigbluebuttonbn_get_recordings_array_fetch_page($mids) {
276
    $recordings = array();
277
    // Do getRecordings is executed using a method GET (supported by all versions of BBB).
278
    $url = \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('getRecordings', ['meetingID' => implode(',', $mids)]);
279
    $xml = bigbluebuttonbn_wrap_xml_load_file($url);
280
    if ($xml && $xml->returncode == 'SUCCESS' && isset($xml->recordings)) {
281
        // If there were meetings already created.
282
        foreach ($xml->recordings->recording as $recordingxml) {
283
            $recording = bigbluebuttonbn_get_recording_array_value($recordingxml);
284
            $recordings[$recording['recordID']] = $recording;
285
286
            // Check if there is childs.
287
            if (isset($recordingxml->breakoutRooms->breakoutRoom)) {
288
                foreach ($recordingxml->breakoutRooms->breakoutRoom as $breakoutroom) {
289
                    $url = \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url(
290
                        'getRecordings',
291
                        ['recordID' => implode(',', (array) $breakoutroom)]
292
                    );
293
                    $xml = bigbluebuttonbn_wrap_xml_load_file($url);
294
                    if ($xml && $xml->returncode == 'SUCCESS' && isset($xml->recordings)) {
295
                        // If there were meetings already created.
296
                        foreach ($xml->recordings->recording as $recordingxml) {
297
                            $recording = bigbluebuttonbn_get_recording_array_value($recordingxml);
298
                            $recordings[$recording['recordID']] = $recording;
299
                        }
300
                    }
301
                }
302
            }
303
        }
304
    }
305
    return $recordings;
306
}
307
308
/**
309
 * Helper function to remove a set of recordings from an array.
310
 *
311
 * @param array  $rids
312
 * @param array  $recordings
313
 *
314
 * @return array
315
 */
316
function bigbluebuttonbn_get_recordings_array_filter($rids, &$recordings) {
317
    foreach ($recordings as $key => $recording) {
318
        if (!in_array($recording['recordID'], $rids)) {
319
            unset($recordings[$key]);
320
        }
321
    }
322
    return $recordings;
323
}
324
325
/**
326
 * Helper function to retrieve imported recordings from the Moodle database.
327
 * The references are stored as events in bigbluebuttonbn_logs.
328
 *
329
 * @param string $courseid
330
 * @param string $bigbluebuttonbnid
331
 * @param bool   $subset
332
 *
333
 * @return associative array with imported recordings indexed by recordID, each recording
334
 * is a non sequential associative array that corresponds to the actual recording in BBB
335
 */
336
function bigbluebuttonbn_get_recordings_imported_array($courseid = 0, $bigbluebuttonbnid = null, $subset = true) {
337
    global $DB;
338
    $select = bigbluebuttonbn_get_recordings_imported_sql_select($courseid, $bigbluebuttonbnid, $subset);
339
    $recordsimported = $DB->get_records_select('bigbluebuttonbn_logs', $select);
340
    $recordsimportedarray = array();
341
    foreach ($recordsimported as $recordimported) {
342
        $meta = json_decode($recordimported->meta, true);
343
        $recording = $meta['recording'];
344
        // Override imported flag with actual ID.
345
        $recording['imported'] = $recordimported->id;
346
        if (isset($recordimported->protected)) {
347
            $recording['protected'] = (string) $recordimported->protected;
348
        }
349
        $recordsimportedarray[$recording['recordID']] = $recording;
350
    }
351
    return $recordsimportedarray;
352
}
353
354
/**
355
 * Helper function to retrive the default config.xml file.
356
 *
357
 * @return string
358
 */
359
function bigbluebuttonbn_get_default_config_xml() {
360
    $xml = bigbluebuttonbn_wrap_xml_load_file(
361
        \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('getDefaultConfigXML')
362
    );
363
    return $xml;
364
}
365
366
/**
367
 * Helper function to convert an xml recording object to an array in the format used by the plugin.
368
 *
369
 * @param object $recording
370
 *
371
 * @return array
372
 */
373
function bigbluebuttonbn_get_recording_array_value($recording) {
374
    // Add formats.
375
    $playbackarray = array();
376
    foreach ($recording->playback->format as $format) {
377
        $playbackarray[(string) $format->type] = array('type' => (string) $format->type,
378
            'url' => trim((string) $format->url), 'length' => (string) $format->length);
379
        // Add preview per format when existing.
380
        if ($format->preview) {
381
            $playbackarray[(string) $format->type]['preview'] = bigbluebuttonbn_get_recording_preview_images($format->preview);
382
        }
383
    }
384
    // Add the metadata to the recordings array.
385
    $metadataarray = bigbluebuttonbn_get_recording_array_meta(get_object_vars($recording->metadata));
386
    $recordingarray = array('recordID' => (string) $recording->recordID,
387
        'meetingID' => (string) $recording->meetingID, 'meetingName' => (string) $recording->name,
388
        'published' => (string) $recording->published, 'startTime' => (string) $recording->startTime,
389
        'endTime' => (string) $recording->endTime, 'playbacks' => $playbackarray);
390
    if (isset($recording->protected)) {
391
        $recordingarray['protected'] = (string) $recording->protected;
392
    }
393
    return $recordingarray + $metadataarray;
394
}
395
396
/**
397
 * Helper function to convert an xml recording preview images to an array in the format used by the plugin.
398
 *
399
 * @param object $preview
400
 *
401
 * @return array
402
 */
403
function bigbluebuttonbn_get_recording_preview_images($preview) {
404
    $imagesarray = array();
405
    foreach ($preview->images->image as $image) {
406
        $imagearray = array('url' => trim((string) $image));
407
        foreach ($image->attributes() as $attkey => $attvalue) {
408
            $imagearray[$attkey] = (string) $attvalue;
409
        }
410
        array_push($imagesarray, $imagearray);
411
    }
412
    return $imagesarray;
413
}
414
415
/**
416
 * Helper function to convert an xml recording metadata object to an array in the format used by the plugin.
417
 *
418
 * @param array $metadata
419
 *
420
 * @return array
421
 */
422
function bigbluebuttonbn_get_recording_array_meta($metadata) {
423
    $metadataarray = array();
424
    foreach ($metadata as $key => $value) {
425
        if (is_object($value)) {
426
            $value = '';
427
        }
428
        $metadataarray['meta_' . $key] = $value;
429
    }
430
    return $metadataarray;
431
}
432
433
/**
434
 * Helper function to sort an array of recordings. It compares the startTime in two recording objecs.
435
 *
436
 * @param object $a
437
 * @param object $b
438
 *
439
 * @return array
440
 */
441
function bigbluebuttonbn_recording_build_sorter($a, $b) {
442
    global $CFG;
443
    $resultless = !empty($CFG->bigbluebuttonbn_recordings_sortorder) ? -1 : 1;
444
    $resultmore = !empty($CFG->bigbluebuttonbn_recordings_sortorder) ? 1 : -1;
445
    if ($a['startTime'] < $b['startTime']) {
446
        return $resultless;
447
    }
448
    if ($a['startTime'] == $b['startTime']) {
449
        return 0;
450
    }
451
    return $resultmore;
452
}
453
454
/**
455
 * Perform deleteRecordings on BBB.
456
 *
457
 * @param string $recordids
458
 *
459
 * @return boolean
460
 */
461 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...
462
    $ids = explode(',', $recordids);
463
    foreach ($ids as $id) {
464
        $xml = bigbluebuttonbn_wrap_xml_load_file(
465
            \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('deleteRecordings', ['recordID' => $id])
466
        );
467
        if ($xml && $xml->returncode != 'SUCCESS') {
468
            return false;
469
        }
470
    }
471
    return true;
472
}
473
474
/**
475
 * Perform publishRecordings on BBB.
476
 *
477
 * @param string $recordids
478
 * @param string $publish
479
 */
480 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...
481
    $ids = explode(',', $recordids);
482
    foreach ($ids as $id) {
483
        $xml = bigbluebuttonbn_wrap_xml_load_file(
484
            \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('publishRecordings', ['recordID' => $id, 'publish' => $publish])
485
        );
486
        if ($xml && $xml->returncode != 'SUCCESS') {
487
            return false;
488
        }
489
    }
490
    return true;
491
}
492
493
/**
494
 * Perform updateRecordings on BBB.
495
 *
496
 * @param string $recordids
497
 * @param array $params ['key'=>param_key, 'value']
498
 */
499 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...
500
    $ids = explode(',', $recordids);
501
    foreach ($ids as $id) {
502
        $xml = bigbluebuttonbn_wrap_xml_load_file(
503
            \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('updateRecordings', ['recordID' => $id] + (array) $params)
504
        );
505
        if ($xml && $xml->returncode != 'SUCCESS') {
506
            return false;
507
        }
508
    }
509
    return true;
510
}
511
512
/**
513
 * Perform end on BBB.
514
 *
515
 * @param string $meetingid
516
 * @param string $modpw
517
 */
518
function bigbluebuttonbn_end_meeting($meetingid, $modpw) {
519
    $xml = bigbluebuttonbn_wrap_xml_load_file(
520
        \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('end', ['meetingID' => $meetingid, 'password' => $modpw])
521
    );
522
    if ($xml) {
523
        // If the xml packet returned failure it displays the message to the user.
524
        return array('returncode' => $xml->returncode, 'message' => $xml->message, 'messageKey' => $xml->messageKey);
525
    }
526
    // If the server is unreachable, then prompts the user of the necessary action.
527
    return null;
528
}
529
530
/**
531
 * Perform api request on BBB.
532
 *
533
 * @return string
534
 */
535
function bigbluebuttonbn_get_server_version() {
536
    $xml = bigbluebuttonbn_wrap_xml_load_file(
537
        \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url()
538
    );
539
    if ($xml && $xml->returncode == 'SUCCESS') {
540
        return $xml->version;
541
    }
542
    return null;
543
}
544
545
/**
546
 * Perform api request on BBB and wraps the response in an XML object
547
 *
548
 * @param string $url
549
 * @param string $method
550
 * @param string $data
551
 * @param string $contenttype
552
 *
553
 * @return object
554
 */
555
function bigbluebuttonbn_wrap_xml_load_file($url, $method = 'GET', $data = null, $contenttype = 'text/xml') {
556
    if (extension_loaded('curl')) {
557
        $response = bigbluebuttonbn_wrap_xml_load_file_curl_request($url, $method, $data, $contenttype);
558
        if (!$response) {
559
            debugging('No response on wrap_simplexml_load_file', DEBUG_DEVELOPER);
560
            return null;
561
        }
562
        $previous = libxml_use_internal_errors(true);
563
        try {
564
            $xml = simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA | LIBXML_NOBLANKS);
565
            return $xml;
566
        } catch (Exception $e) {
567
            libxml_use_internal_errors($previous);
568
            $error = 'Caught exception: ' . $e->getMessage();
569
            debugging($error, DEBUG_DEVELOPER);
570
            return null;
571
        }
572
    }
573
    // Alternative request non CURL based.
574
    $previous = libxml_use_internal_errors(true);
575
    try {
576
        $response = simplexml_load_file($url, 'SimpleXMLElement', LIBXML_NOCDATA | LIBXML_NOBLANKS);
577
        return $response;
578
    } catch (Exception $e) {
579
        $error = 'Caught exception: ' . $e->getMessage();
580
        debugging($error, DEBUG_DEVELOPER);
581
        libxml_use_internal_errors($previous);
582
        return null;
583
    }
584
}
585
586
/**
587
 * Perform api request on BBB using CURL and wraps the response in an XML object
588
 *
589
 * @param string $url
590
 * @param string $method
591
 * @param string $data
592
 * @param string $contenttype
593
 *
594
 * @return object
595
 */
596
function bigbluebuttonbn_wrap_xml_load_file_curl_request($url, $method = 'GET', $data = null, $contenttype = 'text/xml') {
597
    global $CFG;
598
    require_once($CFG->libdir . '/filelib.php');
599
    $c = new curl();
600
    $c->setopt(array('SSL_VERIFYPEER' => true));
601
    if ($method == 'POST') {
602
        if (is_null($data) || is_array($data)) {
603
            return $c->post($url);
604
        }
605
        $options = array();
606
        $options['CURLOPT_HTTPHEADER'] = array(
607
            'Content-Type: ' . $contenttype,
608
            'Content-Length: ' . strlen($data),
609
            'Content-Language: en-US',
610
        );
611
612
        return $c->post($url, $data, $options);
613
    }
614
    if ($method == 'HEAD') {
615
        $c->head($url, array('followlocation' => true, 'timeout' => 1));
616
        return $c->get_info();
617
    }
618
    return $c->get($url);
619
}
620
621
/**
622
 * End the session associated with this instance (if it's running).
623
 *
624
 * @param object $bigbluebuttonbn
625
 *
626
 * @return void
627
 */
628
function bigbluebuttonbn_end_meeting_if_running($bigbluebuttonbn) {
629
    $meetingid = $bigbluebuttonbn->meetingid . '-' . $bigbluebuttonbn->course . '-' . $bigbluebuttonbn->id;
630
    if (bigbluebuttonbn_is_meeting_running($meetingid)) {
631
        bigbluebuttonbn_end_meeting($meetingid, $bigbluebuttonbn->moderatorpass);
632
    }
633
}
634
635
/**
636
 * Returns user roles in a context.
637
 *
638
 * @param object $context
639
 * @param integer $userid
640
 *
641
 * @return array $userroles
642
 */
643
function bigbluebuttonbn_get_user_roles($context, $userid) {
644
    global $DB;
645
    $userroles = get_user_roles($context, $userid);
646
    if ($userroles) {
647
        $where = '';
648
        foreach ($userroles as $userrole) {
649
            $where .= (empty($where) ? ' WHERE' : ' OR') . ' id=' . $userrole->roleid;
650
        }
651
        $userroles = $DB->get_records_sql('SELECT * FROM {role}' . $where);
652
    }
653
    return $userroles;
654
}
655
656
/**
657
 * Returns guest role wrapped in an array.
658
 *
659
 * @return array
660
 */
661
function bigbluebuttonbn_get_guest_role() {
662
    $guestrole = get_guest_role();
663
    return array($guestrole->id => $guestrole);
664
}
665
666
/**
667
 * Returns an array containing all the users in a context.
668
 *
669
 * @param context $context
670
 *
671
 * @return array $users
672
 */
673
function bigbluebuttonbn_get_users(context $context = null) {
674
    $users = (array) get_enrolled_users($context, '', 0, 'u.*', null, 0, 0, true);
675
    foreach ($users as $key => $value) {
676
        $users[$key] = fullname($value);
677
    }
678
    return $users;
679
}
680
681
/**
682
 * Returns an array containing all the users in a context wrapped for html select element.
683
 *
684
 * @param context_course $context
685
 * @param null $bbactivity
686
 * @return array $users
687
 * @throws coding_exception
688
 * @throws moodle_exception
689
 */
690
function bigbluebuttonbn_get_users_select(context_course $context, $bbactivity = null) {
691
    // CONTRIB-7972, check the group of current user and course group mode.
692
    $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...
693
    $users = (array) get_enrolled_users($context, '', 0, 'u.*', null, 0, 0, true);
694
    $course = get_course($context->instanceid);
695
    $groupmode = groups_get_course_groupmode($course);
696
    if ($bbactivity) {
697
        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...
698
        $groupmode = groups_get_activity_groupmode($cm);
699
700
    }
701
    if ($groupmode == SEPARATEGROUPS && !has_capability('moodle/site:accessallgroups', $context)) {
702
        global $USER;
703
        $groups = groups_get_all_groups($course->id, $USER->id);
704
        $users = [];
705
        foreach ($groups as $g) {
706
            $users += (array) get_enrolled_users($context, '', $g->id, 'u.*', null, 0, 0, true);
707
        }
708
    }
709
    return array_map(
710
            function($u) {
711
                return array('id' => $u->id, 'name' => fullname($u));
712
            },
713
            $users);
714
}
715
716
/**
717
 * Returns an array containing all the roles in a context.
718
 *
719
 * @param context $context
720
 * @param bool $onlyviewableroles
721
 *
722
 * @return array $roles
723
 */
724
function bigbluebuttonbn_get_roles(context $context = null, bool $onlyviewableroles = true) {
725
    global $CFG;
726
727
    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...
728
        $roles = (array) get_viewable_roles($context);
729
        foreach ($roles as $key => $value) {
730
            $roles[$key] = $value;
731
        }
732
    } else {
733
        $roles = (array) role_get_names($context);
734
        foreach ($roles as $key => $value) {
735
            $roles[$key] = $value->localname;
736
        }
737
    }
738
739
    return $roles;
740
}
741
742
/**
743
 * Returns an array containing all the roles in a context wrapped for html select element.
744
 *
745
 * @param context $context
746
 * @param bool $onlyviewableroles
747
 *
748
 * @return array $users
749
 */
750
function bigbluebuttonbn_get_roles_select(context $context = null, bool $onlyviewableroles = true) {
751
    global $CFG;
752
753
    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...
754
        $roles = (array) get_viewable_roles($context);
755
        foreach ($roles as $key => $value) {
756
            $roles[$key] = array('id' => $key, 'name' => $value);
757
        }
758
    } else {
759
        $roles = (array) role_get_names($context);
760
        foreach ($roles as $key => $value) {
761
            $roles[$key] = array('id' => $value->id, 'name' => $value->localname);
762
        }
763
    }
764
765
    return $roles;
766
}
767
768
/**
769
 * Returns role that corresponds to an id.
770
 *
771
 * @param string|integer $id
772
 *
773
 * @return object $role
774
 */
775
function bigbluebuttonbn_get_role($id) {
776
    $roles = (array) role_get_names();
777
    if (is_numeric($id) && isset($roles[$id])) {
778
        return (object) $roles[$id];
779
    }
780
    foreach ($roles as $role) {
781
        if ($role->shortname == $id) {
782
            return $role;
783
        }
784
    }
785
}
786
787
/**
788
 * Returns an array to populate a list of participants used in mod_form.js.
789
 *
790
 * @param context $context
791
 * @param null|object $bbactivity
792
 * @return array $data
793
 */
794
function bigbluebuttonbn_get_participant_data($context, $bbactivity = null) {
795
    $data = array(
796
        'all' => array(
797
            'name' => get_string('mod_form_field_participant_list_type_all', 'bigbluebuttonbn'),
798
            'children' => []
799
        ),
800
    );
801
    $data['role'] = array(
802
        'name' => get_string('mod_form_field_participant_list_type_role', 'bigbluebuttonbn'),
803
        'children' => bigbluebuttonbn_get_roles_select($context, true)
804
      );
805
    $data['user'] = array(
806
        'name' => get_string('mod_form_field_participant_list_type_user', 'bigbluebuttonbn'),
807
        'children' => bigbluebuttonbn_get_users_select($context, $bbactivity),
0 ignored issues
show
Bug introduced by
It seems like $bbactivity defined by parameter $bbactivity on line 794 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...
808
    );
809
    return $data;
810
}
811
812
/**
813
 * Returns an array to populate a list of participants used in mod_form.php.
814
 *
815
 * @param object $bigbluebuttonbn
816
 * @param context $context
817
 *
818
 * @return array
819
 */
820
function bigbluebuttonbn_get_participant_list($bigbluebuttonbn, $context) {
821
    global $USER;
822
    if ($bigbluebuttonbn == null) {
823
        return bigbluebuttonbn_get_participant_rules_encoded(
824
            bigbluebuttonbn_get_participant_list_default($context, $USER->id)
825
        );
826
    }
827
    if (empty($bigbluebuttonbn->participants)) {
828
        $bigbluebuttonbn->participants = "[]";
829
    }
830
    $rules = json_decode($bigbluebuttonbn->participants, true);
831
    if (empty($rules)) {
832
        $rules = bigbluebuttonbn_get_participant_list_default($context, bigbluebuttonbn_instance_ownerid($bigbluebuttonbn));
833
    }
834
    return bigbluebuttonbn_get_participant_rules_encoded($rules);
835
}
836
837
/**
838
 * Returns an array to populate a list of participants used in mod_form.php with default values.
839
 *
840
 * @param context $context
841
 * @param integer $ownerid
842
 *
843
 * @return array
844
 */
845
function bigbluebuttonbn_get_participant_list_default($context, $ownerid = null) {
846
    $participantlist = array();
847
    $participantlist[] = array(
848
        'selectiontype' => 'all',
849
        'selectionid' => 'all',
850
        'role' => BIGBLUEBUTTONBN_ROLE_VIEWER,
851
    );
852
    $defaultrules = explode(',', \mod_bigbluebuttonbn\locallib\config::get('participant_moderator_default'));
853
    foreach ($defaultrules as $defaultrule) {
854
        if ($defaultrule == '0') {
855
            if (!empty($ownerid) && is_enrolled($context, $ownerid)) {
856
                $participantlist[] = array(
857
                    'selectiontype' => 'user',
858
                    'selectionid' => (string) $ownerid,
859
                    'role' => BIGBLUEBUTTONBN_ROLE_MODERATOR);
860
            }
861
            continue;
862
        }
863
        $participantlist[] = array(
864
            'selectiontype' => 'role',
865
            'selectionid' => $defaultrule,
866
            'role' => BIGBLUEBUTTONBN_ROLE_MODERATOR);
867
    }
868
    return $participantlist;
869
}
870
871
/**
872
 * Returns an array to populate a list of participants used in mod_form.php with bigbluebuttonbn values.
873
 *
874
 * @param array $rules
875
 *
876
 * @return array
877
 */
878
function bigbluebuttonbn_get_participant_rules_encoded($rules) {
879
    foreach ($rules as $key => $rule) {
880
        if ($rule['selectiontype'] !== 'role' || is_numeric($rule['selectionid'])) {
881
            continue;
882
        }
883
        $role = bigbluebuttonbn_get_role($rule['selectionid']);
884
        if ($role == null) {
885
            unset($rules[$key]);
886
            continue;
887
        }
888
        $rule['selectionid'] = $role->id;
889
        $rules[$key] = $rule;
890
    }
891
    return $rules;
892
}
893
894
/**
895
 * Returns an array to populate a list of participant_selection used in mod_form.php.
896
 *
897
 * @return array
898
 */
899
function bigbluebuttonbn_get_participant_selection_data() {
900
    return [
901
        'type_options' => [
902
            'all' => get_string('mod_form_field_participant_list_type_all', 'bigbluebuttonbn'),
903
            'role' => get_string('mod_form_field_participant_list_type_role', 'bigbluebuttonbn'),
904
            'user' => get_string('mod_form_field_participant_list_type_user', 'bigbluebuttonbn'),
905
        ],
906
        'type_selected' => 'all',
907
        'options' => ['all' => '---------------'],
908
        'selected' => 'all',
909
    ];
910
}
911
912
/**
913
 * Evaluate if a user in a context is moderator based on roles and participation rules.
914
 *
915
 * @param context $context
916
 * @param array $participantlist
917
 * @param integer $userid
918
 *
919
 * @return boolean
920
 */
921
function bigbluebuttonbn_is_moderator($context, $participantlist, $userid = null) {
922
    global $USER;
923
    if (!is_array($participantlist)) {
924
        return false;
925
    }
926
    if (empty($userid)) {
927
        $userid = $USER->id;
928
    }
929
    $userroles = bigbluebuttonbn_get_guest_role();
930
    if (!isguestuser()) {
931
        $userroles = bigbluebuttonbn_get_user_roles($context, $userid);
932
    }
933
    return bigbluebuttonbn_is_moderator_validator($participantlist, $userid, $userroles);
934
}
935
936
/**
937
 * Iterates participant list rules to evaluate if a user is moderator.
938
 *
939
 * @param array $participantlist
940
 * @param integer $userid
941
 * @param array $userroles
942
 *
943
 * @return boolean
944
 */
945
function bigbluebuttonbn_is_moderator_validator($participantlist, $userid, $userroles) {
946
    // Iterate participant rules.
947
    foreach ($participantlist as $participant) {
948
        if (bigbluebuttonbn_is_moderator_validate_rule($participant, $userid, $userroles)) {
949
            return true;
950
        }
951
    }
952
    return false;
953
}
954
955
/**
956
 * Evaluate if a user is moderator based on roles and a particular participation rule.
957
 *
958
 * @param object $participant
959
 * @param integer $userid
960
 * @param array $userroles
961
 *
962
 * @return boolean
963
 */
964
function bigbluebuttonbn_is_moderator_validate_rule($participant, $userid, $userroles) {
965
    if ($participant['role'] == BIGBLUEBUTTONBN_ROLE_VIEWER) {
966
        return false;
967
    }
968
    // Validation for the 'all' rule.
969
    if ($participant['selectiontype'] == 'all') {
970
        return true;
971
    }
972
    // Validation for a 'user' rule.
973
    if ($participant['selectiontype'] == 'user') {
974
        if ($participant['selectionid'] == $userid) {
975
            return true;
976
        }
977
        return false;
978
    }
979
    // Validation for a 'role' rule.
980
    $role = bigbluebuttonbn_get_role($participant['selectionid']);
981
    if ($role != null && array_key_exists($role->id, $userroles)) {
982
        return true;
983
    }
984
    return false;
985
}
986
987
/**
988
 * Helper returns error message key for the language file that corresponds to a bigbluebutton error key.
989
 *
990
 * @param string $messagekey
991
 * @param string $defaultkey
992
 *
993
 * @return string
994
 */
995
function bigbluebuttonbn_get_error_key($messagekey, $defaultkey = null) {
996
    if ($messagekey == 'checksumError') {
997
        return 'index_error_checksum';
998
    }
999
    if ($messagekey == 'maxConcurrent') {
1000
        return 'view_error_max_concurrent';
1001
    }
1002
    return $defaultkey;
1003
}
1004
1005
/**
1006
 * Helper evaluates if a voicebridge number is unique.
1007
 *
1008
 * @param integer $instance
1009
 * @param integer $voicebridge
1010
 *
1011
 * @return string
1012
 */
1013
function bigbluebuttonbn_voicebridge_unique($instance, $voicebridge) {
1014
    global $DB;
1015
    if ($voicebridge == 0) {
1016
        return true;
1017
    }
1018
    $select = 'voicebridge = ' . $voicebridge;
1019
    if ($instance != 0) {
1020
        $select .= ' AND id <>' . $instance;
1021
    }
1022
    if (!$DB->get_records_select('bigbluebuttonbn', $select)) {
1023
        return true;
1024
    }
1025
    return false;
1026
}
1027
1028
/**
1029
 * Helper estimate a duration for the meeting based on the closingtime.
1030
 *
1031
 * @param integer $closingtime
1032
 *
1033
 * @return integer
1034
 */
1035
function bigbluebuttonbn_get_duration($closingtime) {
1036
    $duration = 0;
1037
    $now = time();
1038
    if ($closingtime > 0 && $now < $closingtime) {
1039
        $duration = ceil(($closingtime - $now) / 60);
1040
        $compensationtime = intval((int) \mod_bigbluebuttonbn\locallib\config::get('scheduled_duration_compensation'));
1041
        $duration = intval($duration) + $compensationtime;
1042
    }
1043
    return $duration;
1044
}
1045
1046
/**
1047
 * Helper return array containing the file descriptor for a preuploaded presentation.
1048
 *
1049
 * @param context $context
1050
 * @param string $presentation
1051
 * @param integer $id
1052
 *
1053
 * @return array
1054
 */
1055
function bigbluebuttonbn_get_presentation_array($context, $presentation, $id = null) {
1056
    global $CFG;
1057
    if (empty($presentation)) {
1058
        if ($CFG->bigbluebuttonbn_preuploadpresentation_enabled) {
1059
            // Item has not presentation but presentation is enabled..
1060
            // Check if exist some file by default in general mod setting ("presentationdefault").
1061
            $fs = get_file_storage();
1062
            $files = $fs->get_area_files(
1063
                context_system::instance()->id,
1064
                'mod_bigbluebuttonbn',
1065
                'presentationdefault',
1066
                0,
1067
                "filename",
1068
                false
1069
            );
1070
1071 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...
1072
                // Not exist file by default in "presentationbydefault" setting.
1073
                return array('url' => null, 'name' => null, 'icon' => null, 'mimetype_description' => null);
1074
            }
1075
1076
            // Exists file in general setting to use as default for presentation. Cache image for temp public access.
1077
            $file = reset($files);
1078
            unset($files);
1079
            $pnoncevalue = null;
1080 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...
1081
                // Create the nonce component for granting a temporary public access.
1082
                $cache = cache::make_from_params(
1083
                    cache_store::MODE_APPLICATION,
1084
                    'mod_bigbluebuttonbn',
1085
                    'presentationdefault_cache'
1086
                );
1087
                $pnoncekey = sha1(context_system::instance()->id);
1088
                /* The item id was adapted for granting public access to the presentation once in order
1089
                 * to allow BigBlueButton to gather the file. */
1090
                $pnoncevalue = bigbluebuttonbn_generate_nonce();
1091
                $cache->set($pnoncekey, array('value' => $pnoncevalue, 'counter' => 0));
1092
            }
1093
1094
            $url = moodle_url::make_pluginfile_url(
1095
                $file->get_contextid(),
1096
                $file->get_component(),
1097
                $file->get_filearea(),
1098
                $pnoncevalue,
1099
                $file->get_filepath(),
1100
                $file->get_filename()
1101
            );
1102
            return (array('name' => $file->get_filename(), 'icon' => file_file_icon($file, 24),
1103
                'url' => $url->out(false), 'mimetype_description' => get_mimetype_description($file)));
1104
        }
1105
1106
        return array('url' => null, 'name' => null, 'icon' => null, 'mimetype_description' => null);
1107
    }
1108
    $fs = get_file_storage();
1109
    $files = $fs->get_area_files(
1110
        $context->id,
1111
        'mod_bigbluebuttonbn',
1112
        'presentation',
1113
        0,
1114
        'itemid, filepath, filename',
1115
        false
1116
    );
1117 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...
1118
        return array('url' => null, 'name' => null, 'icon' => null, 'mimetype_description' => null);
1119
    }
1120
    $file = reset($files);
1121
    unset($files);
1122
    $pnoncevalue = null;
1123 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...
1124
        // Create the nonce component for granting a temporary public access.
1125
        $cache = cache::make_from_params(
1126
            cache_store::MODE_APPLICATION,
1127
            'mod_bigbluebuttonbn',
1128
            'presentation_cache'
1129
        );
1130
        $pnoncekey = sha1($id);
1131
        /* The item id was adapted for granting public access to the presentation once in order
1132
         * to allow BigBlueButton to gather the file. */
1133
        $pnoncevalue = bigbluebuttonbn_generate_nonce();
1134
        $cache->set($pnoncekey, array('value' => $pnoncevalue, 'counter' => 0));
1135
    }
1136
    $url = moodle_url::make_pluginfile_url(
1137
        $file->get_contextid(),
1138
        $file->get_component(),
1139
        $file->get_filearea(),
1140
        $pnoncevalue,
1141
        $file->get_filepath(),
1142
        $file->get_filename()
1143
    );
1144
    return array('name' => $file->get_filename(), 'icon' => file_file_icon($file, 24),
1145
        'url' => $url->out(false), 'mimetype_description' => get_mimetype_description($file));
1146
}
1147
1148
/**
1149
 * Helper generates a nonce used for the preuploaded presentation callback url.
1150
 *
1151
 * @return string
1152
 */
1153
function bigbluebuttonbn_generate_nonce() {
1154
    $mt = microtime();
1155
    $rand = mt_rand();
1156
    return md5($mt . $rand);
1157
}
1158
1159
/**
1160
 * Helper generates a random password.
1161
 *
1162
 * @param integer $length
1163
 * @param string $unique
1164
 *
1165
 * @return string
1166
 */
1167
function bigbluebuttonbn_random_password($length = 8, $unique = "") {
1168
    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
1169
    do {
1170
        $password = substr(str_shuffle($chars), 0, $length);
1171
    } while ($unique == $password);
1172
    return $password;
1173
}
1174
1175
/**
1176
 * Helper register a bigbluebuttonbn event.
1177
 *
1178
 * @param string $type
1179
 * @param object $bigbluebuttonbn
1180
 * @param array $options [timecreated, userid, other]
1181
 *
1182
 * @return void
1183
 */
1184
function bigbluebuttonbn_event_log($type, $bigbluebuttonbn, $options = []) {
1185
    global $DB;
1186
    if (!in_array($type, \mod_bigbluebuttonbn\event\events::$events)) {
1187
        // No log will be created.
1188
        return;
1189
    }
1190
    $course = $DB->get_record('course', array('id' => $bigbluebuttonbn->course), '*', MUST_EXIST);
1191
    $cm = get_coursemodule_from_instance('bigbluebuttonbn', $bigbluebuttonbn->id, $course->id, false, MUST_EXIST);
1192
    $context = context_module::instance($cm->id);
1193
    $params = array('context' => $context, 'objectid' => $bigbluebuttonbn->id);
1194
    if (array_key_exists('timecreated', $options)) {
1195
        $params['timecreated'] = $options['timecreated'];
1196
    }
1197
    if (array_key_exists('userid', $options)) {
1198
        $params['userid'] = $options['userid'];
1199
    }
1200
    if (array_key_exists('other', $options)) {
1201
        $params['other'] = $options['other'];
1202
    }
1203
    $event = call_user_func_array(
1204
        '\mod_bigbluebuttonbn\event\\' . $type . '::create',
1205
        array($params)
1206
    );
1207
    $event->add_record_snapshot('course_modules', $cm);
1208
    $event->add_record_snapshot('course', $course);
1209
    $event->add_record_snapshot('bigbluebuttonbn', $bigbluebuttonbn);
1210
    $event->trigger();
1211
}
1212
1213
/**
1214
 * Updates the meeting info cached object when a participant has joined.
1215
 *
1216
 * @param string $meetingid
1217
 * @param bool $ismoderator
1218
 *
1219
 * @return void
1220
 */
1221
function bigbluebuttonbn_participant_joined($meetingid, $ismoderator) {
1222
    $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'mod_bigbluebuttonbn', 'meetings_cache');
1223
    $result = $cache->get($meetingid);
1224
    $meetinginfo = json_decode($result['meeting_info']);
1225
    $meetinginfo->participantCount += 1;
1226
    if ($ismoderator) {
1227
        $meetinginfo->moderatorCount += 1;
1228
    }
1229
    $cache->set($meetingid, array('creation_time' => $result['creation_time'],
1230
        'meeting_info' => json_encode($meetinginfo)));
1231
}
1232
1233
/**
1234
 * Gets a meeting info object cached or fetched from the live session.
1235
 *
1236
 * @param string $meetingid
1237
 * @param boolean $updatecache
1238
 *
1239
 * @return array
1240
 */
1241
function bigbluebuttonbn_get_meeting_info($meetingid, $updatecache = false) {
1242
    $cachettl = (int) \mod_bigbluebuttonbn\locallib\config::get('waitformoderator_cache_ttl');
1243
    $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'mod_bigbluebuttonbn', 'meetings_cache');
1244
    $result = $cache->get($meetingid);
1245
    $now = time();
1246
    if (!$updatecache && !empty($result) && $now < ($result['creation_time'] + $cachettl)) {
1247
        // Use the value in the cache.
1248
        return (array) json_decode($result['meeting_info']);
1249
    }
1250
    // Ping again and refresh the cache.
1251
    $meetinginfo = (array) bigbluebuttonbn_wrap_xml_load_file(
1252
        \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('getMeetingInfo', ['meetingID' => $meetingid])
1253
    );
1254
    $cache->set($meetingid, array('creation_time' => time(), 'meeting_info' => json_encode($meetinginfo)));
1255
    return $meetinginfo;
1256
}
1257
1258
/**
1259
 * Perform isMeetingRunning on BBB.
1260
 *
1261
 * @param string $meetingid
1262
 * @param boolean $updatecache
1263
 *
1264
 * @return boolean
1265
 */
1266
function bigbluebuttonbn_is_meeting_running($meetingid, $updatecache = false) {
1267
    /* As a workaround to isMeetingRunning that always return SUCCESS but only returns true
1268
     * when at least one user is in the session, we use getMeetingInfo instead.
1269
     */
1270
    $meetinginfo = bigbluebuttonbn_get_meeting_info($meetingid, $updatecache);
1271
    return ($meetinginfo['returncode'] === 'SUCCESS');
1272
}
1273
1274
/**
1275
 * Publish an imported recording.
1276
 *
1277
 * @param string $id
1278
 * @param boolean $publish
1279
 *
1280
 * @return boolean
1281
 */
1282 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...
1283
    global $DB;
1284
    // Locate the record to be updated.
1285
    $record = $DB->get_record('bigbluebuttonbn_logs', array('id' => $id));
1286
    $meta = json_decode($record->meta, true);
1287
    // Prepare data for the update.
1288
    $meta['recording']['published'] = ($publish) ? 'true' : 'false';
1289
    $record->meta = json_encode($meta);
1290
    // Proceed with the update.
1291
    $DB->update_record('bigbluebuttonbn_logs', $record);
1292
    return true;
1293
}
1294
1295
/**
1296
 * Delete an imported recording.
1297
 *
1298
 * @param string $id
1299
 *
1300
 * @return boolean
1301
 */
1302
function bigbluebuttonbn_delete_recording_imported($id) {
1303
    global $DB;
1304
    // Execute delete.
1305
    $DB->delete_records('bigbluebuttonbn_logs', array('id' => $id));
1306
    return true;
1307
}
1308
1309
/**
1310
 * Update an imported recording.
1311
 *
1312
 * @param string $id
1313
 * @param array $params ['key'=>param_key, 'value']
1314
 *
1315
 * @return boolean
1316
 */
1317
function bigbluebuttonbn_update_recording_imported($id, $params) {
1318
    global $DB;
1319
    // Locate the record to be updated.
1320
    $record = $DB->get_record('bigbluebuttonbn_logs', array('id' => $id));
1321
    $meta = json_decode($record->meta, true);
1322
    // Prepare data for the update.
1323
    $meta['recording'] = $params + $meta['recording'];
1324
    $record->meta = json_encode($meta);
1325
    // Proceed with the update.
1326
    if (!$DB->update_record('bigbluebuttonbn_logs', $record)) {
1327
        return false;
1328
    }
1329
    return true;
1330
}
1331
1332
/**
1333
 * Protect/Unprotect an imported recording.
1334
 *
1335
 * @param string $id
1336
 * @param boolean $protect
1337
 *
1338
 * @return boolean
1339
 */
1340 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...
1341
    global $DB;
1342
    // Locate the record to be updated.
1343
    $record = $DB->get_record('bigbluebuttonbn_logs', array('id' => $id));
1344
    $meta = json_decode($record->meta, true);
1345
    // Prepare data for the update.
1346
    $meta['recording']['protected'] = ($protect) ? 'true' : 'false';
1347
    $record->meta = json_encode($meta);
1348
    // Proceed with the update.
1349
    $DB->update_record('bigbluebuttonbn_logs', $record);
1350
    return true;
1351
}
1352
1353
/**
1354
 * Sets a custom config.xml file for being used on create.
1355
 *
1356
 * @param string $meetingid
1357
 * @param string $configxml
1358
 *
1359
 * @return object
1360
 */
1361
function bigbluebuttonbn_set_config_xml($meetingid, $configxml) {
1362
    $urldefaultconfig = \mod_bigbluebuttonbn\locallib\config::get('server_url') . 'api/setConfigXML?';
1363
    $configxmlparams = bigbluebuttonbn_set_config_xml_params($meetingid, $configxml);
1364
    $xml = bigbluebuttonbn_wrap_xml_load_file(
1365
        $urldefaultconfig,
1366
        'POST',
1367
        $configxmlparams,
1368
        'application/x-www-form-urlencoded'
1369
    );
1370
    return $xml;
1371
}
1372
1373
/**
1374
 * Sets qs used with a custom config.xml file request.
1375
 *
1376
 * @param string $meetingid
1377
 * @param string $configxml
1378
 *
1379
 * @return string
1380
 */
1381
function bigbluebuttonbn_set_config_xml_params($meetingid, $configxml) {
1382
    $params = 'configXML=' . urlencode($configxml) . '&meetingID=' . urlencode($meetingid);
1383
    $sharedsecret = \mod_bigbluebuttonbn\locallib\config::get('shared_secret');
1384
    $configxmlparams = $params . '&checksum=' . sha1('setConfigXML' . $params . $sharedsecret);
1385
    return $configxmlparams;
1386
}
1387
1388
/**
1389
 * Sets a custom config.xml file for being used on create.
1390
 *
1391
 * @param string $meetingid
1392
 * @param string $configxml
1393
 *
1394
 * @return array
1395
 */
1396
function bigbluebuttonbn_set_config_xml_array($meetingid, $configxml) {
1397
    $configxml = bigbluebuttonbn_set_config_xml($meetingid, $configxml);
1398
    $configxmlarray = (array) $configxml;
1399
    if ($configxmlarray['returncode'] != 'SUCCESS') {
1400
        debugging('BigBlueButton was not able to set the custom config.xml file', DEBUG_DEVELOPER);
1401
        return '';
1402
    }
1403
    return $configxmlarray['configToken'];
1404
}
1405
1406
/**
1407
 * Helper function builds a row for the data used by the recording table.
1408
 *
1409
 * @param array $bbbsession
1410
 * @param array $recording
1411
 * @param array $tools
1412
 *
1413
 * @return array
1414
 */
1415
function bigbluebuttonbn_get_recording_data_row($bbbsession, $recording, $tools = ['protect', 'publish', 'delete']) {
1416
    if (!bigbluebuttonbn_include_recording_table_row($bbbsession, $recording)) {
1417
        return;
1418
    }
1419
    $rowdata = new stdClass();
1420
    // Set recording_types.
1421
    $rowdata->playback = bigbluebuttonbn_get_recording_data_row_types($recording, $bbbsession);
1422
    // Set activity name.
1423
    $rowdata->recording = bigbluebuttonbn_get_recording_data_row_meta_activity($recording, $bbbsession);
1424
    // Set activity description.
1425
    $rowdata->description = bigbluebuttonbn_get_recording_data_row_meta_description($recording, $bbbsession);
1426
    if (bigbluebuttonbn_get_recording_data_preview_enabled($bbbsession)) {
1427
        // Set recording_preview.
1428
        $rowdata->preview = bigbluebuttonbn_get_recording_data_row_preview($recording);
1429
    }
1430
    // Set date.
1431
    $rowdata->date = bigbluebuttonbn_get_recording_data_row_date($recording);
1432
    // Set formatted date.
1433
    $rowdata->date_formatted = bigbluebuttonbn_get_recording_data_row_date_formatted($rowdata->date);
1434
    // Set formatted duration.
1435
    $rowdata->duration_formatted = $rowdata->duration = bigbluebuttonbn_get_recording_data_row_duration($recording);
1436
    // Set actionbar, if user is allowed to manage recordings.
1437
    if ($bbbsession['managerecordings']) {
1438
        $rowdata->actionbar = bigbluebuttonbn_get_recording_data_row_actionbar($recording, $tools);
1439
    }
1440
    return $rowdata;
1441
}
1442
1443
/**
1444
 * Helper function evaluates if a row for the data used by the recording table is editable.
1445
 *
1446
 * @param array $bbbsession
1447
 *
1448
 * @return boolean
1449
 */
1450
function bigbluebuttonbn_get_recording_data_row_editable($bbbsession) {
1451
    return ($bbbsession['managerecordings'] && ((double) $bbbsession['serverversion'] >= 1.0 || $bbbsession['bnserver']));
1452
}
1453
1454
/**
1455
 * Helper function evaluates if recording preview should be included.
1456
 *
1457
 * @param array $bbbsession
1458
 *
1459
 * @return boolean
1460
 */
1461
function bigbluebuttonbn_get_recording_data_preview_enabled($bbbsession) {
1462
    return ((double) $bbbsession['serverversion'] >= 1.0 && $bbbsession['bigbluebuttonbn']->recordings_preview == '1');
1463
}
1464
1465
/**
1466
 * Helper function converts recording date used in row for the data used by the recording table.
1467
 *
1468
 * @param array $recording
1469
 *
1470
 * @return integer
1471
 */
1472
function bigbluebuttonbn_get_recording_data_row_date($recording) {
1473
    if (!isset($recording['startTime'])) {
1474
        return 0;
1475
    }
1476
    return floatval($recording['startTime']);
1477
}
1478
1479
/**
1480
 * Helper function format recording date used in row for the data used by the recording table.
1481
 *
1482
 * @param integer $starttime
1483
 *
1484
 * @return string
1485
 */
1486
function bigbluebuttonbn_get_recording_data_row_date_formatted($starttime) {
1487
    global $USER;
1488
    $starttime = $starttime - ($starttime % 1000);
1489
    // Set formatted date.
1490
    $dateformat = get_string('strftimerecentfull', 'langconfig') . ' %Z';
1491
    return userdate($starttime / 1000, $dateformat, usertimezone($USER->timezone));
1492
}
1493
1494
/**
1495
 * Helper function converts recording duration used in row for the data used by the recording table.
1496
 *
1497
 * @param array $recording
1498
 *
1499
 * @return integer
1500
 */
1501
function bigbluebuttonbn_get_recording_data_row_duration($recording) {
1502
    foreach (array_values($recording['playbacks']) as $playback) {
1503
        // Ignore restricted playbacks.
1504
        if (array_key_exists('restricted', $playback) && strtolower($playback['restricted']) == 'true') {
1505
            continue;
1506
        }
1507
        // Take the lenght form the fist playback with an actual value.
1508
        if (!empty($playback['length'])) {
1509
            return intval($playback['length']);
1510
        }
1511
    }
1512
    return 0;
1513
}
1514
1515
/**
1516
 * Helper function builds recording actionbar used in row for the data used by the recording table.
1517
 *
1518
 * @param array $recording
1519
 * @param array $tools
1520
 *
1521
 * @return string
1522
 */
1523
function bigbluebuttonbn_get_recording_data_row_actionbar($recording, $tools) {
1524
    $actionbar = '';
1525
    foreach ($tools as $tool) {
1526
        $buttonpayload = bigbluebuttonbn_get_recording_data_row_actionbar_payload($recording, $tool);
1527
        if ($tool == 'protect') {
1528
            if (isset($recording['imported'])) {
1529
                $buttonpayload['disabled'] = 'disabled';
1530
            }
1531
            if (!isset($recording['protected'])) {
1532
                $buttonpayload['disabled'] = 'invisible';
1533
            }
1534
        }
1535
        $actionbar .= bigbluebuttonbn_actionbar_render_button($recording, $buttonpayload);
1536
    }
1537
    $head = html_writer::start_tag('div', array(
1538
        'id' => 'recording-actionbar-' . $recording['recordID'],
1539
        'data-recordingid' => $recording['recordID'],
1540
        'data-meetingid' => $recording['meetingID']));
1541
    $tail = html_writer::end_tag('div');
1542
    return $head . $actionbar . $tail;
1543
}
1544
1545
/**
1546
 * Helper function returns the corresponding payload for an actionbar button used in row
1547
 * for the data used by the recording table.
1548
 *
1549
 * @param array $recording
1550
 * @param array $tool
1551
 *
1552
 * @return array
1553
 */
1554
function bigbluebuttonbn_get_recording_data_row_actionbar_payload($recording, $tool) {
1555
    if ($tool == 'protect') {
1556
        $protected = 'false';
1557
        if (isset($recording['protected'])) {
1558
            $protected = $recording['protected'];
1559
        }
1560
        return bigbluebuttonbn_get_recording_data_row_action_protect($protected);
1561
    }
1562
    if ($tool == 'publish') {
1563
        return bigbluebuttonbn_get_recording_data_row_action_publish($recording['published']);
1564
    }
1565
    return array('action' => $tool, 'tag' => $tool);
1566
}
1567
1568
/**
1569
 * Helper function returns the payload for protect action button used in row
1570
 * for the data used by the recording table.
1571
 *
1572
 * @param string $protected
1573
 *
1574
 * @return array
1575
 */
1576
function bigbluebuttonbn_get_recording_data_row_action_protect($protected) {
1577
    if ($protected == 'true') {
1578
        return array('action' => 'unprotect', 'tag' => 'lock');
1579
    }
1580
    return array('action' => 'protect', 'tag' => 'unlock');
1581
}
1582
1583
/**
1584
 * Helper function returns the payload for publish action button used in row
1585
 * for the data used by the recording table.
1586
 *
1587
 * @param string $published
1588
 *
1589
 * @return array
1590
 */
1591
function bigbluebuttonbn_get_recording_data_row_action_publish($published) {
1592
    if ($published == 'true') {
1593
        return array('action' => 'unpublish', 'tag' => 'hide');
1594
    }
1595
    return array('action' => 'publish', 'tag' => 'show');
1596
}
1597
1598
/**
1599
 * Helper function builds recording preview used in row for the data used by the recording table.
1600
 *
1601
 * @param array $recording
1602
 *
1603
 * @return string
1604
 */
1605
function bigbluebuttonbn_get_recording_data_row_preview($recording) {
1606
    $options = array('id' => 'preview-' . $recording['recordID']);
1607
    if ($recording['published'] === 'false') {
1608
        $options['hidden'] = 'hidden';
1609
    }
1610
    $recordingpreview = html_writer::start_tag('div', $options);
1611
    foreach ($recording['playbacks'] as $playback) {
1612
        if (isset($playback['preview'])) {
1613
            $recordingpreview .= bigbluebuttonbn_get_recording_data_row_preview_images($playback);
1614
            break;
1615
        }
1616
    }
1617
    $recordingpreview .= html_writer::end_tag('div');
1618
    return $recordingpreview;
1619
}
1620
1621
/**
1622
 * Helper function builds element with actual images used in recording preview row based on a selected playback.
1623
 *
1624
 * @param array $playback
1625
 *
1626
 * @return string
1627
 */
1628
function bigbluebuttonbn_get_recording_data_row_preview_images($playback) {
1629
    global $CFG;
1630
    $recordingpreview  = html_writer::start_tag('div', array('class' => 'container-fluid'));
1631
    $recordingpreview .= html_writer::start_tag('div', array('class' => 'row'));
1632
    foreach ($playback['preview'] as $image) {
1633
        if ($CFG->bigbluebuttonbn_recordings_validate_url && !bigbluebuttonbn_is_valid_resource(trim($image['url']))) {
1634
            return '';
1635
        }
1636
        $recordingpreview .= html_writer::start_tag('div', array('class' => ''));
1637
        $recordingpreview .= html_writer::empty_tag(
1638
            'img',
1639
            array('src' => trim($image['url']) . '?' . time(), 'class' => 'recording-thumbnail pull-left')
1640
        );
1641
        $recordingpreview .= html_writer::end_tag('div');
1642
    }
1643
    $recordingpreview .= html_writer::end_tag('div');
1644
    $recordingpreview .= html_writer::start_tag('div', array('class' => 'row'));
1645
    $recordingpreview .= html_writer::tag(
1646
        'div',
1647
        get_string('view_recording_preview_help', 'bigbluebuttonbn'),
1648
        array('class' => 'text-center text-muted small')
1649
    );
1650
    $recordingpreview .= html_writer::end_tag('div');
1651
    $recordingpreview .= html_writer::end_tag('div');
1652
    return $recordingpreview;
1653
}
1654
1655
/**
1656
 * Helper function renders recording types to be used in row for the data used by the recording table.
1657
 *
1658
 * @param array $recording
1659
 * @param array $bbbsession
1660
 *
1661
 * @return string
1662
 */
1663
function bigbluebuttonbn_get_recording_data_row_types($recording, $bbbsession) {
1664
    $dataimported = 'false';
1665
    $title = '';
1666
    if (isset($recording['imported'])) {
1667
        $dataimported = 'true';
1668
        $title = get_string('view_recording_link_warning', 'bigbluebuttonbn');
1669
    }
1670
    $visibility = '';
1671
    if ($recording['published'] === 'false') {
1672
        $visibility = 'hidden ';
1673
    }
1674
    $id = 'playbacks-' . $recording['recordID'];
1675
    $recordingtypes = html_writer::start_tag('div', array('id' => $id, 'data-imported' => $dataimported,
1676
        'data-meetingid' => $recording['meetingID'], 'data-recordingid' => $recording['recordID'],
1677
        'title' => $title, $visibility => $visibility));
1678
    foreach ($recording['playbacks'] as $playback) {
1679
        $recordingtypes .= bigbluebuttonbn_get_recording_data_row_type($recording, $bbbsession, $playback);
1680
    }
1681
    $recordingtypes .= html_writer::end_tag('div');
1682
    return $recordingtypes;
1683
}
1684
1685
/**
1686
 * Helper function renders the link used for recording type in row for the data used by the recording table.
1687
 *
1688
 * @param array $recording
1689
 * @param array $bbbsession
1690
 * @param array $playback
1691
 *
1692
 * @return string
1693
 */
1694
function bigbluebuttonbn_get_recording_data_row_type($recording, $bbbsession, $playback) {
1695
    global $CFG, $OUTPUT;
1696
    if (!bigbluebuttonbn_include_recording_data_row_type($recording, $bbbsession, $playback)) {
1697
        return '';
1698
    }
1699
    $text = bigbluebuttonbn_get_recording_type_text($playback['type']);
1700
    $href = $CFG->wwwroot . '/mod/bigbluebuttonbn/bbb_view.php?action=play&bn=' . $bbbsession['bigbluebuttonbn']->id .
1701
        '&mid=' . $recording['meetingID'] . '&rid=' . $recording['recordID'] . '&rtype=' . $playback['type'];
1702
    if (!isset($recording['imported']) || !isset($recording['protected']) || $recording['protected'] === 'false') {
1703
        $href .= '&href=' . urlencode(trim($playback['url']));
1704
    }
1705
    $linkattributes = array(
1706
        'id' => 'recording-play-' . $playback['type'] . '-' . $recording['recordID'],
1707
        'class' => 'btn btn-sm btn-default',
1708
        'onclick' => 'M.mod_bigbluebuttonbn.recordings.recordingPlay(this);',
1709
        'data-action' => 'play',
1710
        'data-target' => $playback['type'],
1711
        'data-href' => $href,
1712
      );
1713
    if ($CFG->bigbluebuttonbn_recordings_validate_url && !bigbluebuttonbn_is_bn_server()
1714
            && !bigbluebuttonbn_is_valid_resource(trim($playback['url']))) {
1715
        $linkattributes['class'] = 'btn btn-sm btn-warning';
1716
        $linkattributes['title'] = get_string('view_recording_format_errror_unreachable', 'bigbluebuttonbn');
1717
        unset($linkattributes['data-href']);
1718
    }
1719
    return $OUTPUT->action_link('#', $text, null, $linkattributes) . '&#32;';
1720
}
1721
1722
/**
1723
 * Helper function to handle yet unknown recording types
1724
 *
1725
 * @param string $playbacktype : for now presentation, video, statistics, capture, notes, podcast
1726
 *
1727
 * @return string the matching language string or a capitalised version of the provided string
1728
 */
1729
function bigbluebuttonbn_get_recording_type_text($playbacktype) {
1730
    // Check first if string exists, and if it does'nt just default to the capitalised version of the string.
1731
    $text = ucwords($playbacktype);
1732
    $typestringid = 'view_recording_format_' . $playbacktype;
1733
    if (get_string_manager()->string_exists($typestringid, 'bigbluebuttonbn')) {
1734
        $text = get_string($typestringid, 'bigbluebuttonbn');
1735
    }
1736
    return $text;
1737
}
1738
1739
/**
1740
 * Helper function validates a remote resource.
1741
 *
1742
 * @param string $url
1743
 *
1744
 * @return boolean
1745
 */
1746
function bigbluebuttonbn_is_valid_resource($url) {
1747
    $urlhost = parse_url($url, PHP_URL_HOST);
1748
    $serverurlhost = parse_url(\mod_bigbluebuttonbn\locallib\config::get('server_url'), PHP_URL_HOST);
1749
    // Skip validation when the recording URL host is the same as the configured BBB server.
1750
    if ($urlhost == $serverurlhost) {
1751
        return true;
1752
    }
1753
    // Skip validation when the recording URL was already validated.
1754
    $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...
1755
    if (array_key_exists($urlhost, $validatedurls)) {
1756
        return $validatedurls[$urlhost];
1757
    }
1758
    // Validate the recording URL.
1759
    $validatedurls[$urlhost] = true;
1760
    $curlinfo = bigbluebuttonbn_wrap_xml_load_file_curl_request($url, 'HEAD');
1761
    if (!isset($curlinfo['http_code']) || $curlinfo['http_code'] != 200) {
1762
        $error = "Resources hosted by " . $urlhost . " are unreachable. Server responded with code " . $curlinfo['http_code'];
1763
        debugging($error, DEBUG_DEVELOPER);
1764
        $validatedurls[$urlhost] = false;
1765
    }
1766
    bigbluebuttonbn_cache_set('recordings_cache', 'validated_urls', $validatedurls);
1767
    return $validatedurls[$urlhost];
1768
}
1769
1770
/**
1771
 * Helper function renders the name for meeting used in row for the data used by the recording table.
1772
 *
1773
 * @param array $recording
1774
 * @param array $bbbsession
1775
 *
1776
 * @return string
1777
 */
1778
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...
1779
    $payload = array();
1780
    $source = 'meetingName';
1781
    $metaname = trim($recording['meetingName']);
1782
    return bigbluebuttonbn_get_recording_data_row_text($recording, $metaname, $source, $payload);
1783
}
1784
1785
/**
1786
 * Helper function renders the name for recording used in row for the data used by the recording table.
1787
 *
1788
 * @param array $recording
1789
 * @param array $bbbsession
1790
 *
1791
 * @return string
1792
 */
1793
function bigbluebuttonbn_get_recording_data_row_meta_activity($recording, $bbbsession) {
1794
    $payload = array();
1795 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...
1796
        $payload = array('recordingid' => $recording['recordID'], 'meetingid' => $recording['meetingID'],
1797
            'action' => 'edit', 'tag' => 'edit',
1798
            'target' => 'name');
1799
    }
1800
    $oldsource = 'meta_contextactivity';
1801
    if (isset($recording[$oldsource])) {
1802
        $metaname = trim($recording[$oldsource]);
1803
        return bigbluebuttonbn_get_recording_data_row_text($recording, $metaname, $oldsource, $payload);
1804
    }
1805
    $newsource = 'meta_bbb-recording-name';
1806 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...
1807
        $metaname = trim($recording[$newsource]);
1808
        return bigbluebuttonbn_get_recording_data_row_text($recording, $metaname, $newsource, $payload);
1809
    }
1810
    $metaname = trim($recording['meetingName']);
1811
    return bigbluebuttonbn_get_recording_data_row_text($recording, $metaname, $newsource, $payload);
1812
}
1813
1814
/**
1815
 * Helper function renders the description for recording used in row for the data used by the recording table.
1816
 *
1817
 * @param array $recording
1818
 * @param array $bbbsession
1819
 *
1820
 * @return string
1821
 */
1822
function bigbluebuttonbn_get_recording_data_row_meta_description($recording, $bbbsession) {
1823
    $payload = array();
1824 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...
1825
        $payload = array('recordingid' => $recording['recordID'], 'meetingid' => $recording['meetingID'],
1826
            'action' => 'edit', 'tag' => 'edit',
1827
            'target' => 'description');
1828
    }
1829
    $oldsource = 'meta_contextactivitydescription';
1830 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...
1831
        $metadescription = trim($recording[$oldsource]);
1832
        return bigbluebuttonbn_get_recording_data_row_text($recording, $metadescription, $oldsource, $payload);
1833
    }
1834
    $newsource = 'meta_bbb-recording-description';
1835 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...
1836
        $metadescription = trim($recording[$newsource]);
1837
        return bigbluebuttonbn_get_recording_data_row_text($recording, $metadescription, $newsource, $payload);
1838
    }
1839
    return bigbluebuttonbn_get_recording_data_row_text($recording, '', $newsource, $payload);
1840
}
1841
1842
/**
1843
 * Helper function renders text element for recording used in row for the data used by the recording table.
1844
 *
1845
 * @param array $recording
1846
 * @param string $text
1847
 * @param string $source
1848
 * @param array $data
1849
 *
1850
 * @return string
1851
 */
1852
function bigbluebuttonbn_get_recording_data_row_text($recording, $text, $source, $data) {
1853
    $htmltext = '<span>' . htmlentities($text) . '</span>';
1854
    if (empty($data)) {
1855
        return $htmltext;
1856
    }
1857
    $target = $data['action'] . '-' . $data['target'];
1858
    $id = 'recording-' . $target . '-' . $data['recordingid'];
1859
    $attributes = array('id' => $id, 'class' => 'quickeditlink col-md-20',
1860
        'data-recordingid' => $data['recordingid'], 'data-meetingid' => $data['meetingid'],
1861
        'data-target' => $data['target'], 'data-source' => $source);
1862
    $head = html_writer::start_tag('div', $attributes);
1863
    $tail = html_writer::end_tag('div');
1864
    $payload = array('action' => $data['action'], 'tag' => $data['tag'], 'target' => $data['target']);
1865
    $htmllink = bigbluebuttonbn_actionbar_render_button($recording, $payload);
1866
    return $head . $htmltext . $htmllink . $tail;
1867
}
1868
1869
/**
1870
 * Helper function render a button for the recording action bar
1871
 *
1872
 * @param array $recording
1873
 * @param array $data
1874
 *
1875
 * @return string
1876
 */
1877
function bigbluebuttonbn_actionbar_render_button($recording, $data) {
1878
    global $OUTPUT;
1879
    if (empty($data)) {
1880
        return '';
1881
    }
1882
    $target = $data['action'];
1883
    if (isset($data['target'])) {
1884
        $target .= '-' . $data['target'];
1885
    }
1886
    $id = 'recording-' . $target . '-' . $recording['recordID'];
1887
    $onclick = 'M.mod_bigbluebuttonbn.recordings.recording' . ucfirst($data['action']) . '(this); return false;';
1888
    if ((boolean) \mod_bigbluebuttonbn\locallib\config::get('recording_icons_enabled')) {
1889
        // With icon for $manageaction.
1890
        $iconattributes = array('id' => $id, 'class' => 'iconsmall');
1891
        $linkattributes = array(
1892
            'id' => $id,
1893
            'onclick' => $onclick,
1894
            'data-action' => $data['action'],
1895
        );
1896
        if (!isset($recording['imported'])) {
1897
            $linkattributes['data-links'] = bigbluebuttonbn_count_recording_imported_instances(
1898
                $recording['recordID']
1899
            );
1900
        }
1901
        if (isset($data['disabled'])) {
1902
            $iconattributes['class'] .= ' fa-' . $data['disabled'];
1903
            $linkattributes['class'] = 'disabled';
1904
            unset($linkattributes['onclick']);
1905
        }
1906
        $icon = new pix_icon(
1907
            'i/' . $data['tag'],
1908
            get_string('view_recording_list_actionbar_' . $data['action'], 'bigbluebuttonbn'),
1909
            'moodle',
1910
            $iconattributes
1911
        );
1912
        return $OUTPUT->action_icon('#', $icon, null, $linkattributes, false);
1913
    }
1914
    // With text for $manageaction.
1915
    $linkattributes = array('title' => get_string($data['tag']), 'class' => 'btn btn-xs btn-danger',
1916
        'onclick' => $onclick);
1917
    return $OUTPUT->action_link('#', get_string($data['action']), null, $linkattributes);
1918
}
1919
1920
/**
1921
 * Helper function builds the recording table.
1922
 *
1923
 * @param array $bbbsession
1924
 * @param array $recordings
1925
 * @param array $tools
1926
 *
1927
 * @return object
1928
 */
1929
function bigbluebuttonbn_get_recording_table($bbbsession, $recordings, $tools = ['protect', 'publish', 'delete']) {
1930
    global $DB;
1931
    // Declare the table.
1932
    $table = new html_table();
1933
    $table->data = array();
1934
    // Initialize table headers.
1935
    $table->head[] = get_string('view_recording_playback', 'bigbluebuttonbn');
1936
    $table->head[] = get_string('view_recording_name', 'bigbluebuttonbn');
1937
    $table->head[] = get_string('view_recording_description', 'bigbluebuttonbn');
1938
    if (bigbluebuttonbn_get_recording_data_preview_enabled($bbbsession)) {
1939
        $table->head[] = get_string('view_recording_preview', 'bigbluebuttonbn');
1940
    }
1941
    $table->head[] = get_string('view_recording_date', 'bigbluebuttonbn');
1942
    $table->head[] = get_string('view_recording_duration', 'bigbluebuttonbn');
1943
    $table->align = array('left', 'left', 'left', 'left', 'left', 'center');
1944
    $table->size = array('', '', '', '', '', '');
1945 View Code Duplication
    if ($bbbsession['managerecordings']) {
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...
1946
        $table->head[] = get_string('view_recording_actionbar', 'bigbluebuttonbn');
1947
        $table->align[] = 'left';
1948
        $table->size[] = (count($tools) * 40) . 'px';
1949
    }
1950
    // Get the groups of the user.
1951
    $usergroups = groups_get_all_groups($bbbsession['course']->id, $bbbsession['userID']);
1952
1953
    // Build table content.
1954
    foreach ($recordings as $recording) {
1955
        $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...
1956
        $shortmeetingid = explode('-', $recording['meetingID']);
1957
        if (isset($shortmeetingid[0])) {
1958
            $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...
1959
        }
1960
        // Check if the record belongs to a Visible Group type.
1961
        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...
1962
        $groupmode = groups_get_activity_groupmode($cm);
1963
        $displayrow = true;
1964 View Code Duplication
        if (($groupmode != VISIBLEGROUPS)
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...
1965
                && !$bbbsession['administrator'] && !$bbbsession['moderator']) {
1966
            $groupid = explode('[', $recording['meetingID']);
1967
            if (isset($groupid[1])) {
1968
                // It is a group recording and the user is not moderator/administrator. Recording should not be included by default.
1969
                $displayrow = false;
1970
                $groupid = explode(']', $groupid[1]);
1971
                if (isset($groupid[0])) {
1972
                    foreach ($usergroups as $usergroup) {
1973
                        if ($usergroup->id == $groupid[0]) {
1974
                            // Include recording if the user is in the same group.
1975
                            $displayrow = true;
1976
                        }
1977
                    }
1978
                }
1979
            }
1980
        }
1981 View Code Duplication
        if ($displayrow) {
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...
1982
            $rowdata = bigbluebuttonbn_get_recording_data_row($bbbsession, $recording, $tools);
1983
            if (!empty($rowdata)) {
1984
                $row = bigbluebuttonbn_get_recording_table_row($bbbsession, $recording, $rowdata);
1985
                array_push($table->data, $row);
1986
            }
1987
        }
1988
    }
1989
    return $table;
1990
}
1991
1992
/**
1993
 * Helper function builds the recording table row and insert into table.
1994
 *
1995
 * @param array $bbbsession
1996
 * @param array $recording
1997
 * @param object $rowdata
1998
 *
1999
 * @return object
2000
 */
2001
function bigbluebuttonbn_get_recording_table_row($bbbsession, $recording, $rowdata) {
2002
    $row = new html_table_row();
2003
    $row->id = 'recording-tr-' . $recording['recordID'];
2004
    $row->attributes['data-imported'] = 'false';
2005
    $texthead = '';
2006
    $texttail = '';
2007
    if (isset($recording['imported'])) {
2008
        $row->attributes['title'] = get_string('view_recording_link_warning', 'bigbluebuttonbn');
2009
        $row->attributes['data-imported'] = 'true';
2010
        $texthead = '<em>';
2011
        $texttail = '</em>';
2012
    }
2013
    $rowdata->date_formatted = str_replace(' ', '&nbsp;', $rowdata->date_formatted);
2014
    $row->cells = array();
2015
    $row->cells[] = $texthead . $rowdata->playback . $texttail;
2016
    $row->cells[] = $texthead . $rowdata->recording . $texttail;
2017
    $row->cells[] = $texthead . $rowdata->description . $texttail;
2018
    if (bigbluebuttonbn_get_recording_data_preview_enabled($bbbsession)) {
2019
        $row->cells[] = $rowdata->preview;
2020
    }
2021
    $row->cells[] = $texthead . $rowdata->date_formatted . $texttail;
2022
    $row->cells[] = $rowdata->duration_formatted;
2023
    if ($bbbsession['managerecordings']) {
2024
        $row->cells[] = $rowdata->actionbar;
2025
    }
2026
    return $row;
2027
}
2028
2029
/**
2030
 * Get the basic data to display in the table view
2031
 *
2032
 * @param array $bbbsession the current session
2033
 * @param array $enabledfeatures feature enabled for this activity
2034
 * @return associative array containing the recordings indexed by recordID, each recording is also a
2035
 * non sequential associative array itself that corresponds to the actual recording in BBB
2036
 */
2037
function bigbluebutton_get_recordings_for_table_view($bbbsession, $enabledfeatures) {
2038
    $bigbluebuttonbnid = null;
2039
    if ($enabledfeatures['showroom']) {
2040
        $bigbluebuttonbnid = $bbbsession['bigbluebuttonbn']->id;
2041
    }
2042
    // Get recordings.
2043
    $recordings = bigbluebuttonbn_get_recordings(
2044
        $bbbsession['course']->id, $bigbluebuttonbnid, $enabledfeatures['showroom'],
2045
        $bbbsession['bigbluebuttonbn']->recordings_deleted
2046
    );
2047
    if ($enabledfeatures['importrecordings']) {
2048
        // Get recording links.
2049
        $bigbluebuttonbnid = $bbbsession['bigbluebuttonbn']->id;
2050
        $recordingsimported = bigbluebuttonbn_get_recordings_imported_array(
2051
            $bbbsession['course']->id, $bigbluebuttonbnid, true
2052
        );
2053
        /* Perform aritmetic addition instead of merge so the imported recordings corresponding to existent
2054
         * recordings are not included. */
2055
        if ($bbbsession['bigbluebuttonbn']->recordings_imported) {
2056
            $recordings = $recordingsimported;
2057
        } else {
2058
            $recordings += $recordingsimported;
2059
        }
2060
    }
2061
    return $recordings;
2062
}
2063
2064
/**
2065
 * Helper function evaluates if recording row should be included in the table.
2066
 *
2067
 * @param array $bbbsession
2068
 * @param array $recording
2069
 *
2070
 * @return boolean
2071
 */
2072
function bigbluebuttonbn_include_recording_table_row($bbbsession, $recording) {
2073
    // Exclude unpublished recordings, only if user has no rights to manage them.
2074
    if ($recording['published'] != 'true' && !$bbbsession['managerecordings']) {
2075
        return false;
2076
    }
2077
    // Imported recordings are always shown as long as they are published.
2078
    if (isset($recording['imported'])) {
2079
        return true;
2080
    }
2081
    // Administrators and moderators are always allowed.
2082
    if ($bbbsession['administrator'] || $bbbsession['moderator']) {
2083
        return true;
2084
    }
2085
    // When groups are enabled, exclude those to which the user doesn't have access to.
2086
    if (isset($bbbsession['group']) && $recording['meetingID'] != $bbbsession['meetingid']) {
2087
        return false;
2088
    }
2089
    return true;
2090
}
2091
2092
/**
2093
 * Helper function triggers a send notification when the recording is ready.
2094
 *
2095
 * @param object $bigbluebuttonbn
2096
 *
2097
 * @return void
2098
 */
2099
function bigbluebuttonbn_send_notification_recording_ready($bigbluebuttonbn) {
2100
    \mod_bigbluebuttonbn\locallib\notifier::notify_recording_ready($bigbluebuttonbn);
2101
}
2102
2103
/**
2104
 * Helper function enqueues list of meeting events to be stored and processed as for completion.
2105
 *
2106
 * @param object $bigbluebuttonbn
2107
 * @param object $jsonobj
2108
 *
2109
 * @return void
2110
 */
2111
function bigbluebuttonbn_process_meeting_events($bigbluebuttonbn, $jsonobj) {
2112
    $meetingid = $jsonobj->{'meeting_id'};
2113
    $recordid = $jsonobj->{'internal_meeting_id'};
2114
    $attendees = $jsonobj->{'data'}->{'attendees'};
2115
    foreach ($attendees as $attendee) {
2116
        $userid = $attendee->{'ext_user_id'};
2117
        $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...
2118
        $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...
2119
        $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...
2120
        $meta['data'] = $attendee;
2121
        // Stores the log.
2122
        bigbluebuttonbn_log($bigbluebuttonbn, BIGBLUEBUTTON_LOG_EVENT_SUMMARY, $overrides, json_encode($meta));
2123
        // Enqueue a task for processing the completion.
2124
        bigbluebuttonbn_enqueue_completion_update($bigbluebuttonbn, $userid);
2125
    }
2126
}
2127
2128
/**
2129
 * Helper function enqueues one user for being validated as for completion.
2130
 *
2131
 * @param object $bigbluebuttonbn
2132
 * @param string $userid
2133
 *
2134
 * @return void
2135
 */
2136
function bigbluebuttonbn_enqueue_completion_update($bigbluebuttonbn, $userid) {
2137
    try {
2138
        // Create the instance of completion_update_state task.
2139
        $task = new \mod_bigbluebuttonbn\task\completion_update_state();
2140
        // Add custom data.
2141
        $data = array(
2142
            'bigbluebuttonbn' => $bigbluebuttonbn,
2143
            'userid' => $userid,
2144
        );
2145
        $task->set_custom_data($data);
2146
        // CONTRIB-7457: Task should be executed by a user, maybe Teacher as Student won't have rights for overriding.
2147
        // $ task -> set_userid ( $ user -> id );.
2148
        // Enqueue it.
2149
        \core\task\manager::queue_adhoc_task($task);
2150
    } catch (Exception $e) {
2151
        mtrace("Error while enqueuing completion_update_state task. " . (string) $e);
2152
    }
2153
}
2154
2155
/**
2156
 * Helper function enqueues completion trigger.
2157
 *
2158
 * @param object $bigbluebuttonbn
2159
 * @param string $userid
2160
 *
2161
 * @return void
2162
 */
2163
function bigbluebuttonbn_completion_update_state($bigbluebuttonbn, $userid) {
2164
    global $CFG;
2165
    require_once($CFG->libdir.'/completionlib.php');
2166
    list($course, $cm) = get_course_and_cm_from_instance($bigbluebuttonbn, 'bigbluebuttonbn');
2167
    $completion = new completion_info($course);
2168
    if (!$completion->is_enabled($cm)) {
2169
        mtrace("Completion not enabled");
2170
        return;
2171
    }
2172
    if (bigbluebuttonbn_get_completion_state($course, $cm, $userid, COMPLETION_AND)) {
2173
        mtrace("Completion succeeded for user $userid");
2174
        $completion->update_state($cm, COMPLETION_COMPLETE, $userid, true);
2175
    } else {
2176
        mtrace("Completion did not succeed for user $userid");
2177
    }
2178
}
2179
2180
/**
2181
 * Helper evaluates if the bigbluebutton server used belongs to blindsidenetworks domain.
2182
 *
2183
 * @return boolean
2184
 */
2185
function bigbluebuttonbn_is_bn_server() {
2186
    if (\mod_bigbluebuttonbn\locallib\config::get('bn_server')) {
2187
        return true;
2188
    }
2189
    $parsedurl = parse_url(\mod_bigbluebuttonbn\locallib\config::get('server_url'));
2190
    if (!isset($parsedurl['host'])) {
2191
        return false;
2192
    }
2193
    $h = $parsedurl['host'];
2194
    $hends = explode('.', $h);
2195
    $hendslength = count($hends);
2196
    return ($hends[$hendslength - 1] == 'com' && $hends[$hendslength - 2] == 'blindsidenetworks');
2197
}
2198
2199
/**
2200
 * Helper function returns a list of courses a user has access to, wrapped in an array that can be used
2201
 * by a html select.
2202
 *
2203
 * @param array $bbbsession
2204
 *
2205
 * @return array
2206
 */
2207
function bigbluebuttonbn_import_get_courses_for_select(array $bbbsession) {
2208
    if ($bbbsession['administrator']) {
2209
        $courses = get_courses('all', 'c.fullname ASC');
2210
        // It includes the name of the site as a course (category 0), so remove the first one.
2211
        unset($courses['1']);
2212
    } else {
2213
        $courses = enrol_get_users_courses($bbbsession['userID'], false, 'id,shortname,fullname');
2214
    }
2215
    $coursesforselect = [];
2216
    foreach ($courses as $course) {
2217
        $coursesforselect[$course->id] = $course->fullname . " (" . $course->shortname . ")";
2218
    }
2219
    return $coursesforselect;
2220
}
2221
2222
/**
2223
 * Helper function renders recording table.
2224
 *
2225
 * @param array $bbbsession
2226
 * @param array $recordings
2227
 * @param array $tools
2228
 *
2229
 * @return array
2230
 */
2231
function bigbluebuttonbn_output_recording_table($bbbsession, $recordings, $tools = ['protect', 'publish', 'delete']) {
2232
    if (isset($recordings) && !empty($recordings)) {
2233
        // There are recordings for this meeting.
2234
        $table = bigbluebuttonbn_get_recording_table($bbbsession, $recordings, $tools);
2235
    }
2236 View Code Duplication
    if (!isset($table) || !isset($table->data)) {
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...
2237
        // Render a table with "No recordings".
2238
        return html_writer::div(
2239
            get_string('view_message_norecordings', 'bigbluebuttonbn'),
2240
            '',
2241
            array('id' => 'bigbluebuttonbn_recordings_table')
2242
        );
2243
    }
2244
    // Render the table.
2245
    return html_writer::div(html_writer::table($table), '', array('id' => 'bigbluebuttonbn_recordings_table'));
2246
}
2247
2248
/**
2249
 * Helper function renders Opencast recording table.
2250
 *
2251
 * @param array $bbbsession
2252
 * @param array $ocrecordings
2253
 *
2254
 * @return array
2255
 */
2256
function bigbluebuttonbn_output_opencast_recording_table($bbbsession, $ocrecordings) {
2257
    // Get the Opencast recording table.
2258
    $table = bigbluebuttonbn_get_opencast_recording_table($bbbsession, $ocrecordings);
2259
    
2260 View Code Duplication
    if (!isset($table) || !isset($table->data)) {
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...
2261
        // Render a table with "No Opencast recordings".
2262
        return html_writer::div(
2263
            get_string('view_message_opencast_norecordings', 'bigbluebuttonbn'),
2264
            '',
2265
            array('id' => 'bigbluebuttonbn_opencast_recordings_table')
2266
        );
2267
    }
2268
    // Render the table.
2269
    return html_writer::div(html_writer::table($table), '', array('id' => 'bigbluebuttonbn_opencast_recordings_table'));
2270
}
2271
2272
/**
2273
 * Helper function builds the Opencast recording table.
2274
 *
2275
 * @param array $bbbsession
2276
 * @param array $ocrecordings
2277
 *
2278
 * @return object
2279
 */
2280
function bigbluebuttonbn_get_opencast_recording_table($bbbsession, $ocrecordings) {
2281
    // Declare the table.
2282
    $table = new html_table();
2283
    $table->data = array();
2284
    // Initialize table headers.
2285
    $table->head[] = get_string('view_recording_playback', 'bigbluebuttonbn');
2286
    $table->head[] = get_string('view_recording_name', 'bigbluebuttonbn');
2287
    $table->head[] = get_string('view_recording_description', 'bigbluebuttonbn');
2288
    if (bigbluebuttonbn_get_recording_data_preview_enabled($bbbsession)) {
2289
        $table->head[] = get_string('view_recording_preview', 'bigbluebuttonbn');
2290
    }
2291
    $table->head[] = get_string('view_recording_date', 'bigbluebuttonbn');
2292
    $table->head[] = get_string('view_recording_duration', 'bigbluebuttonbn');
2293
    $table->align = array('left', 'left', 'left', 'left', 'left', 'center');
2294
    $table->size = array('', '', '', '', '', '');
2295 View Code Duplication
    if ($bbbsession['managerecordings']) {
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...
2296
        $table->head[] = get_string('view_recording_actionbar', 'bigbluebuttonbn');
2297
        $table->align[] = 'left';
2298
        $table->size[] = (count($tools) * 40) . 'px';
0 ignored issues
show
Bug introduced by
The variable $tools 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...
2299
    }
2300
    // Get the groups of the user.
2301
    $usergroups = groups_get_all_groups($bbbsession['course']->id, $bbbsession['userID']);
2302
2303
    // Build table content.
2304
    foreach ($ocrecordings as $ocrecording) {
2305
        // Check if the record belongs to a Visible Group type.
2306
        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...
2307
        $groupmode = groups_get_activity_groupmode($cm);
2308
        $displayrow = true;
2309 View Code Duplication
        if (($groupmode != VISIBLEGROUPS)
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...
2310
                && !$bbbsession['administrator'] && !$bbbsession['moderator']) {
2311
            $groupid = explode('[', $bbbsession['meetingid']);
2312
            if (isset($groupid[1])) {
2313
                // It is a group recording and the user is not moderator/administrator. Recording should not be included by default.
2314
                $displayrow = false;
2315
                $groupid = explode(']', $groupid[1]);
2316
                if (isset($groupid[0])) {
2317
                    foreach ($usergroups as $usergroup) {
2318
                        if ($usergroup->id == $groupid[0]) {
2319
                            // Include recording if the user is in the same group.
2320
                            $displayrow = true;
2321
                        }
2322
                    }
2323
                }
2324
            }
2325
        }
2326 View Code Duplication
        if ($displayrow) {
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...
2327
            $rowdata = bigbluebuttonbn_get_opencast_recording_data_row($bbbsession, $ocrecording);
2328
            if (!empty($rowdata)) {
2329
                $row = bigbluebuttonbn_get_opencast_recording_table_row($bbbsession, $ocrecording, $rowdata);
2330
                array_push($table->data, $row);
2331
            }
2332
        }
2333
    }
2334
    return $table;
2335
}
2336
2337
/**
2338
 * Helper function builds a row for the data used by the Opencast recording table.
2339
 *
2340
 * @param array $bbbsession
2341
 * @param array $ocrecording
2342
 *
2343
 * @return array
2344
 */
2345
function bigbluebuttonbn_get_opencast_recording_data_row($bbbsession, $ocrecording) {
2346
    $rowdata = new stdClass();
2347
    // Set recording playback url.
2348
    $rowdata->playback = bigbluebuttonbn_get_opencast_recording_data_row_playback($ocrecording, $bbbsession);
2349
    // Set recording name from title if exists, otherwise shows "Opencast Video".
2350
    $rowdata->name = isset($ocrecording['title']) ? $ocrecording['title'] : get_string('view_recording_list_opencast', 'bigbluebuttonbn');
2351
    // Set recording description.
2352
    $rowdata->description = isset($ocrecording['description']) ? $ocrecording['description'] : '';
2353
    if (bigbluebuttonbn_get_recording_data_preview_enabled($bbbsession)) {
2354
        // Set recording_preview.
2355
        $rowdata->preview = bigbluebuttonbn_get_opencast_recording_data_row_preview($ocrecording);
2356
    }
2357
    // Set formatted date.
2358
    $rowdata->date_formatted = bigbluebuttonbn_get_opencast_recording_data_row_date_formatted($ocrecording);
2359
    // Set formatted duration.
2360
    $rowdata->duration_formatted = bigbluebuttonbn_get_opencast_recording_data_row_duration($ocrecording['duration']);
2361
    // Set actionbar, if user is allowed to manage recordings.
2362
    if ($bbbsession['managerecordings']) {
2363
        $rowdata->actionbar = bigbluebuttonbn_get_opencast_recording_data_row_actionbar($ocrecording, $bbbsession);
2364
    }
2365
    return $rowdata;
2366
}
2367
2368
/**
2369
 * Helper function renders the link used for Opencast recording playback in row for the data used by the recording table.
2370
 * To display the video, it is important for a video in Opencast to be published with engage-player, also it is required to
2371
 * have filter_opencast plugin installed and configured. 
2372
 * The link redirects user to oc_view.php to authentificate the user via LTI and show the video in Opencast. 
2373
 *
2374
 * @param array $ocrecording
2375
 * @param array $bbbsession
2376
 *
2377
 * @return string
2378
 */
2379
function bigbluebuttonbn_get_opencast_recording_data_row_playback($ocrecording, $bbbsession) {
2380
    global $CFG, $OUTPUT;
2381
    $text = get_string('view_recording_list_opencast', 'bigbluebuttonbn');
2382
    $href = '#';
2383
    // Check if the publication status has engage-player
2384
    if (isset($ocrecording['publication_status']) && in_array('engage-player', $ocrecording['publication_status'])) {
2385
        // Check if filter_opencast is configured
2386
        $consumerkey = get_config('filter_opencast', 'consumerkey');
2387
        $consumersecret = get_config('filter_opencast', 'consumersecret');
2388
        // In order to make LTI auth both consumerkey and consumersecret are required.
2389
        if (!empty($consumerkey) && !empty($consumersecret)) {
2390
            $href = $CFG->wwwroot . '/mod/bigbluebuttonbn/oc_player.php?identifier=' . $ocrecording['identifier'] .
2391
            '&bn=' . $bbbsession['bigbluebuttonbn']->id;
2392
        }
2393
    }
2394
2395
    $linkattributes = array(
2396
        'id' => 'opencast-player-redirect-' . $ocrecording['identifier'],
2397
        'class' => 'btn btn-sm btn-default',
2398
        'target' => '_blank'
2399
      );
2400
    if ($href == '#' || empty($href)) {
2401
        $linkattributes['class'] = 'btn btn-sm btn-warning';
2402
        $linkattributes['title'] = get_string('view_recording_format_errror_unreachable', 'bigbluebuttonbn');
2403
    }
2404
    return $OUTPUT->action_link($href, $text, null, $linkattributes) . '&#32;';
2405
}
2406
2407
/**
2408
 * Helper function builds Opencast recording preview used in row for the data used by the recording table.
2409
 *
2410
 * @param array $ocrecording
2411
 *
2412
 * @return string
2413
 */
2414
function bigbluebuttonbn_get_opencast_recording_data_row_preview($ocrecording) {
2415
    $options = array('id' => 'preview-' . $ocrecording['identifier']);
2416
    $recordingpreview = html_writer::start_tag('div', $options);
2417
    $imageurl = '';
2418
    // Getting preview image from mediapackage attachments.
2419
    if (isset($ocrecording['mediapackage']['attachments']['attachment'])) {
2420
        foreach ($ocrecording['mediapackage']['attachments']['attachment'] as $attachment) {
2421
            // Looking for image only.
2422
            if (isset($attachment['mimetype']) && strpos($attachment['mimetype'], 'image') !== FALSE) {
2423
                // Looking for the url of the preview image.
2424
                if (empty($imageurl) && isset($attachment['type']) && isset($attachment['url'])) {
2425
                    // There are several type of attachments which are different in size.
2426
                    // More suitable sizes are of these types, respectively.
2427
                    $suitabletypes = array('search', 'feed');
2428
                    foreach ($suitabletypes as $type) {
2429
                        if (strpos($attachment['type'], $type) !== FALSE) {
2430
                            $imageurl = $attachment['url'];
2431
                            break;
2432
                        }
2433
                    }
2434
                }
2435
            }
2436
            if (!empty($imageurl)) {
2437
                break;
2438
            }
2439
        }
2440
        if (!empty($imageurl)) {
2441
            $recordingpreview .= bigbluebuttonbn_get_opencast_recording_data_row_preview_images($imageurl);
2442
        }
2443
    }
2444
   
2445
    $recordingpreview .= html_writer::end_tag('div');
2446
    return $recordingpreview;
2447
}
2448
2449
/**
2450
 * Helper function format Opencast recording date used in row for the data used by the recording table.
2451
 *
2452
 * @param array $ocrecording
2453
 *
2454
 * @return string
2455
 */
2456
function bigbluebuttonbn_get_opencast_recording_data_row_date_formatted($ocrecording) {
2457
    global $USER;
2458
    $starttime_str = !empty($ocrecording['start']) ? $ocrecording['start'] : $ocrecording['created'];
2459
    $starttime = strtotime($starttime_str);
2460
    // Set formatted date.
2461
    $dateformat = get_string('strftimerecentfull', 'langconfig') . ' %Z';
2462
    return userdate($starttime, $dateformat, usertimezone($USER->timezone));
2463
}
2464
2465
/**
2466
 * Helper function converts Opencast recording duration used in row for the data used by the recording table.
2467
 *
2468
 * @param array $duration
2469
 *
2470
 * @return integer
2471
 */
2472
function bigbluebuttonbn_get_opencast_recording_data_row_duration($duration) {
2473
    if ($duration) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $duration of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
2474
        // Convert the duration (in miliseconds) into Hours:Minutes:Seconds format
2475
        return gmdate('H:i:s', $duration / 1000);
2476
    }
2477
    return 0;
2478
}
2479
2480
/**
2481
 * Helper function builds Opencast recording actionbar used in row for the data used by the recording table.
2482
 *
2483
 * @param array $ocrecording
2484
 * @param array $bbbsession
2485
 *
2486
 * @return string
2487
 */
2488
function bigbluebuttonbn_get_opencast_recording_data_row_actionbar($ocrecording, $bbbsession) {
2489
    global $OUTPUT;
2490
    if (empty($ocrecording['identifier']) || empty($bbbsession['course'])) {
2491
        return '';
2492
    }
2493
    $actionbar = '';
2494
    $linkattributes = array(
2495
        'target' => '_blank',
2496
        'class' => 'btn btn-xs btn-danger'
2497
    );
2498
    // Creating moodle url, to redirect to Opencast update metadata (Edit) page.
2499
    $opencastediturl = new \moodle_url('/blocks/opencast/updatemetadata.php',
2500
            array('video_identifier' => $ocrecording['identifier'], 'courseid' => $bbbsession['course']->id));
2501
    $linkattributes['id'] = 'opencast-edit-episode-' . $ocrecording['identifier'];
2502
    // Generating Action Link for Opencast update metadata (Edit).
2503
    $actionbar .= $OUTPUT->action_link($opencastediturl, get_string('edit'), null, $linkattributes) . '&#32;';
2504
    
2505
    // Creating moodle url, to redirect to Opencast delete event (Delete) page.
2506
    $opencastdeleteurl = new \moodle_url('/blocks/opencast/deleteevent.php',
2507
            array('identifier' => $ocrecording['identifier'], 'courseid' => $bbbsession['course']->id));
2508
    $linkattributes['id'] = 'opencast-delete-episode-' . $ocrecording['identifier'];
2509
    // Generating Action Link for Opencast delete event (Delete).
2510
    $actionbar .= $OUTPUT->action_link($opencastdeleteurl, get_string('delete'), null, $linkattributes) . '&#32;';
2511
    $head = html_writer::start_tag('div', array(
2512
        'id' => 'recording-actionbar-' . $ocrecording['identifier'],
2513
        'data-recordingid' => $ocrecording['identifier'],
2514
        'data-meetingid' => $bbbsession['meetingid']));
2515
    $tail = html_writer::end_tag('div');
2516
    return $head . $actionbar . $tail;
2517
}
2518
2519
/**
2520
 * Helper function builds the Opencast recording table row and insert into table.
2521
 *
2522
 * @param array $bbbsession
2523
 * @param object $ocrecording
2524
 * @param object $rowdata
2525
 *
2526
 * @return object
2527
 */
2528
function bigbluebuttonbn_get_opencast_recording_table_row($bbbsession, $ocrecording, $rowdata) {
2529
    $row = new html_table_row();
2530
    $row->id = 'recording-tr-' . $ocrecording['identifier'];
2531
    $rowdata->date_formatted = str_replace(' ', '&nbsp;', $rowdata->date_formatted);
2532
    $row->cells = array();
2533
    $row->cells[] = $rowdata->playback;
2534
    $row->cells[] = $rowdata->name;
2535
    $row->cells[] = $rowdata->description;
2536
    if (bigbluebuttonbn_get_recording_data_preview_enabled($bbbsession)) {
2537
        $row->cells[] = $rowdata->preview;
2538
    }
2539
    $row->cells[] = $rowdata->date_formatted;
2540
    $row->cells[] = $rowdata->duration_formatted;
2541
    if ($bbbsession['managerecordings']) {
2542
        $row->cells[] = $rowdata->actionbar;
2543
    }
2544
    return $row;
2545
}
2546
2547
/**
2548
 * Helper function builds element with actual images used in Opencast recording preview row based on a selected playback.
2549
 *
2550
 * @param string $imageurl
2551
 *
2552
 * @return string
2553
 */
2554
function bigbluebuttonbn_get_opencast_recording_data_row_preview_images($imageurl) {
2555
    global $CFG;
2556
    $recordingpreview  = html_writer::start_tag('div', array('class' => 'container-fluid'));
2557
    $recordingpreview .= html_writer::start_tag('div', array('class' => 'row'));
2558
    $recordingpreview .= html_writer::start_tag('div', array('class' => ''));
2559
    $recordingpreview .= html_writer::empty_tag(
2560
        'img',
2561
        array('src' => trim($imageurl) . '?' . time(), 'class' => 'recording-thumbnail pull-left')
2562
    );
2563
    $recordingpreview .= html_writer::end_tag('div');
2564
    $recordingpreview .= html_writer::end_tag('div');
2565
    $recordingpreview .= html_writer::start_tag('div', array('class' => 'row'));
2566
    $recordingpreview .= html_writer::tag(
2567
        'div',
2568
        get_string('view_recording_preview_help', 'bigbluebuttonbn'),
2569
        array('class' => 'text-center text-muted small')
2570
    );
2571
    $recordingpreview .= html_writer::end_tag('div');
2572
    $recordingpreview .= html_writer::end_tag('div');
2573
    return $recordingpreview;
2574
}
2575
2576
/**
2577
 * Helper function to get BBB recordings from the Opencast video avaialble in the course.
2578
 * It uses block_opencast for getting all videos for the course and match them with meeting id.
2579
 * It uses tool_opencast for making an api call to get mediapackage of vidoes.
2580
 *
2581
 * @param object $bbbsession
2582
 * @param string $seriesid
2583
 *
2584
 */
2585
function bigbluebutton_get_opencast_recordings_for_table_view($bbbsession, $seriesid) {
0 ignored issues
show
Unused Code introduced by
The parameter $seriesid 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...
2586
    $bbbocvideos = array();
2587
    // Initializing the api from tool_opencast plugin.
2588
    $api = new \tool_opencast\local\api();
2589
    // Getting an instance of apibridge from block_opencast plugin.
2590
    $opencast = \block_opencast\local\apibridge::get_instance();
2591
    // Getting the course videos from block_opencast plugin.
2592
    $ocvideos = $opencast->get_course_videos($bbbsession['course']->id);
2593
    if ($ocvideos->videos && !empty($ocvideos->videos)) {
2594
        foreach ($ocvideos->videos as $ocvideo) {
2595
            // Check subjects of opencast video contains $bbbsession['meetingid'].
2596
            if (in_array($bbbsession['meetingid'], $ocvideo->subjects)) {
2597
                // Converting $ocvideo object to array.
2598
                $ocvideoarray = json_decode(json_encode($ocvideo), true);
2599
                // Get mediapackage json using api call.
2600
                $url = '/search/episode.json?id=' . $ocvideo->identifier;
2601
                $search_result = json_decode($api->oc_get($url), true);
2602
                if ($api->get_http_code() == 200 && isset($search_result['search-results']['result']['mediapackage'])) {
2603
                    // Add mediapackage to array if exists.
2604
                    $ocvideoarray['mediapackage'] = $search_result['search-results']['result']['mediapackage'];
2605
                }
2606
                $bbbocvideos[] = $ocvideoarray;
2607
            }
2608
        }
2609
    }
2610
    return $bbbocvideos;
2611
}
2612
2613
/**
2614
 * Helper function to convert an html string to plain text.
2615
 *
2616
 * @param string $html
2617
 * @param integer $len
2618
 *
2619
 * @return string
2620
 */
2621
function bigbluebuttonbn_html2text($html, $len = 0) {
2622
    $text = strip_tags($html);
2623
    $text = str_replace('&nbsp;', ' ', $text);
2624
    $textlen = strlen($text);
2625
    $text = mb_substr($text, 0, $len);
2626
    if ($textlen > $len) {
2627
        $text .= '...';
2628
    }
2629
    return $text;
2630
}
2631
2632
/**
2633
 * Helper function to obtain the tags linked to a bigbluebuttonbn activity
2634
 *
2635
 * @param string $id
2636
 *
2637
 * @return string containing the tags separated by commas
2638
 */
2639
function bigbluebuttonbn_get_tags($id) {
2640
    if (class_exists('core_tag_tag')) {
2641
        return implode(',', core_tag_tag::get_item_tags_array('core', 'course_modules', $id));
2642
    }
2643
    return implode(',', tag_get_tags('bigbluebuttonbn', $id));
2644
}
2645
2646
/**
2647
 * Helper function to define the sql used for gattering the bigbluebuttonbnids whose meetingids should be included
2648
 * in the getRecordings request
2649
 *
2650
 * @param string $courseid
2651
 * @param string $bigbluebuttonbnid
2652
 * @param bool   $subset
2653
 *
2654
 * @return string containing the sql used for getting the target bigbluebuttonbn instances
2655
 */
2656
function bigbluebuttonbn_get_recordings_sql_select($courseid, $bigbluebuttonbnid = null, $subset = true) {
2657
    if (empty($courseid)) {
2658
        $courseid = 0;
2659
    }
2660
    if (empty($bigbluebuttonbnid)) {
2661
        return "course = '{$courseid}'";
2662
    }
2663
    if ($subset) {
2664
        return "id = '{$bigbluebuttonbnid}'";
2665
    }
2666
    return "id <> '{$bigbluebuttonbnid}' AND course = '{$courseid}'";
2667
}
2668
2669
/**
2670
 * Helper function to define the sql used for gattering the bigbluebuttonbnids whose meetingids should be included
2671
 * in the getRecordings request considering only those that belong to deleted activities.
2672
 *
2673
 * @param string $courseid
2674
 * @param string $bigbluebuttonbnid
2675
 * @param bool   $subset
2676
 *
2677
 * @return string containing the sql used for getting the target bigbluebuttonbn instances
2678
 */
2679 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...
2680
    $sql = "log = '" . BIGBLUEBUTTONBN_LOG_EVENT_DELETE . "' AND meta like '%has_recordings%' AND meta like '%true%'";
2681
    if (empty($courseid)) {
2682
        $courseid = 0;
2683
    }
2684
    if (empty($bigbluebuttonbnid)) {
2685
        return $sql . " AND courseid = {$courseid}";
2686
    }
2687
    if ($subset) {
2688
        return $sql . " AND bigbluebuttonbnid = '{$bigbluebuttonbnid}'";
2689
    }
2690
    return $sql . " AND courseid = {$courseid} AND bigbluebuttonbnid <> '{$bigbluebuttonbnid}'";
2691
}
2692
2693
/**
2694
 * Helper function to define the sql used for gattering the bigbluebuttonbnids whose meetingids should be included
2695
 * in the getRecordings request considering only those that belong to imported recordings.
2696
 *
2697
 * @param string $courseid
2698
 * @param string $bigbluebuttonbnid
2699
 * @param bool   $subset
2700
 *
2701
 * @return string containing the sql used for getting the target bigbluebuttonbn instances
2702
 */
2703 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...
2704
    $sql = "log = '" . BIGBLUEBUTTONBN_LOG_EVENT_IMPORT . "'";
2705
    if (empty($courseid)) {
2706
        $courseid = 0;
2707
    }
2708
    if (empty($bigbluebuttonbnid)) {
2709
        return $sql . " AND courseid = '{$courseid}'";
2710
    }
2711
    if ($subset) {
2712
        return $sql . " AND bigbluebuttonbnid = '{$bigbluebuttonbnid}'";
2713
    }
2714
    return $sql . " AND courseid = '{$courseid}' AND bigbluebuttonbnid <> '{$bigbluebuttonbnid}'";
2715
}
2716
2717
/**
2718
 * Helper function to get recordings and imported recordings together.
2719
 *
2720
 * @param string $courseid
2721
 * @param string $bigbluebuttonbnid
2722
 * @param bool   $subset
2723
 * @param bool   $includedeleted
2724
 *
2725
 * @return associative array containing the recordings indexed by recordID, each recording is also a
2726
 * non sequential associative array itself that corresponds to the actual recording in BBB
2727
 */
2728
function bigbluebuttonbn_get_allrecordings($courseid = 0, $bigbluebuttonbnid = null, $subset = true, $includedeleted = false) {
2729
    $recordings = bigbluebuttonbn_get_recordings($courseid, $bigbluebuttonbnid, $subset, $includedeleted);
2730
    $recordingsimported = bigbluebuttonbn_get_recordings_imported_array($courseid, $bigbluebuttonbnid, $subset);
2731
    return ($recordings + $recordingsimported);
2732
}
2733
2734
/**
2735
 * Helper function to retrieve recordings from the BigBlueButton. The references are stored as events
2736
 * in bigbluebuttonbn_logs.
2737
 *
2738
 * @param string $courseid
2739
 * @param string $bigbluebuttonbnid
2740
 * @param bool   $subset
2741
 * @param bool   $includedeleted
2742
 *
2743
 * @return associative array containing the recordings indexed by recordID, each recording is also a
2744
 * non sequential associative array itself that corresponds to the actual recording in BBB
2745
 */
2746
function bigbluebuttonbn_get_recordings($courseid = 0, $bigbluebuttonbnid = null, $subset = true, $includedeleted = false) {
2747
    global $DB;
2748
    $select = bigbluebuttonbn_get_recordings_sql_select($courseid, $bigbluebuttonbnid, $subset);
2749
    $bigbluebuttonbns = $DB->get_records_select_menu('bigbluebuttonbn', $select, null, 'id', 'id, meetingid');
2750
    /* Consider logs from deleted bigbluebuttonbn instances whose meetingids should be included in
2751
     * the getRecordings request. */
2752
    if ($includedeleted) {
2753
        $selectdeleted = bigbluebuttonbn_get_recordings_deleted_sql_select($courseid, $bigbluebuttonbnid, $subset);
2754
        $bigbluebuttonbnsdel = $DB->get_records_select_menu(
2755
            'bigbluebuttonbn_logs',
2756
            $selectdeleted,
2757
            null,
2758
            'bigbluebuttonbnid',
2759
            'bigbluebuttonbnid, meetingid'
2760
        );
2761
        if (!empty($bigbluebuttonbnsdel)) {
2762
            // Merge bigbluebuttonbnis from deleted instances, only keys are relevant.
2763
            // Artimetic merge is used in order to keep the keys.
2764
            $bigbluebuttonbns += $bigbluebuttonbnsdel;
2765
        }
2766
    }
2767
    // Gather the meetingids from bigbluebuttonbn logs that include a create with record=true.
2768
    if (empty($bigbluebuttonbns)) {
2769
        return array();
2770
    }
2771
    // Prepare select for loading records based on existent bigbluebuttonbns.
2772
    $sql = 'SELECT DISTINCT meetingid, bigbluebuttonbnid FROM {bigbluebuttonbn_logs} WHERE ';
2773
    $sql .= '(bigbluebuttonbnid=' . implode(' OR bigbluebuttonbnid=', array_keys($bigbluebuttonbns)) . ')';
2774
    // Include only Create events and exclude those with record not true.
2775
    $sql .= ' AND log = ? AND meta LIKE ? AND meta LIKE ?';
2776
    // Execute select for loading records based on existent bigbluebuttonbns.
2777
    $records = $DB->get_records_sql_menu($sql, array(BIGBLUEBUTTONBN_LOG_EVENT_CREATE, '%record%', '%true%'));
2778
    // Get actual recordings.
2779
    return bigbluebuttonbn_get_recordings_array(array_keys($records));
2780
}
2781
2782
/**
2783
 * Helper function iterates an array with recordings and unset those already imported.
2784
 *
2785
 * @param array $recordings
2786
 * @param integer $courseid
2787
 * @param integer $bigbluebuttonbnid
2788
 *
2789
 * @return array
2790
 */
2791
function bigbluebuttonbn_unset_existent_recordings_already_imported($recordings, $courseid, $bigbluebuttonbnid) {
2792
    $recordingsimported = bigbluebuttonbn_get_recordings_imported_array($courseid, $bigbluebuttonbnid, true);
2793
    foreach ($recordings as $key => $recording) {
2794
        if (isset($recordingsimported[$recording['recordID']])) {
2795
            unset($recordings[$key]);
2796
        }
2797
    }
2798
    return $recordings;
2799
}
2800
2801
/**
2802
 * Helper function to count the imported recordings for a recordingid.
2803
 *
2804
 * @param string $recordid
2805
 *
2806
 * @return integer
2807
 */
2808
function bigbluebuttonbn_count_recording_imported_instances($recordid) {
2809
    global $DB;
2810
    $sql = 'SELECT COUNT(DISTINCT id) FROM {bigbluebuttonbn_logs} WHERE log = ? AND meta LIKE ? AND meta LIKE ?';
2811
    return $DB->count_records_sql($sql, array(BIGBLUEBUTTONBN_LOG_EVENT_IMPORT, '%recordID%', "%{$recordid}%"));
2812
}
2813
2814
/**
2815
 * Helper function returns an array with all the instances of imported recordings for a recordingid.
2816
 *
2817
 * @param string $recordid
2818
 *
2819
 * @return array
2820
 */
2821
function bigbluebuttonbn_get_recording_imported_instances($recordid) {
2822
    global $DB;
2823
    $sql = 'SELECT * FROM {bigbluebuttonbn_logs} WHERE log = ? AND meta LIKE ? AND meta LIKE ?';
2824
    $recordingsimported = $DB->get_records_sql($sql, array(BIGBLUEBUTTONBN_LOG_EVENT_IMPORT, '%recordID%',
2825
        "%{$recordid}%"));
2826
    return $recordingsimported;
2827
}
2828
2829
/**
2830
 * Helper function to get how much callback events are logged.
2831
 *
2832
 * @param string $recordid
2833
 * @param string $callbacktype
2834
 *
2835
 * @return integer
2836
 */
2837
function bigbluebuttonbn_get_count_callback_event_log($recordid, $callbacktype = 'recording_ready') {
2838
    global $DB;
2839
    $sql = 'SELECT count(DISTINCT id) FROM {bigbluebuttonbn_logs} WHERE log = ? AND meta LIKE ? AND meta LIKE ?';
2840
    // Callback type added on version 2.4, validate recording_ready first or assume it on records with no callback.
2841
    if ($callbacktype == 'recording_ready') {
2842
        $sql .= ' AND (meta LIKE ? OR meta NOT LIKE ? )';
2843
        $count = $DB->count_records_sql($sql, array(BIGBLUEBUTTON_LOG_EVENT_CALLBACK, '%recordid%', "%$recordid%",
2844
            $callbacktype, 'callback'));
2845
        return $count;
2846
    }
2847
    $sql .= ' AND meta LIKE ?;';
2848
    $count = $DB->count_records_sql($sql, array(BIGBLUEBUTTON_LOG_EVENT_CALLBACK, '%recordid%', "%$recordid%", "%$callbacktype%"));
2849
    return $count;
2850
}
2851
2852
/**
2853
 * Helper function returns an array with the profiles (with features per profile) for the different types
2854
 * of bigbluebuttonbn instances.
2855
 *
2856
 * @return array
2857
 */
2858
function bigbluebuttonbn_get_instance_type_profiles() {
2859
    $instanceprofiles = array(
2860
        BIGBLUEBUTTONBN_TYPE_ALL => array('id' => BIGBLUEBUTTONBN_TYPE_ALL,
2861
            'name' => get_string('instance_type_default', 'bigbluebuttonbn'),
2862
            'features' => array('all')),
2863
        BIGBLUEBUTTONBN_TYPE_ROOM_ONLY => array('id' => BIGBLUEBUTTONBN_TYPE_ROOM_ONLY,
2864
            'name' => get_string('instance_type_room_only', 'bigbluebuttonbn'),
2865
            'features' => array('showroom', 'welcomemessage', 'voicebridge', 'waitformoderator', 'userlimit',
2866
                'recording', 'sendnotifications', 'preuploadpresentation', 'permissions', 'schedule', 'groups',
2867
                'modstandardelshdr', 'availabilityconditionsheader', 'tagshdr', 'competenciessection',
2868
                'clienttype', 'completionattendance', 'completionengagement', 'availabilityconditionsheader')),
2869
        BIGBLUEBUTTONBN_TYPE_RECORDING_ONLY => array('id' => BIGBLUEBUTTONBN_TYPE_RECORDING_ONLY,
2870
            'name' => get_string('instance_type_recording_only', 'bigbluebuttonbn'),
2871
            'features' => array('showrecordings', 'importrecordings', 'availabilityconditionsheader')),
2872
    );
2873
    return $instanceprofiles;
2874
}
2875
2876
/**
2877
 * Helper function returns an array with enabled features for an specific profile type.
2878
 *
2879
 * @param array $typeprofiles
2880
 * @param string $type
2881
 *
2882
 * @return array
2883
 */
2884
function bigbluebuttonbn_get_enabled_features($typeprofiles, $type = null) {
2885
    $enabledfeatures = array();
2886
    $features = $typeprofiles[BIGBLUEBUTTONBN_TYPE_ALL]['features'];
2887
    if (!is_null($type) && key_exists($type, $typeprofiles)) {
2888
        $features = $typeprofiles[$type]['features'];
2889
    }
2890
    $enabledfeatures['showroom'] = (in_array('all', $features) || in_array('showroom', $features));
2891
    // Evaluates if recordings are enabled for the Moodle site.
2892
    $enabledfeatures['showrecordings'] = false;
2893
    if (\mod_bigbluebuttonbn\locallib\config::recordings_enabled()) {
2894
        $enabledfeatures['showrecordings'] = (in_array('all', $features) || in_array('showrecordings', $features));
2895
    }
2896
    $enabledfeatures['importrecordings'] = false;
2897
    if (\mod_bigbluebuttonbn\locallib\config::importrecordings_enabled()) {
2898
        $enabledfeatures['importrecordings'] = (in_array('all', $features) || in_array('importrecordings', $features));
2899
    }
2900
    // Evaluates if clienttype is enabled for the Moodle site.
2901
    $enabledfeatures['clienttype'] = false;
2902
    if (\mod_bigbluebuttonbn\locallib\config::clienttype_enabled()) {
2903
        $enabledfeatures['clienttype'] = (in_array('all', $features) || in_array('clienttype', $features));
2904
    }
2905
    return $enabledfeatures;
2906
}
2907
2908
/**
2909
 * Helper function returns an array with the profiles (with features per profile) for the different types
2910
 * of bigbluebuttonbn instances that the user is allowed to create.
2911
 *
2912
 * @param boolean $room
2913
 * @param boolean $recording
2914
 *
2915
 * @return array
2916
 */
2917
function bigbluebuttonbn_get_instance_type_profiles_create_allowed($room, $recording) {
2918
    $profiles = bigbluebuttonbn_get_instance_type_profiles();
2919
    if (!$room) {
2920
        unset($profiles[BIGBLUEBUTTONBN_TYPE_ROOM_ONLY]);
2921
        unset($profiles[BIGBLUEBUTTONBN_TYPE_ALL]);
2922
    }
2923
    if (!$recording) {
2924
        unset($profiles[BIGBLUEBUTTONBN_TYPE_RECORDING_ONLY]);
2925
        unset($profiles[BIGBLUEBUTTONBN_TYPE_ALL]);
2926
    }
2927
    return $profiles;
2928
}
2929
2930
/**
2931
 * Helper function returns an array with the profiles (with features per profile) for the different types
2932
 * of bigbluebuttonbn instances.
2933
 *
2934
 * @param array $profiles
2935
 *
2936
 * @return array
2937
 */
2938
function bigbluebuttonbn_get_instance_profiles_array($profiles = []) {
2939
    $profilesarray = array();
2940
    foreach ($profiles as $key => $profile) {
2941
        $profilesarray[$profile['id']] = $profile['name'];
2942
    }
2943
    return $profilesarray;
2944
}
2945
2946
/**
2947
 * Helper function returns time in a formatted string.
2948
 *
2949
 * @param integer $time
2950
 *
2951
 * @return string
2952
 */
2953
function bigbluebuttonbn_format_activity_time($time) {
2954
    global $CFG;
2955
    require_once($CFG->dirroot.'/calendar/lib.php');
2956
    $activitytime = '';
2957
    if ($time) {
2958
        $activitytime = calendar_day_representation($time) . ' ' .
2959
        get_string('mod_form_field_notification_msg_at', 'bigbluebuttonbn') . ' ' .
2960
        calendar_time_representation($time);
2961
    }
2962
    return $activitytime;
2963
}
2964
2965
/**
2966
 * Helper function returns array with all the strings to be used in javascript.
2967
 *
2968
 * @return array
2969
 */
2970
function bigbluebuttonbn_get_strings_for_js() {
2971
    $locale = bigbluebuttonbn_get_locale();
2972
    $stringman = get_string_manager();
2973
    $strings = $stringman->load_component_strings('bigbluebuttonbn', $locale);
2974
    return $strings;
2975
}
2976
2977
/**
2978
 * Helper function returns the locale set by moodle.
2979
 *
2980
 * @return string
2981
 */
2982
function bigbluebuttonbn_get_locale() {
2983
    $lang = get_string('locale', 'core_langconfig');
2984
    return substr($lang, 0, strpos($lang, '.'));
2985
}
2986
2987
/**
2988
 * Helper function returns the locale code based on the locale set by moodle.
2989
 *
2990
 * @return string
2991
 */
2992
function bigbluebuttonbn_get_localcode() {
2993
    $locale = bigbluebuttonbn_get_locale();
2994
    return substr($locale, 0, strpos($locale, '_'));
2995
}
2996
2997
/**
2998
 * Helper function returns array with the instance settings used in views.
2999
 *
3000
 * @param string $id
3001
 * @param object $bigbluebuttonbnid
3002
 *
3003
 * @return array
3004
 */
3005
function bigbluebuttonbn_view_validator($id, $bigbluebuttonbnid) {
3006
    if ($id) {
3007
        return bigbluebuttonbn_view_instance_id($id);
3008
    }
3009
    if ($bigbluebuttonbnid) {
3010
        return bigbluebuttonbn_view_instance_bigbluebuttonbn($bigbluebuttonbnid);
3011
    }
3012
}
3013
3014
/**
3015
 * Helper function returns array with the instance settings used in views based on id.
3016
 *
3017
 * @param string $id
3018
 *
3019
 * @return array
3020
 */
3021 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...
3022
    global $DB;
3023
    $cm = get_coursemodule_from_id('bigbluebuttonbn', $id, 0, false, MUST_EXIST);
3024
    $course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
3025
    $bigbluebuttonbn = $DB->get_record('bigbluebuttonbn', array('id' => $cm->instance), '*', MUST_EXIST);
3026
    return array('cm' => $cm, 'course' => $course, 'bigbluebuttonbn' => $bigbluebuttonbn);
3027
}
3028
3029
/**
3030
 * Helper function returns array with the instance settings used in views based on bigbluebuttonbnid.
3031
 *
3032
 * @param object $bigbluebuttonbnid
3033
 *
3034
 * @return array
3035
 */
3036 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...
3037
    global $DB;
3038
    $bigbluebuttonbn = $DB->get_record('bigbluebuttonbn', array('id' => $bigbluebuttonbnid), '*', MUST_EXIST);
3039
    $course = $DB->get_record('course', array('id' => $bigbluebuttonbn->course), '*', MUST_EXIST);
3040
    $cm = get_coursemodule_from_instance('bigbluebuttonbn', $bigbluebuttonbn->id, $course->id, false, MUST_EXIST);
3041
    return array('cm' => $cm, 'course' => $course, 'bigbluebuttonbn' => $bigbluebuttonbn);
3042
}
3043
3044
/**
3045
 * Helper function renders general settings if the feature is enabled.
3046
 *
3047
 * @param object $renderer
3048
 *
3049
 * @return void
3050
 */
3051
function bigbluebuttonbn_settings_general(&$renderer) {
3052
    // Configuration for BigBlueButton.
3053
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_general_shown()) {
3054
        $renderer->render_group_header('general');
3055
        $renderer->render_group_element(
3056
            'server_url',
3057
            $renderer->render_group_element_text('server_url', BIGBLUEBUTTONBN_DEFAULT_SERVER_URL)
3058
        );
3059
        $renderer->render_group_element(
3060
            'shared_secret',
3061
            $renderer->render_group_element_text('shared_secret', BIGBLUEBUTTONBN_DEFAULT_SHARED_SECRET)
3062
        );
3063
    }
3064
}
3065
3066
/**
3067
 * Helper function renders record settings if the feature is enabled.
3068
 *
3069
 * @param object $renderer
3070
 *
3071
 * @return void
3072
 */
3073
function bigbluebuttonbn_settings_record(&$renderer) {
3074
    // Configuration for 'recording' feature.
3075
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_record_meeting_shown()) {
3076
        $renderer->render_group_header('recording');
3077
        $renderer->render_group_element(
3078
            'recording_default',
3079
            $renderer->render_group_element_checkbox('recording_default', 1)
3080
        );
3081
        $renderer->render_group_element(
3082
            'recording_editable',
3083
            $renderer->render_group_element_checkbox('recording_editable', 1)
3084
        );
3085
        $renderer->render_group_element(
3086
            'recording_icons_enabled',
3087
            $renderer->render_group_element_checkbox('recording_icons_enabled', 1)
3088
        );
3089
3090
        // Add recording start to load and allow/hide stop/pause.
3091
        $renderer->render_group_element(
3092
            'recording_all_from_start_default',
3093
            $renderer->render_group_element_checkbox('recording_all_from_start_default', 0)
3094
        );
3095
        $renderer->render_group_element(
3096
            'recording_all_from_start_editable',
3097
            $renderer->render_group_element_checkbox('recording_all_from_start_editable', 0)
3098
        );
3099
        $renderer->render_group_element(
3100
            'recording_hide_button_default',
3101
            $renderer->render_group_element_checkbox('recording_hide_button_default', 0)
3102
        );
3103
        $renderer->render_group_element(
3104
            'recording_hide_button_editable',
3105
            $renderer->render_group_element_checkbox('recording_hide_button_editable', 0)
3106
        );
3107
    }
3108
}
3109
3110
/**
3111
 * Helper function renders import recording settings if the feature is enabled.
3112
 *
3113
 * @param object $renderer
3114
 *
3115
 * @return void
3116
 */
3117 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...
3118
    // Configuration for 'import recordings' feature.
3119
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_import_recordings_shown()) {
3120
        $renderer->render_group_header('importrecordings');
3121
        $renderer->render_group_element(
3122
            'importrecordings_enabled',
3123
            $renderer->render_group_element_checkbox('importrecordings_enabled', 0)
3124
        );
3125
        $renderer->render_group_element(
3126
            'importrecordings_from_deleted_enabled',
3127
            $renderer->render_group_element_checkbox('importrecordings_from_deleted_enabled', 0)
3128
        );
3129
    }
3130
}
3131
3132
/**
3133
 * Helper function renders show recording settings if the feature is enabled.
3134
 *
3135
 * @param object $renderer
3136
 *
3137
 * @return void
3138
 */
3139
function bigbluebuttonbn_settings_showrecordings(&$renderer) {
3140
    // Configuration for 'show recordings' feature.
3141
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_show_recordings_shown()) {
3142
        $renderer->render_group_header('recordings');
3143
        $renderer->render_group_element(
3144
            'recordings_html_default',
3145
            $renderer->render_group_element_checkbox('recordings_html_default', 1)
3146
        );
3147
        $renderer->render_group_element(
3148
            'recordings_html_editable',
3149
            $renderer->render_group_element_checkbox('recordings_html_editable', 0)
3150
        );
3151
        $renderer->render_group_element(
3152
            'recordings_deleted_default',
3153
            $renderer->render_group_element_checkbox('recordings_deleted_default', 1)
3154
        );
3155
        $renderer->render_group_element(
3156
            'recordings_deleted_editable',
3157
            $renderer->render_group_element_checkbox('recordings_deleted_editable', 0)
3158
        );
3159
        $renderer->render_group_element(
3160
            'recordings_imported_default',
3161
            $renderer->render_group_element_checkbox('recordings_imported_default', 0)
3162
        );
3163
        $renderer->render_group_element(
3164
            'recordings_imported_editable',
3165
            $renderer->render_group_element_checkbox('recordings_imported_editable', 1)
3166
        );
3167
        $renderer->render_group_element(
3168
            'recordings_preview_default',
3169
            $renderer->render_group_element_checkbox('recordings_preview_default', 1)
3170
        );
3171
        $renderer->render_group_element(
3172
            'recordings_preview_editable',
3173
            $renderer->render_group_element_checkbox('recordings_preview_editable', 0)
3174
        );
3175
        $renderer->render_group_element(
3176
            'recordings_sortorder',
3177
            $renderer->render_group_element_checkbox('recordings_sortorder', 0)
3178
        );
3179
        $renderer->render_group_element(
3180
            'recordings_validate_url',
3181
            $renderer->render_group_element_checkbox('recordings_validate_url', 1)
3182
        );
3183
    }
3184
}
3185
3186
/**
3187
 * Helper function renders wait for moderator settings if the feature is enabled.
3188
 *
3189
 * @param object $renderer
3190
 *
3191
 * @return void
3192
 */
3193
function bigbluebuttonbn_settings_waitmoderator(&$renderer) {
3194
    // Configuration for wait for moderator feature.
3195
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_wait_moderator_shown()) {
3196
        $renderer->render_group_header('waitformoderator');
3197
        $renderer->render_group_element(
3198
            'waitformoderator_default',
3199
            $renderer->render_group_element_checkbox('waitformoderator_default', 0)
3200
        );
3201
        $renderer->render_group_element(
3202
            'waitformoderator_editable',
3203
            $renderer->render_group_element_checkbox('waitformoderator_editable', 1)
3204
        );
3205
        $renderer->render_group_element(
3206
            'waitformoderator_ping_interval',
3207
            $renderer->render_group_element_text('waitformoderator_ping_interval', 10, PARAM_INT)
3208
        );
3209
        $renderer->render_group_element(
3210
            'waitformoderator_cache_ttl',
3211
            $renderer->render_group_element_text('waitformoderator_cache_ttl', 60, PARAM_INT)
3212
        );
3213
    }
3214
}
3215
3216
/**
3217
 * Helper function renders static voice bridge settings if the feature is enabled.
3218
 *
3219
 * @param object $renderer
3220
 *
3221
 * @return void
3222
 */
3223
function bigbluebuttonbn_settings_voicebridge(&$renderer) {
3224
    // Configuration for "static voice bridge" feature.
3225
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_static_voice_bridge_shown()) {
3226
        $renderer->render_group_header('voicebridge');
3227
        $renderer->render_group_element(
3228
            'voicebridge_editable',
3229
            $renderer->render_group_element_checkbox('voicebridge_editable', 0)
3230
        );
3231
    }
3232
}
3233
3234
/**
3235
 * Helper function renders preuploaded presentation settings if the feature is enabled.
3236
 *
3237
 * @param object $renderer
3238
 *
3239
 * @return void
3240
 */
3241
function bigbluebuttonbn_settings_preupload(&$renderer) {
3242
    // Configuration for "preupload presentation" feature.
3243
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_preupload_presentation_shown()) {
3244
        // This feature only works if curl is installed.
3245
        $preuploaddescripion = get_string('config_preuploadpresentation_description', 'bigbluebuttonbn');
3246
        if (!extension_loaded('curl')) {
3247
            $preuploaddescripion .= '<div class="form-defaultinfo">';
3248
            $preuploaddescripion .= get_string('config_warning_curl_not_installed', 'bigbluebuttonbn');
3249
            $preuploaddescripion .= '</div><br>';
3250
        }
3251
        $renderer->render_group_header('preuploadpresentation', null, $preuploaddescripion);
3252
        if (extension_loaded('curl')) {
3253
            $renderer->render_group_element(
3254
                'preuploadpresentation_enabled',
3255
                $renderer->render_group_element_checkbox('preuploadpresentation_enabled', 0)
3256
            );
3257
        }
3258
    }
3259
}
3260
3261
/**
3262
 * Helper function renders preuploaded presentation manage file if the feature is enabled.
3263
 * This allow to select a file for use as default in all BBB instances if preuploaded presetantion is enable.
3264
 *
3265
 * @param object $renderer
3266
 *
3267
 * @return void
3268
 */
3269
function bigbluebuttonbn_settings_preupload_manage_default_file(&$renderer) {
3270
    // Configuration for "preupload presentation" feature.
3271
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_preupload_presentation_shown()) {
3272
        if (extension_loaded('curl')) {
3273
            // This feature only works if curl is installed.
3274
            $renderer->render_filemanager_default_file_presentation("presentation_default");
3275
        }
3276
    }
3277
}
3278
3279
/**
3280
 * Helper function renders userlimit settings if the feature is enabled.
3281
 *
3282
 * @param object $renderer
3283
 *
3284
 * @return void
3285
 */
3286
function bigbluebuttonbn_settings_userlimit(&$renderer) {
3287
    // Configuration for "user limit" feature.
3288
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_user_limit_shown()) {
3289
        $renderer->render_group_header('userlimit');
3290
        $renderer->render_group_element(
3291
            'userlimit_default',
3292
            $renderer->render_group_element_text('userlimit_default', 0, PARAM_INT)
3293
        );
3294
        $renderer->render_group_element(
3295
            'userlimit_editable',
3296
            $renderer->render_group_element_checkbox('userlimit_editable', 0)
3297
        );
3298
    }
3299
}
3300
3301
/**
3302
 * Helper function renders duration settings if the feature is enabled.
3303
 *
3304
 * @param object $renderer
3305
 *
3306
 * @return void
3307
 */
3308
function bigbluebuttonbn_settings_duration(&$renderer) {
3309
    // Configuration for "scheduled duration" feature.
3310
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_scheduled_duration_shown()) {
3311
        $renderer->render_group_header('scheduled');
3312
        $renderer->render_group_element(
3313
            'scheduled_duration_enabled',
3314
            $renderer->render_group_element_checkbox('scheduled_duration_enabled', 1)
3315
        );
3316
        $renderer->render_group_element(
3317
            'scheduled_duration_compensation',
3318
            $renderer->render_group_element_text('scheduled_duration_compensation', 10, PARAM_INT)
3319
        );
3320
        $renderer->render_group_element(
3321
            'scheduled_pre_opening',
3322
            $renderer->render_group_element_text('scheduled_pre_opening', 10, PARAM_INT)
3323
        );
3324
    }
3325
}
3326
3327
/**
3328
 * Helper function renders participant settings if the feature is enabled.
3329
 *
3330
 * @param object $renderer
3331
 *
3332
 * @return void
3333
 */
3334
function bigbluebuttonbn_settings_participants(&$renderer) {
3335
    // Configuration for defining the default role/user that will be moderator on new activities.
3336
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_moderator_default_shown()) {
3337
        $renderer->render_group_header('participant');
3338
        // UI for 'participants' feature.
3339
        $roles = bigbluebuttonbn_get_roles(null, false);
3340
        $owner = array('0' => get_string('mod_form_field_participant_list_type_owner', 'bigbluebuttonbn'));
3341
        $renderer->render_group_element(
3342
            'participant_moderator_default',
3343
            $renderer->render_group_element_configmultiselect(
3344
                'participant_moderator_default',
3345
                array_keys($owner),
3346
                $owner + $roles // CONTRIB-7966: don't use array_merge here so it does not reindex the array.
3347
            )
3348
        );
3349
    }
3350
}
3351
3352
/**
3353
 * Helper function renders notification settings if the feature is enabled.
3354
 *
3355
 * @param object $renderer
3356
 *
3357
 * @return void
3358
 */
3359
function bigbluebuttonbn_settings_notifications(&$renderer) {
3360
    // Configuration for "send notifications" feature.
3361
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_send_notifications_shown()) {
3362
        $renderer->render_group_header('sendnotifications');
3363
        $renderer->render_group_element(
3364
            'sendnotifications_enabled',
3365
            $renderer->render_group_element_checkbox('sendnotifications_enabled', 1)
3366
        );
3367
    }
3368
}
3369
3370
/**
3371
 * Helper function renders client type settings if the feature is enabled.
3372
 *
3373
 * @param object $renderer
3374
 *
3375
 * @return void
3376
 */
3377
function bigbluebuttonbn_settings_clienttype(&$renderer) {
3378
    // Configuration for "clienttype" feature.
3379
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_clienttype_shown()) {
3380
        $renderer->render_group_header('clienttype');
3381
        $renderer->render_group_element(
3382
            'clienttype_editable',
3383
            $renderer->render_group_element_checkbox('clienttype_editable', 0)
3384
        );
3385
        // Web Client default.
3386
        $default = intval((int) \mod_bigbluebuttonbn\locallib\config::get('clienttype_default'));
3387
        $choices = array(BIGBLUEBUTTON_CLIENTTYPE_FLASH => get_string('mod_form_block_clienttype_flash', 'bigbluebuttonbn'),
3388
            BIGBLUEBUTTON_CLIENTTYPE_HTML5 => get_string('mod_form_block_clienttype_html5', 'bigbluebuttonbn'));
3389
        $renderer->render_group_element(
3390
            'clienttype_default',
3391
            $renderer->render_group_element_configselect(
3392
                'clienttype_default',
3393
                $default,
3394
                $choices
3395
            )
3396
        );
3397
    }
3398
}
3399
3400
/**
3401
 * Helper function renders general settings if the feature is enabled.
3402
 *
3403
 * @param object $renderer
3404
 *
3405
 * @return void
3406
 */
3407 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...
3408
    // Configuration for BigBlueButton.
3409
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_muteonstart_shown()) {
3410
        $renderer->render_group_header('muteonstart');
3411
        $renderer->render_group_element(
3412
            'muteonstart_default',
3413
            $renderer->render_group_element_checkbox('muteonstart_default', 0)
3414
        );
3415
        $renderer->render_group_element(
3416
            'muteonstart_editable',
3417
            $renderer->render_group_element_checkbox('muteonstart_editable', 0)
3418
        );
3419
    }
3420
}
3421
3422
/**
3423
 * Helper function renders general settings if the feature is enabled.
3424
 *
3425
 * @param object $renderer
3426
 *
3427
 * @return void
3428
 */
3429
function bigbluebuttonbn_settings_locksettings(&$renderer) {
3430
    $renderer->render_group_header('locksettings');
3431
    // Configuration for various lock settings for meetings.
3432
    bigbluebuttonbn_settings_disablecam($renderer);
3433
    bigbluebuttonbn_settings_disablemic($renderer);
3434
    bigbluebuttonbn_settings_disableprivatechat($renderer);
3435
    bigbluebuttonbn_settings_disablepublicchat($renderer);
3436
    bigbluebuttonbn_settings_disablenote($renderer);
3437
    bigbluebuttonbn_settings_hideuserlist($renderer);
3438
    bigbluebuttonbn_settings_lockedlayout($renderer);
3439
    bigbluebuttonbn_settings_lockonjoin($renderer);
3440
    bigbluebuttonbn_settings_lockonjoinconfigurable($renderer);
3441
}
3442
3443
/**
3444
 * Helper function renders general settings if the feature is enabled.
3445
 *
3446
 * @param object $renderer
3447
 *
3448
 * @return void
3449
 */
3450
function bigbluebuttonbn_settings_disablecam(&$renderer) {
3451
    // Configuration for BigBlueButton.
3452
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_disablecam_shown()) {
3453
        $renderer->render_group_element(
3454
            'disablecam_default',
3455
            $renderer->render_group_element_checkbox('disablecam_default', 0)
3456
        );
3457
        $renderer->render_group_element(
3458
            'disablecam_editable',
3459
            $renderer->render_group_element_checkbox('disablecam_editable', 1)
3460
        );
3461
    }
3462
}
3463
3464
/**
3465
 * Helper function renders general settings if the feature is enabled.
3466
 *
3467
 * @param object $renderer
3468
 *
3469
 * @return void
3470
 */
3471
function bigbluebuttonbn_settings_disablemic(&$renderer) {
3472
    // Configuration for BigBlueButton.
3473
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_disablemic_shown()) {
3474
        $renderer->render_group_element(
3475
            'disablemic_default',
3476
            $renderer->render_group_element_checkbox('disablemic_default', 0)
3477
        );
3478
        $renderer->render_group_element(
3479
            'disablecam_editable',
3480
            $renderer->render_group_element_checkbox('disablemic_editable', 1)
3481
        );
3482
    }
3483
}
3484
3485
/**
3486
 * Helper function renders general settings if the feature is enabled.
3487
 *
3488
 * @param object $renderer
3489
 *
3490
 * @return void
3491
 */
3492
function bigbluebuttonbn_settings_disableprivatechat(&$renderer) {
3493
    // Configuration for BigBlueButton.
3494
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_disableprivatechat_shown()) {
3495
        $renderer->render_group_element(
3496
            'disableprivatechat_default',
3497
            $renderer->render_group_element_checkbox('disableprivatechat_default', 0)
3498
        );
3499
        $renderer->render_group_element(
3500
            'disableprivatechat_editable',
3501
            $renderer->render_group_element_checkbox('disableprivatechat_editable', 1)
3502
        );
3503
    }
3504
}
3505
3506
/**
3507
 * Helper function renders general settings if the feature is enabled.
3508
 *
3509
 * @param object $renderer
3510
 *
3511
 * @return void
3512
 */
3513
function bigbluebuttonbn_settings_disablepublicchat(&$renderer) {
3514
    // Configuration for BigBlueButton.
3515
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_disablepublicchat_shown()) {
3516
        $renderer->render_group_element(
3517
            'disablepublicchat_default',
3518
            $renderer->render_group_element_checkbox('disablepublicchat_default', 0)
3519
        );
3520
        $renderer->render_group_element(
3521
            'disablepublicchat_editable',
3522
            $renderer->render_group_element_checkbox('disablepublicchat_editable', 1)
3523
        );
3524
    }
3525
}
3526
3527
/**
3528
 * Helper function renders general settings if the feature is enabled.
3529
 *
3530
 * @param object $renderer
3531
 *
3532
 * @return void
3533
 */
3534
function bigbluebuttonbn_settings_disablenote(&$renderer) {
3535
    // Configuration for BigBlueButton.
3536
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_disablenote_shown()) {
3537
        $renderer->render_group_element(
3538
            'disablenote_default',
3539
            $renderer->render_group_element_checkbox('disablenote_default', 0)
3540
        );
3541
        $renderer->render_group_element(
3542
            'disablenote_editable',
3543
            $renderer->render_group_element_checkbox('disablenote_editable', 1)
3544
        );
3545
    }
3546
}
3547
3548
/**
3549
 * Helper function renders general settings if the feature is enabled.
3550
 *
3551
 * @param object $renderer
3552
 *
3553
 * @return void
3554
 */
3555
function bigbluebuttonbn_settings_hideuserlist(&$renderer) {
3556
    // Configuration for BigBlueButton.
3557
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_hideuserlist_shown()) {
3558
        $renderer->render_group_element(
3559
            'hideuserlist_default',
3560
            $renderer->render_group_element_checkbox('hideuserlist_default', 0)
3561
        );
3562
        $renderer->render_group_element(
3563
            'hideuserlist_editable',
3564
            $renderer->render_group_element_checkbox('hideuserlist_editable', 1)
3565
        );
3566
    }
3567
}
3568
3569
/**
3570
 * Helper function renders general settings if the feature is enabled.
3571
 *
3572
 * @param object $renderer
3573
 *
3574
 * @return void
3575
 */
3576
function bigbluebuttonbn_settings_lockedlayout(&$renderer) {
3577
    // Configuration for BigBlueButton.
3578
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_lockedlayout_shown()) {
3579
        $renderer->render_group_element(
3580
            'lockedlayout_default',
3581
            $renderer->render_group_element_checkbox('lockedlayout_default', 0)
3582
        );
3583
        $renderer->render_group_element(
3584
            'lockedlayout_editable',
3585
            $renderer->render_group_element_checkbox('lockedlayout_editable', 1)
3586
        );
3587
    }
3588
}
3589
3590
/**
3591
 * Helper function renders general settings if the feature is enabled.
3592
 *
3593
 * @param object $renderer
3594
 *
3595
 * @return void
3596
 */
3597
function bigbluebuttonbn_settings_lockonjoin(&$renderer) {
3598
    // Configuration for BigBlueButton.
3599
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_lockonjoin_shown()) {
3600
        $renderer->render_group_element(
3601
            'lockonjoin_default',
3602
            $renderer->render_group_element_checkbox('lockonjoin_default', 0)
3603
        );
3604
        $renderer->render_group_element(
3605
            'lockonjoin_editable',
3606
            $renderer->render_group_element_checkbox('lockonjoin_editable', 1)
3607
        );
3608
    }
3609
}
3610
3611
/**
3612
 * Helper function renders general settings if the feature is enabled.
3613
 *
3614
 * @param object $renderer
3615
 *
3616
 * @return void
3617
 */
3618
function bigbluebuttonbn_settings_lockonjoinconfigurable(&$renderer) {
3619
    // Configuration for BigBlueButton.
3620
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_lockonjoinconfigurable_shown()) {
3621
        $renderer->render_group_element(
3622
            'lockonjoinconfigurable_default',
3623
            $renderer->render_group_element_checkbox('lockonjoinconfigurable_default', 0)
3624
        );
3625
        $renderer->render_group_element(
3626
            'lockonjoinconfigurable_editable',
3627
            $renderer->render_group_element_checkbox('lockonjoinconfigurable_editable', 1)
3628
        );
3629
    }
3630
}
3631
3632
/**
3633
 * Helper function renders default messages settings.
3634
 *
3635
 * @param object $renderer
3636
 *
3637
 * @return void
3638
 */
3639
function bigbluebuttonbn_settings_default_messages(&$renderer) {
3640
    $renderer->render_group_header('default_messages');
3641
    $renderer->render_group_element(
3642
        'welcome_default',
3643
        $renderer->render_group_element_textarea('welcome_default', '', PARAM_TEXT)
3644
    );
3645
}
3646
3647
/**
3648
 * Helper function renders extended settings if any of the features there is enabled.
3649
 *
3650
 * @param object $renderer
3651
 *
3652
 * @return void
3653
 */
3654
function bigbluebuttonbn_settings_extended(&$renderer) {
3655
    // Configuration for extended capabilities.
3656
    if (!(boolean) \mod_bigbluebuttonbn\settings\validator::section_settings_extended_shown()) {
3657
        return;
3658
    }
3659
    $renderer->render_group_header('extended_capabilities');
3660
    // UI for 'notify users when recording ready' feature.
3661
    $renderer->render_group_element(
3662
        'recordingready_enabled',
3663
        $renderer->render_group_element_checkbox('recordingready_enabled', 0)
3664
    );
3665
    // Configuration for extended BN capabilities should go here.
3666
}
3667
3668
/**
3669
 * Helper function renders experimental settings if any of the features there is enabled.
3670
 *
3671
 * @param object $renderer
3672
 *
3673
 * @return void
3674
 */
3675
function bigbluebuttonbn_settings_experimental(&$renderer) {
3676
    // Configuration for experimental features should go here.
3677
    $renderer->render_group_header('experimental_features');
3678
    // UI for 'register meeting events' feature.
3679
    $renderer->render_group_element(
3680
        'meetingevents_enabled',
3681
        $renderer->render_group_element_checkbox('meetingevents_enabled', 0)
3682
    );
3683
}
3684
3685
/**
3686
 * Helper function returns a sha1 encoded string that is unique and will be used as a seed for meetingid.
3687
 *
3688
 * @return string
3689
 */
3690
function bigbluebuttonbn_unique_meetingid_seed() {
3691
    global $DB;
3692
    do {
3693
        $encodedseed = sha1(bigbluebuttonbn_random_password(12));
3694
        $meetingid = (string) $DB->get_field('bigbluebuttonbn', 'meetingid', array('meetingid' => $encodedseed));
3695
    } while ($meetingid == $encodedseed);
3696
    return $encodedseed;
3697
}
3698
3699
/**
3700
 * Helper function renders the link used for recording type in row for the data used by the recording table.
3701
 *
3702
 * @param array $recording
3703
 * @param array $bbbsession
3704
 * @param array $playback
3705
 *
3706
 * @return boolean
3707
 */
3708
function bigbluebuttonbn_include_recording_data_row_type($recording, $bbbsession, $playback) {
3709
    // All types that are not restricted are included.
3710
    if (array_key_exists('restricted', $playback) && strtolower($playback['restricted']) == 'false') {
3711
        return true;
3712
    }
3713
    // All types that are not statistics are included.
3714
    if ($playback['type'] != 'statistics') {
3715
        return true;
3716
    }
3717
    // Exclude imported recordings.
3718
    if (isset($recording['imported'])) {
3719
        return false;
3720
    }
3721
    // Exclude non moderators.
3722
    if (!$bbbsession['administrator'] && !$bbbsession['moderator']) {
3723
        return false;
3724
    }
3725
    return true;
3726
}
3727
3728
/**
3729
 * Renders the general warning message.
3730
 *
3731
 * @param string $message
3732
 * @param string $type
3733
 * @param string $href
3734
 * @param string $text
3735
 * @param string $class
3736
 *
3737
 * @return string
3738
 */
3739
function bigbluebuttonbn_render_warning($message, $type = 'info', $href = '', $text = '', $class = '') {
3740
    global $OUTPUT;
3741
    $output = "\n";
3742
    // Evaluates if config_warning is enabled.
3743
    if (empty($message)) {
3744
        return $output;
3745
    }
3746
    $output .= $OUTPUT->box_start(
3747
        'box boxalignleft adminerror alert alert-' . $type . ' alert-block fade in',
3748
        'bigbluebuttonbn_view_general_warning'
3749
    ) . "\n";
3750
    $output .= '    ' . $message . "\n";
3751
    $output .= '  <div class="singlebutton pull-right">' . "\n";
3752
    if (!empty($href)) {
3753
        $output .= bigbluebuttonbn_render_warning_button($href, $text, $class);
3754
    }
3755
    $output .= '  </div>' . "\n";
3756
    $output .= $OUTPUT->box_end() . "\n";
3757
    return $output;
3758
}
3759
3760
/**
3761
 * Renders the general warning button.
3762
 *
3763
 * @param string $href
3764
 * @param string $text
3765
 * @param string $class
3766
 * @param string $title
3767
 *
3768
 * @return string
3769
 */
3770
function bigbluebuttonbn_render_warning_button($href, $text = '', $class = '', $title = '') {
3771
    if ($text == '') {
3772
        $text = get_string('ok', 'moodle');
3773
    }
3774
    if ($title == '') {
3775
        $title = $text;
3776
    }
3777
    if ($class == '') {
3778
        $class = 'btn btn-secondary';
3779
    }
3780
    $output = '  <form method="post" action="' . $href . '" class="form-inline">' . "\n";
3781
    $output .= '      <button type="submit" class="' . $class . '"' . "\n";
3782
    $output .= '          title="' . $title . '"' . "\n";
3783
    $output .= '          >' . $text . '</button>' . "\n";
3784
    $output .= '  </form>' . "\n";
3785
    return $output;
3786
}
3787
3788
/**
3789
 * Check if a BigBlueButtonBN is available to be used by the current user.
3790
 *
3791
 * @param  stdClass  $bigbluebuttonbn  BigBlueButtonBN instance
3792
 *
3793
 * @return boolean                     status if room available and current user allowed to join
3794
 */
3795
function bigbluebuttonbn_get_availability_status($bigbluebuttonbn) {
3796
    list($roomavailable) = bigbluebuttonbn_room_is_available($bigbluebuttonbn);
3797
    list($usercanjoin) = bigbluebuttonbn_user_can_join_meeting($bigbluebuttonbn);
3798
    return ($roomavailable && $usercanjoin);
3799
}
3800
3801
/**
3802
 * Helper for evaluating if scheduled activity is avaiable.
3803
 *
3804
 * @param  stdClass  $bigbluebuttonbn  BigBlueButtonBN instance
3805
 *
3806
 * @return array                       status (room available or not and possible warnings)
3807
 */
3808
function bigbluebuttonbn_room_is_available($bigbluebuttonbn) {
3809
    $open = true;
3810
    $closed = false;
3811
    $warnings = array();
3812
3813
    $timenow = time();
3814
    $timeopen = $bigbluebuttonbn->openingtime;
3815
    $timeclose = $bigbluebuttonbn->closingtime;
3816
    if (!empty($timeopen) && $timeopen > $timenow) {
3817
        $open = false;
3818
    }
3819
    if (!empty($timeclose) && $timenow > $timeclose) {
3820
        $closed = true;
3821
    }
3822
3823
    if (!$open || $closed) {
3824
        if (!$open) {
3825
            $warnings['notopenyet'] = userdate($timeopen);
3826
        }
3827
        if ($closed) {
3828
            $warnings['expired'] = userdate($timeclose);
3829
        }
3830
        return array(false, $warnings);
3831
    }
3832
3833
    return array(true, $warnings);
3834
}
3835
3836
/**
3837
 * Helper for evaluating if meeting can be joined.
3838
 *
3839
 * @param  stdClass $bigbluebuttonbn  BigBlueButtonBN instance
3840
 * @param  string   $mid
3841
 * @param  integer  $userid
3842
 *
3843
 * @return array    status (user allowed to join or not and possible message)
3844
 */
3845
function bigbluebuttonbn_user_can_join_meeting($bigbluebuttonbn, $mid = null, $userid = null) {
3846
    // By default, use a meetingid without groups.
3847
    if (empty($mid)) {
3848
        $mid = $bigbluebuttonbn->meetingid . '-' . $bigbluebuttonbn->course . '-' . $bigbluebuttonbn->id;
3849
    }
3850
    // When meeting is running, all authorized users can join right in.
3851
    if (bigbluebuttonbn_is_meeting_running($mid)) {
3852
        return array(true, get_string('view_message_conference_in_progress', 'bigbluebuttonbn'));
3853
    }
3854
    // When meeting is not running, see if the user can join.
3855
    $context = context_course::instance($bigbluebuttonbn->course);
3856
    $participantlist = bigbluebuttonbn_get_participant_list($bigbluebuttonbn, $context);
3857
    $isadmin = is_siteadmin($userid);
3858
    $ismoderator = bigbluebuttonbn_is_moderator($context, $participantlist, $userid);
3859
    // If user is administrator, moderator or if is viewer and no waiting is required, join allowed.
3860
    if ($isadmin || $ismoderator || !$bigbluebuttonbn->wait) {
3861
        return array(true, get_string('view_message_conference_room_ready', 'bigbluebuttonbn'));
3862
    }
3863
    // Otherwise, no join allowed.
3864
    return array(false, get_string('view_message_conference_wait_for_moderator', 'bigbluebuttonbn'));
3865
}
3866
3867
/**
3868
 * Helper for getting a value from a bigbluebuttonbn cache.
3869
 *
3870
 * @param  string   $name       BigBlueButtonBN cache
3871
 * @param  string   $key        Key to be retrieved
3872
 * @param  integer  $default    Default value in case key is not found or it is empty
3873
 *
3874
 * @return variable key value
3875
 */
3876
function bigbluebuttonbn_cache_get($name, $key, $default = null) {
3877
    $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'mod_bigbluebuttonbn', $name);
3878
    $result = $cache->get($key);
3879
    if (!empty($result)) {
3880
        return $result;
3881
    }
3882
    return $default;
3883
}
3884
3885
/**
3886
 * Helper for setting a value in a bigbluebuttonbn cache.
3887
 *
3888
 * @param  string   $name       BigBlueButtonBN cache
3889
 * @param  string   $key        Key to be created/updated
3890
 * @param  variable $value      Default value to be set
3891
 */
3892
function bigbluebuttonbn_cache_set($name, $key, $value) {
3893
    $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'mod_bigbluebuttonbn', $name);
3894
    $cache->set($key, $value);
3895
}
3896
3897
/**
3898
 * Helper for getting the owner userid of a bigbluebuttonbn instance.
3899
 *
3900
 * @param  stdClass $bigbluebuttonbn  BigBlueButtonBN instance
3901
 *
3902
 * @return integer ownerid (a valid user id or null if not registered/found)
3903
 */
3904
function bigbluebuttonbn_instance_ownerid($bigbluebuttonbn) {
3905
    global $DB;
3906
    $filters = array('bigbluebuttonbnid' => $bigbluebuttonbn->id, 'log' => 'Add');
3907
    $ownerid = (integer) $DB->get_field('bigbluebuttonbn_logs', 'userid', $filters);
3908
    return $ownerid;
3909
}
3910
3911
/**
3912
 * Helper evaluates if the bigbluebutton server used belongs to blindsidenetworks domain.
3913
 *
3914
 * @return boolean
3915
 */
3916
function bigbluebuttonbn_has_html5_client() {
3917
    $checkurl = \mod_bigbluebuttonbn\locallib\bigbluebutton::root() . "html5client/check";
3918
    $curlinfo = bigbluebuttonbn_wrap_xml_load_file_curl_request($checkurl, 'HEAD');
3919
    return (isset($curlinfo['http_code']) && $curlinfo['http_code'] == 200);
3920
}
3921
3922
/**
3923
 * Return the status of an activity [open|not_started|ended].
3924
 *
3925
 * @param array $bbbsession
3926
 * @return string
3927
 */
3928 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...
3929
    $now = time();
3930
    if (!empty($bbbsession['bigbluebuttonbn']->openingtime) && $now < $bbbsession['bigbluebuttonbn']->openingtime) {
3931
        // The activity has not been opened.
3932
        return 'not_started';
3933
    }
3934
    if (!empty($bbbsession['bigbluebuttonbn']->closingtime) && $now > $bbbsession['bigbluebuttonbn']->closingtime) {
3935
        // The activity has been closed.
3936
        return 'ended';
3937
    }
3938
    // The activity is open.
3939
    return 'open';
3940
}
3941
3942
/**
3943
 * Set session URLs.
3944
 *
3945
 * @param array $bbbsession
3946
 * @param int $id
3947
 * @return string
3948
 */
3949
function bigbluebuttonbn_view_session_config(&$bbbsession, $id) {
3950
    // Operation URLs.
3951
    $bbbsession['bigbluebuttonbnURL'] = plugin::necurl(
3952
        '/mod/bigbluebuttonbn/view.php',
3953
        ['id' => $bbbsession['cm']->id]
3954
    );
3955
    $bbbsession['logoutURL'] = plugin::necurl(
3956
        '/mod/bigbluebuttonbn/bbb_view.php',
3957
        ['action' => 'logout', 'id' => $id, 'bn' => $bbbsession['bigbluebuttonbn']->id]
3958
    );
3959
    $bbbsession['recordingReadyURL'] = plugin::necurl(
3960
        '/mod/bigbluebuttonbn/bbb_broker.php',
3961
        ['action' => 'recording_ready', 'bigbluebuttonbn' => $bbbsession['bigbluebuttonbn']->id]
3962
    );
3963
    $bbbsession['meetingEventsURL'] = plugin::necurl(
3964
        '/mod/bigbluebuttonbn/bbb_broker.php',
3965
        ['action' => 'meeting_events', 'bigbluebuttonbn' => $bbbsession['bigbluebuttonbn']->id]
3966
    );
3967
    $bbbsession['joinURL'] = plugin::necurl(
3968
        '/mod/bigbluebuttonbn/bbb_view.php',
3969
        ['action' => 'join', 'id' => $id, 'bn' => $bbbsession['bigbluebuttonbn']->id]
3970
    );
3971
3972
    // Check status and set extra values.
3973
    $activitystatus = bigbluebuttonbn_view_get_activity_status($bbbsession); // In locallib.
3974 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...
3975
        $bbbsession['presentation'] = bigbluebuttonbn_get_presentation_array(
3976
            $bbbsession['context'],
3977
            $bbbsession['bigbluebuttonbn']->presentation
3978
        );
3979
    } else if ($activitystatus == 'open') {
3980
        $bbbsession['presentation'] = bigbluebuttonbn_get_presentation_array(
3981
            $bbbsession['context'],
3982
            $bbbsession['bigbluebuttonbn']->presentation,
3983
            $bbbsession['bigbluebuttonbn']->id
3984
        );
3985
    }
3986
3987
    return $activitystatus;
3988
}
3989
3990
/**
3991
 * Helper for preparing metadata used while creating the meeting.
3992
 *
3993
 * @param  array    $bbbsession
3994
 * @return array
3995
 */
3996
function bigbluebuttonbn_create_meeting_metadata(&$bbbsession) {
3997
    global $USER;
3998
    // Create standard metadata.
3999
    $metadata = [
4000
        'bbb-origin' => $bbbsession['origin'],
4001
        'bbb-origin-version' => $bbbsession['originVersion'],
4002
        'bbb-origin-server-name' => $bbbsession['originServerName'],
4003
        'bbb-origin-server-common-name' => $bbbsession['originServerCommonName'],
4004
        'bbb-origin-tag' => $bbbsession['originTag'],
4005
        'bbb-context' => $bbbsession['course']->fullname,
4006
        'bbb-context-id' => $bbbsession['course']->id,
4007
        'bbb-context-name' => trim(html_to_text($bbbsession['course']->fullname, 0)),
4008
        'bbb-context-label' => trim(html_to_text($bbbsession['course']->shortname, 0)),
4009
        'bbb-recording-name' => bigbluebuttonbn_html2text($bbbsession['meetingname'], 64),
4010
        'bbb-recording-description' => bigbluebuttonbn_html2text($bbbsession['meetingdescription'], 64),
4011
        'bbb-recording-tags' => bigbluebuttonbn_get_tags($bbbsession['cm']->id), // Same as $id.
4012
    ];
4013
    // Special metadata for recording processing.
4014
    if ((boolean) \mod_bigbluebuttonbn\locallib\config::get('recordingstatus_enabled')) {
4015
        $metadata["bn-recording-status"] = json_encode(
4016
            array(
4017
                'email' => array('"' . fullname($USER) . '" <' . $USER->email . '>'),
4018
                'context' => $bbbsession['bigbluebuttonbnURL'],
4019
            )
4020
        );
4021
    }
4022
    if ((boolean) \mod_bigbluebuttonbn\locallib\config::get('recordingready_enabled')) {
4023
        $metadata['bn-recording-ready-url'] = $bbbsession['recordingReadyURL'];
4024
    }
4025
    if ((boolean) \mod_bigbluebuttonbn\locallib\config::get('meetingevents_enabled')) {
4026
        $metadata['analytics-callback-url'] = $bbbsession['meetingEventsURL'];
4027
    }
4028
    // Special metadata for Opencast recordings (passing opencast seriesid of the course as opencast-dc-isPartOf as metadata).
4029
    if ((boolean) \mod_bigbluebuttonbn\locallib\config::get('oc_recording')) {
4030
        $ocseriesid = bigbluebuttonbn_check_opencast($bbbsession['course']->id);
4031
        if ($ocseriesid != false) {
4032
            $metadata['opencast-dc-isPartOf'] = $ocseriesid;
4033
            $metadata['opencast-dc-subject'] = $bbbsession['meetingid'];
4034
        }
4035
    }
4036
    return $metadata;
4037
}
4038
4039
/**
4040
 * Helper function which checks if the Opencast plugin (block_opencast) is installed. The function is called from several places throughout mod_bigbluebuttonbn where Opencast functionality can enhance the BBB meeting recording functionality as soon as the Opencast plugin is present.
4041
 * If called with a course ID as parameter, the function will not only check if the Opencast plugin is installed. It will also ensure that an Opencast series exists for the given course and will return the Opencast series ID instead of a boolean. In this case, the block does not necessarily be placed in the course.
4042
 *
4043
 * @param  string    $courseid
4044
 * @return boolean|string
4045
 */
4046
function bigbluebuttonbn_check_opencast($courseid = null) {
4047
    $blockplugins = core_plugin_manager::instance()->get_plugins_of_type('block');
4048
    // If block_opencast is installed.
4049
    if (in_array('opencast', array_keys($blockplugins))) {
4050
        // Getting an instance of the block_opencast API bridge.
4051
        $opencast = \block_opencast\local\apibridge::get_instance();
4052
        // If opencast is not configured!
4053
        if (!$opencast) {
4054
            return false;
4055
        }
4056
        // If the courseid is required (check if the course has the opencsat series).
4057
        if ($courseid) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $courseid of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
4058
            // Trying to get course seriesid, create if is not set before!
4059
            try {
4060
                $series = $opencast->ensure_course_series_exists($courseid);
4061
                if (is_object($series) && $series->identifier) {
4062
                    $seriesid = $series->identifier;
4063
                } else {
4064
                    $seriesid = $series;
4065
                }
4066
                return $seriesid;
4067
            } catch (Exception $e) {
4068
                return false;
4069
            }
4070
        }
4071
        return true;
4072
    }
4073
    // If block_opencast is not installed
4074
    return false;
4075
}
4076
4077
/**
4078
 * Helper function renders Opencast integration settings if block_opencast is installed.
4079
 *
4080
 * @param object $renderer
4081
 *
4082
 * @return void
4083
 */
4084
function bigbluebuttonbn_settings_opencastintegration(&$renderer) {
4085
    // Configuration for 'Opencast integration' feature when Opencast plugins are installed.
4086
    if ((boolean) bigbluebuttonbn_check_opencast()) {
4087
        $renderer->render_group_header('opencast');
4088
        $renderer->render_group_element(
4089
            'oc_recording',
4090
            $renderer->render_group_element_checkbox('oc_recording', 0)
4091
        );
4092
        $renderer->render_group_element(
4093
            'oc_show_recording',
4094
            $renderer->render_group_element_checkbox('oc_show_recording', 0)
4095
        );
4096
    }
4097
    
4098
}
4099