xref: /plugin/deletepageguard/admin.php (revision 1a97af9eab9d5c777e1efac4ced808b8ed81e4af)
1<?php
2/**
3 * Admin interface for Delete Page Guard pattern validation
4 *
5 * @license GPL 2 (https://www.gnu.org/licenses/gpl-2.0.html) - see LICENSE.md
6 * @author  Johann Duscher <jonny.dee@posteo.net>
7 * @copyright 2025 Johann Duscher
8 */
9
10use dokuwiki\Extension\AdminPlugin;
11
12// Protect against direct call
13if (!defined('DOKU_INC')) die();
14
15/**
16 * Class admin_plugin_deletepageguard
17 *
18 * Provides an admin interface for validating Delete Page Guard patterns
19 * and offering configuration guidance to administrators.
20 */
21class admin_plugin_deletepageguard extends AdminPlugin {
22
23    /**
24     * Return sort order for position in admin menu
25     * @return int
26     */
27    public function getMenuSort() {
28        return 200;
29    }
30
31    /**
32     * Return true if access to this admin plugin is allowed
33     * @return bool
34     */
35    public function forAdminOnly() {
36        return true;
37    }
38
39    /**
40     * Handle user request
41     * @return void
42     */
43    public function handle() {
44        if (isset($_POST['validate_patterns'])) {
45            $this->validatePatternsFromPost();
46        }
47    }
48
49    /**
50     * Render HTML output
51     * @return void
52     */
53    public function html() {
54        echo '<h1>' . $this->getLang('admin_title') . '</h1>';
55        echo '<div class="level1">';
56
57        // Show current patterns and validation results
58        $patterns = $this->getConf('patterns');
59        $this->showPatternValidation($patterns);
60
61        // Add validation form
62        echo '<h2>' . $this->getLang('test_patterns_title') . '</h2>';
63        echo '<form method="post" accept-charset="utf-8">';
64        echo '<p>' . $this->getLang('test_patterns_help') . '</p>';
65        echo '<textarea name="test_patterns" rows="10" cols="80" class="edit">' . hsc($patterns) . '</textarea><br>';
66        echo '<input type="submit" name="validate_patterns" value="' . $this->getLang('validate_button') . '" class="button">';
67        echo '</form>';
68
69        echo '</div>';
70    }
71
72    /**
73     * Validate patterns from POST data
74     * @return void
75     */
76    private function validatePatternsFromPost() {
77        $patterns = $_POST['test_patterns'] ?? '';
78        echo '<h2>' . $this->getLang('validation_results_title') . '</h2>';
79        $this->showPatternValidation($patterns);
80    }
81
82    /**
83     * Display pattern validation results
84     * @param string $patterns The patterns to validate
85     * @return void
86     */
87    private function showPatternValidation($patterns) {
88        if (empty(trim($patterns))) {
89            echo '<div class="info">' . $this->getLang('no_patterns') . '</div>';
90            return;
91        }
92
93        $lines = preg_split('/\R+/', $patterns, -1, PREG_SPLIT_NO_EMPTY);
94        $hasErrors = false;
95        $validCount = 0;
96
97        echo '<div class="level2">';
98        echo '<h3>' . $this->getLang('validation_results') . '</h3>';
99        echo '<ul>';
100
101        foreach ($lines as $i => $line) {
102            $pattern = trim($line);
103            if ($pattern === '') continue;
104
105            $lineNum = $i + 1;
106            $status = $this->validateSinglePattern($pattern);
107
108            if ($status === true) {
109                echo '<li><span style="color: green; font-weight: bold;">✓</span> ';
110                echo '<strong>Line ' . $lineNum . ':</strong> <code>' . hsc($pattern) . '</code></li>';
111                $validCount++;
112            } else {
113                echo '<li><span style="color: red; font-weight: bold;">✗</span> ';
114                echo '<strong>Line ' . $lineNum . ':</strong> <code>' . hsc($pattern) . '</code><br>';
115                echo '&nbsp;&nbsp;&nbsp;<em style="color: red;">' . hsc($status) . '</em></li>';
116                $hasErrors = true;
117            }
118        }
119
120        echo '</ul>';
121
122        if (!$hasErrors && $validCount > 0) {
123            echo '<div class="success">' . sprintf($this->getLang('all_patterns_valid'), $validCount) . '</div>';
124        } elseif ($hasErrors) {
125            echo '<div class="error">' . $this->getLang('some_patterns_invalid') . '</div>';
126        }
127
128        echo '</div>';
129    }
130
131    /**
132     * Validate a single pattern and return detailed error message
133     * @param string $pattern The pattern to validate
134     * @return string|true True if valid, error message if invalid
135     */
136    private function validateSinglePattern($pattern) {
137        // Same validation logic as in action.php but with more detailed messages
138        if (strlen($pattern) > 1000) {
139            return $this->getLang('error_pattern_too_long');
140        }
141
142        if (preg_match('/(\(.*\).*\+.*\(.*\).*\+)|(\(.*\).*\*.*\(.*\).*\*)/', $pattern)) {
143            return $this->getLang('error_pattern_redos');
144        }
145
146        $escapedPattern = '/' . str_replace('/', '\/', $pattern) . '/u';
147        $test = @preg_match($escapedPattern, '');
148        if ($test === false) {
149            $error = error_get_last();
150            $errorMsg = $error && isset($error['message']) ? $error['message'] : 'Unknown error';
151            return $this->getLang('error_pattern_syntax') . ': ' . $errorMsg;
152        }
153
154        return true;
155    }
156}