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

locallib.php ➔ bigbluebuttonbn_end_meeting_if_running()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
17
/**
18
 * Internal library of functions for module BigBlueButtonBN.
19
 *
20
 * @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_end_meeting_if_running($bigbluebuttonbn) {
521
    // End the session associated with this instance (if it's running).
522
    $meetingid = $bigbluebuttonbn->meetingid.'-'.$bigbluebuttonbn->course.'-'.$bigbluebuttonbn->id;
523
    if (bigbluebuttonbn_is_meeting_running($meetingid)) {
524
        bigbluebuttonbn_end_meeting($meetingid, $bigbluebuttonbn->moderatorpass);
525
    }
526
}
527
528
function bigbluebuttonbn_get_user_roles($context, $userid) {
529
    global $DB;
530
    $userroles = get_user_roles($context, $userid);
531
    if ($userroles) {
532
        $where = '';
533
        foreach ($userroles as $value) {
534
            $where .= (empty($where) ? ' WHERE' : ' OR').' id='.$value->roleid;
535
        }
536
        $userroles = $DB->get_records_sql('SELECT * FROM {role}'.$where);
537
    }
538
    return $userroles;
539
}
540
541
function bigbluebuttonbn_get_guest_role() {
542
    $guestrole = get_guest_role();
543
    return array($guestrole->id => $guestrole);
544
}
545
546
function bigbluebuttonbn_get_users(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] = fullname($value);
550
    }
551
    return $users;
552
}
553
554
function bigbluebuttonbn_get_users_select(context $context = null) {
555
    $users = (array) get_enrolled_users($context, '', 0, 'u.*', null, 0, 0, true);
556
    foreach ($users as $key => $value) {
557
        $users[$key] = array('id' => $value->id, 'name' => fullname($value));
558
    }
559
    return $users;
560
}
561
562
function bigbluebuttonbn_get_roles(context $context = null) {
563
    $roles = (array) role_get_names($context);
564
    foreach ($roles as $key => $value) {
565
        $roles[$key] = $value->localname;
566
    }
567
    return $roles;
568
}
569
570
function bigbluebuttonbn_get_roles_select(context $context = null) {
571
    $roles = (array) role_get_names($context);
572
    foreach ($roles as $key => $value) {
573
        $roles[$key] = array('id' => $value->id, 'name' => $value->localname);
574
    }
575
    return $roles;
576
}
577
578
function bigbluebuttonbn_get_role($id) {
579
    $roles = (array) role_get_names();
580
    if (is_numeric($id)) {
581
        return (object)$roles[$id];
582
    }
583
    foreach ($roles as $role) {
584
        if ($role->shortname == $id) {
585
            return $role;
586
        }
587
    }
588
}
589
590
function bigbluebuttonbn_role_unknown() {
591
    return array(
592
              "id" => "0",
593
              "name" => "",
594
              "shortname" => "unknown",
595
              "description" => "",
596
              "sortorder" => "0",
597
              "archetype" => "guest",
598
              "localname" => "Unknown"
599
            );
600
}
601
602
function bigbluebuttonbn_get_participant_data($context) {
603
    $data = array(
604
        'all' => array(
605
            'name' => get_string('mod_form_field_participant_list_type_all', 'bigbluebuttonbn'),
606
            'children' => []
607
          )
608
      );
609
    $data['role'] = array(
610
        'name' => get_string('mod_form_field_participant_list_type_role', 'bigbluebuttonbn'),
611
        'children' => bigbluebuttonbn_get_roles_select($context)
612
      );
613
    $data['user'] = array(
614
        'name' => get_string('mod_form_field_participant_list_type_user', 'bigbluebuttonbn'),
615
        'children' => bigbluebuttonbn_get_users_select($context)
616
      );
617
    return $data;
618
}
619
620
function bigbluebuttonbn_get_participant_list($bigbluebuttonbn, $context) {
621
    if ($bigbluebuttonbn == null) {
622
        return bigbluebuttonbn_get_participant_list_default($context);
623
    }
624
    return bigbluebuttonbn_get_participant_rules_encoded($bigbluebuttonbn);
625
}
626
627
function bigbluebuttonbn_get_participant_list_default($context) {
628
    global $USER;
629
    $participantlistarray = array();
630
    $participantlistarray[] = array(
631
        'selectiontype' => 'all',
632
        'selectionid' => 'all',
633
        'role' => BIGBLUEBUTTONBN_ROLE_VIEWER);
634
    $moderatordefaults = explode(',', \mod_bigbluebuttonbn\locallib\config::get('participant_moderator_default'));
635
    foreach ($moderatordefaults as $moderatordefault) {
636
        if ($moderatordefault == 'owner') {
637
            if (is_enrolled($context, $USER->id)) {
638
                $participantlistarray[] = array(
639
                    'selectiontype' => 'user',
640
                    'selectionid' => $USER->id,
641
                    'role' => BIGBLUEBUTTONBN_ROLE_MODERATOR);
642
            }
643
            continue;
644
        }
645
        $participantlistarray[] = array(
646
              'selectiontype' => 'role',
647
              'selectionid' => $moderatordefault,
648
              'role' => BIGBLUEBUTTONBN_ROLE_MODERATOR);
649
    }
650
    return $participantlistarray;
651
}
652
653
function bigbluebuttonbn_get_participant_rules_encoded($bigbluebuttonbn) {
654
    $rules = json_decode($bigbluebuttonbn->participants, true);
655
    if (!is_array($rules)) {
656
        return array();
657
    }
658
    foreach ($rules as $key => $rule) {
659
        if ( $rule['selectiontype'] !== 'role' || is_numeric($rule['selectionid']) ) {
660
            continue;
661
        }
662
        $role = bigbluebuttonbn_get_role($rule['selectionid']);
663
        if ( $role == null ) {
664
            unset($rules[$key]);
665
            continue;
666
        }
667
        $rule['selectionid'] = $role->id;
668
        $rules[$key] = $rule;
669
    }
670
    return $rules;
671
}
672
673
function bigbluebuttonbn_get_participant_selection_data() {
674
    return [
675
        'type_options' => [
676
            'all' => get_string('mod_form_field_participant_list_type_all', 'bigbluebuttonbn'),
677
            'role' => get_string('mod_form_field_participant_list_type_role', 'bigbluebuttonbn'),
678
            'user' => get_string('mod_form_field_participant_list_type_user', 'bigbluebuttonbn'),
679
          ],
680
        'type_selected' => 'all',
681
        'options' => ['all' => '---------------'],
682
        'selected' => 'all',
683
      ];
684
}
685
686
function bigbluebuttonbn_is_moderator($context, $participants, $userid = null, $userroles = null) {
687
    global $USER;
688
    if (empty($participants)) {
689
        // The room that is being used comes from a previous version.
690
        return has_capability('mod/bigbluebuttonbn:moderate', $context);
691
    }
692
    $participantlist = json_decode($participants);
693
    if (!is_array($participantlist)) {
694
        return false;
695
    }
696
    if (empty($userid)) {
697
        $userid = $USER->id;
698
    }
699
    if (empty($userroles)) {
700
        $userroles = get_user_roles($context, $userid, true);
701
    }
702
    return bigbluebuttonbn_is_moderator_validator($participantlist, $userid , $userroles);
703
}
704
705
function bigbluebuttonbn_is_moderator_validator($participantlist, $userid , $userroles) {
706
    // Iterate participant rules.
707
    foreach ($participantlist as $participant) {
708
        if (bigbluebuttonbn_is_moderator_validate_rule($participant, $userid, $userroles)) {
709
            return true;
710
        }
711
    }
712
    return false;
713
}
714
715
function bigbluebuttonbn_is_moderator_validate_rule($participant, $userid, $userroles) {
716
    if ($participant->role == BIGBLUEBUTTONBN_ROLE_VIEWER) {
717
        return false;
718
    }
719
    // Looks for all configuration.
720
    if ($participant->selectiontype == 'all') {
721
        return true;
722
    }
723
    // Looks for users.
724
    if ($participant->selectiontype == 'user' && $participant->selectionid == $userid) {
725
        return true;
726
    }
727
    // Looks for roles.
728
    $role = bigbluebuttonbn_get_role($participant->selectionid);
729
    if (array_key_exists($role->id, $userroles)) {
730
        return true;
731
    }
732
    return false;
733
}
734
735
function bigbluebuttonbn_get_error_key($messagekey, $defaultkey = null) {
736
    if ($messagekey == 'checksumError') {
737
        return 'index_error_checksum';
738
    }
739
    if ($messagekey == 'maxConcurrent') {
740
        return 'view_error_max_concurrent';
741
    }
742
    return $defaultkey;
743
}
744
745
function bigbluebuttonbn_voicebridge_unique($voicebridge, $id = null) {
746
    global $DB;
747
    $isunique = true;
748
    if ($voicebridge != 0) {
749
        $table = 'bigbluebuttonbn';
750
        $select = 'voicebridge = '.$voicebridge;
751
        if ($id) {
752
            $select .= ' AND id <> '.$id;
753
        }
754
        if ($DB->get_records_select($table, $select)) {
755
            $isunique = false;
756
        }
757
    }
758
    return $isunique;
759
}
760
761
function bigbluebuttonbn_get_duration($closingtime) {
762
    $duration = 0;
763
    $now = time();
764
    if ($closingtime > 0 && $now < $closingtime) {
765
        $duration = ceil(($closingtime - $now) / 60);
766
        $compensationtime = intval((int)\mod_bigbluebuttonbn\locallib\config::get('scheduled_duration_compensation'));
767
        $duration = intval($duration) + $compensationtime;
768
    }
769
    return $duration;
770
}
771
772
function bigbluebuttonbn_get_presentation_array($context, $presentation, $id = null) {
773
    if (empty($presentation)) {
774
        return array('url' => null, 'name' => null, 'icon' => null, 'mimetype_description' => null);
775
    }
776
    $fs = get_file_storage();
777
    $files = $fs->get_area_files($context->id, 'mod_bigbluebuttonbn', 'presentation', 0,
778
        'itemid, filepath, filename', false);
779
    if (count($files) == 0) {
780
        return array('url' => null, 'name' => null, 'icon' => null, 'mimetype_description' => null);
781
    }
782
    $file = reset($files);
783
    unset($files);
784
    $pnoncevalue = null;
785
    if (!is_null($id)) {
786
        // Create the nonce component for granting a temporary public access.
787
        $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'mod_bigbluebuttonbn',
788
            'presentation_cache');
789
        $pnoncekey = sha1($id);
790
        /* The item id was adapted for granting public access to the presentation once in order
791
         * to allow BigBlueButton to gather the file. */
