Skip to content

Commit

Permalink
CTP-3870 Update SORA group overrides logic
Browse files Browse the repository at this point in the history
  • Loading branch information
aydevworks committed Nov 28, 2024
1 parent d83d9aa commit 446dfce
Show file tree
Hide file tree
Showing 13 changed files with 716 additions and 250 deletions.
39 changes: 39 additions & 0 deletions classes/assessment/assessment.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,15 @@ public function apply_extension(extension $extension): void {
if ($extension instanceof ec) {
$this->apply_ec_extension($extension);
} else if ($extension instanceof sora) {
// Skip SORA overrides if the assessment is not an exam.
if (!$this->is_exam()) {
return;
}
// Skip SORA overrides if the end date of the assessment is in the past.
if ($this->get_end_date() < time()) {
return;
}

$this->apply_sora_extension($extension);
}
}
Expand Down Expand Up @@ -190,6 +199,24 @@ public function get_end_date(): ?int {
return null;
}

/**
* Get module name. Return empty string if not applicable.
*
* @return string
*/
public function get_module_name(): string {
return '';
}

/**
* Check if the assessment is an exam. Override in child class if needed.
*
* @return bool
*/
public function is_exam(): bool {
return false;
}

/**
* Check if the assessment is valid for marks transfer.
*
Expand Down Expand Up @@ -236,6 +263,18 @@ public function is_valid_for_extension(): \stdClass {
return $this->set_validity_result(true);
}

/**
* Delete SORA override for a Moodle assessment.
*
* @param array $groupids Default SORA overrides group ids in the course.
* @return void
* @throws \moodle_exception
*/
public function delete_sora_overrides(array $groupids): void {
// Default not supported. Override in child class if needed.
throw new \moodle_exception('error:soraextensionnotsupported', 'local_sitsgradepush');
}

/**
* Set validity result.
*
Expand Down
51 changes: 51 additions & 0 deletions classes/assessment/assign.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,57 @@ public function get_end_date(): ?int {
return $this->sourceinstance->duedate;
}

/**
* Check if this assignment is an exam.
*
* @return bool
*/
public function is_exam(): bool {
$start = $this->get_start_date();
$end = $this->get_end_date();

if ($start && $end) {
$duration = $end - $start;
return $duration > 0 && $duration <= HOURSECS * 5;
}

return false;
}

/**
* Delete SORA override for the assignment.
*
* @param array $groupids Default SORA overrides group ids in the course.
* @return void
* @throws \coding_exception
* @throws \dml_exception
*/
public function delete_sora_overrides(array $groupids): void {
global $CFG, $DB;
require_once($CFG->dirroot . '/mod/assign/locallib.php');

// Skip if group ids are empty.
if (empty($groupids)) {
return;
}

// Find all group overrides for the assignment having the default SORA overrides group ids.
[$insql, $params] = $DB->get_in_or_equal($groupids, SQL_PARAMS_NAMED);
$params['assignid'] = $this->sourceinstance->id;
$sql = "SELECT id FROM {assign_overrides} WHERE assignid = :assignid AND groupid $insql AND userid IS NULL";

$overrides = $DB->get_records_sql($sql, $params);

if (empty($overrides)) {
return;
}

$assign = new \assign($this->context, $this->get_course_module(), null);
foreach ($overrides as $override) {
$assign->delete_override($override->id);
}
}

/**
* Apply EC extension to the assessment.
*
Expand Down
42 changes: 42 additions & 0 deletions classes/assessment/quiz.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,48 @@ public function get_end_date(): ?int {
return $this->get_source_instance()->timeclose;
}

/**
* Check if this quiz is an exam.
*
* @return bool
*/
public function is_exam(): bool {
$originaltimelimit = $this->get_source_instance()->timelimit;
return $originaltimelimit > 0 && $originaltimelimit <= HOURMINS * 5;
}

