1b81b1128SSzymon Olewniczak<?php 2b81b1128SSzymon Olewniczak 3b81b1128SSzymon Olewniczak// must be run within DokuWiki 4b81b1128SSzymon Olewniczakif(!defined('DOKU_INC')) die(); 5b81b1128SSzymon Olewniczak 6b81b1128SSzymon Olewniczak 7b81b1128SSzymon Olewniczakclass syntax_plugin_approve_table extends DokuWiki_Syntax_Plugin { 8b81b1128SSzymon Olewniczak 9058bad72SSzymon Olewniczak protected $states = ['approved', 'draft', 'ready_for_approval']; 10b81b1128SSzymon Olewniczak 11b81b1128SSzymon Olewniczak function getType() { 12b81b1128SSzymon Olewniczak return 'substition'; 13b81b1128SSzymon Olewniczak } 14b81b1128SSzymon Olewniczak 15b81b1128SSzymon Olewniczak function getSort() { 16b81b1128SSzymon Olewniczak return 20; 17b81b1128SSzymon Olewniczak } 18b81b1128SSzymon Olewniczak 19b81b1128SSzymon Olewniczak function PType() { 20b81b1128SSzymon Olewniczak return 'block'; 21b81b1128SSzymon Olewniczak } 22b81b1128SSzymon Olewniczak 23b81b1128SSzymon Olewniczak function connectTo($mode) { 24b81b1128SSzymon Olewniczak $this->Lexer->addSpecialPattern('----+ *approve table *-+\n.*?----+', $mode,'plugin_approve_table'); 25b81b1128SSzymon Olewniczak } 26b81b1128SSzymon Olewniczak 27b81b1128SSzymon Olewniczak function handle($match, $state, $pos, Doku_Handler $handler){ 28b81b1128SSzymon Olewniczak $lines = explode("\n", $match); 29b81b1128SSzymon Olewniczak array_shift($lines); 30b81b1128SSzymon Olewniczak array_pop($lines); 31b81b1128SSzymon Olewniczak 32b1ff32a1SSzymon Olewniczak $params = [ 33b1ff32a1SSzymon Olewniczak 'namespace' => '', 34b1ff32a1SSzymon Olewniczak 'filter' => false, 35058bad72SSzymon Olewniczak 'states' => [], 36b1ff32a1SSzymon Olewniczak 'summarize' => true, 37*2ce523c6SSzymon Olewniczak 'approver' => null 38b1ff32a1SSzymon Olewniczak ]; 39b1ff32a1SSzymon Olewniczak 40b81b1128SSzymon Olewniczak foreach ($lines as $line) { 41b81b1128SSzymon Olewniczak $pair = explode(':', $line, 2); 42b81b1128SSzymon Olewniczak if (count($pair) < 2) { 43b81b1128SSzymon Olewniczak continue; 44b81b1128SSzymon Olewniczak } 45b81b1128SSzymon Olewniczak $key = trim($pair[0]); 46b81b1128SSzymon Olewniczak $value = trim($pair[1]); 47b81b1128SSzymon Olewniczak if ($key == 'states') { 48b81b1128SSzymon Olewniczak $value = array_map('trim', explode(',', $value)); 49b81b1128SSzymon Olewniczak //normalize 50b81b1128SSzymon Olewniczak $value = array_map('strtolower', $value); 51b81b1128SSzymon Olewniczak foreach ($value as $state) { 5299eaf3e2SSzymon Olewniczak if (!in_array($state, $this->states)) { 53b81b1128SSzymon Olewniczak msg('approve plugin: unknown state "'.$state.'" should be: ' . 5499eaf3e2SSzymon Olewniczak implode(', ', $this->states), -1); 55b81b1128SSzymon Olewniczak return false; 56b81b1128SSzymon Olewniczak } 57b81b1128SSzymon Olewniczak } 589aebb494SSzymon Olewniczak } elseif($key == 'filter') { 599aebb494SSzymon Olewniczak $value = trim($value, '/'); 609aebb494SSzymon Olewniczak if (preg_match('/' . $value . '/', null) === false) { 61b81b1128SSzymon Olewniczak msg('approve plugin: invalid filter regex', -1); 62b81b1128SSzymon Olewniczak return false; 639aebb494SSzymon Olewniczak } 645f33cda2SSzymon Olewniczak } elseif ($key == 'summarize') { 655f33cda2SSzymon Olewniczak $value = $value == '0' ? false : true; 66c7d53eabSSzymon Olewniczak } elseif ($key == 'namespace') { 67c7d53eabSSzymon Olewniczak $value = trim(cleanID($value), ':'); 68b81b1128SSzymon Olewniczak } 69b81b1128SSzymon Olewniczak $params[$key] = $value; 70b81b1128SSzymon Olewniczak } 71b81b1128SSzymon Olewniczak return $params; 72b81b1128SSzymon Olewniczak } 73b81b1128SSzymon Olewniczak 74b1ff32a1SSzymon Olewniczak /** 75b1ff32a1SSzymon Olewniczak * Render xhtml output or metadata 76b1ff32a1SSzymon Olewniczak * 77b1ff32a1SSzymon Olewniczak * @param string $mode Renderer mode (supported modes: xhtml) 78b1ff32a1SSzymon Olewniczak * @param Doku_Renderer $renderer The renderer 79b1ff32a1SSzymon Olewniczak * @param array $data The data from the handler() function 80b1ff32a1SSzymon Olewniczak * 81b1ff32a1SSzymon Olewniczak * @return bool If rendering was successful. 82b1ff32a1SSzymon Olewniczak */ 83b1ff32a1SSzymon Olewniczak 84b1ff32a1SSzymon Olewniczak public function render($mode, Doku_Renderer $renderer, $data) 85b1ff32a1SSzymon Olewniczak { 86b1ff32a1SSzymon Olewniczak $method = 'render' . ucfirst($mode); 87b1ff32a1SSzymon Olewniczak if (method_exists($this, $method)) { 88b1ff32a1SSzymon Olewniczak call_user_func([$this, $method], $renderer, $data); 89b1ff32a1SSzymon Olewniczak return true; 90b1ff32a1SSzymon Olewniczak } 91b1ff32a1SSzymon Olewniczak return false; 92b1ff32a1SSzymon Olewniczak } 93b1ff32a1SSzymon Olewniczak 94b1ff32a1SSzymon Olewniczak /** 95b1ff32a1SSzymon Olewniczak * Render metadata 96b1ff32a1SSzymon Olewniczak * 97b1ff32a1SSzymon Olewniczak * @param Doku_Renderer $renderer The renderer 98b1ff32a1SSzymon Olewniczak * @param array $data The data from the handler() function 99b1ff32a1SSzymon Olewniczak */ 100b1ff32a1SSzymon Olewniczak public function renderMetadata(Doku_Renderer $renderer, $params) 101b1ff32a1SSzymon Olewniczak { 102b1ff32a1SSzymon Olewniczak $plugin_name = $this->getPluginName(); 103b1ff32a1SSzymon Olewniczak $renderer->meta['plugin'][$plugin_name] = []; 104b1ff32a1SSzymon Olewniczak 105*2ce523c6SSzymon Olewniczak if ($params['approver'] == '$USER$') { 106*2ce523c6SSzymon Olewniczak $renderer->meta['plugin'][$plugin_name]['dynamic_approver'] = true; 107b1ff32a1SSzymon Olewniczak } 108b1ff32a1SSzymon Olewniczak 109b1ff32a1SSzymon Olewniczak $renderer->meta['plugin'][$plugin_name]['approve_table'] = true; 110b1ff32a1SSzymon Olewniczak } 111b1ff32a1SSzymon Olewniczak 112058bad72SSzymon Olewniczak protected function array_equal($a, $b) { 113058bad72SSzymon Olewniczak return ( 114058bad72SSzymon Olewniczak is_array($a) 115058bad72SSzymon Olewniczak && is_array($b) 116058bad72SSzymon Olewniczak && count($a) == count($b) 117058bad72SSzymon Olewniczak && array_diff($a, $b) === array_diff($b, $a) 118058bad72SSzymon Olewniczak ); 119058bad72SSzymon Olewniczak } 120058bad72SSzymon Olewniczak 121b1ff32a1SSzymon Olewniczak public function renderXhtml(Doku_Renderer $renderer, $params) 122b1ff32a1SSzymon Olewniczak { 123b1ff32a1SSzymon Olewniczak global $INFO; 124b1ff32a1SSzymon Olewniczak 125b81b1128SSzymon Olewniczak global $conf; 126c7d53eabSSzymon Olewniczak /** @var DokuWiki_Auth_Plugin $auth */ 127c7d53eabSSzymon Olewniczak global $auth; 128b81b1128SSzymon Olewniczak 129c7d53eabSSzymon Olewniczak /** @var \helper_plugin_ireadit_db $db_helper */ 130c7d53eabSSzymon Olewniczak $db_helper = plugin_load('helper', 'approve_db'); 131c7d53eabSSzymon Olewniczak $sqlite = $db_helper->getDB(); 1324474ed8aSSzymon Olewniczak 133*2ce523c6SSzymon Olewniczak if ($params['approver'] == '$USER$') { 134*2ce523c6SSzymon Olewniczak $params['approver'] = $INFO['client']; 135a27fc412SSzymon Olewniczak } 136a27fc412SSzymon Olewniczak 137*2ce523c6SSzymon Olewniczak $approver_query = ''; 138c02b6e47SSzymon Olewniczak $query_args = [$params['namespace'].'%']; 139*2ce523c6SSzymon Olewniczak if ($params['approver']) { 140*2ce523c6SSzymon Olewniczak $approver_query .= " AND page.approver LIKE ?"; 141*2ce523c6SSzymon Olewniczak $query_args[] = $params['approver']; 142c02b6e47SSzymon Olewniczak } 143058bad72SSzymon Olewniczak 1449aebb494SSzymon Olewniczak if ($params['filter']) { 145*2ce523c6SSzymon Olewniczak $approver_query .= " AND page.page REGEXP ?"; 1469aebb494SSzymon Olewniczak $query_args[] = $params['filter']; 1479aebb494SSzymon Olewniczak } 148c02b6e47SSzymon Olewniczak 149058bad72SSzymon Olewniczak //if all 3 states are enabled nothing is filtered 150058bad72SSzymon Olewniczak if ($params['states'] && count($params['states']) < 3) { 151058bad72SSzymon Olewniczak if ($this->array_equal(['draft'], $params['states'])) { 152*2ce523c6SSzymon Olewniczak $approver_query .= " AND revision.ready_for_approval IS NULL AND revision.approved IS NULL"; 153058bad72SSzymon Olewniczak } elseif ($this->array_equal(['ready_for_approval'], $params['states'])) { 154*2ce523c6SSzymon Olewniczak $approver_query .= " AND revision.ready_for_approval IS NOT NULL AND revision.approved IS NULL"; 155058bad72SSzymon Olewniczak } elseif ($this->array_equal(['approved'], $params['states'])) { 156*2ce523c6SSzymon Olewniczak $approver_query .= " AND revision.approved IS NOT NULL"; 157058bad72SSzymon Olewniczak } elseif ($this->array_equal(['draft', 'ready_for_approval'], $params['states'])) { 158*2ce523c6SSzymon Olewniczak $approver_query .= " AND revision.approved IS NULL"; 159058bad72SSzymon Olewniczak } elseif ($this->array_equal(['draft', 'approved'], $params['states'])) { 160*2ce523c6SSzymon Olewniczak $approver_query .= " AND (revision.approved IS NOT NULL OR (revision.approved IS NULL AND revision.ready_for_approval IS NULL))"; 161058bad72SSzymon Olewniczak } elseif ($this->array_equal(['ready_for_approval', 'approved'], $params['states'])) { 162*2ce523c6SSzymon Olewniczak $approver_query .= " AND (revision.ready_for_approval IS NOT NULL OR revision.approved IS NOT NULL)"; 163058bad72SSzymon Olewniczak } 164058bad72SSzymon Olewniczak } 165058bad72SSzymon Olewniczak 166*2ce523c6SSzymon Olewniczak $q = "SELECT page.page, page.approver, revision.rev, revision.approved, revision.approved_by, 167c7d53eabSSzymon Olewniczak revision.ready_for_approval, revision.ready_for_approval_by, 168c7d53eabSSzymon Olewniczak LENGTH(page.page) - LENGTH(REPLACE(page.page, ':', '')) AS colons 169c7d53eabSSzymon Olewniczak FROM page INNER JOIN revision ON page.page = revision.page 170c7d53eabSSzymon Olewniczak WHERE page.hidden = 0 AND revision.current=1 AND page.page LIKE ? ESCAPE '_' 171*2ce523c6SSzymon Olewniczak $approver_query 172c7d53eabSSzymon Olewniczak ORDER BY colons, page.page"; 173c02b6e47SSzymon Olewniczak 174c02b6e47SSzymon Olewniczak $res = $sqlite->query($q, $query_args); 175c7d53eabSSzymon Olewniczak $pages = $sqlite->res2arr($res); 176b81b1128SSzymon Olewniczak 177b81b1128SSzymon Olewniczak // Output Table 178b81b1128SSzymon Olewniczak $renderer->doc .= '<table><tr>'; 179b81b1128SSzymon Olewniczak $renderer->doc .= '<th>' . $this->getLang('hdr_page') . '</th>'; 180b81b1128SSzymon Olewniczak $renderer->doc .= '<th>' . $this->getLang('hdr_state') . '</th>'; 181b81b1128SSzymon Olewniczak $renderer->doc .= '<th>' . $this->getLang('hdr_updated') . '</th>'; 182*2ce523c6SSzymon Olewniczak $renderer->doc .= '<th>' . $this->getLang('hdr_approver') . '</th>'; 183b81b1128SSzymon Olewniczak $renderer->doc .= '</tr>'; 184b81b1128SSzymon Olewniczak 185b81b1128SSzymon Olewniczak 186b81b1128SSzymon Olewniczak $all_approved = 0; 187b81b1128SSzymon Olewniczak $all_approved_ready = 0; 188b81b1128SSzymon Olewniczak $all = 0; 189b81b1128SSzymon Olewniczak 190c7d53eabSSzymon Olewniczak $curNS = ''; 191b81b1128SSzymon Olewniczak foreach($pages as $page) { 192c7d53eabSSzymon Olewniczak $id = $page['page']; 193*2ce523c6SSzymon Olewniczak $approver = $page['approver']; 194c7d53eabSSzymon Olewniczak $rev = $page['rev']; 195c7d53eabSSzymon Olewniczak $approved = strtotime($page['approved']); 196c7d53eabSSzymon Olewniczak $approved_by = $page['approved_by']; 197c7d53eabSSzymon Olewniczak $ready_for_approval = strtotime($page['ready_for_approval']); 198c7d53eabSSzymon Olewniczak $ready_for_approval_by = $page['ready_for_approval_by']; 199b81b1128SSzymon Olewniczak 200c7d53eabSSzymon Olewniczak $pageNS = getNS($id); 201c7d53eabSSzymon Olewniczak 202c7d53eabSSzymon Olewniczak if($pageNS != '' && $pageNS != $curNS) { 203c7d53eabSSzymon Olewniczak $curNS = $pageNS; 204c7d53eabSSzymon Olewniczak 205c7d53eabSSzymon Olewniczak $renderer->doc .= '<tr><td colspan="4"><a href="'; 206c7d53eabSSzymon Olewniczak $renderer->doc .= wl($curNS); 207b81b1128SSzymon Olewniczak $renderer->doc .= '">'; 208c7d53eabSSzymon Olewniczak $renderer->doc .= $curNS; 209b81b1128SSzymon Olewniczak $renderer->doc .= '</a> '; 210b81b1128SSzymon Olewniczak $renderer->doc .= '</td></tr>'; 211b81b1128SSzymon Olewniczak } 212b81b1128SSzymon Olewniczak 213b81b1128SSzymon Olewniczak $all += 1; 214c7d53eabSSzymon Olewniczak if ($approved) { 215b81b1128SSzymon Olewniczak $class = 'plugin__approve_green'; 216b81b1128SSzymon Olewniczak $state = $this->getLang('approved'); 217c7d53eabSSzymon Olewniczak $date = $approved; 218c7d53eabSSzymon Olewniczak $by = $approved_by; 219c7d53eabSSzymon Olewniczak 220b81b1128SSzymon Olewniczak $all_approved += 1; 221c7d53eabSSzymon Olewniczak } elseif ($this->getConf('ready_for_approval') && $ready_for_approval) { 222b81b1128SSzymon Olewniczak $class = 'plugin__approve_ready'; 223b81b1128SSzymon Olewniczak $state = $this->getLang('marked_approve_ready'); 224c7d53eabSSzymon Olewniczak $date = $ready_for_approval; 225c7d53eabSSzymon Olewniczak $by = $ready_for_approval_by; 226c7d53eabSSzymon Olewniczak 227b81b1128SSzymon Olewniczak $all_approved_ready += 1; 228c7d53eabSSzymon Olewniczak } else { 229c7d53eabSSzymon Olewniczak $class = 'plugin__approve_red'; 230c7d53eabSSzymon Olewniczak $state = $this->getLang('draft'); 231c7d53eabSSzymon Olewniczak $date = $rev; 232c7d53eabSSzymon Olewniczak $by = p_get_metadata($id, 'last_change user'); 233b81b1128SSzymon Olewniczak } 234b81b1128SSzymon Olewniczak 235b81b1128SSzymon Olewniczak $renderer->doc .= '<tr class="'.$class.'">'; 236b81b1128SSzymon Olewniczak $renderer->doc .= '<td><a href="'; 237c7d53eabSSzymon Olewniczak $renderer->doc .= wl($id); 238b81b1128SSzymon Olewniczak $renderer->doc .= '">'; 239c7d53eabSSzymon Olewniczak if ($conf['useheading'] == '1') { 240c7d53eabSSzymon Olewniczak $heading = p_get_first_heading($id); 241b81b1128SSzymon Olewniczak if ($heading != '') { 242b81b1128SSzymon Olewniczak $renderer->doc .= $heading; 243b81b1128SSzymon Olewniczak } else { 244c7d53eabSSzymon Olewniczak $renderer->doc .= $id; 245b81b1128SSzymon Olewniczak } 246b81b1128SSzymon Olewniczak } else { 247c7d53eabSSzymon Olewniczak $renderer->doc .= $id; 248b81b1128SSzymon Olewniczak } 249b81b1128SSzymon Olewniczak 250b81b1128SSzymon Olewniczak $renderer->doc .= '</a></td><td>'; 251c7d53eabSSzymon Olewniczak $renderer->doc .= '<strong>'.$state. '</strong> '; 252c7d53eabSSzymon Olewniczak 253c7d53eabSSzymon Olewniczak $user = $auth->getUserData($by); 254c7d53eabSSzymon Olewniczak if ($user) { 255c7d53eabSSzymon Olewniczak $renderer->doc .= $this->getLang('by'). ' ' . $user['name']; 256c7d53eabSSzymon Olewniczak } 257b81b1128SSzymon Olewniczak $renderer->doc .= '</td><td>'; 258c7d53eabSSzymon Olewniczak $renderer->doc .= '<a href="' . wl($id) . '">' . dformat($date) . '</a>';; 259c7d53eabSSzymon Olewniczak $renderer->doc .= '</td><td>'; 260*2ce523c6SSzymon Olewniczak if ($approver) { 261*2ce523c6SSzymon Olewniczak $user = $auth->getUserData($approver); 262c7d53eabSSzymon Olewniczak if ($user) { 263c7d53eabSSzymon Olewniczak $renderer->doc .= $user['name']; 264c7d53eabSSzymon Olewniczak } else { 265*2ce523c6SSzymon Olewniczak $renderer->doc .= $approver; 266c7d53eabSSzymon Olewniczak } 267c7d53eabSSzymon Olewniczak } else { 268c7d53eabSSzymon Olewniczak $renderer->doc .= '---'; 269c7d53eabSSzymon Olewniczak } 270b81b1128SSzymon Olewniczak $renderer->doc .= '</td></tr>'; 271b81b1128SSzymon Olewniczak } 272b81b1128SSzymon Olewniczak 2735f33cda2SSzymon Olewniczak if ($params['summarize']) { 274c7d53eabSSzymon Olewniczak if($this->getConf('ready_for_approval')) { 275b81b1128SSzymon Olewniczak $renderer->doc .= '<tr><td><strong>'; 276b81b1128SSzymon Olewniczak $renderer->doc .= $this->getLang('all_approved_ready'); 277b81b1128SSzymon Olewniczak $renderer->doc .= '</strong></td>'; 278b81b1128SSzymon Olewniczak 279c7d53eabSSzymon Olewniczak $renderer->doc .= '<td colspan="3">'; 280b81b1128SSzymon Olewniczak $percent = 0; 281b81b1128SSzymon Olewniczak if($all > 0) { 282b81b1128SSzymon Olewniczak $percent = $all_approved_ready * 100 / $all; 283b81b1128SSzymon Olewniczak } 284b81b1128SSzymon Olewniczak $renderer->doc .= $all_approved_ready . ' / ' . $all . sprintf(" (%.0f%%)", $percent); 285b81b1128SSzymon Olewniczak $renderer->doc .= '</td></tr>'; 286b81b1128SSzymon Olewniczak } 287b81b1128SSzymon Olewniczak 288b81b1128SSzymon Olewniczak $renderer->doc .= '<tr><td><strong>'; 289b81b1128SSzymon Olewniczak $renderer->doc .= $this->getLang('all_approved'); 290b81b1128SSzymon Olewniczak $renderer->doc .= '</strong></td>'; 291b81b1128SSzymon Olewniczak 292c7d53eabSSzymon Olewniczak $renderer->doc .= '<td colspan="3">'; 293b81b1128SSzymon Olewniczak $percent = 0; 294b81b1128SSzymon Olewniczak if($all > 0) { 295b81b1128SSzymon Olewniczak $percent = $all_approved * 100 / $all; 296b81b1128SSzymon Olewniczak } 297b81b1128SSzymon Olewniczak $renderer->doc .= $all_approved . ' / ' . $all . sprintf(" (%.0f%%)", $percent); 298b81b1128SSzymon Olewniczak $renderer->doc .= '</td></tr>'; 2995f33cda2SSzymon Olewniczak } 300b81b1128SSzymon Olewniczak 301b81b1128SSzymon Olewniczak $renderer->doc .= '</table>'; 302b81b1128SSzymon Olewniczak } 303b81b1128SSzymon Olewniczak} 304