792
        $pnoncevalue = bigbluebuttonbn_generate_nonce();
793
        $cache->set($pnoncekey, array('value' => $pnoncevalue, 'counter' => 0));
794
    }
795
    $url = moodle_url::make_pluginfile_url($file->get_contextid(), $file->get_component(),
796
        $file->get_filearea(), $pnoncevalue, $file->get_filepath(), $file->get_filename());
797
798
    return array('name' => $file->get_filename(), 'icon' => file_file_icon($file, 24),
799
            'url' => $url->out(false), 'mimetype_description' => get_mimetype_description($file));
800
}
801
802
803
function bigbluebuttonbn_generate_nonce() {
804
    $mt = microtime();
805
    $rand = mt_rand();
806
    return md5($mt.$rand);
807
}
808
809
function bigbluebuttonbn_random_password($length = 8) {
810
    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_-=+;:,.?';
811
    $password = substr(str_shuffle($chars), 0, $length);
812
    return $password;
813
}
814
815
function bigbluebuttonbn_events() {
816
    return array(
817
        (string) BIGBLUEBUTTON_EVENT_ACTIVITY_VIEWED,
818
        (string) BIGBLUEBUTTON_EVENT_ACTIVITY_MANAGEMENT_VIEWED,
819
        (string) BIGBLUEBUTTON_EVENT_LIVE_SESSION,
820
        (string) BIGBLUEBUTTON_EVENT_MEETING_CREATED,
821
        (string) BIGBLUEBUTTON_EVENT_MEETING_ENDED,
822
        (string) BIGBLUEBUTTON_EVENT_MEETING_JOINED,
823
        (string) BIGBLUEBUTTON_EVENT_MEETING_LEFT,
824
        (string) BIGBLUEBUTTON_EVENT_RECORDING_DELETED,
825
        (string) BIGBLUEBUTTON_EVENT_RECORDING_IMPORTED,
826
        (string) BIGBLUEBUTTON_EVENT_RECORDING_PROTECTED,
827
        (string) BIGBLUEBUTTON_EVENT_RECORDING_PUBLISHED,
828
        (string) BIGBLUEBUTTON_EVENT_RECORDING_UNPROTECTED,
829
        (string) BIGBLUEBUTTON_EVENT_RECORDING_UNPUBLISHED,
830
        (string) BIGBLUEBUTTON_EVENT_RECORDING_EDITED,
831
        (string) BIGBLUEBUTTON_EVENT_RECORDING_VIEWED
832
    );
833
}
834
835
function bigbluebuttonbn_events_action() {
836
    return array(
837
        'view' => (string) BIGBLUEBUTTON_EVENT_ACTIVITY_VIEWED,
838
        'view_management' => (string) BIGBLUEBUTTON_EVENT_ACTIVITY_MANAGEMENT_VIEWED,
839
        'live_action' => (string) BIGBLUEBUTTON_EVENT_LIVE_SESSION,
840
        'meeting_create' => (string) BIGBLUEBUTTON_EVENT_MEETING_CREATED,
841
        'meeting_end' => (string) BIGBLUEBUTTON_EVENT_MEETING_ENDED,
842
        'meeting_join' => (string) BIGBLUEBUTTON_EVENT_MEETING_JOINED,
843
        'meeting_left' => (string) BIGBLUEBUTTON_EVENT_MEETING_LEFT,
844
        'recording_delete' => (string) BIGBLUEBUTTON_EVENT_RECORDING_DELETED,
845
        'recording_import' => (string) BIGBLUEBUTTON_EVENT_RECORDING_IMPORTED,
846
        'recording_protect' => (string) BIGBLUEBUTTON_EVENT_RECORDING_PROTECTED,
847
        'recording_publish' => (string) BIGBLUEBUTTON_EVENT_RECORDING_PUBLISHED,
848
        'recording_unprotect' => (string) BIGBLUEBUTTON_EVENT_RECORDING_UNPROTECTED,
849
        'recording_unpublish' => (string) BIGBLUEBUTTON_EVENT_RECORDING_UNPUBLISHED,
850
        'recording_edit' => (string) BIGBLUEBUTTON_EVENT_RECORDING_EDITED,
851
        'recording_play' => (string) BIGBLUEBUTTON_EVENT_RECORDING_VIEWED
852
    );
853
}
854
855
function bigbluebuttonbn_event_log_standard($eventtype, $bigbluebuttonbn, $cm, $options = []) {
856
    $events = bigbluebuttonbn_events();
857
    if (!in_array($eventtype, $events)) {
858
        // No log will be created.
859
        return;
860
    }
861
    $context = context_module::instance($cm->id);
862
    $eventproperties = array('context' => $context, 'objectid' => $bigbluebuttonbn->id);
863
    if (array_key_exists('timecreated', $options)) {
864
        $eventproperties['timecreated'] = $options['timecreated'];
865
    }
866
    if (array_key_exists('userid', $options)) {
867
        $eventproperties['userid'] = $options['userid'];
868
    }
869
    if (array_key_exists('other', $options)) {
870
        $eventproperties['other'] = $options['other'];
871
    }
872
    $event = call_user_func_array('\mod_bigbluebuttonbn\event\bigbluebuttonbn_'.$eventtype.'::create',
873
      array($eventproperties));
874
    $event->trigger();
875
}
876
877
function bigbluebuttonbn_event_log($eventtype, $bigbluebuttonbn, $cm, $options = []) {
878
    bigbluebuttonbn_event_log_standard($eventtype, $bigbluebuttonbn, $cm, $options);
879
}
880
881
function bigbluebuttonbn_live_session_event_log($event, $bigbluebuttonbn, $cm) {
882
    bigbluebuttonbn_event_log_standard(BIGBLUEBUTTON_EVENT_LIVE_SESSION, $bigbluebuttonbn, $cm,
883
        ['timecreated' => $event->timestamp, 'userid' => $event->user, 'other' => $event->event]);
884
}
885
886
/**
887
 * @param string $meetingid
888
 * @param bool $ismoderator
889
 */
