diff --git a/classes/local/controllers/maintenance_static_page_generator.php b/classes/local/controllers/maintenance_static_page_generator.php index 1dd1426..bb6bde4 100644 --- a/classes/local/controllers/maintenance_static_page_generator.php +++ b/classes/local/controllers/maintenance_static_page_generator.php @@ -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; + } } diff --git a/classes/local/outagelib.php b/classes/local/outagelib.php index 6c96c69..8ddfd17 100644 --- a/classes/local/outagelib.php +++ b/classes/local/outagelib.php @@ -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 */ diff --git a/lang/en/auth_outage.php b/lang/en/auth_outage.php index a451778..d6a20f3 100644 --- a/lang/en/auth_outage.php +++ b/lang/en/auth_outage.php @@ -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'; diff --git a/preview.php b/preview.php index 7ba4625..ef18d85 100644 --- a/preview.php +++ b/preview.php @@ -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()); diff --git a/settings.php b/settings.php index 239dca2..036876a 100644 --- a/settings.php +++ b/settings.php @@ -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 .= '

'.get_string('ipblockersyntax', 'admin').'

'; - $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. diff --git a/tests/phpunit/local/controllers/maintenance_static_page_test.php b/tests/phpunit/local/controllers/maintenance_static_page_test.php index 637bb52..89f74ce 100644 --- a/tests/phpunit/local/controllers/maintenance_static_page_test.php +++ b/tests/phpunit/local/controllers/maintenance_static_page_test.php @@ -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 = "\n". + 'Title'. + 'ContentGoodbye cruel world.'; + 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 = "\n". + 'Title'. + 'ContentGoodbye cruel world.'; + 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 = "\n". + 'Title'. + ''. + 'Goodbye cruel world.'. + 'Goodbye cruel world.'. + ''; + 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 = "\n". + 'Title'. + ''. + 'Goodbye cruel world.'. + 'Goodbye cruel world.'. + ''; + 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 = "\n". + 'Title'. + ''. + 'Goodbye cruel world.'. + 'Goodbye cruel world.'. + ''; + 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 = "\n". + 'Title'. + 'ContentGoodbye cruel world.'; + set_config('remove_selectors', '#invalidid', 'auth_outage'); + $generated = $this->generated_page_html($html); + + self::assertContains('removeme', $generated); + self::assertContains('Goodbye cruel world', $generated); + } } diff --git a/tests/phpunit/local/outagelib_test.php b/tests/phpunit/local/outagelib_test.php index afb1223..544599a 100644 --- a/tests/phpunit/local/outagelib_test.php +++ b/tests/phpunit/local/outagelib_test.php @@ -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) {