MediaWiki REL1_39
ApiTag.php
Go to the documentation of this file.
1<?php
2
26
31class ApiTag extends ApiBase {
32
34
36 private $dbr;
37
39 private $revisionStore;
40
47 public function __construct(
48 ApiMain $main,
49 $action,
50 ILoadBalancer $loadBalancer,
51 RevisionStore $revisionStore
52 ) {
53 parent::__construct( $main, $action );
54 $this->dbr = $loadBalancer->getConnectionRef( DB_REPLICA );
55 $this->revisionStore = $revisionStore;
56 }
57
58 public function execute() {
59 $params = $this->extractRequestParams();
60 $user = $this->getUser();
61
62 // make sure the user is allowed
63 $this->checkUserRightsAny( 'changetags' );
64
65 // Fail early if the user is sitewide blocked.
66 $block = $user->getBlock();
67 if ( $block && $block->isSitewide() ) {
68 $this->dieBlocked( $block );
69 }
70
71 // Check if user can add tags
72 if ( $params['tags'] ) {
73 $ableToTag = ChangeTags::canAddTagsAccompanyingChange( $params['tags'], $this->getAuthority() );
74 if ( !$ableToTag->isOK() ) {
75 $this->dieStatus( $ableToTag );
76 }
77 }
78
79 // validate and process each revid, rcid and logid
80 $this->requireAtLeastOneParameter( $params, 'revid', 'rcid', 'logid' );
81 $ret = [];
82 if ( $params['revid'] ) {
83 foreach ( $params['revid'] as $id ) {
84 $ret[] = $this->processIndividual( 'revid', $params, $id );
85 }
86 }
87 if ( $params['rcid'] ) {
88 foreach ( $params['rcid'] as $id ) {
89 $ret[] = $this->processIndividual( 'rcid', $params, $id );
90 }
91 }
92 if ( $params['logid'] ) {
93 foreach ( $params['logid'] as $id ) {
94 $ret[] = $this->processIndividual( 'logid', $params, $id );
95 }
96 }
97
98 ApiResult::setIndexedTagName( $ret, 'result' );
99 $this->getResult()->addValue( null, $this->getModuleName(), $ret );
100 }
101
102 protected function validateLogId( $logid ) {
103 $result = $this->dbr->selectField( 'logging', 'log_id', [ 'log_id' => $logid ],
104 __METHOD__ );
105 return (bool)$result;
106 }
107
108 protected function processIndividual( $type, $params, $id ) {
109 $user = $this->getUser();
110 $idResult = [ $type => $id ];
111
112 // validate the ID
113 $valid = false;
114 switch ( $type ) {
115 case 'rcid':
116 $valid = RecentChange::newFromId( $id );
117 // TODO: replace use of PermissionManager
118 if ( $valid && $this->getPermissionManager()->isBlockedFrom( $user, $valid->getTitle() ) ) {
119 $idResult['status'] = 'error';
120 // @phan-suppress-next-line PhanTypeMismatchArgument
121 $idResult += $this->getErrorFormatter()->formatMessage( ApiMessage::create(
122 'apierror-blocked',
123 'blocked',
124 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable Block is checked and not null
125 [ 'blockinfo' => $this->getBlockDetails( $user->getBlock() ) ]
126 ) );
127 return $idResult;
128 }
129 break;
130 case 'revid':
131 $valid = $this->revisionStore->getRevisionById( $id );
132 // TODO: replace use of PermissionManager
133 if (
134 $valid &&
135 $this->getPermissionManager()->isBlockedFrom( $user, $valid->getPageAsLinkTarget() )
136 ) {
137 $idResult['status'] = 'error';
138 // @phan-suppress-next-line PhanTypeMismatchArgument
139 $idResult += $this->getErrorFormatter()->formatMessage( ApiMessage::create(
140 'apierror-blocked',
141 'blocked',
142 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable Block is checked and not null
143 [ 'blockinfo' => $this->getBlockDetails( $user->getBlock() ) ]
144 ) );
145 return $idResult;
146 }
147 break;
148 case 'logid':
149 $valid = $this->validateLogId( $id );
150 break;
151 }
152
153 if ( !$valid ) {
154 $idResult['status'] = 'error';
155 // Messages: apierror-nosuchrcid apierror-nosuchrevid apierror-nosuchlogid
156 $idResult += $this->getErrorFormatter()->formatMessage( [ "apierror-nosuch$type", $id ] );
157 return $idResult;
158 }
159
160 $status = ChangeTags::updateTagsWithChecks( $params['add'],
161 $params['remove'],
162 ( $type === 'rcid' ? $id : null ),
163 ( $type === 'revid' ? $id : null ),
164 ( $type === 'logid' ? $id : null ),
165 null,
166 $params['reason'],
167 $this->getAuthority()
168 );
169
170 if ( !$status->isOK() ) {
171 if ( $status->hasMessage( 'actionthrottledtext' ) ) {
172 $idResult['status'] = 'skipped';
173 } else {
174 $idResult['status'] = 'failure';
175 $idResult['errors'] = $this->getErrorFormatter()->arrayFromStatus( $status, 'error' );
176 }
177 } else {
178 $idResult['status'] = 'success';
179 if ( $status->value->logId === null ) {
180 $idResult['noop'] = true;
181 } else {
182 $idResult['actionlogid'] = $status->value->logId;
183 $idResult['added'] = $status->value->addedTags;
184 ApiResult::setIndexedTagName( $idResult['added'], 't' );
185 $idResult['removed'] = $status->value->removedTags;
186 ApiResult::setIndexedTagName( $idResult['removed'], 't' );
187
188 if ( $params['tags'] ) {
189 ChangeTags::addTags( $params['tags'], null, null, $status->value->logId );
190 }
191 }
192 }
193 return $idResult;
194 }
195
196 public function mustBePosted() {
197 return true;
198 }
199
200 public function isWriteMode() {
201 return true;
202 }
203
204 public function getAllowedParams() {
205 return [
206 'rcid' => [
207 ParamValidator::PARAM_TYPE => 'integer',
208 ParamValidator::PARAM_ISMULTI => true,
209 ],
210 'revid' => [
211 ParamValidator::PARAM_TYPE => 'integer',
212 ParamValidator::PARAM_ISMULTI => true,
213 ],
214 'logid' => [
215 ParamValidator::PARAM_TYPE => 'integer',
216 ParamValidator::PARAM_ISMULTI => true,
217 ],
218 'add' => [
219 ParamValidator::PARAM_TYPE => 'tags',
220 ParamValidator::PARAM_ISMULTI => true,
221 ],
222 'remove' => [
223 ParamValidator::PARAM_TYPE => 'string',
224 ParamValidator::PARAM_ISMULTI => true,
225 ],
226 'reason' => [
227 ParamValidator::PARAM_TYPE => 'string',
228 ParamValidator::PARAM_DEFAULT => '',
229 ],
230 'tags' => [
231 ParamValidator::PARAM_TYPE => 'tags',
232 ParamValidator::PARAM_ISMULTI => true,
233 ],
234 ];
235 }
236
237 public function needsToken() {
238 return 'csrf';
239 }
240
241 protected function getExamplesMessages() {
242 return [
243 'action=tag&revid=123&add=vandalism&token=123ABC'
244 => 'apihelp-tag-example-rev',
245 'action=tag&logid=123&remove=spam&reason=Wrongly+applied&token=123ABC'
246 => 'apihelp-tag-example-log',
247 ];
248 }
249
250 public function getHelpUrls() {
251 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Tag';
252 }
253}
This abstract class implements many basic API functions, and is the base of all API classes.
Definition ApiBase.php:56
checkUserRightsAny( $rights, $user=null)
Helper function for permission-denied errors.
Definition ApiBase.php:1560
getErrorFormatter()
Definition ApiBase.php:640
getPermissionManager()
Obtain a PermissionManager instance that subclasses may use in their authorization checks.
Definition ApiBase.php:686
requireAtLeastOneParameter( $params,... $required)
Die if none of a certain set of parameters is set and not false.
Definition ApiBase.php:963
getResult()
Get the result object.
Definition ApiBase.php:629
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition ApiBase.php:765
getModuleName()
Get the name of the module being executed by this instance.
Definition ApiBase.php:498
dieStatus(StatusValue $status)
Throw an ApiUsageException based on the Status object.
Definition ApiBase.php:1515
dieBlocked(Block $block)
Throw an ApiUsageException, which will (if uncaught) call the main module's error handler and die wit...
Definition ApiBase.php:1483
This is the main API class, used for both external and internal processing.
Definition ApiMain.php:52
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
Definition ApiTag.php:204
processIndividual( $type, $params, $id)
Definition ApiTag.php:108
validateLogId( $logid)
Definition ApiTag.php:102
getExamplesMessages()
Returns usage examples for this module.
Definition ApiTag.php:241
isWriteMode()
Indicates whether this module requires write mode.
Definition ApiTag.php:200
getHelpUrls()
Return links to more detailed help pages about the module.
Definition ApiTag.php:250
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
Definition ApiTag.php:58
__construct(ApiMain $main, $action, ILoadBalancer $loadBalancer, RevisionStore $revisionStore)
Definition ApiTag.php:47
mustBePosted()
Indicates whether this module must be called with a POST request.
Definition ApiTag.php:196
needsToken()
Returns the token type this module requires in order to execute.
Definition ApiTag.php:237
static updateTagsWithChecks( $tagsToAdd, $tagsToRemove, $rc_id, $rev_id, $log_id, $params, string $reason, Authority $performer)
Adds and/or removes tags to/from a given change, checking whether it is allowed first,...
static addTags( $tags, $rc_id=null, $rev_id=null, $log_id=null, $params=null, RecentChange $rc=null)
Add tags to a change given its rc_id, rev_id and/or log_id.
static canAddTagsAccompanyingChange(array $tags, Authority $performer=null, $checkBlock=true)
Is it OK to allow the user to apply all the specified tags at the same time as they edit/make the cha...
Service for looking up page revisions.
Service for formatting and validating API parameters.
trait ApiBlockInfoTrait
Basic database interface for live and lazy-loaded relation database handles.
Definition IDatabase.php:39
Create and track the database connections and transactions for a given database cluster.
getConnectionRef( $i, $groups=[], $domain=false, $flags=0)
const DB_REPLICA
Definition defines.php:26