Passed
Push — master ( e9dfe5...fa6a28 )
by MusikAnimal
05:21
created

UserRepository   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 304
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 304
rs 10
c 0
b 0
f 0
wmc 30

14 Methods

Rating   Name   Duplication   Size   Complexity  
B getGroups() 0 25 4
A getId() 0 14 2
B getGlobalGroups() 0 23 4
A getBlockExpiry() 0 9 1
A getUser() 0 7 1
A getRegistrationDate() 0 14 2
A getEditCount() 0 6 1
A getRevTimestampConditions() 0 13 3
B countEdits() 0 24 2
A executeQuery() 0 17 4
A getXtoolsUserInfo() 0 5 1
A getPageAndNamespaceSql() 0 11 3
A maxEdits() 0 3 1
A getUserRights() 0 14 1
1
<?php
2
/**
3
 * This file contains only the UserRepository class.
4
 */
5
6
namespace Xtools;
7
8
use Mediawiki\Api\SimpleRequest;
9
use Symfony\Component\DependencyInjection\Container;
10
use Symfony\Component\HttpFoundation\Session\Session;
11
12
/**
13
 * This class provides data for the User class.
14
 * @codeCoverageIgnore
15
 */
16
class UserRepository extends Repository
17
{
18
    /**
19
     * Convenience method to get a new User object.
20
     * @param string $username The username.
21
     * @param Container $container The DI container.
22
     * @return User
23
     */
24
    public static function getUser($username, Container $container)
25
    {
26
        $user = new User($username);
27
        $userRepo = new UserRepository();
28
        $userRepo->setContainer($container);
29
        $user->setRepository($userRepo);
30
        return $user;
31
    }
32
33
    /**
34
     * Get the user's ID.
35
     * @param string $databaseName The database to query.
36
     * @param string $username The username to find.
37
     * @return int
38
     */
39
    public function getId($databaseName, $username)
40
    {
41
        $cacheKey = $this->getCacheKey(func_get_args(), 'user_id');
42
        if ($this->cache->hasItem($cacheKey)) {
43
            return $this->cache->getItem($cacheKey)->get();
44
        }
45
46
        $userTable = $this->getTableName($databaseName, 'user');
47
        $sql = "SELECT user_id FROM $userTable WHERE user_name = :username LIMIT 1";
48
        $resultQuery = $this->executeProjectsQuery($sql, ['username' => $username]);
49
        $userId = (int)$resultQuery->fetchColumn();
50
51
        // Cache and return.
52
        return $this->setCache($cacheKey, $userId);
53
    }
54
55
    /**
56
     * Get the user's registration date.
57
     * @param string $databaseName The database to query.
58
     * @param string $username The username to find.
59
     * @return string|null As returned by the database.
60
     */
61
    public function getRegistrationDate($databaseName, $username)
62
    {
63
        $cacheKey = $this->getCacheKey(func_get_args(), 'user_registration');
64
        if ($this->cache->hasItem($cacheKey)) {
65
            return $this->cache->getItem($cacheKey)->get();
66
        }
67
68
        $userTable = $this->getTableName($databaseName, 'user');
69
        $sql = "SELECT user_registration FROM $userTable WHERE user_name = :username LIMIT 1";
70
        $resultQuery = $this->executeProjectsQuery($sql, ['username' => $username]);
71
        $registrationDate = $resultQuery->fetchColumn();
72
73
        // Cache and return.
74
        return $this->setCache($cacheKey, $registrationDate);
75
    }
76
77
    /**
78
     * Get the user's (system) edit count.
79
     * @param string $databaseName The database to query.
80
     * @param string $username The username to find.
81
     * @return int|null As returned by the database.
82
     */
83
    public function getEditCount($databaseName, $username)
84
    {
85
        $userTable = $this->getTableName($databaseName, 'user');
86
        $sql = "SELECT user_editcount FROM $userTable WHERE user_name = :username LIMIT 1";
87
        $resultQuery = $this->executeProjectsQuery($sql, ['username' => $username]);
88
        return $resultQuery->fetchColumn();
89
    }
90
91
    /**
92
     * Get group names of the given user.
93
     * @param Project $project The project.
94
     * @param string $username The username.
95
     * @return string[]
96
     */
97
    public function getGroups(Project $project, $username)
98
    {
99
        // Use md5 to ensure the key does not contain reserved characters.
100
        $cacheKey = $this->getCacheKey(func_get_args(), 'user_groups');
101
        if ($this->cache->hasItem($cacheKey)) {
102
            return $this->cache->getItem($cacheKey)->get();
103
        }
104
105
        $this->stopwatch->start($cacheKey, 'XTools');
106
        $api = $this->getMediawikiApi($project);
107
        $params = [
108
            'list' => 'users',
109
            'ususers' => $username,
110
            'usprop' => 'groups'
111
        ];
112
        $query = new SimpleRequest('query', $params);
113
        $result = [];
114
        $res = $api->getRequest($query);
115
        if (isset($res['batchcomplete']) && isset($res['query']['users'][0]['groups'])) {
116
            $result = $res['query']['users'][0]['groups'];
117
        }
118
119
        // Cache and return.
120
        $this->stopwatch->stop($cacheKey);
121
        return $this->setCache($cacheKey, $result);
122
    }
123
124
    /**
125
     * Get a user's global group membership (starting at XTools' default project if none is
126
     * provided). This requires the CentralAuth extension to be installed.
127
     * @link https://www.mediawiki.org/wiki/Extension:CentralAuth
128
     * @param string $username The username.
129
     * @param Project $project The project to query.
130
     * @return string[]
131
     */
132
    public function getGlobalGroups($username, Project $project = null)
133
    {
134
        // Get the default project if not provided.
135
        if (!$project instanceof Project) {
136
            $project = ProjectRepository::getDefaultProject($this->container);
137
        }
138
139
        // Create the API query.
140
        $api = $this->getMediawikiApi($project);
141
        $params = [
142
            'meta' => 'globaluserinfo',
143
            'guiuser' => $username,
144
            'guiprop' => 'groups'
145
        ];
146
        $query = new SimpleRequest('query', $params);
147
148
        // Get the result.
149
        $res = $api->getRequest($query);
150
        $result = [];
151
        if (isset($res['batchcomplete']) && isset($res['query']['globaluserinfo']['groups'])) {
152
            $result = $res['query']['globaluserinfo']['groups'];
153
        }
154
        return $result;
155
    }
156
157
    /**
158
     * Search the ipblocks table to see if the user is currently blocked
159
     * and return the expiry if they are.
160
     * @param $databaseName The database to query.
0 ignored issues
show
Bug introduced by
The type Xtools\The was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
161
     * @param $userId The ID of the user to search for.
162
     * @return bool|string Expiry of active block or false
163
     */
164
    public function getBlockExpiry($databaseName, $userId)
165
    {
166
        $ipblocksTable = $this->getTableName($databaseName, 'ipblocks');
167
        $sql = "SELECT ipb_expiry
168
                FROM $ipblocksTable
169
                WHERE ipb_user = :userId
170
                LIMIT 1";
171
        $resultQuery = $this->executeProjectsQuery($sql, ['userId' => $userId]);
172
        return $resultQuery->fetchColumn();
173
    }
174
175
    /**
176
     * Get edit count within given timeframe and namespace.
177
     * @param Project $project
178
     * @param User $user
179
     * @param int|string $namespace Namespace ID or 'all' for all namespaces
180
     * @param string $start Start date in a format accepted by strtotime()
181
     * @param string $end End date in a format accepted by strtotime()
182
     */
183
    public function countEdits(Project $project, User $user, $namespace = 'all', $start = '', $end = '')
184
    {
185
        $cacheKey = $this->getCacheKey(func_get_args(), 'user_editcount');
186
        if ($this->cache->hasItem($cacheKey)) {
187
            return $this->cache->getItem($cacheKey)->get();
188
        }
189
190
        list($condBegin, $condEnd) = $this->getRevTimestampConditions($start, $end);
191
        list($pageJoin, $condNamespace) = $this->getPageAndNamespaceSql($project, $namespace);
192
        $revisionTable = $project->getTableName('revision');
193
194
        $sql = "SELECT COUNT(rev_id)
195
                FROM $revisionTable
196
                $pageJoin
197
                WHERE rev_user_text = :username
198
                $condNamespace
199
                $condBegin
200
                $condEnd";
201
202
        $resultQuery = $this->executeQuery($sql, $user, $namespace, $start, $end);
203
        $result = $resultQuery->fetchColumn();
204
205
        // Cache and return.
206
        return $this->setCache($cacheKey, $result);
207
    }
208
209
    /**
210
     * Get information about the currently-logged in user.
211
     * @return array
212
     */
213
    public function getXtoolsUserInfo()
214
    {
215
        /** @var Session $session */
216
        $session = $this->container->get('session');
217
        return $session->get('logged_in_user');
218
    }
219
220
    /**
221
     * Maximum number of edits to process, based on configuration.
222
     * @return int
223
     */
224
    public function maxEdits()
225
    {
226
        return $this->container->getParameter('app.max_user_edits');
227
    }
228
229
    /**
230
     * Get SQL clauses for joining on `page` and restricting to a namespace.
231
     * @param  Project $project
232
     * @param  int|string $namespace Namespace ID or 'all' for all namespaces.
233
     * @return array [page join clause, page namespace clause]
234
     */
235
    protected function getPageAndNamespaceSql(Project $project, $namespace)
236
    {
237
        if ($namespace === 'all') {
238
            return [null, null];
239
        }
240
241
        $pageTable = $project->getTableName('page');
242
        $pageJoin = $namespace !== 'all' ? "LEFT JOIN $pageTable ON rev_page = page_id" : null;
243
        $condNamespace = 'AND page_namespace = :namespace';
244
245
        return [$pageJoin, $condNamespace];
246
    }
247
248
    /**
249
     * Get SQL clauses for rev_timestamp, based on whether values for
250
     * the given start and end parameters exist.
251
     * @param  string $start
252
     * @param  string $end
253
     * @param string $tableAlias Alias of table FOLLOWED BY DOT.
254
     * @todo FIXME: merge with Repository::getDateConditions
255
     * @return string[] Clauses for start and end timestamps.
256
     */
257
    protected function getRevTimestampConditions($start, $end, $tableAlias = '')
258
    {
259
        $condBegin = '';
260
        $condEnd = '';
261
262
        if (!empty($start)) {
263
            $condBegin = "AND {$tableAlias}rev_timestamp >= :start ";
264
        }
265
        if (!empty($end)) {
266
            $condEnd = "AND {$tableAlias}rev_timestamp <= :end ";
267
        }
268
269
        return [$condBegin, $condEnd];
270
    }
271
272
    /**
273
     * Prepare the given SQL, bind the given parameters, and execute the Doctrine Statement.
274
     * @param  string $sql
275
     * @param  User   $user
276
     * @param  string $namespace
277
     * @param  string $start
278
     * @param  string $end
279
     * @return \Doctrine\DBAL\Statement
280
     */
281
    protected function executeQuery($sql, User $user, $namespace = 'all', $start = '', $end = '')
282
    {
283
        $params = [
284
            'username' => $user->getUsername(),
285
        ];
286
287
        if (!empty($start)) {
288
            $params['start'] = date('Ymd000000', strtotime($start));
289
        }
290
        if (!empty($end)) {
291
            $params['end'] = date('Ymd235959', strtotime($end));
292
        }
293
        if ($namespace !== 'all') {
294
            $params['namespace'] = $namespace;
295
        }
296
297
        return $this->executeProjectsQuery($sql, $params);
298
    }
299
300
    /**
301
     * Get a user's local user rights on the given Project.
302
     * @param Project $project
303
     * @param User $user
304
     * @return string[]
305
     */
306
    public function getUserRights(Project $project, User $user)
307
    {
308
        $userGroupsTable = $project->getTableName('user_groups');
309
        $userTable = $project->getTableName('user');
310
311
        $sql = "SELECT ug_group
312
                FROM $userGroupsTable
313
                JOIN $userTable ON user_id = ug_user
314
                WHERE user_name = :username";
315
316
        $ret = $this->executeProjectsQuery($sql, [
317
            'username' => $user->getUsername(),
318
        ])->fetchAll(\PDO::FETCH_COLUMN);
319
        return $ret;
320
    }
321
}
322