11a97af9eSJohann Duscher<?php 21a97af9eSJohann Duscher/** 31a97af9eSJohann Duscher * Admin interface for Delete Page Guard pattern validation 41a97af9eSJohann Duscher * 51a97af9eSJohann Duscher * @license GPL 2 (https://www.gnu.org/licenses/gpl-2.0.html) - see LICENSE.md 61a97af9eSJohann Duscher * @author Johann Duscher <jonny.dee@posteo.net> 71a97af9eSJohann Duscher * @copyright 2025 Johann Duscher 81a97af9eSJohann Duscher */ 91a97af9eSJohann Duscher 101a97af9eSJohann Duscheruse dokuwiki\Extension\AdminPlugin; 111a97af9eSJohann Duscher 121a97af9eSJohann Duscher// Protect against direct call 131a97af9eSJohann Duscherif (!defined('DOKU_INC')) die(); 141a97af9eSJohann Duscher 151a97af9eSJohann Duscher/** 161a97af9eSJohann Duscher * Class admin_plugin_deletepageguard 171a97af9eSJohann Duscher * 181a97af9eSJohann Duscher * Provides an admin interface for validating Delete Page Guard patterns 191a97af9eSJohann Duscher * and offering configuration guidance to administrators. 201a97af9eSJohann Duscher */ 211a97af9eSJohann Duscherclass admin_plugin_deletepageguard extends AdminPlugin { 221a97af9eSJohann Duscher 231a97af9eSJohann Duscher /** 241a97af9eSJohann Duscher * Return sort order for position in admin menu 251a97af9eSJohann Duscher * @return int 261a97af9eSJohann Duscher */ 271a97af9eSJohann Duscher public function getMenuSort() { 281a97af9eSJohann Duscher return 200; 291a97af9eSJohann Duscher } 301a97af9eSJohann Duscher 311a97af9eSJohann Duscher /** 32*9a383d51SJohann Duscher * Return the text to display in the admin menu 33*9a383d51SJohann Duscher * @return string 34*9a383d51SJohann Duscher */ 35*9a383d51SJohann Duscher public function getMenuText($language) { 36*9a383d51SJohann Duscher return $this->getLang('menu'); 37*9a383d51SJohann Duscher } 38*9a383d51SJohann Duscher 39*9a383d51SJohann Duscher /** 401a97af9eSJohann Duscher * Return true if access to this admin plugin is allowed 411a97af9eSJohann Duscher * @return bool 421a97af9eSJohann Duscher */ 431a97af9eSJohann Duscher public function forAdminOnly() { 441a97af9eSJohann Duscher return true; 451a97af9eSJohann Duscher } 461a97af9eSJohann Duscher 471a97af9eSJohann Duscher /** 481a97af9eSJohann Duscher * Handle user request 491a97af9eSJohann Duscher * @return void 501a97af9eSJohann Duscher */ 511a97af9eSJohann Duscher public function handle() { 52*9a383d51SJohann Duscher // Nothing to handle - validation is done in html() method 531a97af9eSJohann Duscher } 541a97af9eSJohann Duscher 551a97af9eSJohann Duscher /** 561a97af9eSJohann Duscher * Render HTML output 571a97af9eSJohann Duscher * @return void 581a97af9eSJohann Duscher */ 591a97af9eSJohann Duscher public function html() { 601a97af9eSJohann Duscher echo '<h1>' . $this->getLang('admin_title') . '</h1>'; 611a97af9eSJohann Duscher echo '<div class="level1">'; 621a97af9eSJohann Duscher 63*9a383d51SJohann Duscher // Determine which patterns to show - use POST data if available, otherwise config 64*9a383d51SJohann Duscher $patterns = $_POST['test_patterns'] ?? $this->getConf('patterns'); 65*9a383d51SJohann Duscher 66*9a383d51SJohann Duscher // Show validation results if form was submitted 67*9a383d51SJohann Duscher if (isset($_POST['validate_patterns'])) { 68*9a383d51SJohann Duscher echo '<h2>' . $this->getLang('validation_results_title') . '</h2>'; 691a97af9eSJohann Duscher $this->showPatternValidation($patterns); 70*9a383d51SJohann Duscher } else { 71*9a383d51SJohann Duscher // Show current config patterns on initial load 72*9a383d51SJohann Duscher $this->showPatternValidation($patterns); 73*9a383d51SJohann Duscher } 741a97af9eSJohann Duscher 751a97af9eSJohann Duscher // Add validation form 761a97af9eSJohann Duscher echo '<h2>' . $this->getLang('test_patterns_title') . '</h2>'; 771a97af9eSJohann Duscher echo '<form method="post" accept-charset="utf-8">'; 781a97af9eSJohann Duscher echo '<p>' . $this->getLang('test_patterns_help') . '</p>'; 791a97af9eSJohann Duscher echo '<textarea name="test_patterns" rows="10" cols="80" class="edit">' . hsc($patterns) . '</textarea><br>'; 801a97af9eSJohann Duscher echo '<input type="submit" name="validate_patterns" value="' . $this->getLang('validate_button') . '" class="button">'; 811a97af9eSJohann Duscher echo '</form>'; 821a97af9eSJohann Duscher 831a97af9eSJohann Duscher echo '</div>'; 841a97af9eSJohann Duscher } 851a97af9eSJohann Duscher 861a97af9eSJohann Duscher /** 871a97af9eSJohann Duscher * Display pattern validation results 881a97af9eSJohann Duscher * @param string $patterns The patterns to validate 891a97af9eSJohann Duscher * @return void 901a97af9eSJohann Duscher */ 911a97af9eSJohann Duscher private function showPatternValidation($patterns) { 921a97af9eSJohann Duscher if (empty(trim($patterns))) { 931a97af9eSJohann Duscher echo '<div class="info">' . $this->getLang('no_patterns') . '</div>'; 941a97af9eSJohann Duscher return; 951a97af9eSJohann Duscher } 961a97af9eSJohann Duscher 971a97af9eSJohann Duscher $lines = preg_split('/\R+/', $patterns, -1, PREG_SPLIT_NO_EMPTY); 981a97af9eSJohann Duscher $hasErrors = false; 991a97af9eSJohann Duscher $validCount = 0; 1001a97af9eSJohann Duscher 1011a97af9eSJohann Duscher echo '<div class="level2">'; 1021a97af9eSJohann Duscher echo '<h3>' . $this->getLang('validation_results') . '</h3>'; 1031a97af9eSJohann Duscher echo '<ul>'; 1041a97af9eSJohann Duscher 1051a97af9eSJohann Duscher foreach ($lines as $i => $line) { 1061a97af9eSJohann Duscher $pattern = trim($line); 1071a97af9eSJohann Duscher if ($pattern === '') continue; 1081a97af9eSJohann Duscher 1091a97af9eSJohann Duscher $lineNum = $i + 1; 1101a97af9eSJohann Duscher $status = $this->validateSinglePattern($pattern); 1111a97af9eSJohann Duscher 1121a97af9eSJohann Duscher if ($status === true) { 1131a97af9eSJohann Duscher echo '<li><span style="color: green; font-weight: bold;">✓</span> '; 1141a97af9eSJohann Duscher echo '<strong>Line ' . $lineNum . ':</strong> <code>' . hsc($pattern) . '</code></li>'; 1151a97af9eSJohann Duscher $validCount++; 1161a97af9eSJohann Duscher } else { 1171a97af9eSJohann Duscher echo '<li><span style="color: red; font-weight: bold;">✗</span> '; 1181a97af9eSJohann Duscher echo '<strong>Line ' . $lineNum . ':</strong> <code>' . hsc($pattern) . '</code><br>'; 1191a97af9eSJohann Duscher echo ' <em style="color: red;">' . hsc($status) . '</em></li>'; 1201a97af9eSJohann Duscher $hasErrors = true; 1211a97af9eSJohann Duscher } 1221a97af9eSJohann Duscher } 1231a97af9eSJohann Duscher 1241a97af9eSJohann Duscher echo '</ul>'; 1251a97af9eSJohann Duscher 1261a97af9eSJohann Duscher if (!$hasErrors && $validCount > 0) { 1271a97af9eSJohann Duscher echo '<div class="success">' . sprintf($this->getLang('all_patterns_valid'), $validCount) . '</div>'; 1281a97af9eSJohann Duscher } elseif ($hasErrors) { 1291a97af9eSJohann Duscher echo '<div class="error">' . $this->getLang('some_patterns_invalid') . '</div>'; 1301a97af9eSJohann Duscher } 1311a97af9eSJohann Duscher 1321a97af9eSJohann Duscher echo '</div>'; 1331a97af9eSJohann Duscher } 1341a97af9eSJohann Duscher 1351a97af9eSJohann Duscher /** 136*9a383d51SJohann Duscher * Validate a single pattern by delegating to the action plugin's validator. 137*9a383d51SJohann Duscher * This ensures consistent validation logic between admin UI and runtime checks. 138*9a383d51SJohann Duscher * 1391a97af9eSJohann Duscher * @param string $pattern The pattern to validate 1401a97af9eSJohann Duscher * @return string|true True if valid, error message if invalid 1411a97af9eSJohann Duscher */ 1421a97af9eSJohann Duscher private function validateSinglePattern($pattern) { 143*9a383d51SJohann Duscher // Load the action plugin to use its centralized validation logic 144*9a383d51SJohann Duscher $actionPlugin = plugin_load('action', 'deletepageguard'); 145*9a383d51SJohann Duscher if (!$actionPlugin) { 146*9a383d51SJohann Duscher return 'Error: Could not load validation service'; 1471a97af9eSJohann Duscher } 1481a97af9eSJohann Duscher 149*9a383d51SJohann Duscher // Use the action plugin's validateRegexPattern method (without line number) 150*9a383d51SJohann Duscher $result = $actionPlugin->validateRegexPattern($pattern, 0); 151*9a383d51SJohann Duscher 152*9a383d51SJohann Duscher // The action plugin returns true for valid, string for invalid 153*9a383d51SJohann Duscher // We need to strip the "Line 0: " prefix if present 154*9a383d51SJohann Duscher if (is_string($result)) { 155*9a383d51SJohann Duscher $result = preg_replace('/^Line 0: /', '', $result); 1561a97af9eSJohann Duscher } 1571a97af9eSJohann Duscher 158*9a383d51SJohann Duscher return $result; 1591a97af9eSJohann Duscher } 1601a97af9eSJohann Duscher}