From c1b658832df8df2c2c7e408efecf21bd92d5e268 Mon Sep 17 00:00:00 2001 From: Jerome Mouneyrac Date: Wed, 8 Jun 2011 15:10:26 +0800 Subject: [PATCH] MDL-27551 add enable mobile feature (enable web services + mobile service - add mobile builtin service - add unique shortname for service) --- admin/settings/plugins.php | 3 + lang/en/admin.php | 3 + lang/en/webservice.php | 2 + lib/adminlib.php | 156 +++++++++++++++++++++++++++++++++++++ lib/db/install.xml | 5 +- lib/db/services.php | 10 +++ lib/db/upgrade.php | 13 ++++ lib/moodlelib.php | 4 + lib/upgradelib.php | 28 +++++++ version.php | 2 +- webservice/lib.php | 13 ++++ 11 files changed, 236 insertions(+), 3 deletions(-) diff --git a/admin/settings/plugins.php b/admin/settings/plugins.php index bf8060500e5..f64122b3f47 100644 --- a/admin/settings/plugins.php +++ b/admin/settings/plugins.php @@ -324,6 +324,9 @@ if ($hassiteconfig) { $ADMIN->add('webservicesettings', $temp); /// manage service $temp = new admin_settingpage('externalservices', get_string('externalservices', 'webservice')); + $enablemobiledocurl = new moodle_url(get_docs_url('Enable_mobile_web_services')); + $enablemobiledoclink = html_writer::tag('a', get_string('documentation'),array('href'=>$enablemobiledocurl)); + $temp->add(new admin_setting_enablemobileservice('enablemobilewebservice', get_string('enablemobilewebservice', 'admin'), get_string('configenablemobilewebservice', 'admin', $enablemobiledoclink), 0)); $temp->add(new admin_setting_heading('manageserviceshelpexplaination', get_string('information', 'webservice'), get_string('servicehelpexplanation', 'webservice'))); $temp->add(new admin_setting_manageexternalservices()); $ADMIN->add('webservicesettings', $temp); diff --git a/lang/en/admin.php b/lang/en/admin.php index 09817efec35..b6c3c09141a 100644 --- a/lang/en/admin.php +++ b/lang/en/admin.php @@ -202,6 +202,7 @@ $string['configenablecourserequests'] = 'This will allow any user to request a c $string['configenableglobalsearch'] = 'This setting enables global text searching in resources and activities, it is not compatible with PHP 4.'; $string['configenablegroupmembersonly'] = 'If enabled, access to activities can be restricted to group members only. This may result in an increased server load. In addition, gradebook categories must be set up in a certain way to ensure that activities are hidden from non-group members.'; $string['configenablehtmlpurifier'] = 'Use HTML Purifier instead of KSES for cleaning of untrusted text. HTML Purifier is actively developed and is believed to be more secure, but it is more resource intensive. Expect minor visual differences in the resulting html code. Please note that embed and object tags can not be enabled, MathML tags and old lang tags are not supported.'; +$string['configenablemobilewebservice'] = 'Enable mobile service for the official Moodle app or other app requesting it. For more information, read the {$a}'; $string['configenablerssfeeds'] = 'This switch will enable RSS feeds from across the site. To actually see any change you will need to enable RSS feeds in the individual modules too - go to the Modules settings under Admin Configuration.'; $string['configenablerssfeedsdisabled'] = 'It is not available because RSS feeds are disabled in all the Site. To enable them, go to the Variables settings under Admin Configuration.'; $string['configenablerssfeedsdisabled2'] = 'RSS feeds are disabled at the server level. You need to enable them first in Server/RSS.'; @@ -494,6 +495,7 @@ $string['enablecourserequests'] = 'Enable course requests'; $string['enableglobalsearch'] = 'Enable global search'; $string['enablegroupmembersonly'] = 'Enable group members only'; $string['enablehtmlpurifier'] = 'Enable HTML Purifier'; +$string['enablemobilewebservice'] = 'Enable mobile web service'; $string['enablerecordcache'] = 'Enable record cache'; $string['enablerssfeeds'] = 'Enable RSS feeds'; $string['enablesafebrowserintegration'] = 'Enable Safe Exam Browser integration'; @@ -752,6 +754,7 @@ $string['neverdeleteruns'] = 'Never delete runs'; $string['nobookmarksforuser'] = 'You do not have any bookmarks.'; $string['nodatabase'] = 'No database'; $string['nochanges'] = 'No changes'; +$string['nohttpsformobilewarning'] = 'It is recommended to enable HTTPS with a valid certificate. The Moodle app will always try to use a secured connection first.'; $string['nolangupdateneeded'] = 'All your language packs are up to date, no update is needed'; $string['nomissingstrings'] = 'No missing strings'; $string['nonewsettings'] = 'No new settings were added during this upgrade.'; diff --git a/lang/en/webservice.php b/lang/en/webservice.php index f184bc6b046..96339368887 100644 --- a/lang/en/webservice.php +++ b/lang/en/webservice.php @@ -99,6 +99,8 @@ $string['generalstructure'] = 'General structure'; $string['checkusercapability'] = 'Check user capability'; $string['checkusercapabilitydescription'] = 'The user should have appropriate capabilities according to the protocols used, for example webservice/rest:use, webservice/soap:use. To achieve this, create a web services role with protocol capabilities allowed and assign it to the web services user as a system role.'; $string['information'] = 'Information'; +$string['installserviceshortnameerror'] = 'Coding error: the service shortname "{$a}" should have contains numbers, letters and _-.. only.'; +$string['installexistingserviceshortnameerror'] = 'A web service with the shortname "{$a}" already exists. Can not install/update a different web service with this shortname.'; $string['invalidextparam'] = 'Invalid external api parameter: {$a}'; $string['invalidextresponse'] = 'Invalid external api response: {$a}'; $string['invalidiptoken'] = 'Invalid token - your IP is not supported'; diff --git a/lib/adminlib.php b/lib/adminlib.php index 49289ddc1ff..8dce74366ec 100644 --- a/lib/adminlib.php +++ b/lib/adminlib.php @@ -6381,6 +6381,162 @@ class admin_setting_managerepository extends admin_setting { } } +/** + * Special checkbox for enable mobile web service + * If enable then we store the service id of the mobile service into config table + * If disable then we unstore the service id from the config table + */ +class admin_setting_enablemobileservice extends admin_setting_configcheckbox { + + private $xmlrpcuse; //boolean: true => capability 'webservice/xmlrpc:use' is set for authenticated user role + + /** + * Return true if Authenticated user role has the capability 'webservice/xmlrpc:use', otherwise false + * @return boolean + */ + private function is_xmlrpc_cap_allowed() { + global $DB, $CFG; + + //if the $this->xmlrpcuse variable is not set, it needs to be set + if (empty($this->xmlrpcuse) and $this->xmlrpcuse!==false) { + $params = array(); + $params['permission'] = CAP_ALLOW; + $params['roleid'] = $CFG->defaultuserroleid; + $params['capability'] = 'webservice/xmlrpc:use'; + $this->xmlrpcuse = $DB->record_exists('role_capabilities', $params); + } + + return $this->xmlrpcuse; + } + + /** + * Set the 'webservice/xmlrpc:use' to the Authenticated user role (allow or not) + * @param type $status true to allow, false to not set + */ + private function set_xmlrpc_cap($status) { + global $CFG; + if ($status and !$this->is_xmlrpc_cap_allowed()) { + //need to allow the cap + $permission = CAP_ALLOW; + $assign = true; + } else if (!$status and $this->is_xmlrpc_cap_allowed()){ + //need to disallow the cap + $permission = CAP_INHERIT; + $assign = true; + } + if (!empty($assign)) { + $systemcontext = get_system_context(); + assign_capability('webservice/xmlrpc:use', $permission, $CFG->defaultuserroleid, $systemcontext->id, true); + } + } + + /** + * Builds XHTML to display the control. + * The main purpose of this overloading is to display a warning when https + * is not supported by the server + * @param string $data Unused + * @param string $query + * @return string XHTML + */ + public function output_html($data, $query='') { + global $CFG, $OUTPUT; + $html = parent::output_html($data, $query); + + if ((string)$data === $this->yes) { + require_once($CFG->dirroot . "/lib/filelib.php"); + $curl = new curl(); + $httpswwwroot = str_replace('http:', 'https:', $CFG->wwwroot); //force https url + $curl->head($httpswwwroot . "/login/index.php"); + $info = $curl->get_info(); + if (empty($info['http_code']) or ($info['http_code'] >= 400)) { + $html .= $OUTPUT->notification(get_string('nohttpsformobilewarning', 'admin')); + } + } + + return $html; + } + + /** + * Retrieves the current setting using the objects name + * + * @return string + */ + public function get_setting() { + global $CFG; + $webservicesystem = $CFG->enablewebservices; + require_once($CFG->dirroot . '/webservice/lib.php'); + $webservicemanager = new webservice(); + $mobileservice = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE); + if ($mobileservice->enabled and !empty($webservicesystem) and $this->is_xmlrpc_cap_allowed()) { + return $this->config_read($this->name); //same as returning 1 + } else { + return 0; + } + } + + /** + * Save the selected setting + * + * @param string $data The selected site + * @return string empty string or error message + */ + public function write_setting($data) { + global $DB, $CFG; + $servicename = MOODLE_OFFICIAL_MOBILE_SERVICE; + + require_once($CFG->dirroot . '/webservice/lib.php'); + $webservicemanager = new webservice(); + + if ((string)$data === $this->yes) { + //code run when enable mobile web service + //enable web service systeme if necessary + set_config('enablewebservices', true); + + //enable mobile service + $mobileservice = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE); + $mobileservice->enabled = 1; + $webservicemanager->update_external_service($mobileservice); + + //enable xml-rpc server + $active_protocols = empty($CFG->webserviceprotocols) ? array() : explode(',', $CFG->webserviceprotocols); + + if (!in_array('xmlrpc', $active_protocols)) { + $active_protocols[] = 'xmlrpc'; + set_config('webserviceprotocols', implode(',', $active_protocols)); + } + + //allow xml-rpc:use capability for authenticated user + $this->set_xmlrpc_cap(true); + + } else { + //disable web service system if no other services are enabled + $otherenabledservices = $DB->get_records_select('external_services', + 'enabled = :enabled AND (shortname != :shortname OR shortname IS NULL)', array('enabled' => 1, + 'shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE)); + if (empty($otherenabledservices)) { + set_config('enablewebservices', false); + + //also disable xml-rpc server + $active_protocols = empty($CFG->webserviceprotocols) ? array() : explode(',', $CFG->webserviceprotocols); + $protocolkey = array_search('xmlrpc', $active_protocols); + if ($protocolkey !== false) { + unset($active_protocols[$protocolkey]); + set_config('webserviceprotocols', implode(',', $active_protocols)); + } + + //disallow xml-rpc:use capability for authenticated user + $this->set_xmlrpc_cap(false); + } + + //disable the mobile service + $mobileservice = $webservicemanager->get_external_service_by_shortname(MOODLE_OFFICIAL_MOBILE_SERVICE); + $mobileservice->enabled = 0; + $webservicemanager->update_external_service($mobileservice); + } + + return (parent::write_setting($data)); + } +} /** * Special class for management of external services diff --git a/lib/db/install.xml b/lib/db/install.xml index 5c1397d2a94..1a1f7a6d728 100644 --- a/lib/db/install.xml +++ b/lib/db/install.xml @@ -1,5 +1,5 @@ - @@ -2484,7 +2484,8 @@ - + + diff --git a/lib/db/services.php b/lib/db/services.php index 51cf05bae67..3e550dff549 100644 --- a/lib/db/services.php +++ b/lib/db/services.php @@ -207,3 +207,13 @@ $functions = array( ), ); + +$services = array( + 'Moodle mobile web service' => array( + 'functions' => array ('moodle_enrol_get_users_courses', 'moodle_enrol_get_enrolled_users', + 'moodle_user_get_users_by_id'), + 'enabled' => 0, + 'restrictedusers' => 0, + 'shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE + ), +); \ No newline at end of file diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index 2918eb1bde4..63a1cb26f4e 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -6112,6 +6112,19 @@ WHERE gradeitemid IS NOT NULL AND grademax IS NOT NULL"); upgrade_main_savepoint(true, 2011052300.02); } + if ($oldversion < 2011060200.039) { //TODO: put the right latest version + // Define field shortname to be added to external_services + $table = new xmldb_table('external_services'); + $field = new xmldb_field('shortname', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'timemodified'); + + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + // Conditionally launch add field shortname + // Main savepoint reached + upgrade_main_savepoint(true, 2011060200.039); + } return true; } diff --git a/lib/moodlelib.php b/lib/moodlelib.php index 3dee9f948be..9e6686ad4d2 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -424,6 +424,10 @@ define('HUB_HUBDIRECTORYURL', "http://hubdirectory.moodle.org"); */ define('HUB_MOODLEORGHUBURL', "http://hub.moodle.org"); +/** + * Moodle mobile app service name + */ +define('MOODLE_OFFICIAL_MOBILE_SERVICE', 'moodle_mobile_app'); /// PARAMETER HANDLING //////////////////////////////////////////////////// diff --git a/lib/upgradelib.php b/lib/upgradelib.php index 976d59a59bb..65c7db3d4ae 100644 --- a/lib/upgradelib.php +++ b/lib/upgradelib.php @@ -895,6 +895,7 @@ function external_update_descriptions($component) { $service['enabled'] = empty($service['enabled']) ? 0 : $service['enabled']; $service['requiredcapability'] = empty($service['requiredcapability']) ? null : $service['requiredcapability']; $service['restrictedusers'] = !isset($service['restrictedusers']) ? 1 : $service['restrictedusers']; + $service['shortname'] = !isset($service['shortname']) ? null : $service['shortname']; $update = false; if ($dbservice->enabled != $service['enabled']) { @@ -909,6 +910,23 @@ function external_update_descriptions($component) { $dbservice->restrictedusers = $service['restrictedusers']; $update = true; } + //if shortname is not a PARAM_ALPHANUMEXT, fail (tested here for service update and creation) + if (isset($service['shortname']) and + (clean_param($service['shortname'], PARAM_ALPHANUMEXT) != $service['shortname'])) { + throw new moodle_exception('installserviceshortnameerror', 'webservice', '', $service['shortname']); + } + if ($dbservice->shortname != $service['shortname']) { + //check that shortname is unique + if (isset($service['shortname'])) { //we currently accepts multiple shortname == null + $existingservice = $DB->get_record('external_services', + array('shortname' => $service['shortname'])); + if (!empty($existingservice)) { + throw new moodle_exception('installexistingserviceshortnameerror', 'webservice', '', $service['shortname']); + } + } + $dbservice->shortname = $service['shortname']; + $update = true; + } if ($update) { $DB->update_record('external_services', $dbservice); } @@ -931,11 +949,21 @@ function external_update_descriptions($component) { unset($functions); } foreach ($services as $name => $service) { + //check that shortname is unique + if (isset($service['shortname'])) { //we currently accepts multiple shortname == null + $existingservice = $DB->get_record('external_services', + array('shortname' => $service['shortname'])); + if (!empty($existingservice)) { + throw new moodle_exception('installserviceshortnameerror', 'webservice'); + } + } + $dbservice = new stdClass(); $dbservice->name = $name; $dbservice->enabled = empty($service['enabled']) ? 0 : $service['enabled']; $dbservice->requiredcapability = empty($service['requiredcapability']) ? null : $service['requiredcapability']; $dbservice->restrictedusers = !isset($service['restrictedusers']) ? 1 : $service['restrictedusers']; + $dbservice->shortname = !isset($service['shortname']) ? null : $service['shortname']; $dbservice->component = $component; $dbservice->timecreated = time(); $dbservice->id = $DB->insert_record('external_services', $dbservice); diff --git a/version.php b/version.php index caaa6ff2258..0f0fc3e2835 100644 --- a/version.php +++ b/version.php @@ -30,7 +30,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2011060200.00; // YYYYMMDD = weekly release date of this DEV branch +$version = 2011060200.039; // YYYYMMDD = weekly release date of this DEV branch // RR = release increments - 00 in DEV branches // .XX = incremental changes diff --git a/webservice/lib.php b/webservice/lib.php index ede94bcfe83..3d73b3a54b0 100644 --- a/webservice/lib.php +++ b/webservice/lib.php @@ -394,6 +394,19 @@ class webservice { return $service; } + /** + * Get a external service for a given shortname + * @param service shortname $shortname + * @param integer $strictness IGNORE_MISSING, MUST_EXIST... + * @return object external service + */ + public function get_external_service_by_shortname($shortname, $strictness=IGNORE_MISSING) { + global $DB; + $service = $DB->get_record('external_services', + array('shortname' => $shortname), '*', $strictness); + return $service; + } + /** * Get a external function for a given id * @param function id $functionid