1<?php 2 3if(!defined('DOKU_INC')) die(); 4define(APPROVED, 'Approved'); 5define(READY_FOR_APPROVAL, 'Ready for approval'); 6 7define(METADATA_VERSION_KEY, 'plugin_approve_version'); 8 9class action_plugin_approve_approve extends DokuWiki_Action_Plugin { 10 11 private $hlp; 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 } 26 27 function handle_diff_accept(Doku_Event $event, $param) { 28 global $ID; 29 30 if ($this->hlp->in_namespace($this->getConf('no_apr_namespaces'), $ID)) return; 31 32 if ($event->data == 'diff' && isset($_GET['approve'])) { 33 ptln('<a href="'.DOKU_URL.'doku.php?id='.$_GET['id'].'&approve=approve">'.$this->getLang('approve').'</a>'); 34 } 35 36 if ($event->data == 'diff' && isset($_GET['ready_for_approval']) && $this->getConf('ready_for_approval') === 1) { 37 ptln('<a href="'.DOKU_URL.'doku.php?id='.$_GET['id'].'&ready_for_approval=ready_for_approval">'.$this->getLang('approve_ready').'</a>'); 38 } 39 } 40 41 function handle_showrev(Doku_Event $event, $param) { 42 global $ID, $REV; 43 44 $last = $this->find_lastest_approved(); 45 if ($last == $REV) 46 $event->preventDefault(); 47 } 48 49 function can_approve() { 50 global $ID; 51 return auth_quickaclcheck($ID) >= AUTH_DELETE; 52 } 53 54 function can_edit() { 55 global $ID; 56 return auth_quickaclcheck($ID) >= AUTH_EDIT; 57 } 58 59 function handle_approve(Doku_Event $event, $param) { 60 global $ID, $REV, $INFO; 61 62 if ($this->hlp->in_namespace($this->getConf('no_apr_namespaces'), $ID)) return; 63 64 if ($event->data == 'show' && isset($_GET['approve'])) { 65 if ( ! $this->can_approve()) return; 66 67 //create new page revison 68 saveWikiText($ID, rawWiki($ID), APPROVED); 69 70 header('Location: ?id='.$ID); 71 } 72 73 if ($event->data == 'show' && isset($_GET['ready_for_approval'])) { 74 if ( ! $this->can_edit()) return; 75 76 //change last commit comment to Approved 77 $meta = p_read_metadata($ID); 78 $meta[current][last_change][sum] = $meta[persistent][last_change][sum] = READY_FOR_APPROVAL; 79 $meta[current][last_change][user] = $meta[persistent][last_change][user] = $INFO[client]; 80 if (!array_key_exists($INFO[client], $meta[current][contributor])) { 81 $meta[current][contributor][$INFO[client]] = $INFO[userinfo][name]; 82 $meta[persistent][contributor][$INFO[client]] = $INFO[userinfo][name]; 83 } 84 p_save_metadata($ID, $meta); 85 //update changelog 86 //remove last line from file 87 $changelog_file = metaFN($ID, '.changes'); 88 $changes = file($changelog_file, FILE_SKIP_EMPTY_LINES); 89 $lastLogLine = array_pop($changes); 90 $info = parseChangelogLine($lastLogLine); 91 92 $info[user] = $INFO[client]; 93 $info[sum] = APPROVED; 94 95 $logline = implode("\t", $info)."\n"; 96 array_push($changes, $logline); 97 98 io_saveFile($changelog_file, implode('', $changes)); 99 100 header('Location: ?id='.$ID); 101 } 102 } 103 function handle_viewer(Doku_Event $event, $param) { 104 global $REV, $ID; 105 if ($event->data != 'show') return; 106 if (auth_quickaclcheck($ID) > AUTH_READ || ($this->hlp->in_namespace($this->getConf('no_apr_namespaces'), $ID))) return; 107 108 $last = $this->find_lastest_approved(); 109 //no page is approved 110 if ($last == -1) return; 111 //approved page is the newest page 112 if ($last == 0) return; 113 114 //if we are viewing lastest revision, show last approved 115 if ($REV == 0) header("Location: ?id=$ID&rev=$last"); 116 } 117 function find_lastest_approved() { 118 global $ID; 119 $m = p_get_metadata($ID); 120 $sum = $m['last_change']['sum']; 121 if ($sum == APPROVED) 122 return 0; 123 124 $changelog = new PageChangeLog($ID); 125 //wyszukaj najnowszej zatwierdzonej 126 //poszukaj w dół 127 $chs = $changelog->getRevisions(0, 10000); 128 foreach ($chs as $rev) { 129 $ch = $changelog->getRevisionInfo($rev); 130 if ($ch['sum'] == APPROVED) 131 return $rev; 132 } 133 return -1; 134 } 135 136 function handle_display_banner(Doku_Event $event, $param) { 137 global $ID, $REV, $INFO; 138 139 if ($this->hlp->in_namespace($this->getConf('no_apr_namespaces'), $ID)) return; 140 if ($event->data != 'show') return; 141 if (!$INFO['exists']) return; 142 143 $sum = $this->hlp->page_sum($ID, $REV); 144 145 ptln('<div class="approval '.($sum == APPROVED ? 'approved_yes' : ($sum == READY_FOR_APPROVAL && $this->getConf('ready_for_approval') === 1 ? 'approved_ready' :'approved_no')).'">'); 146 147 tpl_pageinfo(); 148 ptln(' | '); 149 $last_approved_rev = $this->find_lastest_approved(); 150 if ($sum == APPROVED) { 151 $version = p_get_metadata($ID, METADATA_VERSION_KEY); 152 if (!$version) { 153 $version = $this->calculateVersion($ID); 154 p_set_metadata($ID, array(METADATA_VERSION_KEY => $version)); 155 } 156 157 ptln('<span>'.$this->getLang('approved').'</span> (' . $this->getLang('version') . ': ' . $version 158 . ')'); 159 if ($REV != 0 && auth_quickaclcheck($ID) > AUTH_READ) { 160 ptln('<a href="'.wl($ID).'">'); 161 ptln($this->getLang(p_get_metadata($ID, 'last_change sum') == APPROVED ? 'newest_approved' : 'newest_draft')); 162 ptln('</a>'); 163 } else if ($REV != 0 && $REV != $last_approved_rev) { 164 ptln('<a href="'.wl($ID).'">'); 165 ptln($this->getLang('newest_approved')); 166 ptln('</a>'); 167 } 168 } else { 169 ptln('<span>'.$this->getLang('draft').'</span>'); 170 171 if ($sum == READY_FOR_APPROVAL && $this->getConf('ready_for_approval') === 1) { 172 ptln('<span>| '.$this->getLang('marked_approve_ready').'</span>'); 173 } 174 175 176 if ($last_approved_rev == -1) { 177 if ($REV != 0) { 178 ptln('<a href="'.wl($ID).'">'); 179 ptln($this->getLang('newest_draft')); 180 ptln('</a>'); 181 } 182 } else { 183 if ($last_approved_rev != 0) 184 ptln('<a href="'.wl($ID, array('rev' => $last_approved_rev)).'">'); 185 else 186 ptln('<a href="'.wl($ID).'">'); 187 188 ptln($this->getLang('newest_approved')); 189 ptln('</a>'); 190 } 191 192 if ($REV == 0 && $this->can_edit() && $sum != READY_FOR_APPROVAL && $this->getConf('ready_for_approval') === 1) { 193 ptln('<a href="'.wl($ID, array('rev' => $last_approved_rev, 'do' => 'diff', 194 'ready_for_approval' => 'ready_for_approval')).'">'); 195 ptln($this->getLang('approve_ready')); 196 ptln('</a>'); 197 } 198 199 //można zatwierdzać tylko najnowsze strony 200 if ($REV == 0 && $this->can_approve()) { 201 ptln('<a href="'.wl($ID, array('rev' => $last_approved_rev, 'do' => 'diff', 202 'approve' => 'approve')).'">'); 203 ptln($this->getLang('approve')); 204 ptln('</a>'); 205 } 206 207 208 } 209 ptln('</div>'); 210 } 211 212 /** 213 * Check if the page has to be changed 214 * 215 * @param Doku_Event $event event object by reference 216 * @param mixed $param [the parameters passed as fifth argument to register_hook() when this 217 * handler was registered] 218 * @return void 219 */ 220 public function handle_pagesave_before(Doku_Event $event, $param) { 221 $id = $event->data['id']; 222 if ($this->hlp->in_namespace($this->getConf('no_apr_namespaces'), $id)) return; 223 224 //save page if summary is provided 225 if($event->data['summary'] == APPROVED) { 226 $event->data['contentChanged'] = true; 227 228 $version = p_get_metadata($id, METADATA_VERSION_KEY); 229 230 //calculate current version 231 if (!$version) { 232 $version = $this->calculateVersion($id); 233 } else { 234 $version += 1; 235 } 236 237 p_set_metadata($id, array(METADATA_VERSION_KEY => $version)); 238 } 239 } 240 241 /** 242 * Calculate current version 243 * 244 * @param $id 245 * @return int 246 */ 247 protected function calculateVersion($id) { 248 $version = 1; 249 250 $changelog = new PageChangeLog($id); 251 $first = 0; 252 $num = 100; 253 while (count($revs = $changelog->getRevisions($first, $num)) > 0) { 254 foreach ($revs as $rev) { 255 $revInfo = $changelog->getRevisionInfo($rev); 256 if ($revInfo['sum'] == APPROVED) { 257 $version += 1; 258 } 259 } 260 $first += $num; 261 } 262 263 return $version; 264 } 265 266} 267