/**
* Delete SORA override for the quiz.
*
* @param array $groupids Default SORA overrides group ids in the course.
* @return void
* @throws \coding_exception
* @throws \dml_exception
*/
public function delete_sora_overrides(array $groupids): void {
global $CFG, $DB;
require_once($CFG->dirroot . '/mod/assign/locallib.php');

// Skip if group ids are empty.
if (empty($groupids)) {
return;
}

// Find all group overrides for the quiz having the default SORA overrides group ids.
[$insql, $params] = $DB->get_in_or_equal($groupids, SQL_PARAMS_NAMED);
$params['quizid'] = $this->sourceinstance->id;
$sql = "SELECT * FROM {quiz_overrides} WHERE quiz = :quizid AND groupid $insql AND userid IS NULL";

$overrides = $DB->get_records_sql($sql, $params);

if (empty($overrides)) {
return;
}

// Delete the overrides.
$this->get_override_manager()->delete_overrides($overrides);
}

/**
* Apply EC extension to the quiz.
*
Expand Down
4 changes: 2 additions & 2 deletions classes/event/assessment_mapped.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ protected function init(): void {
* @throws \coding_exception
*/
public static function get_name(): string {
return get_string('eventname', 'local_sitsgradepush');
return get_string('event:assessment_mapped', 'local_sitsgradepush');
}

/**
Expand All @@ -52,6 +52,6 @@ public static function get_name(): string {
* @return string
*/
public function get_description(): string {
return "An assessment is mapped to a SITS assessment component.";
return get_string('event:assessment_mapped_desc', 'local_sitsgradepush');
}
}
45 changes: 45 additions & 0 deletions classes/extensionmanager.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

namespace local_sitsgradepush;

use local_sitsgradepush\assessment\assessment;
use local_sitsgradepush\assessment\assessmentfactory;
use local_sitsgradepush\extension\extension;
use local_sitsgradepush\extension\sora;
use local_sitsgradepush\task\process_extensions_new_enrolment;

Expand Down Expand Up @@ -105,4 +108,46 @@ public static function get_user_enrolment_events(int $courseid): array {
limitnum: process_extensions_new_enrolment::BATCH_LIMIT
);
}

/**
* Delete SORA overrides for a Moodle assessment.
*
* @param \stdClass $deletedmapping
* @return void
* @throws \dml_exception
*/
public static function delete_sora_overrides(\stdClass $deletedmapping): void {
try {
// Get Moodle assessment.
$assessment = assessmentfactory::get_assessment($deletedmapping->sourcetype, $deletedmapping->sourceid);

// Nothing to do if the module type is not supported.
if (!extension::is_module_supported($assessment->get_module_name())) {
return;
}

$assessment->delete_sora_overrides(self::get_default_sora_groups_ids_in_course($deletedmapping->courseid));
} catch (\Exception $e) {
logger::log($e->getMessage(), null, "Deleted Mapping: " . json_encode($deletedmapping));
}
}

/**
* Get the default SORA groups IDs in a course.
*
* @param int $courseid
* @return array
* @throws \dml_exception
*/
public static function get_default_sora_groups_ids_in_course(int $courseid): array {
global $DB;
$like = $DB->sql_like('name', ':name', false);
$defaultsoragroups = $DB->get_records_select(
'groups',
"courseid = :courseid AND $like",
['courseid' => $courseid, 'name' => sora::SORA_GROUP_PREFIX . '%'],
fields: 'id',
);
return !empty($defaultsoragroups) ? array_keys($defaultsoragroups) : [];
}
}
8 changes: 7 additions & 1 deletion classes/manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,9 @@ public function save_assessment_mapping(\stdClass $data): int|bool {
// Checked in the above validation, the current mapping to this component grade
// can be deleted as it does not have push records nor mapped to the current activity.
$DB->delete_records(self::TABLE_ASSESSMENT_MAPPING, ['id' => $existingmapping->id]);

// Delete any SORA overrides for the deleted mapping.
extensionmanager::delete_sora_overrides($existingmapping);
assesstype::update_assess_type($existingmapping, assesstype::ACTION_UNLOCK);
}

Expand Down Expand Up @@ -1520,7 +1523,7 @@ public function remove_mapping(int $courseid, int $mappingid): void {
}

