Completed
Push — master ( 7c757d...667317 )
by William
02:47
created

ReportsController::change_state()   A

Complexity

Conditions 5
Paths 6

Size

Total Lines 30

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 5.025

Importance

Changes 0
Metric Value
dl 0
loc 30
ccs 18
cts 20
cp 0.9
rs 9.1288
c 0
b 0
f 0
cc 5
nc 6
nop 1
crap 5.025
1
<?php
2
/* vim: set expandtab sw=4 ts=4 sts=4: */
3
4
/**
5
 * Reports controller handling reports creation and rendering.
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 App\Utility\Sanitize;
23
use Cake\Core\Configure;
24
use Cake\Log\Log;
25
use Cake\Http\Exception\NotFoundException;
26
use Cake\ORM\TableRegistry;
27
28
/**
29
 * Reports controller handling reports modification and rendering.
30
 */
31
class ReportsController extends AppController
32
{
33
    public $components = [
34
        'RequestHandler',
35
        'OrderSearch',
36
    ];
37
38
    public $helpers = [
39
        'Html',
40
        'Form',
41
        'Reports',
42
        'Incidents',
43
    ];
44
    public $uses = [
45
        'Incidents',
46
        'Reports',
47
        'Notifications',
48
        'Developers',
49
    ];
50
51 1
    public function index()
52
    {
53 1
        $this->Reports->recursive = -1;
54 1
        $this->set(
55 1
            'distinct_statuses',
56 1
            $this->_findArrayList(
57 1
                $this->Reports->find()->select(['status'])->distinct(['status']),
58 1
                'status'
59
            )
60
        );
61 1
        $this->set(
62 1
            'distinct_locations',
63 1
            $this->_findArrayList(
64 1
                $this->Reports->find()->select(['location'])
65 1
                    ->distinct(['location']),
66 1
                'location'
67
            )
68
        );
69 1
        $this->set(
70 1
            'distinct_versions',
71 1
            $this->_findArrayList($this->Reports->find()->select(['pma_version'])->distinct(['pma_version']), 'pma_version')
72
        );
73 1
        $this->set(
74 1
            'distinct_error_names',
75 1
            $this->_findArrayList($this->Reports->find('all', [
76 1
                'fields' => ['error_name'],
77
                'conditions' => ['error_name !=' => ''],
78 1
            ])->distinct(['error_name']), 'error_name')
79
        );
80 1
        $this->set('statuses', $this->Reports->status);
81 1
        $this->autoRender = true;
82 1
    }
83
84 1
    public function view($reportId)
85
    {
86 1
        if (! isset($reportId) || ! $reportId) {
87
            throw new NotFoundException(__('Invalid Report'));
88
        }
89 1
        $report = $this->Reports->findById($reportId)->toArray();
90 1
        if (! $report) {
91 1
            throw new NotFoundException(__('Invalid Report'));
92
        }
93
94 1
        $this->set('report', $report);
95 1
        $this->set('project_name', Configure::read('GithubRepoPath'));
96 1
        $this->Reports->id = $reportId;
97 1
        $this->set('incidents', $this->Reports->getIncidents()->toArray());
98 1
        $this->set(
99 1
            'incidents_with_description',
100 1
            $this->Reports->getIncidentsWithDescription()
101
        );
102 1
        $this->set(
103 1
            'incidents_with_stacktrace',
104 1
            $this->Reports->getIncidentsWithDifferentStacktrace()
105
        );
106 1
        $this->set('related_reports', $this->Reports->getRelatedReports());
107 1
        $this->set('status', $this->Reports->status);
108 1
        $this->_setSimilarFields($reportId);
109
110
        // if there is an unread notification for this report, then mark it as read
111 1
        $current_developer = TableRegistry::get('Developers')->
112 1
                    findById($this->request->session()->read('Developer.id'))->all()->first();
113
114 1
        if ($current_developer) {
115 1
            TableRegistry::get('Notifications')->deleteAll(
116
                [
117 1
                    'developer_id' => $current_developer['Developer']['id'],
118 1
                    'report_id' => $reportId,
119
                ],
120 1
                false
121
            );
122
        }
123 1
    }
124
125 1
    public function data_tables()
126
    {
127
        $subquery_params = [
128 1
            'fields' => [
129
                'report_id' => 'report_id',
130
                'inci_count' => 'COUNT(id)',
131
            ],
132
            'group' => 'report_id',
133
        ];
134 1
        $subquery = TableRegistry::get('incidents')->find('all', $subquery_params);
135
136
        // override automatic aliasing, for proper usage in joins
137
        $aColumns = [
138 1
            'id' => 'id',
139
            'error_name' => 'error_name',
140
            'error_message' => 'error_message',
141
            'location' => 'location',
142
            'pma_version' => 'pma_version',
143
            'status' => 'status',
144
            'exception_type' => 'exception_type',
145
            'inci_count' => 'inci_count',
146
        ];
147
148 1
        $searchConditions = $this->OrderSearch->getSearchConditions($aColumns);
149 1
        $orderConditions = $this->OrderSearch->getOrder($aColumns);
150
151
        $params = [
152 1
            'fields' => $aColumns,
153
            'conditions' => [
154 1
                $searchConditions,
155 1
                'related_to is NULL',
156
            ],
157 1
            'order' => $orderConditions,
158
        ];
159
160 1
        $pagedParams = $params;
161 1
        $pagedParams['limit'] = intval($this->request->query('iDisplayLength'));
162 1
        $pagedParams['offset'] = intval($this->request->query('iDisplayStart'));
163
164 1
        $rows = $this->_findAllDataTable(
165 1
            $this->Reports->find('all', $pagedParams)->innerJoin(
166 1
                ['incidents' => $subquery],
167 1
                ['incidents.report_id = Reports.id']
168
            )
169
        );
170
        //$rows = Sanitize::clean($rows);
171 1
        $totalFiltered = $this->Reports->find('all', $params)->count();
172
173
        // change exception_type from boolean values to strings
174
        // add incident count for related reports
175 1
        $dispRows = [];
176 1
        foreach ($rows as $row) {
177 1
            $row[5] = $this->Reports->status[$row[5]];
178 1
            $row[6] = (intval($row[6])) ? ('php') : ('js');
179
            $input_elem = "<input type='checkbox' name='reports[]' value='"
180 1
                . $row[0]
181 1
                . "'/>";
182
183
            $subquery_params_count = [
184 1
                'fields' => [
185
                    'report_id' => 'report_id',
186
                ],
187
            ];
188 1
            $subquery_count = TableRegistry::get('incidents')->find(
189 1
                'all',
190 1
                $subquery_params_count
191
            );
192
193
            $params_count = [
194 1
                'fields' => ['inci_count' => 'inci_count'],
195
                'conditions' => [
196 1
                    'related_to = ' . $row[0],
197
                ],
198
            ];
199
200 1
            $inci_count_related = $this->Reports->find('all', $params_count)->innerJoin(
201 1
                ['incidents' => $subquery_count],
202 1
                ['incidents.report_id = Reports.related_to']
203 1
            )->count();
204
205 1
            $row[7] += $inci_count_related;
206
207 1
            array_unshift($row, $input_elem);
208 1
            array_push($dispRows, $row);
209
        }
210
211
        $response = [
212 1
            'iTotalRecords' => $this->Reports->find('all')->count(),
213 1
            'iTotalDisplayRecords' => $totalFiltered,
214 1
            'sEcho' => intval($this->request->query('sEcho')),
215 1
            'aaData' => $dispRows
216
        ];
217 1
        $this->autoRender = false;
218 1
        $this->response->body(json_encode($response));
219
220 1
        return $this->response;
221
    }
222
223 1
    public function mark_related_to($reportId)
224
    {
225
        // Only allow POST requests
226 1
        $this->request->allowMethod(['post']);
227
228 1
        $relatedTo = $this->request->getData('related_to');
229 1
        if (! $reportId
230 1
            || ! $relatedTo
231 1
            || $reportId == $relatedTo
232
        ) {
233
            throw new NotFoundException(__('Invalid Report'));
234
        }
235
236 1
        $report = $this->Reports->get($reportId);
237 1
        if (! $report) {
238
            throw new NotFoundException(__('Invalid Report'));
239
        }
240
241 1
        $this->Reports->addToRelatedGroup($report, $relatedTo);
242
243 1
        $flash_class = 'alert alert-success';
244 1
        $this->Flash->default(
245
            'This report has been marked the same as #'
246 1
                . $relatedTo,
247 1
            ['params' => ['class' => $flash_class]]
248
        );
249 1
        $this->redirect("/reports/view/$reportId");
250 1
    }
251
252 1
    public function unmark_related_to($reportId)
253
    {
254
        // Only allow POST requests
255 1
        $this->request->allowMethod(['post']);
256
257 1
        if (! $reportId) {
258
            throw new NotFoundException(__('Invalid Report'));
259
        }
260
261 1
        $report = $this->Reports->get($reportId);
262 1
        if (! $report) {
263
            throw new NotFoundException(__('Invalid Report'));
264
        }
265
266 1
        $this->Reports->removeFromRelatedGroup($report);
267
268 1
        $flash_class = 'alert alert-success';
269 1
        $this->Flash->default(
270 1
            'This report has been marked as different.',
271 1
            ['params' => ['class' => $flash_class]]
272
        );
273 1
        $this->redirect("/reports/view/$reportId");
274 1
    }
275
276 1
    public function change_state($reportId)
277
    {
278 1
        if (! $reportId) {
279
            throw new NotFoundException(__('Invalid Report'));
280
        }
281
282 1
        $report = $this->Reports->get($reportId);
283 1
        if (! $report) {
284
            throw new NotFoundException(__('Invalid Report'));
285
        }
286
287 1
        $state = $this->request->data['state'];
288 1
        $newState = null;
289
290 1
        if (array_key_exists($state, $this->Reports->status)) {
291 1
            $newState = $this->Reports->status[$state];
292
        }
293 1
        if (! $newState) {
294 1
            throw new NotFoundException(__('Invalid State'));
295
        }
296 1
        $report->status = $state;
297 1
        $this->Reports->save($report);
298
299 1
        $flash_class = 'alert alert-success';
300 1
        $this->Flash->default(
301 1
            'The state has been successfully changed.',
302 1
            ['params' => ['class' => $flash_class]]
303
        );
304 1
        $this->redirect("/reports/view/$reportId");
305 1
    }
306
307
    /**
308
     * To carry out mass actions on Reports
309
     * Currently only to change their statuses.
310
     * Can be Extended for other mass operations as well.
311
     * Expects an array of Report Ids as a POST parameter.
312
     * @return void
313
     */
314 1
    public function mass_action()
315
    {
316 1
        $flash_class = 'alert alert-error';
317 1
        $state = $this->request->data['state'];
318 1
        $newState = null;
319 1
        if (array_key_exists($state, $this->Reports->status)) {
320 1
            $newState = $this->Reports->status[$state];
321
        }
322
323 1
        if (! $newState) {
324 1
            Log::write(
325 1
                'error',
326 1
                'ERRORED: Invalid param "state" in ReportsController::mass_action()',
327 1
                'alert'
328
            );
329 1
            $msg = 'ERROR: Invalid State!!';
330 1
        } elseif (count($this->request->data['reports']) == 0) {
331 1
            $msg = 'No Reports Selected!! Please Select Reports and try again.';
332
        } else {
333
            $msg = "Status has been changed to '"
334 1
                . $this->request->data['state']
335 1
                . "' for selected Reports!";
336 1
            $flash_class = 'alert alert-success';
337 1
            foreach ($this->request->data['reports'] as $report_id) {
338 1
                $report = $this->Reports->get($report_id);
339 1
                if (! $report) {
340
                    Log::write(
341
                        'error',
342
                        'ERRORED: Invalid report_id in ReportsController::mass_action()',
343
                        'alert'
344
                    );
345
                    $msg = 'ERROR:Invalid Report ID:' . $report_id;
346
                    $flash_class = 'alert alert-error';
347
                    break;
348
                }
349 1
                $report->status = $state;
350 1
                $this->Reports->save($report);
351
            }
352
        }
353
354 1
        $this->Flash->default(
355 1
            $msg,
356 1
            ['params' => ['class' => $flash_class]]
357
        );
358 1
        $this->redirect('/reports/');
359 1
    }
360
361 1
    protected function _setSimilarFields($id)
362
    {
363 1
        $this->Reports->id = $id;
364
365 1
        $this->set('columns', TableRegistry::get('Incidents')->summarizableFields);
366 1
        $relatedEntries = [];
367
368 1 View Code Duplication
        foreach (TableRegistry::get('Incidents')->summarizableFields as $field) {
369
            list($entriesWithCount, $totalEntries) =
370 1
                    $this->Reports->getRelatedByField($field, 25, true);
371 1
            $relatedEntries[$field] = $entriesWithCount;
372 1
            $this->set("${field}_distinct_count", $totalEntries);
373
        }
374
        //error_log(json_encode($relatedEntries));
375
        $this->set('related_entries', $relatedEntries);
376
    }
377
378
    protected function _findArrayList($results, $key)
379
    {
380 1
        $output = [];
381 1
        foreach ($results as $row) {
382 1
            $output[] = $row[$key];
383
        }
384
385 1
        return $output;
386
    }
387
388
    protected function _findAllDataTable($results)
389
    {
390 1
        $output = [];
391 1
        foreach ($results as $row) {
392 1
            $output_row = [];
393 1
            $row = $row->toArray();
394 1
            foreach ($row as $key => $value) {
395 1
                $output_row[] = $value;
396
            }
397 1
            $output[] = $output_row;
398
        }
399
400 1
        return $output;
401
    }
402
}
403