Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
83.65% |
87 / 104 |
|
33.33% |
2 / 6 |
CRAP | |
0.00% |
0 / 1 |
PageTriage | |
83.65% |
87 / 104 |
|
33.33% |
2 / 6 |
30.18 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
addToPageTriageQueue | |
87.10% |
27 / 31 |
|
0.00% |
0 / 1 |
6.08 | |||
setTriageStatus | |
73.81% |
31 / 42 |
|
0.00% |
0 / 1 |
17.52 | |||
update | |
88.89% |
8 / 9 |
|
0.00% |
0 / 1 |
2.01 | |||
retrieve | |
90.91% |
10 / 11 |
|
0.00% |
0 / 1 |
3.01 | |||
bulkSetTagsUpdated | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\PageTriage; |
4 | |
5 | use MediaWiki\MediaWikiServices; |
6 | use MediaWiki\User\UserIdentity; |
7 | use PatrolLog; |
8 | use RecentChange; |
9 | |
10 | /** |
11 | * TODO: This class does too much. Refactoring into services and classes with single responsibility |
12 | * in progress, please don't add new methods here. |
13 | */ |
14 | class PageTriage { |
15 | |
16 | /** @var int The relevant page ID. */ |
17 | protected int $mPageId; |
18 | /** @var int Review status, valid values are QueueRecord::VALID_REVIEW_STATUSES. */ |
19 | protected int $currentReviewStatus; |
20 | /** @var string MediaWiki-style timestamp of when the last review happened. */ |
21 | protected string $mReviewedUpdated; |
22 | |
23 | /** @var bool Used for in-process caching. */ |
24 | protected bool $mLoaded; |
25 | |
26 | public const CACHE_VERSION = 2; |
27 | |
28 | /** |
29 | * @param int $pageId |
30 | */ |
31 | public function __construct( int $pageId ) { |
32 | $this->mPageId = $pageId; |
33 | $this->mLoaded = false; |
34 | } |
35 | |
36 | /** |
37 | * Add page to page triage queue |
38 | * @param int $reviewStatus The reviewed status of the page, see QueueRecord::VALID_REVIEW_STATUSES |
39 | * @param UserIdentity|null $user |
40 | * @param bool $fromRc |
41 | * @return bool true: add new record, false: update existing record |
42 | * @throws MWPageTriageMissingRevisionException |
43 | */ |
44 | public function addToPageTriageQueue( |
45 | int $reviewStatus = 0, |
46 | UserIdentity $user = null, |
47 | bool $fromRc = false |
48 | ): bool { |
49 | if ( $this->retrieve() ) { |
50 | if ( $this->currentReviewStatus !== $reviewStatus ) { |
51 | $this->setTriageStatus( $reviewStatus, $user, $fromRc ); |
52 | } |
53 | return false; |
54 | } |
55 | |
56 | $dbw = PageTriageUtil::getPrimaryConnection(); |
57 | |
58 | // Pull page creation date from database |
59 | // must select from master here since the page has just been created, and probably |
60 | // hasn't propagated to the replicas yet. |
61 | $res = $dbw->newSelectQueryBuilder() |
62 | ->select( [ |
63 | 'creation_date' => 'MIN(rev_timestamp)', |
64 | 'last_edit_date' => 'MAX(rev_timestamp)' |
65 | ] ) |
66 | ->from( 'revision' ) |
67 | ->where( [ 'rev_page' => $this->mPageId ] ) |
68 | ->caller( __METHOD__ ) |
69 | ->fetchRow(); |
70 | |
71 | if ( !$res ) { |
72 | throw new MWPageTriageMissingRevisionException( 'Page missing revision!' ); |
73 | } |
74 | |
75 | $queueRecord = new QueueRecord( |
76 | $this->mPageId, |
77 | $reviewStatus, |
78 | false, |
79 | $res->creation_date, |
80 | null, |
81 | $res->last_edit_date, |
82 | $user ? $user->getId() : 0, |
83 | ); |
84 | /** @var QueueManager $queueManager */ |
85 | $queueManager = MediaWikiServices::getInstance()->get( 'PageTriageQueueManager' ); |
86 | $status = $queueManager->insert( $queueRecord ); |
87 | |
88 | if ( $status->isGood() ) { |
89 | $this->mReviewedUpdated = $queueRecord->getReviewedUpdatedTimestamp(); |
90 | $this->currentReviewStatus = $reviewStatus; |
91 | } |
92 | |
93 | return true; |
94 | } |
95 | |
96 | /** |
97 | * Set the review status of an article in the PageTriage queue. |
98 | * |
99 | * TODO: Move this code into QueueManager::setStatusForPageId(). |
100 | * |
101 | * @param int $newReviewStatus see QueueRecord::VALID_REVIEW_STATUSES |
102 | * @param UserIdentity|null $user |
103 | * @param bool $fromRc |
104 | * @return bool If a page status was updated |
105 | */ |
106 | public function setTriageStatus( int $newReviewStatus = 0, UserIdentity $user = null, bool $fromRc = false ): bool { |
107 | if ( !in_array( $newReviewStatus, QueueRecord::VALID_REVIEW_STATUSES ) ) { |
108 | // TODO: Should log an error here, or maybe just not accept invalid review status to begin with. |
109 | $newReviewStatus = QueueRecord::REVIEW_STATUS_UNREVIEWED; |
110 | } |
111 | |
112 | if ( !$this->retrieve() ) { |
113 | // Page doesn't exist in pagetriage_page |
114 | return false; |
115 | } |
116 | if ( $this->currentReviewStatus === $newReviewStatus ) { |
117 | // Status doesn't change |
118 | return false; |
119 | } |
120 | if ( $this->currentReviewStatus === QueueRecord::REVIEW_STATUS_AUTOPATROLLED && |
121 | $newReviewStatus !== QueueRecord::REVIEW_STATUS_UNREVIEWED ) { |
122 | // Only unreviewing is allowed for autopatrolled articles |
123 | return false; |
124 | } |
125 | |
126 | $dbw = PageTriageUtil::getPrimaryConnection(); |
127 | $dbw->startAtomic( __METHOD__ ); |
128 | $set = [ |
129 | 'ptrp_reviewed' => $newReviewStatus, |
130 | 'ptrp_reviewed_updated' => $dbw->timestamp( wfTimestampNow() ), |
131 | 'ptrp_last_reviewed_by' => $user ? $user->getId() : 0 |
132 | ]; |
133 | $dbw->newUpdateQueryBuilder() |
134 | ->update( 'pagetriage_page' ) |
135 | ->set( $set ) |
136 | ->where( [ |
137 | 'ptrp_page_id' => $this->mPageId, |
138 | $dbw->expr( 'ptrp_reviewed', '!=', $newReviewStatus ), |
139 | ] ) |
140 | ->caller( __METHOD__ ) |
141 | ->execute(); |
142 | |
143 | if ( $dbw->affectedRows() > 0 ) { |
144 | $this->currentReviewStatus = $newReviewStatus; |
145 | $this->mReviewedUpdated = $set['ptrp_reviewed_updated']; |
146 | // @Todo - case for marking a page as untriaged and make sure this logic is correct |
147 | if ( !$fromRc && $newReviewStatus && $user ) { |
148 | $rc = RecentChange::newFromConds( [ |
149 | 'rc_cur_id' => $this->mPageId, |
150 | 'rc_new' => '1' |
151 | ], __METHOD__ ); |
152 | if ( $rc && !$rc->getAttribute( 'rc_patrolled' ) ) { |
153 | $rc->reallyMarkPatrolled(); |
154 | PatrolLog::record( $rc, false, $user, 'pagetriage' ); |
155 | } |
156 | } |
157 | } |
158 | $dbw->endAtomic( __METHOD__ ); |
159 | |
160 | $articleMetadata = new ArticleMetadata( [ $this->mPageId ] ); |
161 | $metadataArray = $articleMetadata->getMetadata(); |
162 | |
163 | if ( array_key_exists( $this->mPageId, $metadataArray ) ) { |
164 | $articleMetadata->flushMetadataFromCache( $this->mPageId ); |
165 | } |
166 | return true; |
167 | } |
168 | |
169 | /** |
170 | * Update the database record |
171 | * @param array $row key => value pair to be updated |
172 | * Todo: ptrpt_reviewed should not updated from this function, add exception to catch this |
173 | * or find a better solution |
174 | */ |
175 | public function update( $row ) { |
176 | if ( !$row ) { |
177 | return; |
178 | } |
179 | |
180 | $dbw = PageTriageUtil::getPrimaryConnection(); |
181 | $dbw->newUpdateQueryBuilder() |
182 | ->update( 'pagetriage_page' ) |
183 | ->set( $row ) |
184 | ->where( [ 'ptrp_page_id' => $this->mPageId ] ) |
185 | ->caller( __METHOD__ ) |
186 | ->execute(); |
187 | } |
188 | |
189 | /** |
190 | * Load a page triage record |
191 | * @return bool |
192 | */ |
193 | public function retrieve() { |
194 | if ( $this->mLoaded ) { |
195 | return true; |
196 | } |
197 | |
198 | $pageTriageServices = PageTriageServices::wrap( MediaWikiServices::getInstance() ); |
199 | $queueLookup = $pageTriageServices->getQueueLookup(); |
200 | $queueRecord = $queueLookup->getByPageId( $this->mPageId ); |
201 | if ( !$queueRecord ) { |
202 | return false; |
203 | } |
204 | |
205 | $this->currentReviewStatus = $queueRecord->getReviewedStatus(); |
206 | $this->mReviewedUpdated = wfTimestamp( TS_UNIX, $queueRecord->getReviewedUpdatedTimestamp() ); |
207 | $this->mLoaded = true; |
208 | return true; |
209 | } |
210 | |
211 | /** |
212 | * Set the tags updated timestamp |
213 | * @param array $pageIds |
214 | * @return string |
215 | */ |
216 | public static function bulkSetTagsUpdated( $pageIds ) { |
217 | $dbw = PageTriageUtil::getPrimaryConnection(); |
218 | |
219 | $now = wfTimestampNow(); |
220 | $dbw->newUpdateQueryBuilder() |
221 | ->update( 'pagetriage_page' ) |
222 | ->set( [ 'ptrp_tags_updated' => $dbw->timestamp( $now ) ] ) |
223 | ->where( [ 'ptrp_page_id' => $pageIds ] ) |
224 | ->caller( __METHOD__ ) |
225 | ->execute(); |
226 | |
227 | return $now; |
228 | } |
229 | } |