Completed
Push — master ( 1d1df5...87b1fe )
by Jesus
07:01
created

locallib.php ➔ bigbluebuttonbn_get_cfg_voicebridge_editable()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 3
nop 0
dl 0
loc 13
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
function bigbluebuttonbn_logs(array $bbbsession, $event, array $overrides = [], $meta = null) {
60
    global $DB;
61
62
    $log = new stdClass();
63
64
    // Default values.
65
    $log->courseid = $bbbsession['course']->id;
66
    $log->bigbluebuttonbnid = $bbbsession['bigbluebuttonbn']->id;
67
    $log->userid = $bbbsession['userID'];
68
    $log->meetingid = $bbbsession['meetingid'];
69
    $log->timecreated = time();
70
    // Overrides.
71
    foreach ($overrides as $key => $value) {
72
        $log->$key = $value;
73
    }
74
75
    $log->log = $event;
76
    if (isset($meta)) {
77
        $log->meta = $meta;
78
    } else if ($event == BIGBLUEBUTTONBN_LOG_EVENT_CREATE) {
79
        $log->meta = '{"record":'.($bbbsession['record'] ? 'true' : 'false').'}';
80
    }
81
82
    $DB->insert_record('bigbluebuttonbn_logs', $log);
83
}
84
85
// BigBlueButton API Calls.
86
function bigbluebuttonbn_get_join_url($meetingid, $username, $pw, $logouturl, $configtoken = null, $userid = null) {
87
    $data = ['meetingID' => $meetingid,
88
              'fullName' => $username,
89
              'password' => $pw,
90
              'logoutURL' => $logouturl,
91
            ];
92
93
    if (!is_null($configtoken)) {
94
        $data['configToken'] = $configtoken;
95
    }
96
    if (!is_null($userid)) {
97
        $data['userID'] = $userid;
98
    }
99
100
    return \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('join', $data);
101
}
102
103
/**
104
 * @param string $recordid
105
 * @param array  $metadata
106
 */
107
function bigbluebuttonbn_get_update_recordings_url($recordid, $metadata = array()) {
108
    return \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('updateRecordings', ['recordID' => $recordid], $metadata);
109
}
110
111
/**
112
 * @param string $data
113
 * @param array  $metadata
114
 * @param string $pname
115
 * @param string $purl
116
 */
117
function bigbluebuttonbn_get_create_meeting_array($data, $metadata = array(), $pname = null, $purl = null) {
118
    $createmeetingurl = \mod_bigbluebuttonbn\locallib\bigbluebutton::action_url('create', $data, $metadata);
0 ignored issues
show
Documentation introduced by
$data is of type string, but the function expects a array.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

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