Issues (186)

includes/Pages/PageJobQueue.php (7 issues)

1
<?php
2
/******************************************************************************
3
 * Wikipedia Account Creation Assistance tool                                 *
4
 * ACC Development Team. Please see team.json for a list of contributors.     *
5
 *                                                                            *
6
 * This is free and unencumbered software released into the public domain.    *
7
 * Please see LICENSE.md for the full licencing statement.                    *
8
 ******************************************************************************/
9
10
namespace Waca\Pages;
11
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\Log;
17
use Waca\DataObjects\Request;
18
use Waca\DataObjects\User;
19
use Waca\Exceptions\ApplicationLogicException;
20
use Waca\Helpers\Logger;
21
use Waca\Helpers\LogHelper;
22
use Waca\Helpers\SearchHelpers\JobQueueSearchHelper;
23
use Waca\Helpers\SearchHelpers\LogSearchHelper;
24
use Waca\Helpers\SearchHelpers\RequestSearchHelper;
25
use Waca\Helpers\SearchHelpers\UserSearchHelper;
26
use Waca\RequestStatus;
27
use Waca\Tasks\PagedInternalPageBase;
28
use Waca\WebRequest;
29
30
class PageJobQueue extends PagedInternalPageBase
31
{
32
    /**
33
     * Main function for this page, when no specific actions are called.
34
     * @return void
35
     */
36
    protected function main()
37
    {
38
        $this->setHtmlTitle('Job Queue Management');
39
40
        $this->prepareMaps();
41
42
        $database = $this->getDatabase();
43
44
        /** @var JobQueue[] $jobList */
45
        // FIXME: domains
46
        $jobList = JobQueueSearchHelper::get($database, 1)
47
            ->statusIn([
48
                JobQueue::STATUS_QUEUED,
49
                JobQueue::STATUS_READY,
50
                JobQueue::STATUS_WAITING,
51
                JobQueue::STATUS_RUNNING,
52
                JobQueue::STATUS_FAILED,
53
            ])
54
            ->notAcknowledged()
55
            ->fetch();
56
57
        $userIds = array();
58
        $requestIds = array();
59
60
        foreach ($jobList as $job) {
61
            $userIds[] = $job->getTriggerUserId();
62
            $requestIds[] = $job->getRequest();
63
64
            $job->setDatabase($database);
65
        }
66
67
        $this->assign('canSeeAll', $this->barrierTest('all', User::getCurrent($database)));
68
69
        $this->assign('users', UserSearchHelper::get($database)->inIds($userIds)->fetchMap('username'));
70
        // FIXME: domains
71
        $this->assign('requests', RequestSearchHelper::get($database, 1)->inIds($requestIds)->fetchMap('name'));
72
73
        $this->assign('joblist', $jobList);
74
        $this->setTemplate('jobqueue/main.tpl');
75
    }
76
77
    protected function all()
78
    {
79
        $this->setHtmlTitle('All Jobs');
80
81
        $this->prepareMaps();
82
83
        $database = $this->getDatabase();
84
85
        // FIXME: domains
86
        $searchHelper = JobQueueSearchHelper::get($database, 1);
87
        $this->setSearchHelper($searchHelper);
88
        $this->setupLimits();
89
90
        $filterUser = WebRequest::getString('filterUser');
91
        $filterTask = WebRequest::getString('filterTask');
92
        $filterStatus = WebRequest::getString('filterStatus');
93
        $filterRequest = WebRequest::getString('filterRequest');
94
        $order = WebRequest::getString('order');
95
96
        if ($filterUser !== null) {
97
            $searchHelper->byUser(User::getByUsername($filterUser, $database)->getId());
98
        }
99
100
        if ($filterTask !== null) {
101
            $searchHelper->byTask($filterTask);
102
        }
103
104
        if ($filterStatus !== null) {
105
            $searchHelper->byStatus($filterStatus);
106
        }
107
108
        if ($filterRequest !== null) {
109
            $searchHelper->byRequest($filterRequest);
0 ignored issues
show
$filterRequest of type string is incompatible with the type integer expected by parameter $request of Waca\Helpers\SearchHelpe...archHelper::byRequest(). ( Ignorable by Annotation )

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

109
            $searchHelper->byRequest(/** @scrutinizer ignore-type */ $filterRequest);
Loading history...
110
        }
111
        
112
        if ($order === null) {
113
            $searchHelper->newestFirst();
114
        }
115
116
        /** @var JobQueue[] $jobList */
117
        $jobList = $searchHelper->getRecordCount($count)->fetch();
118
119
        $this->setupPageData($count, array(
120
            'filterUser' => $filterUser,
121
            'filterTask' => $filterTask,
122
            'filterStatus' => $filterStatus,
123
            'filterRequest' => $filterRequest,
124
            'order' => $order,
125
        ));
126
127
        $userIds = array();
128
        $requestIds = array();
129
130
        foreach ($jobList as $job) {
131
            $userIds[] = $job->getTriggerUserId();
132
            $requestIds[] = $job->getRequest();
133
134
            $job->setDatabase($database);
135
        }
136
137
        $this->getTypeAheadHelper()->defineTypeAheadSource('username-typeahead', function() use ($database) {
138
            return UserSearchHelper::get($database)->fetchColumn('username');
139
        });
140
141
        $this->assign('users', UserSearchHelper::get($database)->inIds($userIds)->fetchMap('username'));
142
        // FIXME: domains!
143
        $this->assign('requests', RequestSearchHelper::get($database, 1)->inIds($requestIds)->fetchMap('name'));
144
145
        $this->assign('joblist', $jobList);
146
147
        $this->addJs("/api.php?action=users&all=true&targetVariable=typeaheaddata");
148
149
        $this->setTemplate('jobqueue/all.tpl');
150
    }
151
152
    protected function view()
153
    {
154
        $jobId = WebRequest::getInt('id');
155
        $database = $this->getDatabase();
156
157
        if ($jobId === null) {
158
            throw new ApplicationLogicException('No job specified');
159
        }
160
161
        /** @var JobQueue $job */
162
        $job = JobQueue::getById($jobId, $database);
163
164
        if ($job === false) {
0 ignored issues
show
The condition $job === false is always false.
Loading history...
165
            throw new ApplicationLogicException('Could not find requested job');
166
        }
167
168
        $this->prepareMaps();
169
170
        $this->assign('user', User::getById($job->getTriggerUserId(), $database));
171
        $this->assign('request', Request::getById($job->getRequest(), $database));
172
        $this->assign('emailTemplate', EmailTemplate::getById($job->getEmailTemplate(), $database));
173
        $this->assign('parent', JobQueue::getById($job->getParent(), $database));
174
175
        /** @var Log[] $logs */
176
        // FIXME: domains
177
        $logs = LogSearchHelper::get($database, 1)->byObjectType('JobQueue')
178
            ->byObjectId($job->getId())->getRecordCount($logCount)->fetch();
179
        if ($logCount === 0) {
180
            $this->assign('log', array());
181
        }
182
        else {
183
            list($users, $logData) = LogHelper::prepareLogsForTemplate($logs, $database, $this->getSiteConfiguration(), $this->getSecurityManager());
184
185
            $this->assign("log", $logData);
186
            $this->assign("users", $users);
187
        }
188
189
        $this->assignCSRFToken();
190
191
        $this->assign('job', $job);
192
193
        $this->assign('canAcknowledge', $this->barrierTest('acknowledge', User::getCurrent($database)));
194
        $this->assign('canRequeue', $this->barrierTest('requeue', User::getCurrent($database)));
195
        $this->assign('canCancel', $this->barrierTest('cancel', User::getCurrent($database)));
196
197
        if ($job->getTask() === UserCreationTask::class || $job->getTask() === BotCreationTask::class) {
198
            if ($job->getEmailTemplate() === null) {
0 ignored issues
show
The condition $job->getEmailTemplate() === null is always false.
Loading history...
199
                $params = json_decode($job->getParameters());
200
201
                if (isset($params->emailText)) {
202
                    $this->assign("creationEmailText", $params->emailText);
203
                }
204
            }
205
        }
206
207
        $this->setHtmlTitle('Job #{$job->getId()|escape}');
208
        $this->setTemplate('jobqueue/view.tpl');
209
    }
210
211
    protected function acknowledge()
212
    {
213
        if (!WebRequest::wasPosted()) {
214
            throw new ApplicationLogicException('This page does not support GET methods.');
215
        }
216
217
        $this->validateCSRFToken();
218
219
        $jobId = WebRequest::postInt('job');
220
        $database = $this->getDatabase();
221
222
        if ($jobId === null) {
223
            throw new ApplicationLogicException('No job specified');
224
        }
225
226
        /** @var JobQueue $job */
227
        $job = JobQueue::getById($jobId, $database);
228
229
        if ($job === false) {
0 ignored issues
show
The condition $job === false is always false.
Loading history...
230
            throw new ApplicationLogicException('Could not find requested job');
231
        }
232
233
        $job->setUpdateVersion(WebRequest::postInt('updateVersion'));
234
        $job->setAcknowledged(true);
0 ignored issues
show
true of type true is incompatible with the type integer expected by parameter $acknowledged of Waca\DataObjects\JobQueue::setAcknowledged(). ( Ignorable by Annotation )

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

234
        $job->setAcknowledged(/** @scrutinizer ignore-type */ true);
Loading history...
235
        $job->save();
236
237
        Logger::backgroundJobAcknowledged($database, $job);
238
239
        $this->redirect('jobQueue', 'view', array('id' => $jobId));
240
    }
241
242
    protected function cancel()
243
    {
244
        if (!WebRequest::wasPosted()) {
245
            throw new ApplicationLogicException('This page does not support GET methods.');
246
        }
247
248
        $this->validateCSRFToken();
249
250
        $jobId = WebRequest::postInt('job');
251
        $database = $this->getDatabase();
252
253
        if ($jobId === null) {
254
            throw new ApplicationLogicException('No job specified');
255
        }
256
257
        /** @var JobQueue $job */
258
        $job = JobQueue::getById($jobId, $database);
259
260
        if ($job === false) {
0 ignored issues
show
The condition $job === false is always false.
Loading history...
261
            throw new ApplicationLogicException('Could not find requested job');
262
        }
263
264
        if ($job->getStatus() !== JobQueue::STATUS_READY
265
            && $job->getStatus() !== JobQueue::STATUS_QUEUED
266
            && $job->getStatus() === JobQueue::STATUS_WAITING) {
267
            throw new ApplicationLogicException('Cannot cancel job not queued for execution');
268
        }
269
270
        $job->setUpdateVersion(WebRequest::postInt('updateVersion'));
271
        $job->setStatus(JobQueue::STATUS_CANCELLED);
272
        $job->setError("Manually cancelled");
273
        $job->setAcknowledged(null);
274
        $job->save();
275
276
        Logger::backgroundJobCancelled($this->getDatabase(), $job);
277
278
        $this->redirect('jobQueue', 'view', array('id' => $jobId));
279
    }
280
281
    protected function requeue()
282
    {
283
        if (!WebRequest::wasPosted()) {
284
            throw new ApplicationLogicException('This page does not support GET methods.');
285
        }
286
287
        $this->validateCSRFToken();
288
289
        $jobId = WebRequest::postInt('job');
290
        $database = $this->getDatabase();
291
292
        if ($jobId === null) {
293
            throw new ApplicationLogicException('No job specified');
294
        }
295
296
        /** @var JobQueue|false $job */
297
        $job = JobQueue::getById($jobId, $database);
298
299
        if ($job === false) {
0 ignored issues
show
The condition $job === false is always false.
Loading history...
300
            throw new ApplicationLogicException('Could not find requested job');
301
        }
302
303
        $job->setStatus(JobQueue::STATUS_QUEUED);
304
        $job->setUpdateVersion(WebRequest::postInt('updateVersion'));
305
        $job->setAcknowledged(null);
306
        $job->setError(null);
307
        $job->save();
308
309
        /** @var Request $request */
310
        $request = Request::getById($job->getRequest(), $database);
311
        $request->setStatus(RequestStatus::JOBQUEUE);
312
        $request->save();
313
314
        Logger::enqueuedJobQueue($database, $request);
315
        Logger::backgroundJobRequeued($database, $job);
316
317
        $this->redirect('jobQueue', 'view', array('id' => $jobId));
318
    }
319
320
    protected function prepareMaps()
321
    {
322
        $taskNameMap = JobQueue::getTaskDescriptions();
323
324
        $statusDecriptionMap = array(
325
            JobQueue::STATUS_CANCELLED => 'The job was cancelled',
326
            JobQueue::STATUS_COMPLETE  => 'The job completed successfully',
327
            JobQueue::STATUS_FAILED    => 'The job encountered an error',
328
            JobQueue::STATUS_QUEUED    => 'The job is in the queue',
329
            JobQueue::STATUS_READY     => 'The job is ready to be picked up by the next job runner execution',
330
            JobQueue::STATUS_RUNNING   => 'The job is being run right now by the job runner',
331
            JobQueue::STATUS_WAITING   => 'The job has been picked up by a job runner',
332
            JobQueue::STATUS_HELD      => 'The job has manually held from processing',
333
        );
334
        $this->assign('taskNameMap', $taskNameMap);
335
        $this->assign('statusDescriptionMap', $statusDecriptionMap);
336
    }
337
}
338