Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
defined('MOODLE_INTERNAL') || die;
27
 
28
use core_calendar\action_factory;
29
use core_calendar\local\event\entities\action_interface;
30
use mod_bigbluebuttonbn\completion\custom_completion;
31
use mod_bigbluebuttonbn\extension;
32
use mod_bigbluebuttonbn\instance;
33
use mod_bigbluebuttonbn\local\bigbluebutton;
34
use mod_bigbluebuttonbn\local\exceptions\server_not_available_exception;
35
use mod_bigbluebuttonbn\local\helpers\files;
36
use mod_bigbluebuttonbn\local\helpers\mod_helper;
37
use mod_bigbluebuttonbn\local\helpers\reset;
38
use mod_bigbluebuttonbn\local\proxy\bigbluebutton_proxy;
39
use mod_bigbluebuttonbn\logger;
40
use mod_bigbluebuttonbn\meeting;
41
use mod_bigbluebuttonbn\recording;
42
use mod_bigbluebuttonbn\local\config;
43
 
44
global $CFG;
45
 
46
/**
47
 * Indicates API features that the bigbluebuttonbn supports.
48
 *
49
 * @param string $feature
50
 * @return mixed True if yes (some features may use other values)
51
 * @uses FEATURE_IDNUMBER
52
 * @uses FEATURE_GROUPS
53
 * @uses FEATURE_GROUPINGS
54
 * @uses FEATURE_GROUPMEMBERSONLY
55
 * @uses FEATURE_MOD_INTRO
56
 * @uses FEATURE_BACKUP_MOODLE2
57
 * @uses FEATURE_COMPLETION_TRACKS_VIEWS
58
 * @uses FEATURE_COMPLETION_HAS_RULES
59
 * @uses FEATURE_GRADE_HAS_GRADE
60
 * @uses FEATURE_GRADE_OUTCOMES
61
 * @uses FEATURE_SHOW_DESCRIPTION
62
 */
63
function bigbluebuttonbn_supports($feature) {
64
    if (!$feature) {
65
        return null;
66
    }
67
    $features = [
68
        FEATURE_IDNUMBER => true,
69
        FEATURE_GROUPS => true,
70
        FEATURE_GROUPINGS => true,
71
        FEATURE_MOD_INTRO => true,
72
        FEATURE_BACKUP_MOODLE2 => true,
73
        FEATURE_COMPLETION_TRACKS_VIEWS => true,
74
        FEATURE_COMPLETION_HAS_RULES => true,
1441 ariadna 75
        FEATURE_GRADE_HAS_GRADE => true,
1 efrain 76
        FEATURE_GRADE_OUTCOMES => false,
77
        FEATURE_SHOW_DESCRIPTION => true,
78
        FEATURE_MOD_PURPOSE => MOD_PURPOSE_COMMUNICATION,
79
    ];
80
    if (isset($features[(string) $feature])) {
81
        return $features[$feature];
82
    }
83
    return null;
84
}
85
 
86
/**
87
 * Given an object containing all the necessary data,
88
 * (defined by the form in mod_form.php) this function
89
 * will create a new instance and return the id number
90
 * of the new instance.
91
 *
92
 * @param stdClass $bigbluebuttonbn An object from the form in mod_form.php
93
 * @return int The id of the newly inserted bigbluebuttonbn record
94
 */
95
function bigbluebuttonbn_add_instance($bigbluebuttonbn) {
96
    global $DB;
97
    // Excecute preprocess.
98
    mod_helper::process_pre_save($bigbluebuttonbn);
99
    // Pre-set initial values.
100
    $bigbluebuttonbn->presentation = files::save_media_file($bigbluebuttonbn);
101
    // Encode meetingid.
102
    $bigbluebuttonbn->meetingid = meeting::get_unique_meetingid_seed();
103
    [$bigbluebuttonbn->guestlinkuid, $bigbluebuttonbn->guestpassword] =
104
        \mod_bigbluebuttonbn\plugin::generate_guest_meeting_credentials();
105
    // Insert a record.
106
    $bigbluebuttonbn->id = $DB->insert_record('bigbluebuttonbn', $bigbluebuttonbn);
107
    // Log insert action.
108
    logger::log_instance_created($bigbluebuttonbn);
109
    // Complete the process.
110
    mod_helper::process_post_save($bigbluebuttonbn);
111
 
112
    // Call any active subplugin so to signal a new creation.
113
    extension::add_instance($bigbluebuttonbn);
1441 ariadna 114
 
115
    // Create new grade item.
116
    bigbluebuttonbn_grade_item_update($bigbluebuttonbn);
117
 
1 efrain 118
    return $bigbluebuttonbn->id;
119
}
120
 
