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
|
|
|
* Library calls for Moodle and BigBlueButton. |
19
|
|
|
* |
20
|
|
|
* @package mod_bigbluebuttonbn |
21
|
|
|
* @copyright 2010 onwards, Blindside Networks Inc |
22
|
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
23
|
|
|
* @author Jesus Federico (jesus [at] blindsidenetworks [dt] com) |
24
|
|
|
* @author Fred Dixon (ffdixon [at] blindsidenetworks [dt] com) |
25
|
|
|
*/ |
26
|
|
|
|
27
|
|
|
defined('MOODLE_INTERNAL') || die; |
28
|
|
|
|
29
|
|
|
global $CFG; |
30
|
|
|
|
31
|
|
|
// JWT is included in Moodle 3.7 core, but a local package is still needed for backward compatibility. |
32
|
|
|
if (!class_exists('\Firebase\JWT\JWT')) { |
33
|
|
|
if (file_exists($CFG->libdir.'/php-jwt/src/JWT.php')) { |
34
|
|
|
require_once($CFG->libdir.'/php-jwt/src/JWT.php'); |
35
|
|
|
} else { |
36
|
|
|
require_once($CFG->dirroot.'/mod/bigbluebuttonbn/vendor/firebase/php-jwt/src/JWT.php'); |
37
|
|
|
} |
38
|
|
|
} |
39
|
|
|
|
40
|
|
|
// Do not declare new $CFG variables if unit tests are running |
41
|
|
|
// as it can cause "unexpected new $CFG->xxx value" warnings. |
42
|
|
|
if (!defined('PHPUNIT_TEST') || !PHPUNIT_TEST) { |
43
|
|
|
if (!isset($CFG->bigbluebuttonbn)) { |
44
|
|
|
$CFG->bigbluebuttonbn = array(); |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
if (file_exists(dirname(__FILE__).'/config.php')) { |
48
|
|
|
require_once(dirname(__FILE__).'/config.php'); |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
/* |
52
|
|
|
* DURATIONCOMPENSATION: Feature removed by configuration |
53
|
|
|
*/ |
54
|
|
|
$CFG->bigbluebuttonbn['scheduled_duration_enabled'] = 0; |
55
|
|
|
/* |
56
|
|
|
* Remove this block when restored |
57
|
|
|
*/ |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
/** @var BIGBLUEBUTTONBN_DEFAULT_SERVER_URL string of default bigbluebutton server url */ |
61
|
|
|
const BIGBLUEBUTTONBN_DEFAULT_SERVER_URL = 'http://test-install.blindsidenetworks.com/bigbluebutton/'; |
62
|
|
|
/** @var BIGBLUEBUTTONBN_DEFAULT_SHARED_SECRET string of default bigbluebutton server shared secret */ |
63
|
|
|
const BIGBLUEBUTTONBN_DEFAULT_SHARED_SECRET = '8cd8ef52e8e101574e400365b55e11a6'; |
64
|
|
|
/** @var BIGBLUEBUTTONBN_LOG_EVENT_ADD string defines the bigbluebuttonbn Add event */ |
65
|
|
|
const BIGBLUEBUTTONBN_LOG_EVENT_ADD = 'Add'; |
66
|
|
|
/** @var BIGBLUEBUTTONBN_LOG_EVENT_EDIT string defines the bigbluebuttonbn Edit event */ |
67
|
|
|
const BIGBLUEBUTTONBN_LOG_EVENT_EDIT = 'Edit'; |
68
|
|
|
/** @var BIGBLUEBUTTONBN_LOG_EVENT_CREATE string defines the bigbluebuttonbn Create event */ |
69
|
|
|
const BIGBLUEBUTTONBN_LOG_EVENT_CREATE = 'Create'; |
70
|
|
|
/** @var BIGBLUEBUTTONBN_LOG_EVENT_JOIN string defines the bigbluebuttonbn Join event */ |
71
|
|
|
const BIGBLUEBUTTONBN_LOG_EVENT_JOIN = 'Join'; |
72
|
|
|
/** @var BIGBLUEBUTTONBN_LOG_EVENT_PLAYED string defines the bigbluebuttonbn Playback event */ |
73
|
|
|
const BIGBLUEBUTTONBN_LOG_EVENT_PLAYED = 'Played'; |
74
|
|
|
/** @var BIGBLUEBUTTONBN_LOG_EVENT_LOGOUT string defines the bigbluebuttonbn Logout event */ |
75
|
|
|
const BIGBLUEBUTTONBN_LOG_EVENT_LOGOUT = 'Logout'; |
76
|
|
|
/** @var BIGBLUEBUTTONBN_LOG_EVENT_IMPORT string defines the bigbluebuttonbn Import event */ |
77
|
|
|
const BIGBLUEBUTTONBN_LOG_EVENT_IMPORT = 'Import'; |
78
|
|
|
/** @var BIGBLUEBUTTONBN_LOG_EVENT_DELETE string defines the bigbluebuttonbn Delete event */ |
79
|
|
|
const BIGBLUEBUTTONBN_LOG_EVENT_DELETE = 'Delete'; |
80
|
|
|
/** @var BIGBLUEBUTTON_LOG_EVENT_CALLBACK string defines the bigbluebuttonbn Callback event */ |
81
|
|
|
const BIGBLUEBUTTON_LOG_EVENT_CALLBACK = 'Callback'; |
82
|
|
|
/** @var BIGBLUEBUTTON_LOG_EVENT_SUMMARY string defines the bigbluebuttonbn Summary event */ |
83
|
|
|
const BIGBLUEBUTTON_LOG_EVENT_SUMMARY = 'Summary'; |
84
|
|
|
/** |
85
|
|
|
* Indicates API features that the bigbluebuttonbn supports. |
86
|
|
|
* |
87
|
|
|
* @uses FEATURE_IDNUMBER |
88
|
|
|
* @uses FEATURE_GROUPS |
89
|
|
|
* @uses FEATURE_GROUPINGS |
90
|
|
|
* @uses FEATURE_GROUPMEMBERSONLY |
91
|
|
|
* @uses FEATURE_MOD_INTRO |
92
|
|
|
* @uses FEATURE_BACKUP_MOODLE2 |
93
|
|
|
* @uses FEATURE_COMPLETION_TRACKS_VIEWS |
94
|
|
|
* @uses FEATURE_COMPLETION_HAS_RULES |
95
|
|
|
* @uses FEATURE_GRADE_HAS_GRADE |
96
|
|
|
* @uses FEATURE_GRADE_OUTCOMES |
97
|
|
|
* @uses FEATURE_SHOW_DESCRIPTION |
98
|
|
|
* @param string $feature |
99
|
|
|
* @return mixed True if yes (some features may use other values) |
100
|
|
|
*/ |
101
|
|
|
function bigbluebuttonbn_supports($feature) { |
102
|
|
|
if (!$feature) { |
103
|
|
|
return null; |
104
|
|
|
} |
105
|
|
|
$features = array( |
106
|
|
|
(string) FEATURE_IDNUMBER => true, |
107
|
|
|
(string) FEATURE_GROUPS => true, |
108
|
|
|
(string) FEATURE_GROUPINGS => true, |
109
|
|
|
(string) FEATURE_GROUPMEMBERSONLY => true, |
110
|
|
|
(string) FEATURE_MOD_INTRO => true, |
111
|
|
|
(string) FEATURE_BACKUP_MOODLE2 => true, |
112
|
|
|
(string) FEATURE_COMPLETION_TRACKS_VIEWS => true, |
113
|
|
|
(string) FEATURE_COMPLETION_HAS_RULES => true, |
114
|
|
|
(string) FEATURE_GRADE_HAS_GRADE => false, |
115
|
|
|
(string) FEATURE_GRADE_OUTCOMES => false, |
116
|
|
|
(string) FEATURE_SHOW_DESCRIPTION => true, |
117
|
|
|
); |
118
|
|
|
if (isset($features[(string) $feature])) { |
119
|
|
|
return $features[$feature]; |
120
|
|
|
} |
121
|
|
|
return null; |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
/** |
125
|
|
|
* Obtains the automatic completion state for this bigbluebuttonbn based on any conditions |
126
|
|
|
* in bigbluebuttonbn settings. |
127
|
|
|
* |
128
|
|
|
* @param object $course Course |
129
|
|
|
* @param object $cm Course-module |
130
|
|
|
* @param int $userid User ID |
131
|
|
|
* @param bool $type Type of comparison (or/and; can be used as return value if no conditions) |
132
|
|
|
* |
133
|
|
|
* @return bool True if completed, false if not. (If no conditions, then return |
134
|
|
|
* value depends on comparison type) |
135
|
|
|
*/ |
136
|
|
|
function bigbluebuttonbn_get_completion_state($course, $cm, $userid, $type) { |
|
|
|
|
137
|
|
|
global $DB; |
138
|
|
|
|
139
|
|
|
// Get bigbluebuttonbn details. |
140
|
|
|
$bigbluebuttonbn = $DB->get_record('bigbluebuttonbn', array('id' => $cm->instance), '*', |
141
|
|
|
MUST_EXIST); |
142
|
|
|
if (!$bigbluebuttonbn) { |
143
|
|
|
throw new Exception("Can't find bigbluebuttonbn {$cm->instance}"); |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
// Default return value. |
147
|
|
|
$result = $type; |
148
|
|
|
|
149
|
|
|
$sql = "SELECT * FROM {bigbluebuttonbn_logs} "; |
150
|
|
|
$sql .= "WHERE bigbluebuttonbnid = ? AND userid = ? AND log = ?"; |
151
|
|
|
$logs = $DB->get_records_sql($sql, array($bigbluebuttonbn->id, $userid, BIGBLUEBUTTON_LOG_EVENT_SUMMARY)); |
152
|
|
|
|
153
|
|
|
if ($bigbluebuttonbn->completionattendance) { |
154
|
|
|
if (!$logs) { |
155
|
|
|
// As completion by attendance was required, the activity hasn't been completed. |
156
|
|
|
return false; |
157
|
|
|
} |
158
|
|
|
$attendancecount = 0; |
159
|
|
|
foreach ($logs as $log) { |
160
|
|
|
$summary = json_decode($log->meta); |
161
|
|
|
$attendancecount += $summary->data->duration; |
162
|
|
|
} |
163
|
|
|
$attendancecount /= 60; |
164
|
|
|
$value = $bigbluebuttonbn->completionattendance <= $attendancecount; |
165
|
|
|
if ($type == COMPLETION_AND) { |
166
|
|
|
$result = $result && $value; |
167
|
|
|
} else { |
168
|
|
|
$result = $result || $value; |
169
|
|
|
} |
170
|
|
|
} |
171
|
|
|
|
172
|
|
View Code Duplication |
if ($bigbluebuttonbn->completionengagementchats) { |
|
|
|
|
173
|
|
|
if (!$logs) { |
174
|
|
|
// As completion by engagement with chat was required, the activity hasn't been completed. |
175
|
|
|
return false; |
176
|
|
|
} |
177
|
|
|
$engagementchatscount = 0; |
178
|
|
|
foreach ($logs as $log) { |
179
|
|
|
$summary = json_decode($log->meta); |
180
|
|
|
$engagementchatscount += $summary->data->engagement->chats; |
181
|
|
|
} |
182
|
|
|
$value = $bigbluebuttonbn->completionengagementchats <= $engagementchatscount; |
183
|
|
|
if ($type == COMPLETION_AND) { |
184
|
|
|
$result = $result && $value; |
185
|
|
|
} else { |
186
|
|
|
$result = $result || $value; |
187
|
|
|
} |
188
|
|
|
} |
189
|
|
|
|
190
|
|
View Code Duplication |
if ($bigbluebuttonbn->completionengagementtalks) { |
|
|
|
|
191
|
|
|
if (!$logs) { |
192
|
|
|
// As completion by engagement with talk was required, the activity hasn't been completed. |
193
|
|
|
return false; |
194
|
|
|
} |
195
|
|
|
$engagementtalkscount = 0; |
196
|
|
|
foreach ($logs as $log) { |
197
|
|
|
$summary = json_decode($log->meta); |
198
|
|
|
$engagementtalkscount += $summary->data->engagement->talks; |
199
|
|
|
} |
200
|
|
|
$value = $bigbluebuttonbn->completionengagementtalks <= $engagementtalkscount; |
201
|
|
|
if ($type == COMPLETION_AND) { |
202
|
|
|
$result = $result && $value; |
203
|
|
|
} else { |
204
|
|
|
$result = $result || $value; |
205
|
|
|
} |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
return $result; |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
/** |
212
|
|
|
* Given an object containing all the necessary data, |
213
|
|
|
* (defined by the form in mod_form.php) this function |
214
|
|
|
* will create a new instance and return the id number |
215
|
|
|
* of the new instance. |
216
|
|
|
* |
217
|
|
|
* @param object $bigbluebuttonbn An object from the form in mod_form.php |
218
|
|
|
* @return int The id of the newly inserted bigbluebuttonbn record |
219
|
|
|
*/ |
220
|
|
View Code Duplication |
function bigbluebuttonbn_add_instance($bigbluebuttonbn) { |
|
|
|
|
221
|
|
|
global $DB; |
222
|
|
|
// Excecute preprocess. |
223
|
|
|
bigbluebuttonbn_process_pre_save($bigbluebuttonbn); |
224
|
|
|
// Pre-set initial values. |
225
|
|
|
$bigbluebuttonbn->presentation = bigbluebuttonbn_get_media_file($bigbluebuttonbn); |
226
|
|
|
// Insert a record. |
227
|
|
|
$bigbluebuttonbn->id = $DB->insert_record('bigbluebuttonbn', $bigbluebuttonbn); |
228
|
|
|
// Encode meetingid. |
229
|
|
|
$bigbluebuttonbn->meetingid = bigbluebuttonbn_unique_meetingid_seed(); |
230
|
|
|
// Set the meetingid column in the bigbluebuttonbn table. |
231
|
|
|
$DB->set_field('bigbluebuttonbn', 'meetingid', $bigbluebuttonbn->meetingid, array('id' => $bigbluebuttonbn->id)); |
232
|
|
|
// Log insert action. |
233
|
|
|
bigbluebuttonbn_log($bigbluebuttonbn, BIGBLUEBUTTONBN_LOG_EVENT_ADD); |
234
|
|
|
// Complete the process. |
235
|
|
|
bigbluebuttonbn_process_post_save($bigbluebuttonbn); |
236
|
|
|
return $bigbluebuttonbn->id; |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
/** |
240
|
|
|
* Given an object containing all the necessary data, |
241
|
|
|
* (defined by the form in mod_form.php) this function |
242
|
|
|
* will update an existing instance with new data. |
243
|
|
|
* |
244
|
|
|
* @param object $bigbluebuttonbn An object from the form in mod_form.php |
245
|
|
|
* @return bool Success/Fail |
246
|
|
|
*/ |
247
|
|
View Code Duplication |
function bigbluebuttonbn_update_instance($bigbluebuttonbn) { |
|
|
|
|
248
|
|
|
global $DB; |
249
|
|
|
// Excecute preprocess. |
250
|
|
|
bigbluebuttonbn_process_pre_save($bigbluebuttonbn); |
251
|
|
|
// Pre-set initial values. |
252
|
|
|
$bigbluebuttonbn->id = $bigbluebuttonbn->instance; |
253
|
|
|
$bigbluebuttonbn->presentation = bigbluebuttonbn_get_media_file($bigbluebuttonbn); |
254
|
|
|
// Update a record. |
255
|
|
|
$DB->update_record('bigbluebuttonbn', $bigbluebuttonbn); |
256
|
|
|
// Get the meetingid column in the bigbluebuttonbn table. |
257
|
|
|
$bigbluebuttonbn->meetingid = (string)$DB->get_field('bigbluebuttonbn', 'meetingid', array('id' => $bigbluebuttonbn->id)); |
258
|
|
|
// Log update action. |
259
|
|
|
bigbluebuttonbn_log($bigbluebuttonbn, BIGBLUEBUTTONBN_LOG_EVENT_EDIT); |
260
|
|
|
// Complete the process. |
261
|
|
|
bigbluebuttonbn_process_post_save($bigbluebuttonbn); |
262
|
|
|
return true; |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
/** |
266
|
|
|
* Given an ID of an instance of this module, |
267
|
|
|
* this function will permanently delete the instance |
268
|
|
|
* and any data that depends on it. |
269
|
|
|
* |
270
|
|
|
* @param int $id Id of the module instance |
271
|
|
|
* |
272
|
|
|
* @return bool Success/Failure |
273
|
|
|
*/ |
274
|
|
|
function bigbluebuttonbn_delete_instance($id) { |
275
|
|
|
global $DB; |
276
|
|
|
|
277
|
|
|
if (!$bigbluebuttonbn = $DB->get_record('bigbluebuttonbn', array('id' => $id))) { |
278
|
|
|
return false; |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
// TODO: End the meeting if it is running. |
282
|
|
|
|
283
|
|
|
$result = true; |
284
|
|
|
|
285
|
|
|
// Delete any dependent records here. |
286
|
|
|
if (!$DB->delete_records('bigbluebuttonbn', array('id' => $bigbluebuttonbn->id))) { |
287
|
|
|
$result = false; |
288
|
|
|
} |
289
|
|
|
|
290
|
|
|
if (!$DB->delete_records('event', array('modulename' => 'bigbluebuttonbn', 'instance' => $bigbluebuttonbn->id))) { |
291
|
|
|
$result = false; |
292
|
|
|
} |
293
|
|
|
|
294
|
|
|
// Log action performed. |
295
|
|
|
bigbluebuttonbn_delete_instance_log($bigbluebuttonbn); |
296
|
|
|
|
297
|
|
|
return $result; |
298
|
|
|
} |
299
|
|
|
|
300
|
|
|
/** |
301
|
|
|
* Given an ID of an instance of this module, |
302
|
|
|
* this function will permanently delete the data that depends on it. |
303
|
|
|
* |
304
|
|
|
* @param object $bigbluebuttonbn Id of the module instance |
305
|
|
|
* |
306
|
|
|
* @return bool Success/Failure |
307
|
|
|
*/ |
308
|
|
|
function bigbluebuttonbn_delete_instance_log($bigbluebuttonbn) { |
309
|
|
|
global $DB; |
310
|
|
|
$sql = "SELECT * FROM {bigbluebuttonbn_logs} "; |
311
|
|
|
$sql .= "WHERE bigbluebuttonbnid = ? AND log = ? AND ". $DB->sql_compare_text('meta') . " = ?"; |
312
|
|
|
$logs = $DB->get_records_sql($sql, array($bigbluebuttonbn->id, BIGBLUEBUTTONBN_LOG_EVENT_CREATE, "{\"record\":true}")); |
313
|
|
|
$meta = "{\"has_recordings\":" . empty($logs) ? "true" : "false" . "}"; |
314
|
|
|
bigbluebuttonbn_log($bigbluebuttonbn, BIGBLUEBUTTONBN_LOG_EVENT_DELETE, [], $meta); |
315
|
|
|
} |
316
|
|
|
|
317
|
|
|
/** |
318
|
|
|
* Return a small object with summary information about what a |
319
|
|
|
* user has done with a given particular instance of this module |
320
|
|
|
* Used for user activity reports. |
321
|
|
|
* |
322
|
|
|
* @param object $course |
323
|
|
|
* @param object $user |
324
|
|
|
* @param object $mod |
325
|
|
|
* @param object $bigbluebuttonbn |
326
|
|
|
* |
327
|
|
|
* @return bool |
328
|
|
|
*/ |
329
|
|
|
function bigbluebuttonbn_user_outline($course, $user, $mod, $bigbluebuttonbn) { |
|
|
|
|
330
|
|
|
if ($completed = bigbluebuttonbn_user_complete($course, $user, $bigbluebuttonbn)) { |
331
|
|
|
return fullname($user) . ' ' . get_string('view_message_has_joined', 'bigbluebuttonbn') . ' ' . |
332
|
|
|
get_string('view_message_session_for', 'bigbluebuttonbn') . ' ' . (string) $completed . ' ' . |
333
|
|
|
get_string('view_message_times', 'bigbluebuttonbn'); |
334
|
|
|
} |
335
|
|
|
return ''; |
336
|
|
|
} |
337
|
|
|
|
338
|
|
|
/** |
339
|
|
|
* Print a detailed representation of what a user has done with |
340
|
|
|
* a given particular instance of this module, for user activity reports. |
341
|
|
|
* |
342
|
|
|
* @param object|int $courseorid |
343
|
|
|
* @param object|int $userorid |
344
|
|
|
* @param object $bigbluebuttonbn |
345
|
|
|
* |
346
|
|
|
* @return bool |
347
|
|
|
*/ |
348
|
|
|
function bigbluebuttonbn_user_complete($courseorid, $userorid, $bigbluebuttonbn) { |
349
|
|
|
global $DB; |
350
|
|
|
if (is_object($courseorid)) { |
351
|
|
|
$course = $courseorid; |
352
|
|
|
} else { |
353
|
|
|
$course = (object)array('id' => $courseorid); |
354
|
|
|
} |
355
|
|
|
if (is_object($userorid)) { |
356
|
|
|
$user = $userorid; |
357
|
|
|
} else { |
358
|
|
|
$user = (object)array('id' => $userorid); |
359
|
|
|
} |
360
|
|
|
$sql = "SELECT COUNT(*) FROM {bigbluebuttonbn_logs} "; |
361
|
|
|
$sql .= "WHERE courseid = ? AND bigbluebuttonbnid = ? AND userid = ? AND (log = ? OR log = ?)"; |
362
|
|
|
$result = $DB->count_records_sql($sql, array($course->id, $bigbluebuttonbn->id, $user->id, |
363
|
|
|
BIGBLUEBUTTONBN_LOG_EVENT_JOIN, BIGBLUEBUTTONBN_LOG_EVENT_PLAYED)); |
364
|
|
|
return $result; |
365
|
|
|
} |
366
|
|
|
|
367
|
|
|
/** |
368
|
|
|
* Returns all other caps used in module. |
369
|
|
|
* |
370
|
|
|
* @return string[] |
371
|
|
|
*/ |
372
|
|
|
function bigbluebuttonbn_get_extra_capabilities() { |
373
|
|
|
return array('moodle/site:accessallgroups'); |
374
|
|
|
} |
375
|
|
|
|
376
|
|
|
/** |
377
|
|
|
* Define items to be reset by course/reset.php |
378
|
|
|
* |
379
|
|
|
* @return array |
380
|
|
|
*/ |
381
|
|
|
function bigbluebuttonbn_reset_course_items() { |
382
|
|
|
$items = array("events" => 0, "tags" => 0, "logs" => 0); |
383
|
|
|
// Include recordings only if enabled. |
384
|
|
|
if ((boolean)\mod_bigbluebuttonbn\locallib\config::recordings_enabled()) { |
385
|
|
|
$items["recordings"] = 0; |
386
|
|
|
} |
387
|
|
|
return $items; |
388
|
|
|
} |
389
|
|
|
|
390
|
|
|
/** |
391
|
|
|
* Called by course/reset.php |
392
|
|
|
* |
393
|
|
|
* @param object $mform |
394
|
|
|
* @return void |
395
|
|
|
*/ |
396
|
|
|
function bigbluebuttonbn_reset_course_form_definition(&$mform) { |
397
|
|
|
$items = bigbluebuttonbn_reset_course_items(); |
398
|
|
|
$mform->addElement('header', 'bigbluebuttonbnheader', get_string('modulenameplural', 'bigbluebuttonbn')); |
399
|
|
|
foreach ($items as $item => $default) { |
400
|
|
|
$mform->addElement( |
401
|
|
|
'advcheckbox', |
402
|
|
|
"reset_bigbluebuttonbn_{$item}", |
403
|
|
|
get_string("reset{$item}", 'bigbluebuttonbn') |
404
|
|
|
); |
405
|
|
|
if ($item == 'logs' || $item == 'recordings') { |
406
|
|
|
$mform->addHelpButton("reset_bigbluebuttonbn_{$item}", "reset{$item}", 'bigbluebuttonbn'); |
407
|
|
|
} |
408
|
|
|
} |
409
|
|
|
} |
410
|
|
|
|
411
|
|
|
/** |
412
|
|
|
* Course reset form defaults. |
413
|
|
|
* |
414
|
|
|
* @param object $course |
415
|
|
|
* @return array |
416
|
|
|
*/ |
417
|
|
|
function bigbluebuttonbn_reset_course_form_defaults($course) { |
|
|
|
|
418
|
|
|
$formdefaults = array(); |
419
|
|
|
$items = bigbluebuttonbn_reset_course_items(); |
420
|
|
|
// All unchecked by default. |
421
|
|
|
foreach ($items as $item => $default) { |
422
|
|
|
$formdefaults["reset_bigbluebuttonbn_{$item}"] = $default; |
423
|
|
|
} |
424
|
|
|
return $formdefaults; |
425
|
|
|
} |
426
|
|
|
|
427
|
|
|
/** |
428
|
|
|
* This function is used by the reset_course_userdata function in moodlelib. |
429
|
|
|
* |
430
|
|
|
* @param array $data the data submitted from the reset course. |
431
|
|
|
* @return array status array |
432
|
|
|
*/ |
433
|
|
|
function bigbluebuttonbn_reset_userdata($data) { |
434
|
|
|
$items = bigbluebuttonbn_reset_course_items(); |
435
|
|
|
$status = array(); |
436
|
|
|
// Any changes to the list of dates that needs to be rolled should be same during course restore and course reset. |
437
|
|
|
// See MDL-9367. |
438
|
|
|
if (array_key_exists('recordings', $items) && !empty($data->reset_bigbluebuttonbn_recordings)) { |
439
|
|
|
// Remove all the recordings from a BBB server that are linked to the room/activities in this course. |
440
|
|
|
bigbluebuttonbn_reset_recordings($data->courseid); |
441
|
|
|
unset($items['recordings']); |
442
|
|
|
$status[] = bigbluebuttonbn_reset_getstatus('recordings'); |
443
|
|
|
} |
444
|
|
|
if (!empty($data->reset_bigbluebuttonbn_tags)) { |
445
|
|
|
// Remove all the tags linked to the room/activities in this course. |
446
|
|
|
bigbluebuttonbn_reset_tags($data->courseid); |
447
|
|
|
unset($items['tags']); |
448
|
|
|
$status[] = bigbluebuttonbn_reset_getstatus('tags'); |
449
|
|
|
} |
450
|
|
|
// TODO : seems to be duplicated code unless we just want to force reset tags. |
451
|
|
|
foreach ($items as $item => $default) { |
452
|
|
|
// Remove instances or elements linked to this course, others than recordings or tags. |
453
|
|
|
if (!empty($data->{"reset_bigbluebuttonbn_{$item}"})) { |
454
|
|
|
call_user_func("bigbluebuttonbn_reset_{$item}", $data->courseid); |
455
|
|
|
$status[] = bigbluebuttonbn_reset_getstatus($item); |
456
|
|
|
} |
457
|
|
|
} |
458
|
|
|
return $status; |
459
|
|
|
} |
460
|
|
|
|
461
|
|
|
/** |
462
|
|
|
* Returns status used on every defined reset action. |
463
|
|
|
* |
464
|
|
|
* @param string $item |
465
|
|
|
* @return array status array |
466
|
|
|
*/ |
467
|
|
|
function bigbluebuttonbn_reset_getstatus($item) { |
468
|
|
|
return array('component' => get_string('modulenameplural', 'bigbluebuttonbn') |
469
|
|
|
, 'item' => get_string("removed{$item}", 'bigbluebuttonbn') |
470
|
|
|
, 'error' => false); |
471
|
|
|
} |
472
|
|
|
|
473
|
|
|
/** |
474
|
|
|
* Used by the reset_course_userdata for deleting events linked to bigbluebuttonbn instances in the course. |
475
|
|
|
* |
476
|
|
|
* @param string $courseid |
477
|
|
|
* @return array status array |
478
|
|
|
*/ |
479
|
|
|
function bigbluebuttonbn_reset_events($courseid) { |
480
|
|
|
global $DB; |
481
|
|
|
// Remove all the events. |
482
|
|
|
return $DB->delete_records('event', array('modulename' => 'bigbluebuttonbn', 'courseid' => $courseid)); |
483
|
|
|
} |
484
|
|
|
|
485
|
|
|
/** |
486
|
|
|
* Used by the reset_course_userdata for deleting tags linked to bigbluebuttonbn instances in the course. |
487
|
|
|
* |
488
|
|
|
* @param array $courseid |
489
|
|
|
* @return array status array |
490
|
|
|
*/ |
491
|
|
|
function bigbluebuttonbn_reset_tags($courseid) { |
492
|
|
|
global $DB; |
493
|
|
|
// Remove all the tags linked to the room/activities in this course. |
494
|
|
|
if ($bigbluebuttonbns = $DB->get_records('bigbluebuttonbn', array('course' => $courseid))) { |
495
|
|
|
foreach ($bigbluebuttonbns as $bigbluebuttonbn) { |
496
|
|
|
if (!$cm = get_coursemodule_from_instance('bigbluebuttonbn', $bigbluebuttonbn->id, $courseid)) { |
497
|
|
|
continue; |
498
|
|
|
} |
499
|
|
|
$context = context_module::instance($cm->id); |
500
|
|
|
core_tag_tag::delete_instances('mod_bigbluebuttonbn', null, $context->id); |
501
|
|
|
} |
502
|
|
|
} |
503
|
|
|
} |
504
|
|
|
|
505
|
|
|
/** |
506
|
|
|
* Used by the reset_course_userdata for deleting bigbluebuttonbn_logs linked to bigbluebuttonbn instances in the course. |
507
|
|
|
* |
508
|
|
|
* @param string $courseid |
509
|
|
|
* @return array status array |
510
|
|
|
*/ |
511
|
|
|
function bigbluebuttonbn_reset_logs($courseid) { |
512
|
|
|
global $DB; |
513
|
|
|
// Remove all the logs. |
514
|
|
|
return $DB->delete_records('bigbluebuttonbn_logs', array('courseid' => $courseid)); |
515
|
|
|
} |
516
|
|
|
|
517
|
|
|
/** |
518
|
|
|
* Used by the reset_course_userdata for deleting recordings in a BBB server linked to bigbluebuttonbn instances in the course. |
519
|
|
|
* |
520
|
|
|
* @param string $courseid |
521
|
|
|
* @return array status array |
522
|
|
|
*/ |
523
|
|
|
function bigbluebuttonbn_reset_recordings($courseid) { |
524
|
|
|
require_once(__DIR__.'/locallib.php'); |
525
|
|
|
// Criteria for search [courseid | bigbluebuttonbn=null | subset=false | includedeleted=true]. |
526
|
|
|
$recordings = bigbluebuttonbn_get_recordings($courseid, null, false, true); |
527
|
|
|
// Remove all the recordings. |
528
|
|
|
bigbluebuttonbn_delete_recordings(implode(",", array_keys($recordings))); |
529
|
|
|
} |
530
|
|
|
|
531
|
|
|
/** |
532
|
|
|
* List of view style log actions. |
533
|
|
|
* |
534
|
|
|
* @return string[] |
535
|
|
|
*/ |
536
|
|
|
function bigbluebuttonbn_get_view_actions() { |
537
|
|
|
return array('view', 'view all'); |
538
|
|
|
} |
539
|
|
|
|
540
|
|
|
/** |
541
|
|
|
* List of update style log actions. |
542
|
|
|
* |
543
|
|
|
* @return string[] |
544
|
|
|
*/ |
545
|
|
|
function bigbluebuttonbn_get_post_actions() { |
546
|
|
|
return array('update', 'add', 'delete'); |
547
|
|
|
} |
548
|
|
|
|
549
|
|
|
/** |
550
|
|
|
* Print an overview of all bigbluebuttonbn instances for the courses. |
551
|
|
|
* |
552
|
|
|
* @param array $courses |
553
|
|
|
* @param array $htmlarray Passed by reference |
554
|
|
|
* |
555
|
|
|
* @return void |
556
|
|
|
*/ |
557
|
|
|
function bigbluebuttonbn_print_overview($courses, &$htmlarray) { |
558
|
|
|
if (empty($courses) || !is_array($courses)) { |
559
|
|
|
return array(); |
560
|
|
|
} |
561
|
|
|
$bns = get_all_instances_in_courses('bigbluebuttonbn', $courses); |
562
|
|
|
foreach ($bns as $bn) { |
563
|
|
|
$now = time(); |
564
|
|
|
if ($bn->openingtime and (!$bn->closingtime or $bn->closingtime > $now)) { |
565
|
|
|
// A bigbluebuttonbn is scheduled. |
566
|
|
|
if (empty($htmlarray[$bn->course]['bigbluebuttonbn'])) { |
567
|
|
|
$htmlarray[$bn->course]['bigbluebuttonbn'] = ''; |
568
|
|
|
} |
569
|
|
|
// Make sure we print all bigbluebutton instances. |
570
|
|
|
$htmlarray[$bn->course]['bigbluebuttonbn'] .= bigbluebuttonbn_print_overview_element($bn, $now); |
571
|
|
|
} |
572
|
|
|
} |
573
|
|
|
} |
574
|
|
|
|
575
|
|
|
/** |
576
|
|
|
* Print an overview of a bigbluebuttonbn instance. |
577
|
|
|
* |
578
|
|
|
* @param array $bigbluebuttonbn |
579
|
|
|
* @param int $now |
580
|
|
|
* |
581
|
|
|
* @return string |
582
|
|
|
*/ |
583
|
|
|
function bigbluebuttonbn_print_overview_element($bigbluebuttonbn, $now) { |
584
|
|
|
global $CFG; |
585
|
|
|
$start = 'started_at'; |
586
|
|
|
if ($bigbluebuttonbn->openingtime > $now) { |
587
|
|
|
$start = 'starts_at'; |
588
|
|
|
} |
589
|
|
|
$classes = ''; |
590
|
|
|
if ($bigbluebuttonbn->visible) { |
591
|
|
|
$classes = 'class="dimmed" '; |
592
|
|
|
} |
593
|
|
|
$str = '<div class="bigbluebuttonbn overview">'."\n"; |
594
|
|
|
$str .= ' <div class="name">'.get_string('modulename', 'bigbluebuttonbn').': '."\n"; |
595
|
|
|
$str .= ' <a '.$classes.'href="'.$CFG->wwwroot.'/mod/bigbluebuttonbn/view.php?id='.$bigbluebuttonbn->coursemodule. |
596
|
|
|
'">'.$bigbluebuttonbn->name.'</a>'."\n"; |
597
|
|
|
$str .= ' </div>'."\n"; |
598
|
|
|
$str .= ' <div class="info">'.get_string($start, 'bigbluebuttonbn').': '.userdate($bigbluebuttonbn->openingtime). |
599
|
|
|
'</div>'."\n"; |
600
|
|
|
if (!empty($bigbluebuttonbn->closingtime)) { |
601
|
|
|
$str .= ' <div class="info">'.get_string('ends_at', 'bigbluebuttonbn').': '.userdate($bigbluebuttonbn->closingtime) |
602
|
|
|
.'</div>'."\n"; |
603
|
|
|
} |
604
|
|
|
$str .= '</div>'."\n"; |
605
|
|
|
return $str; |
606
|
|
|
} |
607
|
|
|
|
608
|
|
|
/** |
609
|
|
|
* Given a course_module object, this function returns any |
610
|
|
|
* "extra" information that may be needed when printing |
611
|
|
|
* this activity in a course listing. |
612
|
|
|
* See get_array_of_activities() in course/lib.php. |
613
|
|
|
* |
614
|
|
|
* @param object $coursemodule |
615
|
|
|
* |
616
|
|
|
* @return null|cached_cm_info |
617
|
|
|
*/ |
618
|
|
|
function bigbluebuttonbn_get_coursemodule_info($coursemodule) { |
619
|
|
|
global $DB; |
620
|
|
|
|
621
|
|
|
$dbparams = ['id' => $coursemodule->instance]; |
622
|
|
|
$fields = 'id, name, intro, introformat, completionattendance'; |
623
|
|
|
$bigbluebuttonbn = $DB->get_record('bigbluebuttonbn', $dbparams, $fields); |
624
|
|
|
if (!$bigbluebuttonbn) { |
625
|
|
|
return false; |
626
|
|
|
} |
627
|
|
|
$info = new cached_cm_info(); |
628
|
|
|
$info->name = $bigbluebuttonbn->name; |
629
|
|
|
if ($coursemodule->showdescription) { |
630
|
|
|
// Convert intro to html. Do not filter cached version, filters run at display time. |
631
|
|
|
$info->content = format_module_intro('bigbluebuttonbn', $bigbluebuttonbn, $coursemodule->id, false); |
632
|
|
|
} |
633
|
|
|
// Populate the custom completion rules as key => value pairs, but only if the completion mode is 'automatic'. |
634
|
|
|
if ($coursemodule->completion == COMPLETION_TRACKING_AUTOMATIC) { |
635
|
|
|
$info->customdata['customcompletionrules']['completionattendance'] = $bigbluebuttonbn->completionattendance; |
636
|
|
|
} |
637
|
|
|
|
638
|
|
|
return $info; |
639
|
|
|
} |
640
|
|
|
|
641
|
|
|
/** |
642
|
|
|
* Callback which returns human-readable strings describing the active completion custom rules for the module instance. |
643
|
|
|
* |
644
|
|
|
* @param cm_info|stdClass $cm object with fields ->completion and ->customdata['customcompletionrules'] |
645
|
|
|
* @return array $descriptions the array of descriptions for the custom rules. |
646
|
|
|
*/ |
647
|
|
|
function mod_bigbluebuttonbn_get_completion_active_rule_descriptions($cm) { |
648
|
|
|
// Values will be present in cm_info, and we assume these are up to date. |
649
|
|
|
if (empty($cm->customdata['customcompletionrules']) |
650
|
|
|
|| $cm->completion != COMPLETION_TRACKING_AUTOMATIC) { |
651
|
|
|
return []; |
652
|
|
|
} |
653
|
|
|
|
654
|
|
|
$descriptions = []; |
655
|
|
|
foreach ($cm->customdata['customcompletionrules'] as $key => $val) { |
656
|
|
|
switch ($key) { |
657
|
|
|
case 'completionattendance': |
658
|
|
|
if (!empty($val)) { |
659
|
|
|
$descriptions[] = get_string('completionattendancedesc', 'bigbluebuttonbn', $val); |
660
|
|
|
$descriptions[] = get_string('completionengagementdesc', 'bigbluebuttonbn', $val); |
661
|
|
|
} |
662
|
|
|
break; |
663
|
|
|
default: |
664
|
|
|
break; |
665
|
|
|
} |
666
|
|
|
} |
667
|
|
|
return $descriptions; |
668
|
|
|
} |
669
|
|
|
|
670
|
|
|
/** |
671
|
|
|
* Runs any processes that must run before a bigbluebuttonbn insert/update. |
672
|
|
|
* |
673
|
|
|
* @param object $bigbluebuttonbn BigBlueButtonBN form data |
674
|
|
|
* |
675
|
|
|
* @return void |
676
|
|
|
**/ |
677
|
|
|
function bigbluebuttonbn_process_pre_save(&$bigbluebuttonbn) { |
678
|
|
|
bigbluebuttonbn_process_pre_save_instance($bigbluebuttonbn); |
679
|
|
|
bigbluebuttonbn_process_pre_save_checkboxes($bigbluebuttonbn); |
680
|
|
|
bigbluebuttonbn_process_pre_save_common($bigbluebuttonbn); |
681
|
|
|
$bigbluebuttonbn->participants = htmlspecialchars_decode($bigbluebuttonbn->participants); |
682
|
|
|
} |
683
|
|
|
|
684
|
|
|
/** |
685
|
|
|
* Runs process for defining the instance (insert/update). |
686
|
|
|
* |
687
|
|
|
* @param object $bigbluebuttonbn BigBlueButtonBN form data |
688
|
|
|
* |
689
|
|
|
* @return void |
690
|
|
|
**/ |
691
|
|
|
function bigbluebuttonbn_process_pre_save_instance(&$bigbluebuttonbn) { |
692
|
|
|
require_once(__DIR__.'/locallib.php'); |
693
|
|
|
$bigbluebuttonbn->timemodified = time(); |
694
|
|
|
if ((integer)$bigbluebuttonbn->instance == 0) { |
695
|
|
|
$bigbluebuttonbn->meetingid = 0; |
696
|
|
|
$bigbluebuttonbn->timecreated = time(); |
697
|
|
|
$bigbluebuttonbn->timemodified = 0; |
698
|
|
|
// As it is a new activity, assign passwords. |
699
|
|
|
$bigbluebuttonbn->moderatorpass = bigbluebuttonbn_random_password(12); |
700
|
|
|
$bigbluebuttonbn->viewerpass = bigbluebuttonbn_random_password(12, $bigbluebuttonbn->moderatorpass); |
701
|
|
|
} |
702
|
|
|
} |
703
|
|
|
|
704
|
|
|
/** |
705
|
|
|
* Runs process for assigning default value to checkboxes. |
706
|
|
|
* |
707
|
|
|
* @param object $bigbluebuttonbn BigBlueButtonBN form data |
708
|
|
|
* |
709
|
|
|
* @return void |
710
|
|
|
**/ |
711
|
|
|
function bigbluebuttonbn_process_pre_save_checkboxes(&$bigbluebuttonbn) { |
712
|
|
|
if (!isset($bigbluebuttonbn->wait)) { |
713
|
|
|
$bigbluebuttonbn->wait = 0; |
714
|
|
|
} |
715
|
|
|
if (!isset($bigbluebuttonbn->record)) { |
716
|
|
|
$bigbluebuttonbn->record = 0; |
717
|
|
|
} |
718
|
|
|
if (!isset($bigbluebuttonbn->recordallfromstart)) { |
719
|
|
|
$bigbluebuttonbn->recordallfromstart = 0; |
720
|
|
|
} |
721
|
|
|
if (!isset($bigbluebuttonbn->recordhidebutton)) { |
722
|
|
|
$bigbluebuttonbn->recordhidebutton = 0; |
723
|
|
|
} |
724
|
|
|
if (!isset($bigbluebuttonbn->recordings_html)) { |
725
|
|
|
$bigbluebuttonbn->recordings_html = 0; |
726
|
|
|
} |
727
|
|
|
if (!isset($bigbluebuttonbn->recordings_deleted)) { |
728
|
|
|
$bigbluebuttonbn->recordings_deleted = 0; |
729
|
|
|
} |
730
|
|
|
if (!isset($bigbluebuttonbn->recordings_imported)) { |
731
|
|
|
$bigbluebuttonbn->recordings_imported = 0; |
732
|
|
|
} |
733
|
|
|
if (!isset($bigbluebuttonbn->recordings_preview)) { |
734
|
|
|
$bigbluebuttonbn->recordings_preview = 0; |
735
|
|
|
} |
736
|
|
|
if (!isset($bigbluebuttonbn->muteonstart)) { |
737
|
|
|
$bigbluebuttonbn->muteonstart = 0; |
738
|
|
|
} |
739
|
|
|
if (!isset($bigbluebuttonbn->disablecam)) { |
740
|
|
|
$bigbluebuttonbn->disablecam = 0; |
741
|
|
|
} |
742
|
|
|
if (!isset($bigbluebuttonbn->disablemic)) { |
743
|
|
|
$bigbluebuttonbn->disablemic = 0; |
744
|
|
|
} |
745
|
|
|
if (!isset($bigbluebuttonbn->disableprivatechat)) { |
746
|
|
|
$bigbluebuttonbn->disableprivatechat = 0; |
747
|
|
|
} |
748
|
|
|
if (!isset($bigbluebuttonbn->disablepublicchat)) { |
749
|
|
|
$bigbluebuttonbn->disablepublicchat = 0; |
750
|
|
|
} |
751
|
|
|
if (!isset($bigbluebuttonbn->disablenote)) { |
752
|
|
|
$bigbluebuttonbn->disablenote = 0; |
753
|
|
|
} |
754
|
|
|
if (!isset($bigbluebuttonbn->hideuserlist)) { |
755
|
|
|
$bigbluebuttonbn->hideuserlist = 0; |
756
|
|
|
} |
757
|
|
|
if (!isset($bigbluebuttonbn->lockedlayout)) { |
758
|
|
|
$bigbluebuttonbn->lockedlayout = 0; |
759
|
|
|
} |
760
|
|
|
if (!isset($bigbluebuttonbn->lockonjoin)) { |
761
|
|
|
$bigbluebuttonbn->lockonjoin = 0; |
762
|
|
|
} |
763
|
|
|
if (!isset($bigbluebuttonbn->lockonjoinconfigurable)) { |
764
|
|
|
$bigbluebuttonbn->lockonjoinconfigurable = 0; |
765
|
|
|
} |
766
|
|
|
if (!isset($bigbluebuttonbn->recordings_validate_url)) { |
767
|
|
|
$bigbluebuttonbn->recordings_validate_url = 1; |
768
|
|
|
} |
769
|
|
|
} |
770
|
|
|
|
771
|
|
|
/** |
772
|
|
|
* Runs process for wipping common settings when 'recordings only'. |
773
|
|
|
* |
774
|
|
|
* @param object $bigbluebuttonbn BigBlueButtonBN form data |
775
|
|
|
* |
776
|
|
|
* @return void |
777
|
|
|
**/ |
778
|
|
|
function bigbluebuttonbn_process_pre_save_common(&$bigbluebuttonbn) { |
779
|
|
|
// Make sure common settings are removed when 'recordings only'. |
780
|
|
|
if ($bigbluebuttonbn->type == BIGBLUEBUTTONBN_TYPE_RECORDING_ONLY) { |
781
|
|
|
$bigbluebuttonbn->groupmode = 0; |
782
|
|
|
$bigbluebuttonbn->groupingid = 0; |
783
|
|
|
} |
784
|
|
|
} |
785
|
|
|
|
786
|
|
|
/** |
787
|
|
|
* Runs any processes that must be run after a bigbluebuttonbn insert/update. |
788
|
|
|
* |
789
|
|
|
* @param object $bigbluebuttonbn BigBlueButtonBN form data |
790
|
|
|
* |
791
|
|
|
* @return void |
792
|
|
|
**/ |
793
|
|
|
function bigbluebuttonbn_process_post_save(&$bigbluebuttonbn) { |
794
|
|
|
if (isset($bigbluebuttonbn->notification) && $bigbluebuttonbn->notification) { |
795
|
|
|
bigbluebuttonbn_process_post_save_notification($bigbluebuttonbn); |
796
|
|
|
} |
797
|
|
|
bigbluebuttonbn_process_post_save_event($bigbluebuttonbn); |
798
|
|
|
bigbluebuttonbn_process_post_save_completion($bigbluebuttonbn); |
799
|
|
|
} |
800
|
|
|
|
801
|
|
|
/** |
802
|
|
|
* Generates a message on insert/update which is sent to all users enrolled. |
803
|
|
|
* |
804
|
|
|
* @param object $bigbluebuttonbn BigBlueButtonBN form data |
805
|
|
|
* |
806
|
|
|
* @return void |
807
|
|
|
**/ |
808
|
|
|
function bigbluebuttonbn_process_post_save_notification(&$bigbluebuttonbn) { |
809
|
|
|
$action = get_string('mod_form_field_notification_msg_modified', 'bigbluebuttonbn'); |
810
|
|
|
if (isset($bigbluebuttonbn->add) && !empty($bigbluebuttonbn->add)) { |
811
|
|
|
$action = get_string('mod_form_field_notification_msg_created', 'bigbluebuttonbn'); |
812
|
|
|
} |
813
|
|
|
\mod_bigbluebuttonbn\locallib\notifier::notify_instance_updated($bigbluebuttonbn, $action); |
814
|
|
|
} |
815
|
|
|
|
816
|
|
|
/** |
817
|
|
|
* Generates an event after a bigbluebuttonbn insert/update. |
818
|
|
|
* |
819
|
|
|
* @param object $bigbluebuttonbn BigBlueButtonBN form data |
820
|
|
|
* |
821
|
|
|
* @return void |
822
|
|
|
**/ |
823
|
|
|
function bigbluebuttonbn_process_post_save_event(&$bigbluebuttonbn) { |
824
|
|
|
global $CFG, $DB; |
825
|
|
|
require_once($CFG->dirroot.'/calendar/lib.php'); |
826
|
|
|
$eventid = $DB->get_field('event', 'id', array('modulename' => 'bigbluebuttonbn', |
827
|
|
|
'instance' => $bigbluebuttonbn->id)); |
828
|
|
|
// Delete the event from calendar when/if openingtime is NOT set. |
829
|
|
|
if (!isset($bigbluebuttonbn->openingtime) || !$bigbluebuttonbn->openingtime) { |
830
|
|
|
if ($eventid) { |
831
|
|
|
$calendarevent = calendar_event::load($eventid); |
832
|
|
|
$calendarevent->delete(); |
833
|
|
|
} |
834
|
|
|
return; |
835
|
|
|
} |
836
|
|
|
// Add evento to the calendar as openingtime is set. |
837
|
|
|
$event = new stdClass(); |
838
|
|
|
$event->eventtype = BIGBLUEBUTTON_EVENT_MEETING_START; |
839
|
|
|
$event->type = CALENDAR_EVENT_TYPE_ACTION; |
840
|
|
|
$event->name = get_string('calendarstarts', 'bigbluebuttonbn', $bigbluebuttonbn->name); |
841
|
|
|
$event->description = format_module_intro('bigbluebuttonbn', $bigbluebuttonbn, $bigbluebuttonbn->coursemodule, false); |
842
|
|
|
$event->format = FORMAT_HTML; |
843
|
|
|
$event->courseid = $bigbluebuttonbn->course; |
844
|
|
|
$event->groupid = 0; |
845
|
|
|
$event->userid = 0; |
846
|
|
|
$event->modulename = 'bigbluebuttonbn'; |
847
|
|
|
$event->instance = $bigbluebuttonbn->id; |
848
|
|
|
$event->timestart = $bigbluebuttonbn->openingtime; |
849
|
|
|
$event->timeduration = 0; |
850
|
|
|
$event->timesort = $event->timestart; |
851
|
|
|
$event->visible = instance_is_visible('bigbluebuttonbn', $bigbluebuttonbn); |
852
|
|
|
$event->priority = null; |
853
|
|
|
// Update the event in calendar when/if eventid was found. |
854
|
|
|
if ($eventid) { |
855
|
|
|
$event->id = $eventid; |
856
|
|
|
$calendarevent = calendar_event::load($eventid); |
857
|
|
|
$calendarevent->update($event); |
858
|
|
|
return; |
859
|
|
|
} |
860
|
|
|
calendar_event::create($event); |
861
|
|
|
} |
862
|
|
|
|
863
|
|
|
/** |
864
|
|
|
* Generates an event after a bigbluebuttonbn activity is completed. |
865
|
|
|
* |
866
|
|
|
* @param object $bigbluebuttonbn BigBlueButtonBN form data |
867
|
|
|
* |
868
|
|
|
* @return void |
869
|
|
|
**/ |
870
|
|
|
function bigbluebuttonbn_process_post_save_completion($bigbluebuttonbn) { |
871
|
|
|
if (!empty($bigbluebuttonbn->completionexpected)) { |
872
|
|
|
\core_completion\api::update_completion_date_event( |
873
|
|
|
$bigbluebuttonbn->coursemodule, |
874
|
|
|
'bigbluebuttonbn', |
875
|
|
|
$bigbluebuttonbn->id, |
876
|
|
|
$bigbluebuttonbn->completionexpected |
877
|
|
|
); |
878
|
|
|
} |
879
|
|
|
} |
880
|
|
|
|
881
|
|
|
/** |
882
|
|
|
* Get a full path to the file attached as a preuploaded presentation |
883
|
|
|
* or if there is none, set the presentation field will be set to blank. |
884
|
|
|
* |
885
|
|
|
* @param object $bigbluebuttonbn BigBlueButtonBN form data |
886
|
|
|
* |
887
|
|
|
* @return string |
888
|
|
|
*/ |
889
|
|
|
function bigbluebuttonbn_get_media_file(&$bigbluebuttonbn) { |
890
|
|
|
if (!isset($bigbluebuttonbn->presentation) || $bigbluebuttonbn->presentation == '') { |
891
|
|
|
return ''; |
892
|
|
|
} |
893
|
|
|
$context = context_module::instance($bigbluebuttonbn->coursemodule); |
894
|
|
|
// Set the filestorage object. |
895
|
|
|
$fs = get_file_storage(); |
896
|
|
|
// Save the file if it exists that is currently in the draft area. |
897
|
|
|
file_save_draft_area_files($bigbluebuttonbn->presentation, $context->id, 'mod_bigbluebuttonbn', 'presentation', 0); |
898
|
|
|
// Get the file if it exists. |
899
|
|
|
$files = $fs->get_area_files( |
900
|
|
|
$context->id, |
901
|
|
|
'mod_bigbluebuttonbn', |
902
|
|
|
'presentation', |
903
|
|
|
0, |
904
|
|
|
'itemid, filepath, filename', |
905
|
|
|
false |
906
|
|
|
); |
907
|
|
|
// Check that there is a file to process. |
908
|
|
|
$filesrc = ''; |
909
|
|
|
if (count($files) == 1) { |
910
|
|
|
// Get the first (and only) file. |
911
|
|
|
$file = reset($files); |
912
|
|
|
$filesrc = '/'.$file->get_filename(); |
913
|
|
|
} |
914
|
|
|
return $filesrc; |
915
|
|
|
} |
916
|
|
|
|
917
|
|
|
/** |
918
|
|
|
* Serves the bigbluebuttonbn attachments. Implements needed access control ;-). |
919
|
|
|
* |
920
|
|
|
* @category files |
921
|
|
|
* |
922
|
|
|
* @param stdClass $course course object |
923
|
|
|
* @param stdClass $cm course module object |
924
|
|
|
* @param stdClass $context context object |
925
|
|
|
* @param string $filearea file area |
926
|
|
|
* @param array $args extra arguments |
927
|
|
|
* @param bool $forcedownload whether or not force download |
928
|
|
|
* @param array $options additional options affecting the file serving |
929
|
|
|
* |
930
|
|
|
* @return false|null false if file not found, does not return if found - justsend the file |
931
|
|
|
*/ |
932
|
|
|
function bigbluebuttonbn_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options = array()) { |
933
|
|
|
if (!bigbluebuttonbn_pluginfile_valid($context, $filearea)) { |
934
|
|
|
return false; |
935
|
|
|
} |
936
|
|
|
$file = bigbluebuttonbn_pluginfile_file($course, $cm, $context, $filearea, $args); |
937
|
|
|
if (empty($file)) { |
938
|
|
|
return false; |
939
|
|
|
} |
940
|
|
|
// Finally send the file. |
941
|
|
|
send_stored_file($file, 0, 0, $forcedownload, $options); // Download MUST be forced - security! |
942
|
|
|
} |
943
|
|
|
|
944
|
|
|
/** |
945
|
|
|
* Helper for validating pluginfile. |
946
|
|
|
* @param stdClass $context context object |
947
|
|
|
* @param string $filearea file area |
948
|
|
|
* |
949
|
|
|
* @return false|null false if file not valid |
950
|
|
|
*/ |
951
|
|
|
function bigbluebuttonbn_pluginfile_valid($context, $filearea) { |
952
|
|
|
|
953
|
|
|
// Can be in context module or in context_system (if is the presentation by default). |
954
|
|
|
if (!in_array($context->contextlevel, array(CONTEXT_MODULE, CONTEXT_SYSTEM))) { |
955
|
|
|
return false; |
956
|
|
|
} |
957
|
|
|
|
958
|
|
|
if (!array_key_exists($filearea, bigbluebuttonbn_get_file_areas())) { |
959
|
|
|
return false; |
960
|
|
|
} |
961
|
|
|
|
962
|
|
|
return true; |
963
|
|
|
} |
964
|
|
|
|
965
|
|
|
/** |
966
|
|
|
* Helper for getting pluginfile. |
967
|
|
|
* |
968
|
|
|
* @param stdClass $course course object |
969
|
|
|
* @param stdClass $cm course module object |
970
|
|
|
* @param stdClass $context context object |
971
|
|
|
* @param string $filearea file area |
972
|
|
|
* @param array $args extra arguments |
973
|
|
|
* |
974
|
|
|
* @return object |
975
|
|
|
*/ |
976
|
|
|
function bigbluebuttonbn_pluginfile_file($course, $cm, $context, $filearea, $args) { |
977
|
|
|
$filename = bigbluebuttonbn_pluginfile_filename($course, $cm, $context, $args); |
978
|
|
|
if (!$filename) { |
|
|
|
|
979
|
|
|
return false; |
980
|
|
|
} |
981
|
|
|
$fullpath = "/$context->id/mod_bigbluebuttonbn/$filearea/0/".$filename; |
982
|
|
|
$fs = get_file_storage(); |
983
|
|
|
$file = $fs->get_file_by_hash(sha1($fullpath)); |
984
|
|
|
if (!$file || $file->is_directory()) { |
985
|
|
|
return false; |
986
|
|
|
} |
987
|
|
|
return $file; |
988
|
|
|
} |
989
|
|
|
|
990
|
|
|
/** |
991
|
|
|
* Helper for give access to the file configured in setting as default presentation. |
992
|
|
|
* |
993
|
|
|
* @param stdClass $course course object |
994
|
|
|
* @param stdClass $cm course module object |
995
|
|
|
* @param stdClass $context context object |
996
|
|
|
* @param array $args extra arguments |
997
|
|
|
* |
998
|
|
|
* @return array |
999
|
|
|
*/ |
1000
|
|
|
function bigbluebuttonbn_default_presentation_get_file($course, $cm, $context, $args) { |
1001
|
|
|
|
1002
|
|
|
// The difference with the standard bigbluebuttonbn_pluginfile_filename() are. |
1003
|
|
|
// - Context is system, so we don't need to check the cmid in this case. |
1004
|
|
|
// - The area is "presentationdefault_cache". |
1005
|
|
|
if (count($args) > 1) { |
1006
|
|
|
$cache = cache::make_from_params( |
1007
|
|
|
cache_store::MODE_APPLICATION, |
1008
|
|
|
'mod_bigbluebuttonbn', |
1009
|
|
|
'presentationdefault_cache' |
1010
|
|
|
); |
1011
|
|
|
|
1012
|
|
|
$noncekey = sha1($context->id); |
1013
|
|
|
$presentationnonce = $cache->get($noncekey); |
1014
|
|
|
$noncevalue = $presentationnonce['value']; |
1015
|
|
|
$noncecounter = $presentationnonce['counter']; |
1016
|
|
|
if ($args['0'] != $noncevalue) { |
1017
|
|
|
return; |
1018
|
|
|
} |
1019
|
|
|
|
1020
|
|
|
// The nonce value is actually used twice because BigBlueButton reads the file two times. |
1021
|
|
|
$noncecounter += 1; |
1022
|
|
|
$cache->set($noncekey, array('value' => $noncevalue, 'counter' => $noncecounter)); |
1023
|
|
|
if ($noncecounter == 2) { |
1024
|
|
|
$cache->delete($noncekey); |
1025
|
|
|
} |
1026
|
|
|
return($args['1']); |
1027
|
|
|
} |
1028
|
|
|
require_course_login($course, true, $cm); |
1029
|
|
|
if (!has_capability('mod/bigbluebuttonbn:join', $context)) { |
1030
|
|
|
return; |
1031
|
|
|
} |
1032
|
|
|
return implode('/', $args); |
1033
|
|
|
} |
1034
|
|
|
|
1035
|
|
|
/** |
1036
|
|
|
* Helper for getting pluginfile name. |
1037
|
|
|
* |
1038
|
|
|
* @param stdClass $course course object |
1039
|
|
|
* @param stdClass $cm course module object |
1040
|
|
|
* @param stdClass $context context object |
1041
|
|
|
* @param array $args extra arguments |
1042
|
|
|
* |
1043
|
|
|
* @return array |
1044
|
|
|
*/ |
1045
|
|
|
function bigbluebuttonbn_pluginfile_filename($course, $cm, $context, $args) { |
1046
|
|
|
global $DB; |
1047
|
|
|
|
1048
|
|
|
if ($context->contextlevel == CONTEXT_SYSTEM) { |
1049
|
|
|
// Plugin has a file to use as default in general setting. |
1050
|
|
|
return(bigbluebuttonbn_default_presentation_get_file($course, $cm, $context, $args)); |
1051
|
|
|
} |
1052
|
|
|
|
1053
|
|
|
if (count($args) > 1) { |
1054
|
|
|
if (!$bigbluebuttonbn = $DB->get_record('bigbluebuttonbn', array('id' => $cm->instance))) { |
1055
|
|
|
return; |
1056
|
|
|
} |
1057
|
|
|
$cache = cache::make_from_params(cache_store::MODE_APPLICATION, 'mod_bigbluebuttonbn', 'presentation_cache'); |
1058
|
|
|
$noncekey = sha1($bigbluebuttonbn->id); |
1059
|
|
|
$presentationnonce = $cache->get($noncekey); |
1060
|
|
|
if (!empty($presentationnonce)) { |
1061
|
|
|
$noncevalue = $presentationnonce['value']; |
1062
|
|
|
$noncecounter = $presentationnonce['counter']; |
1063
|
|
|
} else { |
1064
|
|
|
$noncevalue = null; |
1065
|
|
|
$noncecounter = 0; |
1066
|
|
|
} |
1067
|
|
|
|
1068
|
|
|
if ($args['0'] != $noncevalue) { |
1069
|
|
|
return; |
1070
|
|
|
} |
1071
|
|
|
// The nonce value is actually used twice because BigBlueButton reads the file two times. |
1072
|
|
|
$noncecounter += 1; |
1073
|
|
|
$cache->set($noncekey, array('value' => $noncevalue, 'counter' => $noncecounter)); |
1074
|
|
|
if ($noncecounter == 2) { |
1075
|
|
|
$cache->delete($noncekey); |
1076
|
|
|
} |
1077
|
|
|
return $args['1']; |
1078
|
|
|
} |
1079
|
|
|
require_course_login($course, true, $cm); |
1080
|
|
|
if (!has_capability('mod/bigbluebuttonbn:join', $context)) { |
1081
|
|
|
return; |
1082
|
|
|
} |
1083
|
|
|
return implode('/', $args); |
1084
|
|
|
} |
1085
|
|
|
|
1086
|
|
|
/** |
1087
|
|
|
* Returns an array of file areas. |
1088
|
|
|
* |
1089
|
|
|
* @category files |
1090
|
|
|
* |
1091
|
|
|
* @return array a list of available file areas |
1092
|
|
|
*/ |
1093
|
|
|
function bigbluebuttonbn_get_file_areas() { |
1094
|
|
|
$areas = array(); |
1095
|
|
|
$areas['presentation'] = get_string('mod_form_block_presentation', 'bigbluebuttonbn'); |
1096
|
|
|
$areas['presentationdefault'] = get_string('mod_form_block_presentation_default', 'bigbluebuttonbn'); |
1097
|
|
|
return $areas; |
1098
|
|
|
} |
1099
|
|
|
|
1100
|
|
|
/** |
1101
|
|
|
* Mark the activity completed (if required) and trigger the course_module_viewed event. |
1102
|
|
|
* |
1103
|
|
|
* @param stdClass $bigbluebuttonbn bigbluebuttonbn object |
1104
|
|
|
* @param stdClass $course course object |
1105
|
|
|
* @param stdClass $cm course module object |
1106
|
|
|
* @param stdClass $context context object |
1107
|
|
|
* @since Moodle 3.0 |
1108
|
|
|
*/ |
1109
|
|
|
function bigbluebuttonbn_view($bigbluebuttonbn, $course, $cm, $context) { |
1110
|
|
|
|
1111
|
|
|
// Trigger course_module_viewed event. |
1112
|
|
|
$params = array( |
1113
|
|
|
'context' => $context, |
1114
|
|
|
'objectid' => $bigbluebuttonbn->id |
1115
|
|
|
); |
1116
|
|
|
|
1117
|
|
|
$event = \mod_bigbluebuttonbn\event\activity_viewed::create($params); // Fix event name. |
1118
|
|
|
$event->add_record_snapshot('course_modules', $cm); |
1119
|
|
|
$event->add_record_snapshot('course', $course); |
1120
|
|
|
$event->add_record_snapshot('bigbluebuttonbn', $bigbluebuttonbn); |
1121
|
|
|
$event->trigger(); |
1122
|
|
|
|
1123
|
|
|
// Completion. |
1124
|
|
|
$completion = new completion_info($course); |
1125
|
|
|
$completion->set_module_viewed($cm); |
1126
|
|
|
} |
1127
|
|
|
|
1128
|
|
|
/** |
1129
|
|
|
* Check if the module has any update that affects the current user since a given time. |
1130
|
|
|
* |
1131
|
|
|
* @param cm_info $cm course module data |
1132
|
|
|
* @param int $from the time to check updates from |
1133
|
|
|
* @param array $filter if we need to check only specific updates |
1134
|
|
|
* @return stdClass an object with the different type of areas indicating if they were updated or not |
1135
|
|
|
* @since Moodle 3.2 |
1136
|
|
|
*/ |
1137
|
|
|
function bigbluebuttonbn_check_updates_since(cm_info $cm, $from, $filter = array()) { |
1138
|
|
|
$updates = course_check_module_updates_since($cm, $from, array('content'), $filter); |
1139
|
|
|
return $updates; |
1140
|
|
|
} |
1141
|
|
|
|
1142
|
|
|
|
1143
|
|
|
/** |
1144
|
|
|
* Get icon mapping for font-awesome. |
1145
|
|
|
*/ |
1146
|
|
|
function mod_bigbluebuttonbn_get_fontawesome_icon_map() { |
1147
|
|
|
return [ |
1148
|
|
|
'mod_bigbluebuttonbn:icon' => 'icon-bigbluebutton', |
1149
|
|
|
]; |
1150
|
|
|
} |
1151
|
|
|
|
1152
|
|
|
/** |
1153
|
|
|
* This function receives a calendar event and returns the action associated with it, or null if there is none. |
1154
|
|
|
* |
1155
|
|
|
* This is used by block_myoverview in order to display the event appropriately. If null is returned then the event |
1156
|
|
|
* is not displayed on the block. |
1157
|
|
|
* |
1158
|
|
|
* @param calendar_event $event |
1159
|
|
|
* @param \core_calendar\action_factory $factory |
1160
|
|
|
* @return \core_calendar\local\event\entities\action_interface|null |
1161
|
|
|
*/ |
1162
|
|
|
function mod_bigbluebuttonbn_core_calendar_provide_event_action( |
1163
|
|
|
calendar_event $event, |
1164
|
|
|
\core_calendar\action_factory $factory |
1165
|
|
|
) { |
1166
|
|
|
global $CFG, $DB; |
1167
|
|
|
|
1168
|
|
|
require_once($CFG->dirroot . '/mod/bigbluebuttonbn/locallib.php'); |
1169
|
|
|
|
1170
|
|
|
$time = time(); |
1171
|
|
|
|
1172
|
|
|
// Get mod info. |
1173
|
|
|
$cm = get_fast_modinfo($event->courseid)->instances['bigbluebuttonbn'][$event->instance]; |
1174
|
|
|
|
1175
|
|
|
// Get bigbluebuttonbn activity. |
1176
|
|
|
$bigbluebuttonbn = $DB->get_record('bigbluebuttonbn', array('id' => $event->instance), '*', MUST_EXIST); |
1177
|
|
|
|
1178
|
|
|
// Set flag haspassed if closingtime has already passed only if it is defined. |
1179
|
|
|
$haspassed = ($bigbluebuttonbn->closingtime) && $bigbluebuttonbn->closingtime < $time; |
1180
|
|
|
|
1181
|
|
|
// Set flag hasstarted if startingtime has already passed or not defined. |
1182
|
|
|
$hasstarted = $bigbluebuttonbn->openingtime < $time; |
1183
|
|
|
|
1184
|
|
|
// Return null if it has passed or not started. |
1185
|
|
|
if ($haspassed || !$hasstarted) { |
1186
|
|
|
return null; |
1187
|
|
|
} |
1188
|
|
|
|
1189
|
|
|
// Get if the user has joined in live session or viewed the recorded. |
1190
|
|
|
$usercomplete = bigbluebuttonbn_user_complete($event->courseid, $event->userid, $bigbluebuttonbn); |
1191
|
|
|
// Get if the room is available. |
1192
|
|
|
list($roomavailable) = bigbluebuttonbn_room_is_available($bigbluebuttonbn); |
1193
|
|
|
// Get if the user can join. |
1194
|
|
|
list($usercanjoin) = bigbluebuttonbn_user_can_join_meeting($bigbluebuttonbn); |
1195
|
|
|
|
1196
|
|
|
// Check if the room is closed and the user has already joined this session or played the record. |
1197
|
|
|
if (!$roomavailable && $usercomplete) { |
1198
|
|
|
return null; |
1199
|
|
|
} |
1200
|
|
|
|
1201
|
|
|
// Check if the user can join this session. |
1202
|
|
|
$actionable = ($roomavailable && $usercanjoin); |
1203
|
|
|
|
1204
|
|
|
// Action data. |
1205
|
|
|
$string = get_string('view_room', 'bigbluebuttonbn'); |
1206
|
|
|
$url = new \moodle_url('/mod/bigbluebuttonbn/view.php', array('id' => $cm->id)); |
1207
|
|
|
if (groups_get_activity_groupmode($cm) == NOGROUPS) { |
1208
|
|
|
// No groups mode. |
1209
|
|
|
$string = get_string('view_conference_action_join', 'bigbluebuttonbn'); |
1210
|
|
|
$url = new \moodle_url('/mod/bigbluebuttonbn/bbb_view.php', array('action' => 'join', |
1211
|
|
|
'id' => $cm->id, 'bn' => $bigbluebuttonbn->id, 'timeline' => 1)); |
1212
|
|
|
} |
1213
|
|
|
|
1214
|
|
|
return $factory->create_instance($string, $url, 1, $actionable); |
1215
|
|
|
} |
1216
|
|
|
|
1217
|
|
|
/** |
1218
|
|
|
* Register a bigbluebuttonbn event |
1219
|
|
|
* |
1220
|
|
|
* @param object $bigbluebuttonbn |
1221
|
|
|
* @param string $event |
1222
|
|
|
* @param array $overrides |
1223
|
|
|
* @param string $meta |
1224
|
|
|
* |
1225
|
|
|
* @return bool Success/Failure |
1226
|
|
|
*/ |
1227
|
|
|
function bigbluebuttonbn_log($bigbluebuttonbn, $event, array $overrides = [], $meta = null) { |
1228
|
|
|
global $DB, $USER; |
1229
|
|
|
$log = new stdClass(); |
1230
|
|
|
// Default values. |
1231
|
|
|
$log->courseid = $bigbluebuttonbn->course; |
1232
|
|
|
$log->bigbluebuttonbnid = $bigbluebuttonbn->id; |
1233
|
|
|
$log->userid = $USER->id; |
1234
|
|
|
$log->meetingid = $bigbluebuttonbn->meetingid; |
1235
|
|
|
$log->timecreated = time(); |
1236
|
|
|
$log->log = $event; |
1237
|
|
|
$log->meta = $meta; |
1238
|
|
|
// Overrides. |
1239
|
|
|
foreach ($overrides as $key => $value) { |
1240
|
|
|
$log->$key = $value; |
1241
|
|
|
} |
1242
|
|
|
if (!$DB->insert_record('bigbluebuttonbn_logs', $log)) { |
1243
|
|
|
return false; |
1244
|
|
|
} |
1245
|
|
|
return true; |
1246
|
|
|
} |
1247
|
|
|
|
1248
|
|
|
/** |
1249
|
|
|
* Adds module specific settings to the settings block |
1250
|
|
|
* |
1251
|
|
|
* @param settings_navigation $settingsnav The settings navigation object |
1252
|
|
|
* @param navigation_node $nodenav The node to add module settings to |
1253
|
|
|
*/ |
1254
|
|
|
function bigbluebuttonbn_extend_settings_navigation(settings_navigation $settingsnav, navigation_node $nodenav) { |
|
|
|
|
1255
|
|
|
global $PAGE, $USER; |
1256
|
|
|
// Don't add validate completion if the callback for meetingevents is NOT enabled. |
1257
|
|
|
if (!(boolean)\mod_bigbluebuttonbn\locallib\config::get('meetingevents_enabled')) { |
1258
|
|
|
return; |
1259
|
|
|
} |
1260
|
|
|
// Don't add validate completion if user is not allowed to edit the activity. |
1261
|
|
|
$context = context_module::instance($PAGE->cm->id); |
1262
|
|
|
if (!has_capability('moodle/course:manageactivities', $context, $USER->id)) { |
1263
|
|
|
return; |
1264
|
|
|
} |
1265
|
|
|
$completionvalidate = '#action=completion_validate&bigbluebuttonbn=' . $PAGE->cm->instance; |
1266
|
|
|
$nodenav->add(get_string('completionvalidatestate', 'bigbluebuttonbn'), |
1267
|
|
|
$completionvalidate, navigation_node::TYPE_CONTAINER); |
1268
|
|
|
} |
1269
|
|
|
|
This check looks from parameters that have been defined for a function or method, but which are not used in the method body.