Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
97.59% covered (success)
97.59%
81 / 83
87.50% covered (warning)
87.50%
7 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
ApiPageTriageTagCopyvio
97.59% covered (success)
97.59%
81 / 83
87.50% covered (warning)
87.50%
7 / 8
15
0.00% covered (danger)
0.00%
0 / 1
 execute
93.10% covered (success)
93.10%
27 / 29
0.00% covered (danger)
0.00%
0 / 1
6.01
 insertCopyvioTag
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
1 / 1
2
 deleteCopyvioTag
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
2
 logActivity
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 needsToken
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getAllowedParams
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
1
 mustBePosted
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isWriteMode
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace MediaWiki\Extension\PageTriage\Api;
4
5use ApiBase;
6use ManualLogEntry;
7use MediaWiki\Extension\PageTriage\ArticleMetadata;
8use MediaWiki\Extension\PageTriage\PageTriageUtil;
9use MediaWiki\MediaWikiServices;
10use MediaWiki\Revision\RevisionRecord;
11use MediaWiki\Title\Title;
12use Wikimedia\ParamValidator\ParamValidator;
13use Wikimedia\Rdbms\IDatabase;
14
15class 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}