Completed
Branch master (50b31b)
by Jesus
02:05
created

locallib.php ➔ bigbluebuttonbn_get_presentation_array()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 92

Duplication

Lines 33
Ratio 35.87 %

Importance

Changes 0
Metric Value
cc 7
nc 7
nop 3
dl 33
loc 92
rs 7.2412
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
// 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
 *
103
 * @return string
104
 */
105
function bigbluebuttonbn_get_join_url(
106
    $meetingid,
107
    $username,
108
    $pw,
109
    $logouturl,
110
    $configtoken = null,
111
    $userid = null,
112
    $clienttype = BIGBLUEBUTTON_CLIENTTYPE_FLASH
113
) {
114
    $data = ['meetingID' => $meetingid,
115
        'fullName' => $username,
116
        'password' => $pw,
117
        'logoutURL' => $logouturl,
118
    ];
119
    // Choose between Adobe Flash or HTML5 Client.
120
    if ($clienttype == BIGBLUEBUTTON_CLIENTTYPE_HTML5) {
121
        $data['joinViaHtml5'] = 'true';
122
    }
123
    if (!is_null($configtoken)) {
124
        $data['configToken'] = $configtoken;
125
    }
126
    if (!is_null($userid)) {
127
        $data['userID'] = $userid;
128
    }
129
    return \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('join', $data);
130
}
131
132
/**
133
 * Creates a bigbluebutton meeting and returns the response in an array.
134
 *
135
 * @param array  $data
136
 * @param array  $metadata
137
 * @param string $pname
138
 * @param string $purl
139
 *
140
 * @return array
141
 */
142
function bigbluebuttonbn_get_create_meeting_array($data, $metadata = array(), $pname = null, $purl = null) {
143
    $createmeetingurl = \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('create', $data, $metadata);
144
    $method = 'GET';
145
    $data = null;
146
    if (!is_null($pname) && !is_null($purl)) {
147
        $method = 'POST';
148
        $data = "<?xml version='1.0' encoding='UTF-8'?><modules><module name='presentation'><document url='" .
149
            $purl . "' /></module></modules>";
150
    }
151
    $xml = bigbluebuttonbn_wrap_xml_load_file($createmeetingurl, $method, $data);
152
    if ($xml) {
153
        $response = array('returncode' => $xml->returncode, 'message' => $xml->message, 'messageKey' => $xml->messageKey);
154
        if ($xml->meetingID) {
155
            $response += array('meetingID' => $xml->meetingID, 'attendeePW' => $xml->attendeePW,
156
                'moderatorPW' => $xml->moderatorPW, 'hasBeenForciblyEnded' => $xml->hasBeenForciblyEnded);
157
        }
158
        return $response;
159
    }
160
    return array('returncode' => 'FAILED', 'message' => 'unreachable', 'messageKey' => 'Server is unreachable');
161
}
162
163
/**
164
 * Fetch meeting info and wrap response in array.
165
 *
166
 * @param string $meetingid
167
 *
168
 * @return array
169
 */
170
function bigbluebuttonbn_get_meeting_info_array($meetingid) {
171
    $xml = bigbluebuttonbn_wrap_xml_load_file(
172
        \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('getMeetingInfo', ['meetingID' => $meetingid])
173
    );
174
    if ($xml && $xml->returncode == 'SUCCESS' && empty($xml->messageKey)) {
175
        // Meeting info was returned.
176
        return array('returncode' => $xml->returncode,
177
            'meetingID' => $xml->meetingID,
178
            'moderatorPW' => $xml->moderatorPW,
179
            'attendeePW' => $xml->attendeePW,
180
            'hasBeenForciblyEnded' => $xml->hasBeenForciblyEnded,
181
            'running' => $xml->running,
182
            'recording' => $xml->recording,
183
            'startTime' => $xml->startTime,
184
            'endTime' => $xml->endTime,
185
            'participantCount' => $xml->participantCount,
186
            'moderatorCount' => $xml->moderatorCount,
187
            'attendees' => $xml->attendees,
188
            'metadata' => $xml->metadata,
189
        );
190
    }
191
    if ($xml) {
192
        // Either failure or success without meeting info.
193
        return (array) $xml;
194
    }
195
    // If the server is unreachable, then prompts the user of the necessary action.
196
    return array('returncode' => 'FAILED', 'message' => 'unreachable', 'messageKey' => 'Server is unreachable');
197
}
198
199
/**
200
 * Helper function to retrieve recordings from a BigBlueButton server.
201
 *
202
 * @param string|array $meetingids   list of meetingIDs "mid1,mid2,mid3" or array("mid1","mid2","mid3")
203
 * @param string|array $recordingids list of $recordingids "rid1,rid2,rid3" or array("rid1","rid2","rid3") for filtering
204
 *
205
 * @return associative array with recordings indexed by recordID, each recording is a non sequential associative array
206
 */
207
function bigbluebuttonbn_get_recordings_array($meetingids, $recordingids = []) {
208
    $meetingidsarray = $meetingids;
209
    if (!is_array($meetingids)) {
210
        $meetingidsarray = explode(',', $meetingids);
211
    }
212
    // If $meetingidsarray is empty there is no need to go further.
213
    if (empty($meetingidsarray)) {
214
        return array();
215
    }
216
    $recordings = bigbluebuttonbn_get_recordings_array_fetch($meetingidsarray);
0 ignored issues
show
Bug introduced by
It seems like $meetingidsarray defined by $meetingids on line 208 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...
217
    // Sort recordings.
218
    uasort($recordings, 'bigbluebuttonbn_recording_build_sorter');
219
    // Filter recordings based on recordingIDs.
220
    $recordingidsarray = $recordingids;
221
    if (!is_array($recordingids)) {
222
        $recordingidsarray = explode(',', $recordingids);
223
    }
224
    if (empty($recordingidsarray)) {
225
        // No recording ids, no need to filter.
226
        return $recordings;
227
    }
228
    return bigbluebuttonbn_get_recordings_array_filter($recordingidsarray, $recordings);
0 ignored issues
show
Bug introduced by
It seems like $recordingidsarray defined by $recordingids on line 220 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...
229
}
230
231
/**
232
 * Helper function to fetch recordings from a BigBlueButton server.
233
 *
234
 * @param array $meetingidsarray   array with meeting ids in the form array("mid1","mid2","mid3")
235
 *
236
 * @return associative array with recordings indexed by recordID, each recording is a non sequential associative array
237
 */
238
function bigbluebuttonbn_get_recordings_array_fetch($meetingidsarray) {
239
    $recordings = array();
240
    // Execute a paginated getRecordings request.
241
    $pages = floor(count($meetingidsarray) / 25) + 1;
242
    for ($page = 1; $page <= $pages; ++$page) {
243
        $mids = array_slice($meetingidsarray, ($page - 1) * 25, 25);
244
        $recordings += bigbluebuttonbn_get_recordings_array_fetch_page($mids);
245
    }
246
    return $recordings;
247
}
248
249
/**
250
 * Helper function to fetch one page of upto 25 recordings from a BigBlueButton server.
251
 *
252
 * @param array  $mids
253
 *
254
 * @return array
255
 */
256
function bigbluebuttonbn_get_recordings_array_fetch_page($mids) {
257
    $recordings = array();
258
    // Do getRecordings is executed using a method GET (supported by all versions of BBB).
259
    $url = \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('getRecordings', ['meetingID' => implode(',', $mids)]);
260
    $xml = bigbluebuttonbn_wrap_xml_load_file($url);
261
    if ($xml && $xml->returncode == 'SUCCESS' && isset($xml->recordings)) {
262
        // If there were meetings already created.
263
        foreach ($xml->recordings->recording as $recordingxml) {
264
            $recording = bigbluebuttonbn_get_recording_array_value($recordingxml);
265
            $recordings[$recording['recordID']] = $recording;
266
267
            // Check if there is childs.
268
            if (isset($recordingxml->breakoutRooms->breakoutRoom)) {
269
                foreach ($recordingxml->breakoutRooms->breakoutRoom as $breakoutroom) {
270
                    $url = \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url(
271
                        'getRecordings',
272
                        ['recordID' => implode(',', (array) $breakoutroom)]
273
                    );
274
                    $xml = bigbluebuttonbn_wrap_xml_load_file($url);
275
                    if ($xml && $xml->returncode == 'SUCCESS' && isset($xml->recordings)) {
276
                        // If there were meetings already created.
277
                        foreach ($xml->recordings->recording as $recordingxml) {
278
                            $recording = bigbluebuttonbn_get_recording_array_value($recordingxml);
279
                            $recordings[$recording['recordID']] = $recording;
280
                        }
281
                    }
282
                }
283
            }
284
        }
285
    }
286
    return $recordings;
287
}
288
289
/**
290
 * Helper function to remove a set of recordings from an array.
291
 *
292
 * @param array  $rids
293
 * @param array  $recordings
294
 *
295
 * @return array
296
 */
297
function bigbluebuttonbn_get_recordings_array_filter($rids, &$recordings) {
298
    foreach ($recordings as $key => $recording) {
299
        if (!in_array($recording['recordID'], $rids)) {
300
            unset($recordings[$key]);
301
        }
302
    }
303
    return $recordings;
304
}
305
306
/**
307
 * Helper function to retrieve imported recordings from the Moodle database.
308
 * The references are stored as events in bigbluebuttonbn_logs.
309
 *
310
 * @param string $courseid
311
 * @param string $bigbluebuttonbnid
312
 * @param bool   $subset
313
 *
314
 * @return associative array with imported recordings indexed by recordID, each recording
315
 * is a non sequential associative array that corresponds to the actual recording in BBB
316
 */
317
function bigbluebuttonbn_get_recordings_imported_array($courseid = 0, $bigbluebuttonbnid = null, $subset = true) {
318
    global $DB;
319
    $select = bigbluebuttonbn_get_recordings_imported_sql_select($courseid, $bigbluebuttonbnid, $subset);
320
    $recordsimported = $DB->get_records_select('bigbluebuttonbn_logs', $select);
321
    $recordsimportedarray = array();
322
    foreach ($recordsimported as $recordimported) {
323
        $meta = json_decode($recordimported->meta, true);
324
        $recording = $meta['recording'];
325
        // Override imported flag with actual ID.
326
        $recording['imported'] = $recordimported->id;
327
        if (isset($recordimported->protected)) {
328
            $recording['protected'] = (string) $recordimported->protected;
329
        }
330
        $recordsimportedarray[$recording['recordID']] = $recording;
331
    }
332
    return $recordsimportedarray;
333
}
334
335
/**
336
 * Helper function to retrive the default config.xml file.
337
 *
338
 * @return string
339
 */
340
function bigbluebuttonbn_get_default_config_xml() {
341
    $xml = bigbluebuttonbn_wrap_xml_load_file(
342
        \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('getDefaultConfigXML')
343
    );
344
    return $xml;
345
}
346
347
/**
348
 * Helper function to convert an xml recording object to an array in the format used by the plugin.
349
 *
350
 * @param object $recording
351
 *
352
 * @return array
353
 */
354
function bigbluebuttonbn_get_recording_array_value($recording) {
355
    // Add formats.
356
    $playbackarray = array();
357
    foreach ($recording->playback->format as $format) {
358
        $playbackarray[(string) $format->type] = array('type' => (string) $format->type,
359
            'url' => trim((string) $format->url), 'length' => (string) $format->length);
360
        // Add preview per format when existing.
361
        if ($format->preview) {
362
            $playbackarray[(string) $format->type]['preview'] = bigbluebuttonbn_get_recording_preview_images($format->preview);
363
        }
364
    }
365
    // Add the metadata to the recordings array.
366
    $metadataarray = bigbluebuttonbn_get_recording_array_meta(get_object_vars($recording->metadata));
367
    $recordingarray = array('recordID' => (string) $recording->recordID,
368
        'meetingID' => (string) $recording->meetingID, 'meetingName' => (string) $recording->name,
369
        'published' => (string) $recording->published, 'startTime' => (string) $recording->startTime,
370
        'endTime' => (string) $recording->endTime, 'playbacks' => $playbackarray);
371
    if (isset($recording->protected)) {
372
        $recordingarray['protected'] = (string) $recording->protected;
373
    }
374
    return $recordingarray + $metadataarray;
375
}
376
377
/**
378
 * Helper function to convert an xml recording preview images to an array in the format used by the plugin.
379
 *
380
 * @param object $preview
381
 *
382
 * @return array
383
 */
384
function bigbluebuttonbn_get_recording_preview_images($preview) {
385
    $imagesarray = array();
386
    foreach ($preview->images->image as $image) {
387
        $imagearray = array('url' => trim((string) $image));
388
        foreach ($image->attributes() as $attkey => $attvalue) {
389
            $imagearray[$attkey] = (string) $attvalue;
390
        }
391
        array_push($imagesarray, $imagearray);
392
    }
393
    return $imagesarray;
394
}
395
396
/**
397
 * Helper function to convert an xml recording metadata object to an array in the format used by the plugin.
398
 *
399
 * @param array $metadata
400
 *
401
 * @return array
402
 */
403
function bigbluebuttonbn_get_recording_array_meta($metadata) {
404
    $metadataarray = array();
405
    foreach ($metadata as $key => $value) {
406
        if (is_object($value)) {
407
            $value = '';
408
        }
409
        $metadataarray['meta_' . $key] = $value;
410
    }
411
    return $metadataarray;
412
}
413
414
/**
415
 * Helper function to sort an array of recordings. It compares the startTime in two recording objecs.
416
 *
417
 * @param object $a
418
 * @param object $b
419
 *
420
 * @return array
421
 */
422
function bigbluebuttonbn_recording_build_sorter($a, $b) {
423
    global $CFG;
424
    $resultless = !empty($CFG->bigbluebuttonbn_recordings_sortorder) ? -1 : 1;
425
    $resultmore = !empty($CFG->bigbluebuttonbn_recordings_sortorder) ? 1 : -1;
426
    if ($a['startTime'] < $b['startTime']) {
427
        return $resultless;
428
    }
429
    if ($a['startTime'] == $b['startTime']) {
430
        return 0;
431
    }
432
    return $resultmore;
433
}
434
435
/**
436
 * Perform deleteRecordings on BBB.
437
 *
438
 * @param string $recordids
439
 *
440
 * @return boolean
441
 */
442 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...
443
    $ids = explode(',', $recordids);
444
    foreach ($ids as $id) {
445
        $xml = bigbluebuttonbn_wrap_xml_load_file(
446
            \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('deleteRecordings', ['recordID' => $id])
447
        );
448
        if ($xml && $xml->returncode != 'SUCCESS') {
449
            return false;
450
        }
451
    }
452
    return true;
453
}
454
455
/**
456
 * Perform publishRecordings on BBB.
457
 *
458
 * @param string $recordids
459
 * @param string $publish
460
 */
461 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...
462
    $ids = explode(',', $recordids);
463
    foreach ($ids as $id) {
464
        $xml = bigbluebuttonbn_wrap_xml_load_file(
465
            \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('publishRecordings', ['recordID' => $id, 'publish' => $publish])
466
        );
467
        if ($xml && $xml->returncode != 'SUCCESS') {
468
            return false;
469
        }
470
    }
471
    return true;
472
}
473
474
/**
475
 * Perform updateRecordings on BBB.
476
 *
477
 * @param string $recordids
478
 * @param array $params ['key'=>param_key, 'value']
479
 */
480 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...
481
    $ids = explode(',', $recordids);
482
    foreach ($ids as $id) {
483
        $xml = bigbluebuttonbn_wrap_xml_load_file(
484
            \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('updateRecordings', ['recordID' => $id] + (array) $params)
485
        );
486
        if ($xml && $xml->returncode != 'SUCCESS') {
487
            return false;
488
        }
489
    }
490
    return true;
491
}
492
493
/**
494
 * Perform end on BBB.
495
 *
496
 * @param string $meetingid
497
 * @param string $modpw
498
 */
499
function bigbluebuttonbn_end_meeting($meetingid, $modpw) {
500
    $xml = bigbluebuttonbn_wrap_xml_load_file(
501
        \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('end', ['meetingID' => $meetingid, 'password' => $modpw])
502
    );
503
    if ($xml) {
504
        // If the xml packet returned failure it displays the message to the user.
505
        return array('returncode' => $xml->returncode, 'message' => $xml->message, 'messageKey' => $xml->messageKey);
506
    }
507
    // If the server is unreachable, then prompts the user of the necessary action.
508
    return null;
509
}
510
511
/**
512
 * Perform api request on BBB.
513
 *
514
 * @return string
515
 */
516
function bigbluebuttonbn_get_server_version() {
517
    $xml = bigbluebuttonbn_wrap_xml_load_file(
518
        \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url()
519
    );
520
    if ($xml && $xml->returncode == 'SUCCESS') {
521
        return $xml->version;
522
    }
523
    return null;
524
}
525
526
/**
527
 * Perform api request on BBB and wraps the response in an XML object
528
 *
529
 * @param string $url
530
 * @param string $method
531
 * @param string $data
532
 * @param string $contenttype
533
 *
534
 * @return object
535
 */
536
function bigbluebuttonbn_wrap_xml_load_file($url, $method = 'GET', $data = null, $contenttype = 'text/xml') {
537
    if (extension_loaded('curl')) {
538
        $response = bigbluebuttonbn_wrap_xml_load_file_curl_request($url, $method, $data, $contenttype);
539
        if (!$response) {
540
            debugging('No response on wrap_simplexml_load_file', DEBUG_DEVELOPER);
541
            return null;
542
        }
543
        $previous = libxml_use_internal_errors(true);
544
        try {
545
            $xml = simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA | LIBXML_NOBLANKS);
546
            return $xml;
547
        } catch (Exception $e) {
548
            libxml_use_internal_errors($previous);
549
            $error = 'Caught exception: ' . $e->getMessage();
550
            debugging($error, DEBUG_DEVELOPER);
551
            return null;
552
        }
553
    }
