From 948746eae7a3432f235d8cd7dccea6d17273325a Mon Sep 17 00:00:00 2001 From: Jake Dallimore Date: Mon, 24 Jan 2022 16:45:30 +0800 Subject: [PATCH] MDL-69542 enrol_lti: make lib changes supporting LTI Advantage This change includes: - LTI Advantage specific code in delete_instance(). - LTI version field added to publish as lti tool form. - LTI Advantage specific uuid added to add_instance(). - Moved secret validation (LTI1.1/2.0) to server side, allowing the element to be hidden in LTI Advantage cases. --- enrol/lti/lib.php | 59 ++++++++++++++++++++++++++++++++++-- enrol/lti/tests/lib_test.php | 53 ++++++++++++++++++++++++++++++-- 2 files changed, 106 insertions(+), 6 deletions(-) diff --git a/enrol/lti/lib.php b/enrol/lti/lib.php index df7c08e24a4..d191cf8454b 100644 --- a/enrol/lti/lib.php +++ b/enrol/lti/lib.php @@ -23,6 +23,7 @@ */ use enrol_lti\data_connector; +use enrol_lti\local\ltiadvantage\repository\resource_link_repository; use IMSGlobal\LTI\ToolProvider\ToolConsumer; defined('MOODLE_INTERNAL') || die(); @@ -109,6 +110,11 @@ class enrol_lti_plugin extends enrol_plugin { $data->$field = $value; } + // LTI Advantage: make a unique identifier for the published resource. + if (empty($data->ltiversion) || $data->ltiversion == 'LTI-1p3') { + $data->uuid = \core\uuid::generate(); + } + $DB->insert_record('enrol_lti_tools', $data); return $instanceid; @@ -142,6 +148,11 @@ class enrol_lti_plugin extends enrol_plugin { $tool->$field = $value; } + // LTI Advantage: make a unique identifier for the published resource. + if ($tool->ltiversion == 'LTI-1p3' && empty($tool->uuid)) { + $tool->uuid = \core\uuid::generate(); + } + return $DB->update_record('enrol_lti_tools', $tool); } @@ -157,6 +168,10 @@ class enrol_lti_plugin extends enrol_plugin { // Get the tool associated with this instance. $tool = $DB->get_record('enrol_lti_tools', array('enrolid' => $instance->id), 'id', MUST_EXIST); + // LTI Advantage: delete any resource_link and user_resource_link mappings. + $resourcelinkrepo = new resource_link_repository(); + $resourcelinkrepo->delete_by_resource($tool->id); + // Delete any users associated with this tool. $DB->delete_records('enrol_lti_users', array('toolid' => $tool->id)); @@ -213,6 +228,17 @@ class enrol_lti_plugin extends enrol_plugin { public function edit_instance_form($instance, MoodleQuickForm $mform, $context) { global $DB; + $versionoptions = [ + 'LTI-1p3' => get_string('lti13', 'enrol_lti'), + 'LTI-1p0/LTI-2p0' => get_string('ltilegacy', 'enrol_lti') + ]; + $mform->addElement('select', 'ltiversion', get_string('ltiversion', 'enrol_lti'), $versionoptions); + $mform->addHelpButton('ltiversion', 'ltiversion', 'enrol_lti'); + $legacy = optional_param('legacy', 0, PARAM_INT); + if (empty($instance->id)) { + $mform->setDefault('ltiversion', $legacy ? 'LTI-1p0/LTI-2p0' : 'LTI-1p3'); + } + $nameattribs = array('size' => '20', 'maxlength' => '255'); $mform->addElement('text', 'name', get_string('custominstancename', 'enrol'), $nameattribs); $mform->setType('name', PARAM_TEXT); @@ -259,13 +285,32 @@ class enrol_lti_plugin extends enrol_plugin { $mform->setDefault('rolelearner', '5'); $mform->addHelpButton('rolelearner', 'rolelearner', 'enrol_lti'); + if (!$legacy) { + global $CFG; + require_once($CFG->dirroot . '/auth/lti/auth.php'); + $authmodes = [ + auth_plugin_lti::PROVISIONING_MODE_AUTO_ONLY => get_string('provisioningmodeauto', 'auth_lti'), + auth_plugin_lti::PROVISIONING_MODE_PROMPT_NEW_EXISTING => get_string('provisioningmodenewexisting', 'auth_lti'), + auth_plugin_lti::PROVISIONING_MODE_PROMPT_EXISTING_ONLY => get_string('provisioningmodeexistingonly', 'auth_lti') + ]; + $mform->addElement('select', 'provisioningmodeinstructor', get_string('provisioningmodeteacherlaunch', 'enrol_lti'), + $authmodes); + $mform->addHelpButton('provisioningmodeinstructor', 'provisioningmode', 'enrol_lti'); + $mform->setDefault('provisioningmodeinstructor', auth_plugin_lti::PROVISIONING_MODE_PROMPT_NEW_EXISTING); + + $mform->addElement('select', 'provisioningmodelearner', get_string('provisioningmodestudentlaunch', 'enrol_lti'), + $authmodes); + $mform->addHelpButton('provisioningmodelearner', 'provisioningmode', 'enrol_lti'); + $mform->setDefault('provisioningmodelearner', auth_plugin_lti::PROVISIONING_MODE_AUTO_ONLY); + } + $mform->addElement('header', 'remotesystem', get_string('remotesystem', 'enrol_lti')); $mform->addElement('text', 'secret', get_string('secret', 'enrol_lti'), 'maxlength="64" size="25"'); $mform->setType('secret', PARAM_ALPHANUM); $mform->setDefault('secret', random_string(32)); $mform->addHelpButton('secret', 'secret', 'enrol_lti'); - $mform->addRule('secret', get_string('required'), 'required'); + $mform->hideIf('secret', 'ltiversion', 'eq', 'LTI-1p3'); $mform->addElement('selectyesno', 'gradesync', get_string('gradesync', 'enrol_lti')); $mform->setDefault('gradesync', 1); @@ -337,6 +382,10 @@ class enrol_lti_plugin extends enrol_plugin { $mform->setType('toolid', PARAM_INT); $mform->setConstant('toolid', $ltitool->id); + $mform->addElement('hidden', 'uuid'); + $mform->setType('uuid', PARAM_ALPHANUMEXT); + $mform->setConstant('uuid', $ltitool->uuid); + $mform->setDefaults((array) $ltitool); } } @@ -357,6 +406,11 @@ class enrol_lti_plugin extends enrol_plugin { $errors = array(); + // Secret must be set. + if (empty($data['secret'])) { + $errors['secret'] = get_string('required'); + } + if (!empty($data['enrolenddate']) && $data['enrolenddate'] < $data['enrolstartdate']) { $errors['enrolenddate'] = get_string('enrolenddateerror', 'enrol_lti'); } @@ -409,8 +463,7 @@ function enrol_lti_extend_navigation_course($navigation, $course, $context) { if ($ltiplugin->can_add_instance($course->id)) { $url = new moodle_url('/enrol/lti/index.php', array('courseid' => $course->id)); $settingsnode = navigation_node::create(get_string('sharedexternaltools', 'enrol_lti'), $url, - navigation_node::TYPE_SETTING, null, null, new pix_icon('i/settings', '')); - + navigation_node::TYPE_SETTING, null, 'publishedtools', new pix_icon('i/settings', '')); $navigation->add_node($settingsnode); } } diff --git a/enrol/lti/tests/lib_test.php b/enrol/lti/tests/lib_test.php index 12b12033964..d11e0f82699 100644 --- a/enrol/lti/tests/lib_test.php +++ b/enrol/lti/tests/lib_test.php @@ -25,8 +25,6 @@ namespace enrol_lti; use course_enrolment_manager; use enrol_lti_plugin; -use enrol_lti\data_connector; -use enrol_lti\tool_provider; use IMSGlobal\LTI\ToolProvider\ResourceLink; use IMSGlobal\LTI\ToolProvider\ToolConsumer; use IMSGlobal\LTI\ToolProvider\ToolProvider; @@ -34,6 +32,8 @@ use IMSGlobal\LTI\ToolProvider\User; defined('MOODLE_INTERNAL') || die(); +require_once(__DIR__ . '/local/ltiadvantage/lti_advantage_testcase.php'); + /** * Tests for the enrol_lti_plugin class. * @@ -41,7 +41,7 @@ defined('MOODLE_INTERNAL') || die(); * @copyright 2016 Jun Pataleta * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class lib_test extends \advanced_testcase { +class lib_test extends \lti_advantage_testcase { /** * Test set up. @@ -121,6 +121,53 @@ class lib_test extends \advanced_testcase { $this->assertFalse($DB->record_exists('enrol', [ 'id' => $instance->id ])); } + /** + * Test confirming that relevant data is removed after enrol instance removal. + * + * @covers \enrol_lti_plugin::delete_instance + */ + public function test_delete_instance_lti_advantage() { + global $DB; + // Setup. + [ + $course, + $modresource, + $modresource2, + $courseresource, + $registration, + $deployment + ] = $this->create_test_environment(); + + // Launch the tool. + $mockuser = $this->get_mock_launch_users_with_ids(['1p3_1'])[0]; + $mocklaunch = $this->get_mock_launch($modresource, $mockuser); + $instructoruser = $this->getDataGenerator()->create_user(); + $launchservice = $this->get_tool_launch_service(); + $launchservice->user_launches_tool($instructoruser, $mocklaunch); + + // Verify data exists. + $this->assertEquals(1, $DB->count_records('enrol_lti_user_resource_link')); + $this->assertEquals(1, $DB->count_records('enrol_lti_resource_link')); + $this->assertEquals(1, $DB->count_records('enrol_lti_app_registration')); + $this->assertEquals(1, $DB->count_records('enrol_lti_deployment')); + $this->assertEquals(1, $DB->count_records('enrol_lti_context')); + $this->assertEquals(1, $DB->count_records('enrol_lti_users')); + + // Now delete the enrol instance. + $enrollti = new enrol_lti_plugin(); + $instance = $DB->get_record('enrol', ['id' => $modresource->enrolid]); + $enrollti->delete_instance($instance); + + $this->assertEquals(0, $DB->count_records('enrol_lti_user_resource_link')); + $this->assertEquals(0, $DB->count_records('enrol_lti_resource_link')); + $this->assertEquals(0, $DB->count_records('enrol_lti_users')); + + // App registration, Deployment and Context tables are not affected by instance removal. + $this->assertEquals(1, $DB->count_records('enrol_lti_app_registration')); + $this->assertEquals(1, $DB->count_records('enrol_lti_deployment')); + $this->assertEquals(1, $DB->count_records('enrol_lti_context')); + } + /** * Test for getting user enrolment actions. */