Issues (186)

includes/DataObjects/Ban.php (2 issues)

1
<?php
2
/******************************************************************************
3
 * Wikipedia Account Creation Assistance tool                                 *
4
 * ACC Development Team. Please see team.json for a list of contributors.     *
5
 *                                                                            *
6
 * This is free and unencumbered software released into the public domain.    *
7
 * Please see LICENSE.md for the full licencing statement.                    *
8
 ******************************************************************************/
9
10
namespace Waca\DataObjects;
11
12
use Exception;
13
use PDO;
14
use Waca\DataObject;
15
use Waca\Exceptions\OptimisticLockFailedException;
16
use Waca\PdoDatabase;
17
18
/**
19
 * Ban data object
20
 */
21
class Ban extends DataObject
22
{
23
    const ACTION_BLOCK = 'block';
24
    const ACTION_DROP = 'drop';
25
    const ACTION_DROP_PRECONFIRM = 'drop-pre';
26
    const ACTION_DEFER = 'defer';
27
    const ACTION_NONE = 'none';
28
29
    /** @var string|null */
30
    private $name;
31
    /** @var string|null */
32
    private $ip;
33
    /** @var int|null */
34
    private $ipmask;
35
    /** @var string|null */
36
    private $email;
37
    /** @var string|null */
38
    private $useragent;
39
40
    private $user;
41
    private $reason;
42
    private $date;
43
    private $duration;
44
    private $active;
45
    private $action = self::ACTION_BLOCK;
46
    private $targetqueue;
47
    private $visibility = 'user';
48
    private ?int $domain;
49
50
    /**
51
     * Gets all active bans, filtered by the optional target.
52
     *
53
     * @return Ban[]
54
     */
55
    public static function getActiveBans(PdoDatabase $database, int $domain)
56
    {
57
        $query = <<<SQL
58
SELECT * FROM ban 
59
WHERE (duration > UNIX_TIMESTAMP() OR duration is null) 
60
    AND active = 1
61
    AND (domain IS NULL OR domain = :domain);
62
SQL;
63
        $statement = $database->prepare($query);
64
        $statement->execute([':domain' => $domain]);
65
        $result = array();
66
67
        /** @var Ban $v */
68
        foreach ($statement->fetchAll(PDO::FETCH_CLASS, get_called_class()) as $v) {
69
            $v->setDatabase($database);
70
            $result[] = $v;
71
        }
72
73
        return $result;
74
    }
75
76
    /**
77
     * Gets a ban by its ID if it's currently active.
78
     *
79
     * @return Ban|false
80
     */
81
    public static function getActiveId($id, PdoDatabase $database, int $domain)
82
    {
83
        $statement = $database->prepare(<<<SQL
84
SELECT *
85
FROM ban
86
WHERE id = :id  
87
  AND (domain IS NULL OR domain = :domain)
88
  AND (duration > UNIX_TIMESTAMP() OR duration is null) 
89
  AND active = 1;
90
SQL
91
        );
92
        $statement->bindValue(":id", $id);
93
        $statement->bindValue(":domain", $domain);
94
95
        $statement->execute();
96
97
        $resultObject = $statement->fetchObject(get_called_class());
98
99
        if ($resultObject !== false) {
100
            $resultObject->setDatabase($database);
101
        }
102
103
        return $resultObject;
104
    }
105
106
    public static function getByIdList($values, PdoDatabase $database, int $domain): array
107
    {
108
        if (count($values) === 0) {
109
            return [];
110
        }
111
112
        // use the provided array to produce a list of question marks of the same length as the array.
113
        $valueCount = count($values);
114
        $inSection = str_repeat('?,', $valueCount - 1) . '?';
115
116
        // this is still parameterised! It's using positional parameters instead of named ones.
117
        $query = 'SELECT * FROM ban WHERE id IN (' . $inSection . ')';
118
119
        $query .= ' AND (domain IS NULL OR domain = ?)';
120
        $values[] = $domain;
121
122
        $statement = $database->prepare($query);
123
124
        // execute the statement with the provided parameter list.
125
        $statement->execute($values);
126
127
        $result = [];
128
        foreach ($statement->fetchAll(PDO::FETCH_CLASS, get_called_class()) as $v) {
129
            $v->setDatabase($database);
130
            $result[] = $v;
131
        }
132
133
        return $result;
134
    }
135
136
    /**
137
     * @throws Exception
138
     */
139
    public function save()
140
    {
141
        if ($this->isNew()) {
142
            // insert
143
            $statement = $this->dbObject->prepare(<<<SQL
144
INSERT INTO `ban` (name, email, ip, ipmask, useragent, user, reason, date, duration, active, action, targetqueue, visibility, domain)
145
VALUES (:name, :email, :ip, :ipmask, :useragent, :user, :reason, CURRENT_TIMESTAMP(), :duration, :active, :action, :targetqueue, :visibility, :domain);
146
SQL
147
            );
148
149
            $statement->bindValue(":name", $this->name);
150
            $statement->bindValue(":email", $this->email);
151
            $statement->bindValue(":ip", $this->ip);
152
            $statement->bindValue(":ipmask", $this->ipmask);
153
            $statement->bindValue(":useragent", $this->useragent);
154
155
            $statement->bindValue(":user", $this->user);
156
            $statement->bindValue(":reason", $this->reason);
157
            $statement->bindValue(":duration", $this->duration);
158
            $statement->bindValue(":active", $this->active);
159
            $statement->bindValue(":action", $this->action);
160
            $statement->bindValue(":targetqueue", $this->targetqueue);
161
            $statement->bindValue(":visibility", $this->visibility);
162
            $statement->bindValue(":domain", $this->domain);
163
164
            if ($statement->execute()) {
165
                $this->id = (int)$this->dbObject->lastInsertId();
166
            }
167
            else {
168
                throw new Exception($statement->errorInfo());
0 ignored issues
show
$statement->errorInfo() of type array is incompatible with the type string expected by parameter $message of Exception::__construct(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

168
                throw new Exception(/** @scrutinizer ignore-type */ $statement->errorInfo());
Loading history...
169
            }
170
        }
171
        else {
172
            // update
173
            $statement = $this->dbObject->prepare(<<<SQL
174
UPDATE `ban`
175
SET active = :active, updateversion = updateversion + 1
176
WHERE id = :id AND updateversion = :updateversion;
177
SQL
178
            );
179
            $statement->bindValue(':id', $this->id);
180
            $statement->bindValue(':updateversion', $this->updateversion);
181
182
            $statement->bindValue(':active', $this->active);
183
184
            if (!$statement->execute()) {
185
                throw new Exception($statement->errorInfo());
186
            }
187
188
            if ($statement->rowCount() !== 1) {
189
                throw new OptimisticLockFailedException();
190
            }
191
192
            $this->updateversion++;
193
        }
194
    }
195
196
    /**
197
     * @return string
198
     */
199
    public function getReason()
200
    {
201
        return $this->reason;
202
    }
203
204
    /**
205
     * @param string $reason
206
     */
207
    public function setReason($reason)
208
    {
209
        $this->reason = $reason;
210
    }
211
212
    /**
213
     * @return mixed
214
     */
215
    public function getDate()
216
    {
217
        return $this->date;
218
    }
219
220
    /**
221
     * @return mixed
222
     */
223
    public function getDuration()
224
    {
225
        return $this->duration;
226
    }
227
228
    /**
229
     * @param mixed $duration
230
     */
231
    public function setDuration($duration)
232
    {
233
        $this->duration = $duration;
234
    }
235
236
    /**
237
     * @return bool
238
     */
239
    public function isActive()
240
    {
241
        return $this->active == 1;
242
    }
243
244
    /**
245
     * @param bool $active
246
     */
247
    public function setActive($active)
248
    {
249
        $this->active = $active ? 1 : 0;
250
    }
251
252
    /**
253
     * @return int
254
     */
255
    public function getUser()
256
    {
257
        return $this->user;
258
    }
259
260
    /**
261
     * @param int $user UserID of user who is setting the ban
262
     */
263
    public function setUser($user)
264
    {
265
        $this->user = $user;
266
    }
267
268
    /**
269
     * @return string
270
     */
271
    public function getAction(): string
272
    {
273
        return $this->action;
274
    }
275
276
    /**
277
     * @param string $action
278
     */
279
    public function setAction(string $action): void
280
    {
281
        $this->action = $action;
282
    }
283
284
    /**
285
     * @return string
286
     */
287
    public function getVisibility() : string
288
    {
289
        return $this->visibility;
290
    }
291
292
    /**
293
     * @param string $visibility
294
     */
295
    public function setVisibility(string $visibility): void
296
    {
297
        $this->visibility = $visibility;
298
    }
299
300
    /**
301
     * @return string|null
302
     */
303
    public function getName(): ?string
304
    {
305
        return $this->name;
306
    }
307
308
    /**
309
     * @param string|null $name
310
     */
311
    public function setName(?string $name): void
312
    {
313
        $this->name = $name;
314
    }
315
316
    /**
317
     * @return string|null
318
     */
319
    public function getIp(): ?string
320
    {
321
        if ($this->ip === null) {
322
            return null;
323
        }
324
325
        return inet_ntop($this->ip);
326
    }
327
328
    /**
329
     * @return int|null
330
     */
331
    public function getIpMask(): ?int
332
    {
333
        return $this->ipmask;
334
    }
335
336
    /**
337
     * @param string|null $ip
338
     * @param int|null    $mask
339
     */
340
    public function setIp(?string $ip, ?int $mask): void
341
    {
342
        if ($ip === null) {
343
            $this->ip = null;
344
        }
345
        else {
346
            $this->ip = inet_pton($ip);
347
        }
348
349
        $this->ipmask = $mask;
350
    }
351
352
    /**
353
     * @return string|null
354
     */
355
    public function getEmail(): ?string
356
    {
357
        return $this->email;
358
    }
359
360
    /**
361
     * @param string|null $email
362
     */
363
    public function setEmail(?string $email): void
364
    {
365
        $this->email = $email;
366
    }
367
368
    /**
369
     * @return string|null
370
     */
371
    public function getUseragent(): ?string
372
    {
373
        return $this->useragent;
374
    }
375
376
    /**
377
     * @param string|null $useragent
378
     */
379
    public function setUseragent(?string $useragent): void
380
    {
381
        $this->useragent = $useragent;
382
    }
383
384
    /**
385
     * @return int|null
386
     */
387
    public function getTargetQueue(): ?int
388
    {
389
        return $this->targetqueue;
390
    }
391
392
    /**
393
     * @return RequestQueue|null
394
     */
395
    public function getTargetQueueObject(): ?RequestQueue
396
    {
397
        /** @var RequestQueue $queue */
398
        $queue = RequestQueue::getById($this->targetqueue, $this->getDatabase());
399
        return $queue === false ? null : $queue;
0 ignored issues
show
The condition $queue === false is always false.
Loading history...
400
    }
401
402
    /**
403
     * @param int|null $targetQueue
404
     */
405
    public function setTargetQueue(?int $targetQueue): void
406
    {
407
        $this->targetqueue = $targetQueue;
408
    }
409
410
    public function setDomain(?int $domain): void
411
    {
412
        $this->domain = $domain;
413
    }
414
415
    public function getDomain(): ?int
416
    {
417
        return $this->domain;
418
    }
419
}
420