Merge "Special:Upload should not crash on failing previews"
[mediawiki.git] / includes / api / ApiTag.php
blob7470ff3507c4578bcc7f0236a4174d5f149ed5dc
1 <?php
3 /**
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 * http://www.gnu.org/copyleft/gpl.html
19 * @file
22 /**
23 * @ingroup API
24 * @since 1.25
26 class ApiTag extends ApiBase {
28 public function execute() {
29 $params = $this->extractRequestParams();
30 $user = $this->getUser();
32 // make sure the user is allowed
33 $this->checkUserRightsAny( 'changetags' );
35 if ( $user->isBlocked() ) {
36 $this->dieBlocked( $user->getBlock() );
39 // Check if user can add tags
40 if ( count( $params['tags'] ) ) {
41 $ableToTag = ChangeTags::canAddTagsAccompanyingChange( $params['tags'], $user );
42 if ( !$ableToTag->isOk() ) {
43 $this->dieStatus( $ableToTag );
47 // validate and process each revid, rcid and logid
48 $this->requireAtLeastOneParameter( $params, 'revid', 'rcid', 'logid' );
49 $ret = [];
50 if ( $params['revid'] ) {
51 foreach ( $params['revid'] as $id ) {
52 $ret[] = $this->processIndividual( 'revid', $params, $id );
55 if ( $params['rcid'] ) {
56 foreach ( $params['rcid'] as $id ) {
57 $ret[] = $this->processIndividual( 'rcid', $params, $id );
60 if ( $params['logid'] ) {
61 foreach ( $params['logid'] as $id ) {
62 $ret[] = $this->processIndividual( 'logid', $params, $id );
66 ApiResult::setIndexedTagName( $ret, 'result' );
67 $this->getResult()->addValue( null, $this->getModuleName(), $ret );
70 protected static function validateLogId( $logid ) {
71 $dbr = wfGetDB( DB_REPLICA );
72 $result = $dbr->selectField( 'logging', 'log_id', [ 'log_id' => $logid ],
73 __METHOD__ );
74 return (bool)$result;
77 protected function processIndividual( $type, $params, $id ) {
78 $idResult = [ $type => $id ];
80 // validate the ID
81 $valid = false;
82 switch ( $type ) {
83 case 'rcid':
84 $valid = RecentChange::newFromId( $id );
85 break;
86 case 'revid':
87 $valid = Revision::newFromId( $id );
88 break;
89 case 'logid':
90 $valid = self::validateLogId( $id );
91 break;
94 if ( !$valid ) {
95 $idResult['status'] = 'error';
96 // Messages: apierror-nosuchrcid apierror-nosuchrevid apierror-nosuchlogid
97 $idResult += $this->getErrorFormatter()->formatMessage( [ "apierror-nosuch$type", $id ] );
98 return $idResult;
101 $status = ChangeTags::updateTagsWithChecks( $params['add'],
102 $params['remove'],
103 ( $type === 'rcid' ? $id : null ),
104 ( $type === 'revid' ? $id : null ),
105 ( $type === 'logid' ? $id : null ),
106 null,
107 $params['reason'],
108 $this->getUser() );
110 if ( !$status->isOK() ) {
111 if ( $status->hasMessage( 'actionthrottledtext' ) ) {
112 $idResult['status'] = 'skipped';
113 } else {
114 $idResult['status'] = 'failure';
115 $idResult['errors'] = $this->getErrorFormatter()->arrayFromStatus( $status, 'error' );
117 } else {
118 $idResult['status'] = 'success';
119 if ( is_null( $status->value->logId ) ) {
120 $idResult['noop'] = true;
121 } else {
122 $idResult['actionlogid'] = $status->value->logId;
123 $idResult['added'] = $status->value->addedTags;
124 ApiResult::setIndexedTagName( $idResult['added'], 't' );
125 $idResult['removed'] = $status->value->removedTags;
126 ApiResult::setIndexedTagName( $idResult['removed'], 't' );
128 if ( $params['tags'] ) {
129 ChangeTags::addTags( $params['tags'], null, null, $status->value->logId );
133 return $idResult;
136 public function mustBePosted() {
137 return true;
140 public function isWriteMode() {
141 return true;
144 public function getAllowedParams() {
145 return [
146 'rcid' => [
147 ApiBase::PARAM_TYPE => 'integer',
148 ApiBase::PARAM_ISMULTI => true,
150 'revid' => [
151 ApiBase::PARAM_TYPE => 'integer',
152 ApiBase::PARAM_ISMULTI => true,
154 'logid' => [
155 ApiBase::PARAM_TYPE => 'integer',
156 ApiBase::PARAM_ISMULTI => true,
158 'add' => [
159 ApiBase::PARAM_TYPE => 'tags',
160 ApiBase::PARAM_ISMULTI => true,
162 'remove' => [
163 ApiBase::PARAM_TYPE => 'string',
164 ApiBase::PARAM_ISMULTI => true,
166 'reason' => [
167 ApiBase::PARAM_DFLT => '',
169 'tags' => [
170 ApiBase::PARAM_TYPE => 'tags',
171 ApiBase::PARAM_ISMULTI => true,
176 public function needsToken() {
177 return 'csrf';
180 protected function getExamplesMessages() {
181 return [
182 'action=tag&revid=123&add=vandalism&token=123ABC'
183 => 'apihelp-tag-example-rev',
184 'action=tag&logid=123&remove=spam&reason=Wrongly+applied&token=123ABC'
185 => 'apihelp-tag-example-log',
189 public function getHelpUrls() {
190 return 'https://www.mediawiki.org/wiki/API:Tag';