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