554
    // Alternative request non CURL based.
555
    $previous = libxml_use_internal_errors(true);
556
    try {
557
        $response = simplexml_load_file($url, 'SimpleXMLElement', LIBXML_NOCDATA | LIBXML_NOBLANKS);
558
        return $response;
559
    } catch (Exception $e) {
560
        $error = 'Caught exception: ' . $e->getMessage();
561
        debugging($error, DEBUG_DEVELOPER);
562
        libxml_use_internal_errors($previous);
563
        return null;
564
    }
565
}
566
567
/**
568
 * Perform api request on BBB using CURL and wraps the response in an XML object
569
 *
570
 * @param string $url
571
 * @param string $method
572
 * @param string $data
573
 * @param string $contenttype
574
 *
575
 * @return object
576
 */
577
function bigbluebuttonbn_wrap_xml_load_file_curl_request($url, $method = 'GET', $data = null, $contenttype = 'text/xml') {
578
    $c = new curl();
579
    $c->setopt(array('SSL_VERIFYPEER' => true));
580
    if ($method == 'POST') {
581
        if (is_null($data) || is_array($data)) {
582
            return $c->post($url);
583
        }
584
        $options = array();
585
        $options['CURLOPT_HTTPHEADER'] = array(
586
            'Content-Type: ' . $contenttype,
587
            'Content-Length: ' . strlen($data),
588
            'Content-Language: en-US',
589
        );
590
591
        return $c->post($url, $data, $options);
592
    }
593
    if ($method == 'HEAD') {
594
        $c->head($url, array('followlocation' => true, 'timeout' => 1));
595
        return $c->get_info();
596
    }
597
    return $c->get($url);
598
}
599
600
/**
601
 * End the session associated with this instance (if it's running).
602
 *
603
 * @param object $bigbluebuttonbn
604
 *
605
 * @return void
606
 */
607
function bigbluebuttonbn_end_meeting_if_running($bigbluebuttonbn) {
608
    $meetingid = $bigbluebuttonbn->meetingid . '-' . $bigbluebuttonbn->course . '-' . $bigbluebuttonbn->id;
609
    if (bigbluebuttonbn_is_meeting_running($meetingid)) {
610
        bigbluebuttonbn_end_meeting($meetingid, $bigbluebuttonbn->moderatorpass);
611
    }
612
}
613
614
/**
615
 * Returns user roles in a context.
616
 *
617
 * @param object $context
618
 * @param integer $userid
619
 *
620
 * @return array $userroles
621
 */
622
function bigbluebuttonbn_get_user_roles($context, $userid) {
623
    global $DB;
624
    $userroles = get_user_roles($context, $userid);
625
    if ($userroles) {
626
        $where = '';
627
        foreach ($userroles as $userrole) {
628
            $where .= (empty($where) ? ' WHERE' : ' OR') . ' id=' . $userrole->roleid;
629
        }
630
        $userroles = $DB->get_records_sql('SELECT * FROM {role}' . $where);
631
    }
632
    return $userroles;
633
}
634
635
/**
636
 * Returns guest role wrapped in an array.
637
 *
638
 * @return array
639
 */
640
function bigbluebuttonbn_get_guest_role() {
641
    $guestrole = get_guest_role();
642
    return array($guestrole->id => $guestrole);
643
}
644
645
/**
646
 * Returns an array containing all the users in a context.
647
 *
648
 * @param context $context
649
 *
650
 * @return array $users
651
 */
652
function bigbluebuttonbn_get_users(context $context = null) {
653
    $users = (array) get_enrolled_users($context, '', 0, 'u.*', null, 0, 0, true);
654
    foreach ($users as $key => $value) {
655
        $users[$key] = fullname($value);
656
    }
657
    return $users;
658
}
659
660
/**
661
 * Returns an array containing all the users in a context wrapped for html select element.
662
 *
663
 * @param context $context
664
 *
665
 * @return array $users
666
 */
667
function bigbluebuttonbn_get_users_select(context $context = null) {
668
    $users = (array) get_enrolled_users($context, '', 0, 'u.*', null, 0, 0, true);
669
    foreach ($users as $key => $value) {
670
        $users[$key] = array('id' => $value->id, 'name' => fullname($value));
671
    }
672
    return $users;
673
}
674
675
/**
676
 * Returns an array containing all the roles in a context.
677
 *
678
 * @param context $context
679
 *
680
 * @return array $roles
681
 */
682
function bigbluebuttonbn_get_roles(context $context = null) {
683
    $roles = (array) role_get_names($context);
684
    foreach ($roles as $key => $value) {
685
        $roles[$key] = $value->localname;
686
    }
687
    return $roles;
688
}
689
690
/**
691
 * Returns an array containing all the roles in a context wrapped for html select element.
692
 *
693
 * @param context $context
694
 *
695
 * @return array $users
696
 */
697
function bigbluebuttonbn_get_roles_select(context $context = null) {
698
    $roles = (array) role_get_names($context);
699
    foreach ($roles as $key => $value) {
700
        $roles[$key] = array('id' => $value->id, 'name' => $value->localname);
701
    }
702
    return $roles;
703
}
704
705
/**
706
 * Returns role that corresponds to an id.
707
 *
708
 * @param string|integer $id
709
 *
710
 * @return object $role
711
 */
712
function bigbluebuttonbn_get_role($id) {
713
    $roles = (array) role_get_names();
714
    if (is_numeric($id) && isset($roles[$id])) {
715
        return (object) $roles[$id];
716
    }
717
    foreach ($roles as $role) {
718
        if ($role->shortname == $id) {
719
            return $role;
720
        }
721
    }
722
}
723
724
/**
725
 * Returns an array to populate a list of participants used in mod_form.js.
726
 *
727
 * @param context $context
728
 *
729
 * @return array $data
730
 */
731
function bigbluebuttonbn_get_participant_data($context) {
732
    $data = array(
733
        'all' => array(
734
            'name' => get_string('mod_form_field_participant_list_type_all', 'bigbluebuttonbn'),
735
            'children' => []
736
        ),
737
    );
738
    $data['role'] = array(
739
        'name' => get_string('mod_form_field_participant_list_type_role', 'bigbluebuttonbn'),
740
        'children' => bigbluebuttonbn_get_roles_select($context),
741
    );
742
    $data['user'] = array(
743
        'name' => get_string('mod_form_field_participant_list_type_user', 'bigbluebuttonbn'),
744
        'children' => bigbluebuttonbn_get_users_select($context),
745
    );
746
    return $data;
747
}
748
749
/**
750
 * Returns an array to populate a list of participants used in mod_form.php.
751
 *
752
 * @param object $bigbluebuttonbn
753
 * @param context $context
754
 *
755
 * @return array
756
 */
757
function bigbluebuttonbn_get_participant_list($bigbluebuttonbn, $context) {
758
    global $USER;
759
    if ($bigbluebuttonbn == null) {
760
        return bigbluebuttonbn_get_participant_rules_encoded(
761
            bigbluebuttonbn_get_participant_list_default($context, $USER->id)
762
        );
763
    }
764
    if (empty($bigbluebuttonbn->participants)) {
765
        $bigbluebuttonbn->participants = "[]";
766
    }
767
    $rules = json_decode($bigbluebuttonbn->participants, true);
768
    if (empty($rules)) {
769
        $rules = bigbluebuttonbn_get_participant_list_default($context, bigbluebuttonbn_instance_ownerid($bigbluebuttonbn));
770
    }
771
    return bigbluebuttonbn_get_participant_rules_encoded($rules);
772
}
773
774
/**
775
 * Returns an array to populate a list of participants used in mod_form.php with default values.
776
 *
777
 * @param context $context
778
 * @param integer $ownerid
779
 *
780
 * @return array
781
 */
782
function bigbluebuttonbn_get_participant_list_default($context, $ownerid = null) {
783
    $participantlist = array();
784
    $participantlist[] = array(
785
        'selectiontype' => 'all',
786
        'selectionid' => 'all',
787
        'role' => BIGBLUEBUTTONBN_ROLE_VIEWER,
788
    );
789
    $defaultrules = explode(',', \mod_bigbluebuttonbn\locallib\config::get('participant_moderator_default'));
790
    foreach ($defaultrules as $defaultrule) {
791
        if ($defaultrule == '0') {
792
            if (!empty($ownerid) && is_enrolled($context, $ownerid)) {
793
                $participantlist[] = array(
794
                    'selectiontype' => 'user',
795
                    'selectionid' => (string) $ownerid,
796
                    'role' => BIGBLUEBUTTONBN_ROLE_MODERATOR);
797
            }
798
            continue;
799
        }
800
        $participantlist[] = array(
801
            'selectiontype' => 'role',
802
            'selectionid' => $defaultrule,
803
            'role' => BIGBLUEBUTTONBN_ROLE_MODERATOR);
804
    }
805
    return $participantlist;
806
}
807
808
/**
809
 * Returns an array to populate a list of participants used in mod_form.php with bigbluebuttonbn values.
810
 *
811
 * @param array $rules
812
 *
813
 * @return array
814
 */
815
function bigbluebuttonbn_get_participant_rules_encoded($rules) {
816
    foreach ($rules as $key => $rule) {
817
        if ($rule['selectiontype'] !== 'role' || is_numeric($rule['selectionid'])) {
818
            continue;
819
        }
820
        $role = bigbluebuttonbn_get_role($rule['selectionid']);
821
        if ($role == null) {
822
            unset($rules[$key]);
823
            continue;
824
        }
825
        $rule['selectionid'] = $role->id;
826
        $rules[$key] = $rule;
827
    }
828
    return $rules;
829
}
830
831
/**
832
 * Returns an array to populate a list of participant_selection used in mod_form.php.
833
 *
834
 * @return array
835
 */
836
function bigbluebuttonbn_get_participant_selection_data() {
837
    return [
838
        'type_options' => [
839
            'all' => get_string('mod_form_field_participant_list_type_all', 'bigbluebuttonbn'),
840
            'role' => get_string('mod_form_field_participant_list_type_role', 'bigbluebuttonbn'),
841
            'user' => get_string('mod_form_field_participant_list_type_user', 'bigbluebuttonbn'),
842
        ],
843
        'type_selected' => 'all',
844
        'options' => ['all' => '---------------'],
845
        'selected' => 'all',
846
    ];
847
}
848
849
/**
850
 * Evaluate if a user in a context is moderator based on roles and participation rules.
851
 *
852
 * @param context $context
853
 * @param array $participantlist
854
 * @param integer $userid
855
 *
856
 * @return boolean
857
 */
858
function bigbluebuttonbn_is_moderator($context, $participantlist, $userid = null) {
859
    global $USER;
860
    if (!is_array($participantlist)) {
861
        return false;
862
    }
863
    if (empty($userid)) {
864
        $userid = $USER->id;
865
    }
866
    $userroles = bigbluebuttonbn_get_guest_role();
867
    if (!isguestuser()) {
868
        $userroles = bigbluebuttonbn_get_user_roles($context, $userid);
869
    }
870
    return bigbluebuttonbn_is_moderator_validator($participantlist, $userid, $userroles);
871
}
872
873
/**
874
 * Iterates participant list rules to evaluate if a user is moderator.
875
 *
876
 * @param array $participantlist
877
 * @param integer $userid
878
 * @param array $userroles
879
 *
880
 * @return boolean
881
 */
882
function bigbluebuttonbn_is_moderator_validator($participantlist, $userid, $userroles) {
883
    // Iterate participant rules.
884
    foreach ($participantlist as $participant) {
885
        if (bigbluebuttonbn_is_moderator_validate_rule($participant, $userid, $userroles)) {
886
            return true;
887
        }
888
    }
889
    return false;
890
}
891
892
/**
893
 * Evaluate if a user is moderator based on roles and a particular participation rule.
894
 *
895
 * @param object $participant
896
 * @param integer $userid
897
 * @param array $userroles
898
 *
899
 * @return boolean
900
 */
901
function bigbluebuttonbn_is_moderator_validate_rule($participant, $userid, $userroles) {
902
    if ($participant['role'] == BIGBLUEBUTTONBN_ROLE_VIEWER) {
903
        return false;
904
    }
905
    // Validation for the 'all' rule.
906
    if ($participant['selectiontype'] == 'all') {
907
        return true;
908
    }
909
    // Validation for a 'user' rule.
910
    if ($participant['selectiontype'] == 'user') {
911
        if ($participant['selectionid'] == $userid) {
912
            return true;
913
        }
914
        return false;
915
    }
916
    // Validation for a 'role' rule.
917
    $role = bigbluebuttonbn_get_role($participant['selectionid']);
918
    if ($role != null && array_key_exists($role->id, $userroles)) {
919
        return true;
920
    }
921
    return false;
922
}
923
924
/**
925
 * Helper returns error message key for the language file that corresponds to a bigbluebutton error key.
926
 *
927
 * @param string $messagekey
928
 * @param string $defaultkey
929
 *
930
 * @return string
931
 */
932
function bigbluebuttonbn_get_error_key($messagekey, $defaultkey = null) {
933
    if ($messagekey == 'checksumError') {
934
        return 'index_error_checksum';
935
    }
936
    if ($messagekey == 'maxConcurrent') {
937
        return 'view_error_max_concurrent';
938
    }
939
    return $defaultkey;
940
}
941
942
/**
943
 * Helper evaluates if a voicebridge number is unique.
944
 *
945
 * @param integer $instance
946
 * @param integer $voicebridge
947
 *
948
 * @return string
949
 */
950
function bigbluebuttonbn_voicebridge_unique($instance, $voicebridge) {
951
    global $DB;
952
    if ($voicebridge == 0) {
953
        return true;
954
    }
955
    $select = 'voicebridge = ' . $voicebridge;
956
    if ($instance != 0) {
957
        $select .= ' AND id <>' . $instance;
958
    }
959
    if (!$DB->get_records_select('bigbluebuttonbn', $select)) {
960
        return true;
961
    }
962
    return false;
963
}
964
965
/**
966
 * Helper estimate a duration for the meeting based on the closingtime.
967
 *
968
 * @param integer $closingtime
969
 *
970
 * @return integer
971
 */
972
function bigbluebuttonbn_get_duration($closingtime) {
973
    $duration = 0;
974
    $now = time();
975
    if ($closingtime > 0 && $now < $closingtime) {
976
        $duration = ceil(($closingtime - $now) / 60);
977
        $compensationtime = intval((int) \mod_bigbluebuttonbn\locallib\config::get('scheduled_duration_compensation'));
978
        $duration = intval($duration) + $compensationtime;
979
    }
980
    return $duration;
981
}
982
983
/**
984
 * Helper return array containing the file descriptor for a preuploaded presentation.
985
 *
986
 * @param context $context
987
 * @param string $presentation
988
 * @param integer $id
989
 *
990
 * @return array
991
 */
992
function bigbluebuttonbn_get_presentation_array($context, $presentation, $id = null) {
993
    global $CFG;
994
    if (empty($presentation)) {
995
        if ($CFG->bigbluebuttonbn_preuploadpresentation_enabled) {
996
            // Item has not presentation but presentation is enabled..
997
            // Check if exist some file by default in general mod setting ("presentationdefault").
998
            $fs = get_file_storage();
999
            $files = $fs->get_area_files(
1000
                context_system::instance()->id,
1001
                'mod_bigbluebuttonbn',
1002
                'presentationdefault',
1003
                0,
1004
                "filename",
1005
                false
1006
            );
1007
1008 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...
1009
                // Not exist file by default in "presentationbydefault" setting.
1010
                return array('url' => null, 'name' => null, 'icon' => null, 'mimetype_description' => null);
1011
            }
1012
1013
            // Exists file in general setting to use as default for presentation. Cache image for temp public access.
1014
            $file = reset($files);
1015
            unset($files);
1016
            $pnoncevalue = null;
1017 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...
1018
                // Create the nonce component for granting a temporary public access.
1019
                $cache = cache::make_from_params(
1020
                    cache_store::MODE_APPLICATION,
1021
                    'mod_bigbluebuttonbn',
1022
                    'presentationdefault_cache'
1023
                );
1024
                $pnoncekey = sha1(context_system::instance()->id);
1025
                /* The item id was adapted for granting public access to the presentation once in order
1026
                 * to allow BigBlueButton to gather the file. */
1027
                $pnoncevalue = bigbluebuttonbn_generate_nonce();
1028
                $cache->set($pnoncekey, array('value' => $pnoncevalue, 'counter' => 0));
1029
            }
1030
1031
            $url = moodle_url::make_pluginfile_url(
1032
                $file->get_contextid(),
1033
                $file->get_component(),
1034
                $file->get_filearea(),
1035
                $pnoncevalue,
1036
                $file->get_filepath(),
1037
                $file->get_filename()
1038
            );
1039
            return (array('name' => $file->get_filename(), 'icon' => file_file_icon($file, 24),
1040
                'url' => $url->out(false), 'mimetype_description' => get_mimetype_description($file)));
1041
        }
1042
1043
        return array('url' => null, 'name' => null, 'icon' => null, 'mimetype_description' => null);
1044
    }
1045
    $fs = get_file_storage();
1046
    $files = $fs->get_area_files(
1047
        $context->id,
1048
        'mod_bigbluebuttonbn',
1049
        'presentation',
1050
        0,
1051
        'itemid, filepath, filename',
1052
        false
1053
    );
1054 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...
1055
        return array('url' => null, 'name' => null, 'icon' => null, 'mimetype_description' => null);
1056
    }
1057
    $file = reset($files);
1058
    unset($files);
1059
    $pnoncevalue = null;
1060 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...
1061
        // Create the nonce component for granting a temporary public access.
