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