From 7a4b90df8d5eb64fa8f814a444553dbd1ca82124 Mon Sep 17 00:00:00 2001 From: David Watson <14983002+watson8@users.noreply.github.com> Date: Tue, 1 Oct 2024 15:21:16 +0100 Subject: [PATCH 1/2] CTP-3660 LTI source for Marks Transfer --- classes/assessment/lti.php | 85 ++++++++++++++++++++++++++++++++++++++ classes/submission/lti.php | 80 +++++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 classes/assessment/lti.php create mode 100644 classes/submission/lti.php diff --git a/classes/assessment/lti.php b/classes/assessment/lti.php new file mode 100644 index 0000000..ab8050b --- /dev/null +++ b/classes/assessment/lti.php @@ -0,0 +1,85 @@ +. + +namespace local_sitsgradepush\assessment; + +/** + * Class for LTI assessment. + * + * @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 David Watson + */ +class lti extends activity { + + /** + * Get all participants. + * + * @return array + */ + public function get_all_participants(): array { + global $DB, $CFG; + // For LTI_SETTING_ constants. + require_once("$CFG->dirroot/mod/lti/locallib.php"); + + $context = \context_module::instance($this->coursemodule->id); + $capability = 'mod/lti:view'; + + // Which type of LTI tool is this? + $typeid = $this->sourceinstance->typeid; + if (!$typeid) { + $tool = lti_get_tool_by_url_match($this->sourceinstance->toolurl, $this->sourceinstance->course); + if ($tool) { + $typeid = $tool->id; + } + } + + // Has this tool been configured to accept grades globally or not? + $acceptgradestool = $DB->get_field( + 'lti_types_config', 'value', ['typeid' => $typeid, 'name' => 'acceptgrades'] + ); + if ($acceptgradestool == LTI_SETTING_ALWAYS) { + return get_enrolled_users($context, $capability); + } else if ($acceptgradestool == LTI_SETTING_DELEGATE) { + // Whether or not grades are accepted is determined at course level. + return $this->sourceinstance->instructorchoiceacceptgrades == LTI_SETTING_ALWAYS + ? get_enrolled_users($context, $capability) + : []; + } + return []; + } + + /** + * Get the start date of this assessment. + * + * @return int|null + */ + public function get_start_date(): ?int { + // This activity does not have a start date. + return null; + } + + /** + * Get the end date of this assessment. + * + * @return int|null + */ + public function get_end_date(): ?int { + // This activity does not have a start date. + return null; + } +} diff --git a/classes/submission/lti.php b/classes/submission/lti.php new file mode 100644 index 0000000..d4259f5 --- /dev/null +++ b/classes/submission/lti.php @@ -0,0 +1,80 @@ +. + +namespace local_sitsgradepush\submission; + +/** + * Class for coursework plugin (mod_coursework) submission. + * + * @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 David Watson + */ +class lti extends submission { + /** + * Get hand in datetime. + * + * @return string + */ + public function get_handin_datetime(): string { + if ($this->submissiondata->datesubmitted ?? null) { + return $this->get_iso8601_datetime($this->submissiondata->datesubmitted); + } else { + return ""; + } + } + + /** + * Set the module instance. + * + * @return void + * @throws \dml_exception + * @throws \moodle_exception + */ + protected function set_module_instance() { + global $DB; + if (!$instance = $DB->get_record('lti', ['id' => $this->coursemodule->instance])) { + throw new \moodle_exception( + 'error:coursemodulenotfound', 'local_sitsgradepush', '', null, + "Instance ID: " . $this->coursemodule->instance + ); + } + + $this->modinstance = $instance; + } + + /** + * Set submission. + * + * @return void + * @throws \dml_exception + * @throws \moodle_exception + */ + protected function set_submission_data(): void { + global $DB; + + // User may have multiple attempts. + // In that case we return the most recent attempt details. + $params = ['ltiid' => $this->modinstance->id, 'userid' => $this->userid]; + $attempts = $DB->get_records( + 'lti_submission', $params, 'datesubmitted DESC', '*', 0, 1 + ); + if (!empty($attempts)) { + $this->submissiondata = reset($attempts); + } + } +} From 7f72dade6d6b2fcfae051c8c3ff73bb9c06b71c3 Mon Sep 17 00:00:00 2001 From: David Watson <14983002+watson8@users.noreply.github.com> Date: Tue, 8 Oct 2024 15:06:20 +0100 Subject: [PATCH 2/2] CTP-3660 check LTI grade eligibility --- classes/assessment/lti.php | 67 +++++++++++++++++++-------------- lang/en/local_sitsgradepush.php | 1 + 2 files changed, 40 insertions(+), 28 deletions(-) diff --git a/classes/assessment/lti.php b/classes/assessment/lti.php index ab8050b..6b96fcc 100644 --- a/classes/assessment/lti.php +++ b/classes/assessment/lti.php @@ -32,35 +32,11 @@ class lti extends activity { * @return array */ public function get_all_participants(): array { - global $DB, $CFG; - // For LTI_SETTING_ constants. - require_once("$CFG->dirroot/mod/lti/locallib.php"); - - $context = \context_module::instance($this->coursemodule->id); - $capability = 'mod/lti:view'; - - // Which type of LTI tool is this? - $typeid = $this->sourceinstance->typeid; - if (!$typeid) { - $tool = lti_get_tool_by_url_match($this->sourceinstance->toolurl, $this->sourceinstance->course); - if ($tool) { - $typeid = $tool->id; - } + if (!self::check_assessment_validity()->valid) { + return []; } - - // Has this tool been configured to accept grades globally or not? - $acceptgradestool = $DB->get_field( - 'lti_types_config', 'value', ['typeid' => $typeid, 'name' => 'acceptgrades'] - ); - if ($acceptgradestool == LTI_SETTING_ALWAYS) { - return get_enrolled_users($context, $capability); - } else if ($acceptgradestool == LTI_SETTING_DELEGATE) { - // Whether or not grades are accepted is determined at course level. - return $this->sourceinstance->instructorchoiceacceptgrades == LTI_SETTING_ALWAYS - ? get_enrolled_users($context, $capability) - : []; - } - return []; + $context = \context_module::instance($this->coursemodule->id); + return get_enrolled_users($context, 'mod/lti:view'); } /** @@ -82,4 +58,39 @@ public function get_end_date(): ?int { // This activity does not have a start date. return null; } + + /** + * Check assessment is valid for mapping. + * + * @return \stdClass + */ + public function check_assessment_validity(): \stdClass { + global $CFG, $DB; + + // For LTI_SETTING_ constants. + require_once("$CFG->dirroot/mod/lti/locallib.php"); + + // Which type of LTI tool is this? + $typeid = $this->sourceinstance->typeid; + if (!$typeid) { + $tool = lti_get_tool_by_url_match($this->sourceinstance->toolurl, $this->sourceinstance->course); + if ($tool) { + $typeid = $tool->id; + } + } + + // Has this tool been configured to accept grades globally or not? + $acceptgradestool = $DB->get_field( + 'lti_types_config', 'value', ['typeid' => $typeid, 'name' => 'acceptgrades'] + ); + if ($acceptgradestool == LTI_SETTING_ALWAYS) { + // At system level, LTI grades are set to be sent to gradebook. + return parent::check_assessment_validity(); + } else if ($acceptgradestool == LTI_SETTING_DELEGATE && + $this->sourceinstance->instructorchoiceacceptgrades == LTI_SETTING_ALWAYS) { + // Whether or not grades are accepted is delegated to course level, which is set to yes. + return parent::check_assessment_validity(); + } + return $this->set_validity_result(false, 'error:lti_no_grades'); + } } diff --git a/lang/en/local_sitsgradepush.php b/lang/en/local_sitsgradepush.php index 4d67026..64fc0a3 100644 --- a/lang/en/local_sitsgradepush.php +++ b/lang/en/local_sitsgradepush.php @@ -98,6 +98,7 @@ $string['error:gradetype_not_supported'] = 'The grade type of this assessment is not supported for marks transfer.'; $string['error:inserttask'] = 'Failed to insert task.'; $string['error:invalid_source_type'] = 'Invalid source type. {$a}'; +$string['error:lti_no_grades'] = 'LTI activity is set to not send grades to gradebook'; $string['error:mab_has_push_records'] = 'Assessment component mapping cannot be updated as marks have been transfered for {$a}'; $string['error:mab_invalid_for_mapping'] = 'This assessment component is not valid for mapping due to the following reasons: {$a}.'; $string['error:mab_not_found'] = 'Assessment component not found. ID: {$a}';