MDL-20353 adding missing data types of hidden form fields
[moodle.git] / webservice / lib.php
1 <?php
2 /**
3  * Moodle - Modular Object-Oriented Dynamic Learning Environment
4  *         http://moodle.com
5  *
6  * LICENSE
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details:
17  *
18  *         http://www.gnu.org/copyleft/gpl.html
19  *
20  * @category  Moodle
21  * @package   webservice
22  * @copyright Copyright (c) 1999 onwards Martin Dougiamas     http://dougiamas.com
23  * @license   http://www.gnu.org/copyleft/gpl.html     GNU GPL License
24  */
26 require_once(dirname(dirname(__FILE__)) . '/lib/formslib.php');
28 /**
29  * Returns detailed information about external function
30  * @param string $functionname name of external function
31  * @return aray
32  */
33 function ws_get_function_info($functionname) {
34     global $CFG, $DB;
36     $function = $DB->get_record('external_functions', array('name'=>$functionname), '*', MUST_EXIST);
38     $defpath = get_component_directory($function->component);
39     if (!file_exists("$defpath/db/services.php")) {
40         //TODO: maybe better throw invalid parameter exception
41         return null;
42     }
44     $functions = array();
45     include("$defpath/db/services.php");
47     if (empty($functions[$functionname])) {
48         return null;
49     }
51     $desc = $functions[$functionname];
52     if (empty($desc['classpath'])) {
53         $desc['classpath'] = "$defpath/externallib.php";
54     } else {
55         $desc['classpath'] = "$CFG->dirroot/".$desc['classpath'];
56     }
57     $desc['component'] = $function->component;
59     return $desc;
60 }
62 /**
63  * web service library
64  */
65 final class webservice_lib {
67 /**
68  * Return list of all web service protocol into the webservice folder
69  * @global <type> $CFG
70  * @return <type>
71  */
72     public static function get_list_protocols() {
73         global $CFG;
74         $protocols = array();
75         $directorypath = $CFG->dirroot . "/webservice";
76         if( $dh = opendir($directorypath)) {
77             while( false !== ($file = readdir($dh))) {
78                 if( $file == '.' || $file == '..' || $file == 'CVS') {   // Skip '.' and '..'
79                     continue;
80                 }
81                 $path = $directorypath . '/' . $file;
82                 ///browse the subfolder
83                 if( is_dir($path) ) {
84                     if ($file != 'db') { //we don't want to browse the 'db' subfolder of webservice folder
85                         require_once($path."/lib.php");
86                         $classname = $file."_server";
87                         $protocols[] = new $classname;
88                     }
89                 }
90                 ///retrieve api.php file
91                 else {
92                     continue;
93                 }
94             }
95             closedir($dh);
96         }
97         return $protocols;
98     }
100     /**
101      * Temporary Authentication method to be modified/removed
102      * @global <type> $DB
103      * @param <type> $token
104      * @return <type>
105      */
106     public static function mock_check_token($token) {
107     //fake test
108         if ($token == 456) {
109         ///retrieve the user
110             global $DB;
111             $user = $DB->get_record('user', array('username'=>'wsuser', 'mnethostid'=>1));
113             if (empty($user)) {
114                 return false;
115             }
117             return $user;
118         } else {
119             return false;
120         }
121     }
123     /**
124      * Retrieve all external.php from Moodle (except the one of the exception list)
125      * @param <type> $
126      * @param <type> $directorypath
127      * @return boolean true if n
128      */
129     public static function setListApiFiles( &$files, $directorypath ) {
130         global $CFG;
132         if(is_dir($directorypath)) { //check that we are browsing a folder not a file
134             if( $dh = opendir($directorypath)) {
135                 while( false !== ($file = readdir($dh))) {
137                     if( $file == '.' || $file == '..') {   // Skip '.' and '..'
138                         continue;
139                     }
140                     $path = $directorypath . '/' . $file;
141                     ///browse the subfolder
142                     if( is_dir($path) ) {
143                         webservice_lib::setListApiFiles($files, $path);
144                     }
145                     ///retrieve api.php file
146                     else if ($file == "external.php") {
147                             $files[] = $path;
148                         }
149                 }
150                 closedir($dh);
152             }
153         }
155     }
157     public static function services_discovery() {
158         global $CFG, $DB;
159         $externalfiles = array();
160         webservice_lib::setListApiFiles($externalfiles, $CFG->dirroot);
162         $wsnotification = array();
164         //retrieve all saved services
165         $services = $DB->get_records('external_services', array('custom' => 0)); //we only retrieve not custom service
166         $dbservices = array();
167         foreach ($services as $service) {
168             $dbservices[$service->name] = false; //value false will define obsolote status
169         //once we parse all services from the external files
170         }
172         //retrieve all saved servicefunction association including their function name,
173         //service name, function id and service id
175         $servicesfunctions = $DB->get_records_sql("SELECT fs.id as id, fs.enabled as enabled, s.name as servicename, s.id as serviceid, f.name as functionname, f.id as functionid
176                                     FROM {external_services} s, {external_functions} f, {external_services_functions} fs
177                                    WHERE fs.externalserviceid = s.id AND fs.externalfunctionid = f.id AND s.custom = 0");
178         $dbservicesfunctions = array();
179         foreach ($servicesfunctions as $servicefunction) {
180             $dbservicesfunctions[$servicefunction->servicename][$servicefunction->functionname] = array('serviceid' => $servicefunction->serviceid,
181                 'functionid' => $servicefunction->functionid,
182                 'id' => $servicefunction->id,
183                 'notobsolete' => false);
184         //once we parse all services from the external files
185         }
187         foreach ($externalfiles as $file) {
188             require($file);
189             $classpath = substr($file,strlen($CFG->dirroot)+1); //remove the dir root + / from the file path
190             $classpath = substr($classpath,0,strlen($classpath) - 13); //remove /external.php from the classpath
191             $classpath = str_replace('/','_',$classpath); //convert all / into _
192             $classname = $classpath."_external";
193             $api = new $classname();
194             if (method_exists($api, 'get_descriptions')) {
195                 $descriptions = $api->get_descriptions();
197                 //retrieve all saved function into the DB for this specific external file/component
198                 $functions = $DB->get_records('external_functions', array('component' => $classpath));
199                 //remove the obsolete ones
200                 $dbfunctions = array();
201                 foreach ($functions as $function) {
202                     $dbfunctions[$function->name] = false; //value false is not important we just need the key
203                     if (!array_key_exists($function->name, $descriptions)) {
204                     //remove all obsolete function from the db
205                         $DB->delete_records('external_functions', array('name' => $function->name, 'component' => $classpath));
206                     }
207                 }
209                 foreach ($descriptions as $functionname => $functiondescription) {
210                     if (array_key_exists('service', $functiondescription) && !empty($functiondescription['service'])) { //check that the service has been set in the description
211                     //only create the one not already saved into the database
212                         if (!array_key_exists($functionname, $dbfunctions)) {
213                             $newfunction = new object();
214                             $newfunction->component = $classpath;
215                             $newfunction->name = $functionname;
216                             $DB->insert_record('external_functions', $newfunction);
217                             $notifparams = new object();
218                             $notifparams->functionname = $functionname;
219                             $notifparams->servicename = $functiondescription['service'];
220                             $wsnotification[] = get_string('wsinsertfunction','webservice', $notifparams);
221                         }
223                         //check if the service is into the database
224                         if (!array_key_exists($functiondescription['service'], $dbservices)) {
225                             $newservice = new object();
226                             $newservice->name = $functiondescription['service'];
227                             $newservice->enabled = 0;
228                             $newservice->custom = 0;
229                             $DB->insert_record('external_services', $newservice);
230                         }
231                         $dbservices[$functiondescription['service']] = true; //mark the service as not obsolete
232                     //and add it if it wasn't in the list
233                     }
234                     else {
235                         $errors = new object();
236                         $errors->classname = $classname;
237                         $errors->functionname = $functionname;
238                         throw new moodle_exception("wsdescriptionserviceisempty",'','', $errors);
239                     }
241                     //check if the couple service/function is into the database
242                     if (!array_key_exists($functiondescription['service'], $dbservicesfunctions) || !array_key_exists($functionname, $dbservicesfunctions[$functiondescription['service']])) {
243                         $newassociation = new object();
244                         $newassociation->externalserviceid = $DB->get_field('external_services','id',array('name' => $functiondescription['service']));
245                         $newassociation->externalfunctionid = $DB->get_field('external_functions','id',array('name' => $functionname, 'component' => $classpath));
246                         $newassociation->enabled = 0;
247                         $DB->insert_record('external_services_functions', $newassociation);
248                     }
249                     $dbservicesfunctions[$functiondescription['service']][$functionname]['notobsolete'] = true;
250                 }
251             }
252             else {
253                 throw new moodle_exception("wsdoesntextendbaseclass",'','', $classname);
254             }
255         }
257         //remove all obsolete service (not the custom ones)
258         foreach ($dbservices as $servicename => $notobsolete) {
259             if (!$notobsolete) {
260                 $DB->delete_records('external_services', array('name' => $servicename));
261             }
262         }
264         //remove all obsolete association (not the custom ones)
265         foreach ($dbservicesfunctions as $servicename => $servicefunctions ) {
266             foreach ($servicefunctions as $functioname => $servicefunction) {
267                 if (!$servicefunction['notobsolete']) {
268                     $DB->delete_records('external_services_functions', array('id' => $servicefunction['id']));
269                     $notifparams = new object();
270                     $notifparams->functionname = $functionname;
271                     $notifparams->servicename = $servicename;
272                     $wsnotification[] = get_string('wsdeletefunction','webservice', $notifparams);
273                 }
274             }
275         }
277         return $wsnotification;
278     }
280     /**
281      * Check if the Moodle site has the web service protocol enable
282      * @global object $CFG
283      * @param string $protocol
284      */
285     function display_webservices_availability($protocol) {
286         global $CFG;
288         $available = true;
290         echo get_string('webservicesenable','webservice').": ";
291         if (empty($CFG->enablewebservices)) {
292             echo "<strong style=\"color:red\">".get_string('fail','webservice')."</strong>";
293             $available = false;
294         } else {
295             echo "<strong style=\"color:green\">".get_string('ok','webservice')."</strong>";
296         }
297         echo "<br/>";
299         foreach(webservice_lib::get_list_protocols() as $wsprotocol) {
300             if (strtolower($wsprotocol->get_protocolid()) == strtolower($protocol)) {
301                 echo get_string('protocolenable','webservice',array($wsprotocol->get_protocolid())).": ";
302                 if ( get_config($wsprotocol-> get_protocolid(), "enable")) {
303                     echo "<strong style=\"color:green\">".get_string('ok','webservice')."</strong>";
304                 } else {
305                     echo "<strong style=\"color:red\">".get_string('fail','webservice')."</strong>";
306                     $available = false;
307                 }
308                 echo "<br/>";
309                 continue;
310             }
311         }
313         //check debugging
314         if ($CFG->debugdisplay) {
315             echo "<strong style=\"color:red\">".get_string('debugdisplayon','webservice')."</strong>";
316             $available = false;
317         }
319         return $available;
320     }
324 /**
325  * Web Service server base class
326  */
327 abstract class webservice_server {
329 /**
330  * Web Service Protocol name (eg. SOAP, REST, XML-RPC,...)
331  * @var String
332  */
333     private $protocolname;
335     /**
336      * Web Service Protocol id (eg. soap, rest, xmlrpc...)
337      * @var String
338      */
339     private $protocolid;
341     public function __construct() {
342     }
344     abstract public function run();
346     public function get_protocolname() {
347         return $this->protocolname;
348     }
350     public function get_protocolid() {
351         return $this->protocolid;
352     }
354     public function set_protocolname($protocolname) {
355         $this->protocolname = $protocolname;
356     }
358     public function set_protocolid($protocolid) {
359         $this->protocolid = $protocolid;
360     }
362     public function get_enable() {
363         return get_config($this->get_protocolid(), "enable");
364     }
366     public function set_enable($enable) {
367         set_config("enable", $enable, $this->get_protocolid());
368     }
370     /**
371      * Names of the server settings
372      * @return array
373      */
374     public static function get_setting_names() {
375         return array();
376     }
378     public function settings_form(&$mform) {
379     }
383 /**
384  * Temporary authentication class to be removed/modified
385  */
386 class ws_authentication {
387 /**
388  *
389  * @param object|struct $params
390  * @return integer
391  */
392     function get_token($params) {
393         $params->username = clean_param($params->username, PARAM_ALPHANUM);
394         $params->password = clean_param($params->password, PARAM_ALPHANUM);
395         if ($params->username == 'wsuser' && $params->password == 'wspassword') {
396             return '456';
397         } else {
398             throw new moodle_exception('wrongusernamepassword');
399         }
400     }
403 /**
404  * Form for web service user settings (administration)
405  */
406 final class wsuser_form extends moodleform {
407     protected $username;
409     /**
410      * Definition of the moodleform
411      */
412     public function definition() {
413         global $DB;
414         $this->username = $this->_customdata['username'];
415         $mform =& $this->_form;
417         $mform->addElement('hidden', 'username', $this->username);
418         $mform->setType('username', PARAM_RAW);
419         $param = new stdClass();
420         $param->username = $this->username;
421         $wsuser = $DB->get_record("user", array("username" => $this->username));
423         $mform->addElement('text', 'ipwhitelist', get_string('ipwhitelist', 'admin'), array('value'=>get_user_preferences("ipwhitelist", "", $wsuser->id),'size' => '40'));
424         $mform->addElement('static', null, '',  get_string('ipwhitelistdesc','admin', $param));
426         $this->add_action_buttons(true, get_string('savechanges','admin'));
427     }
430 /**
431  * Form for web service server settings (administration)
432  */
433 final class wssettings_form extends moodleform {
434     protected $settings;
436     /**
437      * Definition of the moodleform
438      */
439     public function definition() {
440         global $DB,$CFG;
441         $settings = $this->_customdata['settings'];
442         $mform =& $this->_form;
444         $mform->addElement('hidden', 'settings', $settings);
445         $mform->setType('settings', PARAM_RAW);
446         $param = new stdClass();
448         require_once($CFG->dirroot . '/webservice/'. $settings . '/lib.php');
449         $servername = $settings.'_server';
450         $server = new $servername();
451         $server->settings_form($mform);
453         // set the data if we have some.
454         $data = array();
455         $option_names = $server->get_setting_names();
456         foreach ($option_names as $config) {
457             $data[$config] = get_config($settings, $config);
458         }
459         $this->set_data($data);
462         $this->add_action_buttons(true, get_string('savechanges','admin'));
463     }
466 /**
467  * Form for web service server settings (administration)
468  */
469 final class wsservicesettings_form extends moodleform {
470     protected $settings;
472     /**
473      * Definition of the moodleform
474      */
475     public function definition() {
476         global $DB,$CFG;
477         $serviceid = $this->_customdata['serviceid'];
478         $mform =& $this->_form;
480         $mform->addElement('hidden', 'serviceid', $serviceid);
481         $mform->setType('serviceid', PARAM_INT);
482         $param = new stdClass();
484      //   require_once($CFG->dirroot . '/webservice/'. $settings . '/lib.php');
485       //  $servername = $settings.'_server';
486       //  $server = new $servername();
487       //  $server->settings_form($mform);
489         // set the data if we have some.
490     //    $data = array();
491      //   $option_names = $server->get_setting_names();
492     //    foreach ($option_names as $config) {
493     //        $data[$config] = get_config($settings, $config);
494     //    }
495     //    $this->set_data($data);
496         $service = $DB->get_record('external_services',array('id' => $serviceid));
498         $mform->addElement('text', 'servicename', get_string('servicename', 'webservice'));
499         $mform->setDefault('servicename',get_string($service->name, 'webservice'));
500         if (!empty($serviceid)) {
501             $mform->disabledIf('servicename', 'serviceid', 'eq', $serviceid);
502         }
504         if (empty($serviceid)) {
505             //display list of functions to select
506         }
508         //display list of functions associated to the service
509         
510         
512         $this->add_action_buttons(true,  get_string('savechanges','admin'));
513     }
517 ?>