Completed
Push — master ( 13e33a...7c2796 )
by Vladimir
17s
created

Ban::getActiveStatuses()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 2
1
<?php
2
/**
3
 * This file contains functionality relating to the banned league players
4
 *
5
 * @package    BZiON\Models
6
 * @license    https://github.com/allejo/bzion/blob/master/LICENSE.md GNU General Public License Version 3
7
 */
8
9
/**
10
 * A ban imposed by an admin on a player
11
 * @package BZiON\Models
12
 */
13
class Ban extends UrlModel implements NamedModel
14
{
15
    /**
16
     * The id of the banned player
17
     * @var int
18
     */
19
    protected $player;
20
21
    /**
22
     * The ban expiration date
23
     * @var TimeDate
24
     */
25
    protected $expiration;
26
27
    /**
28
     * The message that will appear when a player is denied connecting to a game server
29
     * @var string
30
     */
31
    protected $srvmsg;
32
33
    /**
34
     * The ban reason
35
     * @var string
36
     */
37
    protected $reason;
38
39
    /**
40
     * Whether or not a player is allowed to join a server when they are banned
41
     * @var bool
42
     */
43
    protected $allowServerJoin;
44
45
    /**
46
     * The ban creation date
47
     * @var TimeDate
48
     */
49
    protected $created;
50
51
    /**
52
     * The date the ban was last updated
53
     * @var TimeDate
54
     */
55
    protected $updated;
56
57
    /**
58
     * The id of the ban author
59
     * @var int
60
     */
61
    protected $author;
62
63
    /**
64
     * The IP of the banned player if the league would like to implement a global ban list
65
     * @var string[]
66
     */
67
    protected $ipAddresses;
68
69
    /**
70
     * The ban's status
71
     * @var string
72
     */
73
    protected $status;
74
75
    const DEFAULT_STATUS = 'public';
76
77
    /**
78
     * The name of the database table used for queries
79
     */
80
    const TABLE = "bans";
81
82
    const CREATE_PERMISSION = Permission::ADD_BAN;
83
    const EDIT_PERMISSION = Permission::EDIT_BAN;
84
    const SOFT_DELETE_PERMISSION = Permission::SOFT_DELETE_BAN;
85
    const HARD_DELETE_PERMISSION = Permission::HARD_DELETE_BAN;
86
87
    /**
88 2
     * {@inheritdoc}
89
     */
90 2
    protected function assignResult($ban)
91 2
    {
92 1
        $this->player = $ban['player'];
93 1
        $this->expiration = ($ban['expiration'] === null)
94 2
                          ? null
95 2
                          : TimeDate::fromMysql($ban['expiration']);
96 2
        $this->srvmsg = $ban['server_message'];
97 2
        $this->reason = $ban['reason'];
98 2
        $this->allowServerJoin = $ban['allow_server_join'];
99 2
        $this->created = TimeDate::fromMysql($ban['created']);
100 2
        $this->updated = TimeDate::fromMysql($ban['updated']);
101 2
        $this->author = $ban['author'];
102
        $this->status = $ban['status'];
103
    }
104
105
    /**
106
     * {@inheritdoc}
107
     */
108
    protected function assignLazyResult($result)
109
    {
110
        $this->ipAddresses = self::fetchIds("WHERE ban_id = ?", array($this->getId()), "banned_ips", "ip_address");
0 ignored issues
show
Documentation Bug introduced by
It seems like self::fetchIds('WHERE ba...ned_ips', 'ip_address') of type array<integer,integer> is incompatible with the declared type array<integer,string> of property $ipAddresses.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
111
    }
112
113
    /**
114
     * Add an IP to the ban
115
     *
116
     * @param string $ipAddress The IP to add to a ban
117
     */
118 View Code Duplication
    public function addIP($ipAddress)
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...
119
    {
120
        $this->lazyLoad();
121
122
        $this->ipAddresses[] = $ipAddress;
123
        $this->db->execute("INSERT IGNORE INTO banned_ips (id, ban_id, ip_address) VALUES (NULL, ?, ?)", array($this->getId(), $ipAddress));
124
    }
125
126
    /**
127
     * Remove an IP from the ban
128
     *
129
     * @param string $ipAddress The IP to remove from the ban
130
     */
131 View Code Duplication
    public function removeIP($ipAddress)
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...
132
    {
133
        $this->lazyLoad();
134
135
        // Remove $ipAddress from $this->ipAddresses
136
        $this->ipAddresses = array_diff($this->ipAddresses, array($ipAddress));
137
        $this->db->execute("DELETE FROM banned_ips WHERE ban_id = ? AND ip_address = ?", array($this->getId(), $ipAddress));
138
    }
139
140
    /**
141
     * Set the IP addresses of the ban
142
     *
143
     * @todo   Is it worth making this faster?
144
     * @param  string[] $ipAddresses The new IP addresses of the ban
145
     * @return self
146
     */
147
    public function setIPs($ipAddresses)
148
    {
149
        $this->lazyLoad();
150
151
        $oldIPs = $this->ipAddresses;
152
        $this->ipAddresses = $ipAddresses;
153
154
        $newIPs     = array_diff($ipAddresses, $oldIPs);
155
        $removedIPs = array_diff($oldIPs, $ipAddresses);
156
157
        foreach ($newIPs as $ip) {
158
            $this->addIP($ip);
159
        }
160
161
        foreach ($removedIPs as $ip) {
162
            $this->removeIP($ip);
163
        }
164
165
        return $this;
166
    }
167
168
    /**
169
     * Check whether or not a player is allowed to join a server when they've been banned
170
     * @return bool Whether or not a player is allowed to join
171
     */
172
    public function allowedServerJoin()
173
    {
174
        return $this->allowServerJoin;
175
    }
176
177
    /**
178
     * Get the user who imposed the ban
179
     * @return Player The banner
180
     */
181
    public function getAuthor()
182
    {
183
        return Player::get($this->author);
184
    }
185
186
    /**
187
     * Get the creation time of the ban
188
     * @return TimeDate The creation time
189
     */
190
    public function getCreated()
191
    {
192
        return $this->created->copy();
193
    }
194
195
    /**
196
     * Get the expiration time of the ban
197
     * @return TimeDate
198
     */
199
    public function getExpiration()
200
    {
201
        return $this->expiration->copy();
202
    }
203
204
    /**
205
     * Get the ban's description
206
     * @return string
207
     */
208
    public function getReason()
209
    {
210
        return $this->reason;
211
    }
212
213
    /**
214
     * Get the ban summary that will appear when a player is denied access to a league server on join
215
     * @return string The ban summary
216
     */
217
    public function getServerMessage()
218
    {
219
        if ($this->allowedServerJoin()) {
220
            return '';
221
        }
222
223
        return $this->srvmsg;
224
    }
225
226
    /**
227
     * Get the IP address of the banned player
228
     * @return string[]
229
     */
230
    public function getIpAddresses()
231
    {
232
        $this->lazyLoad();
233
234
        return $this->ipAddresses;
235
    }
236
237
    /**
238
     * Get the time when the ban was last updated
239
     * @return TimeDate
240
     */
241
    public function getUpdated()
242
    {
243
        return $this->updated->copy();
244
    }
245
246
    /**
247
     * Get the player who was banned
248
     * @return Player The banned player
249
     */
250
    public function getVictim()
251
    {
252
        return Player::get($this->player);
253
    }
254
255
    /**
256
     * Get the ID of the player who was banned
257
     * @return int The ID of the victim of the ban
258
     */
259
    public function getVictimID()
260
    {
261
        return $this->player;
262
    }
263
264
    /**
265
     * Calculate whether a ban has expired or not.
266
     *
267
     * @return bool True if the ban's expiration time has already passed
268
     */
269
    public function isExpired()
270
    {
271
        if ($this->expiration === null) {
272
            return false;
273
        }
274
275
        return TimeDate::now()->gte($this->expiration);
276
    }
277
278
    /**
279
     * Check whether the ban will expire automatically
280
     *
281
     * @return bool
282
     */
283
    public function willExpire()
284
    {
285
        return $this->expiration !== null;
286
    }
287
288
    /**
289
     * Mark the ban as expired
290
     *
291
     * @return self
292
     */
293
    public function expire()
294
    {
295
        $this->setExpiration(TimeDate::now());
296
        $this->getVictim()->markAsUnbanned();
297
298
        return $this;
299
    }
300
301
    /**
302
     * Set the expiration date of the ban
303
     * @param  TimeDate $expiration The expiration
304 1
     * @return self
305
     */
306 1
    public function setExpiration($expiration)
307 1
    {
308
        if ($expiration !== null) {
309
            $expiration = TimeDate::from($expiration);
310 1
        }
311
312
        return $this->updateProperty($this->expiration, 'expiration', $expiration);
313
    }
314
315
    /**
316
     * Set the server message of the ban
317
     * @param  string $message The new server message
318
     * @return self
319
     */
320
    public function setServerMessage($message)
321
    {
322
        return $this->updateProperty($this->srvmsg, 'server_message', $message);
323
    }
324
325
    /**
326
     * Set the reason of the ban
327
     * @param  string $reason The new ban reason
328
     * @return self
329
     */
330
    public function setReason($reason)
331
    {
332
        return $this->updateProperty($this->reason, 'reason', $reason);
333
    }
334
335
    /**
336
     * Update the last edit timestamp
337
     * @return self
338
     */
339
    public function updateEditTimestamp()
340
    {
341
        return $this->updateProperty($this->updated, "updated", TimeDate::now());
342
    }
343
344
    /**
345
     * Set whether the ban's victim is allowed to enter a match server
346
     * @param  bool $allowServerJoin
347
     * @return self
348
     */
349
    public function setAllowServerJoin($allowServerJoin)
350
    {
351
        return $this->updateProperty($this->allowServerJoin, 'allow_server_join', (bool) $allowServerJoin);
352
    }
353
354
    /**
355
     * Add a new ban
356
     *
357
     * @param int         $playerID        The ID of the victim of the ban
358
     * @param int         $authorID        The ID of the player responsible for the ban
359
     * @param mixed|null $expiration      The expiration of the ban (set to NULL so that it never expires)
360
     * @param string      $reason          The full reason for the ban
361
     * @param string      $srvmsg          A summary of the ban to be displayed on server banlists (max 150 characters)
362
     * @param string[]    $ipAddresses     An array of IPs that have been banned
363
     * @param bool        $allowServerJoin Whether or not the player is allowed to join match servers
364
     *
365 2
     * @return Ban An object representing the ban that was just entered or false if the ban was not created
366
     */
367 2
    public static function addBan($playerID, $authorID, $expiration, $reason, $srvmsg = "", $ipAddresses = array(), $allowServerJoin = false)
368
    {
369 2
        $player = Player::get($playerID);
370 1
371
        if ($expiration !== null) {
372 1
            $expiration = TimeDate::from($expiration)->toMysql();
373
        } else {
374
            $player->markAsBanned();
375
        }
376 2
377 2
        // If there are no IPs to banned or no server ban message, then we'll allow the players to join as observers
378
        if (empty($srvmsg) || empty($ipAddresses)) {
379
            $allowServerJoin = true;
380 2
        }
381 2
382 2
        $ban = self::create(array(
383 2
            'player'            => $playerID,
384 2
            'expiration'        => $expiration,
385 2
            'server_message'    => $srvmsg,
386 2
            'reason'            => $reason,
387 2
            'allow_server_join' => $allowServerJoin,
388
            'author'            => $authorID,
389 2
        ), array('created', 'updated'));
390 2
391 2
        if (is_array($ipAddresses)) {
392
            foreach ($ipAddresses as $ip) {
393
                $ban->addIP($ip);
394
            }
395
        } else {
396
            $ban->addIP($ipAddresses);
397 2
        }
398
399
        return $ban;
400
    }
401
402
    /**
403
     * Get a query builder for news
404
     * @return QueryBuilder
405
     */
406
    public static function getQueryBuilder()
407
    {
408
        return new QueryBuilder('Ban', array(
409
            'columns' => array(
410
                'status'  => 'status',
411
                'updated' => 'updated'
412
            ),
413
        ));
414
    }
415
416
    /**
417
     * {@inheritdoc}
418
     */
419
    public function getName()
420
    {
421
        return 'Ban against ' . $this->getVictim()->getUsername();
422
    }
423
424
    /**
425
     * {@inheritdoc}
426
     */
427
    public function delete()
428
    {
429
        $this->getVictim()->markAsUnbanned();
430
        parent::delete();
431
    }
432
433
    /**
434
     * {@inheritdoc}
435
     */
436
    public static function getLazyColumns()
437
    {
438
        return null;
439
    }
440
441
    /**
442
     * Get all the bans in the database that aren't disabled or deleted
443
     * @return Ban[] An array of ban objects
444
     */
445
    public static function getBans()
446
    {
447
        return self::arrayIdToModel(self::fetchIds("ORDER BY updated DESC"));
448
    }
449
450
    /**
451
     * Get an active ban for the player
452
     * @param  int      $playerId The player's ID
453
     * @return Ban|null null if the player isn't currently banned
454
     */
455
    public static function getBan($playerId)
456
    {
457
        $bans = self::fetchIdsFrom('player', array($playerId), false, "AND (expiration IS NULL OR expiration > UTC_TIMESTAMP())");
458
459
        if (empty($bans)) {
460
            return null;
461 76
        }
462
463 76
        return self::get($bans[0]);
464
    }
465
}
466