xref: /plugin/approve/syntax/table.php (revision 8b39f8808b2b5c38ccb73d4978bc5f55677a7230)
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,
372ce523c6SSzymon 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
1052ce523c6SSzymon Olewniczak        if ($params['approver'] == '$USER$') {
1062ce523c6SSzymon 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
1290c60a293SSzymon Olewniczak        try {
1300c60a293SSzymon Olewniczak            /** @var \helper_plugin_approve_db $db_helper */
131c7d53eabSSzymon Olewniczak            $db_helper = plugin_load('helper', 'approve_db');
132c7d53eabSSzymon Olewniczak            $sqlite = $db_helper->getDB();
1330c60a293SSzymon Olewniczak        } catch (Exception $e) {
1340c60a293SSzymon Olewniczak            msg($e->getMessage(), -1);
1350c60a293SSzymon Olewniczak            return;
1360c60a293SSzymon Olewniczak        }
1374474ed8aSSzymon Olewniczak
1382ce523c6SSzymon Olewniczak        if ($params['approver'] == '$USER$') {
1392ce523c6SSzymon Olewniczak            $params['approver'] = $INFO['client'];
140a27fc412SSzymon Olewniczak        }
141a27fc412SSzymon Olewniczak
1422ce523c6SSzymon Olewniczak        $approver_query = '';
143*8b39f880SSzymon Olewniczak        $query_args = [$params['namespace'].'*'];
1442ce523c6SSzymon Olewniczak        if ($params['approver']) {
1452ce523c6SSzymon Olewniczak            $approver_query .= " AND page.approver LIKE ?";
1462ce523c6SSzymon Olewniczak            $query_args[] = $params['approver'];
147c02b6e47SSzymon Olewniczak        }
148058bad72SSzymon Olewniczak
1499aebb494SSzymon Olewniczak        if ($params['filter']) {
1502ce523c6SSzymon Olewniczak            $approver_query .= " AND page.page REGEXP ?";
1519aebb494SSzymon Olewniczak            $query_args[] = $params['filter'];
1529aebb494SSzymon Olewniczak        }
153c02b6e47SSzymon Olewniczak
154058bad72SSzymon Olewniczak        //if all 3 states are enabled nothing is filtered
155058bad72SSzymon Olewniczak        if ($params['states'] && count($params['states']) < 3) {
156058bad72SSzymon Olewniczak            if ($this->array_equal(['draft'], $params['states'])) {
1572ce523c6SSzymon Olewniczak                $approver_query .= " AND revision.ready_for_approval IS NULL AND revision.approved IS NULL";
158058bad72SSzymon Olewniczak            } elseif ($this->array_equal(['ready_for_approval'], $params['states'])) {
1592ce523c6SSzymon Olewniczak                $approver_query .= " AND revision.ready_for_approval IS NOT NULL AND revision.approved IS NULL";
160058bad72SSzymon Olewniczak            } elseif ($this->array_equal(['approved'], $params['states'])) {
1612ce523c6SSzymon Olewniczak                $approver_query .= " AND revision.approved IS NOT NULL";
162058bad72SSzymon Olewniczak            } elseif ($this->array_equal(['draft', 'ready_for_approval'], $params['states'])) {
1632ce523c6SSzymon Olewniczak                $approver_query .= " AND revision.approved IS NULL";
164058bad72SSzymon Olewniczak            } elseif ($this->array_equal(['draft', 'approved'], $params['states'])) {
1652ce523c6SSzymon Olewniczak                $approver_query .= " AND (revision.approved IS NOT NULL OR (revision.approved IS NULL AND revision.ready_for_approval IS NULL))";
166058bad72SSzymon Olewniczak            } elseif ($this->array_equal(['ready_for_approval', 'approved'], $params['states'])) {
1672ce523c6SSzymon Olewniczak                $approver_query .= " AND (revision.ready_for_approval IS NOT NULL OR revision.approved IS NOT NULL)";
168058bad72SSzymon Olewniczak            }
169058bad72SSzymon Olewniczak        }
170058bad72SSzymon Olewniczak
1712ce523c6SSzymon Olewniczak        $q = "SELECT page.page, page.approver, revision.rev, revision.approved, revision.approved_by,
172c7d53eabSSzymon Olewniczak                    revision.ready_for_approval, revision.ready_for_approval_by,
173c7d53eabSSzymon Olewniczak                    LENGTH(page.page) - LENGTH(REPLACE(page.page, ':', '')) AS colons
174c7d53eabSSzymon Olewniczak                    FROM page INNER JOIN revision ON page.page = revision.page
175*8b39f880SSzymon Olewniczak                    WHERE page.hidden = 0 AND revision.current=1 AND page.page GLOB ?
1762ce523c6SSzymon Olewniczak                            $approver_query
177c7d53eabSSzymon Olewniczak                    ORDER BY colons, page.page";
178c02b6e47SSzymon Olewniczak
179c02b6e47SSzymon Olewniczak        $res = $sqlite->query($q, $query_args);
180c7d53eabSSzymon Olewniczak        $pages = $sqlite->res2arr($res);
181b81b1128SSzymon Olewniczak
182b81b1128SSzymon Olewniczak        // Output Table
183b81b1128SSzymon Olewniczak        $renderer->doc .= '<table><tr>';
184b81b1128SSzymon Olewniczak        $renderer->doc .= '<th>' . $this->getLang('hdr_page') . '</th>';
185b81b1128SSzymon Olewniczak        $renderer->doc .= '<th>' . $this->getLang('hdr_state') . '</th>';
186b81b1128SSzymon Olewniczak        $renderer->doc .= '<th>' . $this->getLang('hdr_updated') . '</th>';
1872ce523c6SSzymon Olewniczak        $renderer->doc .= '<th>' . $this->getLang('hdr_approver') . '</th>';
188b81b1128SSzymon Olewniczak        $renderer->doc .= '</tr>';
189b81b1128SSzymon Olewniczak
190b81b1128SSzymon Olewniczak
191b81b1128SSzymon Olewniczak        $all_approved = 0;
192b81b1128SSzymon Olewniczak        $all_approved_ready = 0;
193b81b1128SSzymon Olewniczak        $all = 0;
194b81b1128SSzymon Olewniczak
195c7d53eabSSzymon Olewniczak        $curNS = '';
196b81b1128SSzymon Olewniczak        foreach($pages as $page) {
197c7d53eabSSzymon Olewniczak            $id = $page['page'];
1982ce523c6SSzymon Olewniczak            $approver = $page['approver'];
199c7d53eabSSzymon Olewniczak            $rev = $page['rev'];
200c7d53eabSSzymon Olewniczak            $approved = strtotime($page['approved']);
201c7d53eabSSzymon Olewniczak            $approved_by = $page['approved_by'];
202c7d53eabSSzymon Olewniczak            $ready_for_approval = strtotime($page['ready_for_approval']);
203c7d53eabSSzymon Olewniczak            $ready_for_approval_by = $page['ready_for_approval_by'];
204b81b1128SSzymon Olewniczak
205c7d53eabSSzymon Olewniczak            $pageNS = getNS($id);
206c7d53eabSSzymon Olewniczak
207c7d53eabSSzymon Olewniczak            if($pageNS != '' && $pageNS != $curNS) {
208c7d53eabSSzymon Olewniczak                $curNS = $pageNS;
209c7d53eabSSzymon Olewniczak
210c7d53eabSSzymon Olewniczak                $renderer->doc .= '<tr><td colspan="4"><a href="';
211c7d53eabSSzymon Olewniczak                $renderer->doc .= wl($curNS);
212b81b1128SSzymon Olewniczak                $renderer->doc .= '">';
213c7d53eabSSzymon Olewniczak                $renderer->doc .= $curNS;
214b81b1128SSzymon Olewniczak                $renderer->doc .= '</a> ';
215b81b1128SSzymon Olewniczak                $renderer->doc .= '</td></tr>';
216b81b1128SSzymon Olewniczak            }
217b81b1128SSzymon Olewniczak
218b81b1128SSzymon Olewniczak            $all += 1;
219c7d53eabSSzymon Olewniczak            if ($approved) {
220b81b1128SSzymon Olewniczak                $class = 'plugin__approve_green';
221b81b1128SSzymon Olewniczak                $state = $this->getLang('approved');
222c7d53eabSSzymon Olewniczak                $date = $approved;
223c7d53eabSSzymon Olewniczak                $by = $approved_by;
224c7d53eabSSzymon Olewniczak
225b81b1128SSzymon Olewniczak                $all_approved += 1;
226c7d53eabSSzymon Olewniczak            } elseif ($this->getConf('ready_for_approval') && $ready_for_approval) {
227b81b1128SSzymon Olewniczak                $class = 'plugin__approve_ready';
228b81b1128SSzymon Olewniczak                $state = $this->getLang('marked_approve_ready');
229c7d53eabSSzymon Olewniczak                $date = $ready_for_approval;
230c7d53eabSSzymon Olewniczak                $by = $ready_for_approval_by;
231c7d53eabSSzymon Olewniczak
232b81b1128SSzymon Olewniczak                $all_approved_ready += 1;
233c7d53eabSSzymon Olewniczak            } else {
234c7d53eabSSzymon Olewniczak                $class = 'plugin__approve_red';
235c7d53eabSSzymon Olewniczak                $state = $this->getLang('draft');
236c7d53eabSSzymon Olewniczak                $date = $rev;
237c7d53eabSSzymon Olewniczak                $by = p_get_metadata($id, 'last_change user');
238b81b1128SSzymon Olewniczak            }
239b81b1128SSzymon Olewniczak
240b81b1128SSzymon Olewniczak            $renderer->doc .= '<tr class="'.$class.'">';
241b81b1128SSzymon Olewniczak            $renderer->doc .= '<td><a href="';
242c7d53eabSSzymon Olewniczak            $renderer->doc .= wl($id);
243b81b1128SSzymon Olewniczak            $renderer->doc .= '">';
244c7d53eabSSzymon Olewniczak            if ($conf['useheading'] == '1') {
245c7d53eabSSzymon Olewniczak                $heading = p_get_first_heading($id);
246b81b1128SSzymon Olewniczak                if ($heading != '') {
247b81b1128SSzymon Olewniczak                    $renderer->doc .= $heading;
248b81b1128SSzymon Olewniczak                } else {
249c7d53eabSSzymon Olewniczak                    $renderer->doc .= $id;
250b81b1128SSzymon Olewniczak                }
251b81b1128SSzymon Olewniczak            } else {
252c7d53eabSSzymon Olewniczak                $renderer->doc .= $id;
253b81b1128SSzymon Olewniczak            }
254b81b1128SSzymon Olewniczak
255b81b1128SSzymon Olewniczak            $renderer->doc .= '</a></td><td>';
256c7d53eabSSzymon Olewniczak            $renderer->doc .= '<strong>'.$state. '</strong> ';
257c7d53eabSSzymon Olewniczak
258c7d53eabSSzymon Olewniczak            $user = $auth->getUserData($by);
259c7d53eabSSzymon Olewniczak            if ($user) {
260c7d53eabSSzymon Olewniczak                $renderer->doc .= $this->getLang('by'). ' ' . $user['name'];
261c7d53eabSSzymon Olewniczak            }
262b81b1128SSzymon Olewniczak            $renderer->doc .= '</td><td>';
263c7d53eabSSzymon Olewniczak            $renderer->doc .= '<a href="' . wl($id) . '">' . dformat($date) . '</a>';;
264c7d53eabSSzymon Olewniczak            $renderer->doc .= '</td><td>';
2652ce523c6SSzymon Olewniczak            if ($approver) {
2662ce523c6SSzymon Olewniczak                $user = $auth->getUserData($approver);
267c7d53eabSSzymon Olewniczak                if ($user) {
268c7d53eabSSzymon Olewniczak                    $renderer->doc .= $user['name'];
269c7d53eabSSzymon Olewniczak                } else {
2702ce523c6SSzymon Olewniczak                    $renderer->doc .= $approver;
271c7d53eabSSzymon Olewniczak                }
272c7d53eabSSzymon Olewniczak            } else {
273c7d53eabSSzymon Olewniczak                $renderer->doc .= '---';
274c7d53eabSSzymon Olewniczak            }
275b81b1128SSzymon Olewniczak            $renderer->doc .= '</td></tr>';
276b81b1128SSzymon Olewniczak        }
277b81b1128SSzymon Olewniczak
2785f33cda2SSzymon Olewniczak        if ($params['summarize']) {
279c7d53eabSSzymon Olewniczak            if($this->getConf('ready_for_approval')) {
280b81b1128SSzymon Olewniczak                $renderer->doc .= '<tr><td><strong>';
281b81b1128SSzymon Olewniczak                $renderer->doc .= $this->getLang('all_approved_ready');
282b81b1128SSzymon Olewniczak                $renderer->doc .= '</strong></td>';
283b81b1128SSzymon Olewniczak
284c7d53eabSSzymon Olewniczak                $renderer->doc .= '<td colspan="3">';
285b81b1128SSzymon Olewniczak                $percent       = 0;
286b81b1128SSzymon Olewniczak                if($all > 0) {
287b81b1128SSzymon Olewniczak                    $percent = $all_approved_ready * 100 / $all;
288b81b1128SSzymon Olewniczak                }
289b81b1128SSzymon Olewniczak                $renderer->doc .= $all_approved_ready . ' / ' . $all . sprintf(" (%.0f%%)", $percent);
290b81b1128SSzymon Olewniczak                $renderer->doc .= '</td></tr>';
291b81b1128SSzymon Olewniczak            }
292b81b1128SSzymon Olewniczak
293b81b1128SSzymon Olewniczak            $renderer->doc .= '<tr><td><strong>';
294b81b1128SSzymon Olewniczak            $renderer->doc .= $this->getLang('all_approved');
295b81b1128SSzymon Olewniczak            $renderer->doc .= '</strong></td>';
296b81b1128SSzymon Olewniczak
297c7d53eabSSzymon Olewniczak            $renderer->doc .= '<td colspan="3">';
298b81b1128SSzymon Olewniczak            $percent       = 0;
299b81b1128SSzymon Olewniczak            if($all > 0) {
300b81b1128SSzymon Olewniczak                $percent = $all_approved * 100 / $all;
301b81b1128SSzymon Olewniczak            }
302b81b1128SSzymon Olewniczak            $renderer->doc .= $all_approved . ' / ' . $all . sprintf(" (%.0f%%)", $percent);
303b81b1128SSzymon Olewniczak            $renderer->doc .= '</td></tr>';
3045f33cda2SSzymon Olewniczak        }
305b81b1128SSzymon Olewniczak
306b81b1128SSzymon Olewniczak        $renderer->doc .= '</table>';
307b81b1128SSzymon Olewniczak    }
308b81b1128SSzymon Olewniczak}
309