Completed
Pull Request — master (#38)
by Jesus
02:07
created

locallib.php ➔ bigbluebutonbn_settings_meetings()   C

Complexity

Conditions 10
Paths 320

Size

Total Lines 56
Code Lines 36

Duplication

Lines 11
Ratio 19.64 %

Importance

Changes 0
Metric Value
cc 10
eloc 36
nc 320
nop 1
dl 11
loc 56
rs 5.0704
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
17
/**
18
 * Internal library of functions for module BigBlueButtonBN.
19
 *
20
 * @author    Fred Dixon  (ffdixon [at] blindsidenetworks [dt] com)
21
 * @author    Jesus Federico  (jesus [at] blindsidenetworks [dt] com)
22
 * @copyright 2010-2017 Blindside Networks Inc
23
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v2 or later
24
 */
25
26
defined('MOODLE_INTERNAL') || die;
27
28
global $CFG;
29
30
require_once(dirname(__FILE__).'/lib.php');
31
32
const BIGBLUEBUTTONBN_FORCED = true;
33
34
const BIGBLUEBUTTONBN_TYPE_ALL = 0;
35
const BIGBLUEBUTTONBN_TYPE_ROOM_ONLY = 1;
36
const BIGBLUEBUTTONBN_TYPE_RECORDING_ONLY = 2;
37
38
const BIGBLUEBUTTONBN_ROLE_VIEWER = 'viewer';
39
const BIGBLUEBUTTONBN_ROLE_MODERATOR = 'moderator';
40
const BIGBLUEBUTTONBN_METHOD_GET = 'GET';
41
const BIGBLUEBUTTONBN_METHOD_POST = 'POST';
42
43
const BIGBLUEBUTTON_EVENT_ACTIVITY_VIEWED = 'activity_viewed';
44
const BIGBLUEBUTTON_EVENT_ACTIVITY_MANAGEMENT_VIEWED = 'activity_management_viewed';
45
const BIGBLUEBUTTON_EVENT_LIVE_SESSION = 'live_session';
46
const BIGBLUEBUTTON_EVENT_MEETING_CREATED = 'meeting_created';
47
const BIGBLUEBUTTON_EVENT_MEETING_ENDED = 'meeting_ended';
48
const BIGBLUEBUTTON_EVENT_MEETING_JOINED = 'meeting_joined';
49
const BIGBLUEBUTTON_EVENT_MEETING_LEFT = 'meeting_left';
50
const BIGBLUEBUTTON_EVENT_RECORDING_DELETED = 'recording_deleted';
51
const BIGBLUEBUTTON_EVENT_RECORDING_IMPORTED = 'recording_imported';
52
const BIGBLUEBUTTON_EVENT_RECORDING_PROTECTED = 'recording_protected';
53
const BIGBLUEBUTTON_EVENT_RECORDING_PUBLISHED = 'recording_published';
54
const BIGBLUEBUTTON_EVENT_RECORDING_UNPROTECTED = 'recording_unprotected';
55
const BIGBLUEBUTTON_EVENT_RECORDING_UNPUBLISHED = 'recording_unpublished';
56
const BIGBLUEBUTTON_EVENT_RECORDING_EDITED = 'recording_edited';
57
const BIGBLUEBUTTON_EVENT_RECORDING_VIEWED = 'recording_viewed';
58
59
/**
60
 * @param array  $bbbsession
61
 * @param string $event
62
 * @param array  $overrides
63
 * @param string $meta
64
 */
65
function bigbluebuttonbn_logs(array $bbbsession, $event, array $overrides = [], $meta = null) {
66
    global $DB;
67
    $log = new stdClass();
68
    // Default values.
69
    $log->courseid = $bbbsession['course']->id;
70
    $log->bigbluebuttonbnid = $bbbsession['bigbluebuttonbn']->id;
71
    $log->userid = $bbbsession['userID'];
72
    $log->meetingid = $bbbsession['meetingid'];
73
    $log->timecreated = time();
74
    // Overrides.
75
    foreach ($overrides as $key => $value) {
76
        $log->$key = $value;
77
    }
78
    $log->log = $event;
79
    if (isset($meta)) {
80
        $log->meta = $meta;
81
    } else if ($event == BIGBLUEBUTTONBN_LOG_EVENT_CREATE) {
82
        $log->meta = '{"record":'.($bbbsession['record'] ? 'true' : 'false').'}';
83
    }
84
    $DB->insert_record('bigbluebuttonbn_logs', $log);
85
}
86
87
/**
88
 * @param string $meetingid
89
 * @param string $username
90
 * @param string $pw
91
 * @param string $logouturl
92
 * @param string $configtoken
93
 * @param string $userid
94
 */
95
function bigbluebuttonbn_get_join_url($meetingid, $username, $pw, $logouturl, $configtoken = null, $userid = null) {
96
    $data = ['meetingID' => $meetingid,
97
              'fullName' => $username,
98
              'password' => $pw,
99
              'logoutURL' => $logouturl,
100
            ];
101
    if (!is_null($configtoken)) {
102
        $data['configToken'] = $configtoken;
103
    }
104
    if (!is_null($userid)) {
105
        $data['userID'] = $userid;
106
    }
107
    return \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('join', $data);
108
}
109
110
/**
111
 * @param array  $data
112
 * @param array  $metadata
113
 * @param string $pname
114
 * @param string $purl
115
 */
116
function bigbluebuttonbn_get_create_meeting_array($data, $metadata = array(), $pname = null, $purl = null) {
117
    $createmeetingurl = \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('create', $data, $metadata);
118
    $method = BIGBLUEBUTTONBN_METHOD_GET;
119
    $data = null;
120
    if (!is_null($pname) && !is_null($purl)) {
121
        $method = BIGBLUEBUTTONBN_METHOD_POST;
122
        $data = "<?xml version='1.0' encoding='UTF-8'?><modules><module name='presentation'><document url='".
123
            $purl."' /></module></modules>";
124
    }
125
    $xml = bigbluebuttonbn_wrap_xml_load_file($createmeetingurl, $method, $data);
126
    if ($xml) {
127
        $response = array('returncode' => $xml->returncode, 'message' => $xml->message, 'messageKey' => $xml->messageKey);
128
        if ($xml->meetingID) {
129
            $response += array('meetingID' => $xml->meetingID, 'attendeePW' => $xml->attendeePW,
130
                'moderatorPW' => $xml->moderatorPW, 'hasBeenForciblyEnded' => $xml->hasBeenForciblyEnded);
131
        }
132
        return $response;
133
    }
134
    return null;
135
}
136
137
/**
138
 * @param string $meetingid
139
 */
140
function bigbluebuttonbn_get_meeting_array($meetingid) {
141
    $meetings = bigbluebuttonbn_get_meetings_array();
142
    if ($meetings) {
143
        foreach ($meetings as $meeting) {
144
            if ($meeting['meetingID'] == $meetingid) {
145
                return $meeting;
146
            }
147
        }
148
    }
149
    return null;
150
}
151
152
function bigbluebuttonbn_get_meetings_array() {
153
    $xml = bigbluebuttonbn_wrap_xml_load_file(\mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('getMeetings'));
154
    if ($xml && $xml->returncode == 'SUCCESS' && empty($xml->messageKey)) {
155
        // Meetings were returned.
156
        $meetings = array();
157
        foreach ($xml->meetings->meeting as $meeting) {
158
            $meetings[] = array('meetingID' => $meeting->meetingID,
159
                                'moderatorPW' => $meeting->moderatorPW,
160
                                'attendeePW' => $meeting->attendeePW,
161
                                'hasBeenForciblyEnded' => $meeting->hasBeenForciblyEnded,
162
                                'running' => $meeting->running, );
163
        }
164
        return $meetings;
165
    }
166 View Code Duplication
    if ($xml) {
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...
167
        // Either failure or success without meetings.
168
        return array('returncode' => $xml->returncode, 'message' => $xml->message, 'messageKey' => $xml->messageKey);
169
    }
170
    // If the server is unreachable, then prompts the user of the necessary action.
171
    return null;
172
}
173
174
/**
175
 * @param string $meetingid
176
 */
177
function bigbluebuttonbn_get_meeting_info_array($meetingid) {
178
    $xml = bigbluebuttonbn_wrap_xml_load_file(
179
        \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('getMeetingInfo', ['meetingID' => $meetingid])
180
      );
181
    if ($xml && $xml->returncode == 'SUCCESS' && empty($xml->messageKey)) {
182
        // Meeting info was returned.
183
        return array('returncode' => $xml->returncode,
184
                     'meetingID' => $xml->meetingID,
185
                     'moderatorPW' => $xml->moderatorPW,
186
                     'attendeePW' => $xml->attendeePW,
187
                     'hasBeenForciblyEnded' => $xml->hasBeenForciblyEnded,
188
                     'running' => $xml->running,
189
                     'recording' => $xml->recording,
190
                     'startTime' => $xml->startTime,
191
                     'endTime' => $xml->endTime,
192
                     'participantCount' => $xml->participantCount,
193
                     'moderatorCount' => $xml->moderatorCount,
194
                     'attendees' => $xml->attendees,
195
                     'metadata' => $xml->metadata,
196
                   );
197
    }
198 View Code Duplication
    if ($xml) {
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...
199
        // Either failure or success without meeting info.
200
        return array('returncode' => $xml->returncode, 'message' => $xml->message, 'messageKey' => $xml->messageKey);
201
    }
202
    // If the server is unreachable, then prompts the user of the necessary action.
203
    return null;
204
}
205
206
/**
207
 * helper function to retrieve recordings from a BigBlueButton server.
208
 *
209
 * @param string or array $meetingids   list of meetingIDs "mid1,mid2,mid3" or array("mid1","mid2","mid3")
210
 * @param string or array $recordingids list of $recordingids "rid1,rid2,rid3" or array("rid1","rid2","rid3") for filtering
211
 *
212
 * @return associative array with recordings indexed by recordID, each recording is a non sequential associative array
213
 */
214
function bigbluebuttonbn_get_recordings_array($meetingids, $recordingids = []) {
215
    $meetingidsarray = $meetingids;
216
    if (!is_array($meetingids)) {
217
        $meetingidsarray = explode(',', $meetingids);
218
    }
219
    // If $meetingidsarray is empty there is no need to go further.
220
    if (empty($meetingidsarray)) {
221
        return array();
222
    }
223
    $recordings = bigbluebuttonbn_get_recordings_array_fetch($meetingidsarray);
224
    // Filter recordings based on recordingIDs.
225
    $recordingidsarray = $recordingids;
226
    if (!is_array($recordingids)) {
227
        $recordingidsarray = explode(',', $recordingids);
228
    }
229
    if (empty($recordingidsarray)) {
230
        // No recording ids, no need to filter.
231
        return $recordings;
232
    }
233
    return bigbluebuttonbn_get_recordings_array_filter($recordingidsarray, $recordings);
234
}
235
236
/**
237
 * helper function to fetch recordings from a BigBlueButton server.
238
 *
239
 * @param array $meetingidsarray   array with meeting ids in the form array("mid1","mid2","mid3")
240
 *
241
 * @return associative array with recordings indexed by recordID, each recording is a non sequential associative array
242
 */
243
function bigbluebuttonbn_get_recordings_array_fetch($meetingidsarray) {
244
    $recordings = array();
245
    // Execute a paginated getRecordings request.
246
    $pages = floor(count($meetingidsarray) / 25) + 1;
247
    for ($page = 1; $page <= $pages; ++$page) {
248
        $mids = array_slice($meetingidsarray, ($page - 1) * 25, 25);
249
        // Do getRecordings is executed using a method GET (supported by all versions of BBB).
250
        $xml = bigbluebuttonbn_wrap_xml_load_file(
251
            \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('getRecordings', ['meetingID' => implode(',', $mids)])
252
          );
253
        if ($xml && $xml->returncode == 'SUCCESS' && isset($xml->recordings)) {
254
            // If there were meetings already created.
255
            foreach ($xml->recordings->recording as $recording) {
256
                $recordingarrayvalue = bigbluebuttonbn_get_recording_array_value($recording);
257
                $recordings[$recordingarrayvalue['recordID']] = $recordingarrayvalue;
258
            }
259
            uasort($recordings, 'bigbluebuttonbn_recording_build_sorter');
260
        }
261
    }
262
    return $recordings;
263
}
264
265
function bigbluebuttonbn_get_recordings_array_filter($recordingidsarray, &$recordings) {
266
    foreach ($recordings as $key => $recording) {
267
        if (!in_array($recording['recordID'], $recordingidsarray)) {
268
            unset($recordings[$key]);
269
        }
270
    }
271
    return $recordings;
272
}
273
274
/**
275
 * Helper function to retrieve imported recordings from the Moodle database.
276
 * The references are stored as events in bigbluebuttonbn_logs.
277
 *
278
 * @param string $courseid
279
 * @param string $bigbluebuttonbnid
280
 * @param bool   $subset
281
 *
282
 * @return associative array with imported recordings indexed by recordID, each recording is a non sequential associative
283
 * array that corresponds to the actual recording in BBB
284
 */
285
function bigbluebuttonbn_get_recordings_imported_array($courseid, $bigbluebuttonbnid = null, $subset = true) {
286
    global $DB;
287
    $select = "courseid = '{$courseid}' AND bigbluebuttonbnid <> '{$bigbluebuttonbnid}' AND log = '" .
288
        BIGBLUEBUTTONBN_LOG_EVENT_IMPORT . "'";
289
    if ($bigbluebuttonbnid === null) {
290
        $select = "courseid = '{$courseid}' AND log = '" . BIGBLUEBUTTONBN_LOG_EVENT_IMPORT . "'";
291
    } else if ($subset) {
292
        $select = "bigbluebuttonbnid = '{$bigbluebuttonbnid}' AND log = '" . BIGBLUEBUTTONBN_LOG_EVENT_IMPORT . "'";
293
    }
294
    $recordsimported = $DB->get_records_select('bigbluebuttonbn_logs', $select);
295
    $recordsimportedarray = array();
296
    foreach ($recordsimported as $recordimported) {
297
        $meta = json_decode($recordimported->meta, true);
298
        $recording = $meta['recording'];
299
        // Override imported flag with actual ID.
300
        $recording['imported'] = $recordimported->id;
301
        if (isset($recordimported->protected)) {
302
            $recording['protected'] = (string) $recordimported->protected;
303
        }
304
        $recordsimportedarray[$recording['recordID']] = $recording;
305
    }
306
    return $recordsimportedarray;
307
}
308
309
function bigbluebuttonbn_get_default_config_xml() {
310
    $xml = bigbluebuttonbn_wrap_xml_load_file(
311
        \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('getDefaultConfigXML')
312
      );
313
    return $xml;
314
}
315
316
function bigbluebuttonbn_get_default_config_xml_array() {
317
    $defaultconfigxml = bigbluebuttonbn_getDefaultConfigXML();
318
    return (array) $defaultconfigxml;
319
}
320
321
function bigbluebuttonbn_get_recording_array_value($recording) {
322
    // Add formats.
323
    $playbackarray = array();
324
    foreach ($recording->playback->format as $format) {
325
        $playbackarray[(string) $format->type] = array('type' => (string) $format->type,
326
            'url' => trim((string) $format->url), 'length' => (string) $format->length);
327
        // Add preview per format when existing.
328
        if ($format->preview) {
329
            $imagesarray = array();
330
            foreach ($format->preview->images->image as $image) {
331
                $imagearray = array('url' => trim((string) $image));
332
                foreach ($image->attributes() as $attkey => $attvalue) {
333
                    $imagearray[$attkey] = (string) $attvalue;
334
                }
335
                array_push($imagesarray, $imagearray);
336
            }
337
            $playbackarray[(string) $format->type]['preview'] = $imagesarray;
338
        }
339
    }
340
    // Add the metadata to the recordings array.
341
    $metadataarray = bigbluebuttonbn_get_recording_array_meta(get_object_vars($recording->metadata));
342
    $recordingarray = array('recordID' => (string) $recording->recordID,
343
        'meetingID' => (string) $recording->meetingID, 'meetingName' => (string) $recording->name,
344
        'published' => (string) $recording->published, 'startTime' => (string) $recording->startTime,
345
        'endTime' => (string) $recording->endTime, 'playbacks' => $playbackarray);
346
    if (isset($recording->protected)) {
347
        $recordingarray['protected'] = (string) $recording->protected;
348
    }
349
    return $recordingarray + $metadataarray;
350
}
351
352
function bigbluebuttonbn_get_recording_array_meta($metadata) {
353
    $metadataarray = array();
354
    foreach ($metadata as $key => $value) {
355
        if (is_object($value)) {
356
            $value = '';
357
        }
358
        $metadataarray['meta_'.$key] = $value;
359
    }
360
    return $metadataarray;
361
}
362
363
function bigbluebuttonbn_recording_build_sorter($a, $b) {
364
    if ($a['startTime'] < $b['startTime']) {
365
        return -1;
366
    }
367
    if ($a['startTime'] == $b['startTime']) {
368
        return 0;
369
    }
370
    return 1;
371
}
372
373
/**
374
 * @param string $recordids
375
 */
376 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...
377
    $ids = explode(',', $recordids);
378
    foreach ($ids as $id) {
379
        $xml = bigbluebuttonbn_wrap_xml_load_file(
380
            \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('deleteRecordings', ['recordID' => $id])
381
          );
382
        if ($xml && $xml->returncode != 'SUCCESS') {
383
            return false;
384
        }
385
    }
386
    return true;
387
}
388
389
/**
390
 * @param string $recordids
391
 * @param string $publish
392
 */
