1<?php 2 3// must be run within DokuWiki 4if(!defined('DOKU_INC')) die(); 5 6 7class syntax_plugin_approve_table extends DokuWiki_Syntax_Plugin { 8 9 protected $states = ['approved', 'draft', 'ready for approval']; 10 11 function getType() { 12 return 'substition'; 13 } 14 15 function getSort() { 16 return 20; 17 } 18 19 function PType() { 20 return 'block'; 21 } 22 23 function connectTo($mode) { 24 $this->Lexer->addSpecialPattern('----+ *approve table *-+\n.*?----+', $mode,'plugin_approve_table'); 25 } 26 27 function handle($match, $state, $pos, Doku_Handler $handler){ 28 $lines = explode("\n", $match); 29 array_shift($lines); 30 array_pop($lines); 31 32 $params = [ 33 'namespace' => '', 34 'filter' => false, 35 'states' => $this->states, 36 'summarize' => true, 37 'maintainer' => null 38 ]; 39 40 foreach ($lines as $line) { 41 $pair = explode(':', $line, 2); 42 if (count($pair) < 2) { 43 continue; 44 } 45 $key = trim($pair[0]); 46 $value = trim($pair[1]); 47 if ($key == 'states') { 48 $value = array_map('trim', explode(',', $value)); 49 //normalize 50 $value = array_map('strtolower', $value); 51 $value = array_map('ucfirst', $value); 52 foreach ($value as $state) { 53 if (!in_array($state, $this->states)) { 54 msg('approve plugin: unknown state "'.$state.'" should be: ' . 55 implode(', ', $this->states), -1); 56 return false; 57 } 58 } 59 } elseif($key == 'filter') { 60 $value = trim($value, '/'); 61 if (preg_match('/' . $value . '/', null) === false) { 62 msg('approve plugin: invalid filter regex', -1); 63 return false; 64 } 65 } elseif ($key == 'summarize') { 66 $value = $value == '0' ? false : true; 67 } elseif ($key == 'namespace') { 68 $value = trim(cleanID($value), ':'); 69 } 70 $params[$key] = $value; 71 } 72 return $params; 73 } 74 75 /** 76 * Render xhtml output or metadata 77 * 78 * @param string $mode Renderer mode (supported modes: xhtml) 79 * @param Doku_Renderer $renderer The renderer 80 * @param array $data The data from the handler() function 81 * 82 * @return bool If rendering was successful. 83 */ 84 85 public function render($mode, Doku_Renderer $renderer, $data) 86 { 87 $method = 'render' . ucfirst($mode); 88 if (method_exists($this, $method)) { 89 call_user_func([$this, $method], $renderer, $data); 90 return true; 91 } 92 return false; 93 } 94 95 /** 96 * Render metadata 97 * 98 * @param Doku_Renderer $renderer The renderer 99 * @param array $data The data from the handler() function 100 */ 101 public function renderMetadata(Doku_Renderer $renderer, $params) 102 { 103 $plugin_name = $this->getPluginName(); 104 $renderer->meta['plugin'][$plugin_name] = []; 105 106 if ($params['maintainer'] == '$USER$') { 107 $renderer->meta['plugin'][$plugin_name]['dynamic_maintainer'] = true; 108 } 109 110 $renderer->meta['plugin'][$plugin_name]['approve_table'] = true; 111 } 112 113 public function renderXhtml(Doku_Renderer $renderer, $params) 114 { 115 global $INFO; 116 117 global $conf; 118 /** @var DokuWiki_Auth_Plugin $auth */ 119 global $auth; 120 121 /** @var \helper_plugin_ireadit_db $db_helper */ 122 $db_helper = plugin_load('helper', 'approve_db'); 123 $sqlite = $db_helper->getDB(); 124 125 if ($params['maintainer'] == '$USER$') { 126 $params['maintainer'] = $INFO['client']; 127 } 128 129 $maintainer_query = ''; 130 $query_args = [$params['namespace'].'%']; 131 if ($params['maintainer']) { 132 $maintainer_query .= " AND page.maintainer LIKE ?"; 133 $query_args[] = $params['maintainer']; 134 } 135 if ($params['filter']) { 136 $maintainer_query .= " AND page.page REGEXP ?"; 137 $query_args[] = $params['filter']; 138 } 139 140 $q = "SELECT page.page, page.maintainer, revision.rev, revision.approved, revision.approved_by, 141 revision.ready_for_approval, revision.ready_for_approval_by, 142 LENGTH(page.page) - LENGTH(REPLACE(page.page, ':', '')) AS colons 143 FROM page INNER JOIN revision ON page.page = revision.page 144 WHERE page.hidden = 0 AND revision.current=1 AND page.page LIKE ? ESCAPE '_' 145 $maintainer_query 146 ORDER BY colons, page.page"; 147 148 $res = $sqlite->query($q, $query_args); 149 $pages = $sqlite->res2arr($res); 150 151 // Output Table 152 $renderer->doc .= '<table><tr>'; 153 $renderer->doc .= '<th>' . $this->getLang('hdr_page') . '</th>'; 154 $renderer->doc .= '<th>' . $this->getLang('hdr_state') . '</th>'; 155 $renderer->doc .= '<th>' . $this->getLang('hdr_updated') . '</th>'; 156 $renderer->doc .= '<th>' . $this->getLang('hdr_maintainer') . '</th>'; 157 $renderer->doc .= '</tr>'; 158 159 160 $all_approved = 0; 161 $all_approved_ready = 0; 162 $all = 0; 163 164 $curNS = ''; 165 foreach($pages as $page) { 166 $id = $page['page']; 167 $maintainer = $page['maintainer']; 168 $rev = $page['rev']; 169 $approved = strtotime($page['approved']); 170 $approved_by = $page['approved_by']; 171 $ready_for_approval = strtotime($page['ready_for_approval']); 172 $ready_for_approval_by = $page['ready_for_approval_by']; 173 174 $pageNS = getNS($id); 175 176 if($pageNS != '' && $pageNS != $curNS) { 177 $curNS = $pageNS; 178 179 $renderer->doc .= '<tr><td colspan="4"><a href="'; 180 $renderer->doc .= wl($curNS); 181 $renderer->doc .= '">'; 182 $renderer->doc .= $curNS; 183 $renderer->doc .= '</a> '; 184 $renderer->doc .= '</td></tr>'; 185 } 186 187 $all += 1; 188 if ($approved) { 189 $class = 'plugin__approve_green'; 190 $state = $this->getLang('approved'); 191 $date = $approved; 192 $by = $approved_by; 193 194 $all_approved += 1; 195 } elseif ($this->getConf('ready_for_approval') && $ready_for_approval) { 196 $class = 'plugin__approve_ready'; 197 $state = $this->getLang('marked_approve_ready'); 198 $date = $ready_for_approval; 199 $by = $ready_for_approval_by; 200 201 $all_approved_ready += 1; 202 } else { 203 $class = 'plugin__approve_red'; 204 $state = $this->getLang('draft'); 205 $date = $rev; 206 $by = p_get_metadata($id, 'last_change user'); 207 } 208 209 $renderer->doc .= '<tr class="'.$class.'">'; 210 $renderer->doc .= '<td><a href="'; 211 $renderer->doc .= wl($id); 212 $renderer->doc .= '">'; 213 if ($conf['useheading'] == '1') { 214 $heading = p_get_first_heading($id); 215 if ($heading != '') { 216 $renderer->doc .= $heading; 217 } else { 218 $renderer->doc .= $id; 219 } 220 } else { 221 $renderer->doc .= $id; 222 } 223 224 $renderer->doc .= '</a></td><td>'; 225 $renderer->doc .= '<strong>'.$state. '</strong> '; 226 227 $user = $auth->getUserData($by); 228 if ($user) { 229 $renderer->doc .= $this->getLang('by'). ' ' . $user['name']; 230 } 231 $renderer->doc .= '</td><td>'; 232 $renderer->doc .= '<a href="' . wl($id) . '">' . dformat($date) . '</a>';; 233 $renderer->doc .= '</td><td>'; 234 if ($maintainer) { 235 $user = $auth->getUserData($maintainer); 236 if ($user) { 237 $renderer->doc .= $user['name']; 238 } else { 239 $renderer->doc .= $maintainer; 240 } 241 } else { 242 $renderer->doc .= '---'; 243 } 244 $renderer->doc .= '</td></tr>'; 245 } 246 247 if ($params['summarize']) { 248 if($this->getConf('ready_for_approval')) { 249 $renderer->doc .= '<tr><td><strong>'; 250 $renderer->doc .= $this->getLang('all_approved_ready'); 251 $renderer->doc .= '</strong></td>'; 252 253 $renderer->doc .= '<td colspan="3">'; 254 $percent = 0; 255 if($all > 0) { 256 $percent = $all_approved_ready * 100 / $all; 257 } 258 $renderer->doc .= $all_approved_ready . ' / ' . $all . sprintf(" (%.0f%%)", $percent); 259 $renderer->doc .= '</td></tr>'; 260 } 261 262 $renderer->doc .= '<tr><td><strong>'; 263 $renderer->doc .= $this->getLang('all_approved'); 264 $renderer->doc .= '</strong></td>'; 265 266 $renderer->doc .= '<td colspan="3">'; 267 $percent = 0; 268 if($all > 0) { 269 $percent = $all_approved * 100 / $all; 270 } 271 $renderer->doc .= $all_approved . ' / ' . $all . sprintf(" (%.0f%%)", $percent); 272 $renderer->doc .= '</td></tr>'; 273 } 274 275 $renderer->doc .= '</table>'; 276 } 277} 278