Issue #22 - Added setting and implemented removing elements by basic CSS selector (only simple .class and #id can be used as of now).

This commit is contained in:
Daniel Thee Roperto
2016-11-14 11:35:08 +11:00
parent 0c97b4be01
commit 27c7558e57
7 changed files with 193 additions and 20 deletions

View File

@@ -25,6 +25,7 @@
namespace auth_outage\local\controllers;
use auth_outage\local\outagelib;
use coding_exception;
use DOMDocument;
use DOMElement;
@@ -49,8 +50,10 @@ class maintenance_static_page_generator {
/**
* maintenance_static_page_generator constructor.
* @param DOMDocument|null $dom
*
* @param DOMDocument|null $dom
* @param maintenance_static_page_io $io
*
* @throws coding_exception
*/
public function __construct($dom, maintenance_static_page_io $io) {
@@ -74,6 +77,7 @@ class maintenance_static_page_generator {
$this->update_link_stylesheet();
$this->update_link_favicon();
$this->update_images();
$this->remove_configured_css_selectors();
$html = $this->dom->saveHTML();
if (trim($html) == '') {
@@ -93,7 +97,6 @@ class maintenance_static_page_generator {
}
/**
* Remove script tags from DOM.
*/
@@ -104,10 +107,7 @@ class maintenance_static_page_generator {
foreach ($scripts as $node) {
$remove[] = $node;
}
// All listed, now remove them.
foreach ($remove as $node) {
$node->parentNode->removeChild($node);
}
$this->remove_nodes_from_dom($remove);
}
/**
@@ -135,6 +135,7 @@ class maintenance_static_page_generator {
/**
* Checks for urls inside filename.
*
* @param string $filename
* @param string $baseref
*/
@@ -195,4 +196,73 @@ class maintenance_static_page_generator {
$link->setAttribute('src', $this->io->generate_file_url($src)); // Works for most image formats.
}
}
/**
* Remove from DOM the CSS selectores defined in the plugin settings.
*/
private function remove_configured_css_selectors() {
$selectors = explode("\n", outagelib::get_config()->remove_selectors);
$remove = [];
foreach ($selectors as $selector) {
// We only support a simple .class or #id -- if support for full selectors must be added
// then I suggest checking http://code.google.com/p/phpquery/ on how to implement it.
$selector = trim($selector);
if ($selector == '') {
continue;
}
$remove = array_merge($remove, $this->fetch_elements_by_selector($selector));
}
$this->remove_nodes_from_dom($remove);
}
/**
* Removes the nodes from the DOM.
*
* @param DOMElement[] $nodes
*/
private function remove_nodes_from_dom(array $nodes) {
foreach ($nodes as $node) {
$node->parentNode->removeChild($node);
}
}
/**
* Fetches all elements based on the given selector.
*
* @param $selector
*
* @return DOMElement[]
*/
private function fetch_elements_by_selector($selector) {
$type = $selector[0];
$selector = substr($selector, 1); // Remove '.' or '#'.
if ($type == '#') {
$element = $this->dom->getElementById($selector);
return is_null($element) ? [] : [$element];
} else {
return $this->fetch_elements_by_class($selector);
}
}
/**
* Fetch all elements which contains the given class.
*
* @param $class
*
* @return DOMElement[]
*/
private function fetch_elements_by_class($class) {
$matches = [];
$elements = $this->dom->getElementsByTagName('*');
foreach ($elements as $element) {
$elementclasses = explode(' ', $element->getAttribute('class'));
if (in_array($class, $elementclasses)) {
$matches[] = $element;
}
}
return $matches;
}
}

View File

@@ -104,7 +104,7 @@ class outagelib {
// There is a previewing or active outage.
$CFG->additionalhtmltopofbody = renderer::get()->render_warningbar($active, $time, false, $preview).
$CFG->additionalhtmltopofbody;
$CFG->additionalhtmltopofbody;
} catch (Exception $e) {
debugging('Exception occured while injecting our code: '.$e->getMessage());
debugging($e->getTraceAsString(), DEBUG_DEVELOPER);
@@ -137,13 +137,14 @@ class outagelib {
*/
public static function get_config_defaults() {
return [
'allowedips' => '',
'css' => '',
'default_autostart' => '0',
'default_duration' => (string)(60 * 60),
'allowedips' => '',
'css' => '',
'default_autostart' => '0',
'default_duration' => (string)(60 * 60),
'default_warning_duration' => (string)(60 * 60),
'default_title' => get_string('defaulttitlevalue', 'auth_outage'),
'default_description' => get_string('defaultdescriptionvalue', 'auth_outage'),
'default_title' => get_string('defaulttitlevalue', 'auth_outage'),
'default_description' => get_string('defaultdescriptionvalue', 'auth_outage'),
'remove_selectors' => '.usermenu',
];
}
@@ -163,6 +164,7 @@ class outagelib {
/**
* Calls Moodle API - set_maintenance_later() to set when the next outage starts.
*
* @param outage|null $outage Outage or null if no scheduled outage.
*/
private static function update_maintenance_later($outage) {
@@ -204,9 +206,11 @@ class outagelib {
/**
* Generates the code to put in sitedata/climaintenance.php when needed.
* @param int $starttime Outage start time.
* @param int $stoptime Outage stop time.
*
* @param int $starttime Outage start time.
* @param int $stoptime Outage stop time.
* @param string $allowedips List of IPs allowed.
*
* @return string
* @throws invalid_parameter_exception
*/
@@ -255,7 +259,9 @@ EOT;
/**
* Updates the static info page by (re)creating or deleting it as needed.
*
* @param outage|null $outage Outage or null if no scheduled outage.
*
* @throws coding_exception
* @throws file_exception
*/

View File

@@ -114,6 +114,8 @@ $string['outagefinishwarning'] = 'You are about to mark this outage as finished.
$string['outageslistfuture'] = 'Planned outages';
$string['outageslistpast'] = 'Outage history';
$string['pluginname'] = 'Outage manager';
$string['removeselectors'] = 'Remove selectors';
$string['removeselectorsdescription'] = 'CSS selectors to remove when rendering a static themed maintenance page. One selector per line.';
$string['settingssectiondefaults'] = 'Default Outage Parameters';
$string['settingssectiondefaultsdescription'] = 'Configure the default values used when creating new outages.';
$string['settingssectionplugin'] = 'Plugin Configuration';

View File

@@ -36,6 +36,6 @@ if (is_null($outage)) {
}
$page = maintenance_static_page::create_from_outage($outage);
$page->set_preview(true);
$page->get_io()->set_preview(true);
$page->generate();
readfile($page->get_template_file());
readfile($page->get_io()->get_template_file());

View File

@@ -90,11 +90,9 @@ if ($hassiteconfig && is_enabled_auth('outage')) {
// Create 'Allowed IPs' settings.
$allowedips = outagelib::get_config()->allowedips;
$description = '';
if (!isset($CFG->auth_outage_check) || !$CFG->auth_outage_check) {
$description .= $OUTPUT->notification(get_string('allowedipsnoconfig', 'auth_outage'), 'notifyfailure');
}
if (trim($allowedips) == '') {
$message = 'allowedipsempty';
$type = 'notifymessage';
@@ -108,7 +106,6 @@ if ($hassiteconfig && is_enabled_auth('outage')) {
$description .= $OUTPUT->notification(get_string($message, 'auth_outage', ['ip' => getremoteaddr()]), $type);
$description .= '<p>'.get_string('ipblockersyntax', 'admin').'</p>';
$settings->add(new admin_setting_configiplist(
'auth_outage/allowedips',
get_string('allowediplist', 'admin'),
@@ -116,6 +113,14 @@ if ($hassiteconfig && is_enabled_auth('outage')) {
$defaults['allowedips']
));
// Create 'Static Page - Elements to Remove' settings.
$settings->add(new admin_setting_configtextarea(
'auth_outage/remove_selectors',
get_string('removeselectors', 'auth_outage'),
get_string('removeselectorsdescription', 'auth_outage'),
$defaults['remove_selectors']
));
// Create category for Outage.
$ADMIN->add('authsettings', new admin_category('auth_outage', get_string('pluginname', 'auth_outage')));
// Add settings page toconfigure defaults.

View File

@@ -174,7 +174,9 @@ class maintenance_static_page_test extends auth_outage_base_testcase {
/**
* Generates the maintenance page (not using preview mode).
*
* @param string $html Input HTML.
*
* @return string Output HTML.
*/
private function generated_page_html($html) {
@@ -228,7 +230,9 @@ class maintenance_static_page_test extends auth_outage_base_testcase {
/**
* Gets a fixture file for this test case.
*
* @param $file
*
* @return string
*/
private function get_fixture_path($file) {
@@ -278,4 +282,88 @@ class maintenance_static_page_test extends auth_outage_base_testcase {
$this->set_expected_exception('coding_exception');
maintenance_static_page_io::file_get_data(200);
}
public function test_remove_css_selector() {
$this->resetAfterTest(true);
$html = "<!DOCTYPE html>\n".
'<html><head><title>Title</title></head>'.
'<body>Content<b class="removeme">Goodbye cruel world.</b></body></html>';
set_config('remove_selectors', '.removeme', 'auth_outage');
$generated = $this->generated_page_html($html);
self::assertNotContains('removeme', $generated);
self::assertNotContains('Goodbye cruel world', $generated);
}
public function test_remove_css_selector_id() {
$this->resetAfterTest(true);
$html = "<!DOCTYPE html>\n".
'<html><head><title>Title</title></head>'.
'<body>Content<b id="removeme">Goodbye cruel world.</b></body></html>';
set_config('remove_selectors', '#removeme', 'auth_outage');
$generated = $this->generated_page_html($html);
self::assertNotContains('removeme', $generated);
self::assertNotContains('Goodbye cruel world', $generated);
}
public function test_remove_css_selector_with_multiline() {
$this->resetAfterTest(true);
$html = "<!DOCTYPE html>\n".
'<html><head><title>Title</title></head>'.
'<body>'.
'<b class="deleteme">Goodbye cruel world.</b>'.
'<b class="removeme">Goodbye cruel world.</b>'.
'</body></html>';
set_config('remove_selectors', ".removeme\n.deleteme", 'auth_outage');
$generated = $this->generated_page_html($html);
self::assertNotContains('removeme', $generated);
self::assertNotContains('deleteme', $generated);
self::assertNotContains('Goodbye cruel world', $generated);
}
public function test_remove_css_selector_needing_trim() {
$this->resetAfterTest(true);
$html = "<!DOCTYPE html>\n".
'<html><head><title>Title</title></head>'.
'<body>'.
'<b class="deleteme">Goodbye cruel world.</b>'.
'<b class="removeme">Goodbye cruel world.</b>'.
'</body></html>';
set_config('remove_selectors', " .removeme \n .deleteme ", 'auth_outage');
$generated = $this->generated_page_html($html);
self::assertNotContains('removeme', $generated);
self::assertNotContains('deleteme', $generated);
self::assertNotContains('Goodbye cruel world', $generated);
}
public function test_remove_css_selector_with_empty_line() {
$this->resetAfterTest(true);
$html = "<!DOCTYPE html>\n".
'<html><head><title>Title</title></head>'.
'<body>'.
'<b class="deleteme">Goodbye cruel world.</b>'.
'<b class="removeme">Goodbye cruel world.</b>'.
'</body></html>';
set_config('remove_selectors', "\n\n.removeme\n\n\n\n.deleteme\n\n", 'auth_outage');
$generated = $this->generated_page_html($html);
self::assertNotContains('removeme', $generated);
self::assertNotContains('deleteme', $generated);
self::assertNotContains('Goodbye cruel world', $generated);
}
public function test_remove_css_selector_with_invalid_id() {
$this->resetAfterTest(true);
$html = "<!DOCTYPE html>\n".
'<html><head><title>Title</title></head>'.
'<body>Content<b id="removeme">Goodbye cruel world.</b></body></html>';
set_config('remove_selectors', '#invalidid', 'auth_outage');
$generated = $this->generated_page_html($html);
self::assertContains('removeme', $generated);
self::assertContains('Goodbye cruel world', $generated);
}
}

View File

@@ -196,6 +196,7 @@ class outagelib_test extends advanced_testcase {
'default_title',
'default_warning_duration',
'allowedips',
'remove_selectors',
];
// Set config with values.
foreach ($keys as $k) {
@@ -221,6 +222,7 @@ class outagelib_test extends advanced_testcase {
'default_duration',
'default_title',
'default_warning_duration',
'remove_selectors',
];
$defaults = outagelib::get_config_defaults();
foreach ($keys as $k) {