1062
        $cache = cache::make_from_params(
1063
            cache_store::MODE_APPLICATION,
1064
            'mod_bigbluebuttonbn',
1065
            'presentation_cache'
1066
        );
1067
        $pnoncekey = sha1($id);
1068
        /* The item id was adapted for granting public access to the presentation once in order
1069
         * to allow BigBlueButton to gather the file. */
1070
        $pnoncevalue = bigbluebuttonbn_generate_nonce();
1071
        $cache->set($pnoncekey, array('value' => $pnoncevalue, 'counter' => 0));
1072
    }
1073
    $url = moodle_url::make_pluginfile_url(
1074
        $file->get_contextid(),
1075
        $file->get_component(),
1076
        $file->get_filearea(),
1077
        $pnoncevalue,
1078
        $file->get_filepath(),
1079
        $file->get_filename()
1080
    );
1081
    return array('name' => $file->get_filename(), 'icon' => file_file_icon($file, 24),
1082
        'url' => $url->out(false), 'mimetype_description' => get_mimetype_description($file));
1083
}
1084
1085
/**
1086
 * Helper generates a nonce used for the preuploaded presentation callback url.
1087
 *
1088
 * @return string
1089
 */
1090
function bigbluebuttonbn_generate_nonce() {
1091
    $mt = microtime();
1092
    $rand = mt_rand();
1093
    return md5($mt . $rand);
1094
}
1095
1096
/**
1097
 * Helper generates a random password.
1098
 *
1099
 * @param integer $length
1100
 * @param string $unique
1101
 *
1102
 * @return string
1103
 */
1104
function bigbluebuttonbn_random_password($length = 8, $unique = "") {
1105
    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_-=+;:,.?';
1106
    do {
1107
        $password = substr(str_shuffle($chars), 0, $length);
1108
    } while ($unique == $password);
1109
    return $password;
1110
}
1111
1112
/**
1113
 * Helper register a bigbluebuttonbn event.
1114
 *
1115
 * @param string $type
1116
 * @param object $bigbluebuttonbn
1117
 * @param array $options [timecreated, userid, other]
1118
 *
1119
 * @return void
1120
 */
1121
function bigbluebuttonbn_event_log($type, $bigbluebuttonbn, $options = []) {
1122
    global $DB;
1123
    if (!in_array($type, \mod_bigbluebuttonbn\event\events::$events)) {
1124
        // No log will be created.
1125
        return;
1126
    }
1127
    $course = $DB->get_record('course', array('id' => $bigbluebuttonbn->course), '*', MUST_EXIST);
1128
    $cm = get_coursemodule_from_instance('bigbluebuttonbn', $bigbluebuttonbn->id, $course->id, false, MUST_EXIST);
1129
    $context = context_module::instance($cm->id);
1130
    $params = array('context' => $context, 'objectid' => $bigbluebuttonbn->id);
1131
    if (array_key_exists('timecreated', $options)) {
1132
        $params['timecreated'] = $options['timecreated'];
1133
    }
1134
    if (array_key_exists('userid', $options)) {
1135
        $params['userid'] = $options['userid'];
1136
    }
1137
    if (array_key_exists('other', $options)) {
1138
        $params['other'] = $options['other'];
1139
    }
1140
    $event = call_user_func_array(
1141
        '\mod_bigbluebuttonbn\event\\' . $type . '::create',
1142
        array($params)
1143
    );
1144
    $event->add_record_snapshot('course_modules', $cm);
1145
    $event->add_record_snapshot('course', $course);
1146
    $event->add_record_snapshot('bigbluebuttonbn', $bigbluebuttonbn);
1147
    $event->trigger();
1148
}
1149
1150
/**
1151
 * Updates the meeting info cached object when a participant has joined.
1152
 *
1153
 * @param string $meetingid
1154
 * @param bool $ismoderator
1155
 *
1156
 * @return void
1157
 */
1158
function bigbluebuttonbn_participant_joined($meetingid, $ismoderator) {
1159
    $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'mod_bigbluebuttonbn', 'meetings_cache');
1160
    $result = $cache->get($meetingid);
1161
    $meetinginfo = json_decode($result['meeting_info']);
1162
    $meetinginfo->participantCount += 1;
1163
    if ($ismoderator) {
1164
        $meetinginfo->moderatorCount += 1;
1165
    }
1166
    $cache->set($meetingid, array('creation_time' => $result['creation_time'],
1167
        'meeting_info' => json_encode($meetinginfo)));
1168
}
1169
1170
/**
1171
 * Gets a meeting info object cached or fetched from the live session.
1172
 *
1173
 * @param string $meetingid
1174
 * @param boolean $updatecache
1175
 *
1176
 * @return array
1177
 */
1178
function bigbluebuttonbn_get_meeting_info($meetingid, $updatecache = false) {
1179
    $cachettl = (int) \mod_bigbluebuttonbn\locallib\config::get('waitformoderator_cache_ttl');
1180
    $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'mod_bigbluebuttonbn', 'meetings_cache');
1181
    $result = $cache->get($meetingid);
1182
    $now = time();
1183
    if (!$updatecache && isset($result) && $now < ($result['creation_time'] + $cachettl)) {
1184
        // Use the value in the cache.
1185
        return (array) json_decode($result['meeting_info']);
1186
    }
1187
    // Ping again and refresh the cache.
1188
    $meetinginfo = (array) bigbluebuttonbn_wrap_xml_load_file(
1189
        \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('getMeetingInfo', ['meetingID' => $meetingid])
1190
    );
1191
    $cache->set($meetingid, array('creation_time' => time(), 'meeting_info' => json_encode($meetinginfo)));
1192
    return $meetinginfo;
1193
}
1194
1195
/**
1196
 * Perform isMeetingRunning on BBB.
1197
 *
1198
 * @param string $meetingid
1199
 * @param boolean $updatecache
1200
 *
1201
 * @return boolean
1202
 */
1203
function bigbluebuttonbn_is_meeting_running($meetingid, $updatecache = false) {
1204
    /* As a workaround to isMeetingRunning that always return SUCCESS but only returns true
1205
     * when at least one user is in the session, we use getMeetingInfo instead.
1206
     */
1207
    $meetinginfo = bigbluebuttonbn_get_meeting_info($meetingid, $updatecache);
1208
    return ($meetinginfo['returncode'] === 'SUCCESS');
1209
}
1210
1211
/**
1212
 * Publish an imported recording.
1213
 *
1214
 * @param string $id
1215
 * @param boolean $publish
1216
 *
1217
 * @return boolean
1218
 */
1219 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...
1220
    global $DB;
1221
    // Locate the record to be updated.
1222
    $record = $DB->get_record('bigbluebuttonbn_logs', array('id' => $id));
1223
    $meta = json_decode($record->meta, true);
1224
    // Prepare data for the update.
1225
    $meta['recording']['published'] = ($publish) ? 'true' : 'false';
1226
    $record->meta = json_encode($meta);
1227
    // Proceed with the update.
1228
    $DB->update_record('bigbluebuttonbn_logs', $record);
1229
    return true;
1230
}
1231
1232
/**
1233
 * Delete an imported recording.
1234
 *
1235
 * @param string $id
1236
 *
1237
 * @return boolean
1238
 */
1239
function bigbluebuttonbn_delete_recording_imported($id) {
1240
    global $DB;
1241
    // Execute delete.
1242
    $DB->delete_records('bigbluebuttonbn_logs', array('id' => $id));
1243
    return true;
1244
}
1245
1246
/**
1247
 * Update an imported recording.
1248
 *
1249
 * @param string $id
1250
 * @param array $params ['key'=>param_key, 'value']
1251
 *
1252
 * @return boolean
1253
 */
1254
function bigbluebuttonbn_update_recording_imported($id, $params) {
1255
    global $DB;
1256
    // Locate the record to be updated.
1257
    $record = $DB->get_record('bigbluebuttonbn_logs', array('id' => $id));
1258
    $meta = json_decode($record->meta, true);
1259
    // Prepare data for the update.
1260
    $meta['recording'] = $params + $meta['recording'];
1261
    $record->meta = json_encode($meta);
1262
    // Proceed with the update.
1263
    if (!$DB->update_record('bigbluebuttonbn_logs', $record)) {
1264
        return false;
1265
    }
1266
    return true;
1267
}
1268
1269
/**
1270
 * Protect/Unprotect an imported recording.
1271
 *
1272
 * @param string $id
1273
 * @param boolean $protect
1274
 *
1275
 * @return boolean
1276
 */
1277 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...
1278
    global $DB;
1279
    // Locate the record to be updated.
1280
    $record = $DB->get_record('bigbluebuttonbn_logs', array('id' => $id));
1281
    $meta = json_decode($record->meta, true);
1282
    // Prepare data for the update.
1283
    $meta['recording']['protected'] = ($protect) ? 'true' : 'false';
1284
    $record->meta = json_encode($meta);
1285
    // Proceed with the update.
1286
    $DB->update_record('bigbluebuttonbn_logs', $record);
1287
    return true;
1288
}
1289
1290
/**
1291
 * Sets a custom config.xml file for being used on create.
1292
 *
1293
 * @param string $meetingid
1294
 * @param string $configxml
1295
 *
1296
 * @return object
1297
 */
1298
function bigbluebuttonbn_set_config_xml($meetingid, $configxml) {
1299
    $urldefaultconfig = \mod_bigbluebuttonbn\locallib\config::get('server_url') . 'api/setConfigXML?';
1300
    $configxmlparams = bigbluebuttonbn_set_config_xml_params($meetingid, $configxml);
1301
    $xml = bigbluebuttonbn_wrap_xml_load_file(
1302
        $urldefaultconfig,
1303
        'POST',
1304
        $configxmlparams,
1305
        'application/x-www-form-urlencoded'
1306
    );
1307
    return $xml;
1308
}
1309
1310
/**
1311
 * Sets qs used with a custom config.xml file request.
1312
 *
1313
 * @param string $meetingid
1314
 * @param string $configxml
1315
 *
1316
 * @return string
1317
 */
1318
function bigbluebuttonbn_set_config_xml_params($meetingid, $configxml) {
1319
    $params = 'configXML=' . urlencode($configxml) . '&meetingID=' . urlencode($meetingid);
1320
    $sharedsecret = \mod_bigbluebuttonbn\locallib\config::get('shared_secret');
1321
    $configxmlparams = $params . '&checksum=' . sha1('setConfigXML' . $params . $sharedsecret);
1322
    return $configxmlparams;
1323
}
1324
1325
/**
1326
 * Sets a custom config.xml file for being used on create.
1327
 *
1328
 * @param string $meetingid
1329
 * @param string $configxml
1330
 *
1331
 * @return array
1332
 */
1333
function bigbluebuttonbn_set_config_xml_array($meetingid, $configxml) {
1334
    $configxml = bigbluebuttonbn_setConfigXML($meetingid, $configxml);
1335
    $configxmlarray = (array) $configxml;
1336
    if ($configxmlarray['returncode'] != 'SUCCESS') {
1337
        debugging('BigBlueButton was not able to set the custom config.xml file', DEBUG_DEVELOPER);
1338
        return '';
1339
    }
1340
    return $configxmlarray['configToken'];
1341
}
1342
1343
/**
1344
 * Helper function builds a row for the data used by the recording table.
1345
 *
1346
 * @param array $bbbsession
1347
 * @param array $recording
1348
 * @param array $tools
1349
 *
1350
 * @return array
1351
 */
1352
function bigbluebuttonbn_get_recording_data_row($bbbsession, $recording, $tools = ['protect', 'publish', 'delete']) {
1353
    if (!bigbluebuttonbn_include_recording_table_row($bbbsession, $recording)) {
1354
        return;
1355
    }
1356
    $rowdata = new stdClass();
1357
    // Set recording_types.
1358
    $rowdata->recording = bigbluebuttonbn_get_recording_data_row_types($recording, $bbbsession);
1359
    // Set meeting name.
1360
    $rowdata->meeting = bigbluebuttonbn_get_recording_data_row_meeting($recording, $bbbsession);
1361
    // Set activity name.
1362
    $rowdata->activity = bigbluebuttonbn_get_recording_data_row_meta_activity($recording, $bbbsession);
1363
    // Set activity description.
1364
    $rowdata->description = bigbluebuttonbn_get_recording_data_row_meta_description($recording, $bbbsession);
1365
    if (bigbluebuttonbn_get_recording_data_preview_enabled($bbbsession)) {
1366
        // Set recording_preview.
1367
        $rowdata->preview = bigbluebuttonbn_get_recording_data_row_preview($recording);
1368
    }
1369
    // Set date.
1370
    $rowdata->date = bigbluebuttonbn_get_recording_data_row_date($recording);
1371
    // Set formatted date.
1372
    $rowdata->date_formatted = bigbluebuttonbn_get_recording_data_row_date_formatted($rowdata->date);
1373
    // Set formatted duration.
1374
    $rowdata->duration_formatted = $rowdata->duration = bigbluebuttonbn_get_recording_data_row_duration($recording);
1375
    // Set actionbar, if user is allowed to manage recordings.
1376
    if ($bbbsession['managerecordings']) {
1377
        $rowdata->actionbar = bigbluebuttonbn_get_recording_data_row_actionbar($recording, $tools);
1378
    }
1379
    return $rowdata;
1380
}
1381
1382
/**
1383
 * Helper function evaluates if a row for the data used by the recording table is editable.
1384
 *
1385
 * @param array $bbbsession
1386
 *
1387
 * @return boolean
1388
 */
1389
function bigbluebuttonbn_get_recording_data_row_editable($bbbsession) {
1390
    return ($bbbsession['managerecordings'] && ((double) $bbbsession['serverversion'] >= 1.0 || $bbbsession['bnserver']));
1391
}
1392
1393
/**
1394
 * Helper function evaluates if recording preview should be included.
1395
 *
1396
 * @param array $bbbsession
1397
 *
1398
 * @return boolean
1399
 */
1400
function bigbluebuttonbn_get_recording_data_preview_enabled($bbbsession) {
1401
    return ((double) $bbbsession['serverversion'] >= 1.0 && $bbbsession['bigbluebuttonbn']->recordings_preview == '1');
1402
}
1403
1404
/**
1405
 * Helper function converts recording date used in row for the data used by the recording table.
1406
 *
1407
 * @param array $recording
1408
 *
1409
 * @return integer
1410
 */
1411
function bigbluebuttonbn_get_recording_data_row_date($recording) {
1412
    if (!isset($recording['startTime'])) {
1413
        return 0;
1414
    }
1415
    return floatval($recording['startTime']);
1416
}
1417
1418
/**
1419
 * Helper function format recording date used in row for the data used by the recording table.
1420
 *
1421
 * @param integer $starttime
1422
 *
1423
 * @return string
1424
 */
1425
function bigbluebuttonbn_get_recording_data_row_date_formatted($starttime) {
1426
    global $USER;
1427
    $starttime = $starttime - ($starttime % 1000);
1428
    // Set formatted date.
1429
    $dateformat = get_string('strftimerecentfull', 'langconfig') . ' %Z';
1430
    return userdate($starttime / 1000, $dateformat, usertimezone($USER->timezone));
1431
}
1432
1433
/**
1434
 * Helper function converts recording duration used in row for the data used by the recording table.
1435
 *
1436
 * @param array $recording
1437
 *
1438
 * @return integer
1439
 */
1440
function bigbluebuttonbn_get_recording_data_row_duration($recording) {
1441
    foreach (array_values($recording['playbacks']) as $playback) {
1442
        // Ignore restricted playbacks.
1443
        if (array_key_exists('restricted', $playback) && strtolower($playback['restricted']) == 'true') {
1444
            continue;
1445
        }
1446
        // Take the lenght form the fist playback with an actual value.
1447
        if (!empty($playback['length'])) {
1448
            return intval($playback['length']);
1449
        }
1450
    }
1451
    return 0;
1452
}
1453
1454
/**
1455
 * Helper function builds recording actionbar used in row for the data used by the recording table.
1456
 *
1457
 * @param array $recording
1458
 * @param array $tools
1459
 *
1460
 * @return string
1461
 */
1462
function bigbluebuttonbn_get_recording_data_row_actionbar($recording, $tools) {
1463
    $actionbar = '';
1464
    foreach ($tools as $tool) {
1465
        $buttonpayload = bigbluebuttonbn_get_recording_data_row_actionbar_payload($recording, $tool);
1466
        if ($tool == 'protect') {
1467
            if (isset($recording['imported'])) {
1468
                $buttonpayload['disabled'] = 'disabled';
1469
            }
1470
            if (!isset($recording['protected'])) {
1471
                $buttonpayload['disabled'] = 'invisible';
1472
            }
1473
        }
1474
        $actionbar .= bigbluebuttonbn_actionbar_render_button($recording, $buttonpayload);
1475
    }
1476
    $head = html_writer::start_tag('div', array(
1477
        'id' => 'recording-actionbar-' . $recording['recordID'],
1478
        'data-recordingid' => $recording['recordID'],
1479
        'data-meetingid' => $recording['meetingID']));
1480
    $tail = html_writer::end_tag('div');
1481
    return $head . $actionbar . $tail;
1482
}
1483
1484
/**
1485
 * Helper function returns the corresponding payload for an actionbar button used in row
1486
 * for the data used by the recording table.
1487
 *
1488
 * @param array $recording
1489
 * @param array $tool
1490
 *
1491
 * @return array
1492
 */
