MDL-16094 File storage conversion Quiz and Questions
[moodle.git] / webservice / wsdoc.php
1 <?php
2 ///////////////////////////////////////////////////////////////////////////
3 //                                                                       //
4 // This file is part of Moodle - http://moodle.org/                      //
5 // Moodle - Modular Object-Oriented Dynamic Learning Environment         //
6 //                                                                       //
7 // Moodle is free software: you can redistribute it and/or modify        //
8 // it under the terms of the GNU General Public License as published by  //
9 // the Free Software Foundation, either version 3 of the License, or     //
10 // (at your option) any later version.                                   //
11 //                                                                       //
12 // Moodle is distributed in the hope that it will be useful,             //
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of        //
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
15 // GNU General Public License for more details.                          //
16 //                                                                       //
17 // You should have received a copy of the GNU General Public License     //
18 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.       //
19 //                                                                       //
20 ///////////////////////////////////////////////////////////////////////////
23 // disable moodle specific debug messages and any errors in output
24 define('NO_MOODLE_COOKIES', true);
26 require_once('../config.php');
27 require_once('lib.php');
30 /**
31  * This class generate the web service documentation specific to one
32  * web service user
33  * @package   webservice
34  * @copyright 2009 Moodle Pty Ltd (http://moodle.com)
35  * @author    Jerome Mouneyrac
36  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37  */
38 class webservice_documentation_generator {
40     /** @property array all external function description*/
41     protected $functions;
43      /** @property string $username name of local user */
44     protected $username = null;
46     /** @property string $password password of the local user */
47     protected $password = null;
49     /** @property string $token token of the local user */
50     protected $token = null;
52     /** @property object $webserviceuser authenticated web service user */
53     protected $webserviceuser = null;
55     /**
56      * Contructor
57      */
58     public function __construct() {
59         $this->functionsdescriptions = array();
60         $this->functions = array();
61     }
63     /**
64      * Run the documentation generation
65      * @return void
66      */
67     public function run() {
69         // init all properties from the request data
70         $this->get_authentication_parameters();
72         // this sets up $this->webserviceuser
73         try {
74             $this->authenticate_user();
75         } catch(moodle_exception $e) {
76             $errormessage = $e->debuginfo;
77             $displayloginpage = true;
78         }
80         if (!empty($displayloginpage)){
81             $this->display_login_page_html($errormessage);
82         } else {
83             // make a descriptions list of all function that user is allowed to excecute
84             $this->generate_documentation();
86             //finally display the documentation
87             $this->display_documentation_html();
88         }
90         die;
91     }
94 ///////////////////////////
95 /////// CLASS METHODS /////
96 ///////////////////////////
98     /**
99      * This method parses the $_REQUEST superglobal and looks for
100      * the following information:
101      *  user authentication - username+password
102      * @return void
103      */
104     protected function get_authentication_parameters() {
105             if (isset($_REQUEST['wsusername'])) {
106                 $this->username = $_REQUEST['wsusername'];
107             }
108             if (isset($_REQUEST['wspassword'])) {
109                 $this->password = $_REQUEST['wspassword'];
110             }
111             if (isset($_REQUEST['token'])) {
112                 $this->token = $_REQUEST['token'];
113             }
114     }
116     /**
117      * Generate the documentation specific to the auhenticated webservice user
118      * @return void
119      */
120     protected function generate_documentation() {
121         global $DB;
123     /// first of all get a complete list of services user is allowed to access
124         $params = array();
125         $wscond1 = '';
126         $wscond2 = '';
128         // make sure the function is listed in at least one service user is allowed to use
129         // allow access only if:
130         //  1/ entry in the external_services_users table if required
131         //  2/ validuntil not reached
132         //  3/ has capability if specified in service desc
133         //  4/ iprestriction
135         $sql = "SELECT s.*, NULL AS iprestriction
136                   FROM {external_services} s
137                   JOIN {external_services_functions} sf ON (sf.externalserviceid = s.id AND s.restrictedusers = 0)
138                  WHERE s.enabled = 1 $wscond1
140                  UNION
142                 SELECT s.*, su.iprestriction
143                   FROM {external_services} s
144                   JOIN {external_services_functions} sf ON (sf.externalserviceid = s.id AND s.restrictedusers = 1)
145                   JOIN {external_services_users} su ON (su.externalserviceid = s.id AND su.userid = :userid)
146                  WHERE s.enabled = 1 AND su.validuntil IS NULL OR su.validuntil < :now $wscond2";
148         $params = array_merge($params, array('userid'=>$this->webserviceuser->id, 'now'=>time()));
150         $serviceids = array();
151         $rs = $DB->get_recordset_sql($sql, $params);
153         // make sure user may access at least one service
154         $allowed = false;
155         foreach ($rs as $service) {
156             if (isset($serviceids[$service->id])) {
157                 continue;
158             }
159             if ($service->requiredcapability and !has_capability($service->requiredcapability, $this->restricted_context)) {
160                 continue; // cap required, sorry
161             }
162             $serviceids[$service->id] = $service->id;
163         }
164         $rs->close();
166         // now get the list of all functions
167         if ($serviceids) {
168             list($serviceids, $params) = $DB->get_in_or_equal($serviceids);
169             $sql = "SELECT f.*
170                       FROM {external_functions} f
171                      WHERE f.name IN (SELECT sf.functionname
172                                         FROM {external_services_functions} sf
173                                        WHERE sf.externalserviceid $serviceids)";
174             $functions = $DB->get_records_sql($sql, $params);
175         } else {
176             $functions = array();
177         }
179         foreach ($functions as $function) {
180             $this->functions[$function->name] = external_function_info($function);
181         }
182     }
184      /**
185      * Authenticate user using username+password
186      * This function sets up $this->webserviceuser.
187      * called into the Moodle header
188      * @return void
189      */
190     protected function authenticate_user() {
191         global $CFG, $DB;
193         if (!NO_MOODLE_COOKIES) {
194             throw new coding_exception('Cookies must be disabled!');
195         }
197         if (!$this->token) {
198             if (!is_enabled_auth('webservice')) {
199                 throw new webservice_access_exception(get_string('wsauthnotenabled', 'webservice'));
200             }
202             if (!$auth = get_auth_plugin('webservice')) {
203                 throw new webservice_access_exception(get_string('wsauthmissing', 'webservice'));
204             }
206             if (!$this->username) {
207                 throw new webservice_access_exception(get_string('missingusername', 'webservice'));
208             }
210             if (!$this->password) {
211                 throw new webservice_access_exception(get_string('missingpassword', 'webservice'));
212             }
214             if (!$auth->user_login_webservice($this->username, $this->password)) {
215                 throw new webservice_access_exception(get_string('wrongusernamepassword', 'webservice'));
216             }
218             $this->webserviceuser = $DB->get_record('user', array('username'=>$this->username, 'mnethostid'=>$CFG->mnet_localhost_id, 'deleted'=>0), '*', MUST_EXIST);
219         } else {
221             if (!$token = $DB->get_record('external_tokens', array('token'=>$this->token, 'tokentype'=>EXTERNAL_TOKEN_PERMANENT))) {
222                 // log failed login attempts
223                 throw new webservice_access_exception(get_string('invalidtoken', 'webservice'));
224             }
226             if ($token->validuntil and $token->validuntil < time()) {
227                 throw new webservice_access_exception(get_string('invalidtimedtoken', 'webservice'));
228             }
230             if ($token->iprestriction and !address_in_subnet(getremoteaddr(), $token->iprestriction)) {
231                 throw new webservice_access_exception(get_string('invalidiptoken', 'webservice'));
232             }
234             $this->webserviceuser = $DB->get_record('user', array('id'=>$token->userid, 'deleted'=>0), '*', MUST_EXIST);
236             // log token access
237             $DB->set_field('external_tokens', 'lastaccess', time(), array('id'=>$token->id));
238         }
242     }
244 ////////////////////////////////////////////////
245 ///// DISPLAY METHODS                      /////
246 ////////////////////////////////////////////////
248     /**
249      * Generate and display the documentation
250      */
251     protected function display_documentation_html() {
252         global $PAGE, $OUTPUT, $SITE, $CFG;
254         $PAGE->set_context(get_context_instance(CONTEXT_SYSTEM));
255         $PAGE->set_url('/webservice/wsdoc');
256         $PAGE->set_docs_path('');
257         $PAGE->set_title($SITE->fullname." ".get_string('wsdocumentation', 'webservice'));
258         $PAGE->set_heading($SITE->fullname." ".get_string('wsdocumentation', 'webservice'));
259         $PAGE->set_pagelayout('popup');
260         $PAGE->set_pagetype('webservice-doc-generator');
262         echo $OUTPUT->header();
264         $activatedprotocol = array();
265         $activatedprotocol['rest'] = webservice_protocol_is_enabled('rest');
266         $activatedprotocol['xmlrpc'] = webservice_protocol_is_enabled('xmlrpc');
267         $renderer = $PAGE->get_renderer('core', 'webservice');
268         /// Check if we are in printable mode
269         $printableformat = false;
270         if (isset($_REQUEST['print'])) {
271             $printableformat = $_REQUEST['print'];
272         }
274         $authparams = array();
275         if (empty($this->token)) {
276             $authparams['wsusername'] = $this->username;
277             $authparams['wspassword'] = $this->password;
278         } else {
279             $authparams['wsusername'] = $this->webserviceuser->username;
280             $authparams['token'] = $this->token;
281         }
283         echo $renderer->documentation_html($this->functions, $printableformat, $activatedprotocol, $authparams);
285         /// trigger browser print operation
286         if (!empty($printableformat)) {
287             $PAGE->requires->js_function_call('window.print', array());
288         }
290         echo $OUTPUT->footer();
292     }
294     /**
295      * Display login page to the web service documentation
296      * @global object $PAGE
297      * @global object $OUTPUT
298      * @global object $SITE
299      * @global object $CFG
300      * @param string $errormessage error message displayed if wrong login
301      */
302      protected function display_login_page_html($errormessage) {
303         global $PAGE, $OUTPUT, $SITE, $CFG;
305         $PAGE->set_context(get_context_instance(CONTEXT_SYSTEM));
306         $PAGE->set_url('/webservice/wsdoc');
307         $PAGE->set_docs_path('');
308         $PAGE->set_title($SITE->fullname." ".get_string('wsdocumentation', 'webservice'));
309         $PAGE->set_heading($SITE->fullname." ".get_string('wsdocumentation', 'webservice'));
310         $PAGE->set_pagelayout('popup');
311         $PAGE->set_pagetype('webservice-doc-generator-login');
313         echo $OUTPUT->header();
315         $renderer = $PAGE->get_renderer('core', 'webservice');
316         echo $renderer->login_page_html($errormessage);
318         echo $OUTPUT->footer();
320     }
325 ///////////////////////////
326 /////// RUN THE SCRIPT ////
327 ///////////////////////////
329 if (empty($CFG->enablewsdocumentation)) {
330     echo get_string('wsdocumentationdisable', 'webservice');
331     die;
334 //run the documentation generator
335 $generator = new webservice_documentation_generator();
336 $generator->run();
337 die;