1<?php 2/** 3 * DokuWiki Plugin publish (Syntax Component) 4 * 5 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 6 * @author Jarrod Lowe <dokuwiki@rrod.net> 7 * @author Andreas Gohr <gohr@cosmocode.de> 8 */ 9 10 11// must be run within DokuWiki 12if(!defined('DOKU_INC')) die(); 13 14 15class syntax_plugin_publish extends DokuWiki_Syntax_Plugin { 16 private $hlp; 17 18 function syntax_plugin_publish(){ 19 $this->hlp = plugin_load('helper','publish'); 20 } 21 22 function pattern() { return '\[APPROVALS.*?\]'; } 23 function getType() { return 'substition'; } 24 function getSort() { return 20; } 25 function PType() { return 'block'; } 26 function connectTo($mode) { $this->Lexer->addSpecialPattern($this->pattern(),$mode,'plugin_publish'); } 27 function handle($match, $state, $pos, &$handler){ 28 $namespace = substr($match, 11, -1); 29 return array($match, $state, $pos, $namespace); 30 } 31 32 function render($mode, &$renderer, $data) { 33 global $conf; 34 35 if($mode == 'xhtml'){ 36 $ns = cleanID(getNS($data[3] . ":*")); 37 $dir = $conf['datadir'] . '/' . str_replace(':', '/', $ns); 38 $pages = array(); 39 search($pages, $dir, array($this,'search_helper'), array($ns, $this->getConf('apr_namespaces'))); 40 if(count($pages) == 0) { 41 $renderer->doc .= '<p class="apr_none">' . $this->getLang('apr_p_none') . '</p>'; 42 return true; 43 } 44 usort($pages, array($this,'_pagesorter')); 45 46 // Output Table 47 $renderer->doc .= '<table class="apr_table"><tr class="apr_head">'; 48 $renderer->doc .= '<th class="apr_page">' . $this->getLang('apr_p_hdr_page') . '</th>'; 49 $renderer->doc .= '<th class="apr_prev">' . $this->getLang('apr_p_hdr_previous') . '</th>'; 50 $renderer->doc .= '<th class="apr_upd">' . $this->getLang('apr_p_hdr_updated') . '</th>'; 51 $renderer->doc .= '</tr>'; 52 $working_ns = null; 53 foreach($pages as $page) { 54 // $page: 0 -> pagename, 1 -> approval metadata, 2 -> last changed date 55 $this_ns = getNS($page[0]); 56 if($this_ns != $working_ns) { 57 $name_ns = $this_ns; 58 if($this_ns == '') { $name_ns = 'root'; } 59 $renderer->doc .= '<tr class="apr_ns"><td colspan="3"><a href="'; 60 $renderer->doc .= wl($this_ns . ':' . $this->getConf('start')); 61 $renderer->doc .= '">'; 62 $renderer->doc .= $name_ns; 63 $renderer->doc .= '</a></td></tr>'; 64 $working_ns = $this_ns; 65 } 66 $updated = '<a href="' . wl($page[0]) . '">' . date('d/m/Y H:i', $page[2]) . '</a>'; 67 if($page[1] == null || count($page[1]) == 0) { 68 // Has never been approved 69 $approved = ''; 70 }else{ 71 $keys = array_keys($page[1]); 72 sort($keys); 73 $last = $keys[count($keys)-1]; 74 $approved .= sprintf($this->getLang('apr_p_approved'), 75 $page[1][$last][1], 76 wl($page[0], 'rev=' . $last), 77 date('d/m/Y H:i', $last)); 78 if($last == $page[2]) { $updated = 'Unchanged'; } //shouldn't be possible: 79 //the search_helper should have 80 //excluded this 81 } 82 83 $renderer->doc .= '<tr class="apr_table'; 84 if($approved == '') { $renderer->doc .= ' apr_never'; } 85 $renderer->doc .= '"><td class="apr_page"><a href="'; 86 $renderer->doc .= wl($page[0]); 87 $renderer->doc .= '">'; 88 $renderer->doc .= $page[0]; 89 $renderer->doc .= '</a></td><td class="apr_prev">'; 90 $renderer->doc .= $approved; 91 $renderer->doc .= '</td><td class="apr_upd">'; 92 $renderer->doc .= $updated; 93 $renderer->doc .= '</td></tr>'; 94 95 //$renderer->doc .= '<tr><td colspan="3">' . print_r($page, true) . '</td></tr>'; 96 } 97 $renderer->doc .= '</table>'; 98 return true; 99 } 100 return false; 101 } 102 103 /** 104 * search callback function 105 * 106 * filter out pages which can't be approved by the current user 107 * then check if they need approving 108 */ 109 function _search_helper(&$data, $base, $file, $type, $lvl, $opts) { 110 $ns = $opts[0]; 111 $valid_ns = $opts[1]; 112 if($type == 'd') { return $this->hlp->in_sub_namespace($valid_ns, $ns . ':' . str_replace('/', ':', $file)); } 113 if(!preg_match('#\.txt$#', $file)) { return false; } 114 $id = pathID($ns . $file); 115 if(!in_namespace($valid_ns, $id)) { return false; } 116 if(auth_quickaclcheck($id) < AUTH_DELETE) { return false; } //insufficent permissions 117 $meta = p_get_metadata($id); 118 if($meta['approval'][$meta['last_change']['date']]) { 119 // Already approved 120 return false; 121 } 122 $data[] = array($id, $meta['approval'], $meta['last_change']['date']); 123 return false; 124 } 125 126 /** 127 * Custom sort callback 128 */ 129 function _pagesorter($a, $b){ 130 $ac = explode(':',$a[0]); 131 $bc = explode(':',$b[0]); 132 $an = count($ac); 133 $bn = count($bc); 134 135 // Same number of elements, can just string sort 136 if($an == $bn) { return strcmp($a[0], $b[0]); } 137 138 // For each level: 139 // If this is not the last element in either list: 140 // same -> continue 141 // otherwise strcmp 142 // If this is the last element in either list, it wins 143 $n = 0; 144 while(true) { 145 if($n + 1 == $an) { return -1; } 146 if($n + 1 == $bn) { return 1; } 147 $s = strcmp($ac[$n], $bc[$n]); 148 if($s != 0) { return $s; } 149 $n += 1; 150 } 151 } 152 153 154} 155 156