121
/**
122
 * Given an object containing all the necessary data,
123
 * (defined by the form in mod_form.php) this function
124
 * will update an existing instance with new data.
125
 *
126
 * @param stdClass $bigbluebuttonbn An object from the form in mod_form.php
127
 * @return bool Success/Fail
128
 */
129
function bigbluebuttonbn_update_instance($bigbluebuttonbn) {
130
    global $DB;
131
    // Excecute preprocess.
132
    mod_helper::process_pre_save($bigbluebuttonbn);
133
 
134
    // Pre-set initial values.
135
    $bigbluebuttonbn->id = $bigbluebuttonbn->instance;
136
    $bigbluebuttonbn->presentation = files::save_media_file($bigbluebuttonbn);
137
 
138
    if (empty($bigbluebuttonbn->guestjoinurl) || empty($bigbluebuttonbn->guestpassword)) {
139
        [$bigbluebuttonbn->guestlinkuid, $bigbluebuttonbn->guestpassword] =
140
            \mod_bigbluebuttonbn\plugin::generate_guest_meeting_credentials();
141
    }
142
    // Update a record.
143
    $DB->update_record('bigbluebuttonbn', $bigbluebuttonbn);
144
 
1441 ariadna 145
    bigbluebuttonbn_grade_item_update($bigbluebuttonbn);
146
 
1 efrain 147
    // Get the meetingid column in the bigbluebuttonbn table.
148
    $bigbluebuttonbn->meetingid = (string) $DB->get_field('bigbluebuttonbn', 'meetingid', ['id' => $bigbluebuttonbn->id]);
149
 
150
    // Log update action.
151
    logger::log_instance_updated(instance::get_from_instanceid($bigbluebuttonbn->id));
152
 
153
    // Complete the process.
154
    mod_helper::process_post_save($bigbluebuttonbn);
155
    // Call any active subplugin so to signal update.
156
    extension::update_instance($bigbluebuttonbn);
157
    return true;
158
}
159
 
160
/**
161
 * Given an ID of an instance of this module,
162
 * this function will permanently delete the instance
163
 * and any data that depends on it.
164
 *
165
 * @param int $id Id of the module instance
166
 *
167
 * @return bool Success/Failure
168
 */
169
function bigbluebuttonbn_delete_instance($id) {
170
    global $DB;
171
 
172
    $instance = instance::get_from_instanceid($id);
173
    if (empty($instance)) {
174
        return false;
175
    }
176
    // End all meeting if any still running.
177
    try {
178
        $meeting = new meeting($instance);
179
        $meeting->end_meeting();
180
    } catch (moodle_exception $e) {
181
        // Do not log any issue when testing.
182
        if (!(defined('PHPUNIT_TEST') && PHPUNIT_TEST) && !defined('BEHAT_SITE_RUNNING')) {
183
            debugging($e->getMessage(), DEBUG_DEVELOPER, $e->getTrace());
184
        }
185
    }
186
    // Get all possible groups (course and course module).
187
    $groupids = [];
188
    if (groups_get_activity_groupmode($instance->get_cm())) {
189
        $coursegroups = groups_get_activity_allowed_groups($instance->get_cm());
190
        $groupids = array_map(
191
            function($gp) {
192
                return $gp->id;
193
            },
194
            $coursegroups);
195
    }
196
    // End all meetings for all groups.
197
    foreach ($groupids as $groupid) {
198
        try {
199
            $instance->set_group_id($groupid);
200
            $meeting = new meeting($instance);
201
            $meeting->end_meeting();
202
        } catch (moodle_exception $e) {
203
            debugging($e->getMessage() . ' for group ' . $groupid, DEBUG_NORMAL, $e->getTrace());
204
        }
205
    }
206
 
207
    $result = true;
208
 
1441 ariadna 209
    // Delete grades.
210
    $bigbluebuttonbn = $DB->get_record('bigbluebuttonbn', ['id' => $id]);
211
    bigbluebuttonbn_grade_item_delete($bigbluebuttonbn);
212
 
1 efrain 213
    // Call any active subplugin so to signal deletion.
214
    extension::delete_instance($id);
215
 
216
    // Delete the instance.
217
    if (!$DB->delete_records('bigbluebuttonbn', ['id' => $id])) {
218
        $result = false;
219
    }
220
 
221
    // Delete dependant events.
222
    if (!$DB->delete_records('event', ['modulename' => 'bigbluebuttonbn', 'instance' => $id])) {
223
        $result = false;
224
    }
225
 
226
    // Log action performed.
227
    logger::log_instance_deleted($instance);
228
 
229
    // Mark dependent recordings as headless.
230
    foreach (recording::get_records(['bigbluebuttonbnid' => $id]) as $recording) {
231
        $recording->set('headless', recording::RECORDING_HEADLESS);
232
        $recording->update();
233
    }
234
 
235
    return $result;
236
}
237
 
