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)) { |
|
|
|
|
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'], |
|
|
|
|
75
|
|
|
'body' => $this->_augmentDescription( |
76
|
|
|
$this->request->data['description'], $reportId), |
|
|
|
|
77
|
|
|
'labels' => $this->request->data['labels'] ? explode(',', $this->request->data['labels']) : array(), |
|
|
|
|
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']); |
|
|
|
|
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; |
|
|
|
|
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; |
|
|
|
|
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
|
|
|
|
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.