Completed
Push — master ( 4b6fbb...9ae9c1 )
by Jesus
02:18
created

locallib.php ➔ bigbluebuttonbn_enqueue_completion_update()   A

Complexity

Conditions 2
Paths 4

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

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