<script type=\"text/javascript\"> window.opener.M.mod_lti.editor.updateToolType({$json}); window.close(); </script> </html> "; echo $script; die; } else { $type->state = LTI_TOOL_STATE_CONFIGURED; $type->course = $COURSE->id; $id = lti_add_type($type, $data); $fromdb = lti_get_type($id); $json = json_encode($fromdb); // Output script to update the calling window. $script = " <html> <script type=\"text/javascript\"> window.opener.M.mod_lti.editor.addToolType({$json}); window.close(); </script> </html> "; echo $script; die;
/** * Return the launch data required for opening the external tool. * * @param stdClass $instance the external tool activity settings * @return array the endpoint URL and parameters (including the signature) * @since Moodle 3.0 */ function lti_get_launch_data($instance) { global $PAGE, $CFG; if (empty($instance->typeid)) { $tool = lti_get_tool_by_url_match($instance->toolurl, $instance->course); if ($tool) { $typeid = $tool->id; } else { $typeid = null; } } else { $typeid = $instance->typeid; $tool = lti_get_type($typeid); } if ($typeid) { $typeconfig = lti_get_type_config($typeid); } else { // There is no admin configuration for this tool. Use configuration in the lti instance record plus some defaults. $typeconfig = (array) $instance; $typeconfig['sendname'] = $instance->instructorchoicesendname; $typeconfig['sendemailaddr'] = $instance->instructorchoicesendemailaddr; $typeconfig['customparameters'] = $instance->instructorcustomparameters; $typeconfig['acceptgrades'] = $instance->instructorchoiceacceptgrades; $typeconfig['allowroster'] = $instance->instructorchoiceallowroster; $typeconfig['forcessl'] = '0'; } // Default the organizationid if not specified. if (empty($typeconfig['organizationid'])) { $urlparts = parse_url($CFG->wwwroot); $typeconfig['organizationid'] = $urlparts['host']; } if (isset($tool->toolproxyid)) { $toolproxy = lti_get_tool_proxy($tool->toolproxyid); $key = $toolproxy->guid; $secret = $toolproxy->secret; } else { $toolproxy = null; if (!empty($instance->resourcekey)) { $key = $instance->resourcekey; } else { if (!empty($typeconfig['resourcekey'])) { $key = $typeconfig['resourcekey']; } else { $key = ''; } } if (!empty($instance->password)) { $secret = $instance->password; } else { if (!empty($typeconfig['password'])) { $secret = $typeconfig['password']; } else { $secret = ''; } } } $endpoint = !empty($instance->toolurl) ? $instance->toolurl : $typeconfig['toolurl']; $endpoint = trim($endpoint); // If the current request is using SSL and a secure tool URL is specified, use it. if (lti_request_is_using_ssl() && !empty($instance->securetoolurl)) { $endpoint = trim($instance->securetoolurl); } // If SSL is forced, use the secure tool url if specified. Otherwise, make sure https is on the normal launch URL. if (isset($typeconfig['forcessl']) && $typeconfig['forcessl'] == '1') { if (!empty($instance->securetoolurl)) { $endpoint = trim($instance->securetoolurl); } $endpoint = lti_ensure_url_is_https($endpoint); } else { if (!strstr($endpoint, '://')) { $endpoint = 'http://' . $endpoint; } } $orgid = $typeconfig['organizationid']; $course = $PAGE->course; $islti2 = isset($tool->toolproxyid); $allparams = lti_build_request($instance, $typeconfig, $course, $typeid, $islti2); if ($islti2) { $requestparams = lti_build_request_lti2($tool, $allparams); } else { $requestparams = $allparams; } $requestparams = array_merge($requestparams, lti_build_standard_request($instance, $orgid, $islti2)); $customstr = ''; if (isset($typeconfig['customparameters'])) { $customstr = $typeconfig['customparameters']; } $requestparams = array_merge($requestparams, lti_build_custom_parameters($toolproxy, $tool, $instance, $allparams, $customstr, $instance->instructorcustomparameters, $islti2)); $launchcontainer = lti_get_launch_container($instance, $typeconfig); $returnurlparams = array('course' => $course->id, 'launch_container' => $launchcontainer, 'instanceid' => $instance->id, 'sesskey' => sesskey()); // Add the return URL. We send the launch container along to help us avoid frames-within-frames when the user returns. $url = new \moodle_url('/mod/lti/return.php', $returnurlparams); $returnurl = $url->out(false); if (isset($typeconfig['forcessl']) && $typeconfig['forcessl'] == '1') { $returnurl = lti_ensure_url_is_https($returnurl); } $target = ''; switch ($launchcontainer) { case LTI_LAUNCH_CONTAINER_EMBED: case LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS: $target = 'iframe'; break; case LTI_LAUNCH_CONTAINER_REPLACE_MOODLE_WINDOW: $target = 'frame'; break; case LTI_LAUNCH_CONTAINER_WINDOW: $target = 'window'; break; } if (!empty($target)) { $requestparams['launch_presentation_document_target'] = $target; } $requestparams['launch_presentation_return_url'] = $returnurl; // Allow request params to be updated by sub-plugins. $plugins = core_component::get_plugin_list('ltisource'); foreach (array_keys($plugins) as $plugin) { $pluginparams = component_callback('ltisource_' . $plugin, 'before_launch', array($instance, $endpoint, $requestparams), array()); if (!empty($pluginparams) && is_array($pluginparams)) { $requestparams = array_merge($requestparams, $pluginparams); } } if (!empty($key) && !empty($secret)) { $parms = lti_sign_parameters($requestparams, $endpoint, "POST", $key, $secret); $endpointurl = new \moodle_url($endpoint); $endpointparams = $endpointurl->params(); // Strip querystring params in endpoint url from $parms to avoid duplication. if (!empty($endpointparams) && !empty($parms)) { foreach (array_keys($endpointparams) as $paramname) { if (isset($parms[$paramname])) { unset($parms[$paramname]); } } } } else { // If no key and secret, do the launch unsigned. $returnurlparams['unsigned'] = '1'; $parms = $requestparams; } return array($endpoint, $parms); }
/** * Processes the tool provider's response to the ContentItemSelectionRequest and builds the configuration data from the * selected content item. This configuration data can be then used when adding a tool into the course. * * @param int $typeid The tool type ID. * @param string $messagetype The value for the lti_message_type parameter. * @param string $ltiversion The value for the lti_version parameter. * @param string $consumerkey The consumer key. * @param string $contentitemsjson The JSON string for the content_items parameter. * @return stdClass The array of module information objects. * @throws moodle_exception * @throws lti\OAuthException */ function lti_tool_configuration_from_content_item($typeid, $messagetype, $ltiversion, $consumerkey, $contentitemsjson) { $tool = lti_get_type($typeid); // Validate parameters. if (!$tool) { throw new moodle_exception('errortooltypenotfound', 'mod_lti'); } // Check lti_message_type. Show debugging if it's not set to ContentItemSelection. // No need to throw exceptions for now since lti_message_type does not seem to be used in this processing at the moment. if ($messagetype !== 'ContentItemSelection') { debugging("lti_message_type is invalid: {$messagetype}. It should be set to 'ContentItemSelection'.", DEBUG_DEVELOPER); } $typeconfig = lti_get_type_config($typeid); if (isset($tool->toolproxyid)) { $islti2 = true; $toolproxy = lti_get_tool_proxy($tool->toolproxyid); $key = $toolproxy->guid; $secret = $toolproxy->secret; } else { $islti2 = false; $toolproxy = null; if (!empty($typeconfig['resourcekey'])) { $key = $typeconfig['resourcekey']; } else { $key = ''; } if (!empty($typeconfig['password'])) { $secret = $typeconfig['password']; } else { $secret = ''; } } // Check LTI versions from our side and the response's side. Show debugging if they don't match. // No need to throw exceptions for now since LTI version does not seem to be used in this processing at the moment. $expectedversion = LTI_VERSION_1; if ($islti2) { $expectedversion = LTI_VERSION_2; } if ($ltiversion !== $expectedversion) { debugging("lti_version from response does not match the tool's configuration. Tool: {$expectedversion}," . " Response: {$ltiversion}", DEBUG_DEVELOPER); } if ($consumerkey !== $key) { throw new moodle_exception('errorincorrectconsumerkey', 'mod_lti'); } $store = new lti\TrivialOAuthDataStore(); $store->add_consumer($key, $secret); $server = new lti\OAuthServer($store); $method = new lti\OAuthSignatureMethod_HMAC_SHA1(); $server->add_signature_method($method); $request = lti\OAuthRequest::from_request(); try { $server->verify_request($request); } catch (lti\OAuthException $e) { throw new lti\OAuthException("OAuth signature failed: " . $e->getMessage()); } $items = json_decode($contentitemsjson); if (empty($items)) { throw new moodle_exception('errorinvaliddata', 'mod_lti', '', $contentitemsjson); } if ($items->{'@context'} !== 'http://purl.imsglobal.org/ctx/lti/v1/ContentItem') { throw new moodle_exception('errorinvalidmediatype', 'mod_lti', '', $items->{'@context'}); } if (!isset($items->{'@graph'}) || !is_array($items->{'@graph'}) || count($items->{'@graph'}) > 1) { throw new moodle_exception('errorinvalidresponseformat', 'mod_lti'); } $config = null; if (!empty($items->{'@graph'})) { $item = $items->{'@graph'}[0]; $config = new stdClass(); $config->name = ''; if (isset($item->title)) { $config->name = $item->title; } if (empty($config->name)) { $config->name = $tool->name; } if (isset($item->text)) { $config->introeditor = ['text' => $item->text, 'format' => FORMAT_PLAIN]; } if (isset($item->icon->{'@id'})) { $iconurl = new moodle_url($item->icon->{'@id'}); // Assign item's icon URL to secureicon or icon depending on its scheme. if (strtolower($iconurl->get_scheme()) === 'https') { $config->secureicon = $iconurl->out(false); } else { $config->icon = $iconurl->out(false); } } if (isset($item->url)) { $url = new moodle_url($item->url); // Assign item URL to securetoolurl or toolurl depending on its scheme. if (strtolower($url->get_scheme()) === 'https') { $config->securetoolurl = $url->out(false); } else { $config->toolurl = $url->out(false); } $config->typeid = 0; } else { $config->typeid = $typeid; } $config->instructorchoicesendname = LTI_SETTING_NEVER; $config->instructorchoicesendemailaddr = LTI_SETTING_NEVER; $config->instructorchoiceacceptgrades = LTI_SETTING_NEVER; $config->launchcontainer = LTI_LAUNCH_CONTAINER_DEFAULT; if (isset($item->placementAdvice->presentationDocumentTarget)) { if ($item->placementAdvice->presentationDocumentTarget === 'window') { $config->launchcontainer = LTI_LAUNCH_CONTAINER_WINDOW; } else { if ($item->placementAdvice->presentationDocumentTarget === 'frame') { $config->launchcontainer = LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS; } else { if ($item->placementAdvice->presentationDocumentTarget === 'iframe') { $config->launchcontainer = LTI_LAUNCH_CONTAINER_EMBED; } } } } if (isset($item->custom)) { $customparameters = []; foreach ($item->custom as $key => $value) { $customparameters[] = "{$key}={$value}"; } $config->instructorcustomparameters = implode("\n", $customparameters); } } return $config; }
/** * Delete a tool type. * * @param int $id The id of the tool type to be deleted * @return array deleted tool type * @since Moodle 3.1 * @throws moodle_exception */ public static function delete_tool_type($id) { $params = self::validate_parameters(self::delete_tool_type_parameters(), array('id' => $id)); $id = $params['id']; $context = context_system::instance(); self::validate_context($context); require_capability('moodle/site:config', $context); $type = lti_get_type($id); if (!empty($type)) { lti_delete_type($id); // If this is the last type for this proxy then remove the proxy // as well so that it isn't orphaned. $types = lti_get_lti_types_from_proxy_id($type->toolproxyid); if (empty($types)) { lti_delete_tool_proxy($type->toolproxyid); } } return array('id' => $id); }
public function test_mod_lti_delete_tool_type_without_capability() { $type = mod_lti_external::create_tool_type($this->getExternalTestFileUrl('/ims_cartridge_basic_lti_link.xml'), '', ''); $this->assertNotEmpty(lti_get_type($type['id'])); $this->expectException('required_capability_exception'); self::setUser($this->teacher); $type = mod_lti_external::delete_tool_type($type['id']); }