Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
97.59% |
81 / 83 |
|
87.50% |
7 / 8 |
CRAP | |
0.00% |
0 / 1 |
ApiPageTriageTagCopyvio | |
97.59% |
81 / 83 |
|
87.50% |
7 / 8 |
15 | |
0.00% |
0 / 1 |
execute | |
93.10% |
27 / 29 |
|
0.00% |
0 / 1 |
6.01 | |||
insertCopyvioTag | |
100.00% |
17 / 17 |
|
100.00% |
1 / 1 |
2 | |||
deleteCopyvioTag | |
100.00% |
16 / 16 |
|
100.00% |
1 / 1 |
2 | |||
logActivity | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
1 | |||
needsToken | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getAllowedParams | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
1 | |||
mustBePosted | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isWriteMode | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | |
3 | namespace MediaWiki\Extension\PageTriage\Api; |
4 | |
5 | use ApiBase; |
6 | use ManualLogEntry; |
7 | use MediaWiki\Extension\PageTriage\ArticleMetadata; |
8 | use MediaWiki\Extension\PageTriage\PageTriageUtil; |
9 | use MediaWiki\MediaWikiServices; |
10 | use MediaWiki\Revision\RevisionRecord; |
11 | use MediaWiki\Title\Title; |
12 | use Wikimedia\ParamValidator\ParamValidator; |
13 | use Wikimedia\Rdbms\IDatabase; |
14 | |
15 | class ApiPageTriageTagCopyvio extends ApiBase { |
16 | |
17 | public function execute() { |
18 | $this->checkUserRightsAny( 'pagetriage-copyvio' ); |
19 | |
20 | $params = $this->extractRequestParams(); |
21 | $revisionStore = MediaWikiServices::getInstance()->getRevisionStore(); |
22 | $revision = $revisionStore->getRevisionById( $params['revid'] ); |
23 | if ( !$revision ) { |
24 | $this->dieWithError( [ 'apierror-nosuchrevid', $params['revid'] ] ); |
25 | } |
26 | |
27 | $pageId = $revision->getPageId(); |
28 | if ( !ArticleMetadata::validatePageIds( [ $pageId ] ) ) { |
29 | $this->dieWithError( 'apierror-bad-pagetriage-page' ); |
30 | } |
31 | |
32 | $tags = ArticleMetadata::getValidTags(); |
33 | if ( !$tags || !$tags['copyvio'] ) { |
34 | $this->dieWithError( 'apierror-pagetriage-missingtag' ); |
35 | } |
36 | |
37 | // If the page hasn't been tagged with copyvio yet, then insert and log. |
38 | $row = [ |
39 | 'ptrpt_page_id' => $pageId, |
40 | 'ptrpt_tag_id' => $tags['copyvio'], |
41 | 'ptrpt_value' => (string)$revision->getId() |
42 | ]; |
43 | $dbw = PageTriageUtil::getPrimaryConnection(); |
44 | $dbr = PageTriageUtil::getReplicaConnection(); |
45 | $ptrptPageId = $dbr->newSelectQueryBuilder() |
46 | ->select( 'ptrpt_page_id' ) |
47 | ->from( 'pagetriage_page_tags' ) |
48 | ->where( $row ) |
49 | ->caller( __METHOD__ ) |
50 | ->fetchField(); |
51 | if ( $params['untag'] ) { |
52 | $result = $this->deleteCopyvioTag( $ptrptPageId, $dbw, $row, $revision ); |
53 | } else { |
54 | $result = $this->insertCopyvioTag( $ptrptPageId, $dbw, $row, $revision ); |
55 | } |
56 | |
57 | $this->getResult()->addValue( null, $this->getModuleName(), $result ); |
58 | } |
59 | |
60 | /** |
61 | * Insert a copyvio tag for a particular revision of a particular page |
62 | * |
63 | * @param int|false $ptrptPageId |
64 | * @param IDatabase $dbw |
65 | * @param array $row SQL condition for use in a WHERE clause |
66 | * @param revisionRecord $revision |
67 | * @return array |
68 | */ |
69 | private function insertCopyvioTag( $ptrptPageId, $dbw, $row, $revision ) { |
70 | $pageNotTaggedForCopyvio = $ptrptPageId === false; |
71 | if ( $pageNotTaggedForCopyvio ) { |
72 | $dbw->newReplaceQueryBuilder() |
73 | ->replaceInto( 'pagetriage_page_tags' ) |
74 | ->uniqueIndexFields( [ 'ptrpt_page_id', 'ptrpt_tag_id' ] ) |
75 | ->row( $row ) |
76 | ->caller( __METHOD__ ) |
77 | ->execute(); |
78 | |
79 | $metadata = new ArticleMetadata( [ $revision->getPageId() ] ); |
80 | $metadata->flushMetadataFromCache(); |
81 | |
82 | $this->logActivity( $revision ); |
83 | $result = [ 'result' => 'success' ]; |
84 | } else { |
85 | $result = [ |
86 | 'result' => 'done', |
87 | 'pagetriage_unchanged_status' => $revision->getId(), |
88 | ]; |
89 | } |
90 | return $result; |
91 | } |
92 | |
93 | /** |
94 | * Delete a copyvio tag for a particular revision of a particular page |
95 | * |
96 | * @param int|false $ptrptPageId |
97 | * @param IDatabase $dbw |
98 | * @param array $row SQL condition for use in a WHERE clause |
99 | * @param revisionRecord $revision |
100 | * @return array |
101 | */ |
102 | private function deleteCopyvioTag( $ptrptPageId, $dbw, $row, $revision ) { |
103 | $pageNotTaggedForCopyvio = $ptrptPageId === false; |
104 | if ( $pageNotTaggedForCopyvio ) { |
105 | $result = [ |
106 | 'result' => 'done', |
107 | 'pagetriage_unchanged_status' => $revision->getId(), |
108 | ]; |
109 | } else { |
110 | $dbw->newDeleteQueryBuilder() |
111 | ->delete( 'pagetriage_page_tags' ) |
112 | ->where( $row ) |
113 | ->caller( __METHOD__ ) |
114 | ->execute(); |
115 | $this->logActivity( $revision, 'delete' ); |
116 | $result = [ 'result' => 'success' ]; |
117 | |
118 | $metadata = new ArticleMetadata( [ $revision->getPageId() ] ); |
119 | $metadata->flushMetadataFromCache(); |
120 | } |
121 | return $result; |
122 | } |
123 | |
124 | /** |
125 | * Log insertion activity for this API endpoint. |
126 | * |
127 | * @param RevisionRecord $revision |
128 | */ |
129 | protected function logActivity( RevisionRecord $revision, string $action = 'insert' ) { |
130 | $logEntry = new ManualLogEntry( 'pagetriage-copyvio', $action ); |
131 | $logEntry->setPerformer( $this->getUser() ); |
132 | $logEntry->setTarget( Title::newFromID( $revision->getPageId() ) ); |
133 | $logEntry->setParameters( [ |
134 | '4::revId' => $revision->getId(), |
135 | ] ); |
136 | $logEntry->addTags( 'pagetriage' ); |
137 | $logEntry->publish( $logEntry->insert() ); |
138 | } |
139 | |
140 | /** @inheritDoc */ |
141 | public function needsToken() { |
142 | return 'csrf'; |
143 | } |
144 | |
145 | /** |
146 | * @inheritDoc |
147 | */ |
148 | public function getAllowedParams() { |
149 | return [ |
150 | 'revid' => [ |
151 | ParamValidator::PARAM_REQUIRED => true, |
152 | ParamValidator::PARAM_TYPE => 'integer' |
153 | ], |
154 | 'untag' => [ |
155 | ParamValidator::PARAM_REQUIRED => false, |
156 | ParamValidator::PARAM_TYPE => 'boolean' |
157 | ] |
158 | ]; |
159 | } |
160 | |
161 | /** @inheritDoc */ |
162 | public function mustBePosted() { |
163 | return true; |
164 | } |
165 | |
166 | /** @inheritDoc */ |
167 | public function isWriteMode() { |
168 | return true; |
169 | } |
170 | } |