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