238
/**
239
 * Return a small object with summary information about what a
240
 * user has done with a given particular instance of this module
241
 * Used for user activity reports.
242
 *
243
 * @param stdClass $course
244
 * @param stdClass $user
245
 * @param cm_info $mod
246
 * @param stdClass $bigbluebuttonbn
247
 *
248
 * @return stdClass with info and time (timestamp of the last log)
249
 */
250
function bigbluebuttonbn_user_outline(stdClass $course, stdClass $user, cm_info $mod, stdClass $bigbluebuttonbn): stdClass {
251
    [$infos, $logtimestamps] = \mod_bigbluebuttonbn\local\helpers\user_info::get_user_info_outline($course, $user, $mod);
252
    return (object) [
253
        'info' => join(',', $infos),
254
        'time' => !empty($logtimestamps) ? max($logtimestamps) : 0
255
    ];
256
}
257
 
258
/**
259
 * Print a detailed representation of what a user has done with
260
 * a given particular instance of this module, for user activity reports.
261
 *
262
 * @param stdClass $course
263
 * @param stdClass $user
264
 * @param cm_info $mod
265
 * @param stdClass $bigbluebuttonbn
266
 *
267
 */
268
function bigbluebuttonbn_user_complete(stdClass $course, stdClass $user, cm_info $mod, stdClass $bigbluebuttonbn) {
269
    [$infos] = \mod_bigbluebuttonbn\local\helpers\user_info::get_user_info_outline($course, $user, $mod);
270
    echo join(', ', $infos);
271
}
272
 
273
/**
274
 * This flags this module with the capability to override the completion status with the custom completion rules.
275
 *
276
 *
277
 * @return int
278
 */
279
function bigbluebuttonbn_get_completion_aggregation_state() {
280
    return COMPLETION_CUSTOM_MODULE_FLOW;
281
}
282
 
283
/**
284
 * Returns all other caps used in module.
285
 *
286
 * @return string[]
287
 */
288
function bigbluebuttonbn_get_extra_capabilities() {
289
    return ['moodle/site:accessallgroups'];
290
}
291
 
292
/**
293
 * Called by course/reset.php
294
 *
295
 * @param MoodleQuickForm $mform
296
 */
297
function bigbluebuttonbn_reset_course_form_definition(&$mform) {
298
    $items = reset::reset_course_items();
299
    $mform->addElement('header', 'bigbluebuttonbnheader', get_string('modulenameplural', 'bigbluebuttonbn'));
300
    foreach ($items as $item => $default) {
301
        $mform->addElement(
302
            'advcheckbox',
303
            "reset_bigbluebuttonbn_{$item}",
304
            get_string("reset{$item}", 'bigbluebuttonbn')
305
        );
306
        if ($item == 'logs' || $item == 'recordings') {
307
            $mform->addHelpButton("reset_bigbluebuttonbn_{$item}", "reset{$item}", 'bigbluebuttonbn');
308
        }
309
    }
310
}
311
 
312
/**
313
 * Course reset form defaults.
314
 *
315
 * @param stdClass $course
316
 * @return array
317
 */
318
function bigbluebuttonbn_reset_course_form_defaults(stdClass $course) {
319
    $formdefaults = [];
320
    $items = reset::reset_course_items();
321
    // All unchecked by default.
322
    foreach ($items as $item => $default) {
323
        $formdefaults["reset_bigbluebuttonbn_{$item}"] = $default;
324
    }
325
    return $formdefaults;
326
}
327
 
328
/**
329
 * This function is used by the reset_course_userdata function in moodlelib.
330
 *
331
 * @param stdClass $data the data submitted from the reset course.
332
 * @return array status array
333
 */
