diff --git a/classes/local/controllers/maintenance_static_page.php b/classes/local/controllers/maintenance_static_page.php index 74f3a33..4c40f06 100644 --- a/classes/local/controllers/maintenance_static_page.php +++ b/classes/local/controllers/maintenance_static_page.php @@ -28,10 +28,6 @@ namespace auth_outage\local\controllers; use auth_outage\local\outage; use coding_exception; use DOMDocument; -use finfo; -use invalid_parameter_exception; -use invalid_state_exception; -use moodle_url; defined('MOODLE_INTERNAL') || die(); @@ -62,7 +58,7 @@ class maintenance_static_page { } else if (PHPUNIT_TEST) { $html = ''; } else { - $data = self::file_get_data($CFG->wwwroot.'/auth/outage/info.php?auth_outage_hide_warning=1&id='.$outage->id); + $data = maintenance_static_page_io::file_get_data($CFG->wwwroot.'/auth/outage/info.php?auth_outage_hide_warning=1&id='.$outage->id); $html = $data['contents']; } @@ -94,331 +90,30 @@ class maintenance_static_page { return new maintenance_static_page($dom); } - /** - * Tries to get the contents of the file or URL. - * @param string $file File to get. - * @return string Contents of $file or an empty string if failed. - */ - private static function file_get_data($file) { - if (self::is_url($file)) { - $curl = curl_init(); - curl_setopt($curl, CURLOPT_URL, $file); - curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); - $contents = curl_exec($curl); - $mime = curl_getinfo($curl, CURLINFO_CONTENT_TYPE); - curl_close($curl); - } else { - $contents = @file_get_contents($file); - $mime = (new finfo(FILEINFO_MIME_TYPE))->buffer($contents); // Not perfect, but try guessing it. - } - if ($contents === false) { - debugging('Cannot fetch: '.$file); - $contents = ''; - $mime = 'unknown'; - } - return ['contents' => $contents, 'mime' => $mime]; - } - - /** - * Checks if the given string starts with "http://" or "https://". - * @param $url - * @return bool - */ - private static function is_url($url) { - return (bool)preg_match('#^http(s)?://#', $url); - } - - /** @var DOMDocument */ - protected $dom; - - /** @var bool */ - protected $preview = false; + /** @var maintenance_static_page_generator */ + protected $generator; /** * maintenance_static_page constructor. * @param DOMDocument|null $dom * @throws coding_exception */ - public function __construct($dom) { - if (!is_null($dom) && !($dom instanceof DOMDocument)) { - throw new coding_exception('$dom must be null or an DOMDocument object.'); - } - $this->dom = $dom; + protected function __construct($dom) { + $io = new maintenance_static_page_io(); + $this->generator = new maintenance_static_page_generator($dom, $io); } /** - * Gets the cli maintenance template file location. - * @return string - */ - public function get_template_file() { - global $CFG; - if ($this->preview) { - return $this->get_resources_folder().'/climaintenance.html'; - } else { - return $CFG->dataroot.'/climaintenance.template.html'; - } - } - - /** - * Gets the resources folder in dataroot. - * - * Warning: this folder will be deleted every time the page is regenerated. - * - * @return string - */ - public function get_resources_folder() { - global $CFG; - - // If you change the path, also change file auth/outage/bootstrap.php as it does not use this reference. - $dir = $CFG->dataroot.'/auth_outage/climaintenance'; - - if ($this->preview) { - $dir = $dir.'/preview'; - } - return $dir; - } - - /** - * Generates the page. + * Requests to generate the static page. */ public function generate() { - $this->cleanup(); - - if (!is_null($this->dom)) { - $this->remove_script_tags(); - $this->update_link_stylesheet(); - $this->update_link_favicon(); - $this->update_images(); - - $html = $this->dom->saveHTML(); - if (trim($html) == '') { - // Should never happen, but just in case... - throw new invalid_state_exception('Sanity check failed, $html is empty.'); - } - file_put_contents($this->get_template_file(), $html); - } + $this->generator->generate(); } /** - * @param boolean $preview - * @return maintenance_static_page + * @return maintenance_static_page_io */ - public function set_preview($preview) { - $this->preview = $preview; - return $this; - } - - /** - * Remove script tags from DOM. - */ - private function remove_script_tags() { - $scripts = $this->dom->getElementsByTagName('script'); - // List items to remove without changing the DOM. - $remove = []; - foreach ($scripts as $node) { - $remove[] = $node; - } - // All listed, now remove them. - foreach ($remove as $node) { - $node->parentNode->removeChild($node); - } - } - - /** - * Clean up the dataroot as needed. - */ - private function cleanup() { - $resources = $this->get_resources_folder(); - if (is_dir($resources)) { - $this->delete_directory_recursively($resources); - } - - $template = $this->get_template_file(); - if (is_file($template)) { - unlink($template); - } - - if (!is_null($this->dom)) { - mkdir($resources, 0775, true); - } - } - - /** - * Deletes the given directory with all its files and subdirectories. - * @param string $dir Directory to delete. - * @throws coding_exception - * @throws invalid_parameter_exception - */ - private function delete_directory_recursively($dir) { - // It should never come from user, but protect against possible attacks anyway. - $dir = realpath($dir); - $safedir = $this->get_resources_folder(); - if (substr($dir, 0, strlen($safedir)) !== $safedir) { - throw new invalid_parameter_exception('Unsafe to delete: '.$dir); - } - - if (!is_dir($dir)) { - throw new coding_exception('Not a directory: '.$dir); - } - $files = scandir($dir); - foreach ($files as $file) { - if (($file == '.') || ($file == '..')) { - continue; - } - $file = $dir.'/'.$file; - if (is_file($file)) { - unlink($file); - continue; - } - if (is_dir($file)) { - $this->delete_directory_recursively($file); - continue; - } - throw new coding_exception('Not a file or directory: '.$file); - } - rmdir($dir); - } - - /** - * Fetch and fixes all link rel="stylesheet" tags. - */ - private function update_link_stylesheet() { - $links = $this->dom->getElementsByTagName('link'); - - foreach ($links as $link) { - $rel = $link->getAttribute("rel"); - $href = $link->getAttribute("href"); - if (($rel != 'stylesheet') || ($href == '')) { - continue; - } - $saved = $this->save_url_file($href); - if (is_null($saved['url'])) { - $url = $href; // Skipped, use original URL. - } else { - $this->update_link_stylesheet_parse($saved['file'], dirname($href)); - $url = $this->get_url_for_file($saved['url']); - } - $link->setAttribute('href', $url); - } - } - - /** - * Checks for urls inside filename. - * @param string $filename - */ - private function update_link_stylesheet_parse($filename, $baseref) { - global $CFG; - - $contents = file_get_contents($filename); - if (!preg_match_all('#url\([\'"]?([^\'"\)]+)#', $contents, $matches)) { - return; - } - foreach ($matches[1] as $original_url) { - // Allow incomplete URLs in CSS, assume it is from moodle root. - if (self::is_url($original_url)) { - $full_url = $original_url; - } else if ($original_url[0] == '/') { - $full_url = $CFG->wwwroot.$original_url; - } else { - $full_url = $baseref.'/'.$original_url; - } - - $saved = $this->save_url_file($full_url); - if (!is_null($saved)) { - $final_url = $this->get_url_for_file($saved['url']); - $contents = str_replace($original_url, $final_url, $contents); - } - } - - file_put_contents($filename, $contents); - } - - /** - * Fetch and fixes the favicon link tag. - */ - private function update_link_favicon() { - $links = $this->dom->getElementsByTagName('link'); - - foreach ($links as $link) { - $rel = $link->getAttribute("rel"); - $href = $link->getAttribute("href"); - if (($rel != 'shortcut icon') || ($href == '')) { - continue; - } - $link->setAttribute('href', $this->generate_file_url($href)); // Works for most image formats. - } - } - - /** - * Fetch and fixes all img tags. - */ - private function update_images() { - $links = $this->dom->getElementsByTagName('img'); - - foreach ($links as $link) { - $src = $link->getAttribute("src"); - if ($src == '') { - continue; - } - $link->setAttribute('src', $this->generate_file_url($src)); // Works for most image formats. - } - } - - /** - * Saves the content of the URL into a file, returning the new URL. - * @param string $url Input URL. - * @return string Output URL. - */ - private function generate_file_url($url) { - $saved = $this->save_url_file($url); - if (is_null($saved)) { - return $url; // Skipped, use original URL. - } - return $this->get_url_for_file($saved['url']); - } - - /** - * Creates a URL for a resource file. - * @param string $filename - * @return string - */ - private function get_url_for_file($filename) { - return (string)new moodle_url('/auth/outage/file.php', ['file' => $filename]); - } - - /** - * Saves the content of the URL into a file, returning the local filename. - * @param string $url Input URL. - * @return string|null Output filename or null if skipped. - */ - private function save_url_file($url) { - global $CFG; - - if (!self::is_url($url)) { - debugging('Found a relative url ('.$url.') -- is it using moodle_url()?'); - return null; // Leave hardcoded URLs as it is. - } - - if (substr($url, 0, strlen($CFG->wwwroot)) !== $CFG->wwwroot) { - return null; // External URL, leave it. - } - - // PHPUnit does not expose a web interface to fetch, point to local file instead. - if (PHPUNIT_TEST) { - $url = str_replace($CFG->wwwroot, $CFG->dirroot, $url); - } - - $data = self::file_get_data($url); - - $mime = trim(base64_encode($data['mime']), '='); - $url = sha1($data['contents']).'.'.$mime; - $filepath = $this->get_resources_folder().'/'.$url; - file_put_contents($filepath, $data['contents']); - - if ($this->preview) { - $url = 'preview/'.$url; - } - - return ['file' => $filepath, 'url' => $url]; + public function get_io() { + return $this->generator->get_io(); } } diff --git a/classes/local/controllers/maintenance_static_page_generator.php b/classes/local/controllers/maintenance_static_page_generator.php new file mode 100644 index 0000000..e4efb00 --- /dev/null +++ b/classes/local/controllers/maintenance_static_page_generator.php @@ -0,0 +1,200 @@ +. + +/** + * maintenance_static_page_generator class. + * + * @package auth_outage + * @author Daniel Thee Roperto + * @copyright 2016 Catalyst IT + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace auth_outage\local\controllers; + +use coding_exception; +use DOMDocument; +use DOMElement; +use invalid_state_exception; + +defined('MOODLE_INTERNAL') || die(); + +/** + * maintenance_static_page_generator class. + * + * @package auth_outage + * @author Daniel Thee Roperto + * @copyright 2016 Catalyst IT + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class maintenance_static_page_generator { + /** @var DOMDocument */ + protected $dom; + + /** @var maintenance_static_page_io */ + protected $io; + + /** + * maintenance_static_page_generator constructor. + * @param DOMDocument|null $dom + * @param maintenance_static_page_io $io + * @throws coding_exception + */ + public function __construct($dom, maintenance_static_page_io $io) { + if (!is_null($dom) && !($dom instanceof DOMDocument)) { + throw new coding_exception('$dom must be null or an DOMDocument object.'); + } + $this->dom = $dom; + $this->io = $io; + } + + /** + * Generates the page. + */ + public function generate() { + $this->io->cleanup(); + + if (!is_null($this->dom)) { + $this->io->create_resources_path(); + + $this->remove_script_tags(); + $this->update_link_stylesheet(); + $this->update_link_favicon(); + $this->update_images(); + + $html = $this->dom->saveHTML(); + if (trim($html) == '') { + // Should never happen, but just in case... + throw new invalid_state_exception('Sanity check failed, $html is empty.'); + } + + $this->io->save_template_file($html); + } + } + + /** + * @return maintenance_static_page_io + */ + public function get_io() { + return $this->io; + } + + + + /** + * Remove script tags from DOM. + */ + private function remove_script_tags() { + $scripts = $this->dom->getElementsByTagName('script'); + // List items to remove without changing the DOM. + $remove = []; + foreach ($scripts as $node) { + $remove[] = $node; + } + // All listed, now remove them. + foreach ($remove as $node) { + $node->parentNode->removeChild($node); + } + } + + /** + * Fetch and fixes all link rel="stylesheet" tags. + */ + private function update_link_stylesheet() { + $links = $this->dom->getElementsByTagName('link'); + + /** @var DOMElement $link */ + foreach ($links as $link) { + $rel = $link->getAttribute("rel"); + $href = $link->getAttribute("href"); + if (($rel != 'stylesheet') || ($href == '')) { + continue; + } + $saved = $this->io->save_url_file($href); + if (is_null($saved['url'])) { + $url = $href; // Skipped, use original URL. + } else { + $this->update_link_stylesheet_parse($saved['file'], dirname($href)); + $url = $this->io->get_url_for_file($saved['url']); + } + $link->setAttribute('href', $url); + } + } + + /** + * Checks for urls inside filename. + * @param string $filename + */ + private function update_link_stylesheet_parse($filename, $baseref) { + global $CFG; + + $contents = file_get_contents($filename); + if (!preg_match_all('#url\([\'"]?([^\'"\)]+)#', $contents, $matches)) { + return; + } + foreach ($matches[1] as $original_url) { + // Allow incomplete URLs in CSS, assume it is from moodle root. + if (maintenance_static_page_io::is_url($original_url)) { + $full_url = $original_url; + } else if ($original_url[0] == '/') { + $full_url = $CFG->wwwroot.$original_url; + } else { + $full_url = $baseref.'/'.$original_url; + } + + $saved = $this->io->save_url_file($full_url); + if (!is_null($saved)) { + $final_url = $this->io->get_url_for_file($saved['url']); + $contents = str_replace($original_url, $final_url, $contents); + } + } + + file_put_contents($filename, $contents); + } + + /** + * Fetch and fixes the favicon link tag. + */ + private function update_link_favicon() { + $links = $this->dom->getElementsByTagName('link'); + + /** @var DOMElement $link */ + foreach ($links as $link) { + $rel = $link->getAttribute("rel"); + $href = $link->getAttribute("href"); + if (($rel != 'shortcut icon') || ($href == '')) { + continue; + } + $link->setAttribute('href', $this->io->generate_file_url($href)); // Works for most image formats. + } + } + + /** + * Fetch and fixes all img tags. + */ + private function update_images() { + $links = $this->dom->getElementsByTagName('img'); + + /** @var DOMElement $link */ + foreach ($links as $link) { + $src = $link->getAttribute("src"); + if ($src == '') { + continue; + } + $link->setAttribute('src', $this->io->generate_file_url($src)); // Works for most image formats. + } + } +} diff --git a/classes/local/controllers/maintenance_static_page_io.php b/classes/local/controllers/maintenance_static_page_io.php new file mode 100644 index 0000000..9814082 --- /dev/null +++ b/classes/local/controllers/maintenance_static_page_io.php @@ -0,0 +1,252 @@ +. + +/** + * maintenance_static_page_io class. + * + * @package auth_outage + * @author Daniel Thee Roperto + * @copyright 2016 Catalyst IT + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace auth_outage\local\controllers; + +use coding_exception; +use finfo; +use invalid_parameter_exception; +use moodle_url; + +defined('MOODLE_INTERNAL') || die(); + +/** + * maintenance_static_page_io class. + * + * @package auth_outage + * @author Daniel Thee Roperto + * @copyright 2016 Catalyst IT + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class maintenance_static_page_io { + /** + * Checks if the given string starts with "http://" or "https://". + * @param $url + * @return bool + */ + public static function is_url($url) { + return (bool)preg_match('#^http(s)?://#', $url); + } + + /** + * Tries to get the contents of the file or URL. + * @param string $file File to get. + * @return string Contents of $file or an empty string if failed. + * @throws coding_exception + */ + public static function file_get_data($file) { + if (!is_string($file)) { + throw new coding_exception('$file is not a string.'); + } + + if (self::is_url($file)) { + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL, $file); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + $contents = curl_exec($curl); + $mime = curl_getinfo($curl, CURLINFO_CONTENT_TYPE); + curl_close($curl); + } else { + $contents = @file_get_contents($file); + $mime = (new finfo(FILEINFO_MIME_TYPE))->buffer($contents); // Not perfect, but try guessing it. + } + if ($contents === false) { + debugging('Cannot fetch: '.$file); + $contents = ''; + $mime = 'unknown'; + } + return ['contents' => $contents, 'mime' => $mime]; + } + + /** @var bool */ + protected $preview = false; + + /** + * @param boolean $preview + */ + public function set_preview($preview) { + $this->preview = $preview; + } + + /** + * Gets the cli maintenance template file location. + * @return string + */ + public function get_template_file() { + global $CFG; + if ($this->preview) { + return $this->get_resources_folder().'/climaintenance.html'; + } else { + return $CFG->dataroot.'/climaintenance.template.html'; + } + } + + /** + * Gets the resources folder in dataroot. + * + * Warning: this folder will be deleted every time the page is regenerated. + * + * @return string + */ + public function get_resources_folder() { + global $CFG; + + // If you change the path, also change file auth/outage/bootstrap.php as it does not use this reference. + $dir = $CFG->dataroot.'/auth_outage/climaintenance'; + + if ($this->preview) { + $dir = $dir.'/preview'; + } + return $dir; + } + + /** + * Clean up the dataroot as needed. + */ + public function cleanup() { + $resources = $this->get_resources_folder(); + if (is_dir($resources)) { + $this->delete_directory_recursively($resources); + } + + $template = $this->get_template_file(); + if (is_file($template)) { + unlink($template); + } + } + + /** + * Clean up the dataroot as needed. + */ + public function create_resources_path() { + mkdir($this->get_resources_folder(), 0775, true); + } + + /** + * Saves the template file with the given string. + * @param string $data + * @throws coding_exception + */ + public function save_template_file($data) { + if (!is_string($data) || ($data === '')) { + throw new coding_exception('$data is not a valid string.'); + } + file_put_contents($this->get_template_file(), $data); + } + + /** + * Deletes the given directory with all its files and subdirectories. + * @param string $dir Directory to delete. + * @throws coding_exception + * @throws invalid_parameter_exception + */ + private function delete_directory_recursively($dir) { + // It should never come from user, but protect against possible attacks anyway. + $dir = realpath($dir); + $safedir = $this->get_resources_folder(); + if (substr($dir, 0, strlen($safedir)) !== $safedir) { + throw new invalid_parameter_exception('Unsafe to delete: '.$dir); + } + + if (!is_dir($dir)) { + throw new coding_exception('Not a directory: '.$dir); + } + $files = scandir($dir); + foreach ($files as $file) { + if (($file == '.') || ($file == '..')) { + continue; + } + $file = $dir.'/'.$file; + if (is_file($file)) { + unlink($file); + continue; + } + if (is_dir($file)) { + $this->delete_directory_recursively($file); + continue; + } + throw new coding_exception('Not a file or directory: '.$file); + } + rmdir($dir); + } + + /** + * Saves the content of the URL into a file, returning the new URL. + * @param string $url Input URL. + * @return string Output URL. + */ + public function generate_file_url($url) { + $saved = $this->save_url_file($url); + if (is_null($saved)) { + return $url; // Skipped, use original URL. + } + return $this->get_url_for_file($saved['url']); + } + + /** + * Creates a URL for a resource file. + * @param string $filename + * @return string + */ + public function get_url_for_file($filename) { + return (string)new moodle_url('/auth/outage/file.php', ['file' => $filename]); + } + + /** + * Saves the content of the URL into a file, returning the local filename. + * @param string $url Input URL. + * @return string|null Output filename or null if skipped. + */ + public function save_url_file($url) { + global $CFG; + + if (!self::is_url($url)) { + debugging('Found a relative url ('.$url.') -- is it using moodle_url()?'); + return null; // Leave hardcoded URLs as it is. + } + + if (substr($url, 0, strlen($CFG->wwwroot)) !== $CFG->wwwroot) { + return null; // External URL, leave it. + } + + // PHPUnit does not expose a web interface to fetch, point to local file instead. + if (PHPUNIT_TEST) { + $url = str_replace($CFG->wwwroot, $CFG->dirroot, $url); + } + + $data = self::file_get_data($url); + + $mime = trim(base64_encode($data['mime']), '='); + $url = sha1($data['contents']).'.'.$mime; + $filepath = $this->get_resources_folder().'/'.$url; + file_put_contents($filepath, $data['contents']); + + if ($this->preview) { + $url = 'preview/'.$url; + } + + return ['file' => $filepath, 'url' => $url]; + } +} diff --git a/tests/phpunit/local/controllers/maintenance_static_page_test.php b/tests/phpunit/local/controllers/maintenance_static_page_test.php index 61d422d..4d3e479 100644 --- a/tests/phpunit/local/controllers/maintenance_static_page_test.php +++ b/tests/phpunit/local/controllers/maintenance_static_page_test.php @@ -24,6 +24,7 @@ */ use auth_outage\local\controllers\maintenance_static_page; +use auth_outage\local\controllers\maintenance_static_page_io; use auth_outage\task\update_static_page; defined('MOODLE_INTERNAL') || die(); @@ -42,17 +43,17 @@ class maintenance_static_page_test extends auth_outage_base_testcase { public function test_templatefile() { global $CFG; $page = maintenance_static_page::create_from_html(''); - self::assertSame($CFG->dataroot.'/climaintenance.template.html', $page->get_template_file()); - $page->set_preview(true); - self::assertSame($CFG->dataroot.'/auth_outage/climaintenance/preview/climaintenance.html', $page->get_template_file()); + self::assertSame($CFG->dataroot.'/climaintenance.template.html', $page->get_io()->get_template_file()); + $page->get_io()->set_preview(true); + self::assertSame($CFG->dataroot.'/auth_outage/climaintenance/preview/climaintenance.html', $page->get_io()->get_template_file()); } public function test_resourcesfolder() { global $CFG; $page = maintenance_static_page::create_from_html(''); - self::assertSame($CFG->dataroot.'/auth_outage/climaintenance', $page->get_resources_folder()); - $page->set_preview(true); - self::assertSame($CFG->dataroot.'/auth_outage/climaintenance/preview', $page->get_resources_folder()); + self::assertSame($CFG->dataroot.'/auth_outage/climaintenance', $page->get_io()->get_resources_folder()); + $page->get_io()->set_preview(true); + self::assertSame($CFG->dataroot.'/auth_outage/climaintenance/preview', $page->get_io()->get_resources_folder()); } public function test_createfromoutage() { @@ -96,10 +97,10 @@ class maintenance_static_page_test extends auth_outage_base_testcase { $page->generate(); // Check for css file. - self::assertFileExists($page->get_resources_folder().'/622ef6e83acfcb274cdf37bdb3bffa0923f9a7ad.dGV4dC9wbGFpbg'); + self::assertFileExists($page->get_io()->get_resources_folder().'/622ef6e83acfcb274cdf37bdb3bffa0923f9a7ad.dGV4dC9wbGFpbg'); // Check for catalyst.png file referenced in url(..) of css. - self::assertFileExists($page->get_resources_folder().'/ff7f7f87a26a908fc72930eaefb6b57306361d16.aW1hZ2UvcG5n'); + self::assertFileExists($page->get_io()->get_resources_folder().'/ff7f7f87a26a908fc72930eaefb6b57306361d16.aW1hZ2UvcG5n'); } public function test_updatelinkstylesheet_urls_quoted() { @@ -111,10 +112,10 @@ class maintenance_static_page_test extends auth_outage_base_testcase { $page->generate(); // Check for css file. - self::assertFileExists($page->get_resources_folder().'/1d84b6d321fef780237f84834b7316c079221a31.dGV4dC9wbGFpbg'); + self::assertFileExists($page->get_io()->get_resources_folder().'/1d84b6d321fef780237f84834b7316c079221a31.dGV4dC9wbGFpbg'); // Check for catalyst.png file referenced in url(..) of css. - self::assertFileExists($page->get_resources_folder().'/ff7f7f87a26a908fc72930eaefb6b57306361d16.aW1hZ2UvcG5n'); + self::assertFileExists($page->get_io()->get_resources_folder().'/ff7f7f87a26a908fc72930eaefb6b57306361d16.aW1hZ2UvcG5n'); } public function test_updatelinkstylesheet_urls_subdir() { @@ -126,10 +127,10 @@ class maintenance_static_page_test extends auth_outage_base_testcase { $page->generate(); // Check for css file. - self::assertFileExists($page->get_resources_folder().'/4ea71b83ab326a15d0d784b34fcda702b6a7427d.dGV4dC9wbGFpbg'); + self::assertFileExists($page->get_io()->get_resources_folder().'/4ea71b83ab326a15d0d784b34fcda702b6a7427d.dGV4dC9wbGFpbg'); // Check for file referenced in url(..) of css. - self::assertFileExists($page->get_resources_folder().'/a02a8a442fa82d5205ffb24722d9df7f35161f56.dGV4dC9wbGFpbg'); + self::assertFileExists($page->get_io()->get_resources_folder().'/a02a8a442fa82d5205ffb24722d9df7f35161f56.dGV4dC9wbGFpbg'); } public function test_updateimages() { @@ -162,9 +163,9 @@ class maintenance_static_page_test extends auth_outage_base_testcase { 'Title'. 'Content'; $page = maintenance_static_page::create_from_html($html); - $page->set_preview(true); + $page->get_io()->set_preview(true); $page->generate(); - $generated = trim(file_get_contents($page->get_template_file())); + $generated = trim(file_get_contents($page->get_io()->get_template_file())); self::assertNotContains($link, $generated); self::assertContains('http://www.example.com/moodle/auth/outage/file.php?file=preview%2F', $generated); @@ -178,7 +179,7 @@ class maintenance_static_page_test extends auth_outage_base_testcase { private function generated_page_html($html) { $page = maintenance_static_page::create_from_html($html); $page->generate(); - $generated = trim(file_get_contents($page->get_template_file())); + $generated = trim(file_get_contents($page->get_io()->get_template_file())); return $generated; } @@ -215,7 +216,7 @@ class maintenance_static_page_test extends auth_outage_base_testcase { $page->generate(); // This checks if content is correct and mime type is correct from the encoded name. - $file = $page->get_resources_folder().'/ff7f7f87a26a908fc72930eaefb6b57306361d16.aW1hZ2UvcG5n'; + $file = $page->get_io()->get_resources_folder().'/ff7f7f87a26a908fc72930eaefb6b57306361d16.aW1hZ2UvcG5n'; self::assertFileExists($file); // We can still assert the contents really match, not just the hash. @@ -232,4 +233,48 @@ class maintenance_static_page_test extends auth_outage_base_testcase { private function get_fixture_path($file) { return (string)new moodle_url('/auth/outage/tests/phpunit/local/controllers/fixtures/'.$file); } + + public function test_invalid_string_saving_template_empty() { + $io = new maintenance_static_page_io(); + $this->set_expected_exception('coding_exception'); + $io->save_template_file(''); + } + + public function test_invalid_string_saving_template_nostring() { + $io = new maintenance_static_page_io(); + $this->set_expected_exception('coding_exception'); + $io->save_template_file(50); + } + + public function test_get_url_for_file() { + $io = new maintenance_static_page_io(); + self::assertSame('http://www.example.com/moodle/auth/outage/file.php?file=img.png', $io->get_url_for_file('img.png')); + } + + public function test_is_url() { + self::assertTrue(maintenance_static_page_io::is_url('http://catalyst.net.nz')); + self::assertTrue(maintenance_static_page_io::is_url('https://www.catalyst-au.net/')); + self::assertFalse(maintenance_static_page_io::is_url('/homepage')); + self::assertFalse(maintenance_static_page_io::is_url('file://homepage')); + } + + public function test_file_get_data() { + $file = __DIR__.'/fixtures/catalyst.png'; + $found = maintenance_static_page_io::file_get_data($file); + self::assertSame(file_get_contents($file), $found['contents']); + self::assertSame('image/png', $found['mime']); + } + + public function test_file_get_data_invalidfile() { + $found = maintenance_static_page_io::file_get_data(__DIR__.'/fixtures/invalidfile'); + self::assertSame('', $found['contents']); + self::assertSame('unknown', $found['mime']); + self::assertCount(1, phpunit_util::get_debugging_messages()); + phpunit_util::reset_debugging(); + } + + public function test_file_get_data_invalidfilename() { + $this->set_expected_exception('coding_exception'); + maintenance_static_page_io::file_get_data(200); + } }