1493
function bigbluebuttonbn_get_recording_data_row_actionbar_payload($recording, $tool) {
1494
    if ($tool == 'protect') {
1495
        $protected = 'false';
1496
        if (isset($recording['protected'])) {
1497
            $protected = $recording['protected'];
1498
        }
1499
        return bigbluebuttonbn_get_recording_data_row_action_protect($protected);
1500
    }
1501
    if ($tool == 'publish') {
1502
        return bigbluebuttonbn_get_recording_data_row_action_publish($recording['published']);
1503
    }
1504
    return array('action' => $tool, 'tag' => $tool);
1505
}
1506
1507
/**
1508
 * Helper function returns the payload for protect action button used in row
1509
 * for the data used by the recording table.
1510
 *
1511
 * @param string $protected
1512
 *
1513
 * @return array
1514
 */
1515
function bigbluebuttonbn_get_recording_data_row_action_protect($protected) {
1516
    if ($protected == 'true') {
1517
        return array('action' => 'unprotect', 'tag' => 'lock');
1518
    }
1519
    return array('action' => 'protect', 'tag' => 'unlock');
1520
}
1521
1522
/**
1523
 * Helper function returns the payload for publish action button used in row
1524
 * for the data used by the recording table.
1525
 *
1526
 * @param string $published
1527
 *
1528
 * @return array
1529
 */
1530
function bigbluebuttonbn_get_recording_data_row_action_publish($published) {
1531
    if ($published == 'true') {
1532
        return array('action' => 'unpublish', 'tag' => 'hide');
1533
    }
1534
    return array('action' => 'publish', 'tag' => 'show');
1535
}
1536
1537
/**
1538
 * Helper function builds recording preview used in row for the data used by the recording table.
1539
 *
1540
 * @param array $recording
1541
 *
1542
 * @return string
1543
 */
1544
function bigbluebuttonbn_get_recording_data_row_preview($recording) {
1545
    $options = array('id' => 'preview-' . $recording['recordID']);
1546
    if ($recording['published'] === 'false') {
1547
        $options['hidden'] = 'hidden';
1548
    }
1549
    $recordingpreview = html_writer::start_tag('div', $options);
1550
    foreach ($recording['playbacks'] as $playback) {
1551
        if (isset($playback['preview'])) {
1552
            $recordingpreview .= bigbluebuttonbn_get_recording_data_row_preview_images($playback);
1553
            break;
1554
        }
1555
    }
1556
    $recordingpreview .= html_writer::end_tag('div');
1557
    return $recordingpreview;
1558
}
1559
1560
/**
1561
 * Helper function builds element with actual images used in recording preview row based on a selected playback.
1562
 *
1563
 * @param array $playback
1564
 *
1565
 * @return string
1566
 */
1567
function bigbluebuttonbn_get_recording_data_row_preview_images($playback) {
1568
    $recordingpreview = html_writer::start_tag('div', array('class' => 'container-fluid'));
1569
    $recordingpreview .= html_writer::start_tag('div', array('class' => 'row'));
1570
    foreach ($playback['preview'] as $image) {
1571
        if (!bigbluebuttonbn_is_valid_resource(trim($image['url']))) {
1572
            return '';
1573
        }
1574
        $recordingpreview .= html_writer::start_tag('div', array('class' => ''));
1575
        $recordingpreview .= html_writer::empty_tag(
1576
            'img',
1577
            array('src' => trim($image['url']) . '?' . time(), 'class' => 'recording-thumbnail pull-left')
1578
        );
1579
        $recordingpreview .= html_writer::end_tag('div');
1580
    }
1581
    $recordingpreview .= html_writer::end_tag('div');
1582
    $recordingpreview .= html_writer::start_tag('div', array('class' => 'row'));
1583
    $recordingpreview .= html_writer::tag(
1584
        'div',
1585
        get_string('view_recording_preview_help', 'bigbluebuttonbn'),
1586
        array('class' => 'text-center text-muted small')
1587
    );
1588
    $recordingpreview .= html_writer::end_tag('div');
1589
    $recordingpreview .= html_writer::end_tag('div');
1590
    return $recordingpreview;
1591
}
1592
1593
/**
1594
 * Helper function renders recording types to be used in row for the data used by the recording table.
1595
 *
1596
 * @param array $recording
1597
 * @param array $bbbsession
1598
 *
1599
 * @return string
1600
 */
1601
function bigbluebuttonbn_get_recording_data_row_types($recording, $bbbsession) {
1602
    $dataimported = 'false';
1603
    $title = '';
1604
    if (isset($recording['imported'])) {
1605
        $dataimported = 'true';
1606
        $title = get_string('view_recording_link_warning', 'bigbluebuttonbn');
1607
    }
1608
    $visibility = '';
1609
    if ($recording['published'] === 'false') {
1610
        $visibility = 'hidden ';
1611
    }
1612
    $id = 'playbacks-' . $recording['recordID'];
1613
    $recordingtypes = html_writer::start_tag('div', array('id' => $id, 'data-imported' => $dataimported,
1614
        'data-meetingid' => $recording['meetingID'], 'data-recordingid' => $recording['recordID'],
1615
        'title' => $title, $visibility => $visibility));
1616
    foreach ($recording['playbacks'] as $playback) {
1617
        $recordingtypes .= bigbluebuttonbn_get_recording_data_row_type($recording, $bbbsession, $playback);
1618
    }
1619
    $recordingtypes .= html_writer::end_tag('div');
1620
    return $recordingtypes;
1621
}
1622
1623
/**
1624
 * Helper function renders the link used for recording type in row for the data used by the recording table.
1625
 *
1626
 * @param array $recording
1627
 * @param array $bbbsession
1628
 * @param array $playback
1629
 *
1630
 * @return string
1631
 */
1632
function bigbluebuttonbn_get_recording_data_row_type($recording, $bbbsession, $playback) {
1633
    global $CFG, $OUTPUT;
1634
    if (!bigbluebuttonbn_include_recording_data_row_type($recording, $bbbsession, $playback)) {
1635
        return '';
1636
    }
1637
    $text = get_string('view_recording_format_' . $playback['type'], 'bigbluebuttonbn');
1638
    $href = $CFG->wwwroot . '/mod/bigbluebuttonbn/bbb_view.php?action=play&bn=' . $bbbsession['bigbluebuttonbn']->id .
1639
        '&mid=' . $recording['meetingID'] . '&rid=' . $recording['recordID'] . '&rtype=' . $playback['type'];
1640
    if (!isset($recording['imported']) || !isset($recording['protected']) || $recording['protected'] === 'false') {
1641
        $href .= '&href=' . urlencode(trim($playback['url']));
1642
    }
1643
    $linkattributes = array(
1644
        'id' => 'recording-play-' . $playback['type'] . '-' . $recording['recordID'],
1645
        'class' => 'btn btn-sm btn-default',
1646
        'onclick' => 'M.mod_bigbluebuttonbn.recordings.recordingPlay(this);',
1647
        'data-action' => 'play',
1648
        'data-target' => $playback['type'],
1649
        'data-href' => $href,
1650
    );
1651
    if (!bigbluebuttonbn_is_bn_server() && !bigbluebuttonbn_is_valid_resource(trim($playback['url']))) {
1652
        $linkattributes['class'] = 'btn btn-sm btn-warning';
1653
        $linkattributes['title'] = get_string('view_recording_format_errror_unreachable', 'bigbluebuttonbn');
1654
        unset($linkattributes['data-href']);
1655
    }
1656
    return $OUTPUT->action_link('#', $text, null, $linkattributes) . '&#32;';
1657
}
1658
1659
/**
1660
 * Helper function validates a remote resource.
1661
 *
1662
 * @param string $url
1663
 *
1664
 * @return boolean
1665
 */
1666
function bigbluebuttonbn_is_valid_resource($url) {
1667
    $urlhost = parse_url($url, PHP_URL_HOST);
1668
    $serverurlhost = parse_url(\mod_bigbluebuttonbn\locallib\config::get('server_url'), PHP_URL_HOST);
1669
    // Skip validation when the recording URL host is the same as the configured BBB server.
1670
    if ($urlhost == $serverurlhost) {
1671
        return true;
1672
    }
1673
    // Skip validation when the recording URL was already validated.
1674
    $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...
1675
    if (array_key_exists($urlhost, $validatedurls)) {
1676
        return $validatedurls[$urlhost];
1677
    }
1678
    // Validate the recording URL.
1679
    $validatedurls[$urlhost] = true;
1680
    $curlinfo = bigbluebuttonbn_wrap_xml_load_file_curl_request($url, 'HEAD');
1681
    if (!isset($curlinfo['http_code']) || $curlinfo['http_code'] != 200) {
1682
        $error = "Resources hosted by " . $urlhost . " are unreachable. Server responded with code " . $curlinfo['http_code'];
1683
        debugging($error, DEBUG_DEVELOPER);
1684
        $validatedurls[$urlhost] = false;
1685
    }
1686
    bigbluebuttonbn_cache_set('recordings_cache', 'validated_urls', $validatedurls);
1687
    return $validatedurls[$urlhost];
1688
}
1689
1690
/**
1691
 * Helper function renders the name for meeting used in row for the data used by the recording table.
1692
 *
1693
 * @param array $recording
1694
 * @param array $bbbsession
1695
 *
1696
 * @return string
1697
 */
1698
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...
1699
    $payload = array();
1700
    $source = 'meetingName';
1701
    $metaname = trim($recording['meetingName']);
1702
    return bigbluebuttonbn_get_recording_data_row_text($recording, $metaname, $source, $payload);
1703
}
1704
1705
/**
1706
 * Helper function renders the name for recording used in row for the data used by the recording table.
1707
 *
1708
 * @param array $recording
1709
 * @param array $bbbsession
1710
 *
1711
 * @return string
1712
 */
1713
function bigbluebuttonbn_get_recording_data_row_meta_activity($recording, $bbbsession) {
1714
    $payload = array();
1715 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...
1716
        $payload = array('recordingid' => $recording['recordID'], 'meetingid' => $recording['meetingID'],
1717
            'action' => 'edit', 'tag' => 'edit',
1718
            'target' => 'name');
1719
    }
1720
    $oldsource = 'meta_contextactivity';
1721
    if (isset($recording[$oldsource])) {
1722
        $metaname = trim($recording[$oldsource]);
1723
        return bigbluebuttonbn_get_recording_data_row_text($recording, $metaname, $oldsource, $payload);
1724
    }
1725
    $newsource = 'meta_bbb-recording-name';
1726 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...
1727
        $metaname = trim($recording[$newsource]);
1728
        return bigbluebuttonbn_get_recording_data_row_text($recording, $metaname, $newsource, $payload);
1729
    }
1730
    $metaname = trim($recording['meetingName']);
1731
    return bigbluebuttonbn_get_recording_data_row_text($recording, $metaname, $newsource, $payload);
1732
}
1733
1734
/**
1735
 * Helper function renders the description for recording used in row for the data used by the recording table.
1736
 *
1737
 * @param array $recording
1738
 * @param array $bbbsession
1739
 *
1740
 * @return string
1741
 */
1742
function bigbluebuttonbn_get_recording_data_row_meta_description($recording, $bbbsession) {
1743
    $payload = array();
1744 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...
1745
        $payload = array('recordingid' => $recording['recordID'], 'meetingid' => $recording['meetingID'],
1746
            'action' => 'edit', 'tag' => 'edit',
1747
            'target' => 'description');
1748
    }
1749
    $oldsource = 'meta_contextactivitydescription';
1750 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...
1751
        $metadescription = trim($recording[$oldsource]);
1752
        return bigbluebuttonbn_get_recording_data_row_text($recording, $metadescription, $oldsource, $payload);
1753
    }
1754
    $newsource = 'meta_bbb-recording-description';
1755 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...
1756
        $metadescription = trim($recording[$newsource]);
1757
        return bigbluebuttonbn_get_recording_data_row_text($recording, $metadescription, $newsource, $payload);
1758
    }
1759
    return bigbluebuttonbn_get_recording_data_row_text($recording, '', $newsource, $payload);
1760
}
1761
1762
/**
1763
 * Helper function renders text element for recording used in row for the data used by the recording table.
1764
 *
1765
 * @param array $recording
1766
 * @param string $text
1767
 * @param string $source
1768
 * @param array $data
1769
 *
1770
 * @return string
1771
 */
1772
function bigbluebuttonbn_get_recording_data_row_text($recording, $text, $source, $data) {
1773
    $htmltext = '<span>' . htmlentities($text) . '</span>';
1774
    if (empty($data)) {
1775
        return $htmltext;
1776
    }
1777
    $target = $data['action'] . '-' . $data['target'];
1778
    $id = 'recording-' . $target . '-' . $data['recordingid'];
1779
    $attributes = array('id' => $id, 'class' => 'quickeditlink col-md-20',
1780
        'data-recordingid' => $data['recordingid'], 'data-meetingid' => $data['meetingid'],
1781
        'data-target' => $data['target'], 'data-source' => $source);
1782
    $head = html_writer::start_tag('div', $attributes);
1783
    $tail = html_writer::end_tag('div');
1784
    $payload = array('action' => $data['action'], 'tag' => $data['tag'], 'target' => $data['target']);
1785
    $htmllink = bigbluebuttonbn_actionbar_render_button($recording, $payload);
1786
    return $head . $htmltext . $htmllink . $tail;
1787
}
1788
1789
/**
1790
 * Helper function render a button for the recording action bar
1791
 *
1792
 * @param array $recording
1793
 * @param array $data
1794
 *
1795
 * @return string
1796
 */
1797
function bigbluebuttonbn_actionbar_render_button($recording, $data) {
1798
    global $OUTPUT;
1799
    if (empty($data)) {
1800
        return '';
1801
    }
1802
    $target = $data['action'];
1803
    if (isset($data['target'])) {
1804
        $target .= '-' . $data['target'];
1805
    }
1806
    $id = 'recording-' . $target . '-' . $recording['recordID'];
1807
    $onclick = 'M.mod_bigbluebuttonbn.recordings.recording' . ucfirst($data['action']) . '(this);';
1808
    if ((boolean) \mod_bigbluebuttonbn\locallib\config::get('recording_icons_enabled')) {
1809
        // With icon for $manageaction.
1810
        $iconattributes = array('id' => $id, 'class' => 'iconsmall');
1811
        $linkattributes = array(
1812
            'id' => $id,
1813
            'onclick' => $onclick,
1814
            'data-action' => $data['action'],
1815
        );
1816
        if (!isset($recording['imported'])) {
1817
            $linkattributes['data-links'] = bigbluebuttonbn_count_recording_imported_instances(
1818
                $recording['recordID']
1819
            );
1820
        }
1821
        if (isset($data['disabled'])) {
1822
            $iconattributes['class'] .= ' fa-' . $data['disabled'];
1823
            $linkattributes['class'] = 'disabled';
1824
            unset($linkattributes['onclick']);
1825
        }
1826
        $icon = new pix_icon(
1827
            'i/' . $data['tag'],
1828
            get_string('view_recording_list_actionbar_' . $data['action'], 'bigbluebuttonbn'),
1829
            'moodle',
1830
            $iconattributes
1831
        );
1832
        return $OUTPUT->action_icon('#', $icon, null, $linkattributes, false);
1833
    }
1834
    // With text for $manageaction.
1835
    $linkattributes = array('title' => get_string($data['tag']), 'class' => 'btn btn-xs btn-danger',
1836
        'onclick' => $onclick);
1837
    return $OUTPUT->action_link('#', get_string($data['action']), null, $linkattributes);
1838
}
1839
1840
/**
1841
 * Helper function builds the data used for headers by the recording table.
1842
 *
1843
 * @param array $bbbsession
1844
 *
1845
 * @return array
1846
 */
1847
function bigbluebuttonbn_get_recording_columns($bbbsession) {
1848
    $columns = array();
1849
    // Initialize table headers.
1850
    $columns[] = array('key' => 'recording', 'label' => get_string('view_recording_recording', 'bigbluebuttonbn'),
1851
        'width' => '125px', 'allowHTML' => true);
1852
    $columns[] = array('key' => 'meeting', 'label' => get_string('view_recording_meeting', 'bigbluebuttonbn'),
1853
        'sortable' => true, 'width' => '175px', 'allowHTML' => true);
1854
    $columns[] = array('key' => 'activity', 'label' => get_string('view_recording_activity', 'bigbluebuttonbn'),
1855
        'sortable' => true, 'width' => '175px', 'allowHTML' => true);
1856
    $columns[] = array('key' => 'description', 'label' => get_string('view_recording_description', 'bigbluebuttonbn'),
1857
        'sortable' => true, 'width' => '250px', 'allowHTML' => true);
1858
    if (bigbluebuttonbn_get_recording_data_preview_enabled($bbbsession)) {
1859
        $columns[] = array('key' => 'preview', 'label' => get_string('view_recording_preview', 'bigbluebuttonbn'),
1860
            'width' => '250px', 'allowHTML' => true);
1861
    }
1862
    $columns[] = array('key' => 'date', 'label' => get_string('view_recording_date', 'bigbluebuttonbn'),
1863
        'sortable' => true, 'width' => '225px', 'allowHTML' => true);
1864
    $columns[] = array('key' => 'duration', 'label' => get_string('view_recording_duration', 'bigbluebuttonbn'),
1865
        'width' => '50px');
1866
    if ($bbbsession['managerecordings']) {
1867
        $columns[] = array('key' => 'actionbar', 'label' => get_string('view_recording_actionbar', 'bigbluebuttonbn'),
1868
            'width' => '120px', 'allowHTML' => true);
1869
    }
1870
    return $columns;
1871
}
1872
1873
/**
1874
 * Helper function builds the data used by the recording table.
1875
 *
1876
 * @param array $bbbsession
1877
 * @param array $recordings
1878
 * @param array $tools
1879
 *
1880
 * @return array
1881
 */
