Commit de260e0f authored by Penny Leach's avatar Penny Leach
Browse files

mnet MDL-21261 large overhaul. This commit changes:

- The way that mnet rpc functions are registered.  Plugins must now
  create db/mnet.php which is an array, similar to services.php.  This
  *replaces* the old mnet_publishes() functions.  version.php must be
  bumped to trigger this.

- More information about each rpc-available function is stored in the
  database, including the class it belongs to, the file it is found in,
  and whether or not it is static.  Methods that are not static must be
  in a class with a constructor that takes no arguments (this can easily
  be achieved with a small wrapper if necessary)

- The xmlrpc dispatcher has been rewritten to remove all the
  dependencies on hardcoded information about auth,mnet,portfolio and
  repository, and just use the information in the database.

- The old hardcoded hidden mnet/testclient.php has been moved to the
  Admin menu under "Development" and rewritten.

- The xmlrpc introspection method profiling is now using php and zend
  reflection - which is a lot nicer than the old way, which was using a
  php-based php parser.  This fixes some inconsistent handling of
  methods without arguments that were advertising their return value as
  the only method parameter.  While this is a *fix*, it breaks BC
  slightly - the old 1.9 broken mnet/testclient.php will now not work
  properly with 2.0

- Dangerous mode is still supported, but old mod/*/rpclib.php is
  now unsupported, due to the fact that any plugin can export mnet
  functions with db/mnet.php.  This is a slight BC break.

Still TODO:

- TEST TEST TEST
- Document the two small BC breaks in release notes
- Document the contract for db/mnet.php
parent 92a89068
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Library functions for mnet
* This file contains the admin related mnet functions
*
* @author Donal McMullan donal@catalyst.net.nz
* @version 0.0.1
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package mnet
* @since 2.0
* @package moodlecore
* @copyright 2010 Penny Leach <penny@liip.ch>
* @copyright 2006 Donal McMullan <donal@catalyst.net.nz>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Parse a file to find out what functions/methods exist in it, and add entries
* for the remote-call-enabled functions to the database.
* upgrades the mnet rpc definitions for the given component.
* this method doesn't return status, an exception will be thrown in the case of an error
*
* The path to a file, e.g. auth/mnet/auth.php can be thought of as
* type/parentname/docname
*
* @param string $type mod, auth or enrol
* @param string $parentname Implementation of type, e.g. 'mnet' in the
* case of auth/mnet/auth.php
* @return bool True on success, else false
* @param string $component the plugin to upgrade, eg auth_mnet
*/
function mnet_get_functions($type, $parentname) {
global $CFG, $DB;
function upgrade_plugin_mnet_functions($component) {
global $DB, $CFG;
$dataobject = new stdClass();
$docname = $type.'.php';
$publishes = array();
if ('mod' == $type) {
$docname = 'rpclib.php';
$relname = '/mod/'.$parentname.'/'.$docname;
$filename = $CFG->dirroot.$relname;
if (file_exists($filename)) include_once $filename;
$mnet_publishes = $parentname.'_mnet_publishes';
if (function_exists($mnet_publishes)) {
(array)$publishes = $mnet_publishes();
}
} else if ('portfolio' == $type) {
$docname = 'lib.php';
$relname = '/portfolio/' . $parentname . '/'. $docname;
$filename = $CFG->dirroot . $relname;
require_once($CFG->libdir . '/portfoliolib.php');
$publishes = (array)portfolio_static_function($parentname, 'mnet_publishes');
} else if ('repository' == $type) {
$docname = 'repository.class.php';
$relname = '/repository/' . $parentname . '/'. $docname;
$filename = $CFG->dirroot . $relname;
require_once($CFG->dirroot . '/repository/lib.php');
$publishes = (array)repository::static_function($parentname, 'mnet_publishes');
} else {
// auth or enrol
$relname = '/'.$type.'/'.$parentname.'/'.$docname;
$filename = $CFG->dirroot.$relname;
if (file_exists($filename)) include_once $filename;
$class = $type.($type=='enrol'? 'ment':'').'_plugin_'.$parentname;
if (class_exists($class)) {
$object = new $class();
if (method_exists($object, 'mnet_publishes')) {
(array)$publishes = $object->mnet_publishes();
}
}
list($type, $plugin) = explode('_', $component);
$path = get_plugin_directory($type, $plugin);
if (file_exists($path . '/db/mnet.php')) {
require_once($path . '/db/mnet.php'); // $publishes comes from this file
}
if (empty($publishes)) {
$publishes = array(); // still need this to be able to disable stuff later
}
$methodServiceArray = array();
foreach($publishes as $service) {
// rekey an array based on the rpc method for easy lookups later
$methodservices = array();
foreach($publishes as $servicename => $service) {
if (is_array($service['methods'])) {
foreach($service['methods'] as $methodname) {
$methodServiceArray[$methodname][] = $service;
$service['servicename'] = $servicename;
$methodservices[$methodname][] = $service;
}
}
}
// Disable functions that don't exist (any more) in the source
// Should these be deleted? What about their permissions records?
$rpcrecords = $DB->get_records('mnet_rpc', array('parent'=>$parentname, 'parent_type'=>$type), 'function_name ASC ');
if (!empty($rpcrecords)) {
foreach($rpcrecords as $rpc) {
if (!array_key_exists($rpc->function_name, $methodServiceArray)) {
$rpc->enabled = 0;
$DB->update_record('mnet_rpc', $rpc);
}
foreach ($DB->get_records('mnet_rpc', array('pluginname'=>$plugin, 'plugintype'=>$type), 'function_name ASC ') as $rpc) {
if (!array_key_exists($rpc->function_name, $methodservices)) {
$DB->set_field('mnet_rpc', 'enabled', 0, array('id' => $rpc->id));
}
}
if (!file_exists($filename)) return false;
if (extension_loaded('tokenizer')) {
include_once "$CFG->dirroot/$CFG->admin/mnet/MethodTable.php";
$functions = (array)MethodTable::create($filename,false);
}
foreach($methodServiceArray as $method => $servicearray) {
if (!empty($functions[$method])) {
$details = $functions[$method];
$profile = $details['arguments'];
if (!isset($details['returns'])) {
array_unshift($profile, array('type' => 'void', 'description' => 'No return value'));
require_once($CFG->dirroot . '/lib/zend/Zend/Server/Reflection.php');
static $cachedclasses = array(); // to store reflection information in
foreach ($publishes as $service => $data) {
$f = $data['filename'];
$c = $data['classname'];
foreach ($data['methods'] as $method) {
$dataobject = new stdclass;
$dataobject->plugintype = $type;
$dataobject->pluginname = $plugin;
$dataobject->enabled = 1;
$dataobject->classname = $c;
$dataobject->filename = $f;
if (is_string($method)) {
$dataobject->function_name = $method;
} else if (is_array($method)) { // wants to override file or class
$dataobject->function_name = $method['method'];
$dataobject->classname = $method['classname'];
$dataobject->filename = $method['filename'];
}
$dataobject->xmlrpc_path = $type.'/'.$plugin.'/'.$dataobject->filename.'/'.$method;
$dataobject->static = false;
require_once($path . '/' . $dataobject->filename);
$functionreflect = null; // slightly different ways to get this depending on whether it's a class method or a function
if (!empty($dataobject->classname)) {
if (!class_exists($dataobject->classname)) {
throw new moodle_exception('installnosuchmethod', 'mnet', '', (object)array('method' => $dataobject->function_name, 'class' => $dataobject->classname));
}
$key = $dataobject->filename . '|' . $dataobject->classname;
if (!array_key_exists($key, $cachedclasses)) { // look to see if we've already got a reflection object
try {
$cachedclasses[$key] = Zend_Server_Reflection::reflectClass($dataobject->classname);
} catch (Zend_Server_Reflection_Exception $e) { // catch these and rethrow them to something more helpful
throw new moodle_exception('installreflectionclasserror', 'mnet', '', (object)array('method' => $dataobject->function_name, 'class' => $dataobject->classname, 'error' => $e->getMessage()));
}
}
$r =& $cachedclasses[$key];
if (!$r->hasMethod($dataobject->function_name)) {
throw new moodle_exception('installnosuchmethod', 'mnet', '', (object)array('method' => $dataobject->function_name, 'class' => $dataobject->classname));
}
// stupid workaround for zend not having a getMethod($name) function
$ms = $r->getMethods();
foreach ($ms as $m) {
if ($m->getName() == $dataobject->function_name) {
$functionreflect = $m;
break;
}
}
$dataobject->static = (int)$functionreflect->isStatic();
} else {
array_unshift($profile, $details['returns']);
if (!function_exists($dataobject->function_name)) {
throw new moodle_exception('installnosuchfunction', 'mnet', '', (object)array('method' => $dataobject->function_name, 'file' => $dataobject->filename));
}
try {
$functionreflect = Zend_Server_Reflection::reflectFunction($dataobject->function_name);
} catch (Zend_Server_Reflection_Exception $e) { // catch these and rethrow them to something more helpful
throw new moodle_exception('installreflectionfunctionerror', 'mnet', '', (object)array('method' => $dataobject->function_name, '' => $dataobject->filename, 'error' => $e->getMessage()));
}
}
$dataobject->profile = serialize($profile);
$dataobject->help = $details['description'];
} else {
$dataobject->profile = serialize(array(array('type' => 'void', 'description' => 'No return value')));
$dataobject->help = '';
}
$dataobject->function_name = $method;
$dataobject->xmlrpc_path = $type.'/'.$parentname.'/'.$docname.'/'.$method;
$dataobject->parent_type = $type;
$dataobject->parent = $parentname;
$dataobject->enabled = '0';
$dataobject->profile = serialize(admin_mnet_method_profile($functionreflect));
$dataobject->help = $functionreflect->getDescription();
if ($record_exists = $DB->get_record('mnet_rpc', array('xmlrpc_path'=>$dataobject->xmlrpc_path))) {
$dataobject->id = $record_exists->id;
$dataobject->enabled = $record_exists->enabled;
$DB->update_record('mnet_rpc', $dataobject);
} else {
$dataobject->id = $DB->insert_record('mnet_rpc', $dataobject, true);
if ($record_exists = $DB->get_record('mnet_rpc', array('xmlrpc_path'=>$dataobject->xmlrpc_path))) {
$dataobject->id = $record_exists->id;
$dataobject->enabled = $record_exists->enabled;
$DB->update_record('mnet_rpc', $dataobject);
} else {
$dataobject->id = $DB->insert_record('mnet_rpc', $dataobject, true);
}
}
foreach($servicearray as $service) {
$serviceobj = $DB->get_record('mnet_service', array('name'=>$service['name']));
if (false == $serviceobj) {
foreach ($methodservices[$dataobject->function_name] as $service) {
if ($serviceobj = $DB->get_record('mnet_service', array('name'=>$service['servicename']))) {
$serviceobj->apiversion = $service['apiversion'];
$DB->update_record('mnet_service', $serviceobj);
} else {
$serviceobj = new stdClass();
$serviceobj->name = $service['name'];
$serviceobj->name = $service['servicename'];
$serviceobj->apiversion = $service['apiversion'];
$serviceobj->offer = 1;
$serviceobj->id = $DB->insert_record('mnet_service', $serviceobj, true);
$serviceobj->id = $DB->insert_record('mnet_service', $serviceobj);
}
if (false == $DB->get_record('mnet_service2rpc', array('rpcid'=>$dataobject->id, 'serviceid'=>$serviceobj->id))) {
if (!$DB->record_exists('mnet_service2rpc', array('rpcid'=>$dataobject->id, 'serviceid'=>$serviceobj->id))) {
$obj = new stdClass();
$obj->rpcid = $dataobject->id;
$obj->serviceid = $serviceobj->id;
......@@ -137,76 +155,32 @@ function mnet_get_functions($type, $parentname) {
}
}
}
return true;
return true;
}
function upgrade_RPC_functions() {
global $CFG;
// TODO: rewrite this thing so that it:
// 1/ does not include half the world
// 2/ returns status if something upgraded - needed for proper conitnue button
// 3/ upgrade functions in general should not use normal function calls to moodle core and modules
$basedir = $CFG->dirroot.'/mod';
if (file_exists($basedir) && filetype($basedir) == 'dir') {
$dirhandle = opendir($basedir);
while (false !== ($dir = readdir($dirhandle))) {
$firstchar = substr($dir, 0, 1);
if ($firstchar == '.' or $dir == 'CVS' or $dir == '_vti_cnf') {
continue;
}
if (filetype($basedir .'/'. $dir) != 'dir') {
continue;
}
mnet_get_functions('mod', $dir);
}
}
$basedir = $CFG->dirroot.'/auth';
if (file_exists($basedir) && filetype($basedir) == 'dir') {
$dirhandle = opendir($basedir);
while (false !== ($dir = readdir($dirhandle))) {
$firstchar = substr($dir, 0, 1);
if ($firstchar == '.' or $dir == 'CVS' or $dir == '_vti_cnf') {
continue;
}
if (filetype($basedir .'/'. $dir) != 'dir') {
continue;
}
mnet_get_functions('auth', $dir);
}
}
$basedir = $CFG->dirroot.'/enrol';
if (file_exists($basedir) && filetype($basedir) == 'dir') {
$dirhandle = opendir($basedir);
while (false !== ($dir = readdir($dirhandle))) {
$firstchar = substr($dir, 0, 1);
if ($firstchar == '.' or $dir == 'CVS' or $dir == '_vti_cnf') {
continue;
}
if (filetype($basedir .'/'. $dir) != 'dir') {
continue;
}
mnet_get_functions('enrol', $dir);
}
}
if ($plugins = get_list_of_plugins('portfolio')) {
foreach ($plugins as $p) {
mnet_get_functions('portfolio', $p);
}
}
if ($plugins = get_list_of_plugins('repository')) {
foreach ($plugins as $p) {
mnet_get_functions('repository', $p);
}
/**
* Given some sort of Zend Reflection function/method object, return a profile array, ready to be serialized and stored
*
* @param Zend_Server_Reflection_Function_Abstract $function can be any subclass of this object type
*
* @return array
*/
function admin_mnet_method_profile(Zend_Server_Reflection_Function_Abstract $function) {
$proto = array_pop($function->getPrototypes());
$ret = $proto->getReturnValue();
$profile = array(
'parameters' => array(),
'return' => array(
'type' => $ret->getType(),
'description' => $ret->getDescription(),
),
);
foreach ($proto->getParameters() as $p) {
$profile['parameters'][] = array(
'name' => $p->getName(),
'type' => $p->getType(),
'description' => $p->getDescription(),
);
}
return $profile;
}
......@@ -16,7 +16,7 @@ echo $OUTPUT->box_start();
<?php
foreach($myservices as $name => $versions) {
$version = current($versions);
$langmodule = ($version['parent_type'] == 'mod' ? '' : ($version['parent_type'] . '_')) . $version['parent'];
$langmodule = ($version['plugintype'] == 'mod' ? '' : ($version['plugintype'] . '_')) . $version['pluginname'];
?>
<tr>
<td align="left" valign="top" colspan="2">
......
......@@ -83,7 +83,7 @@
$id_list .= ', '.$CFG->mnet_all_hosts_id;
}
$concat = $DB->sql_concat('COALESCE(h2s.id,0) ', ' \'-\' ', ' svc.id', '\'-\'', 'r.parent_type', '\'-\'', 'r.parent');
$concat = $DB->sql_concat('COALESCE(h2s.id,0) ', ' \'-\' ', ' svc.id', '\'-\'', 'r.plugintype', '\'-\'', 'r.pluginname');
$query = "
SELECT DISTINCT
......@@ -92,8 +92,8 @@
svc.name,
svc.offer,
svc.apiversion,
r.parent_type,
r.parent,
r.plugintype,
r.pluginname,
h2s.hostid,
h2s.publish,
h2s.subscribe
......@@ -156,8 +156,8 @@
'name' => $result->name,
'offer' => $result->offer,
'apiversion' => $result->apiversion,
'parent_type' => $result->parent_type,
'parent' => $result->parent,
'plugintype' => $result->plugintype,
'pluginname' => $result->pluginname,
'hostsubscribes' => $result->hostsubscribes,
'hostpublishes' => $result->hostpublishes
);
......
......@@ -38,5 +38,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
// XMLDB editor
$ADMIN->add('development', new admin_externalpage('xmldbeditor', get_string('xmldbeditor'), "$CFG->wwwroot/$CFG->admin/xmldb/"));
if ($CFG->mnet_dispatcher_mode !== 'off') {
$ADMIN->add('development', new admin_externalpage('mnettestclient', get_string('testclient', 'mnet'), "$CFG->wwwroot/$CFG->admin/mnet/testclient.php"));
}
} // end of speedup
......@@ -31,27 +31,6 @@ class auth_plugin_mnet extends auth_plugin_base {
$this->config = get_config('auth/mnet');
}
/**
* Provides the allowed RPC services from this class as an array.
* @return array Allowed RPC services.
*/
function mnet_publishes() {
$sso_idp = array();
$sso_idp['name'] = 'sso_idp'; // Name & Description go in lang file
$sso_idp['apiversion'] = 1;
$sso_idp['methods'] = array('user_authorise','keepalive_server', 'kill_children',
'refresh_log', 'fetch_user_image', 'fetch_theme_info',
'update_enrolments');
$sso_sp = array();
$sso_sp['name'] = 'sso_sp'; // Name & Description go in lang file
$sso_sp['apiversion'] = 1;
$sso_sp['methods'] = array('keepalive_client','kill_child');
return array($sso_idp, $sso_sp);
}
/**
* This function is normally used to determine if the username and password
* are correct for local logins. Always returns false, as local users do not
......@@ -74,7 +53,7 @@ class auth_plugin_mnet extends auth_plugin_base {
*/
function user_authorise($token, $useragent) {
global $CFG, $MNET, $SITE, $MNET_REMOTE_CLIENT, $DB;
require_once $CFG->dirroot . '/mnet/xmlrpc/server.php';
require_once $CFG->dirroot . '/mnet/xmlrpc/serverlib.php';
$mnet_session = $DB->get_record('mnet_session', array('token'=>$token, 'useragent'=>$useragent));
if (empty($mnet_session)) {
......@@ -465,11 +444,11 @@ class auth_plugin_mnet extends auth_plugin_base {
* Invoke this function _on_ the IDP to update it with enrolment info local to
* the SP right after calling user_authorise()
*
* Normally called by the SP after calling
* Normally called by the SP after calling user_authorise()
*
* @param string $username The username
* @param string $courses Assoc array of courses following the structure of mnet_enrol_course
* @return bool
* @param string $username The username
* @param string $courses Assoc array of courses following the structure of mnet_enrol_course
* @return bool
*/
function update_enrolments($username, $courses) {
global $MNET_REMOTE_CLIENT, $CFG, $DB;
......@@ -623,7 +602,9 @@ class auth_plugin_mnet extends auth_plugin_base {
* This function is called from admin/auth.php, and outputs a full page with
* a form for configuring this plugin.
*
* @param array $page An object containing all the data for this page.
* @param object $config
* @param object $err
* @param array $user_fields
*/
function config_form($config, $err, $user_fields) {
global $CFG, $DB;
......
<?php
$plugin->version = 2009112400;
$plugin->version = 2010012600;
......@@ -65,22 +65,11 @@ class enrolment_plugin_mnet {
*** MNET functions
***
***/
function mnet_publishes() {
$enrol = array();
$enrol['name'] = 'mnet_enrol'; // Name & Description go in lang file
$enrol['apiversion'] = 1;
$enrol['methods'] = array('available_courses','user_enrolments', 'enrol_user', 'unenrol_user', 'course_enrolments' );
return array($enrol);
}
/**
* Does Foo
* Returns a list of all courses available for remote login
*
* @param string $username The username
* @param int $mnethostid The id of the remote mnethost
* @return bool Whether the user can login from the remote host
* @return array Array of courses
*/
function available_courses() {
global $CFG, $DB;
......
......@@ -256,4 +256,33 @@ $string['error7024'] = 'You send an unencrypted message to the remote site, but
$string['error709'] = 'The remote site failed to obtain a SSL key from you.';
$string['error7026'] = 'The key that your message was signed with differs from the key that the remote host has on file for your server. Further, the remote host attempted to fetch your current key and failed to do so. Please manually re-key with the remote host and try again.';
$string['installnosuchmethod'] = 'Coding error! Something is trying to install a mnet xmlrpc method ($a->method) on a class ($a->class) and it can\'t be found!';
$string['installnosuchfunction'] = 'Coding error! Something is trying to install a mnet xmlrpc function ($a->method) from a file ($a->file) and it can\'t be found!';
$string['installreflectionfunctionerror'] = 'Coding error! MNET introspection failed for function \'$a->method\' in file \'$a->file\'. The original error message, in case it helps, is: \'$a->error\'';
$string['installreflectionclasserror'] = 'Coding error! MNET introspection failed for method \'$a->method\' in class \'$a->class\'. The original error message, in case it helps, is: \'$a->error\'';
// admin strings
$string['hostlist'] = 'List of Networked Hosts';
$string['servicesavailableonhost'] = 'Services available on $a';
$string['serviceid'] = 'Service ID';
$string['service'] = 'Service Name';
$string['version'] = 'Version';
$string['theypublish'] = 'They publish';
$string['theysubscribe'] = 'They subscribe';
$string['listservices'] = 'List services';
$string['methodsavailableonhostinservice'] = 'Methods available for $a->service on $a->host';
$string['methodsavailableonhost'] = 'Methods available on $a';
$string['method'] = 'Method';
$string['options'] = 'Options';
$string['inspect'] = 'Inspect';
$string['methodsignature'] = 'Method signature for $a';
$string['position'] = 'Position';
$string['name'] = 'Name';
$string['type'] = 'Type';
$string['description'] = 'Description';
$string['returnvalue'] = 'Return value';
$string['methodhelp'] = 'Method help for $a';
$string['testclient'] = 'Moodle Network Test Client';
$string['unknown'] = 'Unknown';
$string['notmoodleapplication'] = 'WARNING: This is not a moodle application, so some of the inspection methods may not work properly.';
?>
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="lib/db" VERSION="20100106" COMMENT="XMLDB file for core Moodle tables"
<XMLDB PATH="lib/db" VERSION="20100126" COMMENT="XMLDB file for core Moodle tables"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
>
......@@ -1324,12 +1324,15 @@
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" SEQUENCE="true" COMMENT="Unique Function ID" NEXT="function_name"/>
<FIELD NAME="function_name" TYPE="char" LENGTH="40" NOTNULL="true" SEQUENCE="false" PREVIOUS="id" NEXT="xmlrpc_path"/>
<FIELD NAME="xmlrpc_path" TYPE="char" LENGTH="80" NOTNULL="true" SEQUENCE="false" PREVIOUS="function_name" NEXT="parent_type"/>
<FIELD NAME="parent_type" TYPE="char" LENGTH="20" NOTNULL="true" SEQUENCE="false" PREVIOUS="xmlrpc_path" NEXT="parent"/>
<FIELD NAME="parent" TYPE="char" LENGTH="20" NOTNULL="true" SEQUENCE="false" PREVIOUS="parent_type" NEXT="enabled"/>
<FIELD NAME="enabled" TYPE="int" LENGTH="1" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="parent" NEXT="help"/>
<FIELD NAME="xmlrpc_path" TYPE="char" LENGTH="80" NOTNULL="true" SEQUENCE="false" PREVIOUS="function_name" NEXT="plugintype"/>
<FIELD NAME="plugintype" TYPE="char" LENGTH="20" NOTNULL="true" SEQUENCE="false" PREVIOUS="xmlrpc_path" NEXT="pluginname"/>
<FIELD NAME="pluginname" TYPE="char" LENGTH="20" NOTNULL="true" SEQUENCE="false" PREVIOUS="plugintype" NEXT="enabled"/>
<FIELD NAME="enabled" TYPE="int" LENGTH="1" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="pluginname" NEXT="help"/>
<FIELD NAME="help" TYPE="text" LENGTH="medium" NOTNULL="true" SEQUENCE="false" PREVIOUS="enabled" NEXT="profile"/>
<FIELD NAME="profile" TYPE="text" LENGTH="medium" NOTNULL="true" SEQUENCE="false" COMMENT="Method signature" PREVIOUS="help"/>
<FIELD NAME="profile" TYPE="text" LENGTH="medium" NOTNULL="true" SEQUENCE="false" COMMENT="Method signature" PREVIOUS="help" NEXT="filename"/>
<FIELD NAME="filename" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false" PREVIOUS="profile" NEXT="classname"/>
<FIELD NAME="classname" TYPE="char" LENGTH="150" NOTNULL="false" SEQUENCE="false" PREVIOUS="filename" NEXT="static"/>
<FIELD NAME="static" TYPE="int" LENGTH="1" NOTNULL="false" UNSIGNED="false" SEQUENCE="false" PREVIOUS="classname"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="primary key of the mnet_rpc table"/>
......
......@@ -2868,10 +2868,41 @@ WHERE gradeitemid IS NOT NULL AND grademax IS NOT NULL");
upgrade_main_savepoint($result, 2010011200);
}
if ($result && $oldversion < 2010012500) {
upgrade_fix_incorrect_mnethostids();
upgrade_main_savepoint($result, 2010012500);
}
if ($result && $oldversion < 2010012600) {
// do stuff to the mnet table
$table = new xmldb_table('mnet_rpc');
$field = new xmldb_field('parent_type', XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null, 'xmlrpc_path');
$dbman->rename_field($table, $field, 'plugintype');
$field = new xmldb_field('parent', XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null, 'xmlrpc_path');
$dbman->rename_field($table, $field, 'pluginname');
$field = new xmldb_field('filename', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null, 'profile');
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
$field = new xmldb_field('classname', XMLDB_TYPE_CHAR, '150', null, null, null, null, 'filename');
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
$field = new xmldb_field('static', XMLDB_TYPE_INTEGER, '1', null, null, null, null, 'classname');
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}