mirror of
https://github.com/catalyst/moodle-auth_outage.git
synced 2026-05-16 21:41:31 +02:00
Issue #22 - WIP - Basic replacement for styles and images.
This commit is contained in:
214
classes/local/controllers/maintenance_static_page.php
Normal file
214
classes/local/controllers/maintenance_static_page.php
Normal file
@@ -0,0 +1,214 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* maintenance_static_page class.
|
||||
*
|
||||
* @package auth_outage
|
||||
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
|
||||
* @copyright 2016 Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace auth_outage\local\controllers;
|
||||
|
||||
use auth_outage\local\outage;
|
||||
use coding_exception;
|
||||
use DOMDocument;
|
||||
use DOMElement;
|
||||
use invalid_parameter_exception;
|
||||
use moodle_url;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* maintenance_static_page class.
|
||||
*
|
||||
* @package auth_outage
|
||||
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
|
||||
* @copyright 2016 Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class maintenance_static_page {
|
||||
/** @var int */
|
||||
private static $nextfile = 1;
|
||||
|
||||
/**
|
||||
* Gets the cli maintenance template file location.
|
||||
* @return string
|
||||
*/
|
||||
public static function get_template_file() {
|
||||
global $CFG;
|
||||
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 static function get_resources_folder() {
|
||||
global $CFG;
|
||||
return $CFG->dataroot.'/auth_outage/climaintenance';
|
||||
}
|
||||
|
||||
public static function create_from_outage(outage $outage) {
|
||||
global $CFG;
|
||||
$html = file_get_contents($CFG->wwwroot.'/auth/outage/info.php?auth_outage_hide_warning=1&id='.$outage->id);
|
||||
self::create_from_html($html);
|
||||
}
|
||||
|
||||
public static function create_from_html($html) {
|
||||
if (!is_string($html)) {
|
||||
throw new coding_exception('$html is not valid.');
|
||||
}
|
||||
|
||||
$dom = new DOMDocument();
|
||||
|
||||
// Let's assume we have no parsing errors as we cannot rely on a badly-formed page anyway.
|
||||
libxml_use_internal_errors(true);
|
||||
$dom->loadHTML($html);
|
||||
libxml_clear_errors();
|
||||
|
||||
self::generate($dom);
|
||||
}
|
||||
|
||||
private static function generate(DOMDocument $dom) {
|
||||
self::prepare_dataroot();
|
||||
self::remove_script_tags($dom);
|
||||
self::update_link_stylesheet($dom);
|
||||
self::update_link_favicon($dom);
|
||||
self::update_images($dom);
|
||||
file_put_contents(self::get_template_file(), $dom->saveHTML());
|
||||
}
|
||||
|
||||
private static function remove_script_tags(DOMDocument $dom) {
|
||||
$scripts = $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);
|
||||
}
|
||||
}
|
||||
|
||||
private static function prepare_dataroot() {
|
||||
$dir = self::get_resources_folder();
|
||||
if (is_dir($dir)) {
|
||||
self::delete_directory_recursively($dir);
|
||||
}
|
||||
mkdir($dir, 0775, true);
|
||||
}
|
||||
|
||||
private static function delete_directory_recursively($dir) {
|
||||
// It should never come from user, but protect against possible attacks anyway.
|
||||
$safedir = self::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)) {
|
||||
self::delete_directory_recursively($file);
|
||||
continue;
|
||||
}
|
||||
throw new coding_exception('Not a file or directory: '.$file);
|
||||
}
|
||||
rmdir($dir);
|
||||
}
|
||||
|
||||
private static function update_link_stylesheet(DOMDocument $dom) {
|
||||
$links = $dom->getElementsByTagName('link');
|
||||
|
||||
foreach ($links as $link) {
|
||||
$rel = $link->getAttribute("rel");
|
||||
$href = $link->getAttribute("href");
|
||||
if (($rel != 'stylesheet') || ($href == '')) {
|
||||
continue;
|
||||
}
|
||||
$link->setAttribute('href', self::prepare_url($href, 'css'));
|
||||
}
|
||||
}
|
||||
|
||||
private static function update_link_favicon(DOMDocument $dom) {
|
||||
$links = $dom->getElementsByTagName('link');
|
||||
|
||||
foreach ($links as $link) {
|
||||
$rel = $link->getAttribute("rel");
|
||||
$href = $link->getAttribute("href");
|
||||
if (($rel != 'shortcut icon') || ($href == '')) {
|
||||
continue;
|
||||
}
|
||||
$link->setAttribute('href', self::prepare_url($href, 'png')); // Works for most image formats.
|
||||
}
|
||||
}
|
||||
|
||||
private static function update_images(DOMDocument $dom) {
|
||||
$links = $dom->getElementsByTagName('img');
|
||||
|
||||
foreach ($links as $link) {
|
||||
$src = $link->getAttribute("src");
|
||||
if ($src == '') {
|
||||
continue;
|
||||
}
|
||||
$link->setAttribute('src', self::prepare_url($src, 'png')); // Works for most image formats.
|
||||
}
|
||||
}
|
||||
|
||||
private static function prepare_url($url, $type) {
|
||||
global $CFG;
|
||||
|
||||
if (!preg_match('#^http(s)?://#', $url)) {
|
||||
debugging('Found a relative url ('.$url.') -- is it using moodle_url()?');
|
||||
return $url; // Leave hardcoded URLs as it is.
|
||||
}
|
||||
|
||||
if (substr($url, 0, strlen($CFG->wwwroot)) !== $CFG->wwwroot) {
|
||||
return $url; // External URL, leave it.
|
||||
}
|
||||
|
||||
$file = self::$nextfile++;
|
||||
if ($type != '') {
|
||||
$file .= '.'.$type;
|
||||
}
|
||||
$path = self::get_resources_folder().'/'.$file;
|
||||
|
||||
// PHPUnit will use www.example.com as wwwroot and we don't to copy the file.
|
||||
if (!PHPUNIT_TEST) {
|
||||
copy($url, $path);
|
||||
}
|
||||
|
||||
$url = (string)new moodle_url('/auth/outage/maintenance.php/'.$file);
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
@@ -80,6 +80,7 @@ $string['finish'] = 'Finish';
|
||||
$string['info15secondsbefore'] = '15 seconds before';
|
||||
$string['infoendofoutage'] = 'end of outage';
|
||||
$string['infofrom'] = 'From:';
|
||||
$string['infohidewarning'] = 'no warning bar';
|
||||
$string['infountil'] = 'Until:';
|
||||
$string['infostart'] = 'start';
|
||||
$string['infostartofwarning'] = 'start of warning';
|
||||
|
||||
33
maintenance.php
Normal file
33
maintenance.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* This page is used to regenerate and preview a maintenance mode static page.
|
||||
*
|
||||
* @package auth_outage
|
||||
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
|
||||
* @copyright 2016 Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use auth_outage\dml\outagedb;
|
||||
use auth_outage\local\controllers\maintenance_static_page;
|
||||
|
||||
require_once(__DIR__.'/../../config.php');
|
||||
|
||||
$outage = outagedb::get_next_starting();
|
||||
maintenance_static_page::create_from_outage($outage);
|
||||
readfile(maintenance_static_page::get_template_file());
|
||||
124
tests/phpunit/local/controllers/maintenance_static_page_test.php
Normal file
124
tests/phpunit/local/controllers/maintenance_static_page_test.php
Normal file
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* maintenance_static_page_test task class.
|
||||
*
|
||||
* @package auth_outage
|
||||
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
|
||||
* @copyright 2016 Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use auth_outage\local\controllers\maintenance_static_page;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
require_once(__DIR__.'/../../base_testcase.php');
|
||||
|
||||
/**
|
||||
* maintenance_static_page_test class.
|
||||
*
|
||||
* @package auth_outage
|
||||
* @author Daniel Thee Roperto <daniel.roperto@catalyst-au.net>
|
||||
* @copyright 2016 Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @SuppressWarnings(public) Allow as many methods as needed.
|
||||
*/
|
||||
class maintenance_static_page_test extends auth_outage_base_testcase {
|
||||
/**
|
||||
* Ensures the template file does not exist when starting a test.
|
||||
*/
|
||||
public function setUp() {
|
||||
$file = maintenance_static_page::get_template_file();
|
||||
if (file_exists($file)) {
|
||||
if (is_file($file)) {
|
||||
unlink($file);
|
||||
} else {
|
||||
self::fail('Invalid temp file: '.$file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function test_templatefile() {
|
||||
global $CFG;
|
||||
self::assertSame($CFG->dataroot.'/climaintenance.template.html', maintenance_static_page::get_template_file());
|
||||
}
|
||||
|
||||
public function test_createfromoutage() {
|
||||
// How to fetch a page from PHPUnit environment?
|
||||
}
|
||||
|
||||
public function test_createfromhtml() {
|
||||
$html = "<!DOCTYPE html>\n<html><head><title>Title</title></head><body>Content</body></html>";
|
||||
maintenance_static_page::create_from_html($html);
|
||||
$generated = trim(file_get_contents(maintenance_static_page::get_template_file()));
|
||||
self::assertSame($html, $generated);
|
||||
}
|
||||
|
||||
public function test_removescripttags() {
|
||||
$html = "<!DOCTYPE html>\n".
|
||||
'<html><head><script type="text/javascript" src="http://xyz"></script><title>Title</title></head>'.
|
||||
'<body>Content<script> a < 5; x > 3</script></body></html>';
|
||||
maintenance_static_page::create_from_html($html);
|
||||
|
||||
$generated = file_get_contents(maintenance_static_page::get_template_file());
|
||||
self::assertNotContains('<script', $generated);
|
||||
}
|
||||
|
||||
public function test_updatelinkstylesheet() {
|
||||
$link1 = (string)new moodle_url('/example.css');
|
||||
$link2 = (string)new moodle_url('/auth/outage/stylesheet');
|
||||
$link3 = 'http://google.com/coolstyle.css';
|
||||
$html = "<!DOCTYPE html>\n".
|
||||
'<html><head><link href="'.$link1.'" rel="stylesheet" /><title>Title</title></head>'.
|
||||
'<body><link rel="stylesheet" href="'.$link2.'">Content<link rel="stylesheet" href="'.$link3.'"></body></html>';
|
||||
maintenance_static_page::create_from_html($html);
|
||||
$generated = file_get_contents(maintenance_static_page::get_template_file());
|
||||
|
||||
self::assertContains('http://www.example.com/moodle/auth/outage/maintenance.php/', $generated);
|
||||
self::assertNotContains($link1, $generated);
|
||||
self::assertNotContains($link2, $generated);
|
||||
self::assertContains($link3, $generated);
|
||||
}
|
||||
|
||||
public function test_updateimages() {
|
||||
$link1 = (string)new moodle_url('/example.png');
|
||||
$link2 = (string)new moodle_url('/auth/outage/imagefile');
|
||||
$link3 = 'http://google.com/coolstyle.css';
|
||||
$html = "<!DOCTYPE html>\n".
|
||||
'<html><head><img src="'.$link1.'" alt="an image" /><title>Title</title></head>'.
|
||||
'<body><img src="'.$link2.'">Content<img src="'.$link3.'" /></body></html>';
|
||||
maintenance_static_page::create_from_html($html);
|
||||
$generated = file_get_contents(maintenance_static_page::get_template_file());
|
||||
|
||||
self::assertContains('http://www.example.com/moodle/auth/outage/maintenance.php/', $generated);
|
||||
self::assertNotContains($link1, $generated);
|
||||
self::assertNotContains($link2, $generated);
|
||||
self::assertContains($link3, $generated);
|
||||
}
|
||||
|
||||
public function test_updatelinkfavicon() {
|
||||
$link = (string)new moodle_url('/favicon.jpg');
|
||||
$html = "<!DOCTYPE html>\n".
|
||||
'<html><head><title>Title</title><link rel="shortcut icon" href="'.$link.'""></head>'.
|
||||
'<body>Content</body></html>';
|
||||
maintenance_static_page::create_from_html($html);
|
||||
$generated = file_get_contents(maintenance_static_page::get_template_file());
|
||||
|
||||
self::assertNotContains($link, $generated);
|
||||
self::assertContains('http://www.example.com/moodle/auth/outage/maintenance.php/', $generated);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user