393 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...
394
    $ids = explode(',', $recordids);
395
    foreach ($ids as $id) {
396
        $xml = bigbluebuttonbn_wrap_xml_load_file(
397
            \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('publishRecordings', ['recordID' => $id, 'publish' => $publish])
398
          );
399
        if ($xml && $xml->returncode != 'SUCCESS') {
400
            return false;
401
        }
402
    }
403
    return true;
404
}
405
406
/**
407
 * @param string $recordids
408
 * @param array $params ['key'=>param_key, 'value']
409
 */
410 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...
411
    $ids = explode(',', $recordids);
412
    foreach ($ids as $id) {
413
        $xml = bigbluebuttonbn_wrap_xml_load_file(
414
            \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('updateRecordings', ['recordID' => $id] + (array) $params)
415
          );
416
        if ($xml && $xml->returncode != 'SUCCESS') {
417
            return false;
418
        }
419
    }
420
    return true;
421
}
422
423
/**
424
 * @param string $meetingid
425
 * @param string $modpw
426
 */
427
function bigbluebuttonbn_end_meeting($meetingid, $modpw) {
428
    $xml = bigbluebuttonbn_wrap_xml_load_file(
429
        \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('end', ['meetingID' => $meetingid, 'password' => $modpw])
430
      );
431 View Code Duplication
    if ($xml) {
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...
432
        // If the xml packet returned failure it displays the message to the user.
433
        return array('returncode' => $xml->returncode, 'message' => $xml->message, 'messageKey' => $xml->messageKey);
434
    }
435
    // If the server is unreachable, then prompts the user of the necessary action.
436
    return null;
437
}
438
439
/**
440
 * @param string $meetingid
441
 */
442
function bigbluebuttonbn_is_meeting_running($meetingid) {
443
    $xml = bigbluebuttonbn_wrap_xml_load_file(
444
        \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('isMeetingRunning', ['meetingID' => $meetingid])
445
      );
446
    if ($xml && $xml->returncode == 'SUCCESS') {
447
        return ($xml->running == 'true');
448
    }
449
    return false;
450
}
451
452
function bigbluebuttonbn_get_server_version() {
453
    $xml = bigbluebuttonbn_wrap_xml_load_file(
454
        \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url()
455
      );
456
    if ($xml && $xml->returncode == 'SUCCESS') {
457
        return $xml->version;
458
    }
459
    return null;
460
}
461
462
/**
463
 * @param string $url
464
 * @param string $data
465
 */
