Passed
Push — search ( bdb480...5e7f6e )
by Simon
17:14 queued 07:17
created

PageCustomClose::processAutoCreation()   B

Complexity

Conditions 6
Paths 11

Size

Total Lines 57
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
eloc 35
dl 0
loc 57
ccs 0
cts 0
cp 0
rs 8.7377
c 0
b 0
f 0
cc 6
nc 11
nop 5
crap 42

How to fix   Long Method   

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
 * 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\RequestAction;
10
11
use Exception;
12
use Waca\Background\Task\BotCreationTask;
13
use Waca\Background\Task\UserCreationTask;
14
use Waca\DataObjects\EmailTemplate;
15
use Waca\DataObjects\JobQueue;
16
use Waca\DataObjects\Request;
17
use Waca\DataObjects\RequestQueue;
18
use Waca\DataObjects\User;
19
use Waca\Exceptions\AccessDeniedException;
20
use Waca\Exceptions\ApplicationLogicException;
21
use Waca\Exceptions\OptimisticLockFailedException;
22
use Waca\Fragments\RequestData;
23
use Waca\Helpers\Logger;
24
use Waca\Helpers\OAuthUserHelper;
25
use Waca\PdoDatabase;
26
use Waca\RequestStatus;
27
use Waca\SessionAlert;
28
use Waca\WebRequest;
29
30
class PageCustomClose extends PageCloseRequest
31
{
32
    use RequestData;
33
34
    public const CREATE_OAUTH = 'created-oauth';
35
    public const CREATE_BOT = 'created-bot';
36
37
    protected function main()
38
    {
39
        $database = $this->getDatabase();
40
41
        $request = $this->getRequest($database);
42
        $currentUser = User::getCurrent($this->getDatabase());
43
44
        if ($request->getStatus() === RequestStatus::CLOSED) {
45
            throw new ApplicationLogicException('Request is already closed');
46
        }
47
48
        // Dual-mode page
49
        if (WebRequest::wasPosted()) {
50
            $this->validateCSRFToken();
51
            $success = $this->doCustomClose($currentUser, $request, $database);
52
53
            if ($success) {
54
                $this->redirect();
55
            }
56
        }
57
        else {
58
            $this->assignCSRFToken();
59
            $this->showCustomCloseForm($database, $request);
60
        }
61
    }
62
63
    /**
64
     * @param $database
65
     *
66
     * @return Request
67
     * @throws ApplicationLogicException
68
     */
69
    protected function getRequest(PdoDatabase $database)
70
    {
71
        $requestId = WebRequest::getInt('request');
72
        if ($requestId === null) {
73
            throw new ApplicationLogicException('Request ID not found');
74
        }
75
76
        /** @var Request $request */
77
        $request = Request::getById($requestId, $database);
78
79
        if ($request === false) {
0 ignored issues
show
introduced by
The condition $request === false is always false.
Loading history...
80
            throw new ApplicationLogicException('Request not found');
81
        }
82
83
        return $request;
84
    }
85
86
    /**
87
     * @param PdoDatabase $database
88
     *
89
     * @return EmailTemplate|null
90
     */
91
    protected function getTemplate(PdoDatabase $database)
92
    {
93
        $templateId = WebRequest::getInt('template');
94
        if ($templateId === null) {
95
            return null;
96
        }
97
98
        /** @var EmailTemplate $template */
99
        $template = EmailTemplate::getById($templateId, $database);
100
        if ($template === false || !$template->getActive()) {
101
            return null;
102
        }
103
104
        return $template;
105
    }
106
107
    /**
108
     * @param $database
109
     * @param $request
110
     *
111
     * @throws Exception
112
     */
113
    protected function showCustomCloseForm(PdoDatabase $database, Request $request)
114
    {
115
        $this->setHtmlTitle("Custom close");
116
117
        $currentUser = User::getCurrent($database);
118
        $config = $this->getSiteConfiguration();
119
120
        $allowedPrivateData = $this->isAllowedPrivateData($request, $currentUser);
121
        if (!$allowedPrivateData) {
122
            // we probably shouldn't be showing the user this form if they're not allowed to access private data...
123
            throw new AccessDeniedException($this->getSecurityManager(), $this->getDomainAccessManager());
124
        }
125
126
        $template = $this->getTemplate($database);
127
128
        // Preload data
129
        $this->assign('defaultAction', '');
130
        $this->assign('defaultQueue', null);
131
        $this->assign('preloadText', '');
132
        $this->assign('preloadTitle', '');
133
134
        if ($template !== null) {
135
            $this->assign('defaultAction', $template->getDefaultAction());
136
            $this->assign('defaultQueue', $template->getQueue());
137
            $this->assign('preloadText', $template->getText());
138
            $this->assign('preloadTitle', $template->getName());
139
        }
140
141
        // Static data
142
        $this->assign('requestQueues', $requestQueues = RequestQueue::getEnabledQueues($database));
143
144
        // request data
145
        $this->assign('requestId', $request->getIp());
146
        $this->assign('updateVersion', $request->getUpdateVersion());
147
        $this->setupBasicData($request, $config);
148
        $this->setupReservationDetails($request->getReserved(), $database, $currentUser);
149
        $this->setupPrivateData($request, $config);
150
        $this->setupRelatedRequests($request, $config, $database);
151
152
        // IP location
153
        $trustedIp = $this->getXffTrustProvider()->getTrustedClientIp($request->getIp(), $request->getForwardedIp());
154
        $this->assign('iplocation', $this->getLocationProvider()->getIpLocation($trustedIp));
155
156
        // Confirmations
157
        $this->assign('confirmEmailAlreadySent', $this->checkEmailAlreadySent($request));
158
159
        $this->assign('canSkipCcMailingList', $this->barrierTest('skipCcMailingList', $currentUser));
160
161
        $this->assign('allowWelcomeSkip', false);
162
        $this->assign('forceWelcomeSkip', false);
163
164
        $canOauthCreate = $this->barrierTest(User::CREATION_OAUTH, $currentUser, 'RequestCreation');
165
        $canBotCreate = $this->barrierTest(User::CREATION_BOT, $currentUser, 'RequestCreation');
166
167
        $oauth = new OAuthUserHelper($currentUser, $this->getDatabase(), $this->getOAuthProtocolHelper(), $config);
168
169
        if ($currentUser->getWelcomeTemplate() != 0) {
170
            $this->assign('allowWelcomeSkip', true);
171
172
            if (!$oauth->canWelcome()) {
173
                $this->assign('forceWelcomeSkip', true);
174
            }
175
        }
176
177
        // disable options if there's a misconfiguration.
178
        $canOauthCreate &= $oauth->canCreateAccount();
179
        $canBotCreate &= $this->getSiteConfiguration()->getCreationBotPassword() !== null;
180
181
        $this->assign('canOauthCreate', $canOauthCreate);
182
        $this->assign('canBotCreate', $canBotCreate);
183
184
        // template
185
        $this->setTemplate('custom-close.tpl');
186
    }
187
188
    /**
189
     * @param User        $currentUser
190
     * @param Request     $request
191
     * @param PdoDatabase $database
192
     *
193
     * @throws ApplicationLogicException
194
     */
195
    protected function doCustomClose(User $currentUser, Request $request, PdoDatabase $database) : bool
196
    {
197
        $messageBody = WebRequest::postString('msgbody');
198
        if ($messageBody === null || trim($messageBody) === '') {
199
            throw new ApplicationLogicException('Message body cannot be blank');
200
        }
201
202
        $ccMailingList = true;
203
        if ($this->barrierTest('skipCcMailingList', $currentUser)) {
204
            $ccMailingList = WebRequest::postBoolean('ccMailingList');
205
        }
206
207
        if ($request->getStatus() === RequestStatus::CLOSED) {
208
            throw new ApplicationLogicException('Request is already closed');
209
        }
210
211
        if (!(WebRequest::postBoolean('confirmEmailAlreadySent'))
212
        ) {
213
            throw new ApplicationLogicException('Not all confirmations checked');
214
        }
215
216
        $action = WebRequest::postString('action');
217
218
        if ($action === EmailTemplate::ACTION_CREATED || $action === EmailTemplate::ACTION_NOT_CREATED) {
219
220
            if ($action === EmailTemplate::ACTION_CREATED) {
221
                if ($this->checkAccountCreated($request)) {
222
                    $this->assignCSRFToken();
223
                    $this->showCustomCloseForm($database, $request);
224
225
                    $this->assign("preloadText", $messageBody);
226
                    $this->assign('preloadAction', $action);
227
                    $this->assign('ccMailingList', $ccMailingList);
228
                    $this->assign('showNonExistentAccountWarning', true);
229
                    $this->assign('skipAutoWelcome', WebRequest::postBoolean('skipAutoWelcome'));
230
231
                    return false;
232
                }
233
            }
234
235
            // Close request
236
            $this->closeRequest($request, $database, $action, $messageBody);
237
238
            $this->processWelcome($action, null);
239
240
            // Send the mail after the save, since save can be rolled back
241
            $this->sendMail($request, $messageBody, $currentUser, $ccMailingList);
242
243
            return true;
244
        }
245
246
        if ($action === self::CREATE_OAUTH || $action === self::CREATE_BOT) {
247
            $this->processAutoCreation($currentUser, $action, $request, $messageBody, $ccMailingList);
248
249
            return true;
250
        }
251
252
        if ($action === 'mail') {
253
            $request->setReserved(null);
254
            $request->setUpdateVersion(WebRequest::postInt('updateversion'));
255
            $request->save();
256
257
            // Perform the notifications and stuff *after* we've successfully saved, since the save can throw an OLE
258
            // and be rolled back.
259
260
            // Send mail
261
            $this->sendMail($request, $messageBody, $currentUser, $ccMailingList);
262
263
            Logger::sentMail($database, $request, $messageBody);
264
            Logger::unreserve($database, $request);
265
266
            $this->getNotificationHelper()->sentMail($request);
267
            SessionAlert::success("Sent mail to Request {$request->getId()}");
268
269
            return true;
270
        }
271
272
        $targetQueue = RequestQueue::getByApiName($database, $action, 1);
0 ignored issues
show
Bug introduced by
It seems like $action can also be of type null; however, parameter $apiName of Waca\DataObjects\RequestQueue::getByApiName() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

272
        $targetQueue = RequestQueue::getByApiName($database, /** @scrutinizer ignore-type */ $action, 1);
Loading history...
273
        if ($targetQueue !== false) {
274
            // Defer to other state
275
            $this->deferRequest($request, $database, $targetQueue, $messageBody);
276
277
            // Send the mail after the save, since save can be rolled back
278
            $this->sendMail($request, $messageBody, $currentUser, $ccMailingList);
279
280
            return true;
281
        }
282
283
        throw new ApplicationLogicException('Unknown action for custom close.');
284
    }
285
286
    /**
287
     * @param Request     $request
288
     * @param PdoDatabase $database
289
     * @param string      $action
290
     * @param string      $messageBody
291
     *
292
     * @throws Exception
293
     * @throws OptimisticLockFailedException
294
     */
295
    protected function closeRequest(Request $request, PdoDatabase $database, $action, $messageBody)
296
    {
297
        $request->setStatus(RequestStatus::CLOSED);
298
        $request->setQueue(null);
299
        $request->setReserved(null);
300
        $request->setUpdateVersion(WebRequest::postInt('updateversion'));
301
        $request->save();
302
303
        // Perform the notifications and stuff *after* we've successfully saved, since the save can throw an OLE and
304
        // be rolled back.
305
306
        if ($action == EmailTemplate::ACTION_CREATED) {
307
            $logCloseType = 'custom-y';
308
            $notificationCloseType = "Custom, Created";
309
        }
310
        else {
311
            $logCloseType = 'custom-n';
312
            $notificationCloseType = "Custom, Not Created";
313
        }
314
315
        Logger::closeRequest($database, $request, $logCloseType, $messageBody);
0 ignored issues
show
Bug introduced by
$logCloseType of type string is incompatible with the type integer expected by parameter $target of Waca\Helpers\Logger::closeRequest(). ( Ignorable by Annotation )

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

315
        Logger::closeRequest($database, $request, /** @scrutinizer ignore-type */ $logCloseType, $messageBody);
Loading history...
316
        $this->getNotificationHelper()->requestClosed($request, $notificationCloseType);
317
318
        $requestName = htmlentities($request->getName(), ENT_COMPAT, 'UTF-8');
319
        SessionAlert::success("Request {$request->getId()} ({$requestName}) closed as {$notificationCloseType}.");
320
    }
321
322
    /**
323
     * @param Request      $request
324
     * @param PdoDatabase  $database
325
     * @param RequestQueue $targetQueue
326
     * @param string       $messageBody
327
     *
328
     * @throws OptimisticLockFailedException
329
     */
330
    protected function deferRequest(
331
        Request $request,
332
        PdoDatabase $database,
333
        RequestQueue $targetQueue,
334
        $messageBody
335
    ) {
336
        $request->setStatus(RequestStatus::OPEN);
337
        $request->setQueue($targetQueue->getId());
338
        $request->setReserved(null);
339
        $request->setUpdateVersion(WebRequest::postInt('updateversion'));
340
        $request->save();
341
342
        // Perform the notifications and stuff *after* we've successfully saved, since the save can throw an OLE
343
        // and be rolled back.
344
345
        $deferToLog = $targetQueue->getLogName();
0 ignored issues
show
Deprecated Code introduced by
The function Waca\DataObjects\RequestQueue::getLogName() has been deprecated. ( Ignorable by Annotation )

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

345
        $deferToLog = /** @scrutinizer ignore-deprecated */ $targetQueue->getLogName();
Loading history...
346
        Logger::sentMail($database, $request, $messageBody);
347
        Logger::deferRequest($database, $request, $deferToLog);
348
349
        $this->getNotificationHelper()->requestDeferredWithMail($request);
350
351
        $deferTo = htmlentities($targetQueue->getDisplayName(), ENT_COMPAT, 'UTF-8');
352
        SessionAlert::success("Request {$request->getId()} deferred to $deferTo, sending an email.");
353
    }
354
355
    /**
356
     * @param User    $currentUser
357
     * @param string  $action
358
     * @param Request $request
359
     * @param string  $messageBody
360
     * @param bool    $ccMailingList
361
     *
362
     * @throws AccessDeniedException
363
     * @throws ApplicationLogicException
364
     * @throws OptimisticLockFailedException
365
     */
366
    protected function processAutoCreation(User $currentUser, string $action, Request $request, string $messageBody, bool $ccMailingList): void
367
    {
368
        $db = $this->getDatabase();
369
        $oauth = new OAuthUserHelper($currentUser, $db, $this->getOAuthProtocolHelper(), $this->getSiteConfiguration());
370
        $canOauthCreate = $this->barrierTest(User::CREATION_OAUTH, $currentUser, 'RequestCreation');
371
        $canBotCreate = $this->barrierTest(User::CREATION_BOT, $currentUser, 'RequestCreation');
372
        $canOauthCreate &= $oauth->canCreateAccount();
373
        $canBotCreate &= $this->getSiteConfiguration()->getCreationBotPassword() !== null;
374
375
        $creationTaskClass = null;
376
377
        if ($action === self::CREATE_OAUTH) {
378
            if (!$canOauthCreate) {
379
                throw new AccessDeniedException($this->getSecurityManager(), $this->getDomainAccessManager());
380
            }
381
382
            $creationTaskClass = UserCreationTask::class;
383
        }
384
385
        if ($action === self::CREATE_BOT) {
386
            if (!$canBotCreate) {
387
                throw new AccessDeniedException($this->getSecurityManager(), $this->getDomainAccessManager());
388
            }
389
390
            $creationTaskClass = BotCreationTask::class;
391
        }
392
393
        if ($creationTaskClass === null) {
394
            throw new ApplicationLogicException('Cannot determine creation mode');
395
        }
396
397
        $request->setStatus(RequestStatus::JOBQUEUE);
398
        $request->setReserved(null);
399
        $request->save();
400
401
        $parameters = [
402
            'emailText' => $messageBody,
403
            'ccMailingList' => $ccMailingList
404
        ];
405
406
        $creationTask = new JobQueue();
407
        $creationTask->setTask($creationTaskClass);
408
        $creationTask->setRequest($request->getId());
409
        $creationTask->setTriggerUserId($currentUser->getId());
410
        $creationTask->setParameters(json_encode($parameters));
411
        $creationTask->setDatabase($db);
412
        $creationTask->save();
413
414
        $creationTaskId = $creationTask->getId();
415
416
        Logger::enqueuedJobQueue($db, $request);
417
        $this->getNotificationHelper()->requestCloseQueued($request, 'Custom, Created');
418
419
        SessionAlert::success("Request {$request->getId()} has been queued for autocreation");
420
421
        // forge this since it is actually a creation.
422
        $this->processWelcome(EmailTemplate::ACTION_CREATED, $creationTaskId);
423
    }
424
}
425