Merge branch 'MDL-62815_mod_lti' of git://github.com/davosmith/moodle

This commit is contained in:
Adrian Greeve 2020-01-20 09:53:27 +08:00
commit d29c986d9d
7 changed files with 225 additions and 127 deletions

View File

@ -91,6 +91,28 @@ $capabilities = array(
)
),
// The ability to a preconfigured instance to the course.
'mod/lti:addpreconfiguredinstance' => array(
'captype' => 'write',
'contextlevel' => CONTEXT_COURSE,
'archetypes' => array(
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
),
'clonepermissionsfrom' => 'mod/lti:addinstance',
),
// The ability to add a manual instance (i.e. not from a preconfigured tool) to the course.
'mod/lti:addmanualinstance' => array(
'captype' => 'write',
'contextlevel' => CONTEXT_COURSE,
'archetypes' => array(
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
),
'clonepermissionsfrom' => 'mod/lti:addinstance',
),
// The ability to request the administrator to configure a particular
// External tool globally.
'mod/lti:requesttooladd' => array(

View File

@ -210,7 +210,7 @@ In addition, all web service requests from the tool provider will use SSL.
If using this option, confirm that this Moodle site and the tool provider support SSL.';
$string['generaltool'] = 'General tool';
$string['global_tool_types'] = 'Global preconfigured tools';
$string['global_tool_types'] = 'Preconfigured tools';
$string['grading'] = 'Grade routing';
$string['icon_url'] = 'Icon URL';
$string['icon_url_help'] = 'The icon URL allows the icon that shows up in the course listing for this activity to be modified. Instead of using the default
@ -254,8 +254,10 @@ real estate to the tool, and others provide a more integrated feel with the Mood
$string['launchoptions'] = 'Launch options';
$string['leaveblank'] = 'Leave blank if you do not need them';
$string['lti'] = 'LTI';
$string['lti:addinstance'] = 'Add a new external tool';
$string['lti:addcoursetool'] = 'Add course-specific tool configurations';
$string['lti:addmanualinstance'] = 'Add a manually-configured tool';
$string['lti:addinstance'] = 'Add a new external tool';
$string['lti:addpreconfiguredinstance'] = 'Add a preconfigured tool';
$string['lti:grade'] = 'View grades returned by the external tool';
$string['lti:manage'] = 'Be an Instructor when the tool is launched';
$string['lti:admin'] = 'Be an administrator when the tool is launched';

View File

@ -219,7 +219,9 @@ function lti_get_shortcuts($defaultitem) {
require_once($CFG->dirroot.'/mod/lti/locallib.php');
$types = lti_get_configured_types($COURSE->id, $defaultitem->link->param('sr'));
$types[] = $defaultitem;
if (has_capability('mod/lti:addmanualinstance', context_course::instance($COURSE->id))) {
$types[] = $defaultitem;
}
// Add items defined in ltisource plugins.
foreach (core_component::get_plugin_list('ltisource') as $pluginname => $dir) {

View File

@ -2129,10 +2129,21 @@ function lti_get_lti_types_by_course($courseid, $coursevisible = null) {
}
list($coursevisiblesql, $coursevisparams) = $DB->get_in_or_equal($coursevisible, SQL_PARAMS_NAMED, 'coursevisible');
$courseconds = [];
if (has_capability('mod/lti:addmanualinstance', context_course::instance($courseid))) {
$courseconds[] = "course = :courseid";
}
if (has_capability('mod/lti:addpreconfiguredinstance', context_course::instance($courseid))) {
$courseconds[] = "course = :siteid";
}
if (!$courseconds) {
return [];
}
$coursecond = implode(" OR ", $courseconds);
$query = "SELECT *
FROM {lti_types}
WHERE coursevisible $coursevisiblesql
AND (course = :siteid OR course = :courseid)
AND ($coursecond)
AND state = :active";
return $DB->get_records_sql($query,
@ -2149,7 +2160,9 @@ function lti_get_types_for_add_instance() {
$admintypes = lti_get_lti_types_by_course($COURSE->id);
$types = array();
$types[0] = (object)array('name' => get_string('automatic', 'lti'), 'course' => 0, 'toolproxyid' => null);
if (has_capability('mod/lti:addmanualinstance', context_course::instance($COURSE->id))) {
$types[0] = (object)array('name' => get_string('automatic', 'lti'), 'course' => 0, 'toolproxyid' => null);
}
foreach ($admintypes as $type) {
$types[$type->id] = $type;

View File

@ -42,64 +42,68 @@
this.urlCache = {};
this.toolTypeCache = {};
this.addOptGroups();
var updateToolMatches = function(){
self.updateAutomaticToolMatch(Y.one('#id_toolurl'));
self.updateAutomaticToolMatch(Y.one('#id_securetoolurl'));
};
var typeSelector = Y.one('#id_typeid');
typeSelector.on('change', function(e){
// Reset configuration fields when another preconfigured tool is selected.
self.resetToolFields();
if (typeSelector) {
this.addOptGroups();
updateToolMatches();
typeSelector.on('change', function(e){
// Reset configuration fields when another preconfigured tool is selected.
self.resetToolFields();
self.toggleEditButtons();
updateToolMatches();
if (self.getSelectedToolTypeOption().getAttribute('toolproxy')){
var allowname = Y.one('#id_instructorchoicesendname');
allowname.set('checked', !self.getSelectedToolTypeOption().getAttribute('noname'));
self.toggleEditButtons();
var allowemail = Y.one('#id_instructorchoicesendemailaddr');
allowemail.set('checked', !self.getSelectedToolTypeOption().getAttribute('noemail'));
if (self.getSelectedToolTypeOption().getAttribute('toolproxy')){
var allowname = Y.one('#id_instructorchoicesendname');
allowname.set('checked', !self.getSelectedToolTypeOption().getAttribute('noname'));
var allowgrades = Y.one('#id_instructorchoiceacceptgrades');
allowgrades.set('checked', !self.getSelectedToolTypeOption().getAttribute('nogrades'));
self.toggleGradeSection();
}
});
var allowemail = Y.one('#id_instructorchoicesendemailaddr');
allowemail.set('checked', !self.getSelectedToolTypeOption().getAttribute('noemail'));
var allowgrades = Y.one('#id_instructorchoiceacceptgrades');
allowgrades.set('checked', !self.getSelectedToolTypeOption().getAttribute('nogrades'));
self.toggleGradeSection();
}
});
this.createTypeEditorButtons();
this.toggleEditButtons();
}
var contentItemButton = Y.one('[name="selectcontent"]');
var contentItemUrl = contentItemButton.getAttribute('data-contentitemurl');
// Handle configure from link button click.
contentItemButton.on('click', function() {
var contentItemId = self.getContentItemId();
if (contentItemId) {
// Get activity name and description values.
var title = Y.one('#id_name').get('value').trim();
var text = Y.one('#id_introeditor').get('value').trim();
if (contentItemButton) {
var contentItemUrl = contentItemButton.getAttribute('data-contentitemurl');
// Handle configure from link button click.
contentItemButton.on('click', function() {
var contentItemId = self.getContentItemId();
if (contentItemId) {
// Get activity name and description values.
var title = Y.one('#id_name').get('value').trim();
var text = Y.one('#id_introeditor').get('value').trim();
// Set data to be POSTed.
var postData = {
id: contentItemId,
course: self.settings.courseId,
title: title,
text: text
};
// Set data to be POSTed.
var postData = {
id: contentItemId,
course: self.settings.courseId,
title: title,
text: text
};
require(['mod_lti/contentitem'], function(contentitem) {
contentitem.init(contentItemUrl, postData, function() {
M.mod_lti.editor.toggleGradeSection();
require(['mod_lti/contentitem'], function(contentitem) {
contentitem.init(contentItemUrl, postData, function() {
M.mod_lti.editor.toggleGradeSection();
});
});
});
}
});
this.createTypeEditorButtons();
this.toggleEditButtons();
}
});
}
var textAreas = new Y.NodeList([
Y.one('#id_toolurl'),
@ -121,7 +125,9 @@
var allowgrades = Y.one('#id_instructorchoiceacceptgrades');
allowgrades.on('change', this.toggleGradeSection, this);
updateToolMatches();
if (typeSelector) {
updateToolMatches();
}
},
toggleGradeSection: function(e) {
@ -143,6 +149,10 @@
},
updateAutomaticToolMatch: function(field){
if (!field) {
return;
}
var self = this;
var toolurl = field;
@ -528,11 +538,20 @@
* @returns {number|boolean} The ID of the tool type if it supports Content-Item selection. False, otherwise.
*/
getContentItemId: function() {
var selected = this.getSelectedToolTypeOption();
if (selected.getAttribute('data-contentitem')) {
return selected.getAttribute('data-id');
try {
var selected = this.getSelectedToolTypeOption();
if (selected.getAttribute('data-contentitem')) {
return selected.getAttribute('data-id');
}
return false;
} catch (err) {
// Tool selector not available - check for hidden fields instead.
var content = Y.one('input[name="contentitem"]');
if (!content || !content.get('value')) {
return false;
}
return Y.one('input[name="typeid"]').get('value');
}
return false;
},
/**

View File

@ -60,6 +60,23 @@ class mod_lti_mod_form extends moodleform_mod {
component_callback("ltisource_$type", 'add_instance_hook');
}
// Type ID parameter being passed when adding an preconfigured tool from activity chooser.
$typeid = optional_param('typeid', false, PARAM_INT);
// Show configuration details only if not preset (when new) or user has the capabilities to do so (when editing).
if ($this->_instance) {
$showtypes = has_capability('mod/lti:addpreconfiguredinstance', $this->context);
$showoptions = has_capability('mod/lti:addmanualinstance', $this->context);
if (!$showoptions && $this->current->typeid == 0) {
// If you cannot add a manual instance and this is already a manual instance, then
// remove the 'types' selector.
$showtypes = false;
}
} else {
$showtypes = !$typeid;
$showoptions = !$typeid && has_capability('mod/lti:addmanualinstance', $this->context);
}
$this->typeid = 0;
$mform =& $this->_form;
@ -95,51 +112,63 @@ class mod_lti_mod_form extends moodleform_mod {
$mform->addHelpButton('showdescriptionlaunch', 'display_description', 'lti');
// Tool settings.
$tooltypes = $mform->addElement('select', 'typeid', get_string('external_tool_type', 'lti'));
// Type ID parameter being passed when adding an preconfigured tool from activity chooser.
$typeid = optional_param('typeid', false, PARAM_INT);
if ($typeid) {
$mform->getElement('typeid')->setValue($typeid);
}
$mform->addHelpButton('typeid', 'external_tool_type', 'lti');
$toolproxy = array();
// Array of tool type IDs that don't support ContentItemSelectionRequest.
$noncontentitemtypes = [];
foreach (lti_get_types_for_add_instance() as $id => $type) {
if (!empty($type->toolproxyid)) {
$toolproxy[] = $type->id;
$attributes = array( 'globalTool' => 1, 'toolproxy' => 1);
$enabledcapabilities = explode("\n", $type->enabledcapability);
if (!in_array('Result.autocreate', $enabledcapabilities) || in_array('BasicOutcome.url', $enabledcapabilities)) {
$attributes['nogrades'] = 1;
}
if (!in_array('Person.name.full', $enabledcapabilities) && !in_array('Person.name.family', $enabledcapabilities) &&
!in_array('Person.name.given', $enabledcapabilities)) {
$attributes['noname'] = 1;
}
if (!in_array('Person.email.primary', $enabledcapabilities)) {
$attributes['noemail'] = 1;
}
} else if ($type->course == $COURSE->id) {
$attributes = array( 'editable' => 1, 'courseTool' => 1, 'domain' => $type->tooldomain );
} else if ($id != 0) {
$attributes = array( 'globalTool' => 1, 'domain' => $type->tooldomain);
} else {
$attributes = array();
if ($showtypes) {
$tooltypes = $mform->addElement('select', 'typeid', get_string('external_tool_type', 'lti'));
if ($typeid) {
$mform->getElement('typeid')->setValue($typeid);
}
$mform->addHelpButton('typeid', 'external_tool_type', 'lti');
if ($id) {
$config = lti_get_type_config($id);
if (!empty($config['contentitem'])) {
$attributes['data-contentitem'] = 1;
$attributes['data-id'] = $id;
foreach (lti_get_types_for_add_instance() as $id => $type) {
if (!empty($type->toolproxyid)) {
$toolproxy[] = $type->id;
$attributes = array('globalTool' => 1, 'toolproxy' => 1);
$enabledcapabilities = explode("\n", $type->enabledcapability);
if (!in_array('Result.autocreate', $enabledcapabilities) ||
in_array('BasicOutcome.url', $enabledcapabilities)) {
$attributes['nogrades'] = 1;
}
if (!in_array('Person.name.full', $enabledcapabilities) &&
!in_array('Person.name.family', $enabledcapabilities) &&
!in_array('Person.name.given', $enabledcapabilities)) {
$attributes['noname'] = 1;
}
if (!in_array('Person.email.primary', $enabledcapabilities)) {
$attributes['noemail'] = 1;
}
} else if ($type->course == $COURSE->id) {
$attributes = array('editable' => 1, 'courseTool' => 1, 'domain' => $type->tooldomain);
} else if ($id != 0) {
$attributes = array('globalTool' => 1, 'domain' => $type->tooldomain);
} else {
$noncontentitemtypes[] = $id;
$attributes = array();
}
if ($id) {
$config = lti_get_type_config($id);
if (!empty($config['contentitem'])) {
$attributes['data-contentitem'] = 1;
$attributes['data-id'] = $id;
} else {
$noncontentitemtypes[] = $id;
}
}
$tooltypes->addOption($type->name, $id, $attributes);
}
} else {
$mform->addElement('hidden', 'typeid', $typeid);
$mform->setType('typeid', PARAM_INT);
if ($typeid) {
$config = lti_get_type_config($typeid);
if (!empty($config['contentitem'])) {
$mform->addElement('hidden', 'contentitem', 1);
$mform->setType('contentitem', PARAM_INT);
}
}
$tooltypes->addOption($type->name, $id, $attributes);
}
// Add button that launches the content-item selection dialogue.
@ -148,23 +177,32 @@ class mod_lti_mod_form extends moodleform_mod {
$contentbuttonattributes = [
'data-contentitemurl' => $contentitemurl->out(false)
];
if (!$showtypes) {
if (!$typeid || empty(lti_get_type_config($typeid)['contentitem'])) {
$contentbuttonattributes['disabled'] = 'disabled';
}
}
$contentbuttonlabel = get_string('selectcontent', 'lti');
$contentbutton = $mform->addElement('button', 'selectcontent', $contentbuttonlabel, $contentbuttonattributes);
// Disable select content button if the selected tool doesn't support content item or it's set to Automatic.
$allnoncontentitemtypes = $noncontentitemtypes;
$allnoncontentitemtypes[] = '0'; // Add option value for "Automatic, based on tool URL".
$mform->disabledIf('selectcontent', 'typeid', 'in', $allnoncontentitemtypes);
if ($showtypes) {
$allnoncontentitemtypes = $noncontentitemtypes;
$allnoncontentitemtypes[] = '0'; // Add option value for "Automatic, based on tool URL".
$mform->disabledIf('selectcontent', 'typeid', 'in', $allnoncontentitemtypes);
}
$mform->addElement('text', 'toolurl', get_string('launch_url', 'lti'), array('size' => '64'));
$mform->setType('toolurl', PARAM_URL);
$mform->addHelpButton('toolurl', 'launch_url', 'lti');
$mform->hideIf('toolurl', 'typeid', 'in', $noncontentitemtypes);
if ($showoptions) {
$mform->addElement('text', 'toolurl', get_string('launch_url', 'lti'), array('size' => '64'));
$mform->setType('toolurl', PARAM_URL);
$mform->addHelpButton('toolurl', 'launch_url', 'lti');
$mform->hideIf('toolurl', 'typeid', 'in', $noncontentitemtypes);
$mform->addElement('text', 'securetoolurl', get_string('secure_launch_url', 'lti'), array('size' => '64'));
$mform->setType('securetoolurl', PARAM_URL);
$mform->setAdvanced('securetoolurl');
$mform->addHelpButton('securetoolurl', 'secure_launch_url', 'lti');
$mform->hideIf('securetoolurl', 'typeid', 'in', $noncontentitemtypes);
$mform->addElement('text', 'securetoolurl', get_string('secure_launch_url', 'lti'), array('size' => '64'));
$mform->setType('securetoolurl', PARAM_URL);
$mform->setAdvanced('securetoolurl');
$mform->addHelpButton('securetoolurl', 'secure_launch_url', 'lti');
$mform->hideIf('securetoolurl', 'typeid', 'in', $noncontentitemtypes);
}
$mform->addElement('hidden', 'urlmatchedtypeid', '', array( 'id' => 'id_urlmatchedtypeid' ));
$mform->setType('urlmatchedtypeid', PARAM_INT);
@ -181,36 +219,38 @@ class mod_lti_mod_form extends moodleform_mod {
$mform->addHelpButton('launchcontainer', 'launchinpopup', 'lti');
$mform->setAdvanced('launchcontainer');
$mform->addElement('text', 'resourcekey', get_string('resourcekey', 'lti'));
$mform->setType('resourcekey', PARAM_TEXT);
$mform->setAdvanced('resourcekey');
$mform->addHelpButton('resourcekey', 'resourcekey', 'lti');
$mform->setForceLtr('resourcekey');
$mform->hideIf('resourcekey', 'typeid', 'in', $noncontentitemtypes);
if ($showoptions) {
$mform->addElement('text', 'resourcekey', get_string('resourcekey', 'lti'));
$mform->setType('resourcekey', PARAM_TEXT);
$mform->setAdvanced('resourcekey');
$mform->addHelpButton('resourcekey', 'resourcekey', 'lti');
$mform->setForceLtr('resourcekey');
$mform->hideIf('resourcekey', 'typeid', 'in', $noncontentitemtypes);
$mform->addElement('passwordunmask', 'password', get_string('password', 'lti'));
$mform->setType('password', PARAM_TEXT);
$mform->setAdvanced('password');
$mform->addHelpButton('password', 'password', 'lti');
$mform->hideIf('password', 'typeid', 'in', $noncontentitemtypes);
$mform->addElement('passwordunmask', 'password', get_string('password', 'lti'));
$mform->setType('password', PARAM_TEXT);
$mform->setAdvanced('password');
$mform->addHelpButton('password', 'password', 'lti');
$mform->hideIf('password', 'typeid', 'in', $noncontentitemtypes);
$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->setForceLtr('instructorcustomparameters');
$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->setForceLtr('instructorcustomparameters');
$mform->addElement('text', 'icon', get_string('icon_url', 'lti'), array('size' => '64'));
$mform->setType('icon', PARAM_URL);
$mform->setAdvanced('icon');
$mform->addHelpButton('icon', 'icon_url', 'lti');
$mform->hideIf('icon', 'typeid', 'in', $noncontentitemtypes);
$mform->addElement('text', 'icon', get_string('icon_url', 'lti'), array('size' => '64'));
$mform->setType('icon', PARAM_URL);
$mform->setAdvanced('icon');
$mform->addHelpButton('icon', 'icon_url', 'lti');
$mform->hideIf('icon', 'typeid', 'in', $noncontentitemtypes);
$mform->addElement('text', 'secureicon', get_string('secure_icon_url', 'lti'), array('size' => '64'));
$mform->setType('secureicon', PARAM_URL);
$mform->setAdvanced('secureicon');
$mform->addHelpButton('secureicon', 'secure_icon_url', 'lti');
$mform->hideIf('secureicon', 'typeid', 'in', $noncontentitemtypes);
$mform->addElement('text', 'secureicon', get_string('secure_icon_url', 'lti'), array('size' => '64'));
$mform->setType('secureicon', PARAM_URL);
$mform->setAdvanced('secureicon');
$mform->addHelpButton('secureicon', 'secure_icon_url', 'lti');
$mform->hideIf('secureicon', 'typeid', 'in', $noncontentitemtypes);
}
// Add privacy preferences fieldset where users choose whether to send their data.
$mform->addElement('header', 'privacy', get_string('privacy', 'lti'));

View File

@ -48,7 +48,7 @@
defined('MOODLE_INTERNAL') || die;
$plugin->version = 2019111800; // The current module version (Date: YYYYMMDDXX).
$plugin->version = 2020010800; // The current module version (Date: YYYYMMDDXX).
$plugin->requires = 2019111200; // Requires this Moodle version.
$plugin->component = 'mod_lti'; // Full name of the plugin (used for diagnostics).
$plugin->cron = 0;