466
function bigbluebuttonbn_wrap_xml_load_file($url, $method = BIGBLUEBUTTONBN_METHOD_GET,
467
    $data = null, $contenttype = 'text/xml') {
468
    if (extension_loaded('curl')) {
469
        $response = bigbluebuttonbn_wrap_xml_load_file_curl_request($url, $method, $data, $contenttype);
470
        if (!$response) {
471
            debugging('No response on wrap_simplexml_load_file', DEBUG_DEVELOPER);
472
            return null;
473
        }
474
        $previous = libxml_use_internal_errors(true);
475
        try {
476
            $xml = simplexml_load_string($response, 'SimpleXMLElement', LIBXML_NOCDATA | LIBXML_NOBLANKS);
477
478
            return $xml;
479
        } catch (Exception $e) {
480
            libxml_use_internal_errors($previous);
481
            $error = 'Caught exception: '.$e->getMessage();
482
            debugging($error, DEBUG_DEVELOPER);
483
            return null;
484
        }
485
    }
486
    // Alternative request non CURL based.
487
    $previous = libxml_use_internal_errors(true);
488
    try {
489
        $response = simplexml_load_file($url, 'SimpleXMLElement', LIBXML_NOCDATA | LIBXML_NOBLANKS);
490
        return $response;
491
    } catch (Exception $e) {
492
        $error = 'Caught exception: '.$e->getMessage();
493
        debugging($error, DEBUG_DEVELOPER);
494
        libxml_use_internal_errors($previous);
495
        return null;
496
    }
497
}
498
499
function bigbluebuttonbn_wrap_xml_load_file_curl_request($url, $method = BIGBLUEBUTTONBN_METHOD_GET,
500
    $data = null, $contenttype = 'text/xml') {
501
    $c = new curl();
502
    $c->setopt(array('SSL_VERIFYPEER' => true));
503
    if ($method == BIGBLUEBUTTONBN_METHOD_POST) {
504
        if (is_null($data) || is_array($data)) {
505
            return $c->post($url);
506
        }
507
508
        $options = array();
509
        $options['CURLOPT_HTTPHEADER'] = array(
510
                 'Content-Type: '.$contenttype,
511
                 'Content-Length: '.strlen($data),
512
                 'Content-Language: en-US',
513
               );
514
515
        return $c->post($url, $data, $options);
516
    }
517
    return $c->get($url);
518
}
519
520
function bigbluebuttonbn_get_user_roles($context, $userid) {
521
    global $DB;
522
    $userroles = get_user_roles($context, $userid);
523
    if ($userroles) {
524
        $where = '';
525
        foreach ($userroles as $value) {
526
            $where .= (empty($where) ? ' WHERE' : ' OR').' id='.$value->roleid;
527
        }
528
        $userroles = $DB->get_records_sql('SELECT * FROM {role}'.$where);
529
    }
530
    return $userroles;
531
}
532
533
function bigbluebuttonbn_get_guest_role() {
534
    $guestrole = get_guest_role();
535
    return array($guestrole->id => $guestrole);
536
}
537
538
function bigbluebuttonbn_get_users(context $context = null) {
539
    $users = (array) get_enrolled_users($context, '', 0, 'u.*', null, 0, 0, true);
540
    foreach ($users as $key => $value) {
541
        $users[$key] = fullname($value);
542
    }
543
    return $users;
544
}
545
546
function bigbluebuttonbn_get_users_select(context $context = null) {
547
    $users = (array) get_enrolled_users($context, '', 0, 'u.*', null, 0, 0, true);
548
    foreach ($users as $key => $value) {
549
        $users[$key] = array('id' => $value->id, 'name' => fullname($value));
550
    }
551
    return $users;
552
}
553
554
function bigbluebuttonbn_get_roles(context $context = null) {
555
    $roles = (array) role_get_names($context);
556
    foreach ($roles as $key => $value) {
557
        $roles[$key] = $value->localname;
558
    }
559
    return $roles;
560
}
561
562
function bigbluebuttonbn_get_roles_select(context $context = null) {
563
    $roles = (array) role_get_names($context);
564
    foreach ($roles as $key => $value) {
565
        $roles[$key] = array('id' => $value->id, 'name' => $value->localname);
566
    }
567
    return $roles;
568
}
569
570
function bigbluebuttonbn_get_role($id) {
571
    $roles = (array) role_get_names();
572
    if (is_numeric($id)) {
573
        return (object)$roles[$id];
574
    }
575
    foreach ($roles as $role) {
576
        if ($role->shortname == $id) {
577
            return $role;
578
        }
579
    }
580
}
581
582
function bigbluebuttonbn_role_unknown() {
583
    return array(
584
              "id" => "0",
585
              "name" => "",
586
              "shortname" => "unknown",
587
              "description" => "",
588
              "sortorder" => "0",
589
              "archetype" => "guest",
590
              "localname" => "Unknown"
591
            );
592
}
593
594
function bigbluebuttonbn_get_participant_data($context) {
595
    $data = array(
596
        'all' => array(
597
            'name' => get_string('mod_form_field_participant_list_type_all', 'bigbluebuttonbn'),
598
            'children' => []
599
          )
600
      );
601
    $data['role'] = array(
602
        'name' => get_string('mod_form_field_participant_list_type_role', 'bigbluebuttonbn'),
603
        'children' => bigbluebuttonbn_get_roles_select($context)
604
      );
605
    $data['user'] = array(
606
        'name' => get_string('mod_form_field_participant_list_type_user', 'bigbluebuttonbn'),
607
        'children' => bigbluebuttonbn_get_users_select($context)
608
      );
609
    return $data;
610
}
611
612
function bigbluebuttonbn_get_participant_list($bigbluebuttonbn, $context) {
613
    if ($bigbluebuttonbn == null) {
614
        return bigbluebuttonbn_get_participant_list_default($context);
615
    }
616
    return bigbluebuttonbn_get_participant_rules_encoded($bigbluebuttonbn);
617
}
618
619
function bigbluebuttonbn_get_participant_list_default($context) {
620
    global $USER;
621
    $participantlistarray = array();
622
    $participantlistarray[] = array(
623
        'selectiontype' => 'all',
624
        'selectionid' => 'all',
625
        'role' => BIGBLUEBUTTONBN_ROLE_VIEWER);
626
    $moderatordefaults = explode(',', \mod_bigbluebuttonbn\locallib\config::get('participant_moderator_default'));
627
    foreach ($moderatordefaults as $moderatordefault) {
628
        if ($moderatordefault == 'owner') {
629
            if (is_enrolled($context, $USER->id)) {
630
                $participantlistarray[] = array(
631
                    'selectiontype' => 'user',
632
                    'selectionid' => $USER->id,
633
                    'role' => BIGBLUEBUTTONBN_ROLE_MODERATOR);
634
            }
635
            continue;
636
        }
637
        $participantlistarray[] = array(
638
              'selectiontype' => 'role',
639
              'selectionid' => $moderatordefault,
640
              'role' => BIGBLUEBUTTONBN_ROLE_MODERATOR);
641
    }
642
    return $participantlistarray;
643
}
644
645
function bigbluebuttonbn_get_participant_rules_encoded($bigbluebuttonbn) {
646
    $rules = json_decode($bigbluebuttonbn->participants, true);
647
    if (!is_array($rules)) {
648
        return array();
649
    }
650
    foreach ($rules as $key => $rule) {
651
        if ( $rule['selectiontype'] !== 'role' || is_numeric($rule['selectionid']) ) {
652
            continue;
653
        }
654
        $role = bigbluebuttonbn_get_role($rule['selectionid']);
655
        if ( $role == null ) {
656
            unset($rules[$key]);
657
            continue;
658
        }
659
        $rule['selectionid'] = $role->id;
660
        $rules[$key] = $rule;
661
    }
662
    return $rules;
663
}
664
665
function bigbluebuttonbn_get_participant_selection_data() {
666
    return [
667
        'type_options' => [
668
            'all' => get_string('mod_form_field_participant_list_type_all', 'bigbluebuttonbn'),
669
            'role' => get_string('mod_form_field_participant_list_type_role', 'bigbluebuttonbn'),
670
            'user' => get_string('mod_form_field_participant_list_type_user', 'bigbluebuttonbn'),
671
          ],
672
        'type_selected' => 'all',
673
        'options' => ['all' => '---------------'],
674
        'selected' => 'all',
675
      ];
676
}
677
678
function bigbluebuttonbn_is_moderator($context, $participants, $userid = null, $userroles = null) {
679
    global $USER;
680
    if (empty($participants)) {
681
        // The room that is being used comes from a previous version.
682
        return has_capability('mod/bigbluebuttonbn:moderate', $context);
683
    }
684
    $participantlist = json_decode($participants);
685
    if (!is_array($participantlist)) {
686
        return false;
687
    }
688
    if (empty($userid)) {
689
        $userid = $USER->id;
690
    }
691
    if (empty($userroles)) {
692
        $userroles = get_user_roles($context, $userid, true);
693
    }
694
    return bigbluebuttonbn_is_moderator_validator($participantlist, $userid , $userroles);
695
}
696
697
function bigbluebuttonbn_is_moderator_validator($participantlist, $userid , $userroles) {
698
    // Iterate participant rules.
699
    foreach ($participantlist as $participant) {
700
        if (bigbluebuttonbn_is_moderator_validate_rule($participant, $userid, $userroles)) {
701
            return true;
702
        }
703
    }
704
    return false;
705
}
706
707
function bigbluebuttonbn_is_moderator_validate_rule($participant, $userid, $userroles) {
708
    if ($participant->role == BIGBLUEBUTTONBN_ROLE_VIEWER) {
709
        return false;
710
    }
711
    // Looks for all configuration.
712
    if ($participant->selectiontype == 'all') {
713
        return true;
714
    }
715
    // Looks for users.
716
    if ($participant->selectiontype == 'user' && $participant->selectionid == $userid) {
717
        return true;
718
    }
719
    // Looks for roles.
720
    $role = bigbluebuttonbn_get_role($participant->selectionid);
721
    if (array_key_exists($role->id, $userroles)) {
722
        return true;
723
    }
724
    return false;
725
}
726
727
function bigbluebuttonbn_get_error_key($messagekey, $defaultkey = null) {
728
    if ($messagekey == 'checksumError') {
729
        return 'index_error_checksum';
730
    }
731
    if ($messagekey == 'maxConcurrent') {
732
        return 'view_error_max_concurrent';
733
    }
734
    return $defaultkey;
735
}
736
737
function bigbluebuttonbn_voicebridge_unique($voicebridge, $id = null) {
738
    global $DB;
739
    $isunique = true;
740
    if ($voicebridge != 0) {
741
        $table = 'bigbluebuttonbn';
742
        $select = 'voicebridge = '.$voicebridge;
743
        if ($id) {
744
            $select .= ' AND id <> '.$id;
745
        }
746
        if ($DB->get_records_select($table, $select)) {
747
            $isunique = false;
748
        }
749
    }
750
    return $isunique;
751
}
752
753
function bigbluebuttonbn_get_duration($closingtime) {
754
    $duration = 0;
755
    $now = time();
756
    if ($closingtime > 0 && $now < $closingtime) {
757
        $duration = ceil(($closingtime - $now) / 60);
758
        $compensationtime = intval((int)\mod_bigbluebuttonbn\locallib\config::get('scheduled_duration_compensation'));
759
        $duration = intval($duration) + $compensationtime;
760
    }
761
    return $duration;
762
}
763
764
function bigbluebuttonbn_get_presentation_array($context, $presentation, $id = null) {
765
    if (empty($presentation)) {
766
        return array('url' => null, 'name' => null, 'icon' => null, 'mimetype_description' => null);
767
    }
768
    $fs = get_file_storage();
769
    $files = $fs->get_area_files($context->id, 'mod_bigbluebuttonbn', 'presentation', 0,
770
        'itemid, filepath, filename', false);
771
    if (count($files) == 0) {
772
        return array('url' => null, 'name' => null, 'icon' => null, 'mimetype_description' => null);
773
    }
774
    $file = reset($files);
775
    unset($files);
776
    $pnoncevalue = null;
777
    if (!is_null($id)) {
778
        // Create the nonce component for granting a temporary public access.
779
        $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'mod_bigbluebuttonbn',
780
            'presentation_cache');
781
        $pnoncekey = sha1($id);
782
        /* The item id was adapted for granting public access to the presentation once in order
783
         * to allow BigBlueButton to gather the file. */
784
        $pnoncevalue = bigbluebuttonbn_generate_nonce();
785
        $cache->set($pnoncekey, array('value' => $pnoncevalue, 'counter' => 0));
786
    }
