From: jerome Date: Tue, 25 Aug 2009 05:35:59 +0000 (+0000) Subject: webservice MDL-12886 refactor web service description + implement clean_function_para... X-Git-Url: http://git.mjollnir.org/gw?a=commitdiff_plain;h=fbe52a393f34c49973a69641c2afb5482dfa8cef;p=moodle.git webservice MDL-12886 refactor web service description + implement clean_function_params() function --- diff --git a/lib/moodleexternal.php b/lib/moodleexternal.php new file mode 100644 index 0000000000..67098a23e2 --- /dev/null +++ b/lib/moodleexternal.php @@ -0,0 +1,102 @@ +descriptions = array(); + } + + /** + * + * @param string $functionname + * @return array + */ + public function get_function_webservice_description($functionname) { + if (key_exists($functionname, $this->descriptions)) { + return $this->descriptions[$functionname]; + } + else { + return false; + } + } + + /** + * + * @return array + */ + public function get_descriptions() { + return $this->descriptions; + } + + /** + * This function clean params, because it should only be called by external itself, it has to be protected (server should not call it) + * @param array $params + */ + protected function clean_function_params($functionname, &$params) { + $description = $this->get_function_webservice_description($functionname); + varlog($functionname); + foreach ($params as $param) { //we are applying the algo for all params + $key = key($description['params']); //get next key of the description array => params need to be ordered ! + $this->clean_params($description['params'][$key], $param); + + } + } + + /** + * + * @param $params + */ + protected function clean_params($description, &$params) { + if (!is_array($params)) { + $paramvalue = clean_param($params, $description); + } else { + foreach ($params as $paramname => &$paramvalue) { + if (is_array($paramvalue)) { //it's a list + //A description array does not support list of different objects + //it's why we retrieve the first key, because there should be only one key + $this->clean_params($description[key($description)], $paramvalue); + } + else { + if (is_object($paramvalue)) { //is it a object + $this->clean_object_types($description[$paramname], $paramvalue); + } + else { //it's a primary type + $paramvalue = clean_param($paramvalue, $description[$paramname]); + } + } + + + } + + } + } + + protected function clean_object_types($objectdescription, &$paramobject) { + foreach (get_object_vars($paramobject) as $propertyname => $propertyvalue) { + if (is_array($propertyvalue)) { + $this->clean_params($objectdescription->$propertyname, $propertyvalue); + $paramobject->$propertyname = $propertyvalue; + } else { + $paramobject->$propertyname = clean_param($propertyvalue, $objectdescription->$propertyname); + + } + } + } + +} +?> diff --git a/user/external.php b/user/external.php index 2d3b9baca6..5697d3463a 100644 --- a/user/external.php +++ b/user/external.php @@ -22,6 +22,7 @@ * @copyright Copyright (c) 1999 onwards Martin Dougiamas http://dougiamas.com * @license http://www.gnu.org/copyleft/gpl.html GNU GPL License */ +require_once(dirname(dirname(__FILE__)) . '/lib/moodleexternal.php'); require_once(dirname(dirname(__FILE__)) . '/user/lib.php'); /** @@ -29,31 +30,79 @@ require_once(dirname(dirname(__FILE__)) . '/user/lib.php'); * * @author Jerome Mouneyrac */ -final class user_external { +final class user_external extends moodle_external { + +/** + * Constructor - We set the description of this API in order to be access by Web service + */ + function __construct () { + $this->descriptions = array(); + ///The desciption of the web service + + $user = new stdClass(); + $user->password = PARAM_ALPHANUMEXT; + $user->auth = PARAM_ALPHANUMEXT; + $user->confirmed = PARAM_NUMBER; + $user->username = PARAM_ALPHANUMEXT; + $user->idnumber = PARAM_ALPHANUMEXT; + $user->firstname = PARAM_ALPHANUMEXT; + $user->lastname = PARAM_ALPHANUMEXT; + $user->email = PARAM_NOTAGS; + $user->emailstop = PARAM_NUMBER; + $user->lang = PARAM_ALPHA; + $user->theme = PARAM_ALPHANUM; + $user->timezone = PARAM_ALPHANUMEXT; + $user->mailformat = PARAM_ALPHA; + $user->description = PARAM_TEXT; + $user->city = PARAM_ALPHANUMEXT; + $user->country = PARAM_ALPHANUMEXT; + + $this->descriptions['create_users'] = array( 'params' => array('users' => array($user)), + 'optionalinformation' => 'All params are not mandatory', + 'return' => array('userids' => array(PARAM_NUMBER))); + + $user = new stdClass(); + $user->id = PARAM_NUMBER; + $user->auth = PARAM_ALPHANUMEXT; + $user->confirmed = PARAM_NUMBER; + $user->username = PARAM_ALPHANUMEXT; + $user->idnumber = PARAM_ALPHANUMEXT; + $user->firstname = PARAM_ALPHANUMEXT; + $user->lastname = PARAM_ALPHANUMEXT; + $user->email = PARAM_NOTAGS; + $user->emailstop = PARAM_NUMBER; + $user->lang = PARAM_ALPHA; + $user->theme = PARAM_ALPHANUM; + $user->timezone = PARAM_ALPHANUMEXT; + $user->mailformat = PARAM_ALPHA; + $user->description = PARAM_TEXT; + $user->city = PARAM_ALPHANUMEXT; + $user->country = PARAM_ALPHANUMEXT; + + $this->descriptions['get_users'] = array( 'params' => array('search'=> PARAM_ALPHANUM), + 'optionalparams' => 'All params are not mandatory', + 'return' => array('user' => array( $user))); + + + $this->descriptions['delete_users'] = array( 'params' => array('usernames' => array(PARAM_ALPHANUMEXT)), + 'optionalparams' => 'All params are not mandatory', + 'return' => array('result' => PARAM_BOOL)); + + $user->newusername = PARAM_ALPHANUMEXT; + $this->descriptions['update_users'] = array( 'params' => array('users' => array($user), + 'optionalparams' => 'All params are not mandatory', + 'return' => array('result' => PARAM_BOOL))); + } /** * Retrieve all user * @param array|struct $params - need to be define as struct for XMLRPC - * @subparam string $params->search - the string to search * @return object $return - * @subreturn integer $return:user->id - * @subreturn integer $return:user->auth - * @subreturn integer $return:user->confirmed - * @subreturn string $return:user->username - * @subreturn string $return:user->idnumber - * @subreturn string $return:user->firstname - * @subreturn string $return:user->lastname - * @subreturn string $return:user->email - * @subreturn string $return:user->emailstop - * @subreturn string $return:user->lang - * @subreturn string $return:user->theme - * @subreturn string $return:user->timezone - * @subreturn string $return:user->mailformat */ - static function get_users($params) { + public function get_users($params) { global $USER; - $params['search'] = clean_param($params['search'], PARAM_ALPHANUM); + $this->clean_function_params('get_users', $params); if (has_capability('moodle/user:viewdetails', get_context_instance(CONTEXT_SYSTEM))) { return get_users(true, $params['search'], false, null, 'firstname ASC','', '', '', 1000, 'id, auth, confirmed, username, idnumber, firstname, lastname, email, emailstop, lang, theme, timezone, mailformat, city, description, country'); @@ -63,90 +112,19 @@ final class user_external { } } - /** + /** * Create multiple users * @param array|struct $params - need to be define as struct for XMLRPC - * @subparam string $params:user->username - * @subparam string $params:user->firstname - * @subparam string $params:user->lastname - * @subparam string $params:user->email - * @subparam string $params:user->password * @return array $return ids of new user - * @subreturn integer $return:id user id */ - static function create_users($params) { + public function create_users($params) { global $USER; if (has_capability('moodle/user:create', get_context_instance(CONTEXT_SYSTEM))) { $userids = array(); - foreach ($params as $userparams) { - - $user = new stdClass(); - if (array_key_exists('email', $userparams)) { - $user->email = clean_param($userparams['email'], PARAM_NOTAGS); - } - - if (array_key_exists('password', $userparams)) { - $user->password = clean_param($userparams['password'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('idnumber', $userparams)) { - $user->idnumber = clean_param($userparams['idnumber'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('description', $userparams)) { - $user->description = clean_param($userparams['description'], PARAM_TEXT); - } - - if (array_key_exists('username', $userparams)) { - $user->username = clean_param($userparams['username'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('auth', $userparams)) { - $user->auth = clean_param($userparams['auth'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('confirmed', $userparams)) { - $user->confirmed = clean_param($userparams['confirmed'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('firstname', $userparams)) { - $user->firstname = clean_param($userparams['firstname'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('lastname', $userparams)) { - $user->lastname = clean_param($userparams['lastname'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('emailstop', $userparams)) { - $user->emailstop = clean_param($userparams['emailstop'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('lang', $userparams)) { - $user->lang = clean_param($userparams['lang'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('theme', $userparams)) { - $user->theme = clean_param($userparams['theme'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('timezone', $userparams)) { - $user->timezone = clean_param($userparams['timezone'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('city', $userparams)) { - $user->city = clean_param($userparams['city'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('country', $userparams)) { - $user->country = clean_param($userparams['country'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('mailformat', $userparams)) { - $user->mailformat = clean_param($userparams['mailformat'], PARAM_ALPHANUMEXT); - } - + $this->clean_function_params('create_users', $params); + foreach ($params['users'] as $user) { try { - $userids[$userparams['username']] = create_user($user); + $userids[$user->username] = create_user($user); } catch (dml_write_exception $e) { throw new moodle_exception('wscouldnotcreateeuserindb'); @@ -159,27 +137,24 @@ final class user_external { } } - /** + /** * Delete multiple users * @global object $DB * @param array|struct $params - need to be define as struct for XMLRPC - * @subparam string $params:user->username * @return boolean result true if success */ - static function delete_users($params) { + public function delete_users($params) { global $DB,$USER; $deletionsuccessfull = true; if (has_capability('moodle/user:delete', get_context_instance(CONTEXT_SYSTEM))) { - foreach ($params as $userparams) { - - $username = clean_param($userparams['username'], PARAM_ALPHANUMEXT); + $this->clean_function_params('delete_users', $params); + foreach ($params['usernames'] as $username) { $user = $DB->get_record('user', array('username'=>$username, 'mnethostid'=>1)); - if (empty($user)) { throw new moodle_exception('wscouldnotdeletenoexistinguser'); } - + if (!delete_user($user)) { $deletionsuccessfull = false; //this function is in moodlelib.php } @@ -191,87 +166,27 @@ final class user_external { } } - /** + /** * Update some users information * @global object $DB * @param array|struct $params - need to be define as struct for XMLRPC - * @subparam string $params:user->username - * @subparam string $params:user->newusername - * @subparam string $params:user->firstname * @return boolean result true if success */ - static function update_users($params) { + public function update_users($params) { global $DB,$USER; if (has_capability('moodle/user:update', get_context_instance(CONTEXT_SYSTEM))) { $updatesuccessfull = true; - foreach ($params as $userparams) { - if (array_key_exists('username', $userparams)) { - $username = clean_param($userparams['username'], PARAM_NOTAGS); - } + $this->clean_function_params('update_users', $params); - $user = $DB->get_record('user', array('username'=>$username, 'mnethostid'=>1)); + foreach ($params['users'] as $paramuser) { + + $user = $DB->get_record('user', array('username'=> $paramuser->username, 'mnethostid'=>1)); if (empty($user)) { throw new moodle_exception('wscouldnotupdatenoexistinguser'); } - - if (array_key_exists('email', $userparams)) { - $user->email = clean_param($userparams['email'], PARAM_NOTAGS); - } - - if (array_key_exists('description', $userparams)) { - $user->description = clean_param($userparams['description'], PARAM_TEXT); - } - - if (array_key_exists('newusername', $userparams)) { - $user->username = clean_param($userparams['newusername'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('auth', $userparams)) { - $user->auth = clean_param($userparams['auth'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('confirmed', $userparams)) { - $user->confirmed = clean_param($userparams['confirmed'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('firstname', $userparams)) { - $user->firstname = clean_param($userparams['firstname'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('lastname', $userparams)) { - $user->lastname = clean_param($userparams['lastname'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('emailstop', $userparams)) { - $user->emailstop = clean_param($userparams['emailstop'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('lang', $userparams)) { - $user->lang = clean_param($userparams['lang'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('theme', $userparams)) { - $user->theme = clean_param($userparams['theme'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('timezone', $userparams)) { - $user->timezone = clean_param($userparams['timezone'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('city', $userparams)) { - $user->city = clean_param($userparams['city'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('country', $userparams)) { - $user->country = clean_param($userparams['country'], PARAM_ALPHANUMEXT); - } - - if (array_key_exists('mailformat', $userparams)) { - $user->mailformat = clean_param($userparams['mailformat'], PARAM_ALPHANUMEXT); - } - + $user->username = $paramuser->newusername; try { if( !update_user($user)) { $updatesuccessfull = false; diff --git a/webservice/lib.php b/webservice/lib.php index 891ff6f97c..6424137d9c 100644 --- a/webservice/lib.php +++ b/webservice/lib.php @@ -48,9 +48,11 @@ final class webservice_lib { $path = $directorypath . '/' . $file; ///browse the subfolder if( is_dir($path) ) { + if ($file != 'db') { //we don't want to browse the 'db' subfolder of webservice folder require_once($path."/lib.php"); $classname = $file."_server"; $protocols[] = new $classname; + } } ///retrieve api.php file else { @@ -593,12 +595,12 @@ class ws_authentication { * @param array|struct $params * @return integer */ - function get_token($params) { + function get_token($params) { if ($params['username'] == 'wsuser' && $params['password'] == 'wspassword') { return '456'; } else { throw new moodle_exception('wrongusernamepassword'); - } + } } } diff --git a/webservice/soap/lib.php b/webservice/soap/lib.php index a6c1bc13df..c32ab5c1fd 100644 --- a/webservice/soap/lib.php +++ b/webservice/soap/lib.php @@ -108,7 +108,6 @@ final class soap_server extends webservice_server { $classpath = optional_param('classpath',null,PARAM_ALPHANUM); } require_once(dirname(__FILE__) . '/../../'.$classpath.'/external.php'); - /// run the server if(isset($_GET['wsdl'])) { $autodiscover = new Zend_Soap_AutoDiscover(); diff --git a/webservice/soap/testclient/zend_soap_client.php b/webservice/soap/testclient/zend/zend_soap_client.php similarity index 72% rename from webservice/soap/testclient/zend_soap_client.php rename to webservice/soap/testclient/zend/zend_soap_client.php index c753fc89f6..88b68fe613 100644 --- a/webservice/soap/testclient/zend_soap_client.php +++ b/webservice/soap/testclient/zend/zend_soap_client.php @@ -28,13 +28,22 @@ * Zend Soap sclient */ -require_once('../../../config.php'); -require_once('../lib.php'); +require_once('../../../../config.php'); +require_once('../../lib.php'); + + + include "Zend/Loader.php"; Zend_Loader::registerAutoload(); +$PAGE->set_course($COURSE); +$PAGE->set_url('webservice/soap/testclient/zend/zend_soap_client.php'); + ///Display Moodle page header -print_header('Soap test client', 'Soap test client'.":", true); +$PAGE->set_title('Soap test client'); +$PAGE->set_heading('Soap test client'); +echo $OUTPUT->header(); +//print_header('Soap test client', 'Soap test client'.":", true); /// check that webservices are enable into your Moodle /// WARNING: it makes sens here only because this client runs on the same machine as the @@ -43,16 +52,34 @@ if (!webservice_lib::display_webservices_availability("soap")) { echo "