890
function bigbluebuttonbn_participant_joined($meetingid, $ismoderator) {
891
    $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'mod_bigbluebuttonbn', 'meetings_cache');
892
    $result = $cache->get($meetingid);
893
    $meetinginfo = json_decode($result['meeting_info']);
894
    $meetinginfo->participantCount += 1;
895
    if ($ismoderator) {
896
        $meetinginfo->moderatorCount += 1;
897
    }
898
    $cache->set($meetingid, array('creation_time' => $result['creation_time'],
899
        'meeting_info' => json_encode($meetinginfo)));
900
}
901
902
/**
903
 * @param string $meetingid
904
 * @param boolean $forced
905
 */
906
function bigbluebuttonbn_get_meeting_info($meetingid, $forced = false) {
907
    $cachettl = (int)\mod_bigbluebuttonbn\locallib\config::get('waitformoderator_cache_ttl');
908
    $cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'mod_bigbluebuttonbn', 'meetings_cache');
909
    $result = $cache->get($meetingid);
910
    $now = time();
911
    if (!$forced && isset($result) && $now < ($result['creation_time'] + $cachettl)) {
912
        // Use the value in the cache.
913
        return (array) json_decode($result['meeting_info']);
914
    }
915
    // Ping again and refresh the cache.
916
    $meetinginfo = (array) bigbluebuttonbn_wrap_xml_load_file(
917
        \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('getMeetingInfo', ['meetingID' => $meetingid])
918
      );
919
    $cache->set($meetingid, array('creation_time' => time(), 'meeting_info' => json_encode($meetinginfo)));
920
    return $meetinginfo;
921
}
922
923
/**
924
 * @param string $id
925
 * @param boolean $publish
926
 */
927 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...
928
    global $DB;
929
    // Locate the record to be updated.
930
    $record = $DB->get_record('bigbluebuttonbn_logs', array('id' => $id));
931
    $meta = json_decode($record->meta, true);
932
    // Prepare data for the update.
933
    $meta['recording']['published'] = ($publish) ? 'true' : 'false';
934
    $record->meta = json_encode($meta);
935
    // Proceed with the update.
936
    $DB->update_record('bigbluebuttonbn_logs', $record);
937
    return true;
938
}
939
940
/**
941
 * @param string $id
942
 */
943
function bigbluebuttonbn_delete_recording_imported($id) {
944
    global $DB;
945
    // Execute delete.
946
    $DB->delete_records('bigbluebuttonbn_logs', array('id' => $id));
947
    return true;
948
}
949
950
/**
951
 * @param string $id
952
 * @param array $params ['key'=>param_key, 'value']
953
 */
954
function bigbluebuttonbn_update_recording_imported($id, $params) {
955
    global $DB;
956
    // Locate the record to be updated.
957
    $record = $DB->get_record('bigbluebuttonbn_logs', array('id' => $id));
958
    $meta = json_decode($record->meta, true);
959
    // Prepare data for the update.
960
    $meta['recording'] = $params + $meta['recording'];
961
    $record->meta = json_encode($meta);
962
    // Proceed with the update.
963
    if (!$DB->update_record('bigbluebuttonbn_logs', $record)) {
964
        return false;
965
    }
966
    return true;
967
}
968
969
/**
970
 * @param string $id
971
 * @param boolean $protect
972
 */
973 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...
974
    global $DB;
975
    // Locate the record to be updated.
976
    $record = $DB->get_record('bigbluebuttonbn_logs', array('id' => $id));
977
    $meta = json_decode($record->meta, true);
978
    // Prepare data for the update.
979
    $meta['recording']['protected'] = ($protect) ? 'true' : 'false';
980
    $record->meta = json_encode($meta);
981
    // Proceed with the update.
982
    $DB->update_record('bigbluebuttonbn_logs', $record);
983
    return true;
984
}
985
986
/**
987
 * @param string $meetingid
988
 * @param string $configxml
989
 */
990
function bigbluebuttonbn_set_config_xml_params($meetingid, $configxml) {
991
    $params = 'configXML='.urlencode($configxml).'&meetingID='.urlencode($meetingid);
992
    $configxmlparams = $params.'&checksum='.sha1('setConfigXML'.$params.\mod_bigbluebuttonbn\locallib\config::get('shared_secret'));
993
    return $configxmlparams;
994
}
995
996
/**
997
 * @param string $meetingid
998
 * @param string $configxml
999
 */
1000
function bigbluebuttonbn_set_config_xml($meetingid, $configxml) {
1001
    $urldefaultconfig = \mod_bigbluebuttonbn\locallib\config::get('server_url').'api/setConfigXML?';
1002
    $configxmlparams = bigbluebuttonbn_set_config_xml_params($meetingid, $configxml);
1003
    $xml = bigbluebuttonbn_wrap_xml_load_file($urldefaultconfig, BIGBLUEBUTTONBN_METHOD_POST,
1004
        $configxmlparams, 'application/x-www-form-urlencoded');
1005
    return $xml;
1006
}
1007
1008
/**
1009
 * @param string $meetingid
1010
 * @param string $configxml
1011
 */
