Merge branch 'MDL-62815_mod_lti' of git://github.com/davosmith/moodle
authorAdrian Greeve <abgreeve@gmail.com>
Mon, 20 Jan 2020 01:53:27 +0000 (09:53 +0800)
committerAdrian Greeve <abgreeve@gmail.com>
Mon, 20 Jan 2020 01:53:27 +0000 (09:53 +0800)
mod/lti/db/access.php
mod/lti/lang/en/lti.php
mod/lti/lib.php
mod/lti/locallib.php
mod/lti/mod_form.js
mod/lti/mod_form.php
mod/lti/version.php

index f699c47..6722495 100644 (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(
index e9c8a2b..906f364 100644 (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';
index 0d98e57..e450cd6 100644 (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) {
index ec9bd2f..c69d3ab 100644 (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;
index f341ccc..2b21157 100644 (file)
             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 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();
-
-                    // Set data to be POSTed.
-                    var postData = {
-                        id: contentItemId,
-                        course: self.settings.courseId,
-                        title: title,
-                        text: text
-                    };
+                        var allowgrades = Y.one('#id_instructorchoiceacceptgrades');
+                        allowgrades.set('checked', !self.getSelectedToolTypeOption().getAttribute('nogrades'));
+                        self.toggleGradeSection();
+                    }
+                });
 
-                    require(['mod_lti/contentitem'], function(contentitem) {
-                        contentitem.init(contentItemUrl, postData, function() {
-                            M.mod_lti.editor.toggleGradeSection();
-                        });
-                    });
-                }
-            });
+                this.createTypeEditorButtons();
 
-            this.createTypeEditorButtons();
+                this.toggleEditButtons();
+            }
 
-            this.toggleEditButtons();
+            var contentItemButton = Y.one('[name="selectcontent"]');
+            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
+                        };
+
+                        require(['mod_lti/contentitem'], function(contentitem) {
+                            contentitem.init(contentItemUrl, postData, function() {
+                                M.mod_lti.editor.toggleGradeSection();
+                            });
+                        });
+                    }
+                });
+            }
 
             var textAreas = new Y.NodeList([
                 Y.one('#id_toolurl'),
             var allowgrades = Y.one('#id_instructorchoiceacceptgrades');
             allowgrades.on('change', this.toggleGradeSection, this);
 
-            updateToolMatches();
+            if (typeSelector) {
+                updateToolMatches();
+            }
         },
 
         toggleGradeSection: function(e) {
         },
 
         updateAutomaticToolMatch: function(field){
+            if (!field) {
+                return;
+            }
+
             var self = this;
 
             var toolurl = field;
          * @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;
         },
 
         /**
index bc3ba4e..8eb9fac 100644 (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 ($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');
+
+            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 (!in_array('Person.email.primary', $enabledcapabilities)) {
-                    $attributes['noemail'] = 1;
+
+                if ($id) {
+                    $config = lti_get_type_config($id);
+                    if (!empty($config['contentitem'])) {
+                        $attributes['data-contentitem'] = 1;
+                        $attributes['data-id'] = $id;
+                    } else {
+                        $noncontentitemtypes[] = $id;
+                    }
                 }
-            } 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();
+                $tooltypes->addOption($type->name, $id, $attributes);
             }
-
-            if ($id) {
-                $config = lti_get_type_config($id);
+        } else {
+            $mform->addElement('hidden', 'typeid', $typeid);
+            $mform->setType('typeid', PARAM_INT);
+            if ($typeid) {
+                $config = lti_get_type_config($typeid);
                 if (!empty($config['contentitem'])) {
-                    $attributes['data-contentitem'] = 1;
-                    $attributes['data-id'] = $id;
-                } else {
-                    $noncontentitemtypes[] = $id;
+                    $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);
-
-        $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 ($showtypes) {
+            $allnoncontentitemtypes = $noncontentitemtypes;
+            $allnoncontentitemtypes[] = '0'; // Add option value for "Automatic, based on tool URL".
+            $mform->disabledIf('selectcontent', 'typeid', 'in', $allnoncontentitemtypes);
+        }
 
-        $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);
+        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('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);
-
-        $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('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);
+        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('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', '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'));
index 7921b8b..42ae637 100644 (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;