mirror of
https://github.com/catalyst/moodle-auth_outage.git
synced 2026-05-16 21:41:31 +02:00
Issue #22 - Refactored maintenance_static_page and allowed generate preview page (different location than main template).
This commit is contained in:
@@ -42,32 +42,10 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class maintenance_static_page {
|
||||
/**
|
||||
* 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;
|
||||
// If you change the path, also change file auth/outage/maintenance.php as it does not use this reference.
|
||||
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);
|
||||
return self::create_from_html($html);
|
||||
}
|
||||
|
||||
public static function create_from_html($html) {
|
||||
@@ -82,20 +60,69 @@ class maintenance_static_page {
|
||||
$dom->loadHTML($html);
|
||||
libxml_clear_errors();
|
||||
|
||||
self::generate($dom);
|
||||
return new maintenance_static_page($dom);
|
||||
}
|
||||
|
||||
private static function generate(DOMDocument $dom) {
|
||||
/** @var DOMDocument */
|
||||
protected $dom;
|
||||
|
||||
/** @var bool */
|
||||
protected $preview = false;
|
||||
|
||||
public function __construct(DOMDocument $dom) {
|
||||
$this->dom = $dom;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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/maintenance.php as it does not use this reference.
|
||||
if ($this->preview) {
|
||||
return $CFG->dataroot.'/auth_outage/climaintenance/preview';
|
||||
} else {
|
||||
return $CFG->dataroot.'/auth_outage/climaintenance';
|
||||
}
|
||||
}
|
||||
|
||||
public function generate() {
|
||||
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());
|
||||
self::remove_script_tags();
|
||||
self::update_link_stylesheet();
|
||||
self::update_link_favicon();
|
||||
self::update_images();
|
||||
file_put_contents(self::get_template_file(), $this->dom->saveHTML());
|
||||
}
|
||||
|
||||
private static function remove_script_tags(DOMDocument $dom) {
|
||||
$scripts = $dom->getElementsByTagName('script');
|
||||
/**
|
||||
* @param boolean $preview
|
||||
* @return maintenance_static_page
|
||||
*/
|
||||
public function set_preview($preview) {
|
||||
$this->preview = $preview;
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function remove_script_tags() {
|
||||
$scripts = $this->dom->getElementsByTagName('script');
|
||||
// List items to remove without changing the DOM.
|
||||
$remove = [];
|
||||
foreach ($scripts as $node) {
|
||||
@@ -107,7 +134,7 @@ class maintenance_static_page {
|
||||
}
|
||||
}
|
||||
|
||||
private static function prepare_dataroot() {
|
||||
private function prepare_dataroot() {
|
||||
$dir = self::get_resources_folder();
|
||||
if (is_dir($dir)) {
|
||||
self::delete_directory_recursively($dir);
|
||||
@@ -115,7 +142,7 @@ class maintenance_static_page {
|
||||
mkdir($dir, 0775, true);
|
||||
}
|
||||
|
||||
private static function delete_directory_recursively($dir) {
|
||||
private function delete_directory_recursively($dir) {
|
||||
// It should never come from user, but protect against possible attacks anyway.
|
||||
$dir = realpath($dir);
|
||||
$safedir = self::get_resources_folder();
|
||||
@@ -145,8 +172,8 @@ class maintenance_static_page {
|
||||
rmdir($dir);
|
||||
}
|
||||
|
||||
private static function update_link_stylesheet(DOMDocument $dom) {
|
||||
$links = $dom->getElementsByTagName('link');
|
||||
private function update_link_stylesheet() {
|
||||
$links = $this->dom->getElementsByTagName('link');
|
||||
|
||||
foreach ($links as $link) {
|
||||
$rel = $link->getAttribute("rel");
|
||||
@@ -158,8 +185,8 @@ class maintenance_static_page {
|
||||
}
|
||||
}
|
||||
|
||||
private static function update_link_favicon(DOMDocument $dom) {
|
||||
$links = $dom->getElementsByTagName('link');
|
||||
private function update_link_favicon() {
|
||||
$links = $this->dom->getElementsByTagName('link');
|
||||
|
||||
foreach ($links as $link) {
|
||||
$rel = $link->getAttribute("rel");
|
||||
@@ -171,8 +198,8 @@ class maintenance_static_page {
|
||||
}
|
||||
}
|
||||
|
||||
private static function update_images(DOMDocument $dom) {
|
||||
$links = $dom->getElementsByTagName('img');
|
||||
private function update_images() {
|
||||
$links = $this->dom->getElementsByTagName('img');
|
||||
|
||||
foreach ($links as $link) {
|
||||
$src = $link->getAttribute("src");
|
||||
@@ -183,7 +210,7 @@ class maintenance_static_page {
|
||||
}
|
||||
}
|
||||
|
||||
private static function prepare_url($url, $type) {
|
||||
private function prepare_url($url, $type) {
|
||||
global $CFG;
|
||||
|
||||
if (!preg_match('#^http(s)?://#', $url)) {
|
||||
@@ -205,7 +232,10 @@ class maintenance_static_page {
|
||||
$filepath = self::get_resources_folder().'/'.$filename;
|
||||
file_put_contents($filepath, $contents);
|
||||
|
||||
$url = (string)new moodle_url('/auth/outage/maintenance.php?file='.$filename);
|
||||
if ($this->preview) {
|
||||
$filename = 'preview/'.$filename;
|
||||
}
|
||||
$url = (string)new moodle_url('/auth/outage/maintenance.php', ['file' => $filename]);
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +84,7 @@ $string['infohidewarning'] = 'no warning bar';
|
||||
$string['infountil'] = 'Until:';
|
||||
$string['infostart'] = 'start';
|
||||
$string['infostartofwarning'] = 'start of warning';
|
||||
$string['infostaticpage'] = 'static page';
|
||||
$string['infopagestaticgenerated'] = 'This warning was generated on {$a->time}.';
|
||||
$string['allowedipsempty'] = 'When the allowed IPs list is empty we will not block anyone. You can add your own IP address (<i>{$a->ip}</i>) and block all other IPs.';
|
||||
$string['allowedipshasmyip'] = 'Your IP (<i>{$a->ip}</i>) is in the list and you will not be blocked out during an Outage.';
|
||||
|
||||
@@ -36,9 +36,11 @@ if (isset($_GET['file'])) {
|
||||
$resourcedir = $CFG->dataroot.'/auth_outage/climaintenance';
|
||||
|
||||
// Protect against path traversal attacks.
|
||||
$file = $resourcedir.'/'.basename($_GET['file']);
|
||||
$file = $resourcedir.'/'.$_GET['file'];
|
||||
if (realpath($file) !== $file) {
|
||||
// @codingStandardsIgnoreStart
|
||||
error_log('Invalid file: '.$_GET['file']);
|
||||
// @codingStandardsIgnoreEnd
|
||||
http_response_code(404);
|
||||
die('Not found.');
|
||||
}
|
||||
@@ -59,9 +61,17 @@ if (isset($_GET['file'])) {
|
||||
|
||||
if (isset($_GET['debug'])) {
|
||||
// Use auth/outage/maintenance.php?debug to preview how it will render without triggering maintenance mode.
|
||||
|
||||
require_once(__DIR__.'/../../config.php');
|
||||
$outage = outagedb::get_next_starting();
|
||||
maintenance_static_page::create_from_outage($outage);
|
||||
readfile(maintenance_static_page::get_template_file());
|
||||
$id = optional_param('id', null, PARAM_INT);
|
||||
$outage = is_null($id) ? outagedb::get_next_starting() : outagedb::get_by_id($id);
|
||||
if (is_null($outage)) {
|
||||
throw new invalid_parameter_exception('Outage not found.');
|
||||
}
|
||||
|
||||
$page = maintenance_static_page::create_from_outage($outage);
|
||||
$page->set_preview(true);
|
||||
$page->generate();
|
||||
readfile($page->get_template_file());
|
||||
return;
|
||||
}
|
||||
@@ -38,23 +38,20 @@ require_once(__DIR__.'/../../base_testcase.php');
|
||||
* @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());
|
||||
$page = maintenance_static_page::create_from_html('<html></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());
|
||||
}
|
||||
|
||||
public function test_resourcesfolder() {
|
||||
global $CFG;
|
||||
$page = maintenance_static_page::create_from_html('<html></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());
|
||||
}
|
||||
|
||||
public function test_createfromoutage() {
|
||||
@@ -63,18 +60,16 @@ class maintenance_static_page_test extends auth_outage_base_testcase {
|
||||
|
||||
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);
|
||||
self::assertSame($html, $this->generated_page_html($html));
|
||||
}
|
||||
|
||||
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);
|
||||
maintenance_static_page::create_from_html($html)->generate();
|
||||
|
||||
$generated = file_get_contents(maintenance_static_page::get_template_file());
|
||||
$generated = $this->generated_page_html($html);
|
||||
self::assertNotContains('<script', $generated);
|
||||
}
|
||||
|
||||
@@ -85,8 +80,7 @@ class maintenance_static_page_test extends auth_outage_base_testcase {
|
||||
$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());
|
||||
$generated = $this->generated_page_html($html);
|
||||
|
||||
self::assertContains('http://www.example.com/moodle/auth/outage/maintenance.php?file=', $generated);
|
||||
self::assertNotContains($link1, $generated);
|
||||
@@ -101,8 +95,7 @@ class maintenance_static_page_test extends auth_outage_base_testcase {
|
||||
$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());
|
||||
$generated = $this->generated_page_html($html);
|
||||
|
||||
self::assertContains('http://www.example.com/moodle/auth/outage/maintenance.php?file=', $generated);
|
||||
self::assertNotContains($link1, $generated);
|
||||
@@ -115,10 +108,30 @@ class maintenance_static_page_test extends auth_outage_base_testcase {
|
||||
$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());
|
||||
$generated = $this->generated_page_html($html);
|
||||
|
||||
self::assertNotContains($link, $generated);
|
||||
self::assertContains('http://www.example.com/moodle/auth/outage/maintenance.php?file=', $generated);
|
||||
}
|
||||
|
||||
public function test_previewpath() {
|
||||
$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>';
|
||||
$page = maintenance_static_page::create_from_html($html);
|
||||
$page->set_preview(true);
|
||||
$page->generate();
|
||||
$generated = trim(file_get_contents($page->get_template_file()));
|
||||
|
||||
self::assertNotContains($link, $generated);
|
||||
self::assertContains('http://www.example.com/moodle/auth/outage/maintenance.php?file=preview%2F', $generated);
|
||||
}
|
||||
|
||||
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()));
|
||||
return $generated;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,10 @@ if ($viewbag['admin']) {
|
||||
),
|
||||
get_string('infohidewarning', 'auth_outage')
|
||||
);
|
||||
$adminlinks[] = html_writer::link(
|
||||
new moodle_url('/auth/outage/maintenance.php', ['debug' => '', 'id' => $viewbag['outage']->id]),
|
||||
get_string('infostaticpage', 'auth_outage')
|
||||
);
|
||||
|
||||
$admineditlink = html_writer::link(
|
||||
new moodle_url('/auth/outage/edit.php', ['edit' => $viewbag['outage']->id]),
|
||||
|
||||
Reference in New Issue
Block a user