334
function bigbluebuttonbn_reset_userdata(stdClass $data) {
335
    $items = reset::reset_course_items();
336
    $status = [];
337
 
338
    // Any changes to the list of dates that needs to be rolled should be same during course restore and course reset.
339
    // See MDL-9367.
340
    if (array_key_exists('recordings', $items) && !empty($data->reset_bigbluebuttonbn_recordings)) {
341
        // Remove all the recordings from a BBB server that are linked to the room/activities in this course.
342
        reset::reset_recordings($data->courseid);
343
        unset($items['recordings']);
344
        $status[] = reset::reset_getstatus('recordings');
345
    }
346
 
347
    if (!empty($data->reset_bigbluebuttonbn_tags)) {
348
        // Remove all the tags linked to the room/activities in this course.
349
        reset::reset_tags($data->courseid);
350
        unset($items['tags']);
351
        $status[] = reset::reset_getstatus('tags');
352
    }
353
 
354
    if (!empty($data->reset_bigbluebuttonbn_logs)) {
355
        // Remove all the tags linked to the room/activities in this course.
356
        reset::reset_logs($data->courseid);
357
        unset($items['logs']);
358
        $status[] = reset::reset_getstatus('logs');
359
    }
1441 ariadna 360
    // Remove all grades from gradebook.
361
    if (!empty($data->reset_gradebook_grades)) {
362
        bigbluebuttonbn_reset_gradebook($data->courseid);
363
    }
1 efrain 364
    return $status;
365
}
366
 
367
/**
368
 * Given a course_module object, this function returns any
369
 * "extra" information that may be needed when printing
370
 * this activity in a course listing.
371
 * See get_array_of_activities() in course/lib.php.
372
 *
373
 * @param stdClass $coursemodule
374
 *
375
 * @return null|cached_cm_info
376
 */
377
function bigbluebuttonbn_get_coursemodule_info($coursemodule) {
378
    $instance = instance::get_from_instanceid($coursemodule->instance);
379
    if (empty($instance)) {
380
        return null;
381
    }
382
    $info = new cached_cm_info();
383
    // Warning here: if any of the instance method calls ::get_cm this will result is a recursive call.
384
    // So best is just to access instance variables not linked to the cm.
385
    $info->name = $instance->get_instance_var('name');
386
    if ($coursemodule->showdescription) {
387
        // Convert intro to html. Do not filter cached version, filters run at display time.
388
        $info->content = format_module_intro('bigbluebuttonbn', $instance->get_instance_data(), $coursemodule->id, false);
389
    }
390
    $customcompletionfields = custom_completion::get_defined_custom_rules();
391
    // Populate the custom completion rules as key => value pairs, but only if the completion mode is 'automatic'.
392
    if ($coursemodule->completion == COMPLETION_TRACKING_AUTOMATIC) {
393
        foreach ($customcompletionfields as $completiontype) {
394
            $info->customdata['customcompletionrules'][$completiontype] =
395
                $instance->get_instance_var($completiontype) ?? 0;
396
        }
397
    }
398
 
399
    return $info;
400
}
401
 
402
/**
403
 * Serves the bigbluebuttonbn attachments. Implements needed access control ;-).
404
 *
405
 * @param stdClass $course course object
406
 * @param stdClass $cm course module object
407
 * @param context $context context object
408
 * @param string $filearea file area
409
 * @param array $args extra arguments
410
 * @param bool $forcedownload whether or not force download
411
 * @param array $options additional options affecting the file serving
412
 *
413
 * @return false|null false if file not found, does not return if found - justsend the file
414
 * @category files
415
 *
416
 */
417
function bigbluebuttonbn_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options = []) {
418
    if (!files::pluginfile_valid($context, $filearea)) {
419
        return false;
420
    }
421
    $file = files::pluginfile_file($course, $cm, $context, $filearea, $args);
422
    if (empty($file)) {
423
        return false;
424
    }
425
    // Finally send the file.
426
    return send_stored_file($file, 0, 0, $forcedownload, $options); // Download MUST be forced - security!
427
}
428
 
429
/**
430
 * Mark the activity completed (if required) and trigger the course_module_viewed event.
431
 *
432
 * @param stdClass $bigbluebuttonbn bigbluebuttonbn object
433
 * @param stdClass $course course object
434
 * @param cm_info $cm course module object
435
 * @param context $context context object
436
 * @since Moodle 3.0
437
 */
