1<?php 2 3use dokuwiki\Extension\AdminPlugin; 4use dokuwiki\ChangeLog\PageChangeLog; 5 6/** 7 * All DokuWiki plugins to extend the admin function 8 * need to inherit from this class 9 */ 10class admin_plugin_revert extends AdminPlugin 11{ 12 protected $cmd; 13 // some vars which might need tuning later 14 protected $max_lines = 800; // lines to read from changelog 15 protected $max_revs = 20; // numer of old revisions to check 16 17 18 /** 19 * Constructor 20 */ 21 public function __construct() 22 { 23 $this->setupLocale(); 24 } 25 26 /** 27 * access for managers 28 */ 29 public function forAdminOnly() 30 { 31 return false; 32 } 33 34 /** 35 * return sort order for position in admin menu 36 */ 37 public function getMenuSort() 38 { 39 return 40; 40 } 41 42 /** 43 * handle user request 44 */ 45 public function handle() 46 { 47 } 48 49 /** 50 * output appropriate html 51 */ 52 public function html() 53 { 54 global $INPUT; 55 56 echo $this->locale_xhtml('intro'); 57 58 $this->printSearchForm(); 59 60 if (is_array($INPUT->param('revert')) && checkSecurityToken()) { 61 $this->revertEdits($INPUT->arr('revert'), $INPUT->str('filter')); 62 } elseif ($INPUT->has('filter')) { 63 $this->listEdits($INPUT->str('filter')); 64 } 65 } 66 67 /** 68 * Display the form for searching spam pages 69 */ 70 protected function printSearchForm() 71 { 72 global $lang, $INPUT; 73 echo '<form action="" method="post"><div class="no">'; 74 echo '<label>' . $this->getLang('filter') . ': </label>'; 75 echo '<input type="text" name="filter" class="edit" value="' . hsc($INPUT->str('filter')) . '" /> '; 76 echo '<button type="submit">' . $lang['btn_search'] . '</button> '; 77 echo '<span>' . $this->getLang('note1') . '</span>'; 78 echo '</div></form><br /><br />'; 79 } 80 81 /** 82 * Start the reversion process 83 */ 84 protected function revertEdits($revert, $filter) 85 { 86 echo '<hr /><br />'; 87 echo '<p>' . $this->getLang('revstart') . '</p>'; 88 89 echo '<ul>'; 90 foreach ($revert as $id) { 91 global $REV; 92 93 // Managers can reach this tool without holding edit rights on every 94 // namespace. Normalize the submitted id and enforce per-page edit 95 // permission so pages the user is denied cannot be reverted or blanked. 96 // The listing only offers editable pages, so this guard is reached 97 // only by a hand-crafted request; such ids are silently skipped. 98 $id = cleanID($id); 99 if (auth_quickaclcheck($id) < AUTH_EDIT) { 100 continue; 101 } 102 103 // find the last non-spammy revision 104 $data = ''; 105 $pagelog = new PageChangeLog($id); 106 $old = $pagelog->getRevisions(0, $this->max_revs); 107 if ($old !== []) { 108 foreach ($old as $REV) { 109 $data = rawWiki($id, $REV); 110 if (!str_contains($data, (string) $filter)) break; 111 } 112 } 113 114 if ($data) { 115 saveWikiText($id, $data, 'old revision restored', false); 116 printf('<li><div class="li">' . $this->getLang('reverted') . '</div></li>', $id, $REV); 117 } else { 118 saveWikiText($id, '', '', false); 119 printf('<li><div class="li">' . $this->getLang('removed') . '</div></li>', $id); 120 } 121 @set_time_limit(10); 122 flush(); 123 } 124 echo '</ul>'; 125 126 echo '<p>' . $this->getLang('revstop') . '</p>'; 127 } 128 129 /** 130 * List recent edits matching the given filter 131 */ 132 protected function listEdits($filter) 133 { 134 global $conf; 135 global $lang; 136 echo '<hr /><br />'; 137 echo '<form action="" method="post"><div class="no">'; 138 echo '<input type="hidden" name="filter" value="' . hsc($filter) . '" />'; 139 formSecurityToken(); 140 141 $recents = getRecents(0, $this->max_lines); 142 echo '<ul>'; 143 144 $cnt = 0; 145 foreach ($recents as $recent) { 146 // only offer pages the user may actually revert; getRecents() already 147 // filtered to read permission, this narrows it to edit permission 148 if ($recent['perms'] < AUTH_EDIT) continue; 149 if ($filter) { 150 if (!str_contains(rawWiki($recent['id']), (string) $filter)) continue; 151 } 152 153 $cnt++; 154 $date = dformat($recent['date']); 155 156 echo ($recent['type'] === DOKU_CHANGE_TYPE_MINOR_EDIT) ? '<li class="minor">' : '<li>'; 157 echo '<div class="li">'; 158 echo '<input type="checkbox" name="revert[]" value="' . hsc($recent['id']) . 159 '" checked="checked" id="revert__' . $cnt . '" />'; 160 echo ' <label for="revert__' . $cnt . '">' . $date . '</label> '; 161 162 echo '<a href="' . wl($recent['id'], "do=diff") . '">'; 163 $p = []; 164 $p['src'] = DOKU_BASE . 'lib/images/diff.png'; 165 $p['width'] = 15; 166 $p['height'] = 11; 167 $p['title'] = $lang['diff']; 168 $p['alt'] = $lang['diff']; 169 $att = buildAttributes($p); 170 echo "<img $att />"; 171 echo '</a> '; 172 173 echo '<a href="' . wl($recent['id'], "do=revisions") . '">'; 174 $p = []; 175 $p['src'] = DOKU_BASE . 'lib/images/history.png'; 176 $p['width'] = 12; 177 $p['height'] = 14; 178 $p['title'] = $lang['btn_revs']; 179 $p['alt'] = $lang['btn_revs']; 180 $att = buildAttributes($p); 181 echo "<img $att />"; 182 echo '</a> '; 183 184 echo html_wikilink(':' . $recent['id'], (useHeading('navigation')) ? null : $recent['id']); 185 echo ' – ' . htmlspecialchars($recent['sum']); 186 187 echo ' <span class="user">'; 188 echo $recent['user'] . ' ' . $recent['ip']; 189 echo '</span>'; 190 191 echo '</div>'; 192 echo '</li>'; 193 194 @set_time_limit(10); 195 flush(); 196 } 197 echo '</ul>'; 198 199 echo '<p>'; 200 echo '<button type="submit">' . $this->getLang('revert') . '</button> '; 201 printf($this->getLang('note2'), hsc($filter)); 202 echo '</p>'; 203 204 echo '</div></form>'; 205 } 206} 207//Setup VIM: ex: et ts=4 : 208