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

290
        Logger::closeRequest($database, $request, /** @scrutinizer ignore-type */ $logCloseType, $messageBody);
Loading history...
291
        $this->getNotificationHelper()->requestClosed($request, $notificationCloseType);
292
293
        $requestName = htmlentities($request->getName(), ENT_COMPAT, 'UTF-8');
294
        SessionAlert::success("Request {$request->getId()} ({$requestName}) closed as {$notificationCloseType}.");
295
    }
296
297
    /**
298
     * @param Request     $request
299
     * @param PdoDatabase $database
300
     * @param string      $action
301
     * @param             $availableRequestStates
302
     * @param string      $messageBody
303
     *
304
     * @throws Exception
305
     * @throws OptimisticLockFailedException
306
     */
307
    protected function deferRequest(
308
        Request $request,
309
        PdoDatabase $database,
310
        $action,
311
        $availableRequestStates,
312
        $messageBody
313
    ) {
314
        $request->setStatus($action);
315
        $request->setReserved(null);
316
        $request->setUpdateVersion(WebRequest::postInt('updateversion'));
317
        $request->save();
318
319
        // Perform the notifications and stuff *after* we've successfully saved, since the save can throw an OLE
320
        // and be rolled back.
321
322
        $deferToLog = $availableRequestStates[$action]['defertolog'];
323
        Logger::sentMail($database, $request, $messageBody);
324
        Logger::deferRequest($database, $request, $deferToLog);
325
326
        $this->getNotificationHelper()->requestDeferredWithMail($request);
327
328
        $deferTo = $availableRequestStates[$action]['deferto'];
329
        SessionAlert::success("Request {$request->getId()} deferred to $deferTo, sending an email.");
330
    }
331
332
    /**
333
     * @param User    $currentUser
334
     * @param string  $action
335
     * @param Request $request
336
     * @param string  $messageBody
337
     * @param bool    $ccMailingList
338
     *
339
     * @throws AccessDeniedException
340
     * @throws ApplicationLogicException
341
     * @throws OptimisticLockFailedException
342
     */
343
    protected function processAutoCreation(User $currentUser, string $action, Request $request, string $messageBody, bool $ccMailingList): void
344
    {
345
        $db = $this->getDatabase();
346
        $oauth = new OAuthUserHelper($currentUser, $db, $this->getOAuthProtocolHelper(), $this->getSiteConfiguration());
347
        $canOauthCreate = $this->barrierTest(User::CREATION_OAUTH, $currentUser, 'RequestCreation');
348
        $canBotCreate = $this->barrierTest(User::CREATION_BOT, $currentUser, 'RequestCreation');
349
        $canOauthCreate &= $oauth->canCreateAccount();
350
        $canBotCreate &= $this->getSiteConfiguration()->getCreationBotPassword() !== null;
351
352
        $creationTaskClass = null;
353
354
        if ($action === self::CREATE_OAUTH) {
355
            if(!$canOauthCreate) {
356
                throw new AccessDeniedException($this->getSecurityManager());
357
            }
358
359
            $creationTaskClass = UserCreationTask::class;
360
        }
361
362
        if ($action === self::CREATE_BOT) {
363
            if (!$canBotCreate) {
364
                throw new AccessDeniedException($this->getSecurityManager());
365
            }
366
367
            $creationTaskClass = BotCreationTask::class;
368
        }
369
370
        if ($creationTaskClass === null) {
371
            throw new ApplicationLogicException('Cannot determine creation mode');
372
        }
373
374
        $request->setStatus(RequestStatus::JOBQUEUE);
375
        $request->setReserved(null);
376
        $request->save();
377
378
        $parameters = [
379
            'emailText' => $messageBody,
380
            'ccMailingList' => $ccMailingList
381
        ];
382
383
        $creationTask = new JobQueue();
384
        $creationTask->setTask($creationTaskClass);
385
        $creationTask->setRequest($request->getId());
386
        $creationTask->setTriggerUserId($currentUser->getId());
387
        $creationTask->setParameters(json_encode($parameters));
388
        $creationTask->setDatabase($db);
389
        $creationTask->save();
390
391
        $creationTaskId = $creationTask->getId();
392
393
        Logger::enqueuedJobQueue($db, $request);
394
        $this->getNotificationHelper()->requestCloseQueued($request, 'Custom, Created');
395
396
        SessionAlert::success("Request {$request->getId()} has been queued for autocreation");
397
398
        // forge this since it is actually a creation.
399
        $this->processWelcome(EmailTemplate::CREATED, $creationTaskId);
400
    }
401
}
402