787
    $url = moodle_url::make_pluginfile_url($file->get_contextid(), $file->get_component(),
788
        $file->get_filearea(), $pnoncevalue, $file->get_filepath(), $file->get_filename());
789
790
    return array('name' => $file->get_filename(), 'icon' => file_file_icon($file, 24),
791
            'url' => $url->out(false), 'mimetype_description' => get_mimetype_description($file));
792
}
793
794
795
function bigbluebuttonbn_generate_nonce() {
796
    $mt = microtime();
797
    $rand = mt_rand();
798
    return md5($mt.$rand);
799
}
800
801
function bigbluebuttonbn_random_password($length = 8) {
802
    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_-=+;:,.?';
803
    $password = substr(str_shuffle($chars), 0, $length);
804
    return $password;
805
}
806
807
function bigbluebuttonbn_events() {
808
    return array(
809
        (string) BIGBLUEBUTTON_EVENT_ACTIVITY_VIEWED,
810
        (string) BIGBLUEBUTTON_EVENT_ACTIVITY_MANAGEMENT_VIEWED,
811
        (string) BIGBLUEBUTTON_EVENT_LIVE_SESSION,
812
        (string) BIGBLUEBUTTON_EVENT_MEETING_CREATED,
813
        (string) BIGBLUEBUTTON_EVENT_MEETING_ENDED,
814
        (string) BIGBLUEBUTTON_EVENT_MEETING_JOINED,
815
        (string) BIGBLUEBUTTON_EVENT_MEETING_LEFT,
816
        (string) BIGBLUEBUTTON_EVENT_RECORDING_DELETED,
817
        (string) BIGBLUEBUTTON_EVENT_RECORDING_IMPORTED,
818
        (string) BIGBLUEBUTTON_EVENT_RECORDING_PROTECTED,
819
        (string) BIGBLUEBUTTON_EVENT_RECORDING_PUBLISHED,
820
        (string) BIGBLUEBUTTON_EVENT_RECORDING_UNPROTECTED,
821
        (string) BIGBLUEBUTTON_EVENT_RECORDING_UNPUBLISHED,
822
        (string) BIGBLUEBUTTON_EVENT_RECORDING_EDITED,
823
        (string) BIGBLUEBUTTON_EVENT_RECORDING_VIEWED
824
    );
825
}
826
827
function bigbluebuttonbn_events_action() {
828
    return array(
829
        'view' => (string) BIGBLUEBUTTON_EVENT_ACTIVITY_VIEWED,
830
        'view_management' => (string) BIGBLUEBUTTON_EVENT_ACTIVITY_MANAGEMENT_VIEWED,
831
        'live_action' => (string) BIGBLUEBUTTON_EVENT_LIVE_SESSION,
832
        'meeting_create' => (string) BIGBLUEBUTTON_EVENT_MEETING_CREATED,
833
        'meeting_end' => (string) BIGBLUEBUTTON_EVENT_MEETING_ENDED,
834
        'meeting_join' => (string) BIGBLUEBUTTON_EVENT_MEETING_JOINED,
835
        'meeting_left' => (string) BIGBLUEBUTTON_EVENT_MEETING_LEFT,
836
        'recording_delete' => (string) BIGBLUEBUTTON_EVENT_RECORDING_DELETED,
837
        'recording_import' => (string) BIGBLUEBUTTON_EVENT_RECORDING_IMPORTED,
838
        'recording_protect' => (string) BIGBLUEBUTTON_EVENT_RECORDING_PROTECTED,
839
        'recording_publish' => (string) BIGBLUEBUTTON_EVENT_RECORDING_PUBLISHED,
840
        'recording_unprotect' => (string) BIGBLUEBUTTON_EVENT_RECORDING_UNPROTECTED,
841
        'recording_unpublish' => (string) BIGBLUEBUTTON_EVENT_RECORDING_UNPUBLISHED,
842
        'recording_edit' => (string) BIGBLUEBUTTON_EVENT_RECORDING_EDITED,
843
        'recording_play' => (string) BIGBLUEBUTTON_EVENT_RECORDING_VIEWED
844
    );
845
}
846
847
function bigbluebuttonbn_event_log_standard($eventtype, $bigbluebuttonbn, $cm, $options = []) {
848
    $events = bigbluebuttonbn_events();
849
    if (!in_array($eventtype, $events)) {
850
        // No log will be created.
851
        return;
852
    }
853
    $context = context_module::instance($cm->id);
854
    $eventproperties = array('context' => $context, 'objectid' => $bigbluebuttonbn->id);
855
    if (array_key_exists('timecreated', $options)) {
856
        $eventproperties['timecreated'] = $options['timecreated'];
857
    }
858
    if (array_key_exists('userid', $options)) {
859
        $eventproperties['userid'] = $options['userid'];
860
    }
861
    if (array_key_exists('other', $options)) {
862
        $eventproperties['other'] = $options['other'];
863
    }
864
    $event = call_user_func_array('\mod_bigbluebuttonbn\event\bigbluebuttonbn_'.$eventtype.'::create',
865
      array($eventproperties));
866
    $event->trigger();
867
}
868
869
function bigbluebuttonbn_event_log($eventtype, $bigbluebuttonbn, $cm, $options = []) {
870
    bigbluebuttonbn_event_log_standard($eventtype, $bigbluebuttonbn, $cm, $options);
871
}
872
873
function bigbluebuttonbn_live_session_event_log($event, $bigbluebuttonbn, $cm) {
874
    bigbluebuttonbn_event_log_standard(BIGBLUEBUTTON_EVENT_LIVE_SESSION, $bigbluebuttonbn, $cm,
875
        ['timecreated' => $event->timestamp, 'userid' => $event->user, 'other' => $event->event]);
876
}
877
878
/**
879
 * @param string $meetingid
880
 * @param bool $ismoderator
881
 */
882
function bigbluebuttonbn_participant_joined($meetingid, $ismoderator) {
883
    $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'mod_bigbluebuttonbn', 'meetings_cache');
884
    $result = $cache->get($meetingid);
885
    $meetinginfo = json_decode($result['meeting_info']);
886
    $meetinginfo->participantCount += 1;
887
    if ($ismoderator) {
888
        $meetinginfo->moderatorCount += 1;
889
    }
890
    $cache->set($meetingid, array('creation_time' => $result['creation_time'],
891
        'meeting_info' => json_encode($meetinginfo)));
892
}
893
894
/**
895
 * @param string $meetingid
896
 * @param boolean $forced
897
 */
898
function bigbluebuttonbn_get_meeting_info($meetingid, $forced = false) {
899
    $cachettl = (int)\mod_bigbluebuttonbn\locallib\config::get('waitformoderator_cache_ttl');
900
    $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'mod_bigbluebuttonbn', 'meetings_cache');
901
    $result = $cache->get($meetingid);
902
    $now = time();
903
    if (!$forced && isset($result) && $now < ($result['creation_time'] + $cachettl)) {
904
        // Use the value in the cache.
905
        return (array) json_decode($result['meeting_info']);
906
    }
907
    // Ping again and refresh the cache.
908
    $meetinginfo = (array) bigbluebuttonbn_wrap_xml_load_file(
909
        \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('getMeetingInfo', ['meetingID' => $meetingid])
910
      );
911
    $cache->set($meetingid, array('creation_time' => time(), 'meeting_info' => json_encode($meetinginfo)));
912
    return $meetinginfo;
913
}
914
915
/**
916
 * @param string $id
917
 * @param boolean $publish
918
 */
919 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...
920
    global $DB;
921
    // Locate the record to be updated.
922
    $record = $DB->get_record('bigbluebuttonbn_logs', array('id' => $id));
923
    $meta = json_decode($record->meta, true);
924
    // Prepare data for the update.
925
    $meta['recording']['published'] = ($publish) ? 'true' : 'false';
926
    $record->meta = json_encode($meta);
927
    // Proceed with the update.
928
    $DB->update_record('bigbluebuttonbn_logs', $record);
929
    return true;
930
}
931
932
/**
933
 * @param string $id
934
 */
935
function bigbluebuttonbn_delete_recording_imported($id) {
936
    global $DB;
937
    // Execute delete.
938
    $DB->delete_records('bigbluebuttonbn_logs', array('id' => $id));
939
    return true;
940
}
941
942
/**
943
 * @param string $id
944
 * @param array $params ['key'=>param_key, 'value']
945
 */
946
function bigbluebuttonbn_update_recording_imported($id, $params) {
947
    global $DB;
948
    // Locate the record to be updated.
949
    $record = $DB->get_record('bigbluebuttonbn_logs', array('id' => $id));
950
    $meta = json_decode($record->meta, true);
951
    // Prepare data for the update.
952
    $meta['recording'] = $params + $meta['recording'];
953
    $record->meta = json_encode($meta);
954
    // Proceed with the update.
955
    if (!$DB->update_record('bigbluebuttonbn_logs', $record)) {
956
        return false;
957
    }
958
    return true;
959
}
960
961
/**
962
 * @param string $id
963
 * @param boolean $protect
964
 */
965 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...
966
    global $DB;
967
    // Locate the record to be updated.
968
    $record = $DB->get_record('bigbluebuttonbn_logs', array('id' => $id));
969
    $meta = json_decode($record->meta, true);
970
    // Prepare data for the update.
971
    $meta['recording']['protected'] = ($protect) ? 'true' : 'false';
972
    $record->meta = json_encode($meta);
973
    // Proceed with the update.
974
    $DB->update_record('bigbluebuttonbn_logs', $record);
975
    return true;
976
}
977
978
/**
979
 * @param string $meetingid
980
 * @param string $configxml
981
 */
982
function bigbluebuttonbn_set_config_xml_params($meetingid, $configxml) {
983
    $params = 'configXML='.urlencode($configxml).'&meetingID='.urlencode($meetingid);
984
    $configxmlparams = $params.'&checksum='.sha1('setConfigXML'.$params.\mod_bigbluebuttonbn\locallib\config::get('shared_secret'));
985
    return $configxmlparams;
986
}
987
988
/**
989
 * @param string $meetingid
990
 * @param string $configxml
991
 */
992
function bigbluebuttonbn_set_config_xml($meetingid, $configxml) {
993
    $urldefaultconfig = \mod_bigbluebuttonbn\locallib\config::get('server_url').'api/setConfigXML?';
994
    $configxmlparams = bigbluebuttonbn_set_config_xml_params($meetingid, $configxml);
995
    $xml = bigbluebuttonbn_wrap_xml_load_file($urldefaultconfig, BIGBLUEBUTTONBN_METHOD_POST,
996
        $configxmlparams, 'application/x-www-form-urlencoded');
997
    return $xml;
998
}
999
1000
/**
1001
 * @param string $meetingid
1002
 * @param string $configxml
1003
 */