"; echo "Please fix the previous problem(s), the testing session has been interupted."; echo $OUTPUT->footer(); + // print_footer(); exit(); } +/// Following some code in order to print the authentication WSDL into the end of the source code page +/* + $client = new Zend_Http_Client($CFG->wwwroot."/webservice/soap/server.php?wsdl", array( + 'maxredirects' => 0, + 'timeout' => 30)); + $response = $client->request(); + $wsdl = $response->getBody(); + print $wsdl; + exit(); +*/ + + /// authenticate => get a conversation token from the server /// You need a wsuser/wspassword user in the remote Moodle $client = new Zend_Soap_Client($CFG->wwwroot."/webservice/soap/server.php?wsdl"); try { + + $params = new stdClass(); + $params->username = 'wsuser'; + $params->password = 'wspassword'; $token = $client->get_token(array('username' => "wsuser", 'password' => "wspassword")); + //$token = $client->get_token($params); print "
\n";
-     print "

Token: ".$token; + print "

Token: ".$token; print "
"; } catch (exception $exception) { print "

An exception occured during authentication: \n"; @@ -64,17 +91,16 @@ try { /// Following some code in order to print the WSDL into the end of the source code page /// Change the classpath to get specific service -/* - $client = new Zend_Http_Client($CFG->wwwroot."/webservice/soap/server.php?token=".$token."&classpath=user&wsdl", array( - 'maxredirects' => 0, - 'timeout' => 30)); - $response = $client->request(); - $wsdl = $response->getBody(); - print $wsdl; - exit(); - * - */ - +/** + $client = new Zend_Http_Client($CFG->wwwroot."/webservice/soap/server.php?token=".$token."&classpath=user&wsdl", array( + 'maxredirects' => 0, + 'timeout' => 30)); + $response = $client->request(); + $wsdl = $response->getBody(); + print $wsdl; + exit(); + **/ + /// build the Zend SOAP client from the remote WSDL $client = new Zend_Soap_Client($CFG->wwwroot."/webservice/soap/server.php?token=".$token."&classpath=user&wsdl"); @@ -97,7 +123,13 @@ print ""; print "

