Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 72
0.00% covered (danger)
0.00%
0 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
ApiReview
0.00% covered (danger)
0.00%
0 / 72
0.00% covered (danger)
0.00%
0 / 6
702
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 51
0.00% covered (danger)
0.00%
0 / 1
380
 isWriteMode
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getAllowedParams
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
12
 needsToken
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getExamplesMessages
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3/**
4 * Created on Dec 20, 2008
5 *
6 * API module for MediaWiki's FlaggedRevs extension
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 * http://www.gnu.org/copyleft/gpl.html
22 */
23
24use MediaWiki\Api\ApiBase;
25use MediaWiki\Api\ApiMain;
26use MediaWiki\Revision\RevisionLookup;
27use MediaWiki\Title\Title;
28use Wikimedia\ParamValidator\ParamValidator;
29
30/**
31 * API module to review revisions
32 *
33 * @ingroup FlaggedRevs
34 */
35class ApiReview extends ApiBase {
36
37    private RevisionLookup $revisionLookup;
38
39    public function __construct(
40        ApiMain $main,
41        string $action,
42        RevisionLookup $revisionLookup
43    ) {
44        parent::__construct( $main, $action );
45        $this->revisionLookup = $revisionLookup;
46    }
47
48    /**
49     * The method checks basic permissions of the user to interact
50     * with the page. Then it submits the form of the revision on
51     * approve or unapprove action. It also generates the template
52     * parameters itself.
53     */
54    public function execute() {
55        $params = $this->extractRequestParams();
56        // Check basic permissions
57        $this->checkUserRightsAny( 'review' );
58
59        // Get target rev and title
60        $revid = (int)$params['revid'];
61        $revRecord = $this->revisionLookup->getRevisionById( $revid );
62        if ( !$revRecord ) {
63            $this->dieWithError( [ 'apierror-nosuchrevid', $revid ], 'notarget' );
64        }
65
66        $linkTarget = $revRecord->getPageAsLinkTarget();
67        if ( $this->getPermissionManager()->isBlockedFrom( $this->getUser(), $linkTarget, false ) ) {
68            // @phan-suppress-next-line PhanTypeMismatchArgumentNullable Guaranteed via isBlockedFrom() above
69            $this->dieBlocked( $this->getUser()->getBlock() );
70        }
71
72        $title = Title::newFromLinkTarget( $linkTarget );
73
74        // Construct submit form...
75        $form = new RevisionReviewForm( $this->getUser() );
76        $form->setTitle( $title );
77        $form->setOldId( $revid );
78        $form->setAction( $params['unapprove'] ?
79            RevisionReviewForm::ACTION_UNAPPROVE :
80            RevisionReviewForm::ACTION_APPROVE );
81        if ( isset( $params['comment'] ) ) {
82            $form->setComment( $params['comment'] );
83        }
84        // The flagging parameter has the form 'flag_$name' ($name varies
85        // by wiki). Extract it and put the value into $form->tag.
86        $form->setTag( FlaggedRevs::binaryFlagging() ?
87            1 :
88            (int)$params['flag_' . FlaggedRevs::getTagName() ]
89        );
90        if ( $form->getAction() === RevisionReviewForm::ACTION_APPROVE ) {
91            $form->bypassValidationKey(); // always OK; uses current templates
92        }
93
94        $form->ready(); // all params set
95
96        # Try to do the actual review
97        $status = $form->submit();
98        # Approve/de-approve success
99        if ( $status === true ) {
100            $this->getResult()->addValue(
101                null, $this->getModuleName(), [ 'result' => 'Success' ] );
102        # Generic failures
103        } elseif ( $status === 'review_page_notexists' ) {
104            $this->dieWithError( 'apierror-flaggedrevs-pagedoesnotexist', 'notarget' );
105        } elseif ( $status === 'review_page_unreviewable' ) {
106            $this->dieWithError( 'apierror-flaggedrevs-notreviewable', 'notreviewable' );
107        # Approve-specific failures
108        } elseif ( $form->getAction() === RevisionReviewForm::ACTION_APPROVE ) {
109            if ( $status === 'review_denied' ) {
110                $this->dieWithError( 'apierror-flaggedrevs-cantreview', 'permissiondenied' );
111            } elseif ( $status === 'review_too_low' ) {
112                $this->dieWithError( 'apierror-flaggedrevs-toolow', 'mixedapproval' );
113            } elseif ( $status === 'review_bad_key' ) {
114                $this->dieWithError( 'apierror-flaggedrevs-cantreview', 'permissiondenied' );
115            } elseif ( $status === 'review_bad_tags' ) {
116                $this->dieWithError( 'apierror-flaggedrevs-badflags', 'invalidtags' );
117            } elseif ( $status === 'review_bad_oldid' ) {
118                $this->dieWithError( [ 'apierror-nosuchrevid', $revid ], 'notarget' );
119            } else {
120                // FIXME: review_param_missing? better msg?
121                $this->dieWithError( [ 'apierror-unknownerror-nocode' ], 'unknownerror' );
122            }
123        # De-approve specific failure
124        } elseif ( $form->getAction() === RevisionReviewForm::ACTION_UNAPPROVE ) {
125            if ( $status === 'review_denied' ) {
126                $this->dieWithError( 'apierror-flaggedrevs-cantunreview', 'permissiondenied' );
127            } elseif ( $status === 'review_not_flagged' ) {
128                $this->dieWithError( 'apierror-flaggedrevs-noflaggedrev', 'notarget' );
129            } else {
130                // FIXME: review_param_missing? better msg?
131                $this->dieWithError( [ 'apierror-unknownerror-nocode' ], 'unknownerror' );
132            }
133        }
134    }
135
136    /**
137     * @inheritDoc
138     */
139    public function isWriteMode() {
140        return true;
141    }
142
143    /**
144     * @inheritDoc
145     */
146    protected function getAllowedParams() {
147        $pars = [
148            'revid' => null,
149            'comment' => null,
150            'unapprove' => false
151        ];
152        if ( !FlaggedRevs::binaryFlagging() && !FlaggedRevs::useOnlyIfProtected() ) {
153            $strLevels = array_map( 'strval', range( 0, FlaggedRevs::getMaxLevel() ) );
154            $pars['flag_' . FlaggedRevs::getTagName()] = [
155                ParamValidator::PARAM_DEFAULT => '1', // default
156                ParamValidator::PARAM_TYPE => $strLevels, // array of allowed values
157                ApiBase::PARAM_HELP_MSG => [ 'apihelp-review-param-flag', FlaggedRevs::getTagName() ],
158            ];
159        }
160        return $pars;
161    }
162
163    /**
164     * @return string
165     */
166    public function needsToken() {
167        return 'csrf';
168    }
169
170    /**
171     * @inheritDoc
172     */
173    protected function getExamplesMessages() {
174        return [
175            'action=review&revid=12345&token=123AB&flag_accuracy=1&comment=Ok'
176                => 'apihelp-review-example-1',
177        ];
178    }
179}