Failed Conditions
Pull Request — newinternal-bugfixing (#286)
by Simon
06:57 queued 03:32
created

PageViewRequest::allowEditingComments()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 6
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 11
ccs 0
cts 9
cp 0
crap 12
rs 9.4285
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\Log;
15
use Waca\DataObjects\Request;
16
use Waca\DataObjects\User;
17
use Waca\Exceptions\ApplicationLogicException;
18
use Waca\Fragments\RequestData;
19
use Waca\Helpers\LogHelper;
20
use Waca\Helpers\SearchHelpers\UserSearchHelper;
21
use Waca\PdoDatabase;
22
use Waca\Tasks\InternalPageBase;
23
use Waca\WebRequest;
24
25
class PageViewRequest extends InternalPageBase
26
{
27
    use RequestData;
28
    const STATUS_SYMBOL_OPEN = '&#x2610';
29
    const STATUS_SYMBOL_ACCEPTED = '&#x2611';
30
    const STATUS_SYMBOL_REJECTED = '&#x2612';
31
32
    /**
33
     * Main function for this page, when no specific actions are called.
34
     * @throws ApplicationLogicException
35
     */
36
    protected function main()
37
    {
38
        // set up csrf protection
39
        $this->assignCSRFToken();
40
41
        // get some useful objects
42
        $database = $this->getDatabase();
43
        $request = $this->getRequest($database, WebRequest::getInt('id'));
44
        $config = $this->getSiteConfiguration();
45
        $currentUser = User::getCurrent($database);
46
47
        // Test we should be able to look at this request
48
        if ($config->getEmailConfirmationEnabled()) {
49
            if ($request->getEmailConfirm() !== 'Confirmed') {
50
                // Not allowed to look at this yet.
51
                throw new ApplicationLogicException('The email address has not yet been confirmed for this request.');
52
            }
53
        }
54
55
        $this->setupBasicData($request, $config);
56
57
        $this->setupUsernameData($request);
58
59
        $this->setupTitle($request);
60
61
        $this->setupReservationDetails($request->getReserved(), $database, $currentUser);
62
        $this->setupGeneralData($database);
63
64
        $this->assign('requestDataCleared', false);
65
        if ($request->getEmail() === $this->getSiteConfiguration()->getDataClearEmail()) {
66
            $this->assign('requestDataCleared', true);
67
        }
68
69
        $allowedPrivateData = $this->isAllowedPrivateData($request, $currentUser);
70
71
        $this->setupLogData($request, $database);
72
73
        if ($allowedPrivateData) {
74
            $this->setTemplate('view-request/main-with-data.tpl');
75
            $this->setupPrivateData($request, $currentUser, $this->getSiteConfiguration(), $database);
76
77
            $this->assign('canSetBan', $this->barrierTest('set', $currentUser, PageBan::class));
78
            $this->assign('canSeeCheckuserData', $this->barrierTest('seeUserAgentData', $currentUser, 'RequestData'));
79
80
            if ($this->barrierTest('seeUserAgentData', $currentUser, 'RequestData')) {
81
                $this->setTemplate('view-request/main-with-checkuser-data.tpl');
82
                $this->setupCheckUserData($request);
83
            }
84
        }
85
        else {
86
            $this->setTemplate('view-request/main.tpl');
87
        }
88
    }
89
90
    /**
91
     * @param Request $request
92
     */
93
    protected function setupTitle(Request $request)
94
    {
95
        $statusSymbol = self::STATUS_SYMBOL_OPEN;
96
        if ($request->getStatus() === 'Closed') {
97
            if ($request->getWasCreated()) {
98
                $statusSymbol = self::STATUS_SYMBOL_ACCEPTED;
99
            }
100
            else {
101
                $statusSymbol = self::STATUS_SYMBOL_REJECTED;
102
            }
103
        }
104
105
        $this->setHtmlTitle($statusSymbol . ' #' . $request->getId());
106
    }
107
108
    /**
109
     * Sets up data unrelated to the request, such as the email template information
110
     *
111
     * @param PdoDatabase $database
112
     */
113
    protected function setupGeneralData(PdoDatabase $database)
114
    {
115
        $config = $this->getSiteConfiguration();
116
117
        $this->assign('createAccountReason', 'Requested account at [[WP:ACC]], request #');
118
119
        $this->assign('defaultRequestState', $config->getDefaultRequestStateKey());
120
121
        $this->assign('requestStates', $config->getRequestStates());
122
123
        /** @var EmailTemplate $createdTemplate */
124
        $createdTemplate = EmailTemplate::getById($config->getDefaultCreatedTemplateId(), $database);
125
126
        $this->assign('createdHasJsQuestion', $createdTemplate->getJsquestion() != '');
127
        $this->assign('createdJsQuestion', $createdTemplate->getJsquestion());
128
        $this->assign('createdId', $createdTemplate->getId());
129
        $this->assign('createdName', $createdTemplate->getName());
130
131
        $createReasons = EmailTemplate::getActiveTemplates(EmailTemplate::CREATED, $database);
132
        $this->assign("createReasons", $createReasons);
133
        $declineReasons = EmailTemplate::getActiveTemplates(EmailTemplate::NOT_CREATED, $database);
134
        $this->assign("declineReasons", $declineReasons);
135
136
        $allCreateReasons = EmailTemplate::getAllActiveTemplates(EmailTemplate::CREATED, $database);
137
        $this->assign("allCreateReasons", $allCreateReasons);
138
        $allDeclineReasons = EmailTemplate::getAllActiveTemplates(EmailTemplate::NOT_CREATED, $database);
139
        $this->assign("allDeclineReasons", $allDeclineReasons);
140
        $allOtherReasons = EmailTemplate::getAllActiveTemplates(false, $database);
141
        $this->assign("allOtherReasons", $allOtherReasons);
142
143
        $this->getTypeAheadHelper()->defineTypeAheadSource('username-typeahead', function() use ($database) {
144
            return UserSearchHelper::get($database)->byStatus('Active')->fetchColumn('username');
145
        });
146
    }
147
148
    private function setupLogData(Request $request, PdoDatabase $database)
149
    {
150
        $currentUser = User::getCurrent($database);
151
152
        $logs = LogHelper::getRequestLogsWithComments($request->getId(), $database, $this->getSecurityManager());
153
        $requestLogs = array();
154
155
        if (trim($request->getComment()) !== "") {
156
            $requestLogs[] = array(
157
                'type'     => 'comment',
158
                'security' => 'user',
159
                'userid'   => null,
160
                'user'     => $request->getName(),
161
                'entry'    => null,
162
                'time'     => $request->getDate(),
163
                'canedit'  => false,
164
                'id'       => $request->getId(),
165
                'comment'  => $request->getComment(),
166
            );
167
        }
168
169
        /** @var User[] $nameCache */
170
        $nameCache = array();
171
172
        $editableComments = $this->barrierTest('editOthers', $currentUser, PageEditComment::class);
173
174
        /** @var Log|Comment $entry */
175
        foreach ($logs as $entry) {
176
            // both log and comment have a 'user' field
177
            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...
178
                $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...
179
                $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...
180
            }
181
182
            if ($entry instanceof Comment) {
183
                $requestLogs[] = array(
184
                    'type'     => 'comment',
185
                    'security' => $entry->getVisibility(),
186
                    'user'     => $nameCache[$entry->getUser()]->getUsername(),
187
                    'userid'   => $entry->getUser() == -1 ? null : $entry->getUser(),
188
                    'entry'    => null,
189
                    'time'     => $entry->getTime(),
190
                    'canedit'  => ($editableComments || $entry->getUser() == $currentUser->getId()),
191
                    'id'       => $entry->getId(),
192
                    'comment'  => $entry->getComment(),
193
                );
194
            }
195
196
            if ($entry instanceof Log) {
197
                $invalidUserId = $entry->getUser() === -1 || $entry->getUser() === 0;
198
                $entryUser = $invalidUserId ? User::getCommunity() : $nameCache[$entry->getUser()];
199
200
                $requestLogs[] = array(
201
                    'type'     => 'log',
202
                    'security' => 'user',
203
                    'userid'   => $entry->getUser() == -1 ? null : $entry->getUser(),
204
                    'user'     => $entryUser->getUsername(),
205
                    'entry'    => LogHelper::getLogDescription($entry),
206
                    'time'     => $entry->getTimestamp(),
207
                    'canedit'  => false,
208
                    'id'       => $entry->getId(),
209
                    'comment'  => $entry->getComment(),
210
                );
211
            }
212
        }
213
214
        $this->assign("requestLogs", $requestLogs);
215
    }
216
217
    /**
218
     * @param Request $request
219
     */
220
    protected function setupUsernameData(Request $request)
221
    {
222
        $blacklistData = $this->getBlacklistHelper()->isBlacklisted($request->getName());
223
224
        $this->assign('requestIsBlacklisted', $blacklistData !== false);
225
        $this->assign('requestBlacklist', $blacklistData);
226
227
        try {
228
            $spoofs = $this->getAntiSpoofProvider()->getSpoofs($request->getName());
229
        }
230
        catch (Exception $ex) {
231
            $spoofs = $ex->getMessage();
232
        }
233
234
        $this->assign("spoofs", $spoofs);
235
    }
236
}
237