1882
function bigbluebuttonbn_get_recording_data($bbbsession, $recordings, $tools = ['protect', 'publish', 'delete']) {
1883
    $tabledata = array();
1884
    // Build table content.
1885
    if (isset($recordings) && !array_key_exists('messageKey', $recordings)) {
1886
        // There are recordings for this meeting.
1887
        foreach ($recordings as $recording) {
1888
            $rowdata = bigbluebuttonbn_get_recording_data_row($bbbsession, $recording, $tools);
1889
            if (!empty($rowdata)) {
1890
                array_push($tabledata, $rowdata);
1891
            }
1892
        }
1893
    }
1894
    return $tabledata;
1895
}
1896
1897
/**
1898
 * Helper function builds the recording table.
1899
 *
1900
 * @param array $bbbsession
1901
 * @param array $recordings
1902
 * @param array $tools
1903
 *
1904
 * @return object
1905
 */
1906
function bigbluebuttonbn_get_recording_table($bbbsession, $recordings, $tools = ['protect', 'publish', 'delete']) {
1907
    global $DB;
1908
    // Declare the table.
1909
    $table = new html_table();
1910
    $table->data = array();
1911
    // Initialize table headers.
1912
    $table->head[] = get_string('view_recording_playback', 'bigbluebuttonbn');
1913
    $table->head[] = get_string('view_recording_meeting', 'bigbluebuttonbn');
1914
    $table->head[] = get_string('view_recording_recording', 'bigbluebuttonbn');
1915
    $table->head[] = get_string('view_recording_description', 'bigbluebuttonbn');
1916
    if (bigbluebuttonbn_get_recording_data_preview_enabled($bbbsession)) {
1917
        $table->head[] = get_string('view_recording_preview', 'bigbluebuttonbn');
1918
    }
1919
    $table->head[] = get_string('view_recording_date', 'bigbluebuttonbn');
1920
    $table->head[] = get_string('view_recording_duration', 'bigbluebuttonbn');
1921
    $table->align = array('left', 'left', 'left', 'left', 'left', 'center');
1922
    $table->size = array('', '', '', '', '', '');
1923
    if ($bbbsession['managerecordings']) {
1924
        $table->head[] = get_string('view_recording_actionbar', 'bigbluebuttonbn');
1925
        $table->align[] = 'left';
1926
        $table->size[] = (count($tools) * 40) . 'px';
1927
    }
1928
    // Get the groups of the user.
1929
    $usergroups = groups_get_all_groups($bbbsession['course']->id, $bbbsession['userID']);
1930
1931
    // Build table content.
1932
    foreach ($recordings as $recording) {
1933
        $meetingid = $recording['meetingID'];
1934
        $shortmeetingid = explode('-', $recording['meetingID']);
1935
        if (isset($shortmeetingid[0])) {
1936
            $meetingid = $shortmeetingid[0];
1937
        }
1938
        // Check if the record belongs to a Visible Group type.
1939
        $sql = "SELECT bigbluebuttonbn.id, cm.id, cm.groupmode
1940
                 FROM {bigbluebuttonbn} bigbluebuttonbn
1941
                 JOIN {modules} m
1942
                   ON m.name = :bigbluebuttonbn
1943
                 JOIN {course_modules} cm
1944
                   ON cm.instance = bigbluebuttonbn.id
1945
                  AND cm.module = m.id
1946
                WHERE bigbluebuttonbn.meetingid = :meetingid";
1947
        $params = array('bigbluebuttonbn' => 'bigbluebuttonbn', 'meetingid' => $meetingid);
1948
1949
        $groupmode = $DB->get_record_sql($sql, $params, IGNORE_MULTIPLE);
1950
1951
        $displayrow = true;
1952
        if ((isset($groupmode->groupmode) && (int) $groupmode->groupmode != VISIBLEGROUPS)
1953
            && !$bbbsession['administrator'] && !$bbbsession['moderator']) {
1954
            $groupid = explode('[', $recording['meetingID']);
1955
            if (isset($groupid[1])) {
1956
                // It is a group recording and the user is not moderator/administrator. Recording should not be included by default.
1957
                $displayrow = false;
1958
                $groupid = explode(']', $groupid[1]);
1959
                if (isset($groupid[0])) {
1960
                    foreach ($usergroups as $usergroup) {
1961
                        if ($usergroup->id == $groupid[0]) {
1962
                            // Include recording if the user is in the same group.
1963
                            $displayrow = true;
1964
                        }
1965
                    }
1966
                }
1967
            }
1968
        }
1969
        if ($displayrow) {
1970
            $rowdata = bigbluebuttonbn_get_recording_data_row($bbbsession, $recording, $tools);
1971
            if (!empty($rowdata)) {
1972
                $row = bigbluebuttonbn_get_recording_table_row($bbbsession, $recording, $rowdata);
1973
                array_push($table->data, $row);
1974
            }
1975
        }
1976
    }
1977
    return $table;
1978
}
1979
1980
/**
1981
 * Helper function builds the recording table row and insert into table.
1982
 *
1983
 * @param array $bbbsession
1984
 * @param array $recording
1985
 * @param object $rowdata
1986
 *
1987
 * @return object
1988
 */
1989
function bigbluebuttonbn_get_recording_table_row($bbbsession, $recording, $rowdata) {
1990
    $row = new html_table_row();
1991
    $row->id = 'recording-tr-' . $recording['recordID'];
1992
    $row->attributes['data-imported'] = 'false';
1993
    $texthead = '';
1994
    $texttail = '';
1995
    if (isset($recording['imported'])) {
1996
        $row->attributes['title'] = get_string('view_recording_link_warning', 'bigbluebuttonbn');
1997
        $row->attributes['data-imported'] = 'true';
1998
        $texthead = '<em>';
1999
        $texttail = '</em>';
2000
    }
2001
    $rowdata->date_formatted = str_replace(' ', '&nbsp;', $rowdata->date_formatted);
2002
    $row->cells = array();
2003
    $row->cells[] = $texthead . $rowdata->recording . $texttail;
2004
    $row->cells[] = $texthead . $rowdata->meeting . $texttail;
2005
2006
    $row->cells[] = $texthead . $rowdata->activity . $texttail;
2007
    $row->cells[] = $texthead . $rowdata->description . $texttail;
2008
    if (bigbluebuttonbn_get_recording_data_preview_enabled($bbbsession)) {
2009
        $row->cells[] = $rowdata->preview;
2010
    }
2011
    $row->cells[] = $texthead . $rowdata->date_formatted . $texttail;
2012
    $row->cells[] = $rowdata->duration_formatted;
2013
    if ($bbbsession['managerecordings']) {
2014
        $row->cells[] = $rowdata->actionbar;
2015
    }
2016
    return $row;
2017
}
2018
2019
/**
2020
 * Helper function evaluates if recording row should be included in the table.
2021
 *
2022
 * @param array $bbbsession
2023
 * @param array $recording
2024
 *
2025
 * @return boolean
2026
 */
2027
function bigbluebuttonbn_include_recording_table_row($bbbsession, $recording) {
2028
    // Exclude unpublished recordings, only if user has no rights to manage them.
2029
    if ($recording['published'] != 'true' && !$bbbsession['managerecordings']) {
2030
        return false;
2031
    }
2032
    // Imported recordings are always shown as long as they are published.
2033
    if (isset($recording['imported'])) {
2034
        return true;
2035
    }
2036
    // When groups are enabled, exclude those to which the user doesn't have access to.
2037
    if (isset($bbbsession['group']) && $recording['meetingID'] != $bbbsession['meetingid']) {
2038
        return false;
2039
    }
2040
    return true;
2041
}
2042
2043
/**
2044
 * Helper function triggers a send notification when the recording is ready.
2045
 *
2046
 * @param object $bigbluebuttonbn
2047
 *
2048
 * @return void
2049
 */
2050
function bigbluebuttonbn_send_notification_recording_ready($bigbluebuttonbn) {
2051
    \mod_bigbluebuttonbn\locallib\notifier::notify_recording_ready($bigbluebuttonbn);
2052
}
2053
2054
/**
2055
 * Helper function enqueues list of meeting events to be stored and processed as for completion.
2056
 *
2057
 * @param object $bigbluebuttonbn
2058
 * @param object $jsonobj
2059
 *
2060
 * @return void
2061
 */
2062
function bigbluebuttonbn_process_meeting_events($bigbluebuttonbn, $jsonobj) {
2063
    $meetingid = $jsonobj->{'meeting_id'};
2064
    $recordid = $jsonobj->{'internal_meeting_id'};
2065
    $attendees = $jsonobj->{'data'}->{'attendees'};
2066
    foreach ($attendees as $attendee) {
2067
        $userid = $attendee->{'ext_user_id'};
2068
        $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...
2069
        $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...
2070
        $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...
2071
        $meta['data'] = $attendee;
2072
        // Stores the log.
2073
        bigbluebuttonbn_log($bigbluebuttonbn, BIGBLUEBUTTON_LOG_EVENT_SUMMARY, $overrides, json_encode($meta));
2074
        // Enqueue a task for processing the completion.
2075
        bigbluebuttonbn_enqueue_completion_update($bigbluebuttonbn, $userid);
2076
    }
2077
}
2078
2079
/**
2080
 * Helper function enqueues one user for being validated as for completion.
2081
 *
2082
 * @param object $bigbluebuttonbn
2083
 * @param string $userid
2084
 *
2085
 * @return void
2086
 */
2087
function bigbluebuttonbn_enqueue_completion_update($bigbluebuttonbn, $userid) {
2088
    try {
2089
        // Create the instance of completion_update_state task.
2090
        $task = new \mod_bigbluebuttonbn\task\completion_update_state();
2091
        // Add custom data.
2092
        $data = array(
2093
            'bigbluebuttonbn' => $bigbluebuttonbn,
2094
            'userid' => $userid,
2095
        );
2096
        $task->set_custom_data($data);
2097
        // CONTRIB-7457: Task should be executed by a user, maybe Teacher as Student won't have rights for overriding.
2098
        // $ task -> set_userid ( $ user -> id );.
2099
        // Enqueue it.
2100
        \core\task\manager::queue_adhoc_task($task);
2101
    } catch (Exception $e) {
2102
        mtrace("Error while enqueuing completion_update_state task. " . (string) $e);
2103
    }
2104
}
2105
2106
/**
2107
 * Helper function enqueues completion trigger.
2108
 *
2109
 * @param object $bigbluebuttonbn
2110
 * @param string $userid
2111
 *
2112
 * @return void
2113
 */
2114
function bigbluebuttonbn_completion_update_state($bigbluebuttonbn, $userid) {
2115
    list($course, $cm) = get_course_and_cm_from_instance($bigbluebuttonbn, 'bigbluebuttonbn');
2116
    $completion = new completion_info($course);
2117
    if (!$completion->is_enabled($cm)) {
2118
        mtrace("Completion not enabled");
2119
        return;
2120
    }
2121
    if (!$bigbluebuttonbn->completionattendance) {
2122
        mtrace("Completion by attendance not enabled");
2123
        return;
2124
    }
2125
    if (bigbluebuttonbn_get_completion_state($course, $cm, $userid, COMPLETION_AND)) {
2126
        mtrace("Completion succeeded for user $userid");
2127
        $completion->update_state($cm, COMPLETION_COMPLETE, $userid, true);
2128
    } else {
2129
        mtrace("Completion did not succeed for user $userid");
2130
    }
2131
}
2132
2133
/**
2134
 * Helper evaluates if the bigbluebutton server used belongs to blindsidenetworks domain.
2135
 *
2136
 * @return boolean
2137
 */
2138
function bigbluebuttonbn_is_bn_server() {
2139
    if (\mod_bigbluebuttonbn\locallib\config::get('bn_server')) {
2140
        return true;
2141
    }
2142
    $parsedurl = parse_url(\mod_bigbluebuttonbn\locallib\config::get('server_url'));
2143
    if (!isset($parsedurl['host'])) {
2144
        return false;
2145
    }
2146
    $h = $parsedurl['host'];
2147
    $hends = explode('.', $h);
2148
    $hendslength = count($hends);
2149
    return ($hends[$hendslength - 1] == 'com' && $hends[$hendslength - 2] == 'blindsidenetworks');
2150
}
2151
2152
/**
2153
 * Helper function returns a list of courses a user has access to, wrapped in an array that can be used
2154
 * by a html select.
2155
 *
2156
 * @param array $bbbsession
2157
 *
2158
 * @return array
2159
 */
2160
function bigbluebuttonbn_import_get_courses_for_select(array $bbbsession) {
2161
    if ($bbbsession['administrator']) {
2162
        $courses = get_courses('all', 'c.fullname ASC');
2163
        // It includes the name of the site as a course (category 0), so remove the first one.
2164
        unset($courses['1']);
2165
    } else {
2166
        $courses = enrol_get_users_courses($bbbsession['userID'], false, 'id,shortname,fullname');
2167
    }
2168
    $coursesforselect = [];
2169
    foreach ($courses as $course) {
2170
        $coursesforselect[$course->id] = $course->fullname;
2171
    }
2172
    return $coursesforselect;
2173
}
2174
2175
/**
2176
 * Helper function renders recording table.
2177
 *
2178
 * @param array $bbbsession
2179
 * @param array $recordings
2180
 * @param array $tools
2181
 *
2182
 * @return array
2183
 */
2184
function bigbluebuttonbn_output_recording_table($bbbsession, $recordings, $tools = ['protect', 'publish', 'delete']) {
2185
    if (isset($recordings) && !empty($recordings)) {
2186
        // There are recordings for this meeting.
2187
        $table = bigbluebuttonbn_get_recording_table($bbbsession, $recordings, $tools);
2188
    }
2189
    if (!isset($table) || !isset($table->data)) {
2190
        // Render a table with "No recordings".
2191
        return html_writer::div(
2192
            get_string('view_message_norecordings', 'bigbluebuttonbn'),
2193
            '',
2194
            array('id' => 'bigbluebuttonbn_recordings_table')
2195
        );
2196
    }
2197
    // Render the table.
2198
    return html_writer::div(html_writer::table($table), '', array('id' => 'bigbluebuttonbn_recordings_table'));
2199
}
2200
2201
/**
2202
 * Helper function to convert an html string to plain text.
2203
 *
2204
 * @param string $html
2205
 * @param integer $len
2206
 *
2207
 * @return string
2208
 */
2209
function bigbluebuttonbn_html2text($html, $len = 0) {
2210
    $text = strip_tags($html);
2211
    $text = str_replace('&nbsp;', ' ', $text);
2212
    $textlen = strlen($text);
2213
    $text = substr($text, 0, $len);
2214
    if ($textlen > $len) {
2215
        $text .= '...';
2216
    }
2217
    return $text;
2218
}
2219
2220
/**
2221
 * Helper function to obtain the tags linked to a bigbluebuttonbn activity
2222
 *
2223
 * @param string $id
2224
 *
2225
 * @return string containing the tags separated by commas
2226
 */
2227
function bigbluebuttonbn_get_tags($id) {
2228
    if (class_exists('core_tag_tag')) {
2229
        return implode(',', core_tag_tag::get_item_tags_array('core', 'course_modules', $id));
2230
    }
2231
    return implode(',', tag_get_tags('bigbluebuttonbn', $id));
2232
}
2233
2234
/**
2235
 * Helper function to define the sql used for gattering the bigbluebuttonbnids whose meetingids should be included
2236
 * in the getRecordings request
2237
 *
2238
 * @param string $courseid
2239
 * @param string $bigbluebuttonbnid
2240
 * @param bool   $subset
2241
 *
2242
 * @return string containing the sql used for getting the target bigbluebuttonbn instances
2243
 */
2244
function bigbluebuttonbn_get_recordings_sql_select($courseid, $bigbluebuttonbnid = null, $subset = true) {
2245
    if (empty($courseid)) {
2246
        $courseid = 0;
2247
    }
2248
    if (empty($bigbluebuttonbnid)) {
2249
        return "course = '{$courseid}'";
2250
    }
2251
    if ($subset) {
2252
        return "id = '{$bigbluebuttonbnid}'";
2253
    }
2254
    return "id <> '{$bigbluebuttonbnid}' AND course = '{$courseid}'";
2255
}
2256
2257
/**
2258
 * Helper function to define the sql used for gattering the bigbluebuttonbnids whose meetingids should be included
2259
 * in the getRecordings request considering only those that belong to deleted activities.
2260
 *
2261
 * @param string $courseid
2262
 * @param string $bigbluebuttonbnid
2263
 * @param bool   $subset
2264
 *
2265
 * @return string containing the sql used for getting the target bigbluebuttonbn instances
2266
 */
2267 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...
2268
    $sql = "log = '" . BIGBLUEBUTTONBN_LOG_EVENT_DELETE . "' AND meta like '%has_recordings%' AND meta like '%true%'";
2269
    if (empty($courseid)) {
2270
        $courseid = 0;
2271
    }
2272
    if (empty($bigbluebuttonbnid)) {
2273
        return $sql . " AND courseid = {$courseid}";
2274
    }
2275
    if ($subset) {
2276
        return $sql . " AND bigbluebuttonbnid = '{$bigbluebuttonbnid}'";
2277
    }
2278
    return $sql . " AND courseid = {$courseid} AND bigbluebuttonbnid <> '{$bigbluebuttonbnid}'";
2279
}
2280
2281
/**
2282
 * Helper function to define the sql used for gattering the bigbluebuttonbnids whose meetingids should be included
2283
 * in the getRecordings request considering only those that belong to imported recordings.
2284
 *
2285
 * @param string $courseid
2286
 * @param string $bigbluebuttonbnid
2287
 * @param bool   $subset
2288
 *
2289
 * @return string containing the sql used for getting the target bigbluebuttonbn instances
2290
 */
2291 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...
2292
    $sql = "log = '" . BIGBLUEBUTTONBN_LOG_EVENT_IMPORT . "'";
2293
    if (empty($courseid)) {
2294
        $courseid = 0;
2295
    }