1004
function bigbluebuttonbn_set_config_xml_array($meetingid, $configxml) {
1005
    $configxml = bigbluebuttonbn_setConfigXML($meetingid, $configxml);
1006
    $configxmlarray = (array) $configxml;
1007
    if ($configxmlarray['returncode'] != 'SUCCESS') {
1008
        debugging('BigBlueButton was not able to set the custom config.xml file', DEBUG_DEVELOPER);
1009
        return '';
1010
    }
1011
    return $configxmlarray['configToken'];
1012
}
1013
1014
function bigbluebuttonbn_get_recording_data_row($bbbsession, $recording, $tools = ['protect', 'publish', 'delete']) {
1015
    if (!$bbbsession['managerecordings'] && $recording['published'] != 'true') {
1016
        return;
1017
    }
1018
    $editable = bigbluebuttonbn_get_recording_data_row_editable($bbbsession);
1019
    $row = new stdClass();
1020
    // Set recording_types.
1021
    $row->recording = bigbluebuttonbn_get_recording_data_row_types($recording, $bbbsession['bigbluebuttonbn']->id);
1022
    // Set activity name.
1023
    $row->activity = bigbluebuttonbn_get_recording_data_row_meta_activity($recording, $editable);
1024
    // Set activity description.
1025
    $row->description = bigbluebuttonbn_get_recording_data_row_meta_description($recording, $editable);
1026
    // Set recording_preview.
1027
    $row->preview = bigbluebuttonbn_get_recording_data_row_preview($recording);
1028
    // Set date.
1029
    $row->date = bigbluebuttonbn_get_recording_data_row_date($recording);
1030
    // Set formatted date.
1031
    $row->date_formatted = bigbluebuttonbn_get_recording_data_row_date_formatted($row->date);
1032
    // Set formatted duration.
1033
    $row->duration_formatted = $row->duration = bigbluebuttonbn_get_recording_data_row_duration($recording);
1034
    // Set actionbar, if user is allowed to manage recordings.
1035
    if ($bbbsession['managerecordings']) {
1036
        $row->actionbar = bigbluebuttonbn_get_recording_data_row_actionbar($recording, $tools);
1037
    }
1038
    return $row;
1039
}
1040
1041
function bigbluebuttonbn_get_recording_data_row_editable($bbbsession) {
1042
    return ($bbbsession['managerecordings'] && (double)$bbbsession['serverversion'] >= 1.0);
1043
}
1044
1045
function bigbluebuttonbn_get_recording_data_row_date($recording) {
1046
    if (!isset($recording['startTime'])) {
1047
        return 0;
1048
    }
1049
    return floatval($recording['startTime']);
1050
}
1051
1052
function bigbluebuttonbn_get_recording_data_row_date_formatted($starttime) {
1053
    global $USER;
1054
    $starttime = $starttime - ($starttime % 1000);
1055
    // Set formatted date.
1056
    $dateformat = get_string('strftimerecentfull', 'langconfig').' %Z';
1057
    return userdate($starttime / 1000, $dateformat, usertimezone($USER->timezone));
1058
}
1059
1060
function bigbluebuttonbn_get_recording_data_row_duration($recording) {
1061
    $firstplayback = array_values($recording['playbacks'])[0];
1062
    $length = 0;
1063
    if (isset($firstplayback['length'])) {
1064
        $length = $firstplayback['length'];
1065
    }
1066
    return intval($length);
1067
}
1068
1069
function bigbluebuttonbn_get_recording_data_row_actionbar($recording, $tools) {
1070
    $actionbar = '';
1071
    foreach ($tools as $tool) {
1072
        if ( $tool == 'protect' && !isset($recording['protected']) ) {
1073
            continue;
1074
        }
1075
        $buttonpayload = bigbluebuttonbn_get_recording_data_row_actionbar_payload($recording, $tool);
1076
        $actionbar .= bigbluebuttonbn_actionbar_render_button($recording, $buttonpayload);
1077
    }
1078
    $head = html_writer::start_tag('div', array(
1079
        'id' => 'recording-actionbar-' . $recording['recordID'],
1080
        'data-recordingid' => $recording['recordID'],
1081
        'data-meetingid' => $recording['meetingID']));
1082
    $tail = html_writer::end_tag('div');
1083
    return $head . $actionbar . $tail;
1084
}
1085
1086
function bigbluebuttonbn_get_recording_data_row_actionbar_payload($recording, $tool) {
1087
    if ($tool == 'protect') {
1088
        return bigbluebuttonbn_get_recording_data_row_action_protect($recording['protected']);
1089
    }
1090
    if ($tool == 'publish') {
1091
        return bigbluebuttonbn_get_recording_data_row_action_publish($recording['published']);
1092
    }
1093
    return array('action' => $tool, 'tag' => $tool);
1094
}
1095
1096
function bigbluebuttonbn_get_recording_data_row_action_protect($protected) {
1097
    if ($protected == 'true') {
1098
        return array('action' => 'unprotect', 'tag' => 'lock');
1099
    }
1100
    return array('action' => 'protect', 'tag' => 'unlock');
1101
}
1102
1103
function bigbluebuttonbn_get_recording_data_row_action_publish($published) {
1104
    if ($published == 'true') {
1105
        return array('action' => 'unpublish', 'tag' => 'hide');
1106
    }
1107
    return array('action' => 'publish', 'tag' => 'show');
1108
}
1109
1110
function bigbluebuttonbn_get_recording_data_row_preview($recording) {
1111
    $visibility = '';
1112
    if ($recording['published'] === 'false') {
1113
        $visibility = 'hidden ';
1114
    }
1115
    $recordingpreview = html_writer::start_tag('div',
1116
        array('id' => 'preview-'.$recording['recordID'], $visibility => $visibility));
1117
    foreach ($recording['playbacks'] as $playback) {
1118
        if (isset($playback['preview'])) {
1119
            foreach ($playback['preview'] as $image) {
1120
                $recordingpreview .= html_writer::empty_tag('img',
1121
                    array('src' => trim($image['url']) . '?' . time(), 'class' => 'thumbnail'));
1122
            }
1123
            $recordingpreview .= html_writer::empty_tag('br');
1124
            $recordingpreview .= html_writer::tag('div',
1125
                get_string('view_recording_preview_help', 'bigbluebuttonbn'), array('class' => 'text-muted small'));
1126
            break;
1127
        }
1128
    }
1129
    $recordingpreview .= html_writer::end_tag('div');
1130
    return $recordingpreview;
1131
}
1132
1133
function bigbluebuttonbn_get_recording_data_row_types($recording, $bigbluebuttonbnid) {
1134
    $dataimported = 'false';
1135
    $title = '';
1136
    if (isset($recording['imported'])) {
1137
        $dataimported = 'true';
1138
        $title = get_string('view_recording_link_warning', 'bigbluebuttonbn');
1139
    }
1140
    $visibility = '';
1141
    if ($recording['published'] === 'false') {
1142
        $visibility = 'hidden ';
1143
    }
1144
    $id = 'playbacks-'.$recording['recordID'];
1145
    $recordingtypes = html_writer::start_tag('div', array('id' => $id, 'data-imported' => $dataimported,
1146
          'data-meetingid' => $recording['meetingID'], 'data-recordingid' => $recording['recordID'],
1147
          'title' => $title, $visibility => $visibility));
1148
    foreach ($recording['playbacks'] as $playback) {
1149
        $recordingtypes .= bigbluebuttonbn_get_recording_data_row_type($recording, $bigbluebuttonbnid,
1150
            $playback).'&#32;';
1151
    }
1152
    $recordingtypes .= html_writer::end_tag('div');
1153
    return $recordingtypes;
1154
}
1155
1156
function bigbluebuttonbn_get_recording_data_row_type($recording, $bigbluebuttonbnid, $playback) {
1157
    global $CFG, $OUTPUT;
1158
    $title = get_string('view_recording_format_'.$playback['type'], 'bigbluebuttonbn');
1159
    $onclick = 'M.mod_bigbluebuttonbn.recordings.recording_play(this);';
1160
    $href = $CFG->wwwroot.'/mod/bigbluebuttonbn/bbb_view.php?action=play&bn='.$bigbluebuttonbnid.
1161
      '&mid='.$recording['meetingID'].'&rid='.$recording['recordID'].'&rtype='.$playback['type'];
1162
    if (!isset($recording['imported']) || !isset($recording['protected']) || $recording['protected'] === 'false') {
1163
        $href .= '&href='.urlencode(trim($playback['url']));
1164
    }
1165
    $id = 'recording-play-' . $playback['type'] . '-' . $recording['recordID'];
1166
    $linkattributes = array(
1167
        'id' => $id,
1168
        'onclick' => $onclick,
1169
        'data-action' => 'play',
1170
        'data-target' => $playback['type'],
1171
        'data-href' => $href,
1172
        'class' => 'btn btn-sm btn-default'
1173
      );
1174
    return $OUTPUT->action_link('#', $title, null, $linkattributes);
1175
}
1176
1177
function bigbluebuttonbn_get_recording_data_row_meta_activity($recording, $editable) {
1178
    $payload = array();
1179 View Code Duplication
    if ($editable) {
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...
1180
        $payload = array('recordingid' => $recording['recordID'], 'meetingid' => $recording['meetingID'],
1181
            'action' => 'edit', 'tag' => 'edit',
1182
            'target' => 'name');
1183
    }
1184
    $oldsource = 'meta_contextactivity';
1185 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...
1186
        $metaname = trim($recording[$oldsource]);
1187
        return bigbluebuttonbn_get_recording_data_row_text($recording, $metaname, $oldsource, $payload);
1188
    }
1189
    $newsource = 'meta_bbb-recording-name';
1190 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...
1191
        $metaname = trim($recording[$newsource]);
1192
        return bigbluebuttonbn_get_recording_data_row_text($recording, $metaname, $newsource, $payload);
1193
    }
1194
    $metaname = trim($recording['meetingName']);
1195
    return bigbluebuttonbn_get_recording_data_row_text($recording, $metaname, $newsource, $payload);
1196
}
1197
1198
function bigbluebuttonbn_get_recording_data_row_meta_description($recording, $editable) {
1199
    $payload = array();
1200 View Code Duplication
    if ($editable) {
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...
1201
        $payload = array('recordingid' => $recording['recordID'], 'meetingid' => $recording['meetingID'],
1202
            'action' => 'edit', 'tag' => 'edit',
1203
            'target' => 'description');
1204
    }
1205
    $oldsource = 'meta_contextactivitydescription';
1206 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...
1207
        $metadescription = trim($recording[$oldsource]);
1208
        return bigbluebuttonbn_get_recording_data_row_text($recording, $metadescription, $oldsource, $payload);
1209
    }
1210
    $newsource = 'meta_bbb-recording-description';
1211
    if (isset($recording[$newsource])) {
1212
        $metadescription = trim($recording[$newsource]);
1213
        return bigbluebuttonbn_get_recording_data_row_text($recording, $metadescription, $newsource, $payload);
1214
    }
1215
    return bigbluebuttonbn_get_recording_data_row_text($recording, '', $newsource, $payload);
