Skip to content

Commit

Permalink
CTP-3412 & CTP-3413 Create overrides for ECs & SORAs
Browse files Browse the repository at this point in the history
  • Loading branch information
aydevworks committed Oct 11, 2024
1 parent cf0f357 commit 966c868
Show file tree
Hide file tree
Showing 20 changed files with 1,334 additions and 11 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/moodle-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,6 @@ jobs:
- php: '8.1'
moodle-branch: 'MOODLE_404_STABLE'
database: 'mariadb'
- php: '8.1'
moodle-branch: 'MOODLE_403_STABLE'
database: 'mariadb'

steps:
- name: Check out repository code
Expand Down
14 changes: 14 additions & 0 deletions classes/assessment/activity.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

namespace local_sitsgradepush\assessment;

use core\context\module;
use grade_item;
use local_sitsgradepush\manager;

Expand All @@ -32,13 +33,17 @@ abstract class activity extends assessment {
/** @var \stdClass Course module object */
public \stdClass $coursemodule;

/** @var module Context module */
protected module $context;

/**
* Constructor.
*
* @param \stdClass $coursemodule
*/
public function __construct(\stdClass $coursemodule) {
$this->coursemodule = $coursemodule;
$this->context = \context_module::instance($coursemodule->id);
parent::__construct(assessmentfactory::SOURCETYPE_MOD, $coursemodule->id);
}

Expand Down Expand Up @@ -103,6 +108,15 @@ public function get_module_name(): string {
return $this->coursemodule->modname;
}

/**
* Get the module context.
*
* @return module
*/
public function get_module_context(): module {
return $this->context;
}

/**
* Get the course module id.
*
Expand Down
62 changes: 61 additions & 1 deletion classes/assessment/assessment.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

namespace local_sitsgradepush\assessment;

use local_sitsgradepush\extension\ec;
use local_sitsgradepush\extension\extension;
use local_sitsgradepush\extension\sora;
use local_sitsgradepush\manager;

/**
Expand Down Expand Up @@ -52,6 +55,27 @@ public function __construct(string $sourcetype, int $sourceid) {
$this->set_instance();
}

/**
* Apply extension to the assessment.
*
* @param extension $extension
* @return void
* @throws \moodle_exception
*/
public function apply_extension(extension $extension): void {
$check = $this->is_valid_for_extension();
if (!$check->valid) {
throw new \moodle_exception($check->errorcode, 'local_sitsgradepush');
}

// Do extension base on the extension type.
if ($extension instanceof ec) {
$this->apply_ec_extension($extension);
} else if ($extension instanceof sora) {
$this->apply_sora_extension($extension);
}
}

/**
* Get the source id.
*
Expand Down Expand Up @@ -196,6 +220,19 @@ public function check_assessment_validity(): \stdClass {
return $result;
}

/**
* Check if the assessment is valid for EC or SORA extension.
*
* @return \stdClass
*/
public function is_valid_for_extension(): \stdClass {
if ($this->get_start_date() === null || $this->get_end_date() === null) {
return $this->set_validity_result(false, 'error:dates_not_set');
}

return $this->set_validity_result(true);
}

/**
* Set validity result.
*
Expand Down Expand Up @@ -224,11 +261,34 @@ protected function get_equivalent_grade_from_mark(float $marks): ?string {
return $equivalentgrade;
}

/**
* Apply EC extension.
*
* @param ec $ec
* @return void
* @throws \moodle_exception
*/
protected function apply_ec_extension(ec $ec): void {
// Default not supported. Override in child class if needed.
throw new \moodle_exception('error:ecextensionnotsupported', 'local_sitsgradepush');
}

/**
* Apply SORA extension.
*
* @param sora $sora
* @return void
* @throws \moodle_exception
*/
protected function apply_sora_extension(sora $sora): void {
// Default not supported. Override in child class if needed.
throw new \moodle_exception('error:soraextensionnotsupported', 'local_sitsgradepush');
}

/**
* Get all participants for the assessment.
*
* @return array
*/
abstract public function get_all_participants(): array;

}
181 changes: 179 additions & 2 deletions classes/assessment/assign.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@

namespace local_sitsgradepush\assessment;

use cache;
use local_sitsgradepush\extension\ec;
use local_sitsgradepush\extension\sora;