1012
function bigbluebuttonbn_set_config_xml_array($meetingid, $configxml) {
1013
    $configxml = bigbluebuttonbn_setConfigXML($meetingid, $configxml);
1014
    $configxmlarray = (array) $configxml;
1015
    if ($configxmlarray['returncode'] != 'SUCCESS') {
1016
        debugging('BigBlueButton was not able to set the custom config.xml file', DEBUG_DEVELOPER);
1017
        return '';
1018
    }
1019
    return $configxmlarray['configToken'];
1020
}
1021
1022
function bigbluebuttonbn_get_recording_data_row($bbbsession, $recording, $tools = ['protect', 'publish', 'delete']) {
1023
    if (!$bbbsession['managerecordings'] && $recording['published'] != 'true') {
1024
        return;
1025
    }
1026
    $editable = bigbluebuttonbn_get_recording_data_row_editable($bbbsession);
1027
    $row = new stdClass();
1028
    // Set recording_types.
1029
    $row->recording = bigbluebuttonbn_get_recording_data_row_types($recording, $bbbsession['bigbluebuttonbn']->id);
1030
    // Set activity name.
1031
    $row->activity = bigbluebuttonbn_get_recording_data_row_meta_activity($recording, $editable);
1032
    // Set activity description.
1033
    $row->description = bigbluebuttonbn_get_recording_data_row_meta_description($recording, $editable);
1034
    // Set recording_preview.
1035
    $row->preview = bigbluebuttonbn_get_recording_data_row_preview($recording);
1036
    // Set date.
1037
    $row->date = bigbluebuttonbn_get_recording_data_row_date($recording);
1038
    // Set formatted date.
1039
    $row->date_formatted = bigbluebuttonbn_get_recording_data_row_date_formatted($row->date);
1040
    // Set formatted duration.
1041
    $row->duration_formatted = $row->duration = bigbluebuttonbn_get_recording_data_row_duration($recording);
1042
    // Set actionbar, if user is allowed to manage recordings.
1043
    if ($bbbsession['managerecordings']) {
1044
        $row->actionbar = bigbluebuttonbn_get_recording_data_row_actionbar($recording, $tools);
1045
    }
1046
    return $row;
1047
}
1048
1049
function bigbluebuttonbn_get_recording_data_row_editable($bbbsession) {
1050
    return ($bbbsession['managerecordings'] && (double)$bbbsession['serverversion'] >= 1.0);
1051
}
1052
1053
function bigbluebuttonbn_get_recording_data_row_date($recording) {
1054
    if (!isset($recording['startTime'])) {
1055
        return 0;
1056
    }
1057
    return floatval($recording['startTime']);
1058
}
1059
1060
function bigbluebuttonbn_get_recording_data_row_date_formatted($starttime) {
1061
    global $USER;
1062
    $starttime = $starttime - ($starttime % 1000);
1063
    // Set formatted date.
1064
    $dateformat = get_string('strftimerecentfull', 'langconfig').' %Z';
1065
    return userdate($starttime / 1000, $dateformat, usertimezone($USER->timezone));
1066
}
1067
1068
function bigbluebuttonbn_get_recording_data_row_duration($recording) {
1069
    $firstplayback = array_values($recording['playbacks'])[0];
1070
    $length = 0;
1071
    if (isset($firstplayback['length'])) {
1072
        $length = $firstplayback['length'];
1073
    }
1074
    return intval($length);
1075
}
1076
1077
function bigbluebuttonbn_get_recording_data_row_actionbar($recording, $tools) {
1078
    $actionbar = '';
1079
    foreach ($tools as $tool) {
1080
        if ( $tool == 'protect' && !isset($recording['protected']) ) {
1081
            continue;
1082
        }
1083
        $buttonpayload = bigbluebuttonbn_get_recording_data_row_actionbar_payload($recording, $tool);
1084
        $actionbar .= bigbluebuttonbn_actionbar_render_button($recording, $buttonpayload);
1085
    }
1086
    $head = html_writer::start_tag('div', array(
1087
        'id' => 'recording-actionbar-' . $recording['recordID'],
1088
        'data-recordingid' => $recording['recordID'],
1089
        'data-meetingid' => $recording['meetingID']));
1090
    $tail = html_writer::end_tag('div');
1091
    return $head . $actionbar . $tail;
1092
}
1093
1094
function bigbluebuttonbn_get_recording_data_row_actionbar_payload($recording, $tool) {
1095
    if ($tool == 'protect') {
1096
        return bigbluebuttonbn_get_recording_data_row_action_protect($recording['protected']);
1097
    }
1098
    if ($tool == 'publish') {
1099
        return bigbluebuttonbn_get_recording_data_row_action_publish($recording['published']);
1100
    }
1101
    return array('action' => $tool, 'tag' => $tool);
1102
}
1103
1104
function bigbluebuttonbn_get_recording_data_row_action_protect($protected) {
1105
    if ($protected == 'true') {
1106
        return array('action' => 'unprotect', 'tag' => 'lock');
1107
    }
1108
    return array('action' => 'protect', 'tag' => 'unlock');
1109
}
1110
1111
function bigbluebuttonbn_get_recording_data_row_action_publish($published) {
1112
    if ($published == 'true') {
1113
        return array('action' => 'unpublish', 'tag' => 'hide');
1114
    }
1115
    return array('action' => 'publish', 'tag' => 'show');
1116
}
1117
1118
function bigbluebuttonbn_get_recording_data_row_preview($recording) {
1119
    $visibility = '';
1120
    if ($recording['published'] === 'false') {
1121
        $visibility = 'hidden ';
1122
    }
1123
    $recordingpreview = html_writer::start_tag('div',
1124
        array('id' => 'preview-'.$recording['recordID'], $visibility => $visibility));
1125
    foreach ($recording['playbacks'] as $playback) {
1126
        if (isset($playback['preview'])) {
1127
            foreach ($playback['preview'] as $image) {
1128
                $recordingpreview .= html_writer::empty_tag('img',
1129
                    array('src' => trim($image['url']) . '?' . time(), 'class' => 'thumbnail'));
1130
            }
1131
            $recordingpreview .= html_writer::empty_tag('br');
1132
            $recordingpreview .= html_writer::tag('div',
1133
                get_string('view_recording_preview_help', 'bigbluebuttonbn'), array('class' => 'text-muted small'));
1134
            break;
1135
        }
1136
    }
1137
    $recordingpreview .= html_writer::end_tag('div');
1138
    return $recordingpreview;
1139
}
1140
1141
function bigbluebuttonbn_get_recording_data_row_types($recording, $bigbluebuttonbnid) {
1142
    $dataimported = 'false';
1143
    $title = '';
1144
    if (isset($recording['imported'])) {
1145
        $dataimported = 'true';
1146
        $title = get_string('view_recording_link_warning', 'bigbluebuttonbn');
1147
    }
1148
    $visibility = '';
1149
    if ($recording['published'] === 'false') {
1150
        $visibility = 'hidden ';
1151
    }
1152
    $id = 'playbacks-'.$recording['recordID'];
1153
    $recordingtypes = html_writer::start_tag('div', array('id' => $id, 'data-imported' => $dataimported,
1154
          'data-meetingid' => $recording['meetingID'], 'data-recordingid' => $recording['recordID'],
1155
          'title' => $title, $visibility => $visibility));
1156
    foreach ($recording['playbacks'] as $playback) {
1157
        $recordingtypes .= bigbluebuttonbn_get_recording_data_row_type($recording, $bigbluebuttonbnid,
1158
            $playback).'&#32;';
1159
    }
1160
    $recordingtypes .= html_writer::end_tag('div');
1161
    return $recordingtypes;
1162
}
1163
1164
function bigbluebuttonbn_get_recording_data_row_type($recording, $bigbluebuttonbnid, $playback) {
1165
    global $CFG, $OUTPUT;
1166
    $title = get_string('view_recording_format_'.$playback['type'], 'bigbluebuttonbn');
1167
    $onclick = 'M.mod_bigbluebuttonbn.recordings.recording_play(this);';
1168
    $href = $CFG->wwwroot.'/mod/bigbluebuttonbn/bbb_view.php?action=play&bn='.$bigbluebuttonbnid.
1169
      '&mid='.$recording['meetingID'].'&rid='.$recording['recordID'].'&rtype='.$playback['type'];
1170
    if (!isset($recording['imported']) || !isset($recording['protected']) || $recording['protected'] === 'false') {
1171
        $href .= '&href='.urlencode(trim($playback['url']));
1172
    }
1173
    $id = 'recording-play-' . $playback['type'] . '-' . $recording['recordID'];
1174
    $linkattributes = array(
1175
        'id' => $id,
1176
        'onclick' => $onclick,
1177
        'data-action' => 'play',
1178
        'data-target' => $playback['type'],
1179
        'data-href' => $href,
1180
        'class' => 'btn btn-sm btn-default'
1181
      );
1182
    return $OUTPUT->action_link('#', $title, null, $linkattributes);
1183
}
1184
1185
function bigbluebuttonbn_get_recording_data_row_meta_activity($recording, $editable) {
1186
    $payload = array();
1187 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...
1188
        $payload = array('recordingid' => $recording['recordID'], 'meetingid' => $recording['meetingID'],
1189
            'action' => 'edit', 'tag' => 'edit',
1190
            'target' => 'name');
1191
    }
1192
    $oldsource = 'meta_contextactivity';
1193 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...
1194
        $metaname = trim($recording[$oldsource]);
1195
        return bigbluebuttonbn_get_recording_data_row_text($recording, $metaname, $oldsource, $payload);
1196
    }
1197
    $newsource = 'meta_bbb-recording-name';
1198 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...
1199
        $metaname = trim($recording[$newsource]);
1200
        return bigbluebuttonbn_get_recording_data_row_text($recording, $metaname, $newsource, $payload);
1201
    }
1202
    $metaname = trim($recording['meetingName']);
1203
    return bigbluebuttonbn_get_recording_data_row_text($recording, $metaname, $newsource, $payload);
1204
}
1205
1206
function bigbluebuttonbn_get_recording_data_row_meta_description($recording, $editable) {
1207
    $payload = array();
1208 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...
1209
        $payload = array('recordingid' => $recording['recordID'], 'meetingid' => $recording['meetingID'],
1210
            'action' => 'edit', 'tag' => 'edit',
1211
            'target' => 'description');
1212
    }
1213
    $oldsource = 'meta_contextactivitydescription';
1214 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...
1215
        $metadescription = trim($recording[$oldsource]);
1216
        return bigbluebuttonbn_get_recording_data_row_text($recording, $metadescription, $oldsource, $payload);
1217
    }
1218
    $newsource = 'meta_bbb-recording-description';
