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