2296
    if (empty($bigbluebuttonbnid)) {
2297
        return $sql . " AND courseid = '{$courseid}'";
2298
    }
2299
    if ($subset) {
2300
        return $sql . " AND bigbluebuttonbnid = '{$bigbluebuttonbnid}'";
2301
    }
2302
    return $sql . " AND courseid = '{$courseid}' AND bigbluebuttonbnid <> '{$bigbluebuttonbnid}'";
2303
}
2304
2305
/**
2306
 * Helper function to get recordings and imported recordings together.
2307
 *
2308
 * @param string $courseid
2309
 * @param string $bigbluebuttonbnid
2310
 * @param bool   $subset
2311
 * @param bool   $includedeleted
2312
 *
2313
 * @return associative array containing the recordings indexed by recordID, each recording is also a
2314
 * non sequential associative array itself that corresponds to the actual recording in BBB
2315
 */
2316
function bigbluebuttonbn_get_allrecordings($courseid = 0, $bigbluebuttonbnid = null, $subset = true, $includedeleted = false) {
2317
    $recordings = bigbluebuttonbn_get_recordings($courseid, $bigbluebuttonbnid, $subset, $includedeleted);
2318
    $recordingsimported = bigbluebuttonbn_get_recordings_imported_array($courseid, $bigbluebuttonbnid, $subset);
2319
    return ($recordings + $recordingsimported);
2320
}
2321
2322
/**
2323
 * Helper function to retrieve recordings from the BigBlueButton. The references are stored as events
2324
 * in bigbluebuttonbn_logs.
2325
 *
2326
 * @param string $courseid
2327
 * @param string $bigbluebuttonbnid
2328
 * @param bool   $subset
2329
 * @param bool   $includedeleted
2330
 *
2331
 * @return associative array containing the recordings indexed by recordID, each recording is also a
2332
 * non sequential associative array itself that corresponds to the actual recording in BBB
2333
 */
2334
function bigbluebuttonbn_get_recordings($courseid = 0, $bigbluebuttonbnid = null, $subset = true, $includedeleted = false) {
2335
    global $DB;
2336
    $select = bigbluebuttonbn_get_recordings_sql_select($courseid, $bigbluebuttonbnid, $subset);
2337
    $bigbluebuttonbns = $DB->get_records_select_menu('bigbluebuttonbn', $select, null, 'id', 'id, meetingid');
2338
    /* Consider logs from deleted bigbluebuttonbn instances whose meetingids should be included in
2339
     * the getRecordings request. */
2340
    if ($includedeleted) {
2341
        $selectdeleted = bigbluebuttonbn_get_recordings_deleted_sql_select($courseid, $bigbluebuttonbnid, $subset);
2342
        $bigbluebuttonbnsdel = $DB->get_records_select_menu(
2343
            'bigbluebuttonbn_logs',
2344
            $selectdeleted,
2345
            null,
2346
            'bigbluebuttonbnid',
2347
            'bigbluebuttonbnid, meetingid'
2348
        );
2349
        if (!empty($bigbluebuttonbnsdel)) {
2350
            // Merge bigbluebuttonbnis from deleted instances, only keys are relevant.
2351
            // Artimetic merge is used in order to keep the keys.
2352
            $bigbluebuttonbns += $bigbluebuttonbnsdel;
2353
        }
2354
    }
2355
    // Gather the meetingids from bigbluebuttonbn logs that include a create with record=true.
2356
    if (empty($bigbluebuttonbns)) {
2357
        return array();
2358
    }
2359
    // Prepare select for loading records based on existent bigbluebuttonbns.
2360
    $sql = 'SELECT DISTINCT meetingid, bigbluebuttonbnid FROM {bigbluebuttonbn_logs} WHERE ';
2361
    $sql .= '(bigbluebuttonbnid=' . implode(' OR bigbluebuttonbnid=', array_keys($bigbluebuttonbns)) . ')';
2362
    // Include only Create events and exclude those with record not true.
2363
    $sql .= ' AND log = ? AND meta LIKE ? AND meta LIKE ?';
2364
    // Execute select for loading records based on existent bigbluebuttonbns.
2365
    $records = $DB->get_records_sql_menu($sql, array(BIGBLUEBUTTONBN_LOG_EVENT_CREATE, '%record%', '%true%'));
2366
    // Get actual recordings.
2367
    return bigbluebuttonbn_get_recordings_array(array_keys($records));
2368
}
2369
2370
/**
2371
 * Helper function iterates an array with recordings and unset those already imported.
2372
 *
2373
 * @param array $recordings
2374
 * @param integer $courseid
2375
 * @param integer $bigbluebuttonbnid
2376
 *
2377
 * @return array
2378
 */
2379
function bigbluebuttonbn_unset_existent_recordings_already_imported($recordings, $courseid, $bigbluebuttonbnid) {
2380
    $recordingsimported = bigbluebuttonbn_get_recordings_imported_array($courseid, $bigbluebuttonbnid, true);
2381
    foreach ($recordings as $key => $recording) {
2382
        if (isset($recordingsimported[$recording['recordID']])) {
2383
            unset($recordings[$key]);
2384
        }
2385
    }
2386
    return $recordings;
2387
}
2388
2389
/**
2390
 * Helper function to count the imported recordings for a recordingid.
2391
 *
2392
 * @param string $recordid
2393
 *
2394
 * @return integer
2395
 */
2396
function bigbluebuttonbn_count_recording_imported_instances($recordid) {
2397
    global $DB;
2398
    $sql = 'SELECT COUNT(DISTINCT id) FROM {bigbluebuttonbn_logs} WHERE log = ? AND meta LIKE ? AND meta LIKE ?';
2399
    return $DB->count_records_sql($sql, array(BIGBLUEBUTTONBN_LOG_EVENT_IMPORT, '%recordID%', "%{$recordid}%"));
2400
}
2401
2402
/**
2403
 * Helper function returns an array with all the instances of imported recordings for a recordingid.
2404
 *
2405
 * @param string $recordid
2406
 *
2407
 * @return array
2408
 */
2409
function bigbluebuttonbn_get_recording_imported_instances($recordid) {
2410
    global $DB;
2411
    $sql = 'SELECT * FROM {bigbluebuttonbn_logs} WHERE log = ? AND meta LIKE ? AND meta LIKE ?';
2412
    $recordingsimported = $DB->get_records_sql($sql, array(BIGBLUEBUTTONBN_LOG_EVENT_IMPORT, '%recordID%',
2413
        "%{$recordid}%"));
2414
    return $recordingsimported;
2415
}
2416
2417
/**
2418
 * Helper function to get how much callback events are logged.
2419
 *
2420
 * @param string $recordid
2421
 * @param string $callbacktype
2422
 *
2423
 * @return integer
2424
 */
2425
function bigbluebuttonbn_get_count_callback_event_log($recordid, $callbacktype = 'recording_ready') {
2426
    global $DB;
2427
    $sql = 'SELECT count(DISTINCT id) FROM {bigbluebuttonbn_logs} WHERE log = ? AND meta LIKE ? AND meta LIKE ?';
2428
    // Callback type added on version 2.4, validate recording_ready first or assume it on records with no callback.
2429
    if ($callbacktype == 'recording_ready') {
2430
        $sql .= ' AND (meta LIKE ? OR meta NOT LIKE ? )';
2431
        $count = $DB->count_records_sql($sql, array(BIGBLUEBUTTON_LOG_EVENT_CALLBACK, '%recordid%', "%$recordid%",
2432
            $callbacktype, 'callback'));
2433
        return $count;
2434
    }
2435
    $sql .= ' AND meta LIKE ?;';
2436
    $count = $DB->count_records_sql($sql, array(BIGBLUEBUTTON_LOG_EVENT_CALLBACK, '%recordid%', "%$recordid%", "%$callbacktype%"));
2437
    return $count;
2438
}
2439
2440
/**
2441
 * Helper function returns an array with the profiles (with features per profile) for the different types
2442
 * of bigbluebuttonbn instances.
2443
 *
2444
 * @return array
2445
 */
2446
function bigbluebuttonbn_get_instance_type_profiles() {
2447
    $instanceprofiles = array(
2448
        BIGBLUEBUTTONBN_TYPE_ALL => array('id' => BIGBLUEBUTTONBN_TYPE_ALL,
2449
            'name' => get_string('instance_type_default', 'bigbluebuttonbn'),
2450
            'features' => array('all')),
2451
        BIGBLUEBUTTONBN_TYPE_ROOM_ONLY => array('id' => BIGBLUEBUTTONBN_TYPE_ROOM_ONLY,
2452
            'name' => get_string('instance_type_room_only', 'bigbluebuttonbn'),
2453
            'features' => array('showroom', 'welcomemessage', 'voicebridge', 'waitformoderator', 'userlimit',
2454
                'recording', 'sendnotifications', 'preuploadpresentation', 'permissions', 'schedule', 'groups',
2455
                'modstandardelshdr', 'availabilityconditionsheader', 'tagshdr', 'competenciessection',
2456
                'clienttype', 'completionattendance', 'completionengagement')),
2457
        BIGBLUEBUTTONBN_TYPE_RECORDING_ONLY => array('id' => BIGBLUEBUTTONBN_TYPE_RECORDING_ONLY,
2458
            'name' => get_string('instance_type_recording_only', 'bigbluebuttonbn'),
2459
            'features' => array('showrecordings', 'importrecordings')),
2460
    );
2461
    return $instanceprofiles;
2462
}
2463
2464
/**
2465
 * Helper function returns an array with enabled features for an specific profile type.
2466
 *
2467
 * @param array $typeprofiles
2468
 * @param string $type
2469
 *
2470
 * @return array
2471
 */
2472
function bigbluebuttonbn_get_enabled_features($typeprofiles, $type = null) {
2473
    $enabledfeatures = array();
2474
    $features = $typeprofiles[BIGBLUEBUTTONBN_TYPE_ALL]['features'];
2475
    if (!is_null($type) && key_exists($type, $typeprofiles)) {
2476
        $features = $typeprofiles[$type]['features'];
2477
    }
2478
    $enabledfeatures['showroom'] = (in_array('all', $features) || in_array('showroom', $features));
2479
    // Evaluates if recordings are enabled for the Moodle site.
2480
    $enabledfeatures['showrecordings'] = false;
2481
    if (\mod_bigbluebuttonbn\locallib\config::recordings_enabled()) {
2482
        $enabledfeatures['showrecordings'] = (in_array('all', $features) || in_array('showrecordings', $features));
2483
    }
2484
    $enabledfeatures['importrecordings'] = false;
2485
    if (\mod_bigbluebuttonbn\locallib\config::importrecordings_enabled()) {
2486
        $enabledfeatures['importrecordings'] = (in_array('all', $features) || in_array('importrecordings', $features));
2487
    }
2488
    // Evaluates if clienttype is enabled for the Moodle site.
2489
    $enabledfeatures['clienttype'] = false;
2490
    if (\mod_bigbluebuttonbn\locallib\config::clienttype_enabled()) {
2491
        $enabledfeatures['clienttype'] = (in_array('all', $features) || in_array('clienttype', $features));
2492
    }
2493
    return $enabledfeatures;
2494
}
2495
2496
/**
2497
 * Helper function returns an array with the profiles (with features per profile) for the different types
2498
 * of bigbluebuttonbn instances that the user is allowed to create.
2499
 *
2500
 * @param boolean $room
2501
 * @param boolean $recording
2502
 *
2503
 * @return array
2504
 */
2505
function bigbluebuttonbn_get_instance_type_profiles_create_allowed($room, $recording) {
2506
    $profiles = bigbluebuttonbn_get_instance_type_profiles();
2507
    if (!$room) {
2508
        unset($profiles[BIGBLUEBUTTONBN_TYPE_ROOM_ONLY]);
2509
        unset($profiles[BIGBLUEBUTTONBN_TYPE_ALL]);
2510
    }
2511
    if (!$recording) {
2512
        unset($profiles[BIGBLUEBUTTONBN_TYPE_RECORDING_ONLY]);
2513
        unset($profiles[BIGBLUEBUTTONBN_TYPE_ALL]);
2514
    }
2515
    return $profiles;
2516
}
2517
2518
/**
2519
 * Helper function returns an array with the profiles (with features per profile) for the different types
2520
 * of bigbluebuttonbn instances.
2521
 *
2522
 * @param array $profiles
2523
 *
2524
 * @return array
2525
 */
2526
function bigbluebuttonbn_get_instance_profiles_array($profiles = []) {
2527
    $profilesarray = array();
2528
    foreach ($profiles as $key => $profile) {
2529
        $profilesarray[$profile['id']] = $profile['name'];
2530
    }
2531
    return $profilesarray;
2532
}
2533
2534
/**
2535
 * Helper function returns time in a formatted string.
2536
 *
2537
 * @param integer $time
2538
 *
2539
 * @return string
2540
 */
2541
function bigbluebuttonbn_format_activity_time($time) {
2542
    $activitytime = '';
2543
    if ($time) {
2544
        $activitytime = calendar_day_representation($time) . ' ' .
2545
        get_string('mod_form_field_notification_msg_at', 'bigbluebuttonbn') . ' ' .
2546
        calendar_time_representation($time);
2547
    }
2548
    return $activitytime;
2549
}
2550
2551
/**
2552
 * Helper function returns array with all the strings to be used in javascript.
2553
 *
2554
 * @return array
2555
 */
2556
function bigbluebuttonbn_get_strings_for_js() {
2557
    $locale = bigbluebuttonbn_get_locale();
2558
    $stringman = get_string_manager();
2559
    $strings = $stringman->load_component_strings('bigbluebuttonbn', $locale);
2560
    return $strings;
2561
}
2562
2563
/**
2564
 * Helper function returns the locale set by moodle.
2565
 *
2566
 * @return string
2567
 */
2568
function bigbluebuttonbn_get_locale() {
2569
    $lang = get_string('locale', 'core_langconfig');
2570
    return substr($lang, 0, strpos($lang, '.'));
2571
}
2572
2573
/**
2574
 * Helper function returns the locale code based on the locale set by moodle.
2575
 *
2576
 * @return string
2577
 */
2578
function bigbluebuttonbn_get_localcode() {
2579
    $locale = bigbluebuttonbn_get_locale();
2580
    return substr($locale, 0, strpos($locale, '_'));
2581
}
2582
2583
/**
2584
 * Helper function returns array with the instance settings used in views.
2585
 *
2586
 * @param string $id
2587
 * @param object $bigbluebuttonbnid
2588
 *
2589
 * @return array
2590
 */
2591
function bigbluebuttonbn_view_validator($id, $bigbluebuttonbnid) {
2592
    if ($id) {
2593
        return bigbluebuttonbn_view_instance_id($id);
2594
    }
2595
    if ($bigbluebuttonbnid) {
2596
        return bigbluebuttonbn_view_instance_bigbluebuttonbn($bigbluebuttonbnid);
2597
    }
2598
}
2599
2600
/**
2601
 * Helper function returns array with the instance settings used in views based on id.
2602
 *
2603
 * @param string $id
2604
 *
2605
 * @return array
2606
 */
2607 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...
2608
    global $DB;
2609
    $cm = get_coursemodule_from_id('bigbluebuttonbn', $id, 0, false, MUST_EXIST);
2610
    $course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
2611
    $bigbluebuttonbn = $DB->get_record('bigbluebuttonbn', array('id' => $cm->instance), '*', MUST_EXIST);
2612
    return array('cm' => $cm, 'course' => $course, 'bigbluebuttonbn' => $bigbluebuttonbn);
2613
}
2614
2615
/**
2616
 * Helper function returns array with the instance settings used in views based on bigbluebuttonbnid.
2617
 *
2618
 * @param object $bigbluebuttonbnid
2619
 *
2620
 * @return array
2621
 */
2622 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...
2623
    global $DB;
2624
    $bigbluebuttonbn = $DB->get_record('bigbluebuttonbn', array('id' => $bigbluebuttonbnid), '*', MUST_EXIST);
2625
    $course = $DB->get_record('course', array('id' => $bigbluebuttonbn->course), '*', MUST_EXIST);
2626
    $cm = get_coursemodule_from_instance('bigbluebuttonbn', $bigbluebuttonbn->id, $course->id, false, MUST_EXIST);
2627
    return array('cm' => $cm, 'course' => $course, 'bigbluebuttonbn' => $bigbluebuttonbn);
2628
}
2629
2630
/**
2631
 * Helper function renders general settings if the feature is enabled.
2632
 *
2633
 * @param object $renderer
2634
 *
2635
 * @return void
2636
 */
2637
function bigbluebuttonbn_settings_general(&$renderer) {
2638
    // Configuration for BigBlueButton.
2639
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_general_shown()) {
2640
        $renderer->render_group_header('general');
2641
        $renderer->render_group_element(
2642
            'server_url',
2643
            $renderer->render_group_element_text('server_url', BIGBLUEBUTTONBN_DEFAULT_SERVER_URL)
2644
        );
2645
        $renderer->render_group_element(
2646
            'shared_secret',
2647
            $renderer->render_group_element_text('shared_secret', BIGBLUEBUTTONBN_DEFAULT_SHARED_SECRET)
2648
        );
2649
    }
2650
}
2651
2652
/**
2653
 * Helper function renders record settings if the feature is enabled.
2654
 *
2655
 * @param object $renderer
2656
 *
2657
 * @return void
2658
 */
