1<?php
2/**
3 * Copyright 2010 Yuri Timofeev tim4dev@gmail.com
4 *
5 * This is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This software is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this software.  If not, see <http://www.gnu.org/licenses/>.
17 *
18 * @desc       Gets information about bugs (with depends on) via XML-RPC Bugzilla::WebService
19 * @author     Yuri Timofeev <tim4dev@gmail.com>
20 * @package    bugzillaxmlrpc
21 * @license    http://www.gnu.org/licenses/gpl-3.0.html GNU Public License
22 * @syntax     bugz#12345
23 *
24 */
25
26// must be run within DokuWiki
27if(!defined('DOKU_INC')) die();
28if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
29require_once(DOKU_PLUGIN.'syntax.php');
30
31class syntax_plugin_bugzillaxmlrpc extends DokuWiki_Syntax_Plugin {
32
33    protected $curl_opt = array(
34        CURLOPT_POST    => true,
35        CURLOPT_RETURNTRANSFER => true,
36        CURLOPT_HTTPHEADER  => array( 'Content-Type: text/xml', 'charset=utf-8' )
37    );
38
39    protected $xml_data = array(
40        'remember' => 1
41    );
42
43    protected $cookie_file;
44
45
46    function getInfo(){
47        return array(
48            'author' => 'Yuri Timofeev',
49            'email'  => 'tim4dev@gmail.com',
50            'date'   => '2010-09-09',
51            'name'   => 'bugzilla xml-rpc plugin',
52            'desc'   => 'Gets information about bugs via XML-RPC Bugzilla::WebService',
53            'url'    => 'http://www.dokuwiki.org/plugin:bugzillaxmlrpc',
54        );
55    }
56
57    function getType()  { return 'substition'; }
58    function getPType() { return 'normal'; }
59    function getSort()  { return 777; }
60
61    function connectTo($mode) {
62        $this->Lexer->addSpecialPattern('bugz#[0-9]+', $mode, 'plugin_bugzillaxmlrpc');
63    }
64
65
66    function myLogin() {
67        // Login and get cookie
68        // http://www.bugzilla.org/docs/3.2/en/html/api/Bugzilla/WebService/User.html
69        $this->xml_data['login'] = $this->getConf('login');
70        $this->xml_data['password'] = $this->getConf('password');
71        $ch = curl_init();
72        curl_setopt_array($ch, $this->curl_opt);
73        $request = xmlrpc_encode_request('User.login', $this->xml_data);
74        curl_setopt($ch, CURLOPT_URL, $this->getConf('xmlrpc.cgi'));
75        curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
76        curl_setopt($ch, CURLOPT_COOKIEJAR, $this->cookie_file );
77        $server_output = curl_exec($ch);
78        curl_close($ch);
79        $response = xmlrpc_decode($server_output);
80        if ( empty($response) ) {
81            @unlink($this->cookie_file);
82            return array(1, 'NULL', 'NULL');
83        }
84        return array(0, $response['faultString'], $response['faultCode'], $response['id']);
85    }
86
87
88    /**
89     * Return:
90     * bug_id, summary, dependson, product, creation_ts, bug_status, deadline
91     */
92    function myGetBugInfo($id) {
93        // Login and get bug info
94        // http://www.bugzilla.org/docs/3.2/en/html/api/Bugzilla/WebService/Bug.html
95        $this->xml_data['login'] = $this->getConf('login');
96        $this->xml_data['password'] = $this->getConf('password');
97        $ch = curl_init();
98        curl_setopt_array($ch, $this->curl_opt);
99        $this->xml_data['ids'] = array($id);
100        $request = xmlrpc_encode_request("Bug.get", $this->xml_data);
101        curl_setopt($ch, CURLOPT_URL, $this->getConf('xmlrpc.cgi'));
102        curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
103        curl_setopt($ch, CURLOPT_COOKIEFILE, $this->cookie_file );
104        $server_output = curl_exec($ch);
105        curl_close($ch);
106
107        $response = xmlrpc_decode($server_output);
108        if (xmlrpc_is_fault($response))
109            return array(1, $response[faultString], $response[faultCode], $id);
110        $v = $response['bugs'][0];
111        // Login and get Product info
112        list($error, $faultString, $faultCode, $product) = $this->myGetProductInfo($v['internals']['product_id']);
113        if ($error)
114            return array(1, $response[faultString], $response[faultCode], $id);
115        // return all data
116        return array(0, $response[faultString], $response[faultCode],
117            $id,
118            $v['summary'],
119            $v['dependson'],
120            $product,
121            $v['internals']['creation_ts'],
122            $v['internals']['bug_status'],
123            $v['internals']['deadline']
124            );
125    }
126
127
128    function myGetProductInfo($id) {
129        // Login and get Product info
130        $this->xml_data['login'] = $this->getConf('login');
131        $this->xml_data['password'] = $this->getConf('password');
132        $ch = curl_init();
133        curl_setopt_array($ch, $this->curl_opt);
134        $this->xml_data['ids'] = array($id);
135        $request = xmlrpc_encode_request("Product.get", $this->xml_data);
136        curl_setopt($ch, CURLOPT_URL, $this->getConf('xmlrpc.cgi'));
137        curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
138        curl_setopt($ch, CURLOPT_COOKIEFILE, $this->cookie_file );
139        $server_output = curl_exec($ch);
140        curl_close($ch);
141
142        $response = xmlrpc_decode($server_output);
143        if (xmlrpc_is_fault($response))
144            return array(1, $response[faultString], $response[faultCode]);
145        return array(0, $response[faultString], $response[faultCode], $response['products'][0]['name']);
146    }
147
148    function myLogout() {
149        unlink($this->cookie_file);
150    }
151
152
153    function handle($match, $state, $pos, &$handler) {
154        preg_match('/^bugz#([0-9]+)/', $match, $submatch);
155        $ids = $submatch[1];
156        $data_bugs = array(); // two-dimensional array
157        if (empty($ids)) {
158            $data_bugs[] = array('error' => 1, 'faultString' => 'Empty Id', 'faultCode' => 999, 'id' => 0);
159            $this->myLogout;
160            return array($data_bugs);
161        }
162        // Login and get cookie
163        $this->cookie_file = tempnam('', 'bugzillaxmlrpc');
164        list($error, $faultString, $faultCode, $id) = $this->myLogin();
165        if ($error) {
166            $data_bugs[] = array('error' => 1, 'faultString' => $faultString, 'faultCode' => $faultCode, 'id' => $id);
167            $this->myLogout;
168            return array($data_bugs);
169        }
170        // Login and get bug info
171        // return: bug_id, summary, dependson, product, creation_ts, bug_status, deadline
172        list($error, $faultString, $faultCode, $id, $summary, $dependson, $product, $creation_ts, $bug_status, $deadline) = $this->myGetBugInfo($ids);
173        if ($error) {
174            $data_bugs[] = array('error' => 1, 'faultString' => $faultString, 'faultCode' => $faultCode, 'id' => $id);
175            $this->myLogout;
176            return array($data_bugs);
177        }
178        $data_bugs[0] = array('error' => 0, 'faultString' => $faultString, 'faultCode' => $faultCode,
179            'id' => $id, 'summary' => $summary, 'dependson' => $dependson, 'product' => $product,
180            'creation_ts' => $creation_ts, 'bug_status' => $bug_status, 'deadline' => $deadline);
181        // Get info about dependencies bugs
182        foreach ($dependson as $dep) {
183            list($error, $faultString, $faultCode, $id, $summary, $dependson, $product, $creation_ts, $bug_status, $deadline) = $this->myGetBugInfo($dep);
184            $data_bugs[] = array('error' => 0, 'faultString' => $faultString, 'faultCode' => $faultCode,
185                'id' => $id, 'summary' => $summary, 'dependson' => $dependson, 'product' => $product,
186                'creation_ts' => $creation_ts, 'bug_status' => $bug_status, 'deadline' => $deadline);
187        }
188        // return all data
189        $this->myLogout;
190        return array($data_bugs);
191    }
192
193
194    function render($mode, &$renderer, $data) {
195        if($mode == 'xhtml'){
196            $data0 = $data[0];
197            $html_bug_all = '<ul>' . "\n";
198            $i = 1;
199            foreach ($data0 as $v) {
200                $html_bug = '';
201                if ( ($i == 2) )
202                    $html_bug_all .= '<ul>';
203                $id = $v['id'];
204                if ($v['error']) {
205                    $html_bug .= '<div class="li"><a href="' .
206                        $this->getConf('url').$id. '" target="_blank" title="'.
207                        $this->getLang('title').$id. '" class="interwiki iw_bug">'.
208                        $this->getLang('bug').' #' .$id. '</a> <i>'.
209                        $this->getLang('error_prefix').' : ' . $v['faultCode'] . ' - ' . $v['faultString'] .
210                        '</i></div>';
211                } else {
212                    if ( ($v['bug_status'] == 'CLOSED') || ($v['bug_status'] == 'RESOLVED') ) {
213                        $s1 = '<s>';
214                        $s2 = '</s>';
215                    } else {
216                        $s1 = '';
217                        $s2 = '';
218                    }
219
220                    $html_bug .= '<div class="li"><a href="' .
221                        $this->getConf('url').$id. '" target="_blank" title="'.
222                        $this->getLang('title').$id. '" class="interwiki iw_bug">'.
223                        $this->getLang('bug').' #' .$id. '</a>'.$s1.'<i> '.
224                        $v['product']. '</i> -> <b>'.$v['summary']. '</b>'.
225                        ' ('. $this->getLang('opened').': '. $v['creation_ts'] .', '.
226                        $this->getLang('bug_status').': '. $v['bug_status'] .', '.
227                        $this->getLang('deadline').': '. $v['deadline'].
228                        ') '.$s2.
229                        '</div>';
230                }
231                $html_bug_all .= '<li>'.$html_bug.'</li>' . "\n";
232                $i++;
233            } // foreach
234            if ( $i > 1 )
235                $html_bug_all .= '</ul>';
236            $renderer->doc .= $html_bug_all . '</ul>';
237            return true;
238        }
239        return false;
240    }
241
242
243}
244