1<?php
2// must be run within DokuWiki
3if(!defined('DOKU_INC')) die();
4
5if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
6require_once DOKU_PLUGIN.'syntax.php';
7
8class syntax_plugin_mantisreporter extends DokuWiki_Syntax_Plugin
9{
10    /**
11     * @var int project id
12     */
13    private $projectId;
14
15    /**
16     * Soap client if initialized. Else null.
17     *
18     * @var mixed Soap client
19     */
20    private $soapClient = null;
21
22    /**
23     * get plugin type
24     *
25     * @return string
26     */
27    public function getType() {
28        return 'substition';
29    }
30
31    /**
32     * get sorting order
33     *
34     * @return int
35     */
36    public function getSort() {
37        return 32;
38    }
39
40    /**
41     * Define matching strings
42     *
43     * @param string $mode
44     */
45    public function connectTo($mode) {
46        $this->Lexer->addSpecialPattern('\{\{ mantisReport\?mantisProjectId=\d* }}', $mode, 'plugin_mantisreporter');
47    }
48
49    /**
50     * set the parameters for $data for the render function
51     *
52     * @param string $match gematchte string
53     * @param int $state
54     * @param int $pos
55     * @param DokuHandler $handler
56     *
57     * @return array
58     */
59    public function handle($match, $state, $pos, &$handler) {
60        return array($match, $state, $pos);
61    }
62
63    /**
64     * Render the report html
65     *
66     * @param string $format
67     * @param Doku_Renderer_metadata $renderer
68     * @param array $data
69     *
70     * @return type boolean is de operatie geslaagd?
71     */
72    public function render($format, &$renderer, $data) {
73
74        if('xhtml' === $format) {
75            try {
76                $renderer->doc .= $this->saveIssue();
77            } catch (Exception $e) {
78                print 'Er ging iets fout: ' . $e->getMessage();
79                unset($_POST['reporter']);
80            }
81            try {
82                $this->parseData($data[0]);
83                $renderer->doc .= $this->getHtml();
84                return true;
85            } catch (Exception $e) {
86                print 'Er ging iets fout: ' . $e->getMessage();
87                return false;
88            }
89        } else {
90            return false;
91        }
92    }
93
94    /**
95     * Parse data to filter out variables
96     *
97     * @param string $data
98     *
99     * @return boolean success
100     */
101    private function parseData($data) {
102        $regexId = '#mantisProjectId=(\d*)#i';
103        $resultId = array();
104        preg_match($regexId, $data, $resultId);
105        $this->setProjectId($resultId[1]);
106        return true;
107    }
108
109    /**
110     * Get the project id
111     *
112     * @return int
113     */
114    private function getProjectId() {
115        return $this->projectId;
116    }
117
118    /**
119     * Set the project id
120     *
121     * @param int $projectId
122     */
123    private function setProjectId($projectId) {
124        $this->projectId = $projectId;
125    }
126
127    /**
128     * Get the html for priorities
129     *
130     * @return string
131     */
132    private function getPrioritiesHtml() {
133        $html = "<select name='priority'>";
134        $priorities = $this->getPriorities();
135
136        if(0 === count($priorities)) {
137            return 'Geen prioriteiten gevonden';
138        }
139
140        foreach($priorities as $priority) {
141            $html .= '<option ';
142            if($priority->id == 30) {
143                $html .= 'selected ';
144            }
145            $html .= 'value="'.$priority->id.'">'.$priority->name.'</option>';
146        }
147        return $html . '</select>';
148    }
149
150    /**
151     * Get the html for reporters
152     *
153     * @return string
154     */
155    private function getReportersHtml() {
156        $caller = $_GET['caller'];
157        $html = "<select name='reporter'>";
158        $reporters = $this->getReporters();
159        if(0 === count($reporters)) {
160            return 'Geen reporters gevonden';
161        }
162        foreach($reporters as $reporter) {
163            $html .= '<option value="'.$reporter->id . '"';
164
165            if($reporter->name === $caller) {
166                $html .= ' selected=selected ';
167            }
168            $html .= '>'.$reporter->real_name.'</option>';
169        }
170        return $html . '</select>';
171    }
172
173    /**
174     * Get the html for categories
175     *
176     * @return string
177     */
178    private function getCategoriesHtml() {
179        $html = "<select name='category'>";
180        $categories = $this->getCategories();
181        if(0 === count($categories)) {
182            return 'Geen categorie&euml;n gevonden';
183        }
184        foreach($categories as $category) {
185            $html .= '<option value="'.$category.'">'.$category.'</option>';
186        }
187        return $html . '</select>';
188    }
189
190    /**
191     * Get the html
192     *
193     * @return string
194     */
195    private function getHtml() {
196        $priorities = $this->getPrioritiesHtml();
197        $reporters = $this->getReportersHtml();
198        $categories = $this->getCategoriesHtml();
199        $prognose = $this->getPrognoseHtml();
200        $projectId = $this->getProjectId();
201        $str = <<<EOD
202<form method='POST'>
203<input type='hidden' name='projectId' value='$projectId' />
204    <table class='mantisreporter'>
205        <tr>
206            <td>reporter</td>
207            <td>categorie</td>
208            <td>prioriteit</td>
209        </tr>
210        <tr>
211            <td>
212                $reporters
213            </td>
214            <td>
215                $categories
216            </td>
217            <td>
218                $priorities
219            </td>
220        </tr>
221        <tr>
222            <td colspan='5'>samenvatting</td>
223        </tr>
224        <tr>
225            <td colspan='5'>
226                <input type='text' name='summary' class='summary' required />
227            </td>
228        </tr>
229        <tr>
230            <td colspan='5'>omschrijving</td>
231        </tr>
232        <tr>
233            <td colspan='5'>
234                <textarea name='description' required></textarea>
235            </td>
236        </tr>
237        <tr>
238            <td colspan='5' class='submit'>
239                $prognose &nbsp;&nbsp;&nbsp; <input type='submit' value='ticket aanmaken' />
240            </td>
241        </tr>
242    </table>
243</form>
244EOD;
245        return $str;
246    }
247
248    /**
249     * Get all priorities
250     *
251     * @return string
252     */
253    private function getPriorities() {
254        return $this->callSoapClient('mc_enum_priorities');
255    }
256
257    /**
258     * Get all possible reporters for this project
259     * access 25 means reporters and higher
260     *
261     * @return string
262     */
263    private function getReporters() {
264        $reporters = $this->callSoapClient('mc_project_get_users', array('project_id' => (int) $this->getProjectId(), 'access' => 25));
265        foreach($reporters as $key => $reporter) {
266            if($reporter->name === 'SoapUser') {
267                unset($reporters[$key]);
268            }
269        }
270        return $reporters;
271    }
272
273    /**
274     * Get all possible reporters for this project
275     *
276     * @return string
277     */
278    private function getCategories() {
279        return $this->callSoapClient('mc_project_get_categories', array('project_id' => (int) $this->getProjectId()));
280    }
281
282    /**
283     * Get all possible custom fields for this project
284     *
285     * @return string
286     */
287    private function getCustomFields($projectId = null) {
288        if($projectId === null) {
289            $projectId = $this->getProjectId();
290        }
291        return $this->callSoapClient('mc_project_get_custom_fields', array('project_id' => (int) $projectId));
292    }
293
294    /**
295     * Get html for prognose (if available for this project).
296     *
297     * @return string
298     */
299    private function getPrognoseHtml() {
300        foreach($this->getCustomFields() as $customField) {
301            if('prognose' === $customField->field->name) {
302                return 'prognose <input type="text" min="0" name="prognose" class="prognose-input" required /> uur';
303            }
304        }
305        return '';
306    }
307
308    private function getPrognoseId($projectId) {
309        foreach($this->getCustomFields($projectId) as $customField) {
310            if('prognose' === $customField->field->name) {
311                return $customField->field->id;
312            }
313        }
314        return '';
315    }
316
317    /**
318     * Get the soap client
319     *
320     * @return SoapClient
321     */
322    private function getSoapClient() {
323        if($this->soapClient === null) {
324            ini_set('default_socket_timeout', 5);
325            $this->soapClient = new SoapClient($this->getMantisUrl() . '/api/soap/mantisconnect.php?wsdl', array("connection_timeout"=>5));
326        }
327
328        return $this->soapClient;
329    }
330
331    /**
332     * Send a request to the soap client
333     *
334     * @param string $function what function should be called?
335     * @param array $array extra parameters
336     *
337     * @return mixed result from the request.
338     */
339    private function callSoapClient($function, $array = array()) {
340        $sc = $this->getSoapClient();
341        $parameters = array('username' => $this->getConf('soap_user'), 'password' => $this->getConf('soap_password'));
342        foreach($array as $key => $value) {
343            $parameters[$key] = $value;
344        }
345        $returnValue = $sc->__call($function, $parameters, array());
346        return $returnValue;
347    }
348
349    /**
350     * Save issue
351     *
352     * @return string HTML with a link to the issue.
353     */
354    private function saveIssue() {
355        if(isset($_POST['reporter'])) {
356            $newIssue = new stdClass();
357
358            $newIssue->reporter = new stdClass();
359            $newIssue->reporter->id = (int) $_POST['reporter'];
360
361            $newIssue->priority = new stdClass();
362            $newIssue->priority->id = (int) $_POST['priority'];
363
364            $newIssue->project = new stdClass();
365            $newIssue->project->id = (int) $_POST['projectId'];
366
367            $newIssue->category = $_POST['category'];
368            $newIssue->summary = $_POST['summary'];
369            $newIssue->description = $_POST['description'];
370
371            if($_POST['prognose']) {
372                $prognose = new stdClass();
373                $prognose->field = new stdClass();
374                $prognose->field->id = $this->getPrognoseId($_POST['projectId']);
375                $prognose->field->name = 'prognose';
376
377                $prognose->value = (float) $_POST['prognose'];
378                $newIssue->custom_fields = array(
379                        $prognose
380                    );
381            }
382            $newIssueId = $this->callSoapClient('mc_issue_add', array('issue' => $newIssue));
383            unset($_POST['reporter']);
384            return 'Nieuw issue aangemaakt: <a href="'.$this->getMantisUrl().'/view.php?id=' . $newIssueId . '">' . $newIssueId . '</a><br><br>';
385        }
386    }
387
388    /**
389     * Get the mantis Url
390     *
391     * @return string
392     */
393    private function getMantisUrl() {
394        return $this->getConf('soap_url');
395    }
396
397
398
399
400
401
402 // configuration methods
403  /**
404   * getConf($setting)
405   *
406   * use this function to access plugin configuration variables
407   */
408  function getConf($setting){
409
410    if (!$this->configloaded){ $this->loadConfig(); }
411
412    return $this->conf[$setting];
413  }
414
415  /**
416   * loadConfig()
417   * merges the plugin's default settings with any local settings
418   * this function is automatically called through getConf()
419   */
420  function loadConfig(){
421    global $conf;
422
423    $defaults = $this->readDefaultSettings();
424    $plugin = $this->getPluginName();
425
426    foreach ($defaults as $key => $value) {
427      if (isset($conf['plugin'][$plugin][$key])) continue;
428      $conf['plugin'][$plugin][$key] = $value;
429    }
430
431    $this->configloaded = true;
432    $this->conf =& $conf['plugin'][$plugin];
433  }
434
435  /**
436   * read the plugin's default configuration settings from conf/default.php
437   * this function is automatically called through getConf()
438   *
439   * @return    array    setting => value
440   */
441  function readDefaultSettings() {
442
443    $path = DOKU_PLUGIN.$this->getPluginName().'/conf/';
444    $conf = array();
445
446    if (@file_exists($path.'default.php')) {
447      include($path.'default.php');
448    }
449
450    return $conf;
451  }
452
453}