Passed
Push — master ( 1c40ea...a41f56 )
by MusikAnimal
07:57
created

AdminStatsRepository::getUserGroupIcons()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file contains only the AdminStatsRepository class.
4
 */
5
6
declare(strict_types = 1);
7
8
namespace AppBundle\Repository;
9
10
use AppBundle\Model\Project;
11
use Mediawiki\Api\SimpleRequest;
12
13
/**
14
 * AdminStatsRepository is responsible for retrieving data from the database
15
 * about users with administrative rights on a given wiki.
16
 * @codeCoverageIgnore
17
 */
18
class AdminStatsRepository extends Repository
19
{
20
    /**
21
     * Get the URLs of the icons for the user groups.
22
     * @return string[] System user group name as the key, URL to image as the value.
23
     */
24
    public function getUserGroupIcons(): array
25
    {
26
        return $this->container->getParameter('user_group_icons');
27
    }
28
29
    /**
30
     * Core function to get statistics about users who have admin/patroller/steward-like permissions.
31
     * @param Project $project
32
     * @param string $start SQL-ready format.
33
     * @param string $end
34
     * @param string $type Which 'type' we're querying for, as configured in admin_stats.yml
35
     * @param string[]|null $actions Which log actions to query for.
36
     * @return string[][] with key for each action type (specified in admin_stats.yml), including 'total'.
37
     */
38
    public function getStats(Project $project, string $start, string $end, string $type, ?array $actions = null): array
39
    {
40
        $cacheKey = $this->getCacheKey(func_get_args(), 'adminstats');
41
        if ($this->cache->hasItem($cacheKey)) {
42
            return $this->cache->getItem($cacheKey)->get();
43
        }
44
45
        $userTable = $project->getTableName('user');
46
        $loggingTable = $project->getTableName('logging', 'logindex');
47
        [$countSql, $types, $actions] = $this->getLogSqlParts($type, $actions);
48
49
        $sql = "SELECT user_name AS `username`,
50
                    $countSql
51
                    SUM(IF(log_type != '' AND log_action != '', 1, 0)) AS `total`
52
                FROM $loggingTable
53
                JOIN $userTable ON user_id = log_user
54
                WHERE log_timestamp > '$start' AND log_timestamp <= '$end'
55
                  AND log_type IS NOT NULL
56
                  AND log_action IS NOT NULL
57
                  AND log_type IN ($types)
58
                  AND log_action IN ($actions)
59
                GROUP BY user_name
60
                HAVING `total` > 0
61
                ORDER BY 'total' DESC";
62
63
        $results = $this->executeProjectsQuery($sql)->fetchAll();
64
65
        // Cache and return.
66
        return $this->setCache($cacheKey, $results);
67
    }
68
69
    /**
70
     * Get the SQL to query for the given type and actions.
71
     * @param string $type
72
     * @param string[]|null $requestedActions
73
     * @return string[]
74
     */
75
    private function getLogSqlParts(string $type, ?array $requestedActions = null): array
76
    {
77
        $config = $this->container->getParameter('admin_stats')[$type];
78
79
        // 'permissions' and 'user_group' are only used for self::getAdminGroups()
80
        unset($config['permissions']);
81
        unset($config['user_group']);
82
83
        $countSql = '';
84
        $logTypes = [];
85
        $actions = [];
86
87
        foreach ($config as $key => $logTypeActions) {
88
            if (is_array($requestedActions) && !in_array($key, $requestedActions)) {
89
                continue;
90
            }
91
92
            $keyTypes = [];
93
            $keyActions = [];
94
95
            foreach ($logTypeActions as $entry) {
96
                [$logType, $logAction] = explode('/', $entry);
97
                $logTypes[] = $keyTypes[] = $this->getProjectsConnection()->quote($logType, \PDO::PARAM_STR);
98
                $actions[] = $keyActions[] = $this->getProjectsConnection()->quote($logAction, \PDO::PARAM_STR);
99
            }
100
101
            $keyTypes = implode(',', array_unique($keyTypes));
102
            $keyActions = implode(',', array_unique($keyActions));
103
104
            $countSql .= "SUM(IF((log_type IN ($keyTypes) AND log_action IN ($keyActions)), 1, 0)) AS `$key`,\n";
105
        }
106
107
        return [$countSql, implode(',', array_unique($logTypes)), implode(',', array_unique($actions))];
108
    }
109
110
    /**
111
     * Get the user_group from the config given the 'type'.
112
     * @param string $type
113
     * @return string
114
     */
115
    public function getRelevantUserGroup(string $type): string
116
    {
117
        return $this->container->getParameter('admin_stats')[$type]['user_group'];
118
    }
119
120
    /**
121
     * Get all user groups with permissions applicable to the given 'group'.
122
     * @param Project $project
123
     * @param string $type Which 'type' we're querying for, as configured in admin_stats.yml
124
     * @return array Each entry contains 'name' (user group) and 'rights' (the permissions).
125
     */
126
    public function getUserGroups(Project $project, string $type): array
127
    {
128
        $cacheKey = $this->getCacheKey(func_get_args(), 'admingroups');
129
        if ($this->cache->hasItem($cacheKey)) {
130
            return $this->cache->getItem($cacheKey)->get();
131
        }
132
133
        $permissions = $this->container->getParameter('admin_stats')[$type]['permissions'];
134
        $userGroups = [];
135
136
        $api = $this->getMediawikiApi($project);
137
        $query = new SimpleRequest('query', [
138
            'meta' => 'siteinfo',
139
            'siprop' => 'usergroups',
140
        ]);
141
        $res = $api->getRequest($query);
142
143
        // If there isn't a user groups hash than let it error out... Something else must have gone horribly wrong.
144
        foreach ($res['query']['usergroups'] as $userGroup) {
145
            // If they are able to add and remove user groups,
146
            // we'll treat them as having the 'userrights' permission.
147
            if (isset($userGroup['add']) || isset($userGroup['remove'])) {
148
                array_push($userGroup['rights'], 'userrights');
149
            }
150
151
            if (count(array_intersect($userGroup['rights'], $permissions)) > 0) {
152
                $userGroups[] = $userGroup['name'];
153
            }
154
        }
155
156
        // Cache for a week and return.
157
        return $this->setCache($cacheKey, $userGroups, 'P7D');
158
    }
159
}
160