Create user:"; print "
\n";
 try {
-    var_dump($client->create_users(array(array('username' => "mockuser66",'firstname' => "firstname6",'lastname' => "lastname6",'email' => "mockuser6@mockuser6.com",'password' => "password6"))));
+    $user = new stdClass();
+    $user->password = "password6";
+    $user->email = "mockuser6@mockuser6.com";
+    $user->username = "mockuser66";
+    $user->firstname = "firstname6";
+    $user->lastname = "lastname6";
+    var_dump($client->create_users(array('users' => array($user))));
 } catch (exception $exception) {
     print $exception;
     print "

An exception occured: \n"; @@ -109,7 +141,12 @@ print "
"; print "

Update user:"; print "
\n";
 try {
-    var_dump($client->update_users(array(array('username' => "mockuser66",'newusername' => "mockuser6b",'firstname' => "firstname6b"))));
+    $user1 = new stdClass();
+    $user1->email = "mockuser6@mockuser6.com";
+    $user1->username = "mockuser66";
+    $user1->newusername = 'mockuser6b';
+    $user1->firstname = "firstname6b";
+    var_dump($client->update_users(array('users' => array($user1))));
 } catch (exception $exception) {
     print $exception;
     print "

An exception occured: \n"; @@ -121,7 +158,7 @@ print "
"; print "

Delete user:"; print "
\n";
 try {
-    var_dump($client->delete_users(array(array('username' => "mockuser6b"))));
+    var_dump($client->delete_users(array('usernames' => array("mockuser6b"))));
 } catch (exception $exception) {
     print $exception;
     print "

An exception occured: \n"; @@ -131,6 +168,7 @@ print "
"; /// Display Moodle page footer echo $OUTPUT->footer(); +//print_footer(); /** @@ -144,4 +182,4 @@ function printLastRequestResponse($client) { print ""; } -?> +?> \ No newline at end of file diff --git a/webservice/wsdoc.php b/webservice/wsdoc.php new file mode 100644 index 0000000000..e612e228e1 --- /dev/null +++ b/webservice/wsdoc.php @@ -0,0 +1,265 @@ +. // +// // +/////////////////////////////////////////////////////////////////////////// + +/** + * This file generate a web service documentation in HTML + * This documentation describe how to call a Moodle Web Service + */ +require_once('../config.php'); +require_once('lib.php'); +$protocol = optional_param('protocol',"soap",PARAM_ALPHA); + +/// PAGE settings +$PAGE->set_course($COURSE); +$PAGE->set_url('webservice/wsdoc.php'); +$PAGE->set_title(get_string('wspagetitle', 'webservice')); +$PAGE->set_heading(get_string('wspagetitle', 'webservice')); +echo $OUTPUT->header(); +webservice_lib::display_webservices_availability($protocol); +generate_documentation($protocol); +generate_functionlist(); +echo $OUTPUT->footer(); + + + +/** + * Generate documentation specific to a protocol + * @param string $protocol + */ +function generate_documentation($protocol) { + switch ($protocol) { + + case "soap": + $documentation = get_string('soapdocumentation','webservice'); + break; + case "xmlrpc": + $documentation = get_string('xmlrpcdocumentation','webservice'); + break; + default: + break; + } + echo $documentation; + echo "".get_string('wsuserreminder','webservice').""; + +} + + +/** + * Generate web service function list + * @global object $CFG + */ +function generate_functionlist () { + global $CFG; + $documentation = "

".get_string('functionlist','webservice')."

"; + + //retrieve all external file + $externalfiles = array(); + $externalfunctions = array(); + setListApiFiles($externalfiles, $CFG->dirroot); + + foreach ($externalfiles as $file) { + require($file); + + $classpath = substr($file,strlen($CFG->dirroot)+1); //remove the dir root + / from the file path + $classpath = substr($classpath,0,strlen($classpath) - 13); //remove /external.php from the classpath + $classpath = str_replace('/','_',$classpath); //convert all / into _ + $classname = $classpath."_external"; + $api = new $classname(); + $documentation .= "

".get_string('moodlepath','webservice').": ".$classpath."