1<?php 2 3use dokuwiki\plugin\approve\meta\ApproveConst; 4 5if(!defined('DOKU_INC')) die(); 6 7class action_plugin_approve_approve extends DokuWiki_Action_Plugin { 8 9 /** @var DokuWiki_PluginInterface */ 10 protected $hlp; 11 12 function __construct(){ 13 $this->hlp = plugin_load('helper', 'approve'); 14 } 15 16 function register(Doku_Event_Handler $controller) { 17 18 $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handle_approve', array()); 19 $controller->register_hook('ACTION_ACT_PREPROCESS', 'BEFORE', $this, 'handle_viewer', array()); 20 $controller->register_hook('TPL_ACT_RENDER', 'AFTER', $this, 'handle_diff_accept', array()); 21 $controller->register_hook('TPL_ACT_RENDER', 'BEFORE', $this, 'handle_display_banner', array()); 22 $controller->register_hook('HTML_SHOWREV_OUTPUT', 'BEFORE', $this, 'handle_showrev', array()); 23 // ensure a page revision is created when summary changes: 24 $controller->register_hook('COMMON_WIKIPAGE_SAVE', 'BEFORE', $this, 'handle_pagesave_before'); 25 $controller->register_hook('COMMON_WIKIPAGE_SAVE', 'AFTER', $this, 'handle_pagesave_after'); 26 } 27 28 function handle_diff_accept(Doku_Event $event, $param) { 29 global $ID; 30 31 if ($this->hlp->in_namespace($this->getConf('no_apr_namespaces'), $ID)) return; 32 33 if ($event->data == 'diff' && isset($_GET['approve'])) { 34 ptln('<a href="'.DOKU_URL.'doku.php?id='.$_GET['id'].'&approve=approve">'.$this->getLang('approve').'</a>'); 35 } 36 37 if ($event->data == 'diff' && isset($_GET['ready_for_approval']) && $this->getConf('ready_for_approval') === 1) { 38 ptln('<a href="'.DOKU_URL.'doku.php?id='.$_GET['id'].'&ready_for_approval=ready_for_approval">'.$this->getLang('approve_ready').'</a>'); 39 } 40 } 41 42 function handle_showrev(Doku_Event $event, $param) { 43 global $REV; 44 45 $last = $this->find_lastest_approved(); 46 if ($last == $REV) 47 $event->preventDefault(); 48 } 49 50 function can_approve() { 51 global $ID; 52 return auth_quickaclcheck($ID) >= AUTH_DELETE; 53 } 54 55 function can_edit() { 56 global $ID; 57 return auth_quickaclcheck($ID) >= AUTH_EDIT; 58 } 59 60 function handle_approve(Doku_Event $event, $param) { 61 global $ID; 62 63 if ($this->hlp->in_namespace($this->getConf('no_apr_namespaces'), $ID)) return; 64 65 if ($event->data == 'show' && isset($_GET['approve'])) { 66 if ( ! $this->can_approve()) return; 67 68 //create new page revison 69 saveWikiText($ID, rawWiki($ID), ApproveConst::APPROVED); 70 71 header('Location: ?id='.$ID); 72 } elseif ($event->data == 'show' && isset($_GET['ready_for_approval'])) { 73 if ( ! $this->can_edit()) return; 74 75 //create new page revison 76 saveWikiText($ID, rawWiki($ID), ApproveConst::READY_FOR_APPROVAL); 77 78 header('Location: ?id='.$ID); 79 } 80 } 81 82 function handle_viewer(Doku_Event $event, $param) { 83 global $REV, $ID; 84 if ($event->data != 'show') return; 85 if (auth_quickaclcheck($ID) > AUTH_READ || ($this->hlp->in_namespace($this->getConf('no_apr_namespaces'), $ID))) return; 86 87 $last = $this->find_lastest_approved(); 88 //no page is approved 89 if ($last == -1) return; 90 //approved page is the newest page 91 if ($last == 0) return; 92 93 //if we are viewing lastest revision, show last approved 94 if ($REV == 0) header("Location: ?id=$ID&rev=$last"); 95 } 96 97 function find_lastest_approved() { 98 global $ID; 99 $m = p_get_metadata($ID); 100 $sum = $m['last_change']['sum']; 101 if ($sum == ApproveConst::APPROVED) 102 return 0; 103 104 $changelog = new PageChangeLog($ID); 105 106 $chs = $changelog->getRevisions(0, 10000); 107 foreach ($chs as $rev) { 108 $ch = $changelog->getRevisionInfo($rev); 109 if ($ch['sum'] == ApproveConst::APPROVED) 110 return $rev; 111 } 112 return -1; 113 } 114 115 function handle_display_banner(Doku_Event $event, $param) { 116 global $ID, $REV, $INFO; 117 118 if ($this->hlp->in_namespace($this->getConf('no_apr_namespaces'), $ID)) return; 119 if ($event->data != 'show') return; 120 if (!$INFO['exists']) return; 121 122 $sum = $this->hlp->page_sum($ID, $REV); 123 124 125 $classes = array(); 126 if ($this->getConf('prettyprint')) { 127 $classes[] = 'plugin__approve_noprint'; 128 } 129 130 if ($sum == ApproveConst::APPROVED) { 131 $classes[] = 'plugin__approve_green'; 132 } elseif ($sum == ApproveConst::READY_FOR_APPROVAL && $this->getConf('ready_for_approval')) { 133 $classes[] = 'plugin__approve_ready'; 134 } else { 135 $classes[] = 'plugin__approve_red'; 136 } 137 138 ptln('<div id="plugin__approve" class="' . implode(' ', $classes) . '">'); 139 140 tpl_pageinfo(); 141 ptln(' | '); 142 $last_approved_rev = $this->find_lastest_approved(); 143 if ($sum == ApproveConst::APPROVED) { 144 $versions = p_get_metadata($ID, ApproveConst::METADATA_VERSIONS_KEY); 145 if (!$versions) { 146 $versions = $this->render_metadata_for_approved_page($ID); 147 } 148 if (empty($REV)) { 149 $version = $versions[0]; 150 } else { 151 $version = $versions[$REV]; 152 } 153 154 ptln('<strong>'.$this->getLang('approved').'</strong> (' . $this->getLang('version') . ': ' . $version 155 . ')'); 156 if ($REV != 0 && auth_quickaclcheck($ID) > AUTH_READ) { 157 ptln('<a href="'.wl($ID).'">'); 158 ptln($this->getLang(p_get_metadata($ID, 'last_change sum') == ApproveConst::APPROVED ? 'newest_approved' : 'newest_draft')); 159 ptln('</a>'); 160 } else if ($REV != 0 && $REV != $last_approved_rev) { 161 ptln('<a href="'.wl($ID).'">'); 162 ptln($this->getLang('newest_approved')); 163 ptln('</a>'); 164 } 165 } else { 166 ptln('<span>'.$this->getLang('draft').'</span>'); 167 168 if ($sum == ApproveConst::READY_FOR_APPROVAL && $this->getConf('ready_for_approval') === 1) { 169 ptln('<span>| '.$this->getLang('marked_approve_ready').'</span>'); 170 } 171 172 173 if ($last_approved_rev == -1) { 174 if ($REV != 0) { 175 ptln('<a href="'.wl($ID).'">'); 176 ptln($this->getLang('newest_draft')); 177 ptln('</a>'); 178 } 179 } else { 180 if ($last_approved_rev != 0) 181 ptln('<a href="'.wl($ID, array('rev' => $last_approved_rev)).'">'); 182 else 183 ptln('<a href="'.wl($ID).'">'); 184 185 ptln($this->getLang('newest_approved')); 186 ptln('</a>'); 187 } 188 189 if ($REV == 0 && $this->can_edit() && $sum != ApproveConst::READY_FOR_APPROVAL && $this->getConf('ready_for_approval') === 1) { 190 ptln(' | <a href="'.wl($ID, array('rev' => $last_approved_rev, 'do' => 'diff', 191 'ready_for_approval' => 'ready_for_approval')).'">'); 192 ptln($this->getLang('approve_ready')); 193 ptln('</a>'); 194 } 195 196 if ($REV == 0 && $this->can_approve()) { 197 ptln(' | <a href="'.wl($ID, array('rev' => $last_approved_rev, 'do' => 'diff', 198 'approve' => 'approve')).'">'); 199 ptln($this->getLang('approve')); 200 ptln('</a>'); 201 } 202 203 204 } 205 ptln('</div>'); 206 } 207 208 /** 209 * Check if the page has to be changed 210 * 211 * @param Doku_Event $event event object by reference 212 * @param mixed $param [the parameters passed as fifth argument to register_hook() when this 213 * handler was registered] 214 * @return void 215 */ 216 public function handle_pagesave_before(Doku_Event $event, $param) { 217 global $REV; 218 $id = $event->data['id']; 219 if ($this->hlp->in_namespace($this->getConf('no_apr_namespaces'), $id)) return; 220 221 //save page if summary is provided 222 if($event->data['summary'] == ApproveConst::APPROVED) { 223 $event->data['contentChanged'] = true; 224 } 225 } 226 227 /** 228 * @param Doku_Event $event 229 * @param $param 230 */ 231 public function handle_pagesave_after(Doku_Event $event, $param) { 232 global $REV; 233 $id = $event->data['id']; 234 if ($this->hlp->in_namespace($this->getConf('no_apr_namespaces'), $id)) return; 235 236 //save page if summary is provided 237 if($event->data['summary'] == ApproveConst::APPROVED) { 238 239 $versions = p_get_metadata($id, ApproveConst::METADATA_VERSIONS_KEY); 240 //calculate versions 241 if (!$versions) { 242 $this->render_metadata_for_approved_page($id, $event->data['newRevision']); 243 } else { 244 $curver = $versions[0] + 1; 245 $versions[0] = $curver; 246 $versions[$event->data['newRevision']] = $curver; 247 p_set_metadata($id, array(ApproveConst::METADATA_VERSIONS_KEY => $versions)); 248 } 249 } 250 } 251 252 253 /** 254 * Calculate current version 255 * 256 * @param $id 257 * @return array 258 */ 259 protected function render_metadata_for_approved_page($id, $currev=false) { 260 if (!$currev) $currev = @filemtime(wikiFN($id)); 261 262 $version = $this->approved($id); 263 //version for current page 264 $curver = $version + 1; 265 $versions = array(0 => $curver, $currev => $curver); 266 267 $changelog = new PageChangeLog($id); 268 $first = 0; 269 $num = 100; 270 while (count($revs = $changelog->getRevisions($first, $num)) > 0) { 271 foreach ($revs as $rev) { 272 $revInfo = $changelog->getRevisionInfo($rev); 273 if ($revInfo['sum'] == ApproveConst::APPROVED) { 274 $versions[$rev] = $version; 275 $version -= 1; 276 } 277 } 278 $first += $num; 279 } 280 281 p_set_metadata($id, array(ApproveConst::METADATA_VERSIONS_KEY => $versions)); 282 283 return $versions; 284 } 285 286 /** 287 * Get the number of approved pages 288 * @param $id 289 * @return int 290 */ 291 protected function approved($id) { 292 $count = 0; 293 294 $changelog = new PageChangeLog($id); 295 $first = 0; 296 $num = 100; 297 while (count($revs = $changelog->getRevisions($first, $num)) > 0) { 298 foreach ($revs as $rev) { 299 $revInfo = $changelog->getRevisionInfo($rev); 300 if ($revInfo['sum'] == ApproveConst::APPROVED) { 301 $count += 1; 302 } 303 } 304 $first += $num; 305 } 306 307 return $count; 308 } 309} 310