438
function bigbluebuttonbn_view($bigbluebuttonbn, $course, $cm, $context) {
439
 
440
    // Trigger course_module_viewed event.
441
    $params = [
442
        'context' => $context,
443
        'objectid' => $bigbluebuttonbn->id
444
    ];
445
 
446
    $event = \mod_bigbluebuttonbn\event\course_module_viewed::create($params); // Fix event name.
447
    $cmrecord = $cm->get_course_module_record();
448
    $event->add_record_snapshot('course_modules', $cmrecord);
449
    $event->add_record_snapshot('course', $course);
450
    $event->add_record_snapshot('bigbluebuttonbn', $bigbluebuttonbn);
451
    $event->trigger();
452
 
453
    // Completion.
454
    $completion = new completion_info($course);
455
    $completion->set_module_viewed($cm);
456
}
457
 
458
/**
459
 * Check if the module has any update that affects the current user since a given time.
460
 *
461
 * @param cm_info $cm course module data
462
 * @param int $from the time to check updates from
463
 * @param array $filter if we need to check only specific updates
464
 * @return stdClass an object with the different type of areas indicating if they were updated or not
465
 * @since Moodle 3.2
466
 */
467
function bigbluebuttonbn_check_updates_since(cm_info $cm, $from, $filter = []) {
468
    $updates = course_check_module_updates_since($cm, $from, ['content'], $filter);
469
    return $updates;
470
}
471
 
472
/**
473
 * This function receives a calendar event and returns the action associated with it, or null if there is none.
474
 *
475
 * This is used by block_myoverview in order to display the event appropriately. If null is returned then the event
476
 * is not displayed on the block.
477
 *
478
 * @param calendar_event $event
479
 * @param action_factory $factory
480
 * @return action_interface|null
481
 */
482
function mod_bigbluebuttonbn_core_calendar_provide_event_action(
483
    calendar_event $event,
484
    action_factory $factory
485
) {
486
    global $DB;
487
 
488
    $time = time();
489
 
490
    // Get mod info.
491
    $cm = get_fast_modinfo($event->courseid)->instances['bigbluebuttonbn'][$event->instance];
492
 
493
    // Get bigbluebuttonbn activity.
494
    $bigbluebuttonbn = $DB->get_record('bigbluebuttonbn', ['id' => $event->instance], '*', MUST_EXIST);
495
 
496
    // Set flag haspassed if closingtime has already passed only if it is defined.
497
    $haspassed = ($bigbluebuttonbn->closingtime) && $bigbluebuttonbn->closingtime < $time;
498
 
499
    // Set flag hasstarted if startingtime has already passed or not defined.
500
    $hasstarted = $bigbluebuttonbn->openingtime < $time;
501
 
502
    // Return null if it has passed or not started.
503
    if ($haspassed || !$hasstarted) {
504
        return null;
505
    }
506
 
507
    // Get if the user has joined in live session or viewed the recorded.
508
    $customcompletion = new custom_completion($cm, $event->userid);
509
    $usercomplete = $customcompletion->get_overall_completion_state();
510
    $instance = instance::get_from_instanceid($bigbluebuttonbn->id);
511
    // Get if the room is available.
512
    $roomavailable = $instance->is_currently_open();
513
 
514
    $meetinginfo = null;
515
    // Check first if the server can be contacted.
516
    try {
517
        if (empty(bigbluebutton_proxy::get_server_version())) {
518
            // In this case we should already have debugging message printed.
519
            return null;
520
        }
521
        // Get if the user can join.
522
        $meetinginfo = meeting::get_meeting_info_for_instance($instance);
523
    } catch (moodle_exception $e) {
524
        debugging('Error - Cannot retrieve info from meeting ('.$instance->get_meeting_id().') ' . $e->getMessage());
525
        return null;
526
    }
527
    $usercanjoin = $meetinginfo->canjoin;
528
 
529
    // Check if the room is closed and the user has already joined this session or played the record.
530
    if (!$roomavailable && $usercomplete) {
531
        return null;
532
    }
533
 
534
    // Check if the user can join this session.
535
    $actionable = ($roomavailable && $usercanjoin);
536
 
537
    // Action data.
538
    $string = get_string('view_room', 'bigbluebuttonbn');
539
    $url = new moodle_url('/mod/bigbluebuttonbn/view.php', ['id' => $cm->id]);
540
    if (groups_get_activity_groupmode($cm) == NOGROUPS) {
541
        // No groups mode.
542
        $string = get_string('view_conference_action_join', 'bigbluebuttonbn');
543
        $url = new moodle_url('/mod/bigbluebuttonbn/bbb_view.php', [
544
                'action' => 'join',
545
                'id' => $cm->id,
546
                'bn' => $bigbluebuttonbn->id,
1441 ariadna 547
                'timeline' => 1,
548
                ]
1 efrain 549
        );
550
    }
551
 
552
    return $factory->create_instance($string, $url, 1, $actionable);
553
}
554
 
