Completed
Push — master ( 46bda9...e6f651 )
by Michal
9s
created

GithubController::_getErrors()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
ccs 0
cts 11
cp 0
cc 1
eloc 9
nc 1
nop 2
crap 2
1
<?php
2
3
/* vim: set expandtab sw=4 ts=4 sts=4: */
4
/**
5
 * Sourceforge controller handling source forge ticket submission and creation.
6
 *
7
 * phpMyAdmin Error reporting server
8
 * Copyright (c) phpMyAdmin project (https://www.phpmyadmin.net/)
9
 *
10
 * Licensed under The MIT License
11
 * For full copyright and license information, please see the LICENSE.txt
12
 * Redistributions of files must retain the above copyright notice.
13
 *
14
 * @copyright Copyright (c) phpMyAdmin project (https://www.phpmyadmin.net/)
15
 * @license   https://opensource.org/licenses/mit-license.php MIT License
16
 *
17
 * @see      https://www.phpmyadmin.net/
18
 */
19
20
namespace App\Controller;
21
22
use Cake\Core\Configure;
23
use Cake\Event\Event;
24
use Cake\Log\Log;
25
use Cake\Network\Exception\NotFoundException;
26
use Cake\ORM\TableRegistry;
27
use Cake\Routing\Router;
28
29
/**
30
 * Github controller handling github issue submission and creation.
31
 */
