Completed
Push — master ( e3e8c6...010637 )
by MusikAnimal
12s
created

AdminStatsController   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 214
Duplicated Lines 7.48 %

Coupling/Cohesion

Components 1
Dependencies 2

Importance

Changes 0
Metric Value
wmc 12
lcom 1
cbo 2
dl 16
loc 214
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A getToolShortname() 0 4 1
A indexAction() 16 16 2
D resultAction() 0 154 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
3
/**
4
 * This file contains the code that powers the AdminStats page of XTools.
5
 *
6
 * @version 1.5.1
7
 */
8
9
namespace AppBundle\Controller;
10
11
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
12
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
13
use Symfony\Component\HttpFoundation\Request;
14
use Symfony\Component\HttpFoundation\RedirectResponse;
15
use Xtools\ProjectRepository;
16
17
/**
18
 * Class AdminStatsController
19
 *
20
 * @category AdminStats
21
 * @package  AppBundle\Controller
22
 * @author   XTools Team <[email protected]>
23
 * @license  GPL 3.0
24
 */
25
class AdminStatsController extends XtoolsController
26
{
27
    /**
28
     * Get the tool's shortname.
29
     * @return string
30
     * @codeCoverageIgnore
31
     */
32
    public function getToolShortname()
33
    {
34
        return 'adminstats';
35
    }
36
37
    /**
38
     * Method for rendering the AdminStats Main Form.
39
     * This method redirects if valid parameters are found, making it a
40
     * valid form endpoint as well.
41
     *
42
     * @param Request $request Generated by Symfony
43
     *
44
     * @Route("/adminstats",           name="adminstats")
45
     * @Route("/adminstats/",          name="AdminStatsSlash")
46
     * @Route("/adminstats/index.php", name="AdminStatsIndexPhp")
47
     *
48
     * @return Route|\Symfony\Component\HttpFoundation\Response
49
     */
50 View Code Duplication
    public function indexAction(Request $request)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
51
    {
52
        $params = $this->parseQueryParams($request);
53
54
        // Redirect if we have a project. $results may also include start and/or end date.
55
        if (isset($params['project'])) {
56
            return $this->redirectToRoute('AdminStatsResult', $params);
57
        }
58
59
        // Otherwise render form.
60
        return $this->render('adminStats/index.html.twig', [
61
            'xtPage' => 'adminstats',
62
            'xtPageTitle' => 'tool-adminstats',
63
            'xtSubtitle' => 'tool-adminstats-desc',
64
        ]);
65
    }
66
67
    /**
68
     * Method for rendering the AdminStats Results
69
     *
70
     * @param Request $request The HTTP request.
71
     * @param string $project Project to run the results against
72
     * @param string $start   Date to start on.  Must parse by strtotime.
73
     * @param string $end     Date to end on.  Must parse by strtotime.
74
     *
75
     * @Route(
76
     *   "/adminstats/{project}/{start}/{end}", name="AdminStatsResult",
77
     *   requirements={"start" = "|\d{4}-\d{2}-\d{2}", "end" = "|\d{4}-\d{2}-\d{2}"}
78
     * )
79
     *
80
     * @return Route|\Symfony\Component\HttpFoundation\Response
81
     * @todo Move SQL to a model.
82
     * @codeCoverageIgnore
83
     */
84
    public function resultAction(Request $request, $project, $start = null, $end = null)
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
85
    {
86
        // Load the database information for the tool.
87
        // $projectData will be a redirect if the project is invalid.
88
        $projectData = $this->validateProject($project);
89
        if ($projectData instanceof RedirectResponse) {
90
            return $projectData;
91
        }
92
93
        list($start, $end) = $this->getUTCFromDateParams($start, $end);
94
95
        // Initialize variables - prevents variable undefined errors
96
        $adminIdArr = [];
97
        $adminsWithoutAction = 0;
98
        $adminsWithoutActionPct = 0;
99
100
        // Pull the API helper and database. Then check if we can use this tool
101
        $api = $this->get('app.api_helper');
102
        $conn = $this->get('doctrine')->getManager('replicas')->getConnection();
103
104
        // Generate a diff for the dates - this is the number of days we're spanning.
105
        $days = ($end - $start) / 60 / 60 / 24;
106
107
        // Get admin ID's, used to account for inactive admins
108
        $userGroupsTable = $projectData->getTableName('user_groups');
109
        $ufgTable = $projectData->getTableName('user_former_groups');
110
        $query = "
111
            SELECT ug_user AS user_id
112
            FROM $userGroupsTable
113
            WHERE ug_group = 'sysop'
114
            UNION
115
            SELECT ufg_user AS user_id
116
            FROM $ufgTable
117
            WHERE ufg_group = 'sysop'
118
            ";
119
120
        $res = $conn->prepare($query);
121
        $res->execute();
122
123
        // Iterate over query results, loading each user id into the array
124
        while ($row = $res->fetch()) {
125
            $adminIdArr[] = $row['user_id'] ;
126
        }
127
128
        // Set the query results to be useful in a sql statement.
129
        $adminIds = implode(',', $adminIdArr);
130
131
        // Load up the tables we need and run the mega query.
132
        // This query provides all of the statistics
133
        $userTable = $projectData->getTableName('user');
134
        $loggingTable = $projectData->getTableName('logging', 'userindex');
135
136
        $startDb = date('Ymd000000', $start);
137
        $endDb = date('Ymd235959', $end);
138
139
        // TODO: Fix this - inactive admins aren't getting shown
140
        $query = "
141
            SELECT user_name, user_id,
142
                SUM(IF( (log_type = 'delete'  AND log_action != 'restore'),1,0)) AS mdelete,
143
                SUM(IF( (log_type = 'delete'  AND log_action  = 'restore'),1,0)) AS mrestore,
144
                SUM(IF( (log_type = 'block'   AND log_action != 'unblock'),1,0)) AS mblock,
145
                SUM(IF( (log_type = 'block'   AND log_action  = 'unblock'),1,0)) AS munblock,
146
                SUM(IF( (log_type = 'protect' AND log_action != 'unprotect'),1,0)) AS mprotect,
147
                SUM(IF( (log_type = 'protect' AND log_action  = 'unprotect'),1,0)) AS munprotect,
148
                SUM(IF( log_type  = 'rights',1,0)) AS mrights,
149
                SUM(IF( log_type  = 'import',1,0)) AS mimport,
150
                SUM(IF(log_type  != '',1,0)) AS mtotal
151
            FROM $loggingTable
152
            JOIN $userTable ON user_id = log_user
153
            WHERE log_timestamp > '$startDb' AND log_timestamp <= '$endDb'
154
              AND log_type IS NOT NULL
155
              AND log_action IS NOT NULL
156
              AND log_type IN ('block', 'delete', 'protect', 'import', 'rights')
157
            GROUP BY user_name
158
            HAVING mdelete > 0 OR user_id IN ($adminIds)
159
            ORDER BY mtotal DESC";
160
161
        $res = $conn->prepare($query);
162
        $res->execute();
163
164
        // Fetch all the information out.  Because of pre-processing done
165
        // in the query, we can use this practically raw.
166
        $users = $res->fetchAll();
167
168
        // Pull the admins from the API, for merging.
169
        $admins = $api->getAdmins($project);
170
171
        // Get the total number of admins, the number of admins without
172
        // action, and then later we'll run percentage calculations
173
        $adminCount = count($admins);
174
175
        // Combine the two arrays.  We can't use array_merge here because
176
        // the arrays contain fundamentally different data.  Instead, it's
177
        // done by hand.  Only two values are needed, edit count and groups.
178
        foreach ($users as $key => $value) {
179
            $username = $value['user_name'];
180
181
            if (empty($admins[$username])) {
182
                $admins[$username] = [
183
                    'groups' => '',
184
                ];
185
            }
186
            $users[$key]['groups'] = $admins[$username]['groups'];
187
188
            if ($users[$key]['mtotal'] === 0) {
189
                $adminsWithoutAction++;
190
            }
191
192
            unset($admins[$username]);
193
        }
194
195
        // push any inactive admins back to $users with zero values
196
        if (count($admins)) {
197
            foreach ($admins as $username => $stats) {
198
                $users[] = [
199
                    'user_name' => $username,
200
                    'mdelete' => 0,
201
                    'mrestore' => 0,
202
                    'mblock' => 0,
203
                    'munblock' => 0,
204
                    'mprotect' => 0,
205
                    'munprotect' => 0,
206
                    'mrights' => 0,
207
                    'mimport' => 0,
208
                    'mtotal' => 0,
209
                    'groups' => $stats['groups'],
210
                ];
211
                $adminsWithoutAction++;
212
            }
213
        }
214
215
        if ($adminCount > 0) {
216
            $adminsWithoutActionPct = ($adminsWithoutAction / $adminCount) * 100;
217
        }
218
219
        // Render the result!
220
        return $this->render('adminStats/result.html.twig', [
221
            'xtPage' => 'adminstats',
222
            'xtTitle' => $project,
223
224
            'project' => $projectData,
225
226
            'start_date' => date('Y-m-d', $start),
227
            'end_date' => date('Y-m-d', $end),
228
            'days' => $days,
229
230
            'adminsWithoutAction' => $adminsWithoutAction,
231
            'admins_without_action_pct' => $adminsWithoutActionPct,
232
            'adminCount' => $adminCount,
233
234
            'users' => $users,
235
            'usersCount' => count($users),
236
        ]);
237
    }
238
}
239