/**
* Class for assignment assessment.
*
Expand All @@ -26,14 +30,23 @@
*/
class assign extends activity {

/**
* Is the user a participant in the assignment.
*
* @param int $userid
* @return bool
*/
public function is_user_a_participant(int $userid): bool {
return is_enrolled($this->get_module_context(), $userid, 'mod/assign:submit');
}

/**
* Get all participants.
*
* @return array
*/
public function get_all_participants(): array {
$context = \context_module::instance($this->coursemodule->id);
return get_enrolled_users($context, 'mod/assign:submit');
return get_enrolled_users($this->get_module_context(), 'mod/assign:submit');
}

/**
Expand All @@ -53,4 +66,168 @@ public function get_start_date(): ?int {
public function get_end_date(): ?int {
return $this->sourceinstance->duedate;
}

/**
* Apply EC extension to the assessment.
*
* @param ec $ec The EC extension.
* @return void
*/
protected function apply_ec_extension(ec $ec): void {
global $CFG;
require_once($CFG->dirroot . '/mod/assign/locallib.php');
$originalduedate = $this->get_end_date();

// EC is using a new deadline without time. Extract the time part of the original due date.
$time = date('H:i:s', $originalduedate);

// Get the new date and time.
$newduedate = strtotime($ec->get_new_deadline() . ' ' . $time);

// Override the assignment settings for user.
$this->overrides_due_date($newduedate, $ec->get_userid());
}

/**
* Apply SORA extension to the assessment.
*
* @param sora $sora The SORA extension.
* @return void
* @throws \moodle_exception
*/
protected function apply_sora_extension(sora $sora): void {
global $CFG;
require_once($CFG->dirroot . '/group/lib.php');

// Get time extension in seconds.
$timeextensionperhour = $sora->get_time_extension();

// Calculate the new due date.
// Find the difference between the start and end date in hours. Multiply by the time extension per hour.
$actualextension = (($this->get_end_date() - $this->get_start_date()) / HOURSECS) * $timeextensionperhour;
$newduedate = $this->get_end_date() + round($actualextension);

// Get the group id, create if it doesn't exist and add the user to the group.
$groupid = $sora->get_sora_group_id($this->get_course_id(), $sora->get_userid());

if (!$groupid) {
throw new \moodle_exception('error:cannotgetsoragroupid', 'local_sitsgradepush');
}

$this->overrides_due_date($newduedate, $sora->get_userid(), $groupid);
}

/**
* Overrides the due date for the user or group.
*
* @param int $newduedate The new due date.
* @param int $userid The user id.
* @param int|null $groupid The group id.
* @return void
*/
private function overrides_due_date(int $newduedate, int $userid, ?int $groupid = null): void {
global $CFG, $DB;
require_once($CFG->dirroot . '/mod/assign/locallib.php');
require_once($CFG->dirroot . '/mod/assign/lib.php');

// It is a group override.
if ($groupid) {
$sql = 'SELECT * FROM {assign_overrides} WHERE assignid = :assignid AND groupid = :groupid AND userid IS NULL';
$params = [
'assignid' => $this->get_source_instance()->id,
'groupid' => $groupid,
];
} else {
// It is a user override.
$sql = 'SELECT * FROM {assign_overrides} WHERE assignid = :assignid AND userid = :userid AND groupid IS NULL';
$params = [
'assignid' => $this->get_source_instance()->id,
'userid' => $userid,
];
}

// Check if the override already exists.
$override = $DB->get_record_sql($sql, $params);
if ($override) {
// No need to update if the due date is the same.
if ($override->duedate == $newduedate) {
return;
}
$override->duedate = $newduedate;
$DB->update_record('assign_overrides', $override);
$newrecord = false;
} else {
// Create a new override.
$override = new \stdClass();
$override->assignid = $this->get_source_instance()->id;
$override->duedate = $newduedate;
$override->userid = $groupid ? null : $userid;
$override->groupid = $groupid ?: null;
$override->sortorder = $groupid ? 0 : null;
$override->id = $DB->insert_record('assign_overrides', $override);

// Reorder the group overrides.
if ($groupid) {
reorder_group_overrides($override->assignid);
}
$newrecord = true;
}

// Clear the cache.
$this->clear_override_cache($override);

// Trigger the event.
$this->trigger_override_event($override, $newrecord);

// Update the assign events.
assign_update_events(new \assign($this->context, $this->get_course_module(), null), $override);
}

/**
* Trigger the override event.
*
* @param \stdClass $override The override object.
* @param bool $newrecord Whether the override is a new record.
* @return void
* @throws \coding_exception
*/
private function trigger_override_event(\stdClass $override, bool $newrecord): void {
$params = [
'context' => $this->context,
'other' => [
'assignid' => $override->assignid,
],
];

$params['objectid'] = $override->id;
if (!$override->groupid) {
$params['relateduserid'] = $override->userid;
if ($newrecord) {
$event = \mod_assign\event\user_override_created::create($params);
} else {
$event = \mod_assign\event\user_override_updated::create($params);
}
} else {
$params['other']['groupid'] = $override->groupid;
if ($newrecord) {
$event = \mod_assign\event\group_override_created::create($params);
} else {
$event = \mod_assign\event\group_override_updated::create($params);
}
}
$event->trigger();
}

/**
* Clear the override cache.
*
* @param \stdClass $override The override object.
* @return void
* @throws \coding_exception
*/
private function clear_override_cache(\stdClass $override): void {
$cachekey = $override->groupid ?
"{$override->assignid}_g_{$override->groupid}" : "{$override->assignid}_u_{$override->userid}";
cache::make('mod_assign', 'overrides')->delete($cachekey);
}
}
Loading

0 comments on commit 966c868

Please sign in to comment.