diff --git a/mod/bigbluebuttonbn/backup/moodle2/backup_bigbluebuttonbn_stepslib.php b/mod/bigbluebuttonbn/backup/moodle2/backup_bigbluebuttonbn_stepslib.php index 6877eef6fb4..13a9ed2689d 100644 --- a/mod/bigbluebuttonbn/backup/moodle2/backup_bigbluebuttonbn_stepslib.php +++ b/mod/bigbluebuttonbn/backup/moodle2/backup_bigbluebuttonbn_stepslib.php @@ -52,7 +52,7 @@ class backup_bigbluebuttonbn_activity_structure_step extends backup_activity_str 'clienttype', 'muteonstart', 'completionattendance', 'completionengagementchats', 'completionengagementtalks', 'completionengagementraisehand', 'completionengagementpollvotes', 'completionengagementemojis', - 'guestallowed', 'mustapproveuser', 'showpresentation']); + 'guestallowed', 'mustapproveuser', 'showpresentation', 'grade']); $logs = new backup_nested_element('logs'); diff --git a/mod/bigbluebuttonbn/db/install.xml b/mod/bigbluebuttonbn/db/install.xml index 239b99e97ed..fa500321ba0 100644 --- a/mod/bigbluebuttonbn/db/install.xml +++ b/mod/bigbluebuttonbn/db/install.xml @@ -1,5 +1,5 @@ - @@ -51,6 +51,7 @@ + diff --git a/mod/bigbluebuttonbn/db/upgrade.php b/mod/bigbluebuttonbn/db/upgrade.php index 77d5d283dae..b41b525cfb3 100644 --- a/mod/bigbluebuttonbn/db/upgrade.php +++ b/mod/bigbluebuttonbn/db/upgrade.php @@ -65,6 +65,21 @@ function xmldb_bigbluebuttonbn_upgrade($oldversion = 0) { // Automatically generated Moodle v4.5.0 release upgrade line. // Put any upgrade step following this. + if ($oldversion < 2025011000) { + + // Define field grade to be added to bigbluebuttonbn. + $table = new xmldb_table('bigbluebuttonbn'); + $field = new xmldb_field('grade', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'showpresentation'); + + // Conditionally launch add field grade. + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + // Bigbluebuttonbn savepoint reached. + upgrade_mod_savepoint(true, 2025011000, 'bigbluebuttonbn'); + } + return true; } diff --git a/mod/bigbluebuttonbn/lib.php b/mod/bigbluebuttonbn/lib.php index e7c649ba271..ad142236567 100644 --- a/mod/bigbluebuttonbn/lib.php +++ b/mod/bigbluebuttonbn/lib.php @@ -72,7 +72,7 @@ function bigbluebuttonbn_supports($feature) { FEATURE_BACKUP_MOODLE2 => true, FEATURE_COMPLETION_TRACKS_VIEWS => true, FEATURE_COMPLETION_HAS_RULES => true, - FEATURE_GRADE_HAS_GRADE => false, + FEATURE_GRADE_HAS_GRADE => true, FEATURE_GRADE_OUTCOMES => false, FEATURE_SHOW_DESCRIPTION => true, FEATURE_MOD_PURPOSE => MOD_PURPOSE_COMMUNICATION, @@ -111,6 +111,10 @@ function bigbluebuttonbn_add_instance($bigbluebuttonbn) { // Call any active subplugin so to signal a new creation. extension::add_instance($bigbluebuttonbn); + + // Create new grade item. + bigbluebuttonbn_grade_item_update($bigbluebuttonbn); + return $bigbluebuttonbn->id; } @@ -138,6 +142,8 @@ function bigbluebuttonbn_update_instance($bigbluebuttonbn) { // Update a record. $DB->update_record('bigbluebuttonbn', $bigbluebuttonbn); + bigbluebuttonbn_grade_item_update($bigbluebuttonbn); + // Get the meetingid column in the bigbluebuttonbn table. $bigbluebuttonbn->meetingid = (string) $DB->get_field('bigbluebuttonbn', 'meetingid', ['id' => $bigbluebuttonbn->id]); @@ -200,6 +206,10 @@ function bigbluebuttonbn_delete_instance($id) { $result = true; + // Delete grades. + $bigbluebuttonbn = $DB->get_record('bigbluebuttonbn', ['id' => $id]); + bigbluebuttonbn_grade_item_delete($bigbluebuttonbn); + // Call any active subplugin so to signal deletion. extension::delete_instance($id); @@ -347,6 +357,10 @@ function bigbluebuttonbn_reset_userdata(stdClass $data) { unset($items['logs']); $status[] = reset::reset_getstatus('logs'); } + // Remove all grades from gradebook. + if (!empty($data->reset_gradebook_grades)) { + bigbluebuttonbn_reset_gradebook($data->courseid); + } return $status; } @@ -757,3 +771,90 @@ function bigbluebuttonbn_course_backend_generator_create_activity(tool_generator function bigbluebuttonbn_is_branded(): bool { return true; } + +/** + * Update/create grade item for given BigBlueButtonBN activity + * + * @category grade + * @param stdClass $bigbluebuttonbn instance object + * @param array|object|string|null $grades Optional array/object of grade(s); 'reset' means reset grades in gradebook + * @return int 0 if ok, error code otherwise + */ +function bigbluebuttonbn_grade_item_update(stdClass $bigbluebuttonbn, array|object|string|null $grades=null): int { + global $CFG; + require_once($CFG->libdir.'/gradelib.php'); + $params = ['itemname' => $bigbluebuttonbn->name]; + if ($bigbluebuttonbn->grade == 0) { + $params['gradetype'] = GRADE_TYPE_NONE; + } else if ($bigbluebuttonbn->grade > 0) { + $params['gradetype'] = GRADE_TYPE_VALUE; + $params['grademax'] = $bigbluebuttonbn->grade; + $params['grademin'] = 0; + } else if ($bigbluebuttonbn->grade < 0) { + $params['gradetype'] = GRADE_TYPE_SCALE; + $params['scaleid'] = -$bigbluebuttonbn->grade; + } + if ($grades === 'reset') { + $params['reset'] = true; + $grades = null; + } + return grade_update( + source: 'mod/bigbluebuttonbn', + courseid: $bigbluebuttonbn->course, + itemtype: 'mod', + itemmodule: 'bigbluebuttonbn', + iteminstance: $bigbluebuttonbn->id, + itemnumber: 0, + grades: $grades, + itemdetails: $params + ); +} + +/** + * Update activity grades. + * + * @param stdClass $bigbluebuttonbn instance object + */ +function bigbluebuttonbn_update_grades(stdClass $bigbluebuttonbn): void { + // BigBlueButtonBN does not have a grades table, so we will only update grade item. + bigbluebuttonbn_grade_item_update($bigbluebuttonbn); +} + +/** + * Removes all grades from gradebook + * + * @param int $courseid + */ +function bigbluebuttonbn_reset_gradebook(int $courseid): void { + global $DB; + $sql = "SELECT b.*, cm.idnumber as cmidnumber, b.course as courseid + FROM {bigbluebuttonbn} b, {course_modules} cm, {modules} m + WHERE m.name='bigbluebuttonbn' AND m.id=cm.module AND cm.instance=b.id AND b.course=?"; + + if ($bigbluebuttonbns = $DB->get_records_sql($sql, [$courseid])) { + foreach ($bigbluebuttonbns as $bigbluebuttonbn) { + bigbluebuttonbn_grade_item_update($bigbluebuttonbn, 'reset'); + } + } +} + +/** + * Delete grade item for given activity + * + * @param stdClass $bigbluebuttonbn instance object + * @return int Returns GRADE_UPDATE_OK, GRADE_UPDATE_FAILED, GRADE_UPDATE_MULTIPLE or GRADE_UPDATE_ITEM_LOCKED + */ +function bigbluebuttonbn_grade_item_delete(stdClass $bigbluebuttonbn): int { + global $CFG; + require_once($CFG->libdir.'/gradelib.php'); + return grade_update( + source: 'mod/bigbluebuttonbn', + courseid: $bigbluebuttonbn->course, + itemtype: 'mod', + itemmodule: 'bigbluebuttonbn', + iteminstance: $bigbluebuttonbn->id, + itemnumber: 0, + grades: null, + itemdetails: ['deleted' => 1] + ); +} diff --git a/mod/bigbluebuttonbn/mod_form.php b/mod/bigbluebuttonbn/mod_form.php index 807c94f0094..b2fdd311172 100644 --- a/mod/bigbluebuttonbn/mod_form.php +++ b/mod/bigbluebuttonbn/mod_form.php @@ -94,7 +94,8 @@ class mod_bigbluebuttonbn_mod_form extends moodleform_mod { $this->bigbluebuttonbn_mform_add_block_schedule($mform, $this->current); // Now add subplugins form elements. $this->add_subplugins_elements(); - + // Add standard grading elements. + $this->standard_grading_coursemodule_elements(); // Add standard elements, common to all modules. $this->standard_coursemodule_elements(); // Add standard buttons, common to all modules. diff --git a/mod/bigbluebuttonbn/tests/generator/lib.php b/mod/bigbluebuttonbn/tests/generator/lib.php index 3c385b6f503..07a6adb378d 100644 --- a/mod/bigbluebuttonbn/tests/generator/lib.php +++ b/mod/bigbluebuttonbn/tests/generator/lib.php @@ -66,7 +66,8 @@ class mod_bigbluebuttonbn_generator extends \testing_module_generator { "timecreated" => $now, "timemodified" => $now, "presentation" => null, - "recordings_preview" => 0 + "recordings_preview" => 0, + "grade" => 0, ]; $record = (array) $record; diff --git a/mod/bigbluebuttonbn/tests/lib_test.php b/mod/bigbluebuttonbn/tests/lib_test.php index 6318c2fef9b..db138389397 100644 --- a/mod/bigbluebuttonbn/tests/lib_test.php +++ b/mod/bigbluebuttonbn/tests/lib_test.php @@ -58,7 +58,7 @@ final class lib_test extends \advanced_testcase { $this->resetAfterTest(); $this->assertTrue(bigbluebuttonbn_supports(FEATURE_IDNUMBER)); $this->assertTrue(bigbluebuttonbn_supports(FEATURE_MOD_INTRO)); - $this->assertFalse(bigbluebuttonbn_supports(FEATURE_GRADE_HAS_GRADE)); + $this->assertTrue(bigbluebuttonbn_supports(FEATURE_GRADE_HAS_GRADE)); } /** @@ -547,6 +547,61 @@ final class lib_test extends \advanced_testcase { $this->assertCount(2, $DB->get_records('bigbluebuttonbn_logs', ['bigbluebuttonbnid' => $bbactivity->id])); } + /** + * Reset user data and make sure grades are reset. + * + * @covers ::bigbluebuttonbn_reset_userdata + */ + public function test_bigbluebuttonbn_reset_userdata_with_grades(): void { + global $DB; + $this->resetAfterTest(); + $user = $this->getDataGenerator()->create_user(); + list($bbactivitycontext, $bbactivitycm, $bbactivity) = $this->create_instance($this->course, + ['grade' => 100]); + $this->getDataGenerator()->enrol_user($user->id, $this->course->id); + $this->setUser($user); + + // Pass a user grade. + $grade = []; + $gradeitem = $DB->get_record('grade_items', [ + 'courseid' => $this->course->id, + 'itemtype' => 'mod', + 'itemmodule' => 'bigbluebuttonbn', + 'iteminstance' => $bbactivity->id, + ]); + $grade[$user->id] = [ + 'userid' => $user->id, + 'rawgrade' => 75, + ]; + grade_update( + source: 'mod/bigbluebuttonbn', + courseid: $this->course->id, + itemtype: 'mod', + itemmodule: 'bigbluebuttonbn', + iteminstance: $bbactivity->id, + itemnumber: 0, + grades: $grade + ); + $params = [ + 'userid' => $user->id, + 'itemid' => $gradeitem->id, + 'rawgrade' => 75, + ]; + $gradegrades = $DB->get_records('grade_grades', $params); + $this->assertCount(1, $gradegrades); + + // Reset user data. + $data = new stdClass(); + $data->courseid = $this->course->id; + $data->course = $bbactivity->course; + $data->reset_gradebook_grades = 1; + bigbluebuttonbn_reset_userdata($data); + + // Check grades have been reset. + $gradegrades = $DB->get_records('grade_grades', $params); + $this->assertCount(0, $gradegrades); + } + /** * Check course module * @@ -568,11 +623,27 @@ final class lib_test extends \advanced_testcase { $this->resetAfterTest(); list($bbactivitycontext, $bbactivitycm, $bbactivity) = $this->create_instance(); $result = bigbluebuttonbn_check_updates_since($bbactivitycm, 0); - $this->assertEquals( - '{"configuration":{"updated":false},"contentfiles":{"updated":false},"introfiles":' . - '{"updated":false},"completion":{"updated":false}}', - json_encode($result) - ); + $expected = json_encode([ + 'configuration' => [ + 'updated' => false, + ], + 'contentfiles' => [ + 'updated' => false, + ], + 'introfiles' => [ + 'updated' => false, + ], + 'completion' => [ + 'updated' => false, + ], + 'gradeitems' => [ + 'updated' => false, + ], + 'outcomes' => [ + 'updated' => false, + ], + ]); + $this->assertEquals($expected, json_encode($result)); } /** diff --git a/mod/bigbluebuttonbn/version.php b/mod/bigbluebuttonbn/version.php index 659b32eecbb..f68da5ba66e 100644 --- a/mod/bigbluebuttonbn/version.php +++ b/mod/bigbluebuttonbn/version.php @@ -27,6 +27,6 @@ defined('MOODLE_INTERNAL') || die; -$plugin->version = 2024121800; +$plugin->version = 2025011000; $plugin->requires = 2024100100; $plugin->component = 'mod_bigbluebuttonbn';