1219
    if (isset($recording[$newsource])) {
1220
        $metadescription = trim($recording[$newsource]);
1221
        return bigbluebuttonbn_get_recording_data_row_text($recording, $metadescription, $newsource, $payload);
1222
    }
1223
    return bigbluebuttonbn_get_recording_data_row_text($recording, '', $newsource, $payload);
1224
}
1225
1226
function bigbluebuttonbn_get_recording_data_row_text($recording, $text, $source, $data) {
1227
    $htmltext = '<span>' . htmlentities($text) . '</span>';
1228
    if (empty($data)) {
1229
        return $htmltext;
1230
    }
1231
    $target = $data['action'] . '-' . $data['target'];
1232
    $id = 'recording-' . $target . '-' . $data['recordingid'];
1233
    $attributes = array('id' => $id, 'class' => 'quickeditlink col-md-20',
1234
        'data-recordingid' => $data['recordingid'], 'data-meetingid' => $data['meetingid'],
1235
        'data-target' => $data['target'], 'data-source' => $source);
1236
    $head = html_writer::start_tag('div', $attributes);
1237
    $tail = html_writer::end_tag('div');
1238
    $payload = array('action' => $data['action'], 'tag' => $data['tag'], 'target' => $data['target']);
1239
    $htmllink = bigbluebuttonbn_actionbar_render_button($recording, $payload);
1240
    return $head . $htmltext . $htmllink . $tail;
1241
}
1242
1243
function bigbluebuttonbn_actionbar_render_button($recording, $data) {
1244
    global $OUTPUT;
1245
    if (!$data) {
1246
        return '';
1247
    }
1248
    $target = $data['action'];
1249
    if (isset($data['target'])) {
1250
        $target .= '-' . $data['target'];
1251
    }
1252
    $id = 'recording-' . $target . '-' . $recording['recordID'];
1253
    $onclick = 'M.mod_bigbluebuttonbn.recordings.recording_'.$data['action'].'(this);';
1254
    if ((boolean)\mod_bigbluebuttonbn\locallib\config::get('recording_icons_enabled')) {
1255
        // With icon for $manageaction.
1256
        $iconattributes = array('id' => $id, 'class' => 'iconsmall');
1257
        $icon = new pix_icon('i/'.$data['tag'],
1258
            get_string('view_recording_list_actionbar_' . $data['action'], 'bigbluebuttonbn'),
1259
            'moodle', $iconattributes);
1260
        $linkattributes = array(
1261
            'id' => $id,
1262
            'onclick' => $onclick,
1263
            'data-action' => $data['action'],
1264
            'data-links' => bigbluebuttonbn_get_count_recording_imported_instances($recording['recordID'])
1265
          );
1266
        return $OUTPUT->action_icon('#', $icon, null, $linkattributes, false);
1267
    }
1268
    // With text for $manageaction.
1269
    $linkattributes = array('title' => get_string($data['tag']), 'class' => 'btn btn-xs btn-danger',
1270
        'onclick' => $onclick);
1271
    return $OUTPUT->action_link('#', get_string($data['action']), null, $linkattributes);
1272
}
1273
1274
function bigbluebuttonbn_get_recording_columns($bbbsession) {
1275
    // Set strings to show.
1276
    $recording = get_string('view_recording_recording', 'bigbluebuttonbn');
1277
    $activity = get_string('view_recording_activity', 'bigbluebuttonbn');
1278
    $description = get_string('view_recording_description', 'bigbluebuttonbn');
1279
    $preview = get_string('view_recording_preview', 'bigbluebuttonbn');
1280
    $date = get_string('view_recording_date', 'bigbluebuttonbn');
1281
    $duration = get_string('view_recording_duration', 'bigbluebuttonbn');
1282
    $actionbar = get_string('view_recording_actionbar', 'bigbluebuttonbn');
1283
    // Initialize table headers.
1284
    $recordingsbncolumns = array(
1285
        array('key' => 'recording', 'label' => $recording, 'width' => '125px', 'allowHTML' => true),
1286
        array('key' => 'activity', 'label' => $activity, 'sortable' => true, 'width' => '175px', 'allowHTML' => true),
1287
        array('key' => 'description', 'label' => $description, 'sortable' => true, 'width' => '250px', 'allowHTML' => true),
1288
        array('key' => 'preview', 'label' => $preview, 'width' => '250px', 'allowHTML' => true),
1289
        array('key' => 'date', 'label' => $date, 'sortable' => true, 'width' => '225px', 'allowHTML' => true),
1290
        array('key' => 'duration', 'label' => $duration, 'width' => '50px'),
1291
        );
1292
    if ($bbbsession['managerecordings']) {
1293
        array_push($recordingsbncolumns, array('key' => 'actionbar', 'label' => $actionbar, 'width' => '120px',
1294
            'allowHTML' => true));
1295
    }
1296
    return $recordingsbncolumns;
1297
}
1298
1299
function bigbluebuttonbn_get_recording_data($bbbsession, $recordings, $tools = ['protect', 'publish', 'delete']) {
1300
    $tabledata = array();
1301
    // Build table content.
1302 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...
1303
        // There are recordings for this meeting.
1304
        foreach ($recordings as $recording) {
1305
            $row = bigbluebuttonbn_get_recording_data_row($bbbsession, $recording, $tools);
1306
            if ($row != null) {
1307
                array_push($tabledata, $row);
1308
            }
1309
        }
1310
    }
1311
    return $tabledata;
1312
}
1313
1314
function bigbluebuttonbn_get_recording_table($bbbsession, $recordings, $tools = ['protect', 'publish', 'delete']) {
1315
    // Set strings to show.
1316
    $recording = get_string('view_recording_recording', 'bigbluebuttonbn');
1317
    $description = get_string('view_recording_description', 'bigbluebuttonbn');
1318
    $date = get_string('view_recording_date', 'bigbluebuttonbn');
1319
    $duration = get_string('view_recording_duration', 'bigbluebuttonbn');
1320
    $actionbar = get_string('view_recording_actionbar', 'bigbluebuttonbn');
1321
    $playback = get_string('view_recording_playback', 'bigbluebuttonbn');
1322
    $preview = get_string('view_recording_preview', 'bigbluebuttonbn');
1323
    // Declare the table.
1324
    $table = new html_table();
1325
    $table->data = array();
1326
    // Initialize table headers.
1327
    $table->head = array($playback, $recording, $description, $preview, $date, $duration);
1328
    $table->align = array('left', 'left', 'left', 'left', 'left', 'center');
1329
    $table->size = array('', '', '', '', '', '');
1330
    if ($bbbsession['managerecordings']) {
1331
        $table->head[] = $actionbar;
1332
        $table->align[] = 'left';
1333
        $table->size[] = (count($tools) * 40) . 'px';
1334
    }
1335
    // Build table content.
1336 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...
1337
        // There are recordings for this meeting.
1338
        foreach ($recordings as $recording) {
1339
            if ( !bigbluebuttonbn_include_recording_table_row($bbbsession, $recording) ) {
1340
                continue;
1341
            }
1342
            bigbluebuttonbn_get_recording_table_row($bbbsession, $recording, $tools, $table);
1343
        }
1344
    }
1345
    return $table;
