Failed Conditions
Push — newinternal ( b66232...216d62 )
by Simon
16:33 queued 06:35
created

PageViewRequest::setupUsernameData()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 16
ccs 0
cts 0
cp 0
crap 6
rs 9.7333
c 0
b 0
f 0
1
<?php
2
/******************************************************************************
3
 * Wikipedia Account Creation Assistance tool                                 *
4
 *                                                                            *
5
 * All code in this file is released into the public domain by the ACC        *
6
 * Development Team. Please see team.json for a list of contributors.         *
7
 ******************************************************************************/
8
9
namespace Waca\Pages;
10
11
use Exception;
12
use Waca\DataObjects\Comment;
13
use Waca\DataObjects\EmailTemplate;
14
use Waca\DataObjects\JobQueue;
15
use Waca\DataObjects\Log;
16
use Waca\DataObjects\Request;
17
use Waca\DataObjects\User;
18
use Waca\Exceptions\ApplicationLogicException;
19
use Waca\Fragments\RequestData;
20
use Waca\Helpers\LogHelper;
21
use Waca\Helpers\SearchHelpers\UserSearchHelper;
22
use Waca\PdoDatabase;
23
use Waca\Tasks\InternalPageBase;
24
use Waca\WebRequest;
25
26
class PageViewRequest extends InternalPageBase
27
{
28
    use RequestData;
29
    const STATUS_SYMBOL_OPEN = '&#x2610';
30
    const STATUS_SYMBOL_ACCEPTED = '&#x2611';
31
    const STATUS_SYMBOL_REJECTED = '&#x2612';
32
33
    /**
34
     * Main function for this page, when no specific actions are called.
35
     * @throws ApplicationLogicException
36
     */
37
    protected function main()
38
    {
39
        // set up csrf protection
40
        $this->assignCSRFToken();
41
42
        // get some useful objects
43
        $database = $this->getDatabase();
44
        $request = $this->getRequest($database, WebRequest::getInt('id'));
45
        $config = $this->getSiteConfiguration();
46
        $currentUser = User::getCurrent($database);
47
48
        // Test we should be able to look at this request
49
        if ($config->getEmailConfirmationEnabled()) {
50
            if ($request->getEmailConfirm() !== 'Confirmed') {
51
                // Not allowed to look at this yet.
52
                throw new ApplicationLogicException('The email address has not yet been confirmed for this request.');
53
            }
54
        }
55
56
        $this->setupBasicData($request, $config);
57
58
        $this->setupUsernameData($request);
59
60
        $this->setupTitle($request);
61
62
        $this->setupReservationDetails($request->getReserved(), $database, $currentUser);
63
        $this->setupGeneralData($database);
64
65
        $this->assign('requestDataCleared', false);
66
        if ($request->getEmail() === $this->getSiteConfiguration()->getDataClearEmail()) {
67
            $this->assign('requestDataCleared', true);
68
        }
69
70
        $allowedPrivateData = $this->isAllowedPrivateData($request, $currentUser);
71
72
        $this->setupCreationTypes($currentUser);
73
74
        $this->setupLogData($request, $database);
75
76
        if ($allowedPrivateData) {
77
            $this->setTemplate('view-request/main-with-data.tpl');
78
            $this->setupPrivateData($request, $currentUser, $this->getSiteConfiguration(), $database);
79
80
            $this->assign('canSetBan', $this->barrierTest('set', $currentUser, PageBan::class));
81
            $this->assign('canSeeCheckuserData', $this->barrierTest('seeUserAgentData', $currentUser, 'RequestData'));
82
83
            if ($this->barrierTest('seeUserAgentData', $currentUser, 'RequestData')) {
84
                $this->setTemplate('view-request/main-with-checkuser-data.tpl');
85
                $this->setupCheckUserData($request);
86
            }
87
        }
88
        else {
89
            $this->setTemplate('view-request/main.tpl');
90
        }
91
92
        /** @noinspection JSUnusedGlobalSymbols */
93
        $this->setTailScript(<<<'JS'
94
    var $requestLogs = $('#requestLog');
95
    $requestLogs.scrollTop($requestLogs[0].scrollHeight);
96
    
97
    function changeCreateMode(selectedButton) {
98
        if(selectedButton.value === "manual") {
99
            $("#createManual").show();
100
            $("#createOauth").hide();
101
            $("#createBot").hide();
102
        }
103
        if(selectedButton.value === "oauth") {
104
            $("#createManual").hide();
105
            $("#createOauth").show();
106
            $("#createBot").hide();
107
        }
108
        if(selectedButton.value === "bot") {
109
            $("#createManual").hide();
110
            $("#createOauth").hide();
111
            $("#createBot").show();
112
        }
113
    }
114
JS
115
        );
116
    }
117
118
    /**
119
     * @param Request $request
120
     */
121
    protected function setupTitle(Request $request)
122
    {
123
        $statusSymbol = self::STATUS_SYMBOL_OPEN;
124
        if ($request->getStatus() === 'Closed') {
125
            if ($request->getWasCreated()) {
126
                $statusSymbol = self::STATUS_SYMBOL_ACCEPTED;
127
            }
128
            else {
129
                $statusSymbol = self::STATUS_SYMBOL_REJECTED;
130
            }
131
        }
132
133
        $this->setHtmlTitle($statusSymbol . ' #' . $request->getId());
134
    }
135
136
    /**
137
     * Sets up data unrelated to the request, such as the email template information
138
     *
139
     * @param PdoDatabase $database
140
     */
141
    protected function setupGeneralData(PdoDatabase $database)
142
    {
143
        $config = $this->getSiteConfiguration();
144
145
        $this->assign('createAccountReason', 'Requested account at [[WP:ACC]], request #');
146
147
        $this->assign('defaultRequestState', $config->getDefaultRequestStateKey());
148
149
        $this->assign('requestStates', $config->getRequestStates());
150
151
        /** @var EmailTemplate $createdTemplate */
152
        $createdTemplate = EmailTemplate::getById($config->getDefaultCreatedTemplateId(), $database);
153
154
        $this->assign('createdHasJsQuestion', $createdTemplate->getJsquestion() != '');
155
        $this->assign('createdJsQuestion', $createdTemplate->getJsquestion());
156
        $this->assign('createdId', $createdTemplate->getId());
157
        $this->assign('createdName', $createdTemplate->getName());
158
159
        $createReasons = EmailTemplate::getActiveTemplates(EmailTemplate::CREATED, $database);
160
        $this->assign("createReasons", $createReasons);
161
        $declineReasons = EmailTemplate::getActiveTemplates(EmailTemplate::NOT_CREATED, $database);
162
        $this->assign("declineReasons", $declineReasons);
163
164
        $allCreateReasons = EmailTemplate::getAllActiveTemplates(EmailTemplate::CREATED, $database);
165
        $this->assign("allCreateReasons", $allCreateReasons);
166
        $allDeclineReasons = EmailTemplate::getAllActiveTemplates(EmailTemplate::NOT_CREATED, $database);
167
        $this->assign("allDeclineReasons", $allDeclineReasons);
168
        $allOtherReasons = EmailTemplate::getAllActiveTemplates(false, $database);
169
        $this->assign("allOtherReasons", $allOtherReasons);
170
171
        $this->getTypeAheadHelper()->defineTypeAheadSource('username-typeahead', function() use ($database) {
172
            return UserSearchHelper::get($database)->byStatus('Active')->fetchColumn('username');
173
        });
174
    }
175
176
    private function setupLogData(Request $request, PdoDatabase $database)
177
    {
178
        $currentUser = User::getCurrent($database);
179
180
        $logs = LogHelper::getRequestLogsWithComments($request->getId(), $database, $this->getSecurityManager());
181
        $requestLogs = array();
182
183
        if (trim($request->getComment()) !== "") {
184
            $requestLogs[] = array(
185
                'type'     => 'comment',
186
                'security' => 'user',
187
                'userid'   => null,
188
                'user'     => $request->getName(),
189
                'entry'    => null,
190
                'time'     => $request->getDate(),
191
                'canedit'  => false,
192
                'id'       => $request->getId(),
193
                'comment'  => $request->getComment(),
194
            );
195
        }
196
197
        /** @var User[] $nameCache */
198
        $nameCache = array();
199
200
        $editableComments = $this->barrierTest('editOthers', $currentUser, PageEditComment::class);
201
202
        /** @var Log|Comment $entry */
203
        foreach ($logs as $entry) {
204
            // both log and comment have a 'user' field
205
            if (!array_key_exists($entry->getUser(), $nameCache)) {
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Waca\DataObject as the method getUser() does only exist in the following sub-classes of Waca\DataObject: Waca\DataObjects\Ban, Waca\DataObjects\Comment, Waca\DataObjects\Log, Waca\DataObjects\UserRole. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
206
                $entryUser = User::getById($entry->getUser(), $database);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Waca\DataObject as the method getUser() does only exist in the following sub-classes of Waca\DataObject: Waca\DataObjects\Ban, Waca\DataObjects\Comment, Waca\DataObjects\Log, Waca\DataObjects\UserRole. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
207
                $nameCache[$entry->getUser()] = $entryUser;
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Waca\DataObject as the method getUser() does only exist in the following sub-classes of Waca\DataObject: Waca\DataObjects\Ban, Waca\DataObjects\Comment, Waca\DataObjects\Log, Waca\DataObjects\UserRole. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
208
            }
209
210
            if ($entry instanceof Comment) {
211
                $requestLogs[] = array(
212
                    'type'     => 'comment',
213
                    'security' => $entry->getVisibility(),
214
                    'user'     => $nameCache[$entry->getUser()]->getUsername(),
215
                    'userid'   => $entry->getUser() == -1 ? null : $entry->getUser(),
216
                    'entry'    => null,
217
                    'time'     => $entry->getTime(),
218
                    'canedit'  => ($editableComments || $entry->getUser() == $currentUser->getId()),
219
                    'id'       => $entry->getId(),
220
                    'comment'  => $entry->getComment(),
221
                );
222
            }
223
224
            if ($entry instanceof Log) {
225
                $invalidUserId = $entry->getUser() === -1 || $entry->getUser() === 0;
226
                $entryUser = $invalidUserId ? User::getCommunity() : $nameCache[$entry->getUser()];
227
228
                $entryComment = $entry->getComment();
229
230
                if($entry->getAction() === 'JobIssueRequest' || $entry->getAction() === 'JobCompletedRequest'){
231
                    $data = unserialize($entry->getComment());
232
                    /** @var JobQueue $job */
233
                    $job = JobQueue::getById($data['job'], $database);
234
                    $requestLogs[] = array(
235
                        'type'     => 'joblog',
236
                        'security' => 'user',
237
                        'userid'   => $entry->getUser() == -1 ? null : $entry->getUser(),
238
                        'user'     => $entryUser->getUsername(),
239
                        'entry'    => LogHelper::getLogDescription($entry),
240
                        'time'     => $entry->getTimestamp(),
241
                        'canedit'  => false,
242
                        'id'       => $entry->getId(),
243
                        'jobId'    => $job->getId(),
244
                        'jobDesc'  => JobQueue::getTaskDescriptions()[$job->getTask()],
245
                    );
246
                } else {
247
                    $requestLogs[] = array(
248
                        'type'     => 'log',
249
                        'security' => 'user',
250
                        'userid'   => $entry->getUser() == -1 ? null : $entry->getUser(),
251
                        'user'     => $entryUser->getUsername(),
252
                        'entry'    => LogHelper::getLogDescription($entry),
253
                        'time'     => $entry->getTimestamp(),
254
                        'canedit'  => false,
255
                        'id'       => $entry->getId(),
256
                        'comment'  => $entryComment,
257
                    );
258
                }
259
            }
260
        }
261
262
        $this->assign("requestLogs", $requestLogs);
263
    }
264
265
    /**
266
     * @param Request $request
267
     */
268
    protected function setupUsernameData(Request $request)
269
    {
270
        $blacklistData = $this->getBlacklistHelper()->isBlacklisted($request->getName());
271
272
        $this->assign('requestIsBlacklisted', $blacklistData !== false);
273
        $this->assign('requestBlacklist', $blacklistData);
274
275
        try {
276
            $spoofs = $this->getAntiSpoofProvider()->getSpoofs($request->getName());
277
        }
278
        catch (Exception $ex) {
279
            $spoofs = $ex->getMessage();
280
        }
281
282
        $this->assign("spoofs", $spoofs);
283
    }
284
285
    private function setupCreationTypes(User $user)
286
    {
287
        $this->assign('canManualCreate',
288
            $this->barrierTest(User::CREATION_MANUAL, $user, 'RequestCreation'));
289
        $this->assign('canOauthCreate',
290
            $this->barrierTest(User::CREATION_OAUTH, $user, 'RequestCreation'));
291
        $this->assign('canBotCreate',
292
            $this->barrierTest(User::CREATION_BOT, $user, 'RequestCreation'));
293
    }
294
}
295