555
/**
556
 * Is the event visible?
557
 *
558
 * @param calendar_event $event
559
 * @return bool Returns true if the event is visible to the current user, false otherwise.
560
 */
561
function mod_bigbluebuttonbn_core_calendar_is_event_visible(calendar_event $event) {
562
    $instance = instance::get_from_instanceid($event->instance);
563
    if (!$instance) {
564
        return false;
565
    }
566
    $activitystatus = mod_bigbluebuttonbn\local\proxy\bigbluebutton_proxy::view_get_activity_status($instance);
567
    return $activitystatus != 'ended';
568
}
569
 
570
/**
571
 * Adds module specific settings to the settings block
572
 *
573
 * @param settings_navigation $settingsnav The settings navigation object
574
 * @param navigation_node $nodenav The node to add module settings to
575
 */
576
function bigbluebuttonbn_extend_settings_navigation(settings_navigation $settingsnav, navigation_node $nodenav) {
577
    global $USER;
578
    // Don't add validate completion if the callback for meetingevents is NOT enabled.
579
    if (!(boolean) \mod_bigbluebuttonbn\local\config::get('meetingevents_enabled')) {
580
        return;
581
    }
582
    // Don't add validate completion if user is not allowed to edit the activity.
583
    $context = context_module::instance($settingsnav->get_page()->cm->id);
584
    if (!has_capability('moodle/course:manageactivities', $context, $USER->id)) {
585
        return;
586
    }
587
    $completionvalidate = '#action=completion_validate&bigbluebuttonbn=' . $settingsnav->get_page()->cm->instance;
588
    $nodenav->add(get_string('completionvalidatestate', 'bigbluebuttonbn'),
589
        $completionvalidate, navigation_node::TYPE_CONTAINER);
590
}
591
 
592
/**
593
 * In place editable for the recording table
594
 *
595
 * @param string $itemtype
596
 * @param string $itemid
597
 * @param mixed $newvalue
598
 * @return mixed|null
599
 */
600
function bigbluebuttonbn_inplace_editable($itemtype, $itemid, $newvalue) {
601
    $editableclass = "\\mod_bigbluebuttonbn\\output\\recording_{$itemtype}_editable";
602
    if (class_exists($editableclass)) {
603
        return call_user_func([$editableclass, 'update'], $itemid, $newvalue);
604
    }
605
    return null; // Will raise an exception in core update_inplace_editable method.
606
}
607
 
608
/**
609
 * Returns all events since a given time in specified bigbluebutton activity.
610
 * We focus here on the two events: play and join.
611
 *
612
 * @param array $activities
613
 * @param int $index
614
 * @param int $timestart
615
 * @param int $courseid
616
 * @param int $cmid
617
 * @param int $userid
618
 * @param int $groupid
619
 * @return array
620
 */
621
function bigbluebuttonbn_get_recent_mod_activity(&$activities, &$index, $timestart, $courseid, $cmid, $userid = 0,
622
    $groupid = 0): array {
623
    $instance = instance::get_from_cmid($cmid);
624
    $instance->set_group_id($groupid);
625
    $cm = $instance->get_cm();
626
    $logs =
627
        logger::get_user_completion_logs_with_userfields($instance,
628
            $userid ?? null,
629
            [logger::EVENT_JOIN, logger::EVENT_PLAYED],
630
            $timestart);
631
 
632
    foreach ($logs as $log) {
633
        $activity = new stdClass();
634
 
635
        $activity->type = 'bigbluebuttonbn';
636
        $activity->cmid = $cm->id;
637
        $activity->name = format_string($instance->get_meeting_name(), true);
638
        $activity->sectionnum = $cm->sectionnum;
639
        $activity->timestamp = $log->timecreated;
640
        $activity->user = new stdClass();
641
        $userfields = explode(',', implode(',', \core_user\fields::get_picture_fields()));
642
        foreach ($userfields as $userfield) {
643
            if ($userfield == 'id') {
644
                // Aliased in SQL above.
645
                $activity->user->{$userfield} = $log->userid;
646
            } else {
647
                $activity->user->{$userfield} = $log->{$userfield};
648
            }
649
        }
650
        $activity->user->fullname = fullname($log);
651
        $activity->content = '';
652
        $activity->eventname = logger::get_printable_event_name($log);
653
        if ($log->log == logger::EVENT_PLAYED) {
654
            if (!empty($log->meta)) {
655
                $meta = json_decode($log->meta);
656
                if (!empty($meta->recordingid)) {
657
                    $recording = recording::get_record(['id' => $meta->recordingid]);
658
                    if ($recording) {
659
                        $activity->content = $recording->get('name');
660
                    }
661
                }
662
            }
663
        }
664
        $activities[$index++] = $activity;
665
    }
666
    return $activities;
667
}
668
 
