Completed
Pull Request — master (#114)
by Deven
15:41
created

GithubController   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 317
Duplicated Lines 11.67 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 0%

Importance

Changes 2
Bugs 1 Features 0
Metric Value
wmc 29
c 2
b 1
f 0
lcom 1
cbo 8
dl 37
loc 317
ccs 0
cts 185
cp 0
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A beforeFilter() 0 5 1
B create_issue() 11 38 6
B link_issue() 6 47 6
B unlink_issue() 6 40 5
A _getErrors() 0 10 1
A _augmentDescription() 7 7 1
B _handleGithubResponse() 7 56 9

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/* vim: set noexpandtab sw=2 ts=2 sts=2: */
3
namespace App\Controller;
4
5
use App\Controller\AppController;
6
use Cake\Core\Configure;
7
use Cake\Log\Log;
8
use Cake\Routing\Router;
9
use Cake\Event\Event;
10
use Cake\ORM\TableRegistry;
11
use Cake\Network\Exception\NotFoundException;
12
/**
13
 * Sourceforge controller handling source forge ticket submission and creation
14
 *
15
 * phpMyAdmin Error reporting server
16
 * Copyright (c) phpMyAdmin project (http://www.phpmyadmin.net)
17
 *
18
 * Licensed under The MIT License
19
 * For full copyright and license information, please see the LICENSE.txt
20
 * Redistributions of files must retain the above copyright notice.
21
 *
22
 * @copyright     Copyright (c) phpMyAdmin project (http://www.phpmyadmin.net)
23
 * @package       Server.Controller
24
 * @link          http://www.phpmyadmin.net
25
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
26
 */
27
28
/**
29
 * Github controller handling github issue submission and creation
30
 *
31
 * @package       Server.Controller
32
 */
33
class GithubController extends AppController {
34
35
	public $helpers = array('Html', 'Form');
36
37
	public $components = array('GithubApi');
38
39
	public $uses = array('Report');
40
41
	public function beforeFilter(Event $event) {
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 Integer $reportId
51
     * @throws \NotFoundException
52
     * @throws NotFoundException
53
     */
54
	public function create_issue($reportId) {
55
		if (!$reportId) {
56
				throw new \NotFoundException(__('Invalid report'));
57
		}
58
59
		$report = TableRegistry::get('Reports')->findById($reportId)->toArray();
0 ignored issues
show
Documentation Bug introduced by
The method findById does not exist on object<Cake\ORM\Table>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
60
		if (!$report) {
61
				throw new NotFoundException(__('Invalid report'));
62
		}
63
64 View Code Duplication
		if (empty($this->request->data)) {
65
			$this->set('pma_version', $report[0]['pma_version']);
66
            $this->set('error_name', $report[0]['error_name']);
67
            $this->set('error_message', $report[0]['error_message']);
68
			return;
69
		}
70
        $data = array(
71
			'title' => $this->request->data['summary'],
72
            'body'  => $this->_augmentDescription(
73
					$this->request->data['description'], $reportId),
74
            'labels' => $this->request->data['labels']?split(",", $this->request->data['labels']):Array()
75
		);
76
        $data['labels'][] = 'automated-error-report';
77
        list($issueDetails, $status) = $this->GithubApi->createIssue(
78
            Configure::read('GithubRepoPath'),
79
            $data,
80
            $this->request->session()->read("access_token")
81
        );
82
83
		if ($this->_handleGithubResponse($status, 1, $reportId, $issueDetails['number'])) {
84
			$this->redirect(array('controller' => 'reports', 'action' => 'view',
85
					$reportId));
86 View Code Duplication
        } else {
87
			$flash_class = "alert alert-error";
88
            $this->Flash->default(_getErrors($issueDetails, $status),
0 ignored issues
show
Documentation Bug introduced by
The method default does not exist on object<Cake\Controller\Component\FlashComponent>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
89
					array("params" => array("class" => $flash_class)));
90
        }
91
	}
92
93
	/**
94
	 * Links error report to existing issue on Github
95
	 *
96
	 */
97
	public function link_issue($reportId) {
98
		if (!$reportId) {
99
				throw new NotFoundException(__('Invalid reportId'));
100
		}
101
102
		$report = TableRegistry::get('Reports')->findById($reportId)->all()->first();
0 ignored issues
show
Documentation Bug introduced by
The method findById does not exist on object<Cake\ORM\Table>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
103
		if (!$report) {
104
				throw new NotFoundException(__('Invalid Report'));
105
		}
106
107
		$ticket_id = $this->request->query['ticket_id'];
108
		if(!$ticket_id) {
109
				throw new NotFoundException(__('Invalid Ticket ID!!'));
110
		}
111
112
		$incident = TableRegistry::get('Incidents')->findByReportId($reportId)->all()->first();
0 ignored issues
show
Documentation Bug introduced by
The method findByReportId does not exist on object<Cake\ORM\Table>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
113
		$exception_type = ($incident['exception_type']) ? ('php') : ('js');
114
115
		// "formatted" text of the comment.
116
		$commentText = "Param | Value "
117
			. "\n -----------|--------------------"
118
			. "\n Error Type | " . $report['error_name']
119
			. "\n Error Message |" . $report['error_message']
120
			. "\n Exception Type |" . $exception_type
121
			. "\n Link | [Report#"
122
				. $reportId
123
				."]("
124
				. Router::url('/reports/view/'.$reportId,true)
125
				.")"
126
			. "\n\n*This comment is posted automatically by phpMyAdmin's "
127
			. "[error-reporting-server](http://reports.phpmyadmin.net).*";
128
129
        list($commentDetails, $status) = $this->GithubApi->createComment(
130
            Configure::read('GithubRepoPath'),
131
            array('body' => $commentText),
132
            $ticket_id,
133
            $this->request->session()->read("access_token")
134
        );
135 View Code Duplication
		if (!$this->_handleGithubResponse($status, 2, $reportId, $ticket_id))
136
        {
137
			$flash_class = "alert alert-error";
138
			$this->Flash->default(_getErrors($commentDetails, $status),
0 ignored issues
show
Documentation Bug introduced by
The method default does not exist on object<Cake\Controller\Component\FlashComponent>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
139
					array("params" => array("class" => $flash_class)));
140
        }
141
		$this->redirect(array('controller' => 'reports', 'action' => 'view',
142
						$reportId));
143
	}
144
145
	/**
146
	 * Un-links error report to associated issue on Github
147
	 *
148
	 */
149
	public function unlink_issue($reportId) {
150
		if (!$reportId) {
151
				throw new NotFoundException(__('Invalid reportId'));
152
		}
153
154
		$report = TableRegistry::get('Reports')->findById($reportId)->all()->first();
0 ignored issues
show
Documentation Bug introduced by
The method findById does not exist on object<Cake\ORM\Table>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
155
		if (!$report) {
156
				throw new NotFoundException(__('Invalid Report'));
157
		}
158
159
		$ticket_id = $report['sourceforge_bug_id'];
160
		if(!$ticket_id) {
161
				throw new NotFoundException(__('Invalid Ticket ID!!'));
162
		}
163
164
		// "formatted" text of the comment.
165
		$commentText = "This Issue is no longer associated with [Report#"
166
			. $reportId
167
			. "]("
168
			. Router::url('/reports/view/'.$reportId,true)
169
			. ")"
170
			. "\n\n*This comment is posted automatically by phpMyAdmin's "
171
			. "[error-reporting-server](http://reports.phpmyadmin.net).*";
172
173
        list($commentDetails, $status) = $this->GithubApi->createComment(
174
            Configure::read('GithubRepoPath'),
175
            array('body' => $commentText),
176
            $ticket_id,
177
            $this->request->session()->read("access_token")
178
        );
179
180 View Code Duplication
		if (!$this->_handleGithubResponse($status, 3, $reportId))
181
        {
182
			$flash_class = "alert alert-error";
183
			$this->Flash->default(_getErrors($commentDetails, $status),
0 ignored issues
show
Documentation Bug introduced by
The method default does not exist on object<Cake\Controller\Component\FlashComponent>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
184
					array("params" => array("class" => $flash_class)));
185
        }
186
        $this->redirect(array('controller' => 'reports', 'action' => 'view',
187
						$reportId));
188
	}
189
190
    /**
191
     * Returns pretty error message string
192
     *
193
     * @param Object $response the response returned by Github api
194
     * @param Integer $status status returned by Github API
195
     *
196
     * @return error string
197
     */
198
	protected function _getErrors($response, $status) {
199
		$errorString = "There were some problems with the issue submission."
200
				." Returned status is (" . $status . ")";
201
		$errorString .= "<br/> Here is the dump for the errors field provided by"
202
			. " github: <br/>"
203
			. "<pre>"
204
			. print_r($response, true)
205
			. "</pre>";
206
		return $errorString;
207
	}
208
209
/**
210
 * Returns the description with the added string to link to the report
211
 * @param String $description the original description submitted by the dev
212
 * @param String $reportId the report id relating to the ticket
213
 *
214
 * @return String augmented description
215
 */
216 View Code Duplication
	protected function _augmentDescription($description, $reportId) {
217
        $report = TableRegistry::get('Reports');
218
		$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...
219
		return "$description\n\n\nThis report is related to user submitted report "
220
				. "[#" . $report->id . "](" . $report->getUrl()
0 ignored issues
show
Documentation Bug introduced by
The method getUrl does not exist on object<Cake\ORM\Table>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
221
				. ") on the phpmyadmin error reporting server.";
222
	}
223
224
/**
225
 * Github Response Handler
226
 * @param Integer $response the status returned by Github API
227
 * @param Integer $type type of response.
228
 *			1 for create_issue,
229
 *			2 for link_issue,
230
 *			3 for unlink_issue,
231
 * @param Integer $report_id report id.
232
 * @param Integer $ticket_id ticket id, required for link tivket only.
233
 *
234
 * @return Boolean value. True on success. False on any type of failure.
235
 */
236
	protected function _handleGithubResponse($response, $type, $report_id,  $ticket_id = 1)
237
	{
238
		if (!in_array($type, array(1,2,3))) {
239
			throw new InvalidArgumentException('Invalid Argument "$type".');
240
		}
241
242
		if ($response == 201) {
243
            echo $response;
244
			// success
245
			switch ($type) {
246
				case 1:
247
					$msg = 'Github issue has been created for this report.';
248
					break;
249
				case 2:
250
					$msg = 'Github issue has been linked with this report.';
251
					break;
252
				case 3:
253
					$msg = 'Github issue has been unlinked with this report.';
254
					$ticket_id = null;
255
					break;
256
				default:
257
					$msg = 'Something went wrong!!';
258
					break;
259
			}
260
            $report = TableRegistry::get('Reports')->get($report_id);
261
            $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...
262
			TableRegistry::get('Reports')->save($report);
263
	        $flash_class = "alert alert-success";
264
			$this->Flash->default($msg,
0 ignored issues
show
Documentation Bug introduced by
The method default does not exist on object<Cake\Controller\Component\FlashComponent>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
265
				array("params" => array("class" => $flash_class)));
266
			return true;
267
		} else if ($response === 403) {
268
			$flash_class = "alert alert-error";
269
			$this->Flash->default(
0 ignored issues
show
Documentation Bug introduced by
The method default does not exist on object<Cake\Controller\Component\FlashComponent>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
270
					"Unauthorised access to Github. github"
271
					. " credentials may be out of date. Please check and try again"
272
					. " later.",
273
					array("params" => array("class" => $flash_class)));
274
			return false;
275
		} else if ($response === 404
276
			&& $type == 2
277
		) {
278
			$flash_class = "alert alert-error";
279
			$this->Flash->default(
0 ignored issues
show
Documentation Bug introduced by
The method default does not exist on object<Cake\Controller\Component\FlashComponent>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
280
					"Bug Issue not found on Github."
281
					. " Are you sure the issue number is correct?!! Please check and try again",
282
					 array("params" => array("class" => $flash_class)));
283
			return false;
284 View Code Duplication
		} else {
285
			//fail
286
			$flash_class = "alert alert-error";
287
			$this->Flash->default(json_encode($response),
0 ignored issues
show
Documentation Bug introduced by
The method default does not exist on object<Cake\Controller\Component\FlashComponent>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
288
					array("params" => array("class" => $flash_class)));
289
			return false;
290
		}
291
	}
292
293
	/**
294
	 * Synchronize Report Statuses from Github issue
295
	 * To be used as a cron job.
296
	 * Can not (& should not) be directly accessed via Web.
297
     * TODO
298
	 */
299
	/* public function sync_issue_statuses(){
300
		if (!defined('CRON_DISPATCHER')) {
301
			$this->redirect('/');
302
			exit();
303
		}
304
305
		$reports = TableRegistry::get('Reports')->find(
306
			'all',
307
			array(
308
				'conditions' => array(
309
					'NOT' => array(
310
						'Report.sourceforge_bug_id' => null
311
					)
312
				)
313
			)
314
		);
315
316
		foreach ($reports as $key => $report) {
317
			$i=0;
318
			// fetch the new ticket status
319
			do {
320
				$new_status = $this->SourceForgeApi->getBugTicketStatus(
321
					Configure::read('SourceForgeProjectName'),
322
					$report['sourceforge_bug_id']
323
				);
324
				$i++;
325
			} while($new_status == false && $i <= 3);
326
327
			// if fails all three times, then simply write failure
328
			// into cron_jobs log and move on.
329
			if (!$new_status) {
330
				Log::write(
331
					'cron_jobs',
332
					'FAILED: Fetching status of BugTicket#'
333
						. ($report['sourceforge_bug_id'])
334
						. ' associated with Report#'
335
						. ($report['id']),
336
					'cron_jobs'
337
				);
338
				continue;
339
			}
340
341
			if ($report['status'] != $new_status) {
342
                $rep = TableRegistry::get('Reports')->get($report['id']);
343
                $rep->status = $new_status;
344
				TableRegistry::get('Reports')->save($rep);
345
			}
346
		}
347
		$this->autoRender = false;
348
	} */
349
}
350