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 __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    function handle($match, $state, $pos, Doku_Handler $handler) {
48        switch ($state) {
49            case DOKU_LEXER_SPECIAL:
50                $data = array(
51                    'state' => $state
52                );
53
54                // match @server and @token
55                preg_match("/server *= *(['\"])(.*?)\\1/", $match, $server);
56                if (count($server) != 0) {
57                    $server_data = $this->getServerFromJson($server[2]);
58                    if (!is_null($server_data)) {
59                        $data['server'] = $server_data['url'];
60                        $data['token'] = $server_data['api_token'];
61                    }
62                }
63                if (!isset($data['server']))
64                    $data['server'] = $this->getConf('server.default');
65                if (!isset($data['token']))
66                    $data['token'] = $this->getConf('token.default');
67
68                // match @project-path
69                preg_match("/project-path *= *(['\"])(.*?)\\1/", $match, $project_path);
70                if (count($project_path) != 0)
71                    $data['project-path'] = $project_path[2];
72
73                // match @milestones
74                preg_match("/milestones *= *(['\"])(.*?)\\1/", $match, $milestones);
75                $data['milestones'] = $milestones[2];
76
77                // match @commits
78                preg_match("/commits *= *(['\"])(.*?)\\1/", $match, $commits);
79                $data['commits'] = $commits[2];
80
81                // match @issues
82                preg_match("/issues *= *(['\"])(.*?)\\1/", $match, $issues);
83                $data['issues'] = $issues[2];
84
85                // match @pipelines
86                preg_match("/pipelines *= *(['\"])(.*?)\\1/", $match, $pipelines);
87                $data['pipelines'] = $pipelines[2];
88
89                return $data;
90
91            case DOKU_LEXER_UNMATCHED:
92                return array('state' => $state, 'text' => $match);
93
94            default:
95                return array('state' => $state, 'bytepos_end' => $pos + strlen($match));
96        }
97    }
98
99    function render($mode, Doku_Renderer $renderer, $data) {
100        if ($mode !== 'xhtml') return false;
101        if ($mode != 'xhtml') return false;
102
103        if ($data['error']) {
104            $renderer->doc .= $data['text'];
105            return true;
106        }
107
108        $renderer->info['cache'] = false;
109        switch ($data['state']) {
110            case DOKU_LEXER_SPECIAL:
111                $this->renderGitLab($renderer, $data);
112                break;
113
114            case DOKU_LEXER_ENTER:
115            case DOKU_LEXER_EXIT:
116            case DOKU_LEXER_UNMATCHED:
117                $renderer->doc .= $renderer->_xmlEntities($data['text']);
118                break;
119        }
120
121        return true;
122    }
123
124    function renderGitLab($renderer, $data) {
125        // create GitLabApi object
126        $gitlab = new GitLabApi($data);
127
128        // get project
129        $project = $gitlab->getProject();
130        //dbg($project);
131
132        if (empty($project)) {
133            $this->renderProjectError($renderer, $data);
134            return array('state' => $state, 'bytepos_end' => $pos + strlen($match));
135        }
136
137        $project_id = $project['id'];
138
139        $project_url = $project['web_url'];
140        $project_name = $project['name'];
141        $date_time = $this->getDateTime($project['last_activity_at']);
142        $namespace = $project['namespace']['full_path'];
143
144        $img_url = DOKU_URL . 'lib/plugins/gitlabapi/images/gitlab.png';
145
146        $renderer->doc .= '<div class="gitlab">';
147        $renderer->doc .= '<span><img src="'.$img_url.'" class="gitlab"></span>';
148        $renderer->doc .= '<b class="gitlab">'.$this->getLang('gitlab.project').'</b><br>';
149        $renderer->doc .= '<hr class="gitlab">';
150        $renderer->doc .= '<a href="'.$project_url.'" class="gitlab">'.$project_name.'</a>';
151        $renderer->doc .= ' - <b>Namespace:</b> <a href="'.$data['server'].'/'.$namespace.'"> '.$namespace.'</a>';
152        $renderer->doc .= '<p><b>'.$this->getLang('gitlab.activity').':</b> '.$date_time['date'].' - '.$date_time['time'].'</p>';
153
154        if ($data['milestones'])
155            $this->renderProjectMilestones($renderer, $gitlab, $project_id, $data['milestones']);
156        if ($data['commits'])
157            $this->renderProjectCommits($renderer, $gitlab, $project_id, $data['commits']);
158        if ($data['issues'])
159            $this->renderProjectIssues($renderer, $gitlab, $project_id, $data['issues']);
160        if ($data['pipelines'])
161            $this->renderProjectPipelines($renderer, $gitlab, $project_id, $data['pipelines']);
162
163        $renderer->doc .= '</p>';
164        $renderer->doc .= '</div>';
165
166        $gitlab->closeClient();
167    }
168
169    function renderProjectCommits($renderer, $gitlab, $project_id, $number) {
170        $commits = $gitlab->getCommits($project_id);
171
172        $renderer->doc .= '<b class="gitlab">'.$this->getLang('gitlab.commits').'</b><br>';
173        $renderer->doc .= '<table border="1">
174            <thread>
175                <tr>
176                    <th>Committer Name</th>
177                    <th>Title</th>
178                    <th>Message</th>
179                    <th>Date</th>
180                    <th>URL</th>
181                <tr>
182            </thread>
183            <tbody>';
184
185        $total = count($commits) < $number ? count($commits) : $number;
186        for ($i = 0; $i < $total; $i++) {
187            $renderer->doc .= '<tr>';
188            $renderer->doc .= '<td>'.$commits[$i]['committer_name'].'</td>';
189            $renderer->doc .= '<td>'.$commits[$i]['title'].'</td>';
190            $renderer->doc .= '<td>'.$commits[$i]['message'].'</td>';
191            $renderer->doc .= '<td>'.$commits[$i]['committed_date'].'</td>';
192            $renderer->doc .= '<td><a href='.$commits[$i]['web_url'].'>Commit link</a></td>';
193            $renderer->doc .= '</tr>';
194        }
195        $renderer->doc .= '</tbody></table>';
196    }
197
198    function renderProjectIssues($renderer, $gitlab, $project_id, $number) {
199        $issues = $gitlab->getIssues($project_id);
200
201        $renderer->doc .= '<b class="gitlab">'.$this->getLang('gitlab.issues').'</b><br>';
202        $renderer->doc .= '<table border="1">
203            <thread>
204                <tr>
205                    <th>Author</th>
206                    <th>Title</th>
207                    <th>Labels</th>
208                    <th>Assignees</th>
209                    <th>State</th>
210                    <th>URL</th>
211                <tr>
212            </thread>
213            <tbody>';
214
215        $total = count($issues) < $number ? count($issues) : $number;
216        for ($i = 0; $i < $total; $i++) {
217            $renderer->doc .= '<tr>';
218            $renderer->doc .= '<td>'.$issues[$i]['author']['name'].'</td>';
219            $renderer->doc .= '<td>'.$issues[$i]['title'].'</td>';
220            $labels = $issues[$i]['labels'];
221            $l_list = '';
222            foreach ($labels as $l)
223                $l_list .= $l.', ';
224            $renderer->doc .= '<td>'.rtrim($l_list,', ').'</td>';
225            $assignees = $issues[$i]['assignees'];
226            $a_list = '';
227            foreach ($assignees as $a)
228                $a_list .= $a['name'].', ';
229            $renderer->doc .= '<td>'.rtrim($a_list, ', ').'</td>';
230            $renderer->doc .= '<td>'.$issues[$i]['state'].'</td>';
231            $renderer->doc .= '<td><a href='.$issues[$i]['web_url'].'>Issue link</a></td>';
232            $renderer->doc .= '</tr>';
233        }
234        $renderer->doc .= '</tbody></table>';
235
236    }
237
238    function renderProjectMilestones($renderer, $gitlab, $project_id, $number) {
239        $milestones = $gitlab->getMilestones($project_id);
240
241        $renderer->doc .= '<b class="gitlab">'.$this->getLang('gitlab.milestones').'</b><br>';
242        $renderer->doc .= '<table border="1">
243            <thread>
244                <tr>
245                    <th>Title</th>
246                    <th>Description</th>
247                    <th>State</th>
248                    <th>Created</th>
249                    <th>URL</th>
250                <tr>
251            </thread>
252            <tbody>';
253
254        $total = count($milestones) < $number ? count($milestones) : $number;
255        for ($i = 0; $i < $total; $i++) {
256            $renderer->doc .= '<tr>';
257            $renderer->doc .= '<td>'.$milestones[$i]['title'].'</td>';
258            $renderer->doc .= '<td>'.$milestones[$i]['description'].'</td>';
259            $renderer->doc .= '<td>'.$milestones[$i]['state'].'</td>';
260            $renderer->doc .= '<td>'.$milestones[$i]['created_at'].'</td>';
261            $renderer->doc .= '<td><a href='.$milestones[$i]['web_url'].'>Milestone link</a></td>';
262            $renderer->doc .= '</tr>';
263        }
264
265        $renderer->doc .= '</tbody></table>';
266    }
267
268    function renderProjectPipelines($renderer, $gitlab, $project_id, $number) {
269        $pipelines = $gitlab->getPipelines($project_id);
270
271        $renderer->doc .= '<b class="gitlab">'.$this->getLang('gitlab.pipelines').'</b><br>';
272        $renderer->doc .= '<table border="1">
273            <thread>
274                <tr>
275                    <th>Ref</th>
276                    <th>Status</th>
277                    <th>Source</th>
278                    <th>URL</th>
279                <tr>
280            </thread>
281            <tbody>';
282
283        $total = count($pipelines) < $number ? count($pipelines) : $number;
284        for ($i = 0; $i < $total; $i++) {
285            $renderer->doc .= '<tr>';
286            $renderer->doc .= '<td>'.$pipelines[$i]['ref'].'</td>';
287            $renderer->doc .= '<td>'.$pipelines[$i]['status'].'</td>';
288            $renderer->doc .= '<td>'.$pipelines[$i]['source'].'</td>';
289            $renderer->doc .= '<td><a href='.$pipelines[$i]['web_url'].'>Pipeline link</a></td>';
290            $renderer->doc .= '</tr>';
291        }
292
293        $renderer->doc .= '</tbody></table>';
294
295    }
296
297    function renderProjectError($renderer, $data) {
298        $img_url = DOKU_URL . 'lib/plugins/gitlabapi/images/gitlab.png';
299
300        $renderer->doc .= '<div class="gitlab">';
301        $renderer->doc .= '<span><img src="'.$img_url.'" class="gitlab"></span>';
302        $renderer->doc .= '<b class="gitlab">'.$this->getLang('gitlab.project').'</b><br>';
303        $renderer->doc .= '<hr class="gitlab">';
304        $renderer->doc .= '<p>'.$this->getLang('gitlab.error').'</p>';
305        $renderer->doc .= '</div>';
306    }
307
308    function getDateTime($activity_time) {
309        $date_exploded = explode('T', $activity_time);
310        $time_exploded = explode('Z', $date_exploded[1]);
311
312        return array('date' => $date_exploded[0], 'time' => substr($time_exploded[0], 0, -4));
313    }
314
315}
316
317
318
319