1346
}
1347
1348
function bigbluebuttonbn_get_recording_table_row($bbbsession, $recording, $tools, &$table) {
1349
    $rowdata = bigbluebuttonbn_get_recording_data_row($bbbsession, $recording, $tools);
1350
    if ($rowdata == null) {
1351
        return;
1352
    }
1353
    $row = new html_table_row();
1354
    $row->id = 'recording-td-'.$recording['recordID'];
1355
    $row->attributes['data-imported'] = 'false';
1356
    $texthead = '';
1357
    $texttail = '';
1358
    if (isset($recording['imported'])) {
1359
        $row->attributes['title'] = get_string('view_recording_link_warning', 'bigbluebuttonbn');
1360
        $row->attributes['data-imported'] = 'true';
1361
        $texthead = '<em>';
1362
        $texttail = '</em>';
1363
    }
1364
    $rowdata->date_formatted = str_replace(' ', '&nbsp;', $rowdata->date_formatted);
1365
    $row->cells = array(
1366
        $texthead . $rowdata->recording . $texttail,
1367
        $texthead . $rowdata->activity . $texttail, $texthead . $rowdata->description . $texttail,
1368
        $rowdata->preview, $texthead . $rowdata->date_formatted . $texttail,
1369
        $rowdata->duration_formatted
1370
      );
1371
    if ($bbbsession['managerecordings']) {
1372
        $row->cells[] = $rowdata->actionbar;
1373
    }
1374
    array_push($table->data, $row);
1375
}
1376
1377
function bigbluebuttonbn_include_recording_table_row($bbbsession, $recording) {
1378
    if ( isset($recording['imported']) || !isset($bbbsession['group']) || $recording['meetingID'] == $bbbsession['meetingid'] ) {
1379
        return true;
1380
    }
1381
    return false;
1382
}
1383
1384
function bigbluebuttonbn_send_notification_recording_ready($bigbluebuttonbn) {
1385
    $sender = get_admin();
1386
    // Prepare message.
1387
    $msg = new stdClass();
1388
    // Build the message_body.
1389
    $msg->activity_type = '';
1390
    $msg->activity_title = $bigbluebuttonbn->name;
1391
    $messagetext = '<p>'.get_string('email_body_recording_ready_for', 'bigbluebuttonbn').' '.
1392
        $msg->activity_type.' &quot;'.$msg->activity_title.'&quot; '.
1393
        get_string('email_body_recording_ready_is_ready', 'bigbluebuttonbn').'.</p>';
1394
    bigbluebuttonbn_send_notification($sender, $bigbluebuttonbn, $messagetext);
1395
}
1396
1397
function bigbluebuttonbn_is_bn_server() {
1398
    // Validates if the server may have extended capabilities.
1399
    $parsedurl = parse_url(\mod_bigbluebuttonbn\locallib\config::get('server_url'));
1400
    if (!isset($parsedurl['host'])) {
1401
        return false;
1402
    }
1403
    $h = $parsedurl['host'];
1404
    $hends = explode('.', $h);
1405
    $hendslength = count($hends);
1406
    return ($hends[$hendslength - 1] == 'com' && $hends[$hendslength - 2] == 'blindsidenetworks');
1407
}
1408
1409
function bigbluebuttonbn_import_get_courses_for_select(array $bbbsession) {
1410
    if ($bbbsession['administrator']) {
1411
        $courses = get_courses('all', 'c.id ASC', 'c.id,c.shortname,c.fullname');
1412
        // It includes the name of the site as a course (category 0), so remove the first one.
1413
        unset($courses['1']);
1414
    } else {
1415
        $courses = enrol_get_users_courses($bbbsession['userID'], false, 'id,shortname,fullname');
1416
    }
1417
    $coursesforselect = [];
1418
    foreach ($courses as $course) {
1419
        $coursesforselect[$course->id] = $course->fullname;
1420
    }
1421
    return $coursesforselect;
1422
}
1423
1424
function bigbluebutton_output_recording_table($bbbsession, $recordings, $tools = ['protect', 'publish', 'delete']) {
1425
    if (isset($recordings) && !empty($recordings)) {
1426
        // There are recordings for this meeting.
1427
        $table = bigbluebuttonbn_get_recording_table($bbbsession, $recordings, $tools);
1428
    }
1429
    if (!isset($table) || !isset($table->data)) {
1430
        // Render a table qith "No recordings".
1431
        return html_writer::div(get_string('view_message_norecordings', 'bigbluebuttonbn'), '',
1432
            array('id' => 'bigbluebuttonbn_html_table'));
1433
    }
1434
    // Render the table.
1435
    return html_writer::div(html_writer::table($table), '', array('id' => 'bigbluebuttonbn_html_table'));
1436
}
1437
1438
function bigbluebuttonbn_html2text($html, $len) {
1439
    $text = strip_tags($html);
1440
    $text = str_replace('&nbsp;', ' ', $text);
1441
    $text = substr($text, 0, $len);
1442
    if (strlen($text) > $len) {
1443
        $text .= '...';
1444
    }
1445
    return $text;
1446
}
1447
1448
/**
1449
 * helper function to obtain the tags linked to a bigbluebuttonbn activity
1450
 *
1451
 * @param string $id
1452
 *
1453
 * @return string containing the tags separated by commas
1454
 */
1455
function bigbluebuttonbn_get_tags($id) {
1456
    $tagsarray = core_tag_tag::get_item_tags_array('core', 'course_modules', $id);
1457
    return implode(',', $tagsarray);
1458
}
1459
1460
1461
/**
1462
 * helper function to define the sql used for gattering the bigbluebuttonbnids whose meetingids should be included
1463
 * in the getRecordings request
1464
 *
1465
 * @param string $courseid
1466
 * @param string $bigbluebuttonbnid
1467
 * @param bool   $subset
1468
 *
1469
 * @return string containing the sql used for getting the target bigbluebuttonbn instances
1470
 */
1471
function bigbluebuttonbn_get_recordings_sql_select($courseid, $bigbluebuttonbnid = null, $subset = true) {
1472
    if ($bigbluebuttonbnid === null) {
1473
        return "course = '{$courseid}'";
1474
    }
1475
    if ($subset) {
1476
        return "id = '{$bigbluebuttonbnid}'";
1477
    }
1478
    return "id <> '{$bigbluebuttonbnid}' AND course = '{$courseid}'";
1479
}
1480
1481
function bigbluebuttonbn_get_recordings_sql_selectdeleted($courseid, $bigbluebuttonbnid = null, $subset = true) {
1482
    if ($bigbluebuttonbnid === null) {
1483
        return "courseid = '{$courseid}' AND log = '".BIGBLUEBUTTONBN_LOG_EVENT_DELETE.
1484
            "' AND meta like '%has_recordings%' AND meta like '%true%'";
1485
    }
1486
    if ($subset) {
1487
        return "bigbluebuttonbnid = '{$bigbluebuttonbnid}' AND log = '".BIGBLUEBUTTONBN_LOG_EVENT_DELETE.
1488
            "' AND meta like '%has_recordings%' AND meta like '%true%'";
1489
    }
1490
    return "courseid = '{$courseid}' AND bigbluebuttonbnid <> '{$bigbluebuttonbnid}' AND log = '".
1491
        BIGBLUEBUTTONBN_LOG_EVENT_DELETE."' AND meta like '%has_recordings%' AND meta like '%true%'";
1492
}
1493
1494
function bigbluebuttonbn_get_allrecordings($courseid, $bigbluebuttonbnid = null, $subset = true,
1495
        $includedeleted = false) {
1496
        $recordings = bigbluebuttonbn_get_recordings($courseid, $bigbluebuttonbnid, $subset, $includedeleted);
1497
        $recordingsimported = bigbluebuttonbn_get_recordings_imported_array($courseid, $bigbluebuttonbnid, $subset);
1498
        return ($recordings + $recordingsimported);
1499
}
1500
1501
/**
1502
 * helper function to retrieve recordings from the BigBlueButton. The references are stored as events
1503
 * in bigbluebuttonbn_logs.
1504
 *
1505
 * @param string $courseid
1506
 * @param string $bigbluebuttonbnid
1507
 * @param bool   $subset
1508
 * @param bool   $includedeleted
1509
 *
1510
 * @return associative array containing the recordings indexed by recordID, each recording is also a
1511
 * non sequential associative array itself that corresponds to the actual recording in BBB
1512
 */