1216
}
1217
1218
function bigbluebuttonbn_get_recording_data_row_text($recording, $text, $source, $data) {
1219
    $htmltext = '<span>' . htmlentities($text) . '</span>';
1220
    if (empty($data)) {
1221
        return $htmltext;
1222
    }
1223
    $target = $data['action'] . '-' . $data['target'];
1224
    $id = 'recording-' . $target . '-' . $data['recordingid'];
1225
    $attributes = array('id' => $id, 'class' => 'quickeditlink col-md-20',
1226
        'data-recordingid' => $data['recordingid'], 'data-meetingid' => $data['meetingid'],
1227
        'data-target' => $data['target'], 'data-source' => $source);
1228
    $head = html_writer::start_tag('div', $attributes);
1229
    $tail = html_writer::end_tag('div');
1230
    $payload = array('action' => $data['action'], 'tag' => $data['tag'], 'target' => $data['target']);
1231
    $htmllink = bigbluebuttonbn_actionbar_render_button($recording, $payload);
1232
    return $head . $htmltext . $htmllink . $tail;
1233
}
1234
1235
function bigbluebuttonbn_actionbar_render_button($recording, $data) {
1236
    global $OUTPUT;
1237
    if (!$data) {
1238
        return '';
1239
    }
1240
    $target = $data['action'];
1241
    if (isset($data['target'])) {
1242
        $target .= '-' . $data['target'];
1243
    }
1244
    $id = 'recording-' . $target . '-' . $recording['recordID'];
1245
    $onclick = 'M.mod_bigbluebuttonbn.recordings.recording_'.$data['action'].'(this);';
1246
    if ((boolean)\mod_bigbluebuttonbn\locallib\config::get('recording_icons_enabled')) {
1247
        // With icon for $manageaction.
1248
        $iconattributes = array('id' => $id, 'class' => 'iconsmall');
1249
        $icon = new pix_icon('i/'.$data['tag'],
1250
            get_string('view_recording_list_actionbar_' . $data['action'], 'bigbluebuttonbn'),
1251
            'moodle', $iconattributes);
1252
        $linkattributes = array(
1253
            'id' => $id,
1254
            'onclick' => $onclick,
1255
            'data-action' => $data['action'],
1256
            'data-links' => bigbluebuttonbn_get_count_recording_imported_instances($recording['recordID'])
1257
          );
1258
        return $OUTPUT->action_icon('#', $icon, null, $linkattributes, false);
1259
    }
1260
    // With text for $manageaction.
1261
    $linkattributes = array('title' => get_string($data['tag']), 'class' => 'btn btn-xs btn-danger',
1262
        'onclick' => $onclick);
1263
    return $OUTPUT->action_link('#', get_string($data['action']), null, $linkattributes);
1264
}
1265
1266
function bigbluebuttonbn_get_recording_columns($bbbsession) {
1267
    // Set strings to show.
1268
    $recording = get_string('view_recording_recording', 'bigbluebuttonbn');
1269
    $activity = get_string('view_recording_activity', 'bigbluebuttonbn');
1270
    $description = get_string('view_recording_description', 'bigbluebuttonbn');
1271
    $preview = get_string('view_recording_preview', 'bigbluebuttonbn');
1272
    $date = get_string('view_recording_date', 'bigbluebuttonbn');
1273
    $duration = get_string('view_recording_duration', 'bigbluebuttonbn');
1274
    $actionbar = get_string('view_recording_actionbar', 'bigbluebuttonbn');
1275
    // Initialize table headers.
1276
    $recordingsbncolumns = array(
1277
        array('key' => 'recording', 'label' => $recording, 'width' => '125px', 'allowHTML' => true),
1278
        array('key' => 'activity', 'label' => $activity, 'sortable' => true, 'width' => '175px', 'allowHTML' => true),
1279
        array('key' => 'description', 'label' => $description, 'sortable' => true, 'width' => '250px', 'allowHTML' => true),
1280
        array('key' => 'preview', 'label' => $preview, 'width' => '250px', 'allowHTML' => true),
1281
        array('key' => 'date', 'label' => $date, 'sortable' => true, 'width' => '225px', 'allowHTML' => true),
1282
        array('key' => 'duration', 'label' => $duration, 'width' => '50px'),
1283
        );
1284
    if ($bbbsession['managerecordings']) {
1285
        array_push($recordingsbncolumns, array('key' => 'actionbar', 'label' => $actionbar, 'width' => '120px',
1286
            'allowHTML' => true));
1287
    }
1288
    return $recordingsbncolumns;
1289
}
1290
1291
function bigbluebuttonbn_get_recording_data($bbbsession, $recordings, $tools = ['protect', 'publish', 'delete']) {
1292
    $tabledata = array();
1293
    // Build table content.
1294 View Code Duplication
    if (isset($recordings) && !array_key_exists('messageKey', $recordings)) {
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...
1295
        // There are recordings for this meeting.
1296
        foreach ($recordings as $recording) {
1297
            $row = bigbluebuttonbn_get_recording_data_row($bbbsession, $recording, $tools);
1298
            if ($row != null) {
1299
                array_push($tabledata, $row);
1300
            }
1301
        }
1302
    }
1303
    return $tabledata;
1304
}
1305
1306
function bigbluebuttonbn_get_recording_table($bbbsession, $recordings, $tools = ['protect', 'publish', 'delete']) {
1307
    // Set strings to show.
1308
    $recording = get_string('view_recording_recording', 'bigbluebuttonbn');
1309
    $description = get_string('view_recording_description', 'bigbluebuttonbn');
1310
    $date = get_string('view_recording_date', 'bigbluebuttonbn');
1311
    $duration = get_string('view_recording_duration', 'bigbluebuttonbn');
1312
    $actionbar = get_string('view_recording_actionbar', 'bigbluebuttonbn');
1313
    $playback = get_string('view_recording_playback', 'bigbluebuttonbn');
1314
    $preview = get_string('view_recording_preview', 'bigbluebuttonbn');
1315
    // Declare the table.
1316
    $table = new html_table();
1317
    $table->data = array();
1318
    // Initialize table headers.
1319
    $table->head = array($playback, $recording, $description, $preview, $date, $duration);
1320
    $table->align = array('left', 'left', 'left', 'left', 'left', 'center');
1321
    $table->size = array('', '', '', '', '', '');
1322
    if ($bbbsession['managerecordings']) {
1323
        $table->head[] = $actionbar;
1324
        $table->align[] = 'left';
1325
        $table->size[] = (count($tools) * 40) . 'px';
1326
    }
1327
    // Build table content.
1328 View Code Duplication
    if (isset($recordings) && !array_key_exists('messageKey', $recordings)) {
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...
1329
        // There are recordings for this meeting.
1330
        foreach ($recordings as $recording) {
1331
            if ( !bigbluebuttonbn_include_recording_table_row($bbbsession, $recording) ) {
1332
                continue;
1333
            }
1334
            bigbluebuttonbn_get_recording_table_row($bbbsession, $recording, $tools, $table);
1335
        }
1336
    }
1337
    return $table;
1338
}
1339
1340
function bigbluebuttonbn_get_recording_table_row($bbbsession, $recording, $tools, &$table) {
1341
    $rowdata = bigbluebuttonbn_get_recording_data_row($bbbsession, $recording, $tools);
1342
    if ($rowdata == null) {
1343
        return;
1344
    }
1345
    $row = new html_table_row();
1346
    $row->id = 'recording-td-'.$recording['recordID'];
1347
    $row->attributes['data-imported'] = 'false';
1348
    $texthead = '';
1349
    $texttail = '';
1350
    if (isset($recording['imported'])) {
1351
        $row->attributes['title'] = get_string('view_recording_link_warning', 'bigbluebuttonbn');
1352
        $row->attributes['data-imported'] = 'true';
1353
        $texthead = '<em>';
1354
        $texttail = '</em>';
1355
    }
1356
    $rowdata->date_formatted = str_replace(' ', '&nbsp;', $rowdata->date_formatted);
1357
    $row->cells = array(
1358
        $texthead . $rowdata->recording . $texttail,
1359
        $texthead . $rowdata->activity . $texttail, $texthead . $rowdata->description . $texttail,
1360
        $rowdata->preview, $texthead . $rowdata->date_formatted . $texttail,
1361
        $rowdata->duration_formatted
1362
      );
1363
    if ($bbbsession['managerecordings']) {
1364
        $row->cells[] = $rowdata->actionbar;
1365
    }
1366
    array_push($table->data, $row);
1367
}
1368
1369
function bigbluebuttonbn_include_recording_table_row($bbbsession, $recording) {
1370
    if ( isset($recording['imported']) || !isset($bbbsession['group']) || $recording['meetingID'] == $bbbsession['meetingid'] ) {
1371
        return true;
1372
    }
1373
    return false;
1374
}
1375
1376
function bigbluebuttonbn_send_notification_recording_ready($bigbluebuttonbn) {
1377
    $sender = get_admin();
1378
    // Prepare message.
1379
    $msg = new stdClass();
1380
    // Build the message_body.
1381
    $msg->activity_type = '';
1382
    $msg->activity_title = $bigbluebuttonbn->name;
1383
    $messagetext = '<p>'.get_string('email_body_recording_ready_for', 'bigbluebuttonbn').' '.
1384
        $msg->activity_type.' &quot;'.$msg->activity_title.'&quot; '.
1385
        get_string('email_body_recording_ready_is_ready', 'bigbluebuttonbn').'.</p>';
1386
    bigbluebuttonbn_send_notification($sender, $bigbluebuttonbn, $messagetext);
1387
}
1388
1389
function bigbluebuttonbn_is_bn_server() {
1390
    // Validates if the server may have extended capabilities.
1391
    $parsedurl = parse_url(\mod_bigbluebuttonbn\locallib\config::get('server_url'));
1392
    if (!isset($parsedurl['host'])) {
1393
        return false;
1394
    }
1395
    $h = $parsedurl['host'];
1396
    $hends = explode('.', $h);
1397
    $hendslength = count($hends);
1398
    return ($hends[$hendslength - 1] == 'com' && $hends[$hendslength - 2] == 'blindsidenetworks');
1399
}
1400
1401
function bigbluebuttonbn_import_get_courses_for_select(array $bbbsession) {
1402
    if ($bbbsession['administrator']) {
1403
        $courses = get_courses('all', 'c.id ASC', 'c.id,c.shortname,c.fullname');
1404
        // It includes the name of the site as a course (category 0), so remove the first one.
1405
        unset($courses['1']);
1406
    } else {
1407
        $courses = enrol_get_users_courses($bbbsession['userID'], false, 'id,shortname,fullname');
1408
    }
1409
    $coursesforselect = [];
1410
    foreach ($courses as $course) {
1411
        $coursesforselect[$course->id] = $course->fullname;
1412
    }
1413
    return $coursesforselect;
1414
}
1415
1416
function bigbluebutton_output_recording_table($bbbsession, $recordings, $tools = ['protect', 'publish', 'delete']) {
1417
    if (isset($recordings) && !empty($recordings)) {
1418
        // There are recordings for this meeting.
1419
        $table = bigbluebuttonbn_get_recording_table($bbbsession, $recordings, $tools);
1420
    }
1421
    if (!isset($table) || !isset($table->data)) {
1422
        // Render a table qith "No recordings".
1423
        return html_writer::div(get_string('view_message_norecordings', 'bigbluebuttonbn'), '',
1424
            array('id' => 'bigbluebuttonbn_html_table'));
1425
    }
1426
    // Render the table.
1427
    return html_writer::div(html_writer::table($table), '', array('id' => 'bigbluebuttonbn_html_table'));
1428
}
1429
1430
function bigbluebuttonbn_html2text($html, $len) {
1431
    $text = strip_tags($html);
1432
    $text = str_replace('&nbsp;', ' ', $text);
1433
    $text = substr($text, 0, $len);
1434
    if (strlen($text) > $len) {
1435
        $text .= '...';
1436
    }
1437
    return $text;
1438
}
1439
1440
/**
1441
 * helper function to obtain the tags linked to a bigbluebuttonbn activity
1442
 *
1443
 * @param string $id
1444
 *
1445
 * @return string containing the tags separated by commas
1446
 */