2659
function bigbluebuttonbn_settings_record(&$renderer) {
2660
    // Configuration for 'recording' feature.
2661
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_record_meeting_shown()) {
2662
        $renderer->render_group_header('recording');
2663
        $renderer->render_group_element(
2664
            'recording_default',
2665
            $renderer->render_group_element_checkbox('recording_default', 1)
2666
        );
2667
        $renderer->render_group_element(
2668
            'recording_editable',
2669
            $renderer->render_group_element_checkbox('recording_editable', 1)
2670
        );
2671
        $renderer->render_group_element(
2672
            'recording_icons_enabled',
2673
            $renderer->render_group_element_checkbox('recording_icons_enabled', 1)
2674
        );
2675
2676
        // Add recording start to load and allow/hide stop/pause.
2677
        $renderer->render_group_element(
2678
            'recording_all_from_start_default',
2679
            $renderer->render_group_element_checkbox('recording_all_from_start_default', 0)
2680
        );
2681
        $renderer->render_group_element(
2682
            'recording_all_from_start_editable',
2683
            $renderer->render_group_element_checkbox('recording_all_from_start_editable', 0)
2684
        );
2685
        $renderer->render_group_element(
2686
            'recording_hide_button_default',
2687
            $renderer->render_group_element_checkbox('recording_hide_button_default', 0)
2688
        );
2689
        $renderer->render_group_element(
2690
            'recording_hide_button_editable',
2691
            $renderer->render_group_element_checkbox('recording_hide_button_editable', 0)
2692
        );
2693
    }
2694
}
2695
2696
/**
2697
 * Helper function renders import recording settings if the feature is enabled.
2698
 *
2699
 * @param object $renderer
2700
 *
2701
 * @return void
2702
 */
2703 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...
2704
    // Configuration for 'import recordings' feature.
2705
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_import_recordings_shown()) {
2706
        $renderer->render_group_header('importrecordings');
2707
        $renderer->render_group_element(
2708
            'importrecordings_enabled',
2709
            $renderer->render_group_element_checkbox('importrecordings_enabled', 0)
2710
        );
2711
        $renderer->render_group_element(
2712
            'importrecordings_from_deleted_enabled',
2713
            $renderer->render_group_element_checkbox('importrecordings_from_deleted_enabled', 0)
2714
        );
2715
    }
2716
}
2717
2718
/**
2719
 * Helper function renders show recording settings if the feature is enabled.
2720
 *
2721
 * @param object $renderer
2722
 *
2723
 * @return void
2724
 */
2725
function bigbluebuttonbn_settings_showrecordings(&$renderer) {
2726
    // Configuration for 'show recordings' feature.
2727
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_show_recordings_shown()) {
2728
        $renderer->render_group_header('recordings');
2729
        $renderer->render_group_element(
2730
            'recordings_html_default',
2731
            $renderer->render_group_element_checkbox('recordings_html_default', 1)
2732
        );
2733
        $renderer->render_group_element(
2734
            'recordings_html_editable',
2735
            $renderer->render_group_element_checkbox('recordings_html_editable', 0)
2736
        );
2737
        $renderer->render_group_element(
2738
            'recordings_deleted_default',
2739
            $renderer->render_group_element_checkbox('recordings_deleted_default', 1)
2740
        );
2741
        $renderer->render_group_element(
2742
            'recordings_deleted_editable',
2743
            $renderer->render_group_element_checkbox('recordings_deleted_editable', 0)
2744
        );
2745
        $renderer->render_group_element(
2746
            'recordings_imported_default',
2747
            $renderer->render_group_element_checkbox('recordings_imported_default', 0)
2748
        );
2749
        $renderer->render_group_element(
2750
            'recordings_imported_editable',
2751
            $renderer->render_group_element_checkbox('recordings_imported_editable', 1)
2752
        );
2753
        $renderer->render_group_element(
2754
            'recordings_preview_default',
2755
            $renderer->render_group_element_checkbox('recordings_preview_default', 1)
2756
        );
2757
        $renderer->render_group_element(
2758
            'recordings_preview_editable',
2759
            $renderer->render_group_element_checkbox('recordings_preview_editable', 0)
2760
        );
2761
        $renderer->render_group_element(
2762
            'recordings_sortorder',
2763
            $renderer->render_group_element_checkbox('recordings_sortorder', 0)
2764
        );
2765
    }
2766
}
2767
2768
/**
2769
 * Helper function renders wait for moderator settings if the feature is enabled.
2770
 *
2771
 * @param object $renderer
2772
 *
2773
 * @return void
2774
 */
2775
function bigbluebuttonbn_settings_waitmoderator(&$renderer) {
2776
    // Configuration for wait for moderator feature.
2777
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_wait_moderator_shown()) {
2778
        $renderer->render_group_header('waitformoderator');
2779
        $renderer->render_group_element(
2780
            'waitformoderator_default',
2781
            $renderer->render_group_element_checkbox('waitformoderator_default', 0)
2782
        );
2783
        $renderer->render_group_element(
2784
            'waitformoderator_editable',
2785
            $renderer->render_group_element_checkbox('waitformoderator_editable', 1)
2786
        );
2787
        $renderer->render_group_element(
2788
            'waitformoderator_ping_interval',
2789
            $renderer->render_group_element_text('waitformoderator_ping_interval', 10, PARAM_INT)
2790
        );
2791
        $renderer->render_group_element(
2792
            'waitformoderator_cache_ttl',
2793
            $renderer->render_group_element_text('waitformoderator_cache_ttl', 60, PARAM_INT)
2794
        );
2795
    }
2796
}
2797
2798
/**
2799
 * Helper function renders static voice bridge settings if the feature is enabled.
2800
 *
2801
 * @param object $renderer
2802
 *
2803
 * @return void
2804
 */
2805
function bigbluebuttonbn_settings_voicebridge(&$renderer) {
2806
    // Configuration for "static voice bridge" feature.
2807
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_static_voice_bridge_shown()) {
2808
        $renderer->render_group_header('voicebridge');
2809
        $renderer->render_group_element(
2810
            'voicebridge_editable',
2811
            $renderer->render_group_element_checkbox('voicebridge_editable', 0)
2812
        );
2813
    }
2814
}
2815
2816
/**
2817
 * Helper function renders preuploaded presentation settings if the feature is enabled.
2818
 *
2819
 * @param object $renderer
2820
 *
2821
 * @return void
2822
 */
2823
function bigbluebuttonbn_settings_preupload(&$renderer) {
2824
    // Configuration for "preupload presentation" feature.
2825
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_preupload_presentation_shown()) {
2826
        // This feature only works if curl is installed.
2827
        $preuploaddescripion = get_string('config_preuploadpresentation_description', 'bigbluebuttonbn');
2828
        if (!extension_loaded('curl')) {
2829
            $preuploaddescripion .= '<div class="form-defaultinfo">';
2830
            $preuploaddescripion .= get_string('config_warning_curl_not_installed', 'bigbluebuttonbn');
2831
            $preuploaddescripion .= '</div><br>';
2832
        }
2833
        $renderer->render_group_header('preuploadpresentation', null, $preuploaddescripion);
2834
        if (extension_loaded('curl')) {
2835
            $renderer->render_group_element(
2836
                'preuploadpresentation_enabled',
2837
                $renderer->render_group_element_checkbox('preuploadpresentation_enabled', 0)
2838
            );
2839
        }
2840
    }
2841
}
2842
2843
/**
2844
 * Helper function renders preuploaded presentation manage file if the feature is enabled.
2845
 * This allow to select a file for use as default in all BBB instances if preuploaded presetantion is enable.
2846
 *
2847
 * @param object $renderer
2848
 *
2849
 * @return void
2850
 */
2851
function bigbluebuttonbn_settings_preupload_manage_default_file(&$renderer) {
2852
    // Configuration for "preupload presentation" feature.
2853
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_preupload_presentation_shown()) {
2854
        if (extension_loaded('curl')) {
2855
            // This feature only works if curl is installed.
2856
            $renderer->render_filemanager_default_file_presentation("presentation_default");
2857
        }
2858
    }
2859
}
2860
2861
/**
2862
 * Helper function renders userlimit settings if the feature is enabled.
2863
 *
2864
 * @param object $renderer
2865
 *
2866
 * @return void
2867
 */
2868
function bigbluebuttonbn_settings_userlimit(&$renderer) {
2869
    // Configuration for "user limit" feature.
2870
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_user_limit_shown()) {
2871
        $renderer->render_group_header('userlimit');
2872
        $renderer->render_group_element(
2873
            'userlimit_default',
2874
            $renderer->render_group_element_text('userlimit_default', 0, PARAM_INT)
2875
        );
2876
        $renderer->render_group_element(
2877
            'userlimit_editable',
2878
            $renderer->render_group_element_checkbox('userlimit_editable', 0)
2879
        );
2880
    }
2881
}
2882
2883
/**
2884
 * Helper function renders duration settings if the feature is enabled.
2885
 *
2886
 * @param object $renderer
2887
 *
2888
 * @return void
2889
 */
2890
function bigbluebuttonbn_settings_duration(&$renderer) {
2891
    // Configuration for "scheduled duration" feature.
2892
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_scheduled_duration_shown()) {
2893
        $renderer->render_group_header('scheduled');
2894
        $renderer->render_group_element(
2895
            'scheduled_duration_enabled',
2896
            $renderer->render_group_element_checkbox('scheduled_duration_enabled', 1)
2897
        );
2898
        $renderer->render_group_element(
2899
            'scheduled_duration_compensation',
2900
            $renderer->render_group_element_text('scheduled_duration_compensation', 10, PARAM_INT)
2901
        );
2902
        $renderer->render_group_element(
2903
            'scheduled_pre_opening',
2904
            $renderer->render_group_element_text('scheduled_pre_opening', 10, PARAM_INT)
2905
        );
2906
    }
2907
}
2908
2909
/**
2910
 * Helper function renders participant settings if the feature is enabled.
2911
 *
2912
 * @param object $renderer
2913
 *
2914
 * @return void
2915
 */
2916
function bigbluebuttonbn_settings_participants(&$renderer) {
2917
    // Configuration for defining the default role/user that will be moderator on new activities.
2918
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_moderator_default_shown()) {
2919
        $renderer->render_group_header('participant');
2920
        // UI for 'participants' feature.
2921
        $roles = bigbluebuttonbn_get_roles();
2922
        $owner = array('0' => get_string('mod_form_field_participant_list_type_owner', 'bigbluebuttonbn'));
2923
        $renderer->render_group_element(
2924
            'participant_moderator_default',
2925
            $renderer->render_group_element_configmultiselect(
2926
                'participant_moderator_default',
2927
                array_keys($owner),
2928
                array_merge($owner, $roles)
2929
            )
2930
        );
2931
    }
2932
}
2933
2934
/**
2935
 * Helper function renders notification settings if the feature is enabled.
2936
 *
2937
 * @param object $renderer
2938
 *
2939
 * @return void
2940
 */
2941
function bigbluebuttonbn_settings_notifications(&$renderer) {
2942
    // Configuration for "send notifications" feature.
2943
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_send_notifications_shown()) {
2944
        $renderer->render_group_header('sendnotifications');
2945
        $renderer->render_group_element(
2946
            'sendnotifications_enabled',
2947
            $renderer->render_group_element_checkbox('sendnotifications_enabled', 1)
2948
        );
2949
    }
2950
}
2951
2952
/**
2953
 * Helper function renders client type settings if the feature is enabled.
2954
 *
2955
 * @param object $renderer
2956
 *
2957
 * @return void
2958
 */
2959
function bigbluebuttonbn_settings_clienttype(&$renderer) {
2960
    // Configuration for "clienttype" feature.
2961
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_clienttype_shown()) {
2962
        $renderer->render_group_header('clienttype');
2963
        $renderer->render_group_element(
2964
            'clienttype_editable',
2965
            $renderer->render_group_element_checkbox('clienttype_editable', 0)
2966
        );
2967
        // Web Client default.
2968
        $default = intval((int) \mod_bigbluebuttonbn\locallib\config::get('clienttype_default'));
2969
        $choices = array(BIGBLUEBUTTON_CLIENTTYPE_FLASH => get_string('mod_form_block_clienttype_flash', 'bigbluebuttonbn'),
2970
            BIGBLUEBUTTON_CLIENTTYPE_HTML5 => get_string('mod_form_block_clienttype_html5', 'bigbluebuttonbn'));
2971
        $renderer->render_group_element(
2972
            'clienttype_default',
2973
            $renderer->render_group_element_configselect(
2974
                'clienttype_default',
2975
                $default,
2976
                $choices
2977
            )
2978
        );
2979
    }
2980
}
2981
2982
/**
2983
 * Helper function renders general settings if the feature is enabled.
2984
 *
2985
 * @param object $renderer
2986
 *
2987
 * @return void
2988
 */
2989 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...
2990
    // Configuration for BigBlueButton.
2991
    if ((boolean) \mod_bigbluebuttonbn\settings\validator::section_muteonstart_shown()) {
2992
        $renderer->render_group_header('muteonstart');
2993
        $renderer->render_group_element(
2994
            'muteonstart_default',
2995
            $renderer->render_group_element_checkbox('muteonstart_default', 0)
2996
        );
2997
        $renderer->render_group_element(
2998
            'muteonstart_editable',
2999
            $renderer->render_group_element_checkbox('muteonstart_editable', 0)
3000
        );
3001
    }
3002
}
3003
3004
/**
3005
 * Helper function renders extended settings if any of the features there is enabled.
3006
 *
3007
 * @param object $renderer
3008
 *
3009
 * @return void
3010
 */
3011 View Code Duplication
function bigbluebuttonbn_settings_extended(&$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...
3012
    // Configuration for 'notify users when recording ready' feature.
3013
    if (!(boolean) \mod_bigbluebuttonbn\settings\validator::section_settings_extended_shown()) {
3014
        return;
3015
    }
3016
    $renderer->render_group_header('extended_capabilities');
3017
    // UI for 'notify users when recording ready' feature.
3018
    $renderer->render_group_element(
3019
        'recordingready_enabled',
3020
        $renderer->render_group_element_checkbox('recordingready_enabled', 0)
3021
    );
3022
    // Configuration for extended BN capabilities.
3023
    if (bigbluebuttonbn_is_bn_server()) {
3024
        // UI for 'register meeting events' feature.
3025
        $renderer->render_group_element(
3026
            'meetingevents_enabled',
3027
            $renderer->render_group_element_checkbox('meetingevents_enabled', 0)
3028
        );
3029
    }
3030
}
3031
3032
/**
3033
 * Helper function returns a sha1 encoded string that is unique and will be used as a seed for meetingid.
3034
 *
3035
 * @return string
3036
 */
3037
function bigbluebuttonbn_unique_meetingid_seed() {
3038
    global $DB;
3039
    do {
3040
        $encodedseed = sha1(bigbluebuttonbn_random_password(12));
3041
        $meetingid = (string) $DB->get_field('bigbluebuttonbn', 'meetingid', array('meetingid' => $encodedseed));
3042
    } while ($meetingid == $encodedseed);
3043
    return $encodedseed;
3044
}
3045
3046
/**
3047
 * Helper function renders the link used for recording type in row for the data used by the recording table.
3048
 *
3049
 * @param array $recording
3050
 * @param array $bbbsession
3051
 * @param array $playback
3052
 *
3053
 * @return boolean
3054
 */
3055
function bigbluebuttonbn_include_recording_data_row_type($recording, $bbbsession, $playback) {
3056
    // All types that are not restricted are included.
3057
    if (array_key_exists('restricted', $playback) && strtolower($playback['restricted']) == 'false') {
3058
        return true;
3059
    }
3060
    // All types that are not statistics are included.
3061
    if ($playback['type'] != 'statistics') {
3062
        return true;
3063
    }
3064
    // Exclude imported recordings.
3065
    if (isset($recording['imported'])) {
3066
        return false;
3067
    }
3068
    // Exclude non moderators.
3069
    if (!$bbbsession['administrator'] && !$bbbsession['moderator']) {
3070
        return false;
3071
    }
3072
    return true;
3073
}
3074
3075
/**
3076
 * Renders the general warning message.
3077
 *
3078
 * @param string $message
3079
 * @param string $type
3080
 * @param string $href
3081
 * @param string $text
3082
 * @param string $class
3083
 *
3084
 * @return string
3085
 */
3086
function bigbluebuttonbn_render_warning($message, $type = 'info', $href = '', $text = '', $class = '') {
3087
    global $OUTPUT;
3088
    $output = "\n";
3089
    // Evaluates if config_warning is enabled.
3090
    if (empty($message)) {
3091
        return $output;
3092
    }
3093
    $output .= $OUTPUT->box_start(
3094
        'box boxalignleft adminerror alert alert-' . $type . ' alert-block fade in',
3095
        'bigbluebuttonbn_view_general_warning'
3096
    ) . "\n";
3097
    $output .= '    ' . $message . "\n";
3098
    $output .= '  <div class="singlebutton pull-right">' . "\n";
3099
    if (!empty($href)) {
3100
        $output .= bigbluebuttonbn_render_warning_button($href, $text, $class);
3101
    }
3102
    $output .= '  </div>' . "\n";
3103
    $output .= $OUTPUT->box_end() . "\n";
3104
    return $output;
3105
}
3106
3107
/**
3108
 * Renders the general warning button.
3109
 *
3110
 * @param string $href
3111
 * @param string $text
3112
 * @param string $class
3113
 * @param string $title
3114
 *
3115
 * @return string
3116
 */
3117
function bigbluebuttonbn_render_warning_button($href, $text = '', $class = '', $title = '') {
3118
    if ($text == '') {
3119
        $text = get_string('ok', 'moodle');
3120
    }
3121
    if ($title == '') {
3122
        $title = $text;
3123
    }
3124
    if ($class == '') {
3125
        $class = 'btn btn-secondary';
3126
    }
3127
    $output = '  <form method="post" action="' . $href . '" class="form-inline">' . "\n";
3128
    $output .= '      <button type="submit" class="' . $class . '"' . "\n";
3129
    $output .= '          title="' . $title . '"' . "\n";
3130
    $output .= '          >' . $text . '</button>' . "\n";
3131
    $output .= '  </form>' . "\n";
3132
    return $output;
3133
}
3134
3135
/**
3136
 * Check if a BigBlueButtonBN is available to be used by the current user.
3137
 *
3138
 * @param  stdClass  $bigbluebuttonbn  BigBlueButtonBN instance
3139
 *
3140
 * @return boolean                     status if room available and current user allowed to join
3141
 */