1513
function bigbluebuttonbn_get_recordings($courseid, $bigbluebuttonbnid = null, $subset = true,
1514
        $includedeleted = false) {
1515
    global $DB;
1516
    $select = bigbluebuttonbn_get_recordings_sql_select($courseid, $bigbluebuttonbnid, $subset);
1517
    $bigbluebuttonbns = $DB->get_records_select_menu('bigbluebuttonbn', $select, null, 'id', 'id, meetingid');
1518
    /* Consider logs from deleted bigbluebuttonbn instances whose meetingids should be included in
1519
     * the getRecordings request. */
1520
    if ($includedeleted) {
1521
        $selectdeleted = bigbluebuttonbn_get_recordings_sql_selectdeleted($courseid, $bigbluebuttonbnid, $subset);
1522
        $bigbluebuttonbnsdel = $DB->get_records_select_menu('bigbluebuttonbn_logs', $selectdeleted, null,
1523
            'bigbluebuttonbnid', 'bigbluebuttonbnid, meetingid');
1524
        if (!empty($bigbluebuttonbnsdel)) {
1525
            // Merge bigbluebuttonbnis from deleted instances, only keys are relevant.
1526
            // Artimetic merge is used in order to keep the keys.
1527
            $bigbluebuttonbns += $bigbluebuttonbnsdel;
1528
        }
1529
    }
1530
    // Gather the meetingids from bigbluebuttonbn logs that include a create with record=true.
1531
    if (empty($bigbluebuttonbns)) {
1532
        return array();
1533
    }
1534
    // Prepare select for loading records based on existent bigbluebuttonbns.
1535
    $sql = 'SELECT DISTINCT meetingid, bigbluebuttonbnid FROM {bigbluebuttonbn_logs} WHERE ';
1536
    $sql .= '(bigbluebuttonbnid='.implode(' OR bigbluebuttonbnid=', array_keys($bigbluebuttonbns)).')';
1537
    // Include only Create events and exclude those with record not true.
1538
    $sql .= ' AND log = ? AND meta LIKE ? AND meta LIKE ?';
1539
    // Execute select for loading records based on existent bigbluebuttonbns.
1540
    $records = $DB->get_records_sql_menu($sql, array(BIGBLUEBUTTONBN_LOG_EVENT_CREATE, '%record%', '%true%'));
1541
    // Get actual recordings.
1542
    return bigbluebuttonbn_get_recordings_array(array_keys($records));
1543
}
1544
1545
function bigbluebuttonbn_unset_existent_recordings_already_imported($recordings, $courseid, $bigbluebuttonbnid) {
1546
    $recordingsimported = bigbluebuttonbn_get_recordings_imported_array($courseid, $bigbluebuttonbnid, true);
1547
    foreach ($recordings as $key => $recording) {
1548
        if (isset($recordingsimported[$recording['recordID']])) {
1549
            unset($recordings[$key]);
1550
        }
1551
    }
1552
    return $recordings;
1553
}
1554
1555
function bigbluebuttonbn_get_count_recording_imported_instances($recordid) {
1556
    global $DB;
1557
    $sql = 'SELECT COUNT(DISTINCT id) FROM {bigbluebuttonbn_logs} WHERE log = ? AND meta LIKE ? AND meta LIKE ?';
1558
    return $DB->count_records_sql($sql, array(BIGBLUEBUTTONBN_LOG_EVENT_IMPORT, '%recordID%', "%{$recordid}%"));
1559
}
1560
1561
function bigbluebuttonbn_get_recording_imported_instances($recordid) {
1562
    global $DB;
1563
    $sql = 'SELECT * FROM {bigbluebuttonbn_logs} WHERE log = ? AND meta LIKE ? AND meta LIKE ?';
1564
    $recordingsimported = $DB->get_records_sql($sql, array(BIGBLUEBUTTONBN_LOG_EVENT_IMPORT, '%recordID%',
1565
        "%{$recordid}%"));
1566
    return $recordingsimported;
1567
}
1568
1569
function bigbluebuttonbn_get_instance_type_profiles() {
1570
    $instanceprofiles = array(
1571
            array('id' => BIGBLUEBUTTONBN_TYPE_ALL, 'name' => get_string('instance_type_default', 'bigbluebuttonbn'),
1572
                'features' => array('all')),
1573
            array('id' => BIGBLUEBUTTONBN_TYPE_ROOM_ONLY, 'name' => get_string('instance_type_room_only', 'bigbluebuttonbn'),
1574
                'features' => array('showroom', 'welcomemessage', 'voicebridge', 'waitformoderator', 'userlimit', 'recording',
1575
                    'sendnotifications', 'preuploadpresentation', 'permissions', 'schedule', 'groups')),
1576
            array('id' => BIGBLUEBUTTONBN_TYPE_RECORDING_ONLY, 'name' => get_string('instance_type_recording_only',
1577
                'bigbluebuttonbn'), 'features' => array('showrecordings', 'importrecordings')),
1578
    );
1579
    return $instanceprofiles;
1580
}
1581
1582
function bigbluebuttonbn_get_enabled_features($typeprofiles, $type = null) {
1583
    $enabledfeatures = array();
1584
    $features = $typeprofiles[0]['features'];
1585
    if (!is_null($type)) {
1586
        $features = $typeprofiles[$type]['features'];
1587
    }
1588
    $enabledfeatures['showroom'] = (in_array('all', $features) || in_array('showroom', $features));
1589
    $enabledfeatures['showrecordings'] = false;
1590
    $enabledfeatures['importrecordings'] = false;
1591
    // Evaluates if recordings are enabled for the Moodle site.
1592
    $enabledfeatures['showrecordings'] = (in_array('all', $features) || in_array('showrecordings', $features));
1593
    $enabledfeatures['importrecordings'] = (in_array('all', $features) || in_array('importrecordings', $features));
1594
    return $enabledfeatures;
1595
}
1596
1597
function bigbluebuttonbn_get_instance_profiles_array($profiles = null) {
1598
    if (is_null($profiles) || empty($profiles)) {
1599
        $profiles = bigbluebuttonbn_get_instance_type_profiles();
1600
    }
1601
    $profilesarray = array();
1602
    foreach ($profiles as $profile) {
1603
        $profilesarray += array("{$profile['id']}" => $profile['name']);
1604
    }
1605
    return $profilesarray;
1606
}
1607
1608
function bigbluebuttonbn_format_activity_time($time) {
1609
    $activitytime = '';
1610
    if ($time) {
1611
        $activitytime = calendar_day_representation($time).' '.
1612
          get_string('mod_form_field_notification_msg_at', 'bigbluebuttonbn').' '.
1613
          calendar_time_representation($time);
1614
    }
1615
    return $activitytime;
1616
}
1617
1618
function bigbluebuttonbn_get_strings_for_js() {
1619
    $locale = bigbluebuttonbn_get_locale();
1620
    $stringman = get_string_manager();
1621
    $strings = $stringman->load_component_strings('bigbluebuttonbn', $locale);
1622
    return $strings;
1623
}
1624
1625
function bigbluebuttonbn_get_locale() {
1626
    $lang = get_string('locale', 'core_langconfig');
1627
    return substr($lang, 0, strpos($lang, '.'));
1628
}
1629
1630
function bigbluebuttonbn_get_localcode() {
1631
    $locale = bigbluebuttonbn_get_locale();
1632
    return substr($locale, 0, strpos($locale, '_'));
1633
}
1634
1635
function bigbluebuttonbn_views_validator($id, $bigbluebuttonbnid) {
1636
    if ($id) {
1637
        return bigbluebuttonbn_views_instance_id($id);
1638
    }
1639
    if ($bigbluebuttonbnid) {
1640
        return bigbluebuttonbn_views_instance_bigbluebuttonbn($bigbluebuttonbnid);
1641
    }
1642
    return;
1643
}
1644
1645 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...
1646
    global $DB;
1647
    $cm = get_coursemodule_from_id('bigbluebuttonbn', $id, 0, false, MUST_EXIST);
1648
    $course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
1649
    $bigbluebuttonbn = $DB->get_record('bigbluebuttonbn', array('id' => $cm->instance), '*', MUST_EXIST);
1650
    return array('cm' => $cm, 'course' => $course, 'bigbluebuttonbn' => $bigbluebuttonbn);
1651
}
1652
1653 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...
1654
    global $DB;
1655
    $bigbluebuttonbn = $DB->get_record('bigbluebuttonbn', array('id' => $bigbluebuttonbnid), '*', MUST_EXIST);
1656
    $course = $DB->get_record('course', array('id' => $bigbluebuttonbn->course), '*', MUST_EXIST);
1657
    $cm = get_coursemodule_from_instance('bigbluebuttonbn', $bigbluebuttonbn->id, $course->id, false, MUST_EXIST);
