Passed
Branch master (0917e1)
by MusikAnimal
11:12
created

UserRepository::getBlockExpiry()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 2
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file contains only the UserRepository class.
4
 */
5
6
declare(strict_types = 1);
7
8
namespace AppBundle\Repository;
9
10
use AppBundle\Model\Project;
11
use AppBundle\Model\User;
12
use Doctrine\DBAL\Driver\ResultStatement;
13
use PDO;
14
use Symfony\Component\DependencyInjection\ContainerInterface;
15
use Symfony\Component\HttpFoundation\Session\Session;
16
17
/**
18
 * This class provides data for the User class.
19
 * @codeCoverageIgnore
20
 */
21
class UserRepository extends Repository
22
{
23
    /**
24
     * Convenience method to get a new User object.
25
     * @param string $username The username.
26
     * @param ContainerInterface $container The DI container.
27
     * @return User
28
     */
29
    public static function getUser(string $username, ContainerInterface $container): User
30
    {
31
        $user = new User($username);
32
        $userRepo = new UserRepository();
33
        $userRepo->setContainer($container);
34
        $user->setRepository($userRepo);
35
        return $user;
36
    }
37
38
    /**
39
     * Get the user's ID and registration date.
40
     * @param string $databaseName The database to query.
41
     * @param string $username The username to find.
42
     * @return array|false With keys 'userId' and regDate'. false if user not found.
43
     */
44
    public function getIdAndRegistration(string $databaseName, string $username)
45
    {
46
        $cacheKey = $this->getCacheKey(func_get_args(), 'user_id_reg');
47
        if ($this->cache->hasItem($cacheKey)) {
48
            return $this->cache->getItem($cacheKey)->get();
49
        }
50
51
        $userTable = $this->getTableName($databaseName, 'user');
52
        $sql = "SELECT user_id AS userId, user_registration AS regDate
53
                FROM $userTable
54
                WHERE user_name = :username
55
                LIMIT 1";
56
        $resultQuery = $this->executeProjectsQuery($databaseName, $sql, ['username' => $username]);
57
58
        // Cache and return.
59
        return $this->setCache($cacheKey, $resultQuery->fetch());
60
    }
61
62
    /**
63
     * Get the user's actor ID.
64
     * @param string $databaseName
65
     * @param string $username
66
     * @return int|null
67
     */
68
    public function getActorId(string $databaseName, string $username): int
69
    {
70
        $cacheKey = $this->getCacheKey(func_get_args(), 'user_actor_id');
71
        if ($this->cache->hasItem($cacheKey)) {
72
            return (int)$this->cache->getItem($cacheKey)->get();
73
        }
74
75
        $actorTable = $this->getTableName($databaseName, 'actor');
76
77
        $sql = "SELECT actor_id
78
                FROM $actorTable
79
                WHERE actor_name = :username
80
                LIMIT 1";
81
        $resultQuery = $this->executeProjectsQuery($databaseName, $sql, ['username' => $username]);
82
83
        // Cache and return.
84
        return (int)$this->setCache($cacheKey, $resultQuery->fetchColumn());
85
    }
86
87
    /**
88
     * Get the user's (system) edit count.
89
     * @param string $databaseName The database to query.
90
     * @param string $username The username to find.
91
     * @return string|false As returned by the database.
92
     */
93
    public function getEditCount(string $databaseName, string $username)
94
    {
95
        $cacheKey = $this->getCacheKey(func_get_args(), 'user_edit_count');
96
        if ($this->cache->hasItem($cacheKey)) {
97
            return (int)$this->cache->getItem($cacheKey)->get();
98
        }
99
100
        $userTable = $this->getTableName($databaseName, 'user');
101
        $sql = "SELECT user_editcount FROM $userTable WHERE user_name = :username LIMIT 1";
102
        $resultQuery = $this->executeProjectsQuery($databaseName, $sql, ['username' => $username]);
103
104
        return (int)$this->setCache($cacheKey, $resultQuery->fetchColumn());
105
    }
106
107
    /**
108
     * Search the ipblocks table to see if the user is currently blocked and return the expiry if they are.
109
     * @param string $databaseName The database to query.
110
     * @param string $username The username of the user to search for.
111
     * @return bool|string Expiry of active block or false
112
     */
113
    public function getBlockExpiry(string $databaseName, string $username)
114
    {
115
        $ipblocksTable = $this->getTableName($databaseName, 'ipblocks', 'ipindex');
116
        $sql = "SELECT ipb_expiry
117
                FROM $ipblocksTable
118
                WHERE ipb_address = :username
119
                LIMIT 1";
120
        $resultQuery = $this->executeProjectsQuery($databaseName, $sql, ['username' => $username]);
121
        return $resultQuery->fetchColumn();
122
    }
123
124
    /**
125
     * Get edit count within given timeframe and namespace.
126
     * @param Project $project
127
     * @param User $user
128
     * @param int|string $namespace Namespace ID or 'all' for all namespaces
129
     * @param int|false $start Start date as Unix timestamp.
130
     * @param int|false $end End date as Unix timestamp.
131
     * @return int
132
     */
133
    public function countEdits(Project $project, User $user, $namespace = 'all', $start = false, $end = false): int
134
    {
135
        $cacheKey = $this->getCacheKey(func_get_args(), 'user_editcount');
136
        if ($this->cache->hasItem($cacheKey)) {
137
            return (int)$this->cache->getItem($cacheKey)->get();
138
        }
139
140
        $revDateConditions = $this->getDateConditions($start, $end);
141
        [$pageJoin, $condNamespace] = $this->getPageAndNamespaceSql($project, $namespace);
142
        $revisionTable = $project->getTableName('revision');
143
144
        $sql = "SELECT COUNT(rev_id)
145
                FROM $revisionTable
146
                $pageJoin
147
                WHERE rev_actor = :actorId
148
                $condNamespace
149
                $revDateConditions";
150
151
        $resultQuery = $this->executeQuery($sql, $project, $user, $namespace);
152
        $result = (int)$resultQuery->fetchColumn();
153
154
        // Cache and return.
155
        return $this->setCache($cacheKey, $result);
156
    }
157
158
    /**
159
     * Get information about the currently-logged in user.
160
     * @return array|object|null null if not logged in.
161
     */
162
    public function getXtoolsUserInfo()
163
    {
164
        /** @var Session $session */
165
        $session = $this->container->get('session');
166
        return $session->get('logged_in_user');
167
    }
168
169
    /**
170
     * Maximum number of edits to process, based on configuration.
171
     * @return int
172
     */
173
    public function maxEdits(): int
174
    {
175
        return (int)$this->container->getParameter('app.max_user_edits');
176
    }
177
178
    /**
179
     * Get SQL clauses for joining on `page` and restricting to a namespace.
180
     * @param Project $project
181
     * @param int|string $namespace Namespace ID or 'all' for all namespaces.
182
     * @return array [page join clause, page namespace clause]
183
     */
184
    protected function getPageAndNamespaceSql(Project $project, $namespace): array
185
    {
186
        if ('all' === $namespace) {
187
            return [null, null];
188
        }
189
190
        $pageTable = $project->getTableName('page');
191
        $pageJoin = 'all' !== $namespace ? "LEFT JOIN $pageTable ON rev_page = page_id" : null;
192
        $condNamespace = 'AND page_namespace = :namespace';
193
194
        return [$pageJoin, $condNamespace];
195
    }
196
197
    /**
198
     * Get SQL fragments for filtering by user.
199
     * Used in self::getPagesCreatedInnerSql().
200
     * @param bool $dateFiltering Whether the query you're working with has date filtering.
201
     *   If false, a clause to check timestamp > 1 is added to force use of the timestamp index.
202
     * @return string[] Keys 'whereRev' and 'whereArc'.
203
     */
204
    public function getUserConditions(bool $dateFiltering = false): array
205
    {
206
        return [
207
            'whereRev' => " rev_actor = :actorId ".($dateFiltering ? '' : "AND rev_timestamp > 1 "),
208
            'whereArc' => " ar_actor = :actorId ".($dateFiltering ? '' : "AND ar_timestamp > 1 "),
209
        ];
210
    }
211
212
    /**
213
     * Prepare the given SQL, bind the given parameters, and execute the Doctrine Statement.
214
     * @param string $sql
215
     * @param Project $project
216
     * @param User $user
217
     * @param int|string|null $namespace Namespace ID, or 'all'/null for all namespaces.
218
     * @param array $extraParams Will get merged in the params array used for binding values.
219
     * @return ResultStatement
220
     */
221
    protected function executeQuery(
222
        string $sql,
223
        Project $project,
224
        User $user,
225
        $namespace = 'all',
226
        array $extraParams = []
227
    ): ResultStatement {
228
        $params = ['actorId' => $user->getActorId($project)];
229
230
        if ('all' !== $namespace) {
231
            $params['namespace'] = $namespace;
232
        }
233
234
        return $this->executeProjectsQuery($project, $sql, array_merge($params, $extraParams));
235
    }
236
237
    /**
238
     * Get a user's local user rights on the given Project.
239
     * @param Project $project
240
     * @param User $user
241
     * @return string[]
242
     */
243
    public function getUserRights(Project $project, User $user): array
244
    {
245
        $cacheKey = $this->getCacheKey(func_get_args(), 'user_rights');
246
        if ($this->cache->hasItem($cacheKey)) {
247
            return $this->cache->getItem($cacheKey)->get();
248
        }
249
250
        $userGroupsTable = $project->getTableName('user_groups');
251
        $userTable = $project->getTableName('user');
252
253
        $sql = "SELECT ug_group
254
                FROM $userGroupsTable
255
                JOIN $userTable ON user_id = ug_user
256
                WHERE user_name = :username";
257
258
        $ret = $this->executeProjectsQuery($project, $sql, [
259
            'username' => $user->getUsername(),
260
        ])->fetchAll(PDO::FETCH_COLUMN);
261
262
        // Cache and return.
263
        return $this->setCache($cacheKey, $ret);
264
    }
265
266
    /**
267
     * Get a user's global group membership (starting at XTools' default project if none is
268
     * provided). This requires the CentralAuth extension to be installed.
269
     * @link https://www.mediawiki.org/wiki/Extension:CentralAuth
270
     * @param string $username The username.
271
     * @param Project|null $project The project to query.
272
     * @return string[]
273
     */
274
    public function getGlobalUserRights(string $username, ?Project $project = null): array
275
    {
276
        $cacheKey = $this->getCacheKey(func_get_args(), 'user_global_groups');
277
        if ($this->cache->hasItem($cacheKey)) {
278
            return $this->cache->getItem($cacheKey)->get();
279
        }
280
281
        // Get the default project if not provided.
282
        if (!$project instanceof Project) {
283
            $project = ProjectRepository::getDefaultProject($this->container);
284
        }
285
286
        $params = [
287
            'meta' => 'globaluserinfo',
288
            'guiuser' => $username,
289
            'guiprop' => 'groups',
290
        ];
291
292
        $res = $this->executeApiRequest($project, $params);
293
        $result = [];
294
        if (isset($res['batchcomplete']) && isset($res['query']['globaluserinfo']['groups'])) {
295
            $result = $res['query']['globaluserinfo']['groups'];
296
        }
297
298
        // Cache and return.
299
        return $this->setCache($cacheKey, $result);
300
    }
301
}
302