diff --git a/classes/collabora.php b/classes/collabora.php index 278fd6f..7320c1d 100644 --- a/classes/collabora.php +++ b/classes/collabora.php @@ -280,13 +280,21 @@ private function get_file_mimetype() { private function get_discovery_xml() { $baseurl = trim(get_config('mod_collabora', 'url')); if (!$baseurl) { - throw new \moodle_exception('collaboraurlnotset', 'mod_collabora'); + // Get the product name, if it's already cached. + $cache = \cache::make('mod_collabora', 'capabilities'); + if (!$productname = $cache->get('productname')) { + $productname = get_string('default_server_name', 'mod_collabora'); + } + throw new \moodle_exception('collaboraurlnotset', 'mod_collabora', '', $productname); } $cache = \cache::make('mod_collabora', 'discovery'); if (!$xml = $cache->get($baseurl)) { $url = rtrim($baseurl, '/').'/hosting/discovery'; $curl = new \curl(); $xml = $curl->get($url); + if ($curl->get_errno()) { + return ''; + } $cache->set($baseurl, $xml); } return $xml; @@ -299,8 +307,11 @@ private function get_discovery_xml() { * @return string */ private function get_url_from_mimetype($discoveryxml, $mimetype) { - $xml = new \SimpleXMLElement($discoveryxml); - $app = $xml->xpath("//app[@name='{$mimetype}']"); + $app = null; + if ($discoveryxml) { + $xml = new \SimpleXMLElement($discoveryxml); + $app = $xml->xpath("//app[@name='{$mimetype}']"); + } if (!$app) { throw new \moodle_exception('unsupportedtype', 'mod_collabora', '', $mimetype); } @@ -312,6 +323,75 @@ private function get_url_from_mimetype($discoveryxml, $mimetype) { return (string)$url; } + /** + * Get the capabilities JSON file from the collabora server. + * @return string + */ + private function get_capabilities_json() { + $cache = \cache::make('mod_collabora', 'capabilities'); + if (!$json = $cache->get('json')) { + // Pull it from the discovery.xml. + $app = null; + $discoveryxml = $this->get_discovery_xml(); + if ($discoveryxml) { + $xml = new \SimpleXMLElement($discoveryxml); + $app = $xml->xpath("//app[@name='Capabilities']"); + } + if (!$app) { + throw new \moodle_exception('discovery_error_no_caps_url', 'mod_collabora'); + } + $action = $app[0]->action; + $url = isset($action['urlsrc']) ? $action['urlsrc'] : ''; + if (!$url) { + throw new \moodle_exception('discovery_error_no_caps_url', 'mod_collabora'); + } + + $curl = new \curl(); + $json = $curl->get($url); + if ($curl->get_errno()) { + return ''; + } + $cache->set('json', $json); // Cache the Capabilities JSON file. + } + + return $json; + } + + /** + * Get the product name from the collabora server. + * @return string + */ + public function get_product_name() { + $cache = \cache::make('mod_collabora', 'capabilities'); + if (!$productname = $cache->get('productname')) { + $caps = $this->get_capabilities_json(); + $json = json_decode($caps); + if (isset($json->{'productName'})) { + $productname = $json->{'productName'}; + $cache->set('productname', $productname); + } + } + + return $productname; + } + + /** + * Resets the caches. Useful when the server is changed. + * @return string + */ + public function reset_caches() { + $cache = \cache::make('mod_collabora', 'capabilities'); + $cache->delete('json'); + $cache->delete('productname'); + + // Clear the discovery.xml cache. + $baseurl = trim(get_config('mod_collabora', 'url')); + if ($baseurl) { + $cache = \cache::make('mod_collabora', 'discovery'); + $cache->delete($baseurl); + } + } + /** * Get the URL of the handler, base on the mimetype of the existing file. * @return string diff --git a/db/caches.php b/db/caches.php index 48c2481..1d1e10a 100644 --- a/db/caches.php +++ b/db/caches.php @@ -28,4 +28,7 @@ 'discovery' => [ 'mode' => cache_store::MODE_APPLICATION, ], -]; \ No newline at end of file + 'capabilities' => [ + 'mode' => cache_store::MODE_APPLICATION, + ], +]; diff --git a/lang/en/collabora.php b/lang/en/collabora.php index 4652d4e..484753a 100644 --- a/lang/en/collabora.php +++ b/lang/en/collabora.php @@ -25,12 +25,15 @@ defined('MOODLE_INTERNAL') || die(); $string['cachedef_discovery'] = 'Collabora discovery XML file'; +$string['discovery_error_no_caps_url'] = 'The discovery.xml file does not contain the Capabilities URL'; +$string['cachedef_capabilities'] = 'Capabilities file and fields'; $string['collabora:addinstance'] = 'Add collaborative document to a course'; $string['collabora:editlocked'] = 'Edit a locked collaborative document'; $string['collabora:lock'] = 'Lock/unlock a collaborative document'; $string['collabora:view'] = 'View a collaborative document'; -$string['collaboraurl'] = 'Collabora URL'; -$string['collaboraurlnotset'] = 'Collabora URL is not configured for this site'; +$string['default_server_name'] = 'Collabora Online'; +$string['collaboraurl'] = '{$a} URL'; +$string['collaboraurlnotset'] = '{$a} URL is not configured for this site'; $string['current'] = 'Current tab'; $string['defaultdisplay'] = 'Default display'; $string['defaultdisplaydescription'] = 'Default display description'; diff --git a/settings.php b/settings.php index 1b6a0f9..9e28c51 100644 --- a/settings.php +++ b/settings.php @@ -25,8 +25,35 @@ defined('MOODLE_INTERNAL') || die(); if ($hassiteconfig) { + + $productname = ''; + try { + // If we have a URL, fetch the product name from the server. + // And if we had it, re-fetch it, in case it's changed. + if (get_config('mod_collabora', 'url')) { + $collabora = new \mod_collabora\collabora(0, 0, -1, 0); + // Remove from the cache to force fetching. + $collabora->reset_caches(); + $productname = $collabora->get_product_name(); + } + } catch (Exception $e) { + // For some reason we couldn't discover the server name. + // Possibly the server doesn't have the capabilities file. + $productname = ''; + } + finally { + // Fallback. + if (empty($productname)) { + $cache = \cache::make('mod_collabora', 'capabilities'); + if (!$productname = $cache->get('productname')) { + // If it's not already cached, default, as we are aren't configured yet. + $productname = get_string('default_server_name', 'mod_collabora'); + } + } + } + $settings->add(new admin_setting_configtext('mod_collabora/url', - new lang_string('collaboraurl', 'mod_collabora'), '', '', PARAM_URL)); + new lang_string('collaboraurl', 'mod_collabora', $productname), '', '', PARAM_URL)); $settings->add(new admin_setting_configselect('mod_collabora/defaultformat', new lang_string('defaultformat', 'mod_collabora'), '', diff --git a/version.php b/version.php index d810a15..41759b9 100644 --- a/version.php +++ b/version.php @@ -24,7 +24,7 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2020090100; +$plugin->version = 2020091200; $plugin->requires = 2018051700; // M3.5. $plugin->component = 'mod_collabora'; $plugin->maturity = MATURITY_STABLE;