32
class GithubController extends AppController
33
{
34
    public $helpers = array('Html', 'Form');
35
36
    public $components = array('GithubApi');
37
38
    public $uses = array('Report');
39
40
    public function beforeFilter(Event $event)
41
    {
42
        parent::beforeFilter($event);
43
        $this->GithubApi->githubConfig = Configure::read('GithubConfig');
44
        $this->GithubApi->githubRepo = Configure::read('GithubRepoPath');
45
    }
46
47
    /**
48
     * create Github Issue.
49
     *
50
     * @param int $reportId
51
     *
52
     * @throws \NotFoundException
53
     * @throws NotFoundException
54
     */
55
    public function create_issue($reportId)
56
    {
57
        if (!$reportId) {
58
            throw new \NotFoundException(__('Invalid report'));
59
        }
60
61
        $report = TableRegistry::get('Reports')->findById($reportId)->toArray();
62
        if (!$report) {
63
            throw new NotFoundException(__('Invalid report'));
64
        }
65
66 View Code Duplication
        if (empty($this->request->data)) {
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$data has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getData() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
67
            $this->set('pma_version', $report[0]['pma_version']);
68
            $this->set('error_name', $report[0]['error_name']);
69
            $this->set('error_message', $report[0]['error_message']);
70
71
            return;
72
        }
73
        $data = array(
74
            'title' => $this->request->data['summary'],
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$data has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getData() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
75
            'body' => $this->_augmentDescription(
76
                    $this->request->data['description'], $reportId),
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$data has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getData() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
77
            'labels' => $this->request->data['labels'] ? explode(',', $this->request->data['labels']) : array(),
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$data has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getData() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
78
        );
79
        $data['labels'][] = 'automated-error-report';
80
        list($issueDetails, $status) = $this->GithubApi->createIssue(
81
            Configure::read('GithubRepoPath'),
82
            $data,
83
            $this->request->session()->read('access_token')
84
        );
85
86
        if ($this->_handleGithubResponse($status, 1, $reportId, $issueDetails['number'])) {
87
            $this->redirect(array('controller' => 'reports', 'action' => 'view',
88
                $reportId, ));
89
        } else {
90
            $flash_class = 'alert alert-error';
91
            $this->Flash->default(_getErrors($issueDetails, $status),
92
                array('params' => array('class' => $flash_class)));
93
        }
94
    }
95
96
    /**
97
     * Links error report to existing issue on Github.
98
     *
99
     * @param mixed $reportId
100
     */
101
    public function link_issue($reportId)
102
    {
103
        if (!$reportId) {
104
            throw new NotFoundException(__('Invalid reportId'));
105
        }
106
107
        $report = TableRegistry::get('Reports')->findById($reportId)->all()->first();
108
        if (!$report) {
109
            throw new NotFoundException(__('Invalid Report'));
110
        }
111
112
        $ticket_id = intval($this->request->query['ticket_id']);
0 ignored issues
show
Deprecated Code introduced by
The property Cake\Http\ServerRequest::$query has been deprecated with message: 3.4.0 This public property will be removed in 4.0.0. Use getQuery() or getQueryParams() instead.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
113
        if (!$ticket_id) {
114
            throw new NotFoundException(__('Invalid Ticket ID!!'));
115
        }
116
117
        $incident = TableRegistry::get('Incidents')->findByReportId($reportId)->all()->first();
118
        $exception_type = ($incident['exception_type']) ? ('php') : ('js');
119
120
        // "formatted" text of the comment.
121
        $commentText = 'Param | Value '
122
            . "\n -----------|--------------------"
123
            . "\n Error Type | " . $report['error_name']
124
            . "\n Error Message |" . $report['error_message']
125
            . "\n Exception Type |" . $exception_type
126
            . "\n Link | [Report#"
127
                . $reportId
128
                . ']('
129
                . Router::url('/reports/view/' . $reportId, true)
130
                . ')'
131
            . "\n\n*This comment is posted automatically by phpMyAdmin's "
132
            . '[error-reporting-server](https://reports.phpmyadmin.net).*';
133
134
        list($commentDetails, $status) = $this->GithubApi->createComment(
135
            Configure::read('GithubRepoPath'),
136
            array('body' => $commentText),
137
            $ticket_id,
138
            $this->request->session()->read('access_token')
139
        );
140 View Code Duplication
        if (!$this->_handleGithubResponse($status, 2, $reportId, $ticket_id)) {
141
            $flash_class = 'alert alert-error';
142
            $this->Flash->default(_getErrors($commentDetails, $status),
143
                    array('params' => array('class' => $flash_class)));
144
        }
145
146
        $this->redirect(array('controller' => 'reports', 'action' => 'view',
147
                        $reportId, ));
148
    }
149
150
    /**
151
     * Un-links error report to associated issue on Github.
152
     *
153
     * @param mixed $reportId
154
     */
155
    public function unlink_issue($reportId)
156
    {
157
        if (!$reportId) {
158
            throw new NotFoundException(__('Invalid reportId'));
159
        }
160
161
        $report = TableRegistry::get('Reports')->findById($reportId)->all()->first();
162
        if (!$report) {
163
            throw new NotFoundException(__('Invalid Report'));
164
        }
165
166
        $ticket_id = $report['sourceforge_bug_id'];
167
        if (!$ticket_id) {
168
            throw new NotFoundException(__('Invalid Ticket ID!!'));
169
        }
170
171
        // "formatted" text of the comment.
172
        $commentText = 'This Issue is no longer associated with [Report#'
173
            . $reportId
174
            . ']('
175
            . Router::url('/reports/view/' . $reportId, true)
176
            . ')'
177
            . "\n\n*This comment is posted automatically by phpMyAdmin's "
178
            . '[error-reporting-server](https://reports.phpmyadmin.net).*';
179
180
        list($commentDetails, $status) = $this->GithubApi->createComment(
181
            Configure::read('GithubRepoPath'),
182
            array('body' => $commentText),
183
            $ticket_id,
184
            $this->request->session()->read('access_token')
185
        );
186
187 View Code Duplication
        if (!$this->_handleGithubResponse($status, 3, $reportId)) {
188
            $flash_class = 'alert alert-error';
189
            $this->Flash->default(_getErrors($commentDetails, $status),
190
                    array('params' => array('class' => $flash_class)));
191
        }
192
193
        $this->redirect(array('controller' => 'reports', 'action' => 'view',
194
                        $reportId, ));
195
    }
196
197
    /**
198
     * Returns pretty error message string.
199
     *
200
     * @param object $response the response returned by Github api
201
     * @param int    $status   status returned by Github API
202
     *
203
     * @return error string
204
     */
205
    protected function _getErrors($response, $status)
206
    {
207
        $errorString = 'There were some problems with the issue submission.'
208
            . ' Returned status is (' . $status . ')';
209
        $errorString .= '<br/> Here is the dump for the errors field provided by'
210
            . ' github: <br/>'
211
            . '<pre>'
212
            . print_r($response, true)
213
            . '</pre>';
214
215
        return $errorString;
216
    }
217
218
    /**
219
     * Returns the description with the added string to link to the report.
220
     *
221
     * @param string $description the original description submitted by the dev
222
     * @param string $reportId    the report id relating to the ticket
223
     *
224
     * @return string augmented description
225
     */
226 View Code Duplication
    protected function _augmentDescription($description, $reportId)
227
    {
228
        $report = TableRegistry::get('Reports');
229
        $report->id = $reportId;
0 ignored issues
show
Bug introduced by
The property id does not seem to exist in Cake\ORM\Table.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
230
231
        return "$description\n\n\nThis report is related to user submitted report "
232
            . '[#' . $report->id . '](' . $report->getUrl()
233
            . ') on the phpmyadmin error reporting server.';
234
    }
235
236
    /**
237
     * Github Response Handler.
238
     *
239
     * @param int $response  the status returned by Github API
240
     * @param int $type      type of response. 1 for create_issue, 2 for link_issue, 3 for unlink_issue,
241
     *                       1 for create_issue,
242
     *                       2 for link_issue,
243
     *                       3 for unlink_issue,
244
     * @param int $report_id report id
245
     * @param int $ticket_id ticket id, required for link tivket only
246
     *
247
     * @return bool value. True on success. False on any type of failure.
248
     */
249
    protected function _handleGithubResponse($response, $type, $report_id, $ticket_id = 1)
250
    {
251
        if (!in_array($type, array(1, 2, 3))) {
252
            throw new InvalidArgumentException('Invalid Argument "$type".');
253
        }
254
255
        if ($response == 201) {
256
            echo $response;
257
            // success
258
            switch ($type) {
259
                case 1:
260
                    $msg = 'Github issue has been created for this report.';
261
                    break;
262
                case 2:
263
                    $msg = 'Github issue has been linked with this report.';
264
                    break;
265
                case 3:
266
                    $msg = 'Github issue has been unlinked with this report.';
267
                    $ticket_id = null;
268
                    break;
269
                default:
270
                    $msg = 'Something went wrong!!';
271
                    break;
272
            }
273
            $report = TableRegistry::get('Reports')->get($report_id);
274
            $report->sourceforge_bug_id = $ticket_id;
0 ignored issues
show
Bug introduced by
Accessing sourceforge_bug_id on the interface Cake\Datasource\EntityInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
275
            TableRegistry::get('Reports')->save($report);
276
            $flash_class = 'alert alert-success';
277
            $this->Flash->default($msg,
278
                array('params' => array('class' => $flash_class)));
279
280
            return true;
281
        } elseif ($response === 403) {
282
            $flash_class = 'alert alert-error';
283
            $this->Flash->default(
284
                    'Unauthorised access to Github. github'
285
                    . ' credentials may be out of date. Please check and try again'
286
                    . ' later.',
287
                    array('params' => array('class' => $flash_class)));
288
289
            return false;
290
        } elseif ($response === 404
291
            && $type == 2
292
        ) {
293
            $flash_class = 'alert alert-error';
294
            $this->Flash->default(
295
                    'Bug Issue not found on Github.'
296
                    . ' Are you sure the issue number is correct?!! Please check and try again',
297
                     array('params' => array('class' => $flash_class)));
298
299
            return false;
300
        }
301
            //fail
302
            $flash_class = 'alert alert-error';
303
        $this->Flash->default(json_encode($response),
304
                    array('params' => array('class' => $flash_class)));
305
306
        return false;
307
    }
308
309
    /*
310
     * Synchronize Report Statuses from Github issue
311
     * To be used as a cron job.
312
     * Can not (& should not) be directly accessed via Web.
313
     * TODO
314
     */
315
    /* public function sync_issue_statuses(){
316
        if (!defined('CRON_DISPATCHER')) {
317
            $this->redirect('/');
318
            exit();
319
        }
320
321
        $reports = TableRegistry::get('Reports')->find(
322
            'all',
323
            array(
324
                'conditions' => array(
325
                    'NOT' => array(
326
                        'Report.sourceforge_bug_id' => null
327
                    )
328
                )
329
            )
330
        );
331
332
        foreach ($reports as $key => $report) {
333
            $i=0;
334
            // fetch the new ticket status
335
            do {
336
                $new_status = $this->SourceForgeApi->getBugTicketStatus(
337
                    Configure::read('SourceForgeProjectName'),
338
                    $report['sourceforge_bug_id']
339
                );
340
                $i++;
341
            } while($new_status == false && $i <= 3);
342
343
            // if fails all three times, then simply write failure
344
            // into cron_jobs log and move on.
345
            if (!$new_status) {
346
                Log::write(
347
                    'cron_jobs',
348
                    'FAILED: Fetching status of BugTicket#'
349
                        . ($report['sourceforge_bug_id'])
350
                        . ' associated with Report#'
351
                        . ($report['id']),
352
                    'cron_jobs'
353
                );
354
                continue;
355
            }
356
357
            if ($report['status'] != $new_status) {
358
                $rep = TableRegistry::get('Reports')->get($report['id']);
359
                $rep->status = $new_status;
360
                TableRegistry::get('Reports')->save($rep);
361
            }
362
        }
363
        $this->autoRender = false;
364
    } */
365
}
366