diff --git a/db/mnet.php b/db/mnet.php index 27a6a33..223fd8a 100644 --- a/db/mnet.php +++ b/db/mnet.php @@ -26,12 +26,13 @@ $publishes = array( 'assign_submission_mahara' => array( - 'apiversion' => 1, + 'apiversion' => 2, 'classname' => 'mnetservice_assign_submission_mahara', 'filename' => 'mnetlib.php', 'methods' => array( 'donothing', - 'can_view_view', + // TODO: Uncomment if MDL-52172 gets merged +// 'can_view_view', ), ), ); diff --git a/db/upgrade.php b/db/upgrade.php index 9544c85..f3ee76f 100644 --- a/db/upgrade.php +++ b/db/upgrade.php @@ -177,7 +177,7 @@ function xmldb_assignsubmission_mahara_upgrade($oldversion) { $pluginman = core_plugin_manager::instance(); $uninstallurl = $pluginman->get_uninstall_url('assignfeedback_mahara', 'overview'); $uninstall = html_writer::link($uninstallurl, 'uninstall'); - echo html_writer::div("It seems you are using assignfeedback_mahara plugin. " + echo html_writer::div("It seems you are using the assignfeedback_mahara plugin. " . "This plugin is no longer required for Mahara pages unlocking and conflicting " . "with this upgrade. Please " . $uninstall . " assignfeedback_mahara " . "plugin first, remove its installation directory, and then proceed " diff --git a/lib.php b/lib.php index 3bd8ae2..afda1dc 100644 --- a/lib.php +++ b/lib.php @@ -65,5 +65,48 @@ function assignsubmission_mahara_sitelist() { h.name"; return $DB->get_records_sql_menu($sql, array('mnet_localhost_id'=>$CFG->mnet_localhost_id)); +} + +/** + * Determines whether or not the specified mnethost is publishing the function needed to + * do Mahara page permissions via MNet. + * TODO: Update this function if MDL-52172 gets merged + * + * @param int $mnethostid + * @return boolean + */ +function assignsubmission_mahara_is_mnet_acl_enabled($mnethostid) { + global $DB, $CFG; + $sql = ' + SELECT r.xmlrpcpath + FROM + {mnet_host} h + INNER JOIN {mnet_host2service} h2s + ON h.id = h2s.hostid + INNER JOIN {mnet_service} s + ON s.id = h2s.serviceid + AND s.name=\'assign_submission_mahara\' + INNER JOIN {mnet_service2rpc} s2r + ON s.id = s2r.serviceid + INNER JOIN {mnet_rpc} r + on r.id = s2r.rpcid + AND r.functionname = \'can_view_view\' + AND r.pluginname = \'mahara\' + AND r.plugintype = \'local\' + WHERE + h.id = :mnethostid + AND h.deleted = 0 + AND h2s.publish = 1 + AND r.enabled = 1 + '; + $ret = $DB->record_exists_sql($sql, array('mnethostid' => $mnethostid)); + // Seemed like a good idea, but it fills up the logs too much. +// if (!$ret) { +// debugging('You should install the Mahara local plugin and publish its service, for better' +// .' interoperability with the Mahara assignment submission plugin.', +// DEBUG_DEVELOPER +// ); +// } + return $ret; } diff --git a/locallib.php b/locallib.php index a22e09f..ce5316d 100644 --- a/locallib.php +++ b/locallib.php @@ -25,6 +25,7 @@ */ defined('MOODLE_INTERNAL') || die(); +require_once ($CFG->dirroot . '/mod/assign/submission/mahara/lib.php'); /** * library class for Mahara submission plugin extending submission plugin base class @@ -349,7 +350,17 @@ public function mnet_submit_view($submission, $viewid, $iscollection, $viewowner else { $username = $DB->get_field('user', 'username', array('id'=>$viewownermoodleid)); } - return $this->mnet_send_request('submit_view_for_assessment', array($username, $viewid, $iscollection, $lock)); + + // Check whether we're set up to use mnet-based access control or not. + if (assignsubmission_mahara_is_mnet_acl_enabled($this->get_config('mnethostid'))) { + // Request API level 2 from Mahara (no tokens) + $apilevel = 'moodle-assignsubmission-mahara:2'; + } + else { + $apilevel = 'moodle-assignsubmission-mahara:1'; + } + + return $this->mnet_send_request('submit_view_for_assessment', array($username, $viewid, $iscollection, $apilevel, $lock)); } /** @@ -521,26 +532,13 @@ public function save(stdClass $submission, stdClass $data) { throw new moodle_exception('errormnetrequest', 'assignsubmission_mahara', '', $this->get_error()); } - // TODO: This is workaround code for interacting with older versions of Mahara that relied - // on secreturl tokens for access control. If we're interacting with one of those, then - // the response data will include a non-null 'accesskey' field even though we asked them not to - // lock the page. If that's the case, then we need to now immediately release the page. - // - // This will leave the page unlocked, but due to a bug in the original implementation, - // the access key will continue working until/unless the page is submitted to another - // Moodle assignment. - if (!$this->get_config('lock')) { - // Check whether returned url has a token (tests whether new version of mahara in use - if (is_array($response) && array_key_exists('accesskey', $response) && $response['accesskey'] != false) { - $this->mnet_release_submitted_view($data->viewid, array(), $iscollection); - $status = self::MAHARA_STATUS_RELEASED; - } - else { - $status = self::MAHARA_STATUS_NORMAL; - } - } else { + // Update our record of the Mahara page's status + if ($this->get_config('lock')) { $status = self::MAHARA_STATUS_LOCKED; } + else { + $status = $this->lock_unlock_workaround($data->viewid, $iscollection, $response); + } $params = array( @@ -657,23 +655,18 @@ public function submit_for_grading($submission) { $maharasubmission = $this->get_mahara_submission($submission->id); // Lock view on Mahara side as it has been submitted for assessment. - if (!$response = $this->mnet_submit_view($submission, $maharasubmission->viewid, $maharasubmission->iscollection, null, $this->get_config('lock'))) { + $response = $this->mnet_submit_view($submission, $maharasubmission->viewid, $maharasubmission->iscollection, null, $this->get_config('lock')); + if (!$response || !is_array($response)) { throw new moodle_exception('errormnetrequest', 'assignsubmission_mahara', '', $this->get_error()); } $maharasubmission->viewurl = $response['url']; - $maharasubmission->viewstatus = self::MAHARA_STATUS_LOCKED; - if (!$this->get_config('lock')) { - // TODO: Workaround code for dealing with older versions of Mahara - if (is_array($response) && array_key_exists('accesskey', $response) && $response['accesskey'] != false) { - if ($this->mnet_release_submitted_view($maharasubmission->viewid, array(), $maharasubmission->iscollection) === false) { - throw new moodle_exception('errormnetrequest', 'assignsubmission_mahara', '', $this->get_error()); - } - $maharasubmission->viewstatus = self::MAHARA_STATUS_RELEASED; - } - else { - $maharasubmission->viewstatus = self::MAHARA_STATUS_NORMAL; - } + // Update our record of the page's status + if ($this->get_config('lock')) { + $maharasubmission->viewstatus = self::MAHARA_STATUS_LOCKED; + } + else { + $maharasubmission->viewstatus = $this->lock_unlock_workaround($maharasubmission, $response); } $DB->update_record('assignsubmission_mahara', $maharasubmission); @@ -820,7 +813,8 @@ public function get_preview_url($name, $url, $title = null) { } /** - * Display the teacher's view of the submission. + * Display the view of the submission (as seen in the gradebook, in the student's view, + * and in the teacher's view. * * @global stdClass $DB * @global stdClass $USER @@ -846,19 +840,27 @@ public function view(stdClass $submission) { if ($submission->attemptnumber < $lastattempt) { $result .= get_string('previousattemptsnotvisible', 'assignsubmission_mahara'); } else { - // Either the page is viewed by the author or access code has been issued - $remotehost = $DB->get_field('mnet_host', 'wwwroot', array('id'=>$this->get_config('mnethostid'))); - // Generate the gradebook access URL - $teacherurl = $maharasubmission->viewurl . '&assignment=' . $maharasubmission->assignment; - if ($maharasubmission->iscollection) { - $teacherurl .= '&mnetcollid=' . $maharasubmission->viewid; - } else { - $teacherurl .= '&mnetviewid=' . $maharasubmission->viewid; + if (assignsubmission_mahara_is_mnet_acl_enabled($this->get_config('mnethostid'))) { + // Mahara can use an Mnet callback to verify access control. + // Add params needed by that callback. + $url = $maharasubmission->viewurl . '&assignment=' . $maharasubmission->assignment; + if ($maharasubmission->iscollection) { + $url .= '&mnetcollid=' . $maharasubmission->viewid; + } + else { + $url .= '&mnetviewid=' . $maharasubmission->viewid; + } + } + else { + // Mahara cannot use an MNet callback to verify access control. + // If the viewer is the page owner, then no problem. If it's the teacher, + // this URL will (hopefully) have an active access token on it! + $url = $maharasubmission->viewurl; } - $url = $this->mnetify_url($teacherurl); - return $this->get_preview_url($maharasubmission->viewtitle, $url); + $mneturl = $this->mnetify_url($url); + return $this->get_preview_url($maharasubmission->viewtitle, $mneturl); } } return $result; @@ -1019,4 +1021,42 @@ public function set_mahara_submission_status($submissionid, $status) { } return $DB->set_field('assignsubmission_mahara', 'viewstatus', $status, array('submission' => $submissionid)); } + + + /** + * A workaround method for dealing with an older Mahara installation that cannot + * + * Older Mahara sites rely on an access token for access control, even for pages that are meant + * to be unlocked. In this case we "never lock" the page by actually locking it and immediately + * unlocking it. The access key remains active after unlocking due to a bug in Mahara, and the + * teacher can continue to use that unless the student submits the page to another assignment. + * + * @param int $viewid The view/collection id + * @param boolean $iscollection Whether it's a view or collection + * @param array $response The response data from the MNet submission request + * @throws moodle_exception + * @return int What the submission's mahara page status should be now + */ + /*** + * + * @param unknown $response + * @throws moodle_exception + * @return string + */ + public function lock_unlock_workaround($viewid, $iscollection, $response) { + + $apiversion = (array_key_exists('apilevel', $response)) ? $response['apilevel'] : 'moodle-assignsubmission-mahara:1'; + list($apiname, $apinumber) = explode(':', $apiversion, 2); + + if ($apiname === 'moodle-assignsubmission-mahara' && $apinumber >= 2) { + return self::MAHARA_STATUS_NORMAL; + } + else { + // Older or unknown version of API. Unlock the page. + if ($this->mnet_release_submitted_view($viewid, array(), (bool) $iscollection)) { + throw new moodle_exception('errormnetrequest', 'assignsubmission_mahara', '', $this->get_error()); + } + return self::MAHARA_STATUS_RELEASED; + } + } } diff --git a/version.php b/version.php index de891f5..19da807 100644 --- a/version.php +++ b/version.php @@ -29,3 +29,8 @@ $plugin->component = 'assignsubmission_mahara'; $plugin->maturity = MATURITY_STABLE; $plugin->release = '1.2-mdl2.7+'; // Plugin version 1.2, for Moodle 2.7+ + +// TODO: Will no longer be necessary if MDL-52172 is merged. +$plugin->dependencies = array( + 'local_mahara' => 2015021005 +); \ No newline at end of file