1658
    return array('cm' => $cm, 'course' => $course, 'bigbluebuttonbn' => $bigbluebuttonbn);
1659
}
1660
1661
function bigbluebutonbn_settings_general(&$renderer) {
1662
    // Configuration for BigBlueButton.
1663
    if ((boolean)\mod_bigbluebuttonbn\settings\renderer::section_general_shown()) {
1664
        $renderer->render_group_header('general');
1665
        $renderer->render_group_element('server_url', $renderer->render_group_element_text('server_url', BIGBLUEBUTTONBN_DEFAULT_SERVER_URL));
1666
        $renderer->render_group_element('shared_secret', $renderer->render_group_element_text('shared_secret', BIGBLUEBUTTONBN_DEFAULT_SHARED_SECRET));
1667
    }
1668
}
1669
1670
function bigbluebutonbn_settings_recordings(&$renderer) {
1671
    // Evaluates if recordings are enabled for the Moodle site.
1672
    if (!(boolean)\mod_bigbluebuttonbn\locallib\config::recordings_enabled()) {
1673
        return;
1674
    }
1675
    // Configuration for 'recording' feature.
1676 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...
1677
        $renderer->render_group_header('recording');
1678
        $renderer->render_group_element('recording_default', $renderer->render_group_element_checkbox('recording_default', 1));
1679
        $renderer->render_group_element('recording_editable', $renderer->render_group_element_checkbox('recording_editable', 1));
1680
        $renderer->render_group_element('recording_icons_enabled', $renderer->render_group_element_checkbox('recording_icons_enabled', 1));
1681
    }
1682
    // Configuration for 'import recordings' feature.
1683 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...
1684
        $renderer->render_group_header('importrecordings');
1685
        $renderer->render_group_element('importrecordings_enabled', $renderer->render_group_element_checkbox('importrecordings_enabled', 0));
1686
        $renderer->render_group_element('importrecordings_from_deleted_enabled', $renderer->render_group_element_checkbox('importrecordings_from_deleted_enabled', 0));
1687
    }
1688
    // Configuration for 'show recordings' feature.
1689
    if ((boolean)\mod_bigbluebuttonbn\settings\renderer::section_show_recordings_shown()) {
1690
        $renderer->render_group_header('recordings');
1691
        $renderer->render_group_element('recordings_html_default', $renderer->render_group_element_checkbox('recordings_html_default', 1));
1692
        $renderer->render_group_element('recordings_html_editable', $renderer->render_group_element_checkbox('recordings_html_editable', 0));
1693
        $renderer->render_group_element('recordings_deleted_default', $renderer->render_group_element_checkbox('recordings_deleted_default', 1));
1694
        $renderer->render_group_element('recordings_deleted_editable', $renderer->render_group_element_checkbox('recordings_deleted_editable', 0));
1695
        $renderer->render_group_element('recordings_imported_default', $renderer->render_group_element_checkbox('recordings_imported_default', 0));
1696
        $renderer->render_group_element('recordings_imported_editable', $renderer->render_group_element_checkbox('recordings_imported_editable', 1));
1697
    }
1698
}
1699
1700
function bigbluebutonbn_settings_meetings(&$renderer) {
1701
    // Configuration for wait for moderator feature.
1702
    if ((boolean)\mod_bigbluebuttonbn\settings\renderer::section_wait_moderator_shown()) {
1703
        $renderer->render_group_header('waitformoderator');
1704
        $renderer->render_group_element('waitformoderator_default', $renderer->render_group_element_checkbox('waitformoderator_default', 0));
1705
        $renderer->render_group_element('waitformoderator_editable', $renderer->render_group_element_checkbox('waitformoderator_editable', 1));
1706
        $renderer->render_group_element('waitformoderator_ping_interval', $renderer->render_group_element_text('waitformoderator_ping_interval', 10, PARAM_INT));
1707
        $renderer->render_group_element('waitformoderator_cache_ttl', $renderer->render_group_element_text('waitformoderator_cache_ttl', 60, PARAM_INT));
1708
    }
1709
    // Configuration for "static voice bridge" feature.
1710
    if ((boolean)\mod_bigbluebuttonbn\settings\renderer::section_static_voice_bridge_shown()) {
1711
        $renderer->render_group_header('voicebridge');
1712
        $renderer->render_group_element('voicebridge_editable', $renderer->render_group_element_checkbox('voicebridge_editable', 0));
1713
    }
1714
    // Configuration for "preupload presentation" feature.
1715
    if ((boolean)\mod_bigbluebuttonbn\settings\renderer::section_preupload_presentation_shown()) {
1716
        // This feature only works if curl is installed.
1717
        $preuploaddescripion = get_string('config_preuploadpresentation_description', 'bigbluebuttonbn');
1718
        if (!extension_loaded('curl')) {
1719
            $preuploaddescripion .= '<div class="form-defaultinfo">'.get_string('config_warning_curl_not_installed', 'bigbluebuttonbn').'</div><br>';
1720
        }
1721
        $renderer->render_group_header('preuploadpresentation', null, $preuploaddescripion);
1722
        if (extension_loaded('curl')) {
1723
            $renderer->render_group_element('preuploadpresentation_enabled', $renderer->render_group_element_checkbox('preuploadpresentation_enabled', 0));
1724
        }
1725
    }
1726
    // Configuration for "user limit" feature.
1727 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...
1728
        $renderer->render_group_header('userlimit');
1729
        $renderer->render_group_element('userlimit_default', $renderer->render_group_element_text('userlimit_default', 0, PARAM_INT));
1730
        $renderer->render_group_element('userlimit_editable', $renderer->render_group_element_checkbox('userlimit_editable', 0));
1731
    }
1732
    // Configuration for "scheduled duration" feature.
1733 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...
1734
        $renderer->render_group_header('scheduled');
1735
        $renderer->render_group_element('scheduled_duration_enabled', $renderer->render_group_element_checkbox('scheduled_duration_enabled', 1));
1736
        $renderer->render_group_element('scheduled_duration_compensation', $renderer->render_group_element_text('scheduled_duration_compensation', 10, PARAM_INT));
1737
        $renderer->render_group_element('scheduled_pre_opening', $renderer->render_group_element_text('scheduled_pre_opening', 10, PARAM_INT));
1738
    }
1739
    // Configuration for defining the default role/user that will be moderator on new activities.
1740
    if ((boolean)\mod_bigbluebuttonbn\settings\renderer::section_moderator_default_shown()) {
1741
        $renderer->render_group_header('participant');
1742
        // UI for 'participants' feature.
1743
        $roles = bigbluebuttonbn_get_roles();
1744
        $owner = array('0' => get_string('mod_form_field_participant_list_type_owner', 'bigbluebuttonbn'));
1745
        $renderer->render_group_element('participant_moderator_default',
1746
            $renderer->render_group_element_configmultiselect('participant_moderator_default', array_keys($owner), array_merge($owner, $roles))
1747
          );
1748
    }
1749
    // Configuration for "send notifications" feature.
1750
    if ((boolean)\mod_bigbluebuttonbn\settings\renderer::section_send_notifications_shown()) {
1751
        $renderer->render_group_header('sendnotifications');
1752
        $renderer->render_group_element('sendnotifications_enabled', $renderer->render_group_element_checkbox('sendnotifications_enabled', 1));
1753
    }
1754
}
1755
1756
function bigbluebutonbn_settings_extended(&$renderer) {
1757
    // Configuration for extended BN capabilities.
1758
    if (!bigbluebuttonbn_is_bn_server()) {
1759
        return;
1760
    }
1761
    // Configuration for 'notify users when recording ready' feature.
1762 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...
1763
        $renderer->render_group_header('extended_capabilities');
1764
        // UI for 'notify users when recording ready' feature.
1765
        $renderer->render_group_element('recordingready_enabled', $renderer->render_group_element_checkbox('recordingready_enabled', 0));
1766
        // UI for 'register meeting events' feature.
1767
        $renderer->render_group_element('meetingevents_enabled', $renderer->render_group_element_checkbox('meetingevents_enabled', 0));
1768
    }
1769
}
1770