Passed
Branch dev (4bd34d)
by Bob
02:19
created

authCheck::checkPermissions()   D

Complexity

Conditions 30
Paths 116

Size

Total Lines 91
Code Lines 56

Duplication

Lines 13
Ratio 14.29 %

Importance

Changes 0
Metric Value
cc 30
eloc 56
nc 116
nop 0
dl 13
loc 91
rs 4.3115
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * The MIT License (MIT)
4
 *
5
 * Copyright (c) 2016 Robert Sardinia
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
 * of this software and associated documentation files (the "Software"), to deal
9
 * in the Software without restriction, including without limitation the rights
10
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 * copies of the Software, and to permit persons to whom the Software is
12
 * furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included in all
15
 * copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
 * SOFTWARE.
24
 */
25
26
27
/**
28
 * Class fileAuthCheck
29
 * @property int nextCheck
30
 */
31
class authCheck
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
32
{
33
34
    /**
35
     * @var
36
     */
37
    private $config;
38
    private $db;
39
    private $dbUser;
40
    private $dbPass;
41
    private $dbName;
42
    private $guildID;
43
    private $corpTickers;
44
    private $authGroups;
45
    private $exempt;
46
    private $alertChannel;
47
    private $guild;
48
    private $nameEnforce;
49
    private $standingsBased;
50
    private $nameCheck;
51
    private $apiKey;
52
    private $discord;
53
    private $logger;
54
55
    /**
56
     * @param $config
57
     * @param $discord
58
     * @param $logger
59
     */
60
    public function init($config, $discord, $logger)
61
    {
62
        $this->config = $config;
63
        $this->discord = $discord;
64
        $this->logger = $logger;
65
        $this->db = $config['database']['host'];
66
        $this->dbUser = $config['database']['user'];
67
        $this->dbPass = $config['database']['pass'];
68
        $this->dbName = $config['database']['database'];
69
        $this->guildID = $config['bot']['guild'];
70
        $this->exempt = $config['plugins']['auth']['exempt'];
71
        $this->corpTickers = $config['plugins']['auth']['corpTickers'];
72
        $this->nameEnforce = $config['plugins']['auth']['nameEnforce'];
73
        $this->standingsBased = $config['plugins']['auth']['standings']['enabled'];
74
        $this->apiKey = $config['eve']['apiKeys'];
75
        $this->authGroups = $config['plugins']['auth']['authGroups'];
76
        $this->alertChannel = $config['plugins']['auth']['alertChannel'];
77
        $this->guild = $config['bot']['guild'];
78
        $this->nextCheck = 0;
79
80
        //Set name check to happen if corpTicker or nameEnforce is set
81
        if ($this->nameEnforce === 'true' || $this->corpTickers === 'true') {
82
            $this->nameCheck = 'true';
83
        }
84
85
        //check if cache has been set
86
        $permsChecked = getPermCache('permsLastChecked');
87
        $namesChecked = getPermCache('nextRename');
88
        if ($namesChecked === NULL) {
89
            setPermCache('nextRename', time());
90
        }
91
92
        //if not set set for now (30 minutes from now for role removal)
93
        if ($permsChecked === NULL) {
94
            setPermCache('permsLastChecked', time() - 5);
95
            setPermCache('authStateLastChecked', time() + 7200);
96
        }
97
    }
98
99
    public function tick()
100
    {
101
        // What was the servers last reported state
102
        $lastStatus = getPermCache('serverState');
103
        if ($lastStatus === 'online') {
104
            $permsChecked = getPermCache('permsLastChecked');
105
            $stateChecked = getPermCache('authStateLastChecked');
106
            $namesChecked = getPermCache('nextRename');
107
            $standingsChecked = getPermCache('nextStandingsCheck');
108
109
            if ($permsChecked <= time()) {
110
                $this->logger->addInfo('AuthCheck: Checking for users who have left corp/alliance....');
111
                $this->checkPermissions();
112
                $this->logger->addInfo('AuthCheck: Corp/alliance check complete.');
113
            }
114
115
            if ($stateChecked <= time()) {
116
                $this->logger->addInfo('AuthCheck: Checking for users who have been wrongly given roles....');
117
                $this->checkAuthState();
118
                $this->logger->addInfo('AuthCheck: Role check complete.');
119
            }
120
121
            if ($this->nameCheck === 'true' && $namesChecked <= time()) {
122
                $this->logger->addInfo('AuthCheck: Resetting player names....');
123
                $this->nameReset();
124
                $this->logger->addInfo('AuthCheck: Names reset.');
125
            }
126
127
            if ($this->standingsBased === 'true' && $standingsChecked <= time()) {
128
                $this->logger->addInfo('AuthCheck: Updating Standings');
129
                $this->standingsUpdate();
130
                $this->logger->addInfo('AuthCheck: Standings Updated');
131
            }
132
        }
133
    }
134
135
    /**
136
     * @return null
137
     */
138
139
    //Remove members who have roles but never authed
140
    private function checkPermissions()
141
    {
142
        //Get guild object
143
        $guild = $this->discord->guilds->get('id', $this->guildID);
144
145
        //Establish connection to mysql
146
        $conn = new mysqli($this->db, $this->dbUser, $this->dbPass, $this->dbName);
147
148
        $sql = "SELECT characterID, discordID, eveName, role FROM authUsers WHERE active='yes'";
149
150
        $result = $conn->query($sql);
151
152
        //Set empty arrays
153
        $corpArray = array();
154
        $allianceArray = array();
155
156
        // If config is outdated
157 View Code Duplication
        if (null === $this->authGroups) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
158
            $msg = '**Auth Failure:** Please update the bots config to the latest version.';
159
            queueMessage($msg, $this->alertChannel, $this->guild);
160
            $nextCheck = time() + 10800;
161
            setPermCache('permsLastChecked', $nextCheck);
162
            return null;
163
        }
164
165
        //Set corp/ally id arrays
166
        foreach ($this->authGroups as $authGroup) {
167
            if ($authGroup['corpID'] !== 0) {
168
                $corpArray[] = (int)$authGroup['corpID'];
169
            }
170
            if ($authGroup['allianceID'] !== 0) {
171
                $allianceArray[] = (int)$authGroup['allianceID'];
172
            }
173
        }
174
175
        if ($result->num_rows >= 1) {
176
            while ($rows = $result->fetch_assoc()) {
177
                $charID = $rows['characterID'];
178
                $discordID = $rows['discordID'];
179
                $role = $rows['role'];
180
                $member = $guild->members->get('id', $discordID);
181
                $eveName = $rows['eveName'];
182
                //Check if member has roles
183
                if (null === @$member->roles) {
184
                    continue;
185
                }
186
187
                //Auth things
188
                $character = characterDetails($charID);
189
                //if issue with esi, skip
190
                if (null === $character) {
191
                    continue;
192
                }
193
                $corporationID = $character['corporation_id'];
194
                $corporationDetails = corpDetails($corporationID);
195
                if (null === $corporationDetails) {
196
                    continue;
197
                }
198
                $allianceID = @$corporationDetails['alliance_id'];
199
200
                //check if user authed based on standings
201
                $standings = null;
202
                if ($role === 'blue' || 'neut' || 'red') {
203
                    $allianceContacts = getContacts($allianceID);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $allianceContacts is correct as getContacts($allianceID) (which targets getContacts()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
204
                    $corpContacts = getContacts($corporationID);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $corpContacts is correct as getContacts($corporationID) (which targets getContacts()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
205 View Code Duplication
                    if ($role === 'blue' && ($allianceContacts['standings'] || $corpContacts['standings'] === 5 || 10)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
206
                        $standings = 1;
207
                    }
208 View Code Duplication
                    if ($role === 'red' && ($allianceContacts['standings'] || $corpContacts['standings'] === -5 || -10)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
209
                        $standings = 1;
210
                    }
211
                    if ($role === 'neut' && ($allianceContacts['standings'] || $corpContacts['standings'] === 0 || (@(int)$allianceContacts['standings'] && @(int)$corpContacts['standings'] === null || ''))) {
212
                        $standings = 1;
213
                    }
214
                }
215
                if (!in_array((int)$allianceID, $allianceArray) && !in_array((int)$corporationID, $corpArray) && null === $standings) {
216
                    // Deactivate user in database
217
                    $sql = "UPDATE authUsers SET active='no' WHERE discordID='$discordID'";
218
                    $this->logger->addInfo("AuthCheck: {$eveName} account has been deactivated as they are no longer in a correct corp/alliance.");
219
                    $conn->query($sql);
220
                    continue;
221
                }
222
            }
223
            $nextCheck = time() + 10800;
224
            setPermCache('permsLastChecked', $nextCheck);
225
            return null;
226
        }
227
        $nextCheck = time() + 10800;
228
        setPermCache('permsLastChecked', $nextCheck);
229
        return null;
230
    }
231
232
    //Check user corp/alliance affiliation
233
234
235
    private function checkAuthState()
236
    {
237
238
        //Check if exempt roles are set
239
        if (null === $this->exempt) {
240
            $this->exempt = '0';
241
        }
242
243
        // If config is outdated
244 View Code Duplication
        if (null === $this->authGroups) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
245
            $msg = '**Auth Failure:** Please update the bots config to the latest version.';
246
            queueMessage($msg, $this->alertChannel, $this->guild);
247
            //queue up next check
248
            $nextCheck = time() + 1800;
249
            setPermCache('authStateLastChecked', $nextCheck);
250
            return null;
251
        }
252
253
        //Establish connection to mysql
254
        $conn = new mysqli($this->db, $this->dbUser, $this->dbPass, $this->dbName);
255
256
        //get bot ID so we don't remove out own roles
257
        $botID = $this->discord->id;
258
259
        //Get guild object
260
        $guild = $this->discord->guilds->get('id', $this->guildID);
261
262
        //Check to make sure guildID is set correctly
263
        if (null === $guild) {
264
            $this->logger->addError('Config Error: Ensure the guild entry in the config is the guildID (aka serverID) for the main server that the bot is in.');
265
            $nextCheck = time() + 7200;
266
            setPermCache('authLastChecked', $nextCheck);
267
            return null;
268
        }
269
270
        //create empty array to store names
271
        $removedRoles = array();
272
        $userCount = 0;
273
274
        //Perform check if roles were added without permission
275
        foreach ($guild->members as $member) {
276
            $id = $member->id;
277
            $username = $member->username;
278
            $roles = $member->roles;
279
280
            //Skip to next member if this user has no roles
281
            if (null === $roles) {
282
                continue;
283
            }
284
            $sql = "SELECT * FROM authUsers WHERE discordID='$id' AND active='yes'";
285
            $result = $conn->query($sql);
286
287
            //If they are NOT active in the db, check for roles to remove
288
            if ($result->num_rows === 0) {
289
                $userCount++;
290
                foreach ($roles as $role) {
291
                    if ($id !== $botID && !in_array($role->name, $this->exempt, true)) {
292
                        $member->removeRole($role);
293
                        $guild->members->save($member);
294
                        // Add users name to array
295
                        if (!in_array($username, $removedRoles)) {
296
                            $removedRoles[] = $username;
297
                        }
298
                    }
299
                }
300
            }
301
        }
302
        //Report removed users to log and channel
303
        $nameList = implode(', ', $removedRoles);
304
        if ($userCount > 0 && strlen($nameList) > 3 && null !== $nameList) {
305
            $msg = "Following users roles have been removed - {$nameList}";
306
            queueMessage($msg, $this->alertChannel, $this->guild);
307
            $this->logger->addInfo("AuthCheck: Roles removed from {$nameList}");
308
        }
309
        //queue up next check
310
        $nextCheck = time() + 1800;
311
        setPermCache('authStateLastChecked', $nextCheck);
312
        return null;
313
    }
314
315
    private function nameReset()
316
    {
317
        //Get guild object
318
        $guild = $this->discord->guilds->get('id', $this->guildID);
319
320
        //Get name queue status
321
        $x = (int)getPermCache('nameQueueState');
322
323
        //Establish connection to mysql
324
        $conn = new mysqli($this->db, $this->dbUser, $this->dbPass, $this->dbName);
325
        $sql = "SELECT id FROM authUsers WHERE active='yes'";
326
        $count = $conn->query($sql);
327
        $rowAmount = round($count->num_rows / 2);
328
        if ($x === 1) {
329
            $sql = "SELECT characterID, discordID, eveName  FROM authUsers WHERE active='yes' ORDER BY id ASC LIMIT {$rowAmount} OFFSET {$rowAmount}";
330
            setPermCache('nameQueueState', 0);
331
        } else {
332
            $sql = "SELECT characterID, discordID, eveName  FROM authUsers WHERE active='yes' ORDER BY id ASC LIMIT {$rowAmount}";
333
            setPermCache('nameQueueState', 1);
334
        }
335
        $result = $conn->query($sql);
336
337
        // If config is outdated
338 View Code Duplication
        if (null === $this->authGroups) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
339
            $msg = '**Auth Failure:** Please update the bots config to the latest version.';
340
            queueMessage($msg, $this->alertChannel, $this->guild);
341
            $nextCheck = time() + 1800;
342
            setPermCache('nextRename', $nextCheck);
343
            return null;
344
        }
345
346
        if (@$result->num_rows >= 1) {
347
            while ($rows = $result->fetch_assoc()) {
348
                $charID = $rows['characterID'];
349
                $discordID = $rows['discordID'];
350
                $member = $guild->members->get('id', $discordID);
351
                $eveName = $rows['eveName'];
352
                //Check if member has roles
353
                if (null === @$member->roles) {
354
                    continue;
355
                }
356
357
                //Get current nickname
358
                $guild = $this->discord->guilds->get('id', $this->guildID);
359
                $member = $guild->members->get('id', $discordID);
360
                $nickName = $member->nick;
361
                $userName = $member->user->username;
362
                //If nick isn't set than make it username
363
                if ($nickName === '' || null === $nickName) {
364
                    $nickName = $userName;
365
                }
366
367
                //Check for bad tickers
368
                if (strpos($nickName, '[U]') !== false) {
369
                    $nickName = str_replace('[U]', '', $nickName);
370
                    queueRename($discordID, $nickName, $this->guildID);
371
                    continue;
372
                }
373
374
                //corp ticker
375
                if ($this->corpTickers === 'true') {
376
                    $character = characterDetails($charID);
377
                    if (null === $character['corporation_id']) {
378
                        continue;
379
                    }
380
                    $corpInfo = getCorpInfo($character['corporation_id']);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $corpInfo is correct as getCorpInfo($character['corporation_id']) (which targets getCorpInfo()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
381
                    //Clean bad entries
382
                    if (@$corpInfo['corpTicker'] === 'U') {
383
                        deleteCorpInfo(@$corpInfo['corpID']);
384
                    }
385
                    $nick = null;
386 View Code Duplication
                    if (null !== @$corpInfo['corpTicker']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
387
                        $corpTicker = (string)$corpInfo['corpTicker'];
388
                        if ($this->nameEnforce === 'true') {
389
                            $nick = "[{$corpTicker}] {$eveName}";
390
                        } elseif ((string)$nickName === "[{$corpTicker}]") {
391
                            $nick = "[{$corpTicker}] {$userName}";
392
                        } elseif (strpos($nickName, $corpTicker) === false) {
393
                            $nick = "[{$corpTicker}] {$nickName}";
394
                        } elseif (strpos($nickName, $corpTicker) !== false) {
395
                            continue;
396
                        }
397
                        if ($nick !== $nickName) {
398
                            queueRename($discordID, $nick, $this->guildID);
399
                        }
400
                        continue;
401
                    }
402
                    $corporationDetails = corpDetails($character['corporation_id']);
403
                    if (null === $corporationDetails) {
404
                        continue;
405
                    }
406
                    $corpTicker = $corporationDetails['ticker'];
407
                    //Check for bad tickers (ESI ERROR?)
408
                    if (@$corpTicker === 'U') {
409
                        continue;
410
                    }
411
                    $corpName = (string)$corporationDetails['corporation_name'];
412 View Code Duplication
                    if (null !== $corpTicker) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
413
                        if ($this->nameEnforce === 'true') {
414
                            $nick = "[{$corpTicker}] {$eveName}";
415
                        } elseif ((string)$nickName === "[{$corpTicker}]") {
416
                            $nick = "[{$corpTicker}] {$userName}";
417
                        } elseif (strpos($nickName, $corpTicker) === false) {
418
                            $nick = "[{$corpTicker}] {$nickName}";
419
                        } elseif (strpos($nickName, $corpTicker) !== false) {
420
                            continue;
421
                        }
422
                        if ($nick !== $nickName) {
423
                            queueRename($discordID, $nick, $this->guildID);
424
                            addCorpInfo($character['corporation_id'], $corpTicker, $corpName);
425
                        }
426
                        continue;
427
                    }
428
                    continue;
429
                }
430
                $nick = "{$eveName}";
431
                if ($nick !== $nickName) {
432
                    queueRename($discordID, $nick, $this->guildID);
433
                }
434
                continue;
435
            }
436
            $nextCheck = time() + 1800;
437
            setPermCache('nextRename', $nextCheck);
438
            return null;
439
        }
440
        $nextCheck = time() + 1800;
441
        setPermCache('nextRename', $nextCheck);
442
        return null;
443
444
    }
445
446
    private function standingsUpdate()
447
    {
448
        foreach ($this->apiKey as $apiKey) {
449
            if ((string)$apiKey['keyID'] === (string)$this->config['plugins']['auth']['standings']['apiKey']) {
450
                $url = "https://api.eveonline.com/char/ContactList.xml.aspx?keyID={$apiKey['keyID']}&vCode={$apiKey['vCode']}&characterID={$apiKey['characterID']}";
451
                $xml = makeApiRequest($url);
452
                if (empty($xml)) {
453
                    return null;
454
                }
455
                foreach ($xml->result->rowset as $contactType) {
456
                    if ((string)$contactType->attributes()->name === 'corporateContactList' || 'allianceContactList') {
457
                        foreach ($contactType->row as $contact) {
458
                            if (null !== $contact['contactID'] && $contact['contactName'] && $contact['standing']) {
459
                                addContactInfo($contact['contactID'], $contact['contactName'], $contact['standing']);
460
                            }
461
                        }
462
                    }
463
                }
464
            }
465
        }
466
        $nextCheck = time() + 86400;
467
        setPermCache('nextStandingsCheck', $nextCheck);
468
    }
469
}
470