1b81b1128SSzymon Olewniczak<?php 2b81b1128SSzymon Olewniczak 3b81b1128SSzymon Olewniczakuse dokuwiki\plugin\approve\meta\ApproveConst; 4b81b1128SSzymon Olewniczak 5b81b1128SSzymon Olewniczak// must be run within DokuWiki 6b81b1128SSzymon Olewniczakif(!defined('DOKU_INC')) die(); 7b81b1128SSzymon Olewniczak 8b81b1128SSzymon Olewniczak 9b81b1128SSzymon Olewniczakclass syntax_plugin_approve_table extends DokuWiki_Syntax_Plugin { 10b81b1128SSzymon Olewniczak 11*99eaf3e2SSzymon Olewniczak protected $states = []; 12*99eaf3e2SSzymon Olewniczak 13*99eaf3e2SSzymon Olewniczak public function __construct() { 14*99eaf3e2SSzymon Olewniczak $this->states = [$this->getConf('sum approved'), 15*99eaf3e2SSzymon Olewniczak $this->getConf('sum ready for approval'), 16*99eaf3e2SSzymon Olewniczak $this->getConf('sum draft')]; 17*99eaf3e2SSzymon Olewniczak } 18b81b1128SSzymon Olewniczak 19b81b1128SSzymon Olewniczak function getType() { 20b81b1128SSzymon Olewniczak return 'substition'; 21b81b1128SSzymon Olewniczak } 22b81b1128SSzymon Olewniczak 23b81b1128SSzymon Olewniczak function getSort() { 24b81b1128SSzymon Olewniczak return 20; 25b81b1128SSzymon Olewniczak } 26b81b1128SSzymon Olewniczak 27b81b1128SSzymon Olewniczak function PType() { 28b81b1128SSzymon Olewniczak return 'block'; 29b81b1128SSzymon Olewniczak } 30b81b1128SSzymon Olewniczak 31b81b1128SSzymon Olewniczak function connectTo($mode) { 32b81b1128SSzymon Olewniczak $this->Lexer->addSpecialPattern('----+ *approve table *-+\n.*?----+', $mode,'plugin_approve_table'); 33b81b1128SSzymon Olewniczak } 34b81b1128SSzymon Olewniczak 35b81b1128SSzymon Olewniczak function handle($match, $state, $pos, Doku_Handler $handler){ 36b81b1128SSzymon Olewniczak $lines = explode("\n", $match); 37b81b1128SSzymon Olewniczak array_shift($lines); 38b81b1128SSzymon Olewniczak array_pop($lines); 39b81b1128SSzymon Olewniczak 40b81b1128SSzymon Olewniczak $params = []; 41b81b1128SSzymon Olewniczak foreach ($lines as $line) { 42b81b1128SSzymon Olewniczak $pair = explode(':', $line, 2); 43b81b1128SSzymon Olewniczak if (count($pair) < 2) { 44b81b1128SSzymon Olewniczak continue; 45b81b1128SSzymon Olewniczak } 46b81b1128SSzymon Olewniczak $key = trim($pair[0]); 47b81b1128SSzymon Olewniczak $value = trim($pair[1]); 48b81b1128SSzymon Olewniczak if ($key == 'states') { 49b81b1128SSzymon Olewniczak $value = array_map('trim', explode(',', $value)); 50b81b1128SSzymon Olewniczak //normalize 51b81b1128SSzymon Olewniczak $value = array_map('strtolower', $value); 52b81b1128SSzymon Olewniczak $value = array_map('ucfirst', $value); 53b81b1128SSzymon Olewniczak foreach ($value as $state) { 54*99eaf3e2SSzymon Olewniczak if (!in_array($state, $this->states)) { 55b81b1128SSzymon Olewniczak msg('approve plugin: unknown state "'.$state.'" should be: ' . 56*99eaf3e2SSzymon Olewniczak implode(', ', $this->states), -1); 57b81b1128SSzymon Olewniczak return false; 58b81b1128SSzymon Olewniczak } 59b81b1128SSzymon Olewniczak } 60b81b1128SSzymon Olewniczak } elseif($key == 'filter' && preg_match($value, null) === false) { 61b81b1128SSzymon Olewniczak msg('approve plugin: invalid filter regex', -1); 62b81b1128SSzymon Olewniczak return false; 635f33cda2SSzymon Olewniczak } elseif ($key == 'summarize') { 645f33cda2SSzymon Olewniczak $value = $value == '0' ? false : true; 65b81b1128SSzymon Olewniczak } 66b81b1128SSzymon Olewniczak $params[$key] = $value; 67b81b1128SSzymon Olewniczak } 68b81b1128SSzymon Olewniczak return $params; 69b81b1128SSzymon Olewniczak } 70b81b1128SSzymon Olewniczak 71b81b1128SSzymon Olewniczak function render($mode, Doku_Renderer $renderer, $params) { 72b81b1128SSzymon Olewniczak global $conf; 73b81b1128SSzymon Olewniczak 74b81b1128SSzymon Olewniczak if ($mode != 'xhtml') return false; 75b81b1128SSzymon Olewniczak if ($params === false) return false; 76b81b1128SSzymon Olewniczak 77b81b1128SSzymon Olewniczak $defaults = [ 78b81b1128SSzymon Olewniczak 'namespace' => '', 79b81b1128SSzymon Olewniczak 'filter' => false, 80*99eaf3e2SSzymon Olewniczak 'states' => $this->states, 815f33cda2SSzymon Olewniczak 'summarize' => true, 82b81b1128SSzymon Olewniczak ]; 83b81b1128SSzymon Olewniczak 84b81b1128SSzymon Olewniczak $params = array_replace($defaults, $params); 85b81b1128SSzymon Olewniczak 86b81b1128SSzymon Olewniczak $namespace = cleanID(getNS($params['namespace'] . ":*")); 87b81b1128SSzymon Olewniczak 88b81b1128SSzymon Olewniczak $pages = $this->_getPagesFromNamespace($namespace, $params['filter'], $params['states']); 89b81b1128SSzymon Olewniczak 90b81b1128SSzymon Olewniczak usort($pages, array($this,'_pagesorter')); 91b81b1128SSzymon Olewniczak 92b81b1128SSzymon Olewniczak // Output Table 93b81b1128SSzymon Olewniczak $renderer->doc .= '<table><tr>'; 94b81b1128SSzymon Olewniczak $renderer->doc .= '<th>' . $this->getLang('hdr_page') . '</th>'; 95b81b1128SSzymon Olewniczak $renderer->doc .= '<th>' . $this->getLang('hdr_state') . '</th>'; 96b81b1128SSzymon Olewniczak $renderer->doc .= '<th>' . $this->getLang('hdr_updated') . '</th>'; 97b81b1128SSzymon Olewniczak $renderer->doc .= '</tr>'; 98b81b1128SSzymon Olewniczak 99b81b1128SSzymon Olewniczak 100b81b1128SSzymon Olewniczak $all_approved = 0; 101b81b1128SSzymon Olewniczak $all_approved_ready = 0; 102b81b1128SSzymon Olewniczak $all = 0; 103b81b1128SSzymon Olewniczak 104b81b1128SSzymon Olewniczak $working_ns = null; 105b81b1128SSzymon Olewniczak foreach($pages as $page) { 106b81b1128SSzymon Olewniczak // $page: 0 -> pagename, 1 -> true -> approved else false, 2 -> last changed date 107b81b1128SSzymon Olewniczak $this_ns = getNS($page[0]); 108b81b1128SSzymon Olewniczak 109b81b1128SSzymon Olewniczak if($this_ns != $working_ns) { 110b81b1128SSzymon Olewniczak $name_ns = $this_ns; 111b81b1128SSzymon Olewniczak if($this_ns == '') { $name_ns = 'root'; } 112b81b1128SSzymon Olewniczak $renderer->doc .= '<tr><td colspan="3"><a href="'; 113b81b1128SSzymon Olewniczak $renderer->doc .= wl($this_ns . ':' . $this->getConf('start')); 114b81b1128SSzymon Olewniczak $renderer->doc .= '">'; 115b81b1128SSzymon Olewniczak $renderer->doc .= $name_ns; 116b81b1128SSzymon Olewniczak $renderer->doc .= '</a> '; 117b81b1128SSzymon Olewniczak $renderer->doc .= '</td></tr>'; 118b81b1128SSzymon Olewniczak $working_ns = $this_ns; 119b81b1128SSzymon Olewniczak } 120b81b1128SSzymon Olewniczak 121b81b1128SSzymon Olewniczak $updated = '<a href="' . wl($page[0]) . '">' . dformat($page[2]) . '</a>'; 122b81b1128SSzymon Olewniczak 123b81b1128SSzymon Olewniczak $class = 'plugin__approve_red'; 124b81b1128SSzymon Olewniczak $state = $this->getLang('draft'); 125b81b1128SSzymon Olewniczak $all += 1; 126b81b1128SSzymon Olewniczak 127b81b1128SSzymon Olewniczak if ($page[1] === 'approved') { 128b81b1128SSzymon Olewniczak $class = 'plugin__approve_green'; 129b81b1128SSzymon Olewniczak $state = $this->getLang('approved'); 130b81b1128SSzymon Olewniczak $all_approved += 1; 131b81b1128SSzymon Olewniczak } elseif ($page[1] === 'ready for approval' && $this->getConf('ready_for_approval') === 1) { 132b81b1128SSzymon Olewniczak $class = 'plugin__approve_ready'; 133b81b1128SSzymon Olewniczak $state = $this->getLang('marked_approve_ready'); 134b81b1128SSzymon Olewniczak $all_approved_ready += 1; 135b81b1128SSzymon Olewniczak } 136b81b1128SSzymon Olewniczak 137b81b1128SSzymon Olewniczak $renderer->doc .= '<tr class="'.$class.'">'; 138b81b1128SSzymon Olewniczak $renderer->doc .= '<td><a href="'; 139b81b1128SSzymon Olewniczak $renderer->doc .= wl($page[0]); 140b81b1128SSzymon Olewniczak $renderer->doc .= '">'; 141b81b1128SSzymon Olewniczak if ($conf['useheading'] === '1') { 142b81b1128SSzymon Olewniczak $heading = p_get_first_heading($page[0]); 143b81b1128SSzymon Olewniczak if ($heading != '') { 144b81b1128SSzymon Olewniczak $renderer->doc .= $heading; 145b81b1128SSzymon Olewniczak } else { 146b81b1128SSzymon Olewniczak $renderer->doc .= $page[0]; 147b81b1128SSzymon Olewniczak } 148b81b1128SSzymon Olewniczak 149b81b1128SSzymon Olewniczak } else { 150b81b1128SSzymon Olewniczak $renderer->doc .= $page[0]; 151b81b1128SSzymon Olewniczak } 152b81b1128SSzymon Olewniczak 153b81b1128SSzymon Olewniczak $renderer->doc .= '</a></td><td>'; 154b81b1128SSzymon Olewniczak $renderer->doc .= '<strong>'.$state. '</strong> '. $this->getLang('by'). ' ' . $page[4]; 155b81b1128SSzymon Olewniczak $renderer->doc .= '</td><td>'; 156b81b1128SSzymon Olewniczak $renderer->doc .= $updated; 157b81b1128SSzymon Olewniczak $renderer->doc .= '</td></tr>'; 158b81b1128SSzymon Olewniczak } 159b81b1128SSzymon Olewniczak 1605f33cda2SSzymon Olewniczak if ($params['summarize']) { 161b81b1128SSzymon Olewniczak if($this->getConf('ready_for_approval') === 1) { 162b81b1128SSzymon Olewniczak $renderer->doc .= '<tr><td><strong>'; 163b81b1128SSzymon Olewniczak $renderer->doc .= $this->getLang('all_approved_ready'); 164b81b1128SSzymon Olewniczak $renderer->doc .= '</strong></td>'; 165b81b1128SSzymon Olewniczak 166b81b1128SSzymon Olewniczak $renderer->doc .= '<td colspan="2">'; 167b81b1128SSzymon Olewniczak $percent = 0; 168b81b1128SSzymon Olewniczak if($all > 0) { 169b81b1128SSzymon Olewniczak $percent = $all_approved_ready * 100 / $all; 170b81b1128SSzymon Olewniczak } 171b81b1128SSzymon Olewniczak $renderer->doc .= $all_approved_ready . ' / ' . $all . sprintf(" (%.0f%%)", $percent); 172b81b1128SSzymon Olewniczak $renderer->doc .= '</td></tr>'; 173b81b1128SSzymon Olewniczak } 174b81b1128SSzymon Olewniczak 175b81b1128SSzymon Olewniczak $renderer->doc .= '<tr><td><strong>'; 176b81b1128SSzymon Olewniczak $renderer->doc .= $this->getLang('all_approved'); 177b81b1128SSzymon Olewniczak $renderer->doc .= '</strong></td>'; 178b81b1128SSzymon Olewniczak 179b81b1128SSzymon Olewniczak $renderer->doc .= '<td colspan="2">'; 180b81b1128SSzymon Olewniczak $percent = 0; 181b81b1128SSzymon Olewniczak if($all > 0) { 182b81b1128SSzymon Olewniczak $percent = $all_approved * 100 / $all; 183b81b1128SSzymon Olewniczak } 184b81b1128SSzymon Olewniczak $renderer->doc .= $all_approved . ' / ' . $all . sprintf(" (%.0f%%)", $percent); 185b81b1128SSzymon Olewniczak $renderer->doc .= '</td></tr>'; 1865f33cda2SSzymon Olewniczak } 187b81b1128SSzymon Olewniczak 188b81b1128SSzymon Olewniczak $renderer->doc .= '</table>'; 189b81b1128SSzymon Olewniczak return true; 190b81b1128SSzymon Olewniczak } 191b81b1128SSzymon Olewniczak 192b81b1128SSzymon Olewniczak function _search_helper(&$data, $base, $file, $type, $lvl, $opts) { 193b81b1128SSzymon Olewniczak global $lang; 194b81b1128SSzymon Olewniczak 195b81b1128SSzymon Olewniczak $ns = $opts[0]; 196b81b1128SSzymon Olewniczak $invalid_ns = $opts[1]; 197b81b1128SSzymon Olewniczak $page_regex = $opts[2]; 198b81b1128SSzymon Olewniczak $states = $opts[3]; 199b81b1128SSzymon Olewniczak 200b81b1128SSzymon Olewniczak if ($type == 'd') { 201b81b1128SSzymon Olewniczak return true; 202b81b1128SSzymon Olewniczak } 203b81b1128SSzymon Olewniczak 204b81b1128SSzymon Olewniczak if (!preg_match('#\.txt$#', $file)) { 205b81b1128SSzymon Olewniczak return false; 206b81b1128SSzymon Olewniczak } 207b81b1128SSzymon Olewniczak 208b81b1128SSzymon Olewniczak $id = pathID($ns . $file); 209b81b1128SSzymon Olewniczak if (!empty($invalid_ns) && $this->hlp->in_namespace($invalid_ns, $id)) { 210b81b1128SSzymon Olewniczak return false; 211b81b1128SSzymon Olewniczak } 212b81b1128SSzymon Olewniczak 213b81b1128SSzymon Olewniczak //check page_regex 214b81b1128SSzymon Olewniczak if ($page_regex && !preg_match($page_regex, $id)) { 215b81b1128SSzymon Olewniczak return false; 216b81b1128SSzymon Olewniczak } 217b81b1128SSzymon Olewniczak 218b81b1128SSzymon Olewniczak //check states 219b81b1128SSzymon Olewniczak 220b81b1128SSzymon Olewniczak 221b81b1128SSzymon Olewniczak $meta = p_get_metadata($id); 222b81b1128SSzymon Olewniczak 223b81b1128SSzymon Olewniczak 224b81b1128SSzymon Olewniczak //check states 225b81b1128SSzymon Olewniczak $sum = $meta['last_change']['sum']; 226*99eaf3e2SSzymon Olewniczak if ($sum == $this->getConf('sum approved') && !in_array($this->getConf('sum approved'), $states)) { 227b81b1128SSzymon Olewniczak return false; 228b81b1128SSzymon Olewniczak } 229b81b1128SSzymon Olewniczak 230*99eaf3e2SSzymon Olewniczak if ($sum == $this->getConf('sum ready for approval') && 231*99eaf3e2SSzymon Olewniczak !in_array($this->getConf('sum ready for approval'), $states)) { 232b81b1128SSzymon Olewniczak return false; 233b81b1128SSzymon Olewniczak } 234b81b1128SSzymon Olewniczak 235*99eaf3e2SSzymon Olewniczak if ($sum != $this->getConf('sum approved') && 236*99eaf3e2SSzymon Olewniczak $sum != $this->getConf('sum ready for approval') && 237*99eaf3e2SSzymon Olewniczak !in_array($this->getConf('sum draft'), $states)) { 238b81b1128SSzymon Olewniczak return false; 239b81b1128SSzymon Olewniczak } 240b81b1128SSzymon Olewniczak 241b81b1128SSzymon Olewniczak $date = $meta['date']['modified']; 242*99eaf3e2SSzymon Olewniczak if (isset($meta['last_change']) && $meta['last_change']['sum'] === $this->getConf('sum approved')) { 243b81b1128SSzymon Olewniczak $approved = 'approved'; 244*99eaf3e2SSzymon Olewniczak } elseif (isset($meta['last_change']) && $meta['last_change']['sum'] === $this->getConf('sum ready for approval')) { 245b81b1128SSzymon Olewniczak $approved = 'ready for approval'; 246b81b1128SSzymon Olewniczak } else { 247b81b1128SSzymon Olewniczak $approved = 'not approved'; 248b81b1128SSzymon Olewniczak } 249b81b1128SSzymon Olewniczak 250b81b1128SSzymon Olewniczak if (isset($meta['last_change'])) { 251b81b1128SSzymon Olewniczak $user = $meta['last_change']['user']; 252b81b1128SSzymon Olewniczak 253b81b1128SSzymon Olewniczak if (isset($meta['contributor'][$user])) { 254b81b1128SSzymon Olewniczak $full_name = $meta['contributor'][$user]; 255b81b1128SSzymon Olewniczak } else { 256b81b1128SSzymon Olewniczak $full_name = $meta['creator']; 257b81b1128SSzymon Olewniczak } 258b81b1128SSzymon Olewniczak } else { 259b81b1128SSzymon Olewniczak $user = ''; 260b81b1128SSzymon Olewniczak $full_name = '('.$lang['external_edit'].')'; 261b81b1128SSzymon Olewniczak } 262b81b1128SSzymon Olewniczak 263b81b1128SSzymon Olewniczak 264b81b1128SSzymon Olewniczak $data[] = array($id, $approved, $date, $user, $full_name); 265b81b1128SSzymon Olewniczak 266b81b1128SSzymon Olewniczak return false; 267b81b1128SSzymon Olewniczak } 268b81b1128SSzymon Olewniczak 269b81b1128SSzymon Olewniczak function _getPagesFromNamespace($namespace, $page_regex=false, $states=[]) { 270b81b1128SSzymon Olewniczak global $conf; 271b81b1128SSzymon Olewniczak $dir = $conf['datadir'] . '/' . str_replace(':', '/', $namespace); 272b81b1128SSzymon Olewniczak $pages = array(); 273b81b1128SSzymon Olewniczak search($pages, $dir, array($this,'_search_helper'), 274b81b1128SSzymon Olewniczak array($namespace, $this->getConf('no_apr_namespaces'), $page_regex, $states)); 275b81b1128SSzymon Olewniczak 276b81b1128SSzymon Olewniczak return $pages; 277b81b1128SSzymon Olewniczak } 278b81b1128SSzymon Olewniczak 279b81b1128SSzymon Olewniczak 280b81b1128SSzymon Olewniczak 281b81b1128SSzymon Olewniczak /** 282b81b1128SSzymon Olewniczak * Custom sort callback 283b81b1128SSzymon Olewniczak */ 284b81b1128SSzymon Olewniczak function _pagesorter($a, $b){ 285b81b1128SSzymon Olewniczak $ac = explode(':',$a[0]); 286b81b1128SSzymon Olewniczak $bc = explode(':',$b[0]); 287b81b1128SSzymon Olewniczak $an = count($ac); 288b81b1128SSzymon Olewniczak $bn = count($bc); 289b81b1128SSzymon Olewniczak 290b81b1128SSzymon Olewniczak // Same number of elements, can just string sort 291b81b1128SSzymon Olewniczak if($an == $bn) { return strcmp($a[0], $b[0]); } 292b81b1128SSzymon Olewniczak 293b81b1128SSzymon Olewniczak // For each level: 294b81b1128SSzymon Olewniczak // If this is not the last element in either list: 295b81b1128SSzymon Olewniczak // same -> continue 296b81b1128SSzymon Olewniczak // otherwise strcmp 297b81b1128SSzymon Olewniczak // If this is the last element in either list, it wins 298b81b1128SSzymon Olewniczak $n = 0; 299b81b1128SSzymon Olewniczak while(true) { 300b81b1128SSzymon Olewniczak if($n + 1 == $an) { return -1; } 301b81b1128SSzymon Olewniczak if($n + 1 == $bn) { return 1; } 302b81b1128SSzymon Olewniczak $s = strcmp($ac[$n], $bc[$n]); 303b81b1128SSzymon Olewniczak if($s != 0) { return $s; } 304b81b1128SSzymon Olewniczak $n += 1; 305b81b1128SSzymon Olewniczak } 306b81b1128SSzymon Olewniczak } 307b81b1128SSzymon Olewniczak 308b81b1128SSzymon Olewniczak} 309