switch($action){
case 'find_tool_config':
$toolurl = required_param('toolurl', PARAM_RAW);
-
+
$tool = lti_get_tool_by_url_match($toolurl, $courseid);
-
+
if(!empty($tool)){
$response->toolid = $tool->id;
$response->toolname = htmlspecialchars($tool->name);
$response->tooldomain = htmlspecialchars($tool->tooldomain);
}
-
break;
}
// Define each element separated
$basiclti = new backup_nested_element('lti', array('id'), array(
- 'name',
- 'intro',
- 'introformat',
- 'timecreated',
+ 'name',
+ 'intro',
+ 'introformat',
+ 'timecreated',
'timemodified',
- 'typeid',
- 'toolurl',
- 'preferheight',
+ 'typeid',
+ 'toolurl',
+ 'preferheight',
'launchcontainer',
'instructorchoicesendname',
'instructorchoicesendemailaddr',
- 'instructorchoiceacceptgrades',
+ 'instructorchoiceacceptgrades',
'instructorchoiceallowroster',
- 'instructorchoiceallowsetting',
- 'grade',
+ 'instructorchoiceallowsetting',
+ 'grade',
'instructorcustomparameters',
'showtitle',
'showdescription'
$data->course = $this->get_courseid();
require_once($CFG->dirroot.'/mod/lti/lib.php');
-
+
$newitemid = lti_add_instance($data);
-
+
// insert the basiclti record
//$newitemid = $DB->insert_record('lti', $data);
// immediately after inserting "activity" record, call this
'manager' => CAP_ALLOW
)
),
-
+
'mod/lti:manage' => array(
'riskbitmask' => RISK_XSS,
'manager' => CAP_ALLOW
)
),
-
+
'mod/lti:addcoursetool' => array(
'captype' => 'write',
'contextlevel' => CONTEXT_COURSE,
'manager' => CAP_ALLOW
)
),
-
+
'mod/lti:requesttooladd' => array(
'captype' => 'write',
'contextlevel' => CONTEXT_COURSE,
global $DB;
$dbman = $DB->get_manager();
-
+
if ($oldversion < 2011100701) {
$table = new xmldb_table('lti');
$field = new xmldb_field('icon', XMLDB_TYPE_TEXT, 'small', null, null, null, null, 'servicesalt');
}
upgrade_mod_savepoint(true, 2011100701, 'lti');
- }
-
+ }
+
if ($oldversion < 2011101801) {
$table = new xmldb_table('lti');
$field = new xmldb_field('securetoolurl', XMLDB_TYPE_TEXT, 'small', null, null, null, null, 'toolurl');
-
+
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
-
+
$field = new xmldb_field('secureicon', XMLDB_TYPE_TEXT, 'small', null, null, null, null, 'icon');
-
+
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
- }
-
+ }
+
upgrade_mod_savepoint(true, 2011101801, 'lti');
}
-
- $result = true;
-
+ $result = true;
return $result;
}
//-------------------------------------------------------------------------------
// Add basiclti elements
$mform->addElement('header', 'setup', get_string('tool_settings', 'lti'));
-
+
$mform->addElement('text', 'lti_typename', get_string('typename', 'lti'));
$mform->setType('lti_typename', PARAM_INT);
$mform->addHelpButton('lti_typename', 'typename','lti');
-
$mform->addRule('lti_typename', null, 'required', null, 'client');
$mform->addElement('text', 'lti_toolurl', get_string('toolurl', 'lti'), array('size'=>'64'));
$mform->addElement('text', 'lti_resourcekey', get_string('resourcekey_admin', 'lti'));
$mform->setType('lti_resourcekey', PARAM_TEXT);
$mform->addHelpButton('lti_resourcekey', 'resourcekey_admin', 'lti');
-
+
$mform->addElement('passwordunmask', 'lti_password', get_string('password_admin', 'lti'));
$mform->setType('lti_password', PARAM_TEXT);
$mform->addHelpButton('lti_password', 'password_admin', 'lti');
-
+
$mform->addElement('textarea', 'lti_customparameters', get_string('custom', 'lti'), array('rows'=>4, 'cols'=>60));
$mform->setType('lti_customparameters', PARAM_TEXT);
$mform->addHelpButton('lti_customparameters', 'custom', 'lti');
-
+
if(!empty($this->_customdata->isadmin)){
$mform->addElement('checkbox', 'lti_coursevisible', ' ', ' ' . get_string('show_in_course', 'lti'));
$mform->addHelpButton('lti_coursevisible', 'show_in_course', 'lti');
} else {
$mform->addElement('hidden', 'lti_coursevisible', '1');
}
-
+
$mform->addElement('hidden', 'typeid');
-
+
$launchoptions=array();
$launchoptions[LTI_LAUNCH_CONTAINER_EMBED] = get_string('embed', 'lti');
$launchoptions[LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS] = get_string('embed_no_blocks', 'lti');
$mform->addElement('select', 'lti_launchcontainer', get_string('default_launch_container', 'lti'), $launchoptions);
$mform->setDefault('lti_launchcontainer', LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS);
$mform->addHelpButton('lti_launchcontainer', 'default_launch_container', 'lti');
-
+
// Add privacy preferences fieldset where users choose whether to send their data
$mform->addElement('header', 'privacy', get_string('privacy', 'lti'));
$mform->addElement('checkbox', 'lti_forcessl',' ', ' ' . get_string('force_ssl', 'lti'), $options);
$mform->setDefault('lti_forcessl', '0');
-
$mform->addHelpButton('lti_forcessl', 'force_ssl', 'lti');
-
+
if(!empty($this->_customdata->isadmin)){
//-------------------------------------------------------------------------------
// Add setup parameters fieldset
$mform->setType('lti_organizationurl', PARAM_TEXT);
$mform->addHelpButton('lti_organizationurl', 'organizationurl', 'lti');
}
-
+
/* Suppress this for now - Chuck
$mform->addElement('text', 'lti_organizationdescr', get_string('organizationdescr', 'lti'));
$mform->setType('lti_organizationdescr', PARAM_TEXT);
//-------------------------------------------------------------------------------
// Add a hidden element to signal a tool fixing operation after a problematic backup - restore process
//$mform->addElement('hidden', 'lti_fix');
-
+
$tab = optional_param('tab', '', PARAM_ALPHAEXT);
$mform->addElement('hidden', 'tab', $tab);
-
+
$courseid = optional_param('course', 1, PARAM_INT);
$mform->addElement('hidden', 'course', $courseid);
-
+
//-------------------------------------------------------------------------------
// Add standard buttons, common to all modules
$this->add_action_buttons();
'name' => 'mod_lti_submissions',
'fullpath' => '/mod/lti/submissions.js',
'requires' => array('base'),
- 'strings' => array(
-
- ),
+ 'strings' => array(),
);
$PAGE->requires->js_init_call('M.mod_lti.submissions.init', array(), true, $module);
foreach($submissions as $submission){
$row = $rowtemplate;
-
+
foreach($submission as $key => $value){
if($key === 'datesubmitted'){
$value = userdate($value);
}
-
+
$row = str_replace('<!--' . $key . '-->', $value, $row);
}
-
+
$rows .= $row;
}
$type = lti_get_type($typeid);
if($type->course != $courseid){
throw new Exception('You do not have permissions to edit this tool type.');
-
die;
}
}
if (isset($data->submitbutton) && confirm_sesskey()) {
$type = new stdClass();
-
+
if (!empty($typeid)) {
$type->id = $typeid;
$name = json_encode($data->lti_typename);
lti_update_type($type, $data);
-
+
$fromdb = lti_get_type($typeid);
$json = json_encode($fromdb);
-
+
//Output script to update the calling window.
$script = <<<SCRIPT
<script type="text/javascript">
window.opener.M.mod_lti.editor.updateToolType({$json});
-
window.close();
</script>
SCRIPT;
-
+
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 = <<<SCRIPT
<script type="text/javascript">
window.opener.M.mod_lti.editor.addToolType({$json});
-
window.close();
</script>
SCRIPT;
-
+
echo $script;
-
+
die;
}
} else if(isset($data->cancel)){
- $script = <<<SCRIPT
- <script type="text/javascript">
- window.close();
- </script>
+ $script = <<<SCRIPT
+ <script type="text/javascript">
+ window.close();
+ </script>
SCRIPT;
-
- echo $script;
+
+ echo $script;
die;
}
//Delete action is called via ajax
if ($action == 'delete'){
lti_delete_type($typeid);
-
die;
}
$formdata->timecreated = time();
$formdata->timemodified = $formdata->timecreated;
$formdata->servicesalt = uniqid('', true);
-
+
if(!isset($formdata->grade)){
$formdata->grade = 100;
}
-
+
$id = $DB->insert_record("lti", $formdata);
if ($formdata->instructorchoiceacceptgrades == LTI_SETTING_ALWAYS) {
$basiclti = $DB->get_record('lti', array('id'=>$id));
-
+
if(!isset($formdata->cmidnumber)){
$formdata->cmidnumber = '';
}
-
+
$basiclti->cmidnumber = $formdata->cmidnumber;
-
+
lti_grade_item_update($basiclti);
}
if(!isset($formdata->showtitle)){
$formdata->showtitle = 0;
}
-
+
if(!isset($formdata->showdescription)){
$formdata->showdescription = 0;
}
-
+
if ($formdata->instructorchoiceacceptgrades == LTI_SETTING_ALWAYS) {
$basicltirec = $DB->get_record("lti", array("id" => $formdata->id));
$basicltirec->cmidnumber = $formdata->cmidnumber;
-
+
lti_grade_item_update($basicltirec);
} else {
lti_grade_item_delete($formdata);
function lti_get_coursemodule_info($coursemodule){
global $DB;
-
+
$lti = $DB->get_record('lti', array('id' => $coursemodule->instance), 'icon, secureicon');
$info = new stdClass();
-
+
//We want to use the right icon based on whether the current page is being requested over http or https.
//There's a potential problem here as the icon URLs are cached in the modinfo field and won't be updated for each request.
if(lti_request_is_using_ssl() && !empty($lti->secureicon)){
$info->icon = $lti->icon;
}
}
-
+
return $info;
}
function lti_extend_settings_navigation($settings, $parentnode) {
global $PAGE;
-
+
if(has_capability('mod/lti:grade', get_context_instance(CONTEXT_MODULE, $PAGE->cm->id))){
$keys = $parentnode->get_children_key_list();
-
+
$node = navigation_node::create('Submissions',
new moodle_url('/mod/lti/grade.php', array('id'=>$PAGE->cm->id)),
navigation_node::TYPE_SETTING, null, 'mod_lti_submissions');
} else {
$typeid = $instance->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['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(!empty($instance->resourcekey)){
$key = $instance->resourcekey;
} else if(!empty($typeconfig['resourcekey'])){
} 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($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;
$launchcontainer = lti_get_launch_container($instance, $typeconfig);
$returnurlparams = array('course' => $course->id, 'launch_container' => $launchcontainer, 'instanceid' => $instance->id);
-
+
if ( $orgid ) {
$requestparams["tool_consumer_instance_guid"] = $orgid;
}
-
+
if(empty($key) || empty($secret)){
$returnurlparams['unsigned'] = '1';
-
+
//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($typeconfig['forcessl'] == '1'){
$returnurl = lti_ensure_url_is_https($returnurl);
}
-
+
$requestparams['launch_presentation_return_url'] = $returnurl;
}
-
+
if(!empty($key) && !empty($secret)){
$parms = lti_sign_parameters($requestparams, $endpoint, "POST", $key, $secret);
} else {
//If no key and secret, do the launch unsigned.
$parms = $requestparams;
}
-
+
$debuglaunch = ( $instance->debuglaunch == 1 );
-
+
$content = lti_post_launch_html($parms, $endpoint, $debuglaunch);
-
+
echo $content;
}
function lti_build_sourcedid($instanceid, $userid, $launchid = null, $servicesalt){
$data = new stdClass();
-
+
$data->instanceid = $instanceid;
$data->userid = $userid;
if(!empty($launchid)){
if(empty($instance->cmid)){
$instance->cmid = 0;
}
-
+
$role = lti_get_ims_role($USER, $instance->cmid, $instance->course);
$locale = $course->lang;
);
$placementsecret = $instance->servicesalt;
-
+
if ( isset($placementsecret) ) {
$sourcedid = json_encode(lti_build_sourcedid($instance->id, $USER->id, null, $placementsecret));
}
( $typeconfig['acceptgrades'] == LTI_SETTING_ALWAYS ||
( $typeconfig['acceptgrades'] == LTI_SETTING_DELEGATE && $instance->instructorchoiceacceptgrades == LTI_SETTING_ALWAYS ) ) ) {
$requestparams["lis_result_sourcedid"] = $sourcedid;
-
+
$serviceurl = $CFG->wwwroot . '/mod/lti/service.php';
if($typeconfig['forcessl'] == '1'){
$serviceurl = lti_ensure_url_is_https($serviceurl);
}
-
+
$requestparams["ext_ims_lis_basic_outcome_url"] = $serviceurl;
}
//This needs to be here to support launching without javascript.
$submittext = get_string('press_to_submit', 'lti');
$requestparams["ext_submit"] = $submittext;
-
+
$requestparams["lti_version"] = "LTI-1p0";
$requestparams["lti_message_type"] = "basic-lti-launch-request";
/* Suppress this for now - Chuck
if ( $orgdesc ) $requestparams["tool_consumer_instance_description"] = $orgdesc;
*/
-
+
return $requestparams;
}
function lti_get_tool_table($tools, $id){
global $CFG, $USER;
$html = '';
-
+
$typename = get_string('typename', 'lti');
$baseurl = get_string('baseurl', 'lti');
$action = get_string('action', 'lti');
$createdon = get_string('createdon', 'lti');
-
+
if($id == 'lti_configured'){
$html .= '<div><a style="margin-top:.25em" href="'.$CFG->wwwroot.'/mod/lti/typessettings.php?action=add&sesskey='.$USER->sesskey.'">'.get_string('addtype', 'lti').'</a></div>';
}
-
+
if (!empty($tools)) {
$html .= <<<HTML
<div id="{$id}_container" style="margin-top:.5em;margin-bottom:.5em">
</tr>
</thead>
HTML;
-
+
foreach ($tools as $type) {
$date = userdate($type->timecreated);
$accept = get_string('accept', 'lti');
$update = get_string('update', 'lti');
$delete = get_string('delete', 'lti');
-
+
$accepthtml = <<<HTML
<a class="editing_accept" href="{$CFG->wwwroot}/mod/lti/typessettings.php?action=accept&id={$type->id}&sesskey={$USER->sesskey}&tab={$id}" title="{$accept}">
<img class="iconsmall" alt="{$accept}" src="{$CFG->wwwroot}/pix/t/clear.gif"/>
HTML;
$deleteaction = 'delete';
-
+
if($type->state == LTI_TOOL_STATE_CONFIGURED){
$accepthtml = '';
}
-
+
if($type->state != LTI_TOOL_STATE_REJECTED) {
$deleteaction = 'reject';
$delete = get_string('reject', 'lti');
}
-
+
$html .= <<<HTML
<tr>
<td>
} else {
$html .= get_string('no_' . $id, 'lti');
}
-
+
return $html;
}
/**
* Gets the IMS role string for the specified user and LTI course module.
- *
+ *
* @param mixed $user User object or user id
* @param int $cmid The course module id of the LTI activity
* @return string A role string suitable for passing with an LTI launch
*/
function lti_get_ims_role($user, $cmid, $courseid) {
$roles = array();
-
+
if(empty($cmid)){
//If no cmid is passed, check if the user is a teacher in the course
//This allows other modules to programmatically "fake" a launch without
//a real LTI instance
$coursecontext = get_context_instance(CONTEXT_COURSE, $courseid);
-
+
if(has_capability('moodle/course:manageactivities', $coursecontext)){
array_push($roles, 'Instructor');
} else {
if(is_siteadmin($user)){
array_push($roles, 'urn:lti:sysrole:ims/lis/Administrator');
}
-
+
return join(',', $roles);
}
SELECT name, value
FROM {lti_types_config}
WHERE typeid = :typeid1
-
+
UNION ALL
-
+
SELECT 'toolurl' AS name, baseurl AS value
FROM {lti_types}
WHERE id = :typeid2
QUERY;
-
+
$typeconfig = array();
$configs = $DB->get_records_sql($query, array('typeid1' => $typeid, 'typeid2' => $typeid));
-
+
if (!empty($configs)) {
foreach ($configs as $config) {
$typeconfig[$config->name] = $config->value;
}
}
-
+
return $typeconfig;
}
function lti_get_tools_by_url($url, $state, $courseid = null){
$domain = lti_get_domain_from_url($url);
-
+
return lti_get_tools_by_domain($domain, $state, $courseid);
}
function lti_get_tools_by_domain($domain, $state = null, $courseid = null){
global $DB, $SITE;
-
+
$filters = array('tooldomain' => $domain);
-
+
$statefilter = '';
$coursefilter = '';
-
+
if($state){
$statefilter = 'AND state = :state';
}
-
+
if($courseid && $courseid != $SITE->id){
$coursefilter = 'OR course = :courseid';
}
-
+
$query = <<<QUERY
SELECT * FROM {lti_types}
WHERE
AND (course = :siteid $coursefilter)
$statefilter
QUERY;
-
+
return $DB->get_records_sql($query, array(
- 'courseid' => $courseid,
- 'siteid' => $SITE->id,
- 'tooldomain' => $domain,
+ 'courseid' => $courseid,
+ 'siteid' => $SITE->id,
+ 'tooldomain' => $domain,
'state' => $state
));
}
} else {
$filter = array();
}
-
+
return $DB->get_records('lti_types', $filter);
}
function lti_get_types_for_add_instance(){
global $DB, $SITE, $COURSE;
-
+
$query = <<<QUERY
SELECT *
FROM {lti_types}
AND (course = :siteid OR course = :courseid)
AND state = :active
QUERY;
-
+
$admintypes = $DB->get_records_sql($query, array('siteid' => $SITE->id, 'courseid' => $COURSE->id, 'active' => LTI_TOOL_STATE_CONFIGURED));
-
+
$types = array();
$types[0] = (object)array('name' => get_string('automatic', 'lti'), 'course' => $SITE->id);
-
+
foreach($admintypes as $type) {
$types[$type->id] = $type;
}
-
+
return $types;
}
function lti_get_domain_from_url($url){
$matches = array();
-
+
if(preg_match(LTI_URL_DOMAIN_REGEX, $url, $matches)){
return $matches[1];
}
function lti_get_tool_by_url_match($url, $courseid = null, $state = LTI_TOOL_STATE_CONFIGURED){
$possibletools = lti_get_tools_by_url($url, $state, $courseid);
-
+
return lti_get_best_tool_by_url($url, $possibletools, $courseid);
}
if(!isset($urlparts['path'])){
$urlparts['path'] = '';
}
-
+
if(!isset($urlparts['host'])){
$urlparts['host'] = '';
}
-
+
if(substr($urlparts['host'], 0, 4) === 'www.'){
$urlparts['host'] = substr($urlparts['host'], 4);
}
-
+
return $urllower = $urlparts['host'] . '/' . $urlparts['path'];
}
if(count($tools) === 0){
return null;
}
-
+
$urllower = lti_get_url_thumbprint($url);
-
+
foreach($tools as $tool){
$tool->_matchscore = 0;
-
+
$toolbaseurllower = lti_get_url_thumbprint($tool->baseurl);
-
+
if($urllower === $toolbaseurllower){
//100 points for exact thumbprint match
$tool->_matchscore += 100;
//50 points if tool thumbprint starts with the base URL thumbprint
$tool->_matchscore += 50;
}
-
+
//Prefer course tools over site tools
if(!empty($courseid)){
//Minus 25 points for not matching the course id (global tools)
}
}
}
-
+
$bestmatch = array_reduce($tools, function($value, $tool){
if($tool->_matchscore > $value->_matchscore){
return $tool;
} else {
return $value;
}
-
+
}, (object)array('_matchscore' => -1));
-
+
//None of the tools are suitable for this URL
if($bestmatch->_matchscore <= 0){
return null;
}
-
+
return $bestmatch;
}
function lti_get_shared_secrets_by_key($key){
global $DB;
-
+
//Look up the shared secret for the specified key in both the types_config table (for configured tools)
//And in the lti resource table for ad-hoc tools
$query = <<<QUERY
FROM {lti_types_config} t1
INNER JOIN {lti_types_config} t2 ON t1.typeid = t2.typeid
INNER JOIN {lti_types} type ON t2.typeid = type.id
- WHERE
+ WHERE
t1.name = 'resourcekey'
AND t1.value = :key1
AND t2.name = 'password'
AND type.state = :configured
UNION
-
+
SELECT password AS value
FROM {lti}
WHERE resourcekey = :key2
QUERY;
-
+
$sharedsecrets = $DB->get_records_sql($query, array('configured' => LTI_TOOL_STATE_CONFIGURED, 'key1' => $key, 'key2' => $key));
-
+
$values = array_map(function($item){
return $item->value;
}, $sharedsecrets);
-
+
//There should really only be one shared secret per key. But, we can't prevent
//more than one getting entered. For instance, if the same key is used for two tool providers.
return $values;
function lti_set_state_for_type($id, $state){
global $DB;
-
+
$DB->update_record('lti_types', array('id' => $id, 'state' => $state));
}
$config = lti_get_type_config($id);
$type->lti_typename = $basicltitype->name;
-
+
$type->typeid = $basicltitype->id;
-
+
$type->lti_toolurl = $basicltitype->baseurl;
-
+
if (isset($config['resourcekey'])) {
$type->lti_resourcekey = $config['resourcekey'];
}
if(isset($config['forcessl'])){
$type->lti_forcessl = $config['forcessl'];
}
-
+
if (isset($config['organizationid'])) {
$type->lti_organizationid = $config['organizationid'];
}
if (isset($config['launchcontainer'])) {
$type->lti_launchcontainer = $config['launchcontainer'];
}
-
+
if (isset($config['coursevisible'])) {
$type->lti_coursevisible = $config['coursevisible'];
}
-
+
if (isset($config['debuglaunch'])) {
$type->lti_debuglaunch = $config['debuglaunch'];
}
-
+
if (isset($config['module_class_type'])) {
$type->lti_module_class_type = $config['module_class_type'];
}
$type->baseurl = $config->lti_toolurl;
$type->tooldomain = lti_get_domain_from_url($config->lti_toolurl);
$type->name = $config->lti_typename;
-
+
$type->coursevisible = !empty($config->lti_coursevisible) ? $config->lti_coursevisible : 0;
$config->lti_coursevisible = $type->coursevisible;
-
+
$type->forcessl = !empty($config->lti_forcessl) ? $config->lti_forcessl : 0;
$config->lti_forcessl = $type->forcessl;
-
+
$type->timemodified = time();
-
+
unset ($config->lti_typename);
unset ($config->lti_toolurl);
}
function lti_update_type($type, $config){
global $DB;
-
+
lti_prepare_type_for_save($type, $config);
-
+
if ($DB->update_record('lti_types', $type)) {
foreach ($config as $key => $value) {
if (substr($key, 0, 4)=='lti_' && !is_null($value)) {
$record->typeid = $type->id;
$record->name = substr($key, 4);
$record->value = $value;
-
+
lti_update_config($record);
}
}
function lti_add_type($type, $config){
global $USER, $SITE, $DB;
-
+
lti_prepare_type_for_save($type, $config);
-
+
if(!isset($type->state)){
$type->state = LTI_TOOL_STATE_PENDING;
}
-
+
if(!isset($type->timecreated)){
$type->timecreated = time();
}
-
+
if(!isset($type->createdby)){
$type->createdby = $USER->id;
}
-
+
if(!isset($type->course)){
$type->course = $SITE->id;
}
-
+
//Create a salt value to be used for signing passed data to extension services
//The outcome service uses the service salt on the instance. This can be used
//for communication with services not related to a specific LTI instance.
}
}
}
-
+
return $id;
}
$return = true;
$old = $DB->get_record('lti_types_config', array('typeid' => $config->typeid, 'name' => $config->name));
-
+
if ($old) {
$config->id = $old->id;
$return = $DB->update_record('lti_types_config', $config);
$parms = $oldparms;
$testtoken = '';
-
+
$hmacmethod = new lti\OAuthSignatureMethod_HMAC_SHA1();
$testconsumer = new lti\OAuthConsumer($oauthconsumerkey, $oauthconsumersecret, null);
*/
function lti_post_launch_html($newparms, $endpoint, $debug=false) {
//global $lastbasestring;
-
+
$r = "<form action=\"".$endpoint."\" name=\"ltiLaunchForm\" id=\"ltiLaunchForm\" method=\"post\" encType=\"application/x-www-form-urlencoded\">\n";
-
+
$submittext = $newparms['ext_submit'];
// Contruct html for the launch parameters
function lti_get_type($typeid){
global $DB;
-
+
return $DB->get_record('lti_types', array('id' => $typeid));
}
function lti_get_launch_container($lti, $toolconfig){
+ if(empty($lti->launchcontainer)){
+ $lti->launchcontainer = LTI_LAUNCH_CONTAINER_DEFAULT;
+ }
+
if($lti->launchcontainer == LTI_LAUNCH_CONTAINER_DEFAULT){
if(isset($toolconfig['launchcontainer'])){
$launchcontainer = $toolconfig['launchcontainer'];
} else {
$launchcontainer = $lti->launchcontainer;
}
-
+
if(empty($launchcontainer) || $launchcontainer == LTI_LAUNCH_CONTAINER_DEFAULT){
$launchcontainer = LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS;
}
if($devicetype === 'mobile' || $devicetype === 'tablet' ){
$launchcontainer = LTI_LAUNCH_CONTAINER_REPLACE_MOODLE_WINDOW;
}
-
+
return $launchcontainer;
}
$url = 'https://' . substr($url, 8);
}
}
-
+
return $url;
}
*/
(function(){
var Y;
-
+
M.mod_lti = M.mod_lti || {};
M.mod_lti.editor = {
if(yui3){
Y = yui3;
}
-
+
var self = this;
this.settings = Y.JSON.parse(settings);
var typeSelector = Y.one('#id_typeid');
typeSelector.on('change', function(e){
updateToolMatches();
-
+
self.toggleEditButtons();
});
this.createTypeEditorButtons();
this.toggleEditButtons();
-
+
var textAreas = new Y.NodeList([
Y.one('#id_toolurl'),
Y.one('#id_securetoolurl'),
Y.one('#id_resourcekey'),
Y.one('#id_password')
]);
-
+
var debounce;
textAreas.on('keyup', function(e){
clearTimeout(debounce);
updateToolMatches();
}, 2000);
});
-
+
updateToolMatches();
},
updateAutomaticToolMatch: function(field){
var self = this;
-
+
var toolurl = field;
var typeSelector = Y.one('#id_typeid');
-
+
var id = field.get('id') + '_lti_automatch_tool';
var automatchToolDisplay = Y.one('#' + id);
automatchToolDisplay = Y.Node.create('<span />')
.set('id', id)
.setStyle('padding-left', '1em');
-
+
toolurl.insert(automatchToolDisplay, 'after');
}
//The entered URL does not match the domain of the tool configuration
automatchToolDisplay.set('innerHTML', '<img style="vertical-align:text-bottom" src="' + self.settings.warning_icon_url + '" />' + M.str.lti.domain_mismatch);
}
-
+
return;
}
}
}
};
-
+
//Cache urls which have already been checked to increaes performance
if(self.urlCache[url]){
continuation(self.urlCache[url]);
if(globalOptions.size() > 0){
typeSelector.append(globalGroup);
}
-
+
if(courseOptions.size() > 0){
typeSelector.append(courseGroup);
}
*/
createTypeEditorButtons: function(){
var self = this;
-
+
var typeSelector = Y.one('#id_typeid');
var createIcon = function(id, tooltip, iconUrl){
- return Y.Node.create('<a />')
+ return Y.Node.create('<a />')
.set('id', id)
.set('title', tooltip)
.setStyle('margin-left', '.5em')
} else {
typeSelector.append(option);
}
-
+
//Adding the new tool may affect which tool gets matched automatically
this.clearToolCache();
this.updateAutomaticToolMatch();
var option = typeSelector.one('option[value=' + toolType.id + ']');
option.set('text', toolType.name)
.set('domain', toolType.tooldomain);
-
+
//Editing the tool may affect which tool gets matched automatically
this.clearToolCache();
this.updateAutomaticToolMatch();
deleteTool: function(toolTypeId){
var self = this;
-
+
Y.io(self.settings.instructor_tool_type_edit_url + '&action=delete&typeid=' + toolTypeId, {
on: {
success: function(){
self.getSelectedToolTypeOption().remove();
-
+
//Editing the tool may affect which tool gets matched automatically
self.clearToolCache();
self.updateAutomaticToolMatch();
findToolByUrl: function(url, callback){
var self = this;
-
- Y.io(self.settings.ajax_url, {
+
+ Y.io(self.settings.ajax_url, {
data: {action: 'find_tool_config',
course: self.settings.courseId,
toolurl: url
on: {
success: function(transactionid, xhr){
var response = xhr.response;
-
+
var toolInfo = Y.JSON.parse(response);
-
+
callback(toolInfo);
},
failure: function(){
global $DB, $PAGE, $OUTPUT, $USER, $COURSE;
$this->typeid = 0;
-
+
$mform =& $this->_form;
//-------------------------------------------------------------------------------
/// Adding the "general" fieldset, where all the common settings are shown
$mform->addElement('checkbox', 'showtitle', ' ', ' ' . get_string('display_name', 'lti'));
$mform->setAdvanced('showtitle');
$mform->addHelpButton('showtitle', 'display_name', 'lti');
-
+
$mform->addElement('checkbox', 'showdescription', ' ', ' ' . get_string('display_description', 'lti'));
$mform->setAdvanced('showdescription');
$mform->addHelpButton('showdescription', 'display_description', 'lti');
-
+
//Tool settings
$tooltypes = $mform->addElement('select', 'typeid', get_string('external_tool_type', 'lti'), array());
$mform->addHelpButton('typeid', 'external_tool_type', 'lti');
-
+
foreach(lti_get_types_for_add_instance() as $id => $type){
if($type->course == $COURSE->id) {
$attributes = array( 'editable' => 1, 'courseTool' => 1, 'domain' => $type->tooldomain );
} else {
$attributes = array();
}
-
+
$tooltypes->addOption($type->name, $id, $attributes);
}
-
+
$mform->addElement('text', 'toolurl', get_string('launch_url', 'lti'), array('size'=>'64'));
$mform->setType('toolurl', PARAM_TEXT);
$mform->addHelpButton('toolurl', 'launch_url', 'lti');
-
+
$mform->addElement('text', 'securetoolurl', get_string('secure_launch_url', 'lti'), array('size'=>'64'));
$mform->setType('securetoolurl', PARAM_TEXT);
$mform->setAdvanced('securetoolurl');
$mform->addHelpButton('securetoolurl', 'secure_launch_url', 'lti');
-
+
$launchoptions=array();
$launchoptions[LTI_LAUNCH_CONTAINER_DEFAULT] = get_string('default', 'lti');
$launchoptions[LTI_LAUNCH_CONTAINER_EMBED] = get_string('embed', 'lti');
$mform->addElement('select', 'launchcontainer', get_string('launchinpopup', 'lti'), $launchoptions);
$mform->setDefault('launchcontainer', LTI_LAUNCH_CONTAINER_DEFAULT);
$mform->addHelpButton('launchcontainer', 'launchinpopup', 'lti');
-
+
$mform->addElement('text', 'resourcekey', get_string('resourcekey', 'lti'));
$mform->setType('resourcekey', PARAM_TEXT);
$mform->setAdvanced('resourcekey');
$mform->addHelpButton('resourcekey', 'resourcekey', 'lti');
-
+
$mform->addElement('passwordunmask', 'password', get_string('password', 'lti'));
$mform->setType('password', PARAM_TEXT);
$mform->setAdvanced('password');
$mform->addHelpButton('password', 'password', 'lti');
-
+
$mform->addElement('textarea', 'instructorcustomparameters', get_string('custom', 'lti'), array('rows'=>4, 'cols'=>60));
$mform->setType('instructorcustomparameters', PARAM_TEXT);
$mform->setAdvanced('instructorcustomparameters');
$mform->addHelpButton('instructorcustomparameters', 'custom', 'lti');
-
+
$mform->addElement('text', 'icon', get_string('icon_url', 'lti'), array('size'=>'64'));
$mform->setType('icon', PARAM_TEXT);
$mform->setAdvanced('icon');
$mform->addHelpButton('icon', 'icon_url', 'lti');
-
+
$mform->addElement('text', 'secureicon', get_string('secure_icon_url', 'lti'), array('size'=>'64'));
$mform->setType('secureicon', PARAM_TEXT);
$mform->setAdvanced('secureicon');
$mform->addHelpButton('secureicon', 'secure_icon_url', 'lti');
-
+
//-------------------------------------------------------------------------------
// Add privacy preferences fieldset where users choose whether to send their data
$mform->addElement('header', 'privacy', get_string('privacy', 'lti'));
$mform->addElement('checkbox', 'instructorchoicesendname', ' ', ' ' . get_string('share_name', 'lti'));
$mform->setDefault('instructorchoicesendname', '1');
$mform->addHelpButton('instructorchoicesendname', 'share_name', 'lti');
-
+
$mform->addElement('checkbox', 'instructorchoicesendemailaddr', ' ', ' ' . get_string('share_email', 'lti'));
$mform->setDefault('instructorchoicesendemailaddr', '1');
$mform->addHelpButton('instructorchoicesendemailaddr', 'share_email', 'lti');
-
+
$mform->addElement('checkbox', 'instructorchoiceacceptgrades', ' ', ' ' . get_string('accept_grades', 'lti'));
$mform->setDefault('instructorchoiceacceptgrades', '1');
$mform->addHelpButton('instructorchoiceacceptgrades', 'accept_grades', 'lti');
-
+
$mform->addElement('checkbox', 'instructorchoiceallowroster', ' ', ' ' . get_string('share_roster', 'lti'));
$mform->setDefault('instructorchoiceallowroster', '1');
$mform->addHelpButton('instructorchoiceallowroster', 'share_roster', 'lti');
-
+
//-------------------------------------------------------------------------------
/* $debugoptions=array();
//-------------------------------------------------------------------------------
// add standard elements, common to all modules
$this->standard_coursemodule_elements();
-
$mform->setAdvanced('cmidnumber');
//-------------------------------------------------------------------------------
// add standard buttons, common to all modules
$editurl = new moodle_url("/mod/lti/instructor_edit_tool_type.php?sesskey={$USER->sesskey}&course={$COURSE->id}");
$ajaxurl = new moodle_url('/mod/lti/ajax.php');
-
+
$jsinfo = (object)array(
'edit_icon_url' => (string)$OUTPUT->pix_url('t/edit'),
'add_icon_url' => (string)$OUTPUT->pix_url('t/add'),
'ajax_url' => $ajaxurl->out(true),
'courseId' => $COURSE->id
);
-
+
$module = array(
'name' => 'mod_lti_edit',
'fullpath' => '/mod/lti/mod_form.js',
array('tool_config_not_found', 'lti')
),
);
-
+
$PAGE->requires->js_init_call('M.mod_lti.editor.init', array(json_encode($jsinfo)), true, $module);
}
*/
function definition_after_data() {
parent::definition_after_data();
-
+
//$mform =& $this->_form;
}
$tooltype = new stdClass();
$toolconfig = new stdClass();
- $toolconfig->lti_toolurl = lti_get_domain_from_url($lti->toolurl);
+ $toolconfig->lti_toolurl = lti_get_domain_from_url($lti->toolurl);
$toolconfig->lti_typename = $toolconfig->lti_toolurl;
lti_add_type($tooltype, $toolconfig);
-
+
echo get_string('lti_tool_request_added', 'lti');
} else {
echo get_string('lti_tool_request_existing', 'lti');
if(!empty($errormsg)){
$url = new moodle_url('/mod/lti/return.php', array('course' => $courseid));
$PAGE->set_url($url);
-
+
$pagetitle = strip_tags($course->shortname);
$PAGE->set_title($pagetitle);
$PAGE->set_heading($course->fullname);
-
+
//Avoid frame-in-frame action
if($launchcontainer == LTI_LAUNCH_CONTAINER_EMBED || $launchcontainer == LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS) {
$PAGE->set_pagelayout('embedded');
} else {
$PAGE->set_pagelayout('incourse');
}
-
+
echo $OUTPUT->header();
-
+
echo get_string('lti_launch_error', 'lti');
-
+
echo htmlspecialchars($errormsg);
$canaddtools = has_capability('mod/lti:addcoursetool', get_context_instance(CONTEXT_COURSE, $courseid));
-
+
if($unsigned == 1 && $canaddtools){
echo '<br /><br />';
-
+
$links = new stdClass();
$coursetooleditor = new moodle_url('/mod/lti/instructor_edit_tool_type.php', array('course' => $courseid, 'action' => 'add'));
$links->course_tool_editor = $coursetooleditor->out(false);
-
+
$adminrequesturl = new moodle_url('/mod/lti/request_tool.php', array('instanceid' => $instanceid));
$links->admin_request_url = $adminrequesturl->out(false);
-
+
echo get_string('lti_launch_error_unsigned_help', 'lti', $links);
-
+
echo get_string('lti_launch_error_tool_request', 'lti', $links);
}
-
+
echo $OUTPUT->footer();
} else {
$courseurl = new moodle_url('/course/view.php', array('id' => $courseid));
$url = $courseurl->out();
-
+
//Avoid frame-in-frame action
if($launchcontainer == LTI_LAUNCH_CONTAINER_EMBED || $launchcontainer == LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS) {
//Output a page containing some script to break out of frames and redirect them
-
+
echo '<html><body>';
-
+
$script = <<<SCRIPT
<script type='text/javascript'>
//<![CDATA[
//]]
</script>
SCRIPT;
-
+
$clickhere = get_string('return_to_course', 'lti', (object)array('link' => $url));
$noscript = <<<NOSCRIPT
{$clickhere}
</noscript>
NOSCRIPT;
-
+
echo $script;
echo $noscript;
-
+
echo '</body></html>';
} else {
//If no error, take them back to the course
foreach(getallheaders() as $name => $value){
if($name === 'Authorization'){
$oauthparams = lti\OAuthUtil::split_header($value);
-
+
$consumerkey = $oauthparams['oauth_consumer_key'];
break;
}
switch($messagetype){
case 'replaceResultRequest':
$parsed = lti_parse_grade_replace_message($xml);
-
+
$ltiinstance = $DB->get_record('lti', array('id' => $parsed->instanceid));
-
+
lti_verify_sourcedid($ltiinstance, $parsed);
-
+
$gradestatus = lti_update_grade($ltiinstance, $parsed->userid, $parsed->launchid, $parsed->gradeval);
-
+
$responsexml = lti_get_response_xml(
- $gradestatus ? 'success' : 'error',
+ $gradestatus ? 'success' : 'error',
'Grade replace response',
$parsed->messageid,
'replaceResultResponse'
);
-
+
echo $responsexml->asXML();
-
+
break;
-
+
case 'readResultRequest':
$parsed = lti_parse_grade_read_message($xml);
-
+
$ltiinstance = $DB->get_record('lti', array('id' => $parsed->instanceid));
-
+
//Getting the grade requires the context is set
$context = get_context_instance(CONTEXT_COURSE, $ltiinstance->course);
$PAGE->set_context($context);
-
+
lti_verify_sourcedid($ltiinstance, $parsed);
-
+
$grade = lti_read_grade($ltiinstance, $parsed->userid);
-
+
$responsexml = lti_get_response_xml(
isset($grade) ? 'success' : 'error',
'Result read',
$parsed->messageid,
'readResultResponse'
);
-
+
$node = $responsexml->imsx_POXBody->readResultResponse;
$node->addChild('result')
->addChild('resultScore')
->addChild('textString', isset($grade) ? $grade : '');
-
+
echo $responsexml->asXML();
-
+
break;
-
+
case 'deleteResultRequest':
$parsed = lti_parse_grade_delete_message($xml);
-
+
$ltiinstance = $DB->get_record('lti', array('id' => $parsed->instanceid));
-
+
lti_verify_sourcedid($ltiinstance, $parsed);
-
+
$gradestatus = lti_delete_grade($ltiinstance, $parsed->userid);
-
+
$responsexml = lti_get_response_xml(
- $gradestatus ? 'success' : 'error',
- 'Grade delete request',
- $parsed->messageid,
+ $gradestatus ? 'success' : 'error',
+ 'Grade delete request',
+ $parsed->messageid,
'deleteResultResponse'
);
-
+
echo $responsexml->asXML();
-
+
break;
-
+
default:
//Fire an event if we get a web service request which we don't support directly.
//This will allow others to extend the LTI services, which I expect to be a common
$data->messagetype = $messagetype;
$data->consumerkey = $consumerkey;
$data->sharedsecret = $sharedsecret;
-
+
//If an event handler handles the web service, it should set this global to true
//So this code knows whether to send an "operation not supported" or not.
global $lti_web_service_handled;
$lti_web_service_handled = false;
-
+
events_trigger('lti_unknown_service_api_call', $data);
-
+
if(!$lti_web_service_handled){
$responsexml = lti_get_response_xml(
- 'unsupported',
- 'unsupported',
+ 'unsupported',
+ 'unsupported',
lti_parse_message_id($xml),
$messagetype
);
echo $responsexml->asXML();
}
-
+
break;
}
function lti_get_response_xml($codemajor, $description, $messageref, $messagetype){
$xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><imsx_POXEnvelopeResponse />');
$xml->addAttribute('xmlns', 'http://www.imsglobal.org/lis/oms1p0/pox');
-
+
$headerinfo = $xml->addChild('imsx_POXHeader')
->addChild('imsx_POXResponseHeaderInfo');
-
+
$headerinfo->addChild('imsx_version', 'V1.0');
$headerinfo->addChild('imsx_messageIdentifier', (string)mt_rand());
-
+
$statusinfo = $headerinfo->addChild('imsx_statusInfo');
$statusinfo->addchild('imsx_codeMajor', $codemajor);
$statusinfo->addChild('imsx_severity', 'status');
$statusinfo->addChild('imsx_description', $description);
$statusinfo->addChild('imsx_messageRefIdentifier', $messageref);
-
+
$xml->addChild('imsx_POXBody')
->addChild($messagetype);
-
+
return $xml;
}
function lti_parse_message_id($xml){
$node = $xml->imsx_POXHeader->imsx_POXRequestHeaderInfo->imsx_messageIdentifier;
$messageid = (string)$node;
-
+
return $messageid;
}
function lti_parse_grade_replace_message($xml){
$node = $xml->imsx_POXBody->replaceResultRequest->resultRecord->sourcedGUID->sourcedId;
$resultjson = json_decode((string)$node);
-
+
$node = $xml->imsx_POXBody->replaceResultRequest->resultRecord->result->resultScore->textString;
$grade = floatval((string)$node);
-
+
$parsed = new stdClass();
$parsed->gradeval = $grade * 100;
-
+
$parsed->instanceid = $resultjson->data->instanceid;
$parsed->userid = $resultjson->data->userid;
$parsed->launchid = $resultjson->data->launchid;
$parsed->sourcedidhash = $resultjson->hash;
-
+
$parsed->messageid = lti_parse_message_id($xml);
-
+
return $parsed;
}
function lti_parse_grade_read_message($xml){
$node = $xml->imsx_POXBody->readResultRequest->resultRecord->sourcedGUID->sourcedId;
$resultjson = json_decode((string)$node);
-
+
$parsed = new stdClass();
$parsed->instanceid = $resultjson->data->instanceid;
$parsed->userid = $resultjson->data->userid;
$parsed->launchid = $resultjson->data->launchid;
$parsed->sourcedidhash = $resultjson->hash;
-
+
$parsed->messageid = lti_parse_message_id($xml);
-
+
return $parsed;
}
function lti_parse_grade_delete_message($xml){
$node = $xml->imsx_POXBody->deleteResultRequest->resultRecord->sourcedGUID->sourcedId;
$resultjson = json_decode((string)$node);
-
+
$parsed = new stdClass();
$parsed->instanceid = $resultjson->data->instanceid;
$parsed->userid = $resultjson->data->userid;
$parsed->launchid = $resultjson->data->launchid;
$parsed->sourcedidhash = $resultjson->hash;
-
+
$parsed->messageid = lti_parse_message_id($xml);
-
+
return $parsed;
}
function lti_update_grade($ltiinstance, $userid, $launchid, $gradeval){
global $CFG, $DB;
require_once($CFG->libdir . '/gradelib.php');
-
+
$params = array();
$params['itemname'] = $ltiinstance->name;
$grade->userid = $userid;
$grade->rawgrade = $gradeval;
- $status = grade_update(LTI_SOURCE, $ltiinstance->course, LTI_ITEM_TYPE, LTI_ITEM_MODULE, $ltiinstance->id, 0, $grade, $params);
+ $status = grade_update(LTI_SOURCE, $ltiinstance->course, LTI_ITEM_TYPE, LTI_ITEM_MODULE, $ltiinstance->id, 0, $grade, $params);
$record = $DB->get_record('lti_submission', array('ltiid' => $ltiinstance->id, 'userid' => $userid, 'launchid' => $launchid), 'id');
if($record){
} else {
$id = null;
}
-
+
if(!empty($id)){
$DB->update_record('lti_submission', array(
'id' => $id,
} else {
$DB->insert_record('lti_submission', array(
'ltiid' => $ltiinstance->id,
- 'userid' => $userid,
- 'datesubmitted' => time(),
+ 'userid' => $userid,
+ 'datesubmitted' => time(),
'dateupdated' => time(),
'gradepercent' => $gradeval,
'originalgrade' => $gradeval,
'state' => 1
));
}
-
+
return $status == GRADE_UPDATE_OK;
}
function lti_read_grade($ltiinstance, $userid){
global $CFG;
require_once($CFG->libdir . '/gradelib.php');
-
+
$grades = grade_get_grades($ltiinstance->course, LTI_ITEM_TYPE, LTI_ITEM_MODULE, $ltiinstance->id, $userid);
-
+
if (isset($grades) && isset($grades->items[0]) && is_array($grades->items[0]->grades)) {
foreach ($grades->items[0]->grades as $agrade) {
$grade = $agrade->grade;
break;
}
}
-
+
if(isset($grade)){
return $grade;
}
function lti_delete_grade($ltiinstance, $userid){
global $CFG;
require_once($CFG->libdir . '/gradelib.php');
-
+
$grade = new stdClass();
$grade->userid = $userid;
$grade->rawgrade = null;
$status = grade_update(LTI_SOURCE, $ltiinstance->course, LTI_ITEM_TYPE, LTI_ITEM_MODULE, $ltiinstance->id, 0, $grade, array('deleted'=>1));
-
+
return $status == GRADE_UPDATE_OK || $status == GRADE_UPDATE_ITEM_DELETED; //grade_update seems to return ok now, but could reasonably return deleted in the future
}
function lti_verify_message($key, $sharedsecrets, $body, $headers = null){
foreach($sharedsecrets as $secret){
$signaturefailed = false;
-
+
try{
lti\handleOAuthBodyPOST($key, $secret, $body, $headers);
}
catch(Exception $e){
$signaturefailed = true;
}
-
+
if(!$signaturefailed){
return $secret;//Return the secret used to sign the message)
}
}
-
+
return false;
}
function lti_verify_sourcedid($ltiinstance, $parsed){
$sourceid = lti_build_sourcedid($parsed->instanceid, $parsed->userid, $parsed->launchid, $ltiinstance->servicesalt);
-
+
if($sourceid->hash != $parsed->sourcedidhash){
throw new Exception('SourcedId hash not valid');
}
$baseurl = get_string('baseurl', 'lti');
$action = get_string('action', 'lti');
$createdon = get_string('createdon', 'lti');
-
+
$types = lti_filter_get_types($SITE->id);
-
+
$configuredtools = array_filter($types, function($value){
return $value->state == LTI_TOOL_STATE_CONFIGURED;
});
-
+
$configuredtoolshtml = lti_get_tool_table($configuredtools, 'lti_configured');
$pendingtools = array_filter($types, function($value){
return $value->state == LTI_TOOL_STATE_PENDING;
});
-
+
$pendingtoolshtml = lti_get_tool_table($pendingtools, 'lti_pending');
-
+
$rejectedtools = array_filter($types, function($value){
return $value->state == LTI_TOOL_STATE_REJECTED;
});
-
+
$rejectedtoolshtml = lti_get_tool_table($rejectedtools, 'lti_rejected');
-
+
$tab = optional_param('tab', '', PARAM_ALPHAEXT);
$activeselected = '';
$pendingselected = '';
$activeselected = 'class="selected"';
break;
}
-
+
$template = <<<HTML
<div id="lti_tabs" class="yui-navset">
<ul id="lti_tab_heading" class="yui-nav" style="display:none">
lti_tab_heading.style.display = '';
new YAHOO.widget.TabView('lti_tabs');
-
+
var setupTools = function(id, sort){
var lti_tools = YAHOO.util.Dom.get(id + "_tools");
-
+
if(lti_tools){
var dataSource = new YAHOO.util.DataSource(lti_tools);
-
+
var configuredColumns = [
{key:"name", label:"$typename", sortable:true},
{key:"baseURL", label:"$baseurl", sortable:true},
//]]
</script>
HTML;
-
+
$PAGE->requires->yui2_lib('tabview');
$PAGE->requires->yui2_lib('datatable');
-
+
$settings->add(new admin_setting_heading('lti_types', get_string('external_tool_types', 'lti') . $OUTPUT->help_icon('main_admin', 'lti'), $template));
}
class lti_locallib_test extends UnitTestCase {
public static $includecoverage = array('mod/lti/locallib.php');
-
+
function test_split_custom_parameters() {
$this->assertEqual(lti_split_custom_parameters("x=1\ny=2"),
array('custom_x' => '1', 'custom_y'=> '2'));
-
+
$this->assertEqual(lti_split_custom_parameters('x=1;y=2'),
array('custom_x' => '1', 'custom_y'=> '2'));
-
+
$this->assertEqual(lti_split_custom_parameters('Review:Chapter=1.2.56'),
array('custom_review_chapter' => '1.2.56'));
-
+
$this->assertEqual(lti_split_custom_parameters('Complex!@#$^*(){}[]KEY=Complex!@#$^*(){}[]Value'),
array('custom_complex____________key' => 'Complex!@#$^*(){}[]Value'));
}
</imsx_POXBody>
</imsx_POXEnvelopeRequest>
XML;
-
+
$parsed = lti_parse_grade_replace_message(new SimpleXMLElement($message));
-
+
$this->assertEqual($parsed->userid, '2');
$this->assertEqual($parsed->instanceid, '2');
$this->assertEqual($parsed->sourcedidhash, '0b5078feab59b9938c333ceaae21d8e003a7b295e43cdf55338445254421076b');
-
+
$ltiinstance = (object)array('servicesalt' => '4e5fcc06de1d58.44963230');
-
+
lti_verify_sourcedid($ltiinstance, $parsed);
}
}
*/
(function(){
var Y;
-
+
M.mod_lti = M.mod_lti || {};
-
+
M.mod_lti.submissions = {
init: function(yui3){
if(yui3){
Y = yui3;
}
-
+
this.setupTable();
-
-
+
+
},
-
+
setupTable: function(){
var lti_submissions_table = YAHOO.util.Dom.get('lti_submissions_table');
-
+
var dataSource = new YAHOO.util.DataSource(lti_submissions_table);
var configuredColumns = [
{ key: "user", label: "User", sortable:true },
{ key: "date", label: "Submission Date", sortable:true, formatter: 'date' },
- { key: "grade",
- label: "Grade",
- sortable:true,
+ { key: "grade",
+ label: "Grade",
+ sortable:true,
formatter: function(cell, record, column, data){
cell.innerHTML = parseFloat(data).toFixed(1) + '%';
- }
+ }
}
];
sortedBy: {key:"date", dir:"desc"}
}
);
-
+
Y.one('#lti_submissions_table_container').setStyle('display', '');
}
}
if (confirm_sesskey() && isset($data->submitbutton)) {
$type = new stdClass();
-
+
if (isset($id)) {
$type->id = $id;
lti_update_type($type, $data);
-
+
redirect($redirect);
die;
} else {
$type->state = LTI_TOOL_STATE_CONFIGURED;
-
+
lti_add_type($type, $data);
-
+
redirect($redirect);
die;
}
} else {
// Request the launch content with an object tag
echo '<object id="contentframe" height="600px" width="100%" type="text/html" data="launch.php?id='.$cm->id.'"></object>';
-
+
//Output script to make the object tag be as large as possible
$resize = <<<'SCRIPT'
<script type='text/javascript'>
var dom = YAHOO.util.Dom;
var frame = document.getElementById('contentframe');
-
+
var padding = 15; //The bottom of the iframe wasn't visible on some themes. Probably because of border widths, etc.
var lastHeight;
var viewportHeight = dom.getViewportHeight();
if(lastHeight !== Math.min(dom.getDocumentHeight(), viewportHeight)){
-
+
frame.style.height = viewportHeight - dom.getY(frame) - padding + 'px';
lastHeight = Math.min(dom.getDocumentHeight(), dom.getViewportHeight());
//]]
</script>
SCRIPT;
-
+
echo $resize;
}