669
/**
670
 * Outputs the bigbluebutton logs indicated by $activity.
671
 *
672
 * @param stdClass $activity the activity object the bigbluebuttonbn resides in
673
 * @param int $courseid the id of the course the bigbluebuttonbn resides in
674
 * @param bool $detail not used, but required for compatibilty with other modules
675
 * @param array $modnames not used, but required for compatibilty with other modules
676
 * @param bool $viewfullnames not used, but required for compatibilty with other modules
677
 */
678
function bigbluebuttonbn_print_recent_mod_activity(stdClass $activity, int $courseid, bool $detail, array $modnames,
679
    bool $viewfullnames) {
680
    global $OUTPUT;
681
    $modinfo = [];
682
    $userpicture = $OUTPUT->user_picture($activity->user);
683
 
684
    $template = ['userpicture' => $userpicture,
685
        'submissiontimestamp' => $activity->timestamp,
686
        'modinfo' => $modinfo,
687
        'userurl' => new moodle_url('/user/view.php', array('id' => $activity->user->id, 'course' => $courseid)),
688
        'fullname' => $activity->user->fullname];
689
    if (isset($activity->eventname)) {
690
        $template['eventname'] = $activity->eventname;
691
    }
692
    echo $OUTPUT->render_from_template('mod_bigbluebuttonbn/recentactivity', $template);
693
}
694
 
695
/**
696
 * Given a course and a date, prints a summary of all the activity for this module
697
 *
698
 * @param object $course
699
 * @param bool $viewfullnames capability
700
 * @param int $timestart
701
 * @return bool success
702
 */
703
function bigbluebuttonbn_print_recent_activity(object $course, bool $viewfullnames, int $timestart): bool {
704
    global $OUTPUT;
705
    $modinfo = get_fast_modinfo($course);
706
    if (empty($modinfo->instances['bigbluebuttonbn'])) {
707
        return true;
708
    }
709
    $out = '';
710
    foreach ($modinfo->instances['bigbluebuttonbn'] as $cm) {
711
        if (!$cm->uservisible) {
712
            continue;
713
        }
714
        $instance = instance::get_from_cmid($cm->id);
715
        $logs = logger::get_user_completion_logs_with_userfields($instance,
716
            null,
717
            [logger::EVENT_JOIN, logger::EVENT_PLAYED],
718
            $timestart);
719
        if ($logs) {
720
            echo $OUTPUT->heading(get_string('new_bigblubuttonbn_activities', 'bigbluebuttonbn') . ':', 6);
721
            foreach ($logs as $log) {
722
                $activityurl = new moodle_url('/mod/bigbluebuttonbn/index.php', ['id' => $course->id]);
723
                print_recent_activity_note($log->timecreated,
724
                    $log,
725
                    logger::get_printable_event_name($log) . ' - ' . $instance->get_meeting_name(),
726
                    $activityurl->out(),
727
                    false,
728
                    $viewfullnames);
729
            }
730
        }
731
 
732
        echo $out;
733
    }
734
    return true;
735
}
736
 
737
 
738
/**
739
 * Creates a number of BigblueButtonBN activities.
740
 *
741
 * @param tool_generator_course_backend $backend
742
 * @param testing_data_generator $generator
743
 * @param int $courseid
744
 * @param int $number
745
 * @return void
746
 */
747
function bigbluebuttonbn_course_backend_generator_create_activity(tool_generator_course_backend $backend,
748
    testing_data_generator $generator,
749
    int $courseid,
750
    int $number
751
) {
752
    // Set up generator.
753
    $bbbgenerator = $generator->get_plugin_generator('mod_bigbluebuttonbn');
754
 
755
    // Create assignments.
756
    $backend->log('createbigbluebuttonbn', $number, true, 'mod_bigbluebuttonbn');
757
    for ($i = 0; $i < $number; $i++) {
758
        $record = array('course' => $courseid);
759
        $options = array('section' => $backend->get_target_section());
760
        $bbbgenerator->create_instance($record, $options);
761
        $backend->dot($i, $number);
762
    }
763
    $backend->end_log();
764
}
765
 