3142
function bigbluebuttonbn_get_availability_status($bigbluebuttonbn) {
3143
    list($roomavailable) = bigbluebuttonbn_room_is_available($bigbluebuttonbn);
3144
    list($usercanjoin) = bigbluebuttonbn_user_can_join_meeting($bigbluebuttonbn);
3145
    return ($roomavailable && $usercanjoin);
3146
}
3147
3148
/**
3149
 * Helper for evaluating if scheduled activity is avaiable.
3150
 *
3151
 * @param  stdClass  $bigbluebuttonbn  BigBlueButtonBN instance
3152
 *
3153
 * @return array                       status (room available or not and possible warnings)
3154
 */
3155
function bigbluebuttonbn_room_is_available($bigbluebuttonbn) {
3156
    $open = true;
3157
    $closed = false;
3158
    $warnings = array();
3159
3160
    $timenow = time();
3161
    $timeopen = $bigbluebuttonbn->openingtime;
3162
    $timeclose = $bigbluebuttonbn->closingtime;
3163
    if (!empty($timeopen) && $timeopen > $timenow) {
3164
        $open = false;
3165
    }
3166
    if (!empty($timeclose) && $timenow > $timeclose) {
3167
        $closed = true;
3168
    }
3169
3170
    if (!$open || $closed) {
3171
        if (!$open) {
3172
            $warnings['notopenyet'] = userdate($timeopen);
3173
        }
3174
        if ($closed) {
3175
            $warnings['expired'] = userdate($timeclose);
3176
        }
3177
        return array(false, $warnings);
3178
    }
3179
3180
    return array(true, $warnings);
3181
}
3182
3183
/**
3184
 * Helper for evaluating if meeting can be joined.
3185
 *
3186
 * @param  stdClass $bigbluebuttonbn  BigBlueButtonBN instance
3187
 * @param  string   $mid
3188
 * @param  integer  $userid
3189
 *
3190
 * @return array    status (user allowed to join or not and possible message)
3191
 */
3192
function bigbluebuttonbn_user_can_join_meeting($bigbluebuttonbn, $mid = null, $userid = null) {
3193
    // By default, use a meetingid without groups.
3194
    if (empty($mid)) {
3195
        $mid = $bigbluebuttonbn->meetingid . '-' . $bigbluebuttonbn->course . '-' . $bigbluebuttonbn->id;
3196
    }
3197
    // When meeting is running, all authorized users can join right in.
3198
    if (bigbluebuttonbn_is_meeting_running($mid)) {
3199
        return array(true, get_string('view_message_conference_in_progress', 'bigbluebuttonbn'));
3200
    }
3201
    // When meeting is not running, see if the user can join.
3202
    $context = context_course::instance($bigbluebuttonbn->course);
3203
    $participantlist = bigbluebuttonbn_get_participant_list($bigbluebuttonbn, $context);
3204
    $isadmin = is_siteadmin($userid);
3205
    $ismoderator = bigbluebuttonbn_is_moderator($context, $participantlist, $userid);
3206
    // If user is administrator, moderator or if is viewer and no waiting is required, join allowed.
3207
    if ($isadmin || $ismoderator || !$bigbluebuttonbn->wait) {
3208
        return array(true, get_string('view_message_conference_room_ready', 'bigbluebuttonbn'));
3209
    }
3210
    // Otherwise, no join allowed.
3211
    return array(false, get_string('view_message_conference_wait_for_moderator', 'bigbluebuttonbn'));
3212
}
3213
3214
/**
3215
 * Helper for getting a value from a bigbluebuttonbn cache.
3216
 *
3217
 * @param  string   $name       BigBlueButtonBN cache
3218
 * @param  string   $key        Key to be retrieved
3219
 * @param  integer  $default    Default value in case key is not found or it is empty
3220
 *
3221
 * @return variable key value
3222
 */
3223
function bigbluebuttonbn_cache_get($name, $key, $default = null) {
3224
    $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'mod_bigbluebuttonbn', $name);
3225
    $result = $cache->get($key);
3226
    if (!empty($result)) {
3227
        return $result;
3228
    }
3229
    return $default;
3230
}
3231
3232
/**
3233
 * Helper for setting a value in a bigbluebuttonbn cache.
3234
 *
3235
 * @param  string   $name       BigBlueButtonBN cache
3236
 * @param  string   $key        Key to be created/updated
3237
 * @param  variable $value      Default value to be set
3238
 */
3239
function bigbluebuttonbn_cache_set($name, $key, $value) {
3240
    $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'mod_bigbluebuttonbn', $name);
3241
    $cache->set($key, $value);
3242
}
3243
3244
/**
3245
 * Helper for getting the owner userid of a bigbluebuttonbn instance.
3246
 *
3247
 * @param  stdClass $bigbluebuttonbn  BigBlueButtonBN instance
3248
 *
3249
 * @return integer ownerid (a valid user id or null if not registered/found)
3250
 */
3251
function bigbluebuttonbn_instance_ownerid($bigbluebuttonbn) {
3252
    global $DB;
3253
    $filters = array('bigbluebuttonbnid' => $bigbluebuttonbn->id, 'log' => 'Add');
3254
    $ownerid = (integer) $DB->get_field('bigbluebuttonbn_logs', 'userid', $filters);
3255
    return $ownerid;
3256
}
3257
3258
/**
3259
 * Helper evaluates if the bigbluebutton server used belongs to blindsidenetworks domain.
3260
 *
3261
 * @return boolean
3262
 */
3263
function bigbluebuttonbn_has_html5_client() {
3264
    $checkurl = \mod_bigbluebuttonbn\locallib\bigbluebutton::root() . "html5client/check";
3265
    $curlinfo = bigbluebuttonbn_wrap_xml_load_file_curl_request($checkurl, 'HEAD');
3266
    return (isset($curlinfo['http_code']) && $curlinfo['http_code'] == 200);
3267
}
3268
3269
/**
3270
 * Setup the bbbsession variable that is used all accross the plugin.
3271
 *
3272
 * @param object $context
3273
 * @param array $bbbsession
3274
 * @return void
3275
 */
3276 View Code Duplication
function bigbluebuttonbn_view_bbbsession_set($context, &$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...
3277
    global $CFG, $USER;
3278
    // User data.
3279
    $bbbsession['username'] = fullname($USER);
3280
    $bbbsession['userID'] = $USER->id;
3281
    // User roles.
3282
    $bbbsession['administrator'] = is_siteadmin($bbbsession['userID']);
3283
    $participantlist = bigbluebuttonbn_get_participant_list($bbbsession['bigbluebuttonbn'], $context);
3284
    $bbbsession['moderator'] = bigbluebuttonbn_is_moderator($context, $participantlist);
3285
    $bbbsession['managerecordings'] = ($bbbsession['administrator']
3286
        || has_capability('mod/bigbluebuttonbn:managerecordings', $context));
3287
    $bbbsession['importrecordings'] = ($bbbsession['managerecordings']);
3288
    // Server data.
3289
    $bbbsession['modPW'] = $bbbsession['bigbluebuttonbn']->moderatorpass;
3290
    $bbbsession['viewerPW'] = $bbbsession['bigbluebuttonbn']->viewerpass;
3291
    // Database info related to the activity.
3292
    $bbbsession['meetingid'] = $bbbsession['bigbluebuttonbn']->meetingid . '-' . $bbbsession['course']->id . '-' .
3293
    $bbbsession['bigbluebuttonbn']->id;
3294
    $bbbsession['meetingname'] = $bbbsession['bigbluebuttonbn']->name;
3295
    $bbbsession['meetingdescription'] = $bbbsession['bigbluebuttonbn']->intro;
3296
    // Extra data for setting up the Meeting.
3297
    $bbbsession['userlimit'] = intval((int) \mod_bigbluebuttonbn\locallib\config::get('userlimit_default'));
3298
    if ((boolean) \mod_bigbluebuttonbn\locallib\config::get('userlimit_editable')) {
3299
        $bbbsession['userlimit'] = intval($bbbsession['bigbluebuttonbn']->userlimit);
3300
    }
3301
    $bbbsession['voicebridge'] = $bbbsession['bigbluebuttonbn']->voicebridge;
3302
    if ($bbbsession['bigbluebuttonbn']->voicebridge > 0) {
3303
        $bbbsession['voicebridge'] = 70000 + $bbbsession['bigbluebuttonbn']->voicebridge;
3304
    }
3305
    $bbbsession['wait'] = $bbbsession['bigbluebuttonbn']->wait;
3306
    $bbbsession['record'] = $bbbsession['bigbluebuttonbn']->record;
3307
    $bbbsession['recordallfromstart'] = $CFG->bigbluebuttonbn_recording_all_from_start_default;
3308
    if ($CFG->bigbluebuttonbn_recording_all_from_start_editable) {
3309
        $bbbsession['recordallfromstart'] = $bbbsession['bigbluebuttonbn']->recordallfromstart;
3310
    }
3311
3312
    $bbbsession['recordhidebutton'] = $CFG->bigbluebuttonbn_recording_hide_button_default;
3313
    if ($CFG->bigbluebuttonbn_recording_hide_button_editable) {
3314
        $bbbsession['recordhidebutton'] = $bbbsession['bigbluebuttonbn']->recordhidebutton;
3315
    }
3316
3317
    $bbbsession['welcome'] = $bbbsession['bigbluebuttonbn']->welcome;
3318
    if (!isset($bbbsession['welcome']) || $bbbsession['welcome'] == '') {
3319
        $bbbsession['welcome'] = get_string('mod_form_field_welcome_default', 'bigbluebuttonbn');
3320
    }
3321
    if ($bbbsession['bigbluebuttonbn']->record) {
3322
        // Check if is enable record all from start.
3323
        if ($bbbsession['recordallfromstart']) {
3324
            $bbbsession['welcome'] .= '<br><br>' . get_string(
3325
                'bbbrecordallfromstartwarning',
3326
                'bigbluebuttonbn'
3327
            );
3328
        } else {
3329
            $bbbsession['welcome'] .= '<br><br>' . get_string('bbbrecordwarning', 'bigbluebuttonbn');
3330
        }
3331
    }
3332
    $bbbsession['openingtime'] = $bbbsession['bigbluebuttonbn']->openingtime;
3333
    $bbbsession['closingtime'] = $bbbsession['bigbluebuttonbn']->closingtime;
3334
    $bbbsession['muteonstart'] = $bbbsession['bigbluebuttonbn']->muteonstart;
3335
    // Additional info related to the course.
3336
    $bbbsession['context'] = $context;
3337
    // Metadata (origin).
3338
    $bbbsession['origin'] = 'Moodle';
3339
    $bbbsession['originVersion'] = $CFG->release;
3340
    $parsedurl = parse_url($CFG->wwwroot);
3341
    $bbbsession['originServerName'] = $parsedurl['host'];
3342
    $bbbsession['originServerUrl'] = $CFG->wwwroot;
3343
    $bbbsession['originServerCommonName'] = '';
3344
    $bbbsession['originTag'] = 'moodle-mod_bigbluebuttonbn (' . get_config('mod_bigbluebuttonbn', 'version') . ')';
3345
    $bbbsession['bnserver'] = bigbluebuttonbn_is_bn_server();
3346
    // Setting for clienttype, assign flash if not enabled, or default if not editable.
3347
    $bbbsession['clienttype'] = BIGBLUEBUTTON_CLIENTTYPE_FLASH;
3348
    if (\mod_bigbluebuttonbn\locallib\config::clienttype_enabled()) {
3349
        $bbbsession['clienttype'] = \mod_bigbluebuttonbn\locallib\config::get('clienttype_default');
3350
    }
3351
    if (\mod_bigbluebuttonbn\locallib\config::get('clienttype_editable') && isset($bbbsession['bigbluebuttonbn']->clienttype)) {
3352
        $bbbsession['clienttype'] = $bbbsession['bigbluebuttonbn']->clienttype;
3353
    }
3354
}
3355
3356
/**
3357
 * Return the status of an activity [open|not_started|ended].
3358
 *
3359
 * @param array $bbbsession
3360
 * @return string
3361
 */
3362 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...
3363
    $now = time();
3364
    if (!empty($bbbsession['bigbluebuttonbn']->openingtime) && $now < $bbbsession['bigbluebuttonbn']->openingtime) {
3365
        // The activity has not been opened.
3366
        return 'not_started';
3367
    }
3368
    if (!empty($bbbsession['bigbluebuttonbn']->closingtime) && $now > $bbbsession['bigbluebuttonbn']->closingtime) {
3369
        // The activity has been closed.
3370
        return 'ended';
3371
    }
3372
    // The activity is open.
3373
    return 'open';
3374
}
3375
3376
/**
3377
 * Set session URLs.
3378
 *
3379
 * @param array $bbbsession
3380
 * @param int $id
3381
 * @return string
3382
 */
3383
function bigbluebuttonbn_view_session_config(&$bbbsession, $id) {
3384
    // Operation URLs.
3385
    $bbbsession['bigbluebuttonbnURL'] = plugin::necurl(
3386
        '/mod/bigbluebuttonbn/view.php',
3387
        ['id' => $bbbsession['cm']->id]
3388
    );
3389
    $bbbsession['logoutURL'] = plugin::necurl(
3390
        '/mod/bigbluebuttonbn/bbb_view.php',
3391
        ['action' => 'logout', 'id' => $id, 'bn' => $bbbsession['bigbluebuttonbn']->id]
3392
    );
3393
    $bbbsession['recordingReadyURL'] = plugin::necurl(
3394
        '/mod/bigbluebuttonbn/bbb_broker.php',
3395
        ['action' => 'recording_ready', 'bigbluebuttonbn' => $bbbsession['bigbluebuttonbn']->id]
3396
    );
3397
    $bbbsession['meetingEventsURL'] = plugin::necurl(
3398
        '/mod/bigbluebuttonbn/bbb_broker.php',
3399
        ['action' => 'meeting_events', 'bigbluebuttonbn' => $bbbsession['bigbluebuttonbn']->id]
3400
    );
3401
    $bbbsession['joinURL'] = plugin::necurl(
3402
        '/mod/bigbluebuttonbn/bbb_view.php',
3403
        ['action' => 'join', 'id' => $id, 'bn' => $bbbsession['bigbluebuttonbn']->id]
3404
    );
3405
3406
    // Check status and set extra values.
3407
    $activitystatus = bigbluebuttonbn_view_get_activity_status($bbbsession); // In locallib.
3408 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...
3409
        $bbbsession['presentation'] = bigbluebuttonbn_get_presentation_array(
3410
            $bbbsession['context'],
3411
            $bbbsession['bigbluebuttonbn']->presentation
3412
        );
3413
    } else if ($activitystatus == 'open') {
3414
        $bbbsession['presentation'] = bigbluebuttonbn_get_presentation_array(
3415
            $bbbsession['context'],
3416
            $bbbsession['bigbluebuttonbn']->presentation,
3417
            $bbbsession['bigbluebuttonbn']->id
3418
        );
3419
    }
3420
3421
    return $activitystatus;
3422
}
3423
3424
/**
3425
 * Helper for preparing metadata used while creating the meeting.
3426
 *
3427
 * @param  array    $bbbsession
3428
 * @return array
3429
 */
3430
function bigbluebuttonbn_create_meeting_metadata(&$bbbsession) {
3431
    global $USER;
3432
    // Create standard metadata.
3433
    $metadata = [
3434
        'bbb-origin' => $bbbsession['origin'],
3435
        'bbb-origin-version' => $bbbsession['originVersion'],
3436
        'bbb-origin-server-name' => $bbbsession['originServerName'],
3437
        'bbb-origin-server-common-name' => $bbbsession['originServerCommonName'],
3438
        'bbb-origin-tag' => $bbbsession['originTag'],
3439
        'bbb-context' => $bbbsession['course']->fullname,
3440
        'bbb-context-id' => $bbbsession['course']->id,
3441
        'bbb-context-name' => trim(html_to_text($bbbsession['course']->fullname, 0)),
3442
        'bbb-context-label' => trim(html_to_text($bbbsession['course']->shortname, 0)),
3443
        'bbb-recording-name' => bigbluebuttonbn_html2text($bbbsession['meetingname'], 64),
3444
        'bbb-recording-description' => bigbluebuttonbn_html2text($bbbsession['meetingdescription'], 64),
3445
        'bbb-recording-tags' => bigbluebuttonbn_get_tags($bbbsession['cm']->id), // Same as $id.
3446
    ];
3447
    // Special metadata for recording processing.
3448
    if ((boolean) \mod_bigbluebuttonbn\locallib\config::get('recordingstatus_enabled')) {
3449
        $metadata["bn-recording-status"] = json_encode(
3450
            array(
3451
                'email' => array('"' . fullname($USER) . '" <' . $USER->email . '>'),
3452
                'context' => $bbbsession['bigbluebuttonbnURL'],
3453
            )
3454
        );
3455
    }
3456
    if ((boolean) \mod_bigbluebuttonbn\locallib\config::get('recordingready_enabled')) {
3457
        $metadata['bn-recording-ready-url'] = $bbbsession['recordingReadyURL'];
3458
    }
3459
    if ((boolean) \mod_bigbluebuttonbn\locallib\config::get('meetingevents_enabled')) {
3460
        $metadata['analytics-callback-url'] = $bbbsession['meetingEventsURL'];
3461
    }
3462
    return $metadata;
3463
}
3464