1<?php
2/**
3 * GitLab Api Plugin
4 *
5 * @license : BSD-3 Clause
6 * @author  : Mehmet Ozgan <mozgan@gmail.com>
7 */
8
9if (!defined('DOKU_INC')) { die(); }
10
11require_once __DIR__.'/gitlab/gitlabapi.php';
12
13class syntax_plugin_gitlabapi extends DokuWiki_Syntax_Plugin {
14    /**
15     * Syntax Plugins
16     *
17     * The class needs to implement at least the following functions:
18     *  -) getType()
19     *  -) getSort()
20     *  -) connectTo($mode)
21     *  -) handle($match, $state, $pos, Doku_Handler $handler)
22     *  -) render($mode, Doku_Renderer $renderer, $data)
23     *
24     *  More information: https://www.dokuwiki.org/devel:syntax_plugins#syntax_types
25     */
26
27    public function getType() { return 'substition'; }
28
29    public function getPType() { return 'normal'; }
30
31    public function getSort() { return 196; }
32
33    public function connectTo($mode) {
34        $this->Lexer->addSpecialPattern('<gitlab-api[^>]*/>', $mode, 'plugin_gitlabapi');
35    }
36
37    function getServerFromJson($server) {
38        $json_file = file_get_contents(__DIR__.'/server.json');
39        $json_data = json_decode($json_file, true);
40        if (isset($json_data[$server])) {
41            return $json_data[$server];
42        } else {
43            return null;
44        }
45    }
46
47
48    function handle($match, $state, $pos, Doku_Handler $handler) {
49        switch ($state) {
50            case DOKU_LEXER_SPECIAL:
51                $data = array(
52                    'state' => $state
53                );
54
55                // match @server and @token
56                preg_match("/server *= *(['\"])(.*?)\\1/", $match, $server);
57                if (!empty($server)) {
58                    $server_data = $this->getServerFromJson($server[2]);
59                    if (!is_null($server_data)) {
60                        $data['server'] = $server_data['url'];
61                        $data['token'] = $server_data['api_token'];
62                    }
63                }
64                if (!isset($data['server'])) {
65                    $data['server'] = $this->getConf('server.default');
66                }
67
68                if (!isset($data['token'])) {
69                    $data['token'] = $this->getConf('token.default');
70                }
71
72                // match @project-path
73                preg_match("/project-path *= *(['\"])(.*?)\\1/", $match, $project_path);
74                if (!empty($project_path)) {
75                    $data['project-path'] = $project_path[2];
76                }
77
78                // match @milestones
79                preg_match("/milestones *= *(['\"])(.*?)\\1/", $match, $milestones);
80                if(!empty($milestones)) {
81                    $data['milestones'] = $milestones[2];
82                }
83
84                // match @commits
85                preg_match("/commits *= *(['\"])(.*?)\\1/", $match, $commits);
86                if(!empty($commits)) {
87                    $data['commits'] = $commits[2];
88                }
89
90                // match @issues
91                preg_match("/issues *= *(['\"])(.*?)\\1/", $match, $issues);
92                if(!empty($issues)) {
93                    $data['issues'] = $issues[2];
94                }
95
96                // match @pipelines
97                preg_match("/pipelines *= *(['\"])(.*?)\\1/", $match, $pipelines);
98                if(!empty($pipelines)) {
99                    $data['pipelines'] = $pipelines[2];
100                }
101
102                return $data;
103
104            case DOKU_LEXER_UNMATCHED:
105                return array('state' => $state, 'text' => $match);
106
107            default:
108                return array('state' => $state, 'bytepos_end' => $pos + strlen($match));
109        }
110    }
111
112    function render($mode, Doku_Renderer $renderer, $data) {
113        if ($mode !== 'xhtml') { return false; }
114        if ($mode != 'xhtml') { return false; }
115
116        if (isset($data['error'])) {
117            $renderer->doc .= $data['text'];
118            return true;
119        }
120
121        $renderer->info['cache'] = false;
122        switch ($data['state']) {
123            case DOKU_LEXER_SPECIAL:
124                $this->renderGitLab($renderer, $data);
125                break;
126
127            case DOKU_LEXER_ENTER:
128            case DOKU_LEXER_EXIT:
129            case DOKU_LEXER_UNMATCHED:
130                $renderer->doc .= $renderer->_xmlEntities($data['text']);
131                break;
132        }
133
134        return true;
135    }
136
137    function renderGitLab($renderer, $data) {
138        // create GitLabApi object
139        $gitlab = new GitLabApi($data);
140
141        // get project
142        $project = $gitlab->getProject();
143        //dbg($project);
144
145        if (empty($project)) {
146            $this->renderProjectError($renderer, $data);
147            return array('state' => $state, 'bytepos_end' => $pos + strlen($match));
148        }
149
150        $project_id = $project['id'];
151
152        $project_url = $project['web_url'];
153        $project_name = $project['name'];
154        $date_time = $this->getDateTime($project['last_activity_at']);
155        $namespace = $project['namespace']['full_path'];
156
157        $img_url = DOKU_URL . 'lib/plugins/gitlabapi/images/gitlab.png';
158
159        $renderer->doc .= '<div class="gitlab">';
160        $renderer->doc .= '<span><img src="'.$img_url.'" class="gitlab"></span>';
161        $renderer->doc .= '<b class="gitlab">'.$this->getLang('gitlab.project').'</b><br>';
162        $renderer->doc .= '<hr class="gitlab">';
163        $renderer->doc .= '<a href="'.$project_url.'" class="gitlab">'.$project_name.'</a>';
164        $renderer->doc .= ' - <b>Namespace:</b> <a href="'.$data['server'].'/'.$namespace.'"> '.$namespace.'</a>';
165        $renderer->doc .= '<p><b>'.$this->getLang('gitlab.activity').':</b> '.$date_time['date'].' - '.$date_time['time'].'</p>';
166
167        if (!empty($data['milestones'])) {
168            $this->renderProjectMilestones($renderer, $gitlab, $project_id, $data['milestones']);
169        }
170        if (!empty($data['commits'])) {
171            $this->renderProjectCommits($renderer, $gitlab, $project_id, $data['commits']);
172        }
173        if (!empty($data['issues'])) {
174            $this->renderProjectIssues($renderer, $gitlab, $project_id, $data['issues']);
175        }
176        if (!empty($data['pipelines'])) {
177            $this->renderProjectPipelines($renderer, $gitlab, $project_id, $data['pipelines']);
178        }
179
180        $renderer->doc .= '</p>';
181        $renderer->doc .= '</div>';
182
183        $gitlab->closeClient();
184    }
185
186    function renderProjectCommits($renderer, $gitlab, $project_id, $number) {
187        $commits = $gitlab->getCommits($project_id);
188
189        $renderer->doc .= '<b class="gitlab">'.$this->getLang('gitlab.commits').'</b><br>';
190        $renderer->doc .= '<table border="1">
191            <thread>
192                <tr>
193                    <th>Committer Name</th>
194                    <th>Title</th>
195                    <th>Message</th>
196                    <th>Date</th>
197                    <th>URL</th>
198                <tr>
199            </thread>
200            <tbody>';
201
202        $total = count($commits) < $number ? count($commits) : $number;
203        for ($i = 0; $i < $total; $i++) {
204            $renderer->doc .= '<tr>';
205            $renderer->doc .= '<td>'.$commits[$i]['committer_name'].'</td>';
206            $renderer->doc .= '<td>'.$commits[$i]['title'].'</td>';
207            $renderer->doc .= '<td>'.$commits[$i]['message'].'</td>';
208            $renderer->doc .= '<td>'.$commits[$i]['committed_date'].'</td>';
209            $renderer->doc .= '<td><a href='.$commits[$i]['web_url'].'>Commit link</a></td>';
210            $renderer->doc .= '</tr>';
211        }
212        $renderer->doc .= '</tbody></table>';
213    }
214
215    function renderProjectIssues($renderer, $gitlab, $project_id, $number) {
216        $issues = $gitlab->getIssues($project_id);
217
218        $renderer->doc .= '<b class="gitlab">'.$this->getLang('gitlab.issues').'</b><br>';
219        $renderer->doc .= '<table border="1">
220            <thread>
221                <tr>
222                    <th>Author</th>
223                    <th>Title</th>
224                    <th>Labels</th>
225                    <th>Assignees</th>
226                    <th>State</th>
227                    <th>URL</th>
228                <tr>
229            </thread>
230            <tbody>';
231
232        $total = count($issues) < $number ? count($issues) : $number;
233        for ($i = 0; $i < $total; $i++) {
234            if ($issues[$i]['state'] == 'closed') {
235                continue;
236            }
237            $renderer->doc .= '<tr>';
238            $renderer->doc .= '<td>'.$issues[$i]['author']['name'].'</td>';
239            $renderer->doc .= '<td>'.$issues[$i]['title'].'</td>';
240            $labels = $issues[$i]['labels'];
241            $l_list = '';
242            foreach ($labels as $l) {
243                $l_list .= $l.', ';
244            }
245            $renderer->doc .= '<td>'.rtrim($l_list,', ').'</td>';
246            $assignees = $issues[$i]['assignees'];
247            $a_list = '';
248            foreach ($assignees as $a) {
249                $a_list .= $a['name'].', ';
250            }
251            $renderer->doc .= '<td>'.rtrim($a_list, ', ').'</td>';
252            $renderer->doc .= '<td>'.$issues[$i]['state'].'</td>';
253            $renderer->doc .= '<td><a href='.$issues[$i]['web_url'].'>Issue link</a></td>';
254            $renderer->doc .= '</tr>';
255        }
256        $renderer->doc .= '</tbody></table>';
257
258    }
259
260    function renderProjectMilestones($renderer, $gitlab, $project_id, $number) {
261        $milestones = $gitlab->getMilestones($project_id);
262
263        $renderer->doc .= '<b class="gitlab">'.$this->getLang('gitlab.milestones').'</b><br>';
264        $renderer->doc .= '<table border="1">
265            <thread>
266                <tr>
267                    <th>Title</th>
268                    <th>Description</th>
269                    <th>State</th>
270                    <th>Created</th>
271                    <th>URL</th>
272                <tr>
273            </thread>
274            <tbody>';
275
276        $total = count($milestones) < $number ? count($milestones) : $number;
277        for ($i = 0; $i < $total; $i++) {
278            $renderer->doc .= '<tr>';
279            $renderer->doc .= '<td>'.$milestones[$i]['title'].'</td>';
280            $renderer->doc .= '<td>'.$milestones[$i]['description'].'</td>';
281            $renderer->doc .= '<td>'.$milestones[$i]['state'].'</td>';
282            $renderer->doc .= '<td>'.$milestones[$i]['created_at'].'</td>';
283            $renderer->doc .= '<td><a href='.$milestones[$i]['web_url'].'>Milestone link</a></td>';
284            $renderer->doc .= '</tr>';
285        }
286
287        $renderer->doc .= '</tbody></table>';
288    }
289
290    function renderProjectPipelines($renderer, $gitlab, $project_id, $number) {
291        $pipelines = $gitlab->getPipelines($project_id);
292
293        $renderer->doc .= '<b class="gitlab">'.$this->getLang('gitlab.pipelines').'</b><br>';
294        $renderer->doc .= '<table border="1">
295            <thread>
296                <tr>
297                    <th>Ref</th>
298                    <th>Status</th>
299                    <th>Source</th>
300                    <th>URL</th>
301                <tr>
302            </thread>
303            <tbody>';
304
305        $total = count($pipelines) < $number ? count($pipelines) : $number;
306        for ($i = 0; $i < $total; $i++) {
307            $renderer->doc .= '<tr>';
308            $renderer->doc .= '<td>'.$pipelines[$i]['ref'].'</td>';
309            $renderer->doc .= '<td>'.$pipelines[$i]['status'].'</td>';
310            $renderer->doc .= '<td>'.$pipelines[$i]['source'].'</td>';
311            $renderer->doc .= '<td><a href='.$pipelines[$i]['web_url'].'>Pipeline link</a></td>';
312            $renderer->doc .= '</tr>';
313        }
314
315        $renderer->doc .= '</tbody></table>';
316
317    }
318
319    function renderProjectError($renderer, $data) {
320        $img_url = DOKU_URL . 'lib/plugins/gitlabapi/images/gitlab.png';
321
322        $renderer->doc .= '<div class="gitlab">';
323        $renderer->doc .= '<span><img src="'.$img_url.'" class="gitlab"></span>';
324        $renderer->doc .= '<b class="gitlab">'.$this->getLang('gitlab.project').'</b><br>';
325        $renderer->doc .= '<hr class="gitlab">';
326        $renderer->doc .= '<p>'.$this->getLang('gitlab.error').'</p>';
327        $renderer->doc .= '</div>';
328    }
329
330    function getDateTime($activity_time) {
331        $date_exploded = explode('T', $activity_time);
332        $time_exploded = explode('Z', $date_exploded[1]);
333
334        return array('date' => $date_exploded[0], 'time' => substr($time_exploded[0], 0, -4));
335    }
336
337}
338
339
340
341