766
/**
767
 * Whether the activity is branded.
768
 * This information is used, for instance, to decide if a filter should be applied to the icon or not.
769
 *
770
 * @return bool True if the activity is branded, false otherwise.
771
 */
772
function bigbluebuttonbn_is_branded(): bool {
773
    return true;
774
}
1441 ariadna 775
 
776
/**
777
 * Update/create grade item for given BigBlueButtonBN activity
778
 *
779
 * @category grade
780
 * @param stdClass $bigbluebuttonbn instance object
781
 * @param array|object|string|null $grades Optional array/object of grade(s); 'reset' means reset grades in gradebook
782
 * @return int 0 if ok, error code otherwise
783
 */
784
function bigbluebuttonbn_grade_item_update(stdClass $bigbluebuttonbn, array|object|string|null $grades=null): int {
785
    global $CFG;
786
    require_once($CFG->libdir.'/gradelib.php');
787
    $params = ['itemname' => $bigbluebuttonbn->name];
788
    if ($bigbluebuttonbn->grade == 0) {
789
        $params['gradetype'] = GRADE_TYPE_NONE;
790
    } else if ($bigbluebuttonbn->grade > 0) {
791
        $params['gradetype'] = GRADE_TYPE_VALUE;
792
        $params['grademax'] = $bigbluebuttonbn->grade;
793
        $params['grademin'] = 0;
794
    } else if ($bigbluebuttonbn->grade < 0) {
795
        $params['gradetype'] = GRADE_TYPE_SCALE;
796
        $params['scaleid'] = -$bigbluebuttonbn->grade;
797
    }
798
    if ($grades === 'reset') {
799
        $params['reset'] = true;
800
        $grades = null;
801
    }
802
    return grade_update(
803
        source: 'mod/bigbluebuttonbn',
804
        courseid: $bigbluebuttonbn->course,
805
        itemtype: 'mod',
806
        itemmodule: 'bigbluebuttonbn',
807
        iteminstance: $bigbluebuttonbn->id,
808
        itemnumber: 0,
809
        grades: $grades,
810
        itemdetails: $params
811
    );
812
}
813
 
814
/**
815
 * Update activity grades.
816
 *
817
 * @param stdClass $bigbluebuttonbn instance object
818
 */
819
function bigbluebuttonbn_update_grades(stdClass $bigbluebuttonbn): void {
820
    // BigBlueButtonBN does not have a grades table, so we will only update grade item.
821
    bigbluebuttonbn_grade_item_update($bigbluebuttonbn);
822
}
823
 
824
/**
825
 * Removes all grades from gradebook
826
 *
827
 * @param int $courseid
828
 */
829
function bigbluebuttonbn_reset_gradebook(int $courseid): void {
830
    global $DB;
831
    $sql = "SELECT b.*, cm.idnumber as cmidnumber, b.course as courseid
832
              FROM {bigbluebuttonbn} b, {course_modules} cm, {modules} m
833
             WHERE m.name='bigbluebuttonbn' AND m.id=cm.module AND cm.instance=b.id AND b.course=?";
834
 
835
    if ($bigbluebuttonbns = $DB->get_records_sql($sql, [$courseid])) {
836
        foreach ($bigbluebuttonbns as $bigbluebuttonbn) {
837
            bigbluebuttonbn_grade_item_update($bigbluebuttonbn, 'reset');
838
        }
839
    }
840
}
841
 
842
/**
843
 * Delete grade item for given activity
844
 *
845
 * @param stdClass $bigbluebuttonbn instance object
846
 * @return int Returns GRADE_UPDATE_OK, GRADE_UPDATE_FAILED, GRADE_UPDATE_MULTIPLE or GRADE_UPDATE_ITEM_LOCKED
847
 */
848
function bigbluebuttonbn_grade_item_delete(stdClass $bigbluebuttonbn): int {
849
    global $CFG;
850
    require_once($CFG->libdir.'/gradelib.php');
851
    return grade_update(
852
        source: 'mod/bigbluebuttonbn',
853
        courseid: $bigbluebuttonbn->course,
854
        itemtype: 'mod',
855
        itemmodule: 'bigbluebuttonbn',
856
        iteminstance: $bigbluebuttonbn->id,
857
        itemnumber: 0,
858
        grades: null,
859
        itemdetails: ['deleted' => 1]
860
    );
861
}