// Check the mapping exists.
if (!$DB->record_exists(self::TABLE_ASSESSMENT_MAPPING, ['id' => $mappingid])) {
if (!$mapping = $DB->get_record(self::TABLE_ASSESSMENT_MAPPING, ['id' => $mappingid])) {
throw new \moodle_exception('error:assessmentmapping', 'local_sitsgradepush', '', $mappingid);
}

Expand All @@ -1531,6 +1534,9 @@ public function remove_mapping(int $courseid, int $mappingid): void {

// Everything is fine, remove the mapping.
$DB->delete_records(self::TABLE_ASSESSMENT_MAPPING, ['id' => $mappingid]);

// Delete any SORA overrides for the deleted mapping.
extensionmanager::delete_sora_overrides($mapping);
}

/**
Expand Down
1 change: 1 addition & 0 deletions lang/en/local_sitsgradepush.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@
$string['error:turnitin_numparts'] = 'Turnitin assignment with multiple parts is not supported by Marks Transfer.';
$string['error:user_data_not_set.'] = 'User data is not set.';
$string['event:assessment_mapped'] = 'Assessment mapped';
$string['event:assessment_mapped_desc'] = 'An assessment is mapped to a SITS assessment component.';
$string['form:alert_no_mab_found'] = 'No assessment components found';
$string['form:info_turnitin_numparts'] = 'Please note Turnitin assignment with multiple parts is not supported by Marks Transfer.';
$string['gradepushassessmentselect'] = 'Select SITS assessment';
Expand Down
95 changes: 95 additions & 0 deletions tests/aws/sqs_test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

namespace local_sitsgradepush;

use Aws\Sqs\SqsClient;
use local_sitsgradepush\aws\sqs;

/**
* Tests for the sqs class.
*
* @package local_sitsgradepush
* @copyright 2024 onwards University College London {@link https://www.ucl.ac.uk/}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @author Alex Yeung <[email protected]>
*/
final class sqs_test extends \advanced_testcase {

/**
* Set up the test.
*
* @return void
*/
protected function setUp(): void {
$this->resetAfterTest();
}

/**
* Test get_client returns sqs client.
*
* @covers \local_sitsgradepush\aws\sqs::get_client
* @return void
*/
public function test_get_client_returns_sqs_client(): void {
$sqs = new sqs();
$client = $sqs->get_client();
$this->assertInstanceOf(SqsClient::class, $client);
}

/**
* Test constructor throws exception if configs missing.
*
* @covers \local_sitsgradepush\aws\sqs::__construct
* @return void
* @throws \coding_exception
*/
public function test_constructor_throws_exception_if_configs_missing(): void {
// Set the required configs to empty.
set_config('aws_region', '', 'local_sitsgradepush');
set_config('aws_key', '', 'local_sitsgradepush');
set_config('aws_secret', '', 'local_sitsgradepush');

$this->expectException(\moodle_exception::class);
$this->expectExceptionMessage(get_string('error:missingrequiredconfigs', 'local_sitsgradepush'));

new sqs();
}

/**
* Test check_required_configs_are_set returns configs.
*
* @covers \local_sitsgradepush\aws\sqs::__construct
* @covers \local_sitsgradepush\aws\sqs::check_required_configs_are_set
* @return void
* @throws \ReflectionException
*/
public function test_check_required_configs_are_set_returns_configs(): void {
// Set the required configs.
set_config('aws_region', 'us-east', 'local_sitsgradepush');
set_config('aws_key', 'awskey-1234', 'local_sitsgradepush');
set_config('aws_secret', 'secret-2468', 'local_sitsgradepush');

$sqs = new sqs();
$reflection = new \ReflectionClass($sqs);
$method = $reflection->getMethod('check_required_configs_are_set');
$method->setAccessible(true);
$configs = $method->invoke($sqs);
$this->assertEquals('us-east', $configs->aws_region);
$this->assertEquals('awskey-1234', $configs->aws_key);
$this->assertEquals('secret-2468', $configs->aws_secret);
}
}
Loading

0 comments on commit 446dfce

Please sign in to comment.