1447
function bigbluebuttonbn_get_tags($id) {
1448
    $tagsarray = core_tag_tag::get_item_tags_array('core', 'course_modules', $id);
1449
    return implode(',', $tagsarray);
1450
}
1451
1452
1453
/**
1454
 * helper function to define the sql used for gattering the bigbluebuttonbnids whose meetingids should be included
1455
 * in the getRecordings request
1456
 *
1457
 * @param string $courseid
1458
 * @param string $bigbluebuttonbnid
1459
 * @param bool   $subset
1460
 *
1461
 * @return string containing the sql used for getting the target bigbluebuttonbn instances
1462
 */
1463
function bigbluebuttonbn_get_recordings_sql_select($courseid, $bigbluebuttonbnid = null, $subset = true) {
1464
    if ($bigbluebuttonbnid === null) {
1465
        return "course = '{$courseid}'";
1466
    }
1467
    if ($subset) {
1468
        return "id = '{$bigbluebuttonbnid}'";
1469
    }
1470
    return "id <> '{$bigbluebuttonbnid}' AND course = '{$courseid}'";
1471
}
1472
1473
function bigbluebuttonbn_get_recordings_sql_selectdeleted($courseid, $bigbluebuttonbnid = null, $subset = true) {
1474
    if ($bigbluebuttonbnid === null) {
1475
        return "courseid = '{$courseid}' AND log = '".BIGBLUEBUTTONBN_LOG_EVENT_DELETE.
1476
            "' AND meta like '%has_recordings%' AND meta like '%true%'";
1477
    }
1478
    if ($subset) {
1479
        return "bigbluebuttonbnid = '{$bigbluebuttonbnid}' AND log = '".BIGBLUEBUTTONBN_LOG_EVENT_DELETE.
1480
            "' AND meta like '%has_recordings%' AND meta like '%true%'";
1481
    }
1482
    return "courseid = '{$courseid}' AND bigbluebuttonbnid <> '{$bigbluebuttonbnid}' AND log = '".
1483
        BIGBLUEBUTTONBN_LOG_EVENT_DELETE."' AND meta like '%has_recordings%' AND meta like '%true%'";
1484
}
1485
1486
function bigbluebuttonbn_get_allrecordings($courseid, $bigbluebuttonbnid = null, $subset = true,
1487
        $includedeleted = false) {
1488
        $recordings = bigbluebuttonbn_get_recordings($courseid, $bigbluebuttonbnid, $subset, $includedeleted);
1489
        $recordingsimported = bigbluebuttonbn_get_recordings_imported_array($courseid, $bigbluebuttonbnid, $subset);
1490
        return ($recordings + $recordingsimported);
1491
}
1492
1493
/**
1494
 * helper function to retrieve recordings from the BigBlueButton. The references are stored as events
1495
 * in bigbluebuttonbn_logs.
1496
 *
1497
 * @param string $courseid
1498
 * @param string $bigbluebuttonbnid
1499
 * @param bool   $subset
1500
 * @param bool   $includedeleted
1501
 *
1502
 * @return associative array containing the recordings indexed by recordID, each recording is also a
1503
 * non sequential associative array itself that corresponds to the actual recording in BBB
1504
 */
1505
function bigbluebuttonbn_get_recordings($courseid, $bigbluebuttonbnid = null, $subset = true,
1506
        $includedeleted = false) {
1507
    global $DB;
1508
    $select = bigbluebuttonbn_get_recordings_sql_select($courseid, $bigbluebuttonbnid, $subset);
1509
    $bigbluebuttonbns = $DB->get_records_select_menu('bigbluebuttonbn', $select, null, 'id', 'id, meetingid');
1510
    /* Consider logs from deleted bigbluebuttonbn instances whose meetingids should be included in
1511
     * the getRecordings request. */
1512
    if ($includedeleted) {
1513
        $selectdeleted = bigbluebuttonbn_get_recordings_sql_selectdeleted($courseid, $bigbluebuttonbnid, $subset);
1514
        $bigbluebuttonbnsdel = $DB->get_records_select_menu('bigbluebuttonbn_logs', $selectdeleted, null,
1515
            'bigbluebuttonbnid', 'bigbluebuttonbnid, meetingid');
1516
        if (!empty($bigbluebuttonbnsdel)) {
1517
            // Merge bigbluebuttonbnis from deleted instances, only keys are relevant.
1518
            // Artimetic merge is used in order to keep the keys.
1519
            $bigbluebuttonbns += $bigbluebuttonbnsdel;
1520
        }
1521
    }
1522
    // Gather the meetingids from bigbluebuttonbn logs that include a create with record=true.
1523
    if (empty($bigbluebuttonbns)) {
1524
        return array();
1525
    }
1526
    // Prepare select for loading records based on existent bigbluebuttonbns.
1527
    $sql = 'SELECT DISTINCT meetingid, bigbluebuttonbnid FROM {bigbluebuttonbn_logs} WHERE ';
1528
    $sql .= '(bigbluebuttonbnid='.implode(' OR bigbluebuttonbnid=', array_keys($bigbluebuttonbns)).')';
1529
    // Include only Create events and exclude those with record not true.
1530
    $sql .= ' AND log = ? AND meta LIKE ? AND meta LIKE ?';
1531
    // Execute select for loading records based on existent bigbluebuttonbns.
1532
    $records = $DB->get_records_sql_menu($sql, array(BIGBLUEBUTTONBN_LOG_EVENT_CREATE, '%record%', '%true%'));
1533
    // Get actual recordings.
1534
    return bigbluebuttonbn_get_recordings_array(array_keys($records));
1535
}
1536
1537
function bigbluebuttonbn_unset_existent_recordings_already_imported($recordings, $courseid, $bigbluebuttonbnid) {
1538
    $recordingsimported = bigbluebuttonbn_get_recordings_imported_array($courseid, $bigbluebuttonbnid, true);
1539
    foreach ($recordings as $key => $recording) {
1540
        if (isset($recordingsimported[$recording['recordID']])) {
1541
            unset($recordings[$key]);
1542
        }
1543
    }
1544
    return $recordings;
1545
}
1546
1547
function bigbluebuttonbn_get_count_recording_imported_instances($recordid) {
1548
    global $DB;
1549
    $sql = 'SELECT COUNT(DISTINCT id) FROM {bigbluebuttonbn_logs} WHERE log = ? AND meta LIKE ? AND meta LIKE ?';
1550
    return $DB->count_records_sql($sql, array(BIGBLUEBUTTONBN_LOG_EVENT_IMPORT, '%recordID%', "%{$recordid}%"));
1551
}
1552
1553
function bigbluebuttonbn_get_recording_imported_instances($recordid) {
1554
    global $DB;
1555
    $sql = 'SELECT * FROM {bigbluebuttonbn_logs} WHERE log = ? AND meta LIKE ? AND meta LIKE ?';
1556
    $recordingsimported = $DB->get_records_sql($sql, array(BIGBLUEBUTTONBN_LOG_EVENT_IMPORT, '%recordID%',
1557
        "%{$recordid}%"));
1558
    return $recordingsimported;
1559
}
1560
1561
function bigbluebuttonbn_get_instance_type_profiles() {
1562
    $instanceprofiles = array(
1563
            array('id' => BIGBLUEBUTTONBN_TYPE_ALL, 'name' => get_string('instance_type_default', 'bigbluebuttonbn'),
1564
                'features' => array('all')),
1565
            array('id' => BIGBLUEBUTTONBN_TYPE_ROOM_ONLY, 'name' => get_string('instance_type_room_only', 'bigbluebuttonbn'),
1566
                'features' => array('showroom', 'welcomemessage', 'voicebridge', 'waitformoderator', 'userlimit', 'recording',
1567
                    'sendnotifications', 'preuploadpresentation', 'permissions', 'schedule', 'groups')),
1568
            array('id' => BIGBLUEBUTTONBN_TYPE_RECORDING_ONLY, 'name' => get_string('instance_type_recording_only',
1569
                'bigbluebuttonbn'), 'features' => array('showrecordings', 'importrecordings')),
1570
    );
1571
    return $instanceprofiles;
1572
}
1573
1574
function bigbluebuttonbn_get_enabled_features($typeprofiles, $type = null) {
1575
    $enabledfeatures = array();
1576
    $features = $typeprofiles[0]['features'];
1577
    if (!is_null($type)) {
1578
        $features = $typeprofiles[$type]['features'];
1579
    }
1580
    $enabledfeatures['showroom'] = (in_array('all', $features) || in_array('showroom', $features));
1581
    $enabledfeatures['showrecordings'] = false;
1582
    $enabledfeatures['importrecordings'] = false;
1583
    // Evaluates if recordings are enabled for the Moodle site.
1584
    $enabledfeatures['showrecordings'] = (in_array('all', $features) || in_array('showrecordings', $features));
1585
    $enabledfeatures['importrecordings'] = (in_array('all', $features) || in_array('importrecordings', $features));
1586
    return $enabledfeatures;
1587
}
1588
1589
function bigbluebuttonbn_get_instance_profiles_array($profiles = null) {
1590
    if (is_null($profiles) || empty($profiles)) {
1591
        $profiles = bigbluebuttonbn_get_instance_type_profiles();
1592
    }
1593
    $profilesarray = array();
1594
    foreach ($profiles as $profile) {
1595
        $profilesarray += array("{$profile['id']}" => $profile['name']);
1596
    }
1597
    return $profilesarray;
1598
}
1599
1600
function bigbluebuttonbn_format_activity_time($time) {
1601
    $activitytime = '';
1602
    if ($time) {
1603
        $activitytime = calendar_day_representation($time).' '.
1604
          get_string('mod_form_field_notification_msg_at', 'bigbluebuttonbn').' '.
1605
          calendar_time_representation($time);
1606
    }
1607
    return $activitytime;
1608
}
1609
1610
function bigbluebuttonbn_get_strings_for_js() {
1611
    $locale = bigbluebuttonbn_get_locale();
1612
    $stringman = get_string_manager();
1613
    $strings = $stringman->load_component_strings('bigbluebuttonbn', $locale);
1614
    return $strings;
1615
}
1616
1617
function bigbluebuttonbn_get_locale() {
1618
    $lang = get_string('locale', 'core_langconfig');
1619
    return substr($lang, 0, strpos($lang, '.'));
1620
}
1621
1622
function bigbluebuttonbn_get_localcode() {
1623
    $locale = bigbluebuttonbn_get_locale();
1624
    return substr($locale, 0, strpos($locale, '_'));
1625
}
1626
1627
function bigbluebuttonbn_views_validator($id, $bigbluebuttonbnid) {
1628
    if ($id) {
1629
        return bigbluebuttonbn_views_instance_id($id);
1630
    }
1631
    if ($bigbluebuttonbnid) {
1632
        return bigbluebuttonbn_views_instance_bigbluebuttonbn($bigbluebuttonbnid);
1633
    }
1634
    return;
1635
}
1636
1637 View Code Duplication
function bigbluebuttonbn_views_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...
1638
    global $DB;
1639
    $cm = get_coursemodule_from_id('bigbluebuttonbn', $id, 0, false, MUST_EXIST);
1640
    $course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
1641
    $bigbluebuttonbn = $DB->get_record('bigbluebuttonbn', array('id' => $cm->instance), '*', MUST_EXIST);
1642
    return array('cm' => $cm, 'course' => $course, 'bigbluebuttonbn' => $bigbluebuttonbn);
1643
}
1644
1645 View Code Duplication
function bigbluebuttonbn_views_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...
1646
    global $DB;
1647
    $bigbluebuttonbn = $DB->get_record('bigbluebuttonbn', array('id' => $bigbluebuttonbnid), '*', MUST_EXIST);
1648
    $course = $DB->get_record('course', array('id' => $bigbluebuttonbn->course), '*', MUST_EXIST);
1649
    $cm = get_coursemodule_from_instance('bigbluebuttonbn', $bigbluebuttonbn->id, $course->id, false, MUST_EXIST);
1650
    return array('cm' => $cm, 'course' => $course, 'bigbluebuttonbn' => $bigbluebuttonbn);
1651
}
1652
1653
function bigbluebutonbn_settings_general(&$renderer) {
1654
    global $CFG;
1655
    // Configuration for BigBlueButton.
1656
    if ((boolean)\mod_bigbluebuttonbn\settings\renderer::section_general_shown()) {
1657
        $renderer->render_group_header('general');
1658
        $renderer->render_group_element('server_url', $renderer->render_group_element_text('server_url', BIGBLUEBUTTONBN_DEFAULT_SERVER_URL));
1659
        $renderer->render_group_element('shared_secret', $renderer->render_group_element_text('shared_secret', BIGBLUEBUTTONBN_DEFAULT_SHARED_SECRET));
1660
    }
1661
}
1662
1663
function bigbluebutonbn_settings_recordings(&$renderer) {
1664
    global $CFG;
1665
    // Evaluates if recordings are enabled for the Moodle site.
1666
    if (!(boolean)\mod_bigbluebuttonbn\locallib\config::recordings_enabled()) {
1667
        return;
1668
    }
1669
    // Configuration for 'recording' feature.
1670 View Code Duplication
    if ((boolean)\mod_bigbluebuttonbn\settings\renderer::section_record_meeting_shown()) {
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
        $renderer->render_group_header('recording');
1672
        $renderer->render_group_element('recording_default', $renderer->render_group_element_checkbox('recording_default', 1));
1673
        $renderer->render_group_element('recording_editable', $renderer->render_group_element_checkbox('recording_editable', 1));
1674
        $renderer->render_group_element('recording_icons_enabled', $renderer->render_group_element_checkbox('recording_icons_enabled', 1));
1675
    }
1676
    // Configuration for 'import recordings' feature.
1677 View Code Duplication
    if ((boolean)\mod_bigbluebuttonbn\settings\renderer::section_import_recordings_shown()) {
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...
1678
        $renderer->render_group_header('importrecordings');
1679
        $renderer->render_group_element('importrecordings_enabled', $renderer->render_group_element_checkbox('importrecordings_enabled', 0));
1680
        $renderer->render_group_element('importrecordings_from_deleted_enabled', $renderer->render_group_element_checkbox('importrecordings_from_deleted_enabled', 0));
1681
    }
1682
    // Configuration for 'show recordings' feature.
1683
    if ((boolean)\mod_bigbluebuttonbn\settings\renderer::section_show_recordings_shown()) {
1684
        $renderer->render_group_header('recordings');
1685
        $renderer->render_group_element('recordings_html_default', $renderer->render_group_element_checkbox('recordings_html_default', 1));
1686
        $renderer->render_group_element('recordings_html_editable', $renderer->render_group_element_checkbox('recordings_html_editable', 0));
1687
        $renderer->render_group_element('recordings_deleted_default', $renderer->render_group_element_checkbox('recordings_deleted_default', 1));
1688
        $renderer->render_group_element('recordings_deleted_editable', $renderer->render_group_element_checkbox('recordings_deleted_editable', 0));
1689
        $renderer->render_group_element('recordings_imported_default', $renderer->render_group_element_checkbox('recordings_imported_default', 0));
1690
        $renderer->render_group_element('recordings_imported_editable', $renderer->render_group_element_checkbox('recordings_imported_editable', 1));
1691
    }
1692
}
1693
1694
function bigbluebutonbn_settings_meetings(&$renderer) {
1695
    global $CFG;
1696
    // Configuration for wait for moderator feature.
1697
    if ((boolean)\mod_bigbluebuttonbn\settings\renderer::section_wait_moderator_shown()) {
1698
        $renderer->render_group_header('waitformoderator');
1699
        $renderer->render_group_element('waitformoderator_default', $renderer->render_group_element_checkbox('waitformoderator_default', 0));
1700
        $renderer->render_group_element('waitformoderator_editable', $renderer->render_group_element_checkbox('waitformoderator_editable', 1));
1701
        $renderer->render_group_element('waitformoderator_ping_interval', $renderer->render_group_element_text('waitformoderator_ping_interval', 10, PARAM_INT));
1702
        $renderer->render_group_element('waitformoderator_cache_ttl', $renderer->render_group_element_text('waitformoderator_cache_ttl', 60, PARAM_INT));
1703
    }
1704
    // Configuration for "static voice bridge" feature.
1705
    if ((boolean)\mod_bigbluebuttonbn\settings\renderer::section_static_voice_bridge_shown()) {
1706
        $renderer->render_group_header('voicebridge');
1707
        $renderer->render_group_element('voicebridge_editable', $renderer->render_group_element_checkbox('voicebridge_editable', 0));
1708
    }
1709
    // Configuration for "preupload presentation" feature.
1710
    if ((boolean)\mod_bigbluebuttonbn\settings\renderer::section_preupload_presentation_shown()) {
1711
        // This feature only works if curl is installed.
1712
        $preuploadpresentationdescrip = get_string('config_preuploadpresentation_description', 'bigbluebuttonbn');
1713
        if (!extension_loaded('curl')) {
1714
            $preuploadpresentationdescrip .= '<div class="form-defaultinfo">'.get_string('config_warning_curl_not_installed', 'bigbluebuttonbn').'</div><br>';
1715
        }
1716
        $renderer->render_group_header('preuploadpresentation', null, $preuploadpresentationdescrip);
1717
        if (extension_loaded('curl')) {
1718
            $renderer->render_group_element('preuploadpresentation_enabled', $renderer->render_group_element_checkbox('preuploadpresentation_enabled', 0));
1719
        }
1720
    }
1721
    // Configuration for "user limit" feature.
1722 View Code Duplication
    if ((boolean)\mod_bigbluebuttonbn\settings\renderer::section_user_limit_shown()) {
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...
1723
        $renderer->render_group_header('userlimit');
1724
        $renderer->render_group_element('userlimit_default', $renderer->render_group_element_text('userlimit_default', 0, PARAM_INT));
1725
        $renderer->render_group_element('userlimit_editable', $renderer->render_group_element_checkbox('userlimit_editable', 0));
1726
    }
1727
    // Configuration for "scheduled duration" feature.
1728 View Code Duplication
    if ((boolean)\mod_bigbluebuttonbn\settings\renderer::section_scheduled_duration_shown()) {
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...
1729
        $renderer->render_group_header('scheduled');
1730
        $renderer->render_group_element('scheduled_duration_enabled', $renderer->render_group_element_checkbox('scheduled_duration_enabled', 1));
1731
        $renderer->render_group_element('scheduled_duration_compensation', $renderer->render_group_element_text('scheduled_duration_compensation', 10, PARAM_INT));
1732
        $renderer->render_group_element('scheduled_pre_opening', $renderer->render_group_element_text('scheduled_pre_opening', 10, PARAM_INT));
1733
    }
1734
    // Configuration for defining the default role/user that will be moderator on new activities.
1735
    if ((boolean)\mod_bigbluebuttonbn\settings\renderer::section_moderator_default_shown()) {
1736
        $renderer->render_group_header('participant');
1737
        // UI for 'participants' feature.
1738
        $roles = bigbluebuttonbn_get_roles();
1739
        $owner = array('0' => get_string('mod_form_field_participant_list_type_owner', 'bigbluebuttonbn'));
1740
        $renderer->render_group_element('participant_moderator_default',
1741
            $renderer->render_group_element_configmultiselect('participant_moderator_default', array_keys($owner), array_merge($owner, $roles))
1742
          );
1743
    }
1744
    // Configuration for "send notifications" feature.
1745
    if ((boolean)\mod_bigbluebuttonbn\settings\renderer::section_send_notifications_shown()) {
1746
        $renderer->render_group_header('sendnotifications');
1747
        $renderer->render_group_element('sendnotifications_enabled', $renderer->render_group_element_checkbox('sendnotifications_enabled', 1));
1748
    }
1749
}
1750
1751
function bigbluebutonbn_settings_extended(&$renderer) {
1752
    global $CFG;
1753
    // Configuration for extended BN capabilities.
1754
    if (!bigbluebuttonbn_is_bn_server()) {
1755
        return;
1756
    }
1757
    // Configuration for 'notify users when recording ready' feature.
1758 View Code Duplication
    if ((boolean)\mod_bigbluebuttonbn\settings\renderer::section_settings_extended_shown()) {
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...
1759
        $renderer->render_group_header('extended_capabilities');
1760
        // UI for 'notify users when recording ready' feature.
1761
        $renderer->render_group_element('recordingready_enabled', $renderer->render_group_element_checkbox('recordingready_enabled', 0));
1762
        // UI for 'register meeting events' feature.
1763
        $renderer->render_group_element('meetingevents_enabled', $renderer->render_group_element_checkbox('meetingevents_enabled', 0));
1764
    }
1765
}
1766