Passed
Push — bantools ( 0a2554...2e796f )
by
unknown
18:08 queued 09:26
created

getExpiredUnconstrainedCount()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 27
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 22
c 0
b 0
f 0
dl 0
loc 27
ccs 0
cts 0
cp 0
rs 9.568
cc 1
nc 1
nop 2
crap 2
1
<?php /** @noinspection SqlConstantCondition */
2
3
/******************************************************************************
4
 * Wikipedia Account Creation Assistance tool                                 *
5
 *                                                                            *
6
 * All code in this file is released into the public domain by the ACC        *
7
 * Development Team. Please see team.json for a list of contributors.         *
8
 ******************************************************************************/
9
10
namespace Waca\ConsoleTasks;
11
12
use Waca\PdoDatabase;
13
use Waca\Tasks\ConsoleTaskBase;
14
15
class OldRequestCleanupTask extends ConsoleTaskBase
16
{
17
    public function execute()
18
    {
19
        $database = $this->getDatabase();
20
        $expiryTime = [':expiry' => $this->getSiteConfiguration()->getEmailConfirmationExpiryDays()];
21
22
        // start by fetching the number of unconfirmed requests which have expired
23
        $eligibleRecords = $this->getExpiredCount($database, $expiryTime);
24
25
        // fetch the number of unconfirmed requests which have expired and which have no FK constraints which would
26
        // otherwise prevent their deletion
27
        $eligibleUnconstrainedRecords = $this->getExpiredUnconstrainedCount($database, $expiryTime);
28
29
        // Delete any requester comments for expired requests
30
        $requesterCommentDelete = <<<SQL
31
            DELETE FROM comment
32
            WHERE 1 = 1 
33
                -- only requester comments
34
                AND comment.visibility = 'requester'
35
                -- where the following record exists
36
                AND exists(
37
                    SELECT 1 FROM request r
38
                    WHERE 1 = 1
39
                        -- a request matching the currently-checked comment
40
                        AND comment.request = r.id
41
                        -- and the request is expired
42
                        AND r.date < DATE_SUB(CURRENT_TIMESTAMP(), INTERVAL :expiry DAY)
43
                        -- no confirmed email address
44
                        AND r.emailconfirm <> 'Confirmed'
45
                        -- not already marked as stale
46
                        AND r.emailconfirm <> 'Stale'
47
                        -- email confirmation was requested
48
                        AND r.emailconfirm <> ''
49
                        -- no non-requester comments exist (nobody has commented on the request)
50
                        AND NOT exists (SELECT 1 FROM comment c2 WHERE c2.request = r.id AND c2.visibility <> 'requester')
51
                        -- no jobqueue entries for this request exist
52
                        AND NOT exists (SELECT 1 FROM jobqueue j WHERE j.request = r.id)
53
                        -- no log entries for this request exist
54
                        AND NOT exists (SELECT 1 FROM log l WHERE l.objectid = r.id and l.objecttype = 'Request')
55
                );
56
SQL;
57
        $statement = $database->prepare($requesterCommentDelete);
58
        $statement->execute($expiryTime);
59
        $deletedComments = $statement->rowCount();
60
61
        // Delete any expired requests with no remaining FK constraints
62
        $requestDelete = <<<SQL
63
            DELETE FROM request
64
            WHERE 1 = 1
65
              -- request date older than X days ago
66
              AND request.date < DATE_SUB(CURRENT_TIMESTAMP(), INTERVAL :expiry DAY)
67
              -- no confirmed email address
68
              AND request.emailconfirm <> 'Confirmed'
69
              -- not already marked as stale
70
              AND request.emailconfirm <> 'Stale'
71
              -- email confirmation was requested
72
              AND request.emailconfirm <> ''
73
              -- no comments exist (we just deleted requester comments)
74
              AND NOT exists(SELECT 1 FROM comment c WHERE c.request = request.id)
75
              -- no jobqueue entries for this request exist
76
              AND NOT exists(SELECT 1 FROM jobqueue j WHERE j.request = request.id)
77
              -- no log entries for this request exist
78
              AND NOT exists(SELECT 1 FROM log l WHERE l.objectid = request.id and l.objecttype = 'Request');
79
SQL;
80
        $statement = $database->prepare($requestDelete);
81
        $statement->execute($expiryTime);
82
        $deletedRequests = $statement->rowCount();
83
84
        // We've deleted all we can sensibly get away with. Disable the ability to email-confirm requests, and close
85
        // them as stale. The purge job will pick up the clearing of any private data.
86
        // Note - *very* few requests should get this far; it normally means a tool admin has overridden the
87
        // email-confirmation lockout and done something to the non-confirmed request.
88
89
        $splatExpired = <<<SQL
90
            UPDATE request 
91
                SET emailconfirm = 'Stale', status = 'Closed', updateversion = updateversion + 1
92
            WHERE 1 = 1
93
                AND request.date < DATE_SUB(CURRENT_TIMESTAMP(), INTERVAL :expiry DAY)
94
                AND request.emailconfirm <> 'Confirmed'
95
                AND request.emailconfirm <> 'Stale'
96
                AND request.emailconfirm <> ''
97
            ;
98
SQL;
99
100
        $statement = $database->prepare($splatExpired);
101
        $statement->execute($expiryTime);
102
        $requestsMarkedStale = $statement->rowCount();
103
104
        // All done.
105
        $database->commit();
106
107
        printf('Cleanup: %d expired; %d unconstrained, %d comments deleted, %d requests deleted, %d marked stale',
108
            $eligibleRecords, $eligibleUnconstrainedRecords, $deletedComments, $deletedRequests, $requestsMarkedStale);
109
    }
110
111
    private function getExpiredCount(PdoDatabase $database, array $expiryTime)
112
    {
113
        $statement = $database->prepare(<<<SQL
114
            SELECT COUNT(*) FROM request r
115
            WHERE 1 = 1 
116
              -- request date older than X days ago
117
              AND r.date < DATE_SUB(CURRENT_TIMESTAMP(), INTERVAL :expiry DAY)
118
              -- no confirmed email address
119
              AND r.emailconfirm <> 'Confirmed'
120
              -- not already marked as stale
121
              AND r.emailconfirm <> 'Stale'
122
              -- email confirmation was requested
123
              AND r.emailconfirm <> '';
124
SQL
125
        );
126
127
        $statement->execute($expiryTime);
128
        $eligibleRecords = $statement->fetchColumn();
129
        $statement->closeCursor();
130
131
        return $eligibleRecords;
132
    }
133
134
    private function getExpiredUnconstrainedCount(PdoDatabase $database, array $expiryTime)
135
    {
136
        $statement = $database->prepare(<<<SQL
137
            SELECT COUNT(*) FROM request r
138
            WHERE 1 = 1 
139
                -- request date older than X days ago
140
                AND r.date < DATE_SUB(CURRENT_TIMESTAMP(), INTERVAL :expiry DAY)
141
                -- no confirmed email address
142
                AND r.emailconfirm <> 'Confirmed'
143
                -- not already marked as stale
144
                AND r.emailconfirm <> 'Stale'
145
                -- email confirmation was requested
146
                AND r.emailconfirm <> ''
147
                -- no comments for this request exist
148
                AND NOT exists(SELECT 1 FROM comment c WHERE c.request = r.id)
149
                -- no jobqueue entries for this request exist
150
                AND NOT exists(SELECT 1 FROM jobqueue j WHERE j.request = r.id)
151
                -- no log entries for this request exist
152
                AND NOT exists(SELECT 1 FROM log l WHERE l.objectid = r.id AND l.objecttype = 'Request');
153
SQL
154
        );
155
156
        $statement->execute($expiryTime);
157
        $eligibleRecords = $statement->fetchColumn();
158
        $statement->closeCursor();
159
160
        return $eligibleRecords;
161
    }
162
}