MediaWiki  master
ApiBlock.php
Go to the documentation of this file.
1 <?php
42 
49 class ApiBlock extends ApiBase {
50 
53 
55  private $blockPermissionCheckerFactory;
56 
58  private $blockUserFactory;
59 
61  private $titleFactory;
62 
64  private $userIdentityLookup;
65 
67  private $watchedItemStore;
68 
70  private $blockUtils;
71 
73  private $blockActionInfo;
74 
88  public function __construct(
89  ApiMain $main,
90  $action,
91  BlockPermissionCheckerFactory $blockPermissionCheckerFactory,
92  BlockUserFactory $blockUserFactory,
93  TitleFactory $titleFactory,
94  UserIdentityLookup $userIdentityLookup,
95  WatchedItemStoreInterface $watchedItemStore,
96  BlockUtils $blockUtils,
97  BlockActionInfo $blockActionInfo,
98  WatchlistManager $watchlistManager,
99  UserOptionsLookup $userOptionsLookup
100  ) {
101  parent::__construct( $main, $action );
102 
103  $this->blockPermissionCheckerFactory = $blockPermissionCheckerFactory;
104  $this->blockUserFactory = $blockUserFactory;
105  $this->titleFactory = $titleFactory;
106  $this->userIdentityLookup = $userIdentityLookup;
107  $this->watchedItemStore = $watchedItemStore;
108  $this->blockUtils = $blockUtils;
109  $this->blockActionInfo = $blockActionInfo;
110 
111  // Variables needed in ApiWatchlistTrait trait
112  $this->watchlistExpiryEnabled = $this->getConfig()->get( MainConfigNames::WatchlistExpiry );
113  $this->watchlistMaxDuration =
114  $this->getConfig()->get( MainConfigNames::WatchlistExpiryMaxDuration );
115  $this->watchlistManager = $watchlistManager;
116  $this->userOptionsLookup = $userOptionsLookup;
117  }
118 
125  public function execute() {
126  $this->checkUserRightsAny( 'block' );
127  $params = $this->extractRequestParams();
128  $this->requireOnlyOneParameter( $params, 'user', 'userid' );
129 
130  // Make sure $target contains a parsed target
131  if ( $params['user'] !== null ) {
132  $target = $params['user'];
133  } else {
134  $target = $this->userIdentityLookup->getUserIdentityByUserId( $params['userid'] );
135  if ( !$target ) {
136  $this->dieWithError( [ 'apierror-nosuchuserid', $params['userid'] ], 'nosuchuserid' );
137  }
138  }
139  [ $target, $targetType ] = $this->blockUtils->parseBlockTarget( $target );
140 
141  if (
142  $params['noemail'] &&
143  !$this->blockPermissionCheckerFactory
144  ->newBlockPermissionChecker(
145  $target,
146  $this->getAuthority()
147  )
148  ->checkEmailPermissions()
149  ) {
150  $this->dieWithError( 'apierror-cantblock-email' );
151  }
152 
153  $restrictions = [];
154  if ( $params['partial'] ) {
155  $pageRestrictions = array_map(
156  [ PageRestriction::class, 'newFromTitle' ],
157  (array)$params['pagerestrictions']
158  );
159 
160  $namespaceRestrictions = array_map( static function ( $id ) {
161  return new NamespaceRestriction( 0, $id );
162  }, (array)$params['namespacerestrictions'] );
163  $restrictions = array_merge( $pageRestrictions, $namespaceRestrictions );
164 
165  if ( $this->getConfig()->get( MainConfigNames::EnablePartialActionBlocks ) ) {
166  $actionRestrictions = array_map( function ( $action ) {
167  return new ActionRestriction( 0, $this->blockActionInfo->getIdFromAction( $action ) );
168  }, (array)$params['actionrestrictions'] );
169  $restrictions = array_merge( $restrictions, $actionRestrictions );
170  }
171  }
172 
173  $status = $this->blockUserFactory->newBlockUser(
174  $target,
175  $this->getAuthority(),
176  $params['expiry'],
177  $params['reason'],
178  [
179  'isCreateAccountBlocked' => $params['nocreate'],
180  'isEmailBlocked' => $params['noemail'],
181  'isHardBlock' => !$params['anononly'],
182  'isAutoblocking' => $params['autoblock'],
183  'isUserTalkEditBlocked' => !$params['allowusertalk'],
184  'isHideUser' => $params['hidename'],
185  'isPartial' => $params['partial'],
186  ],
187  $restrictions,
188  $params['tags']
189  )->placeBlock( $params['reblock'] );
190 
191  if ( !$status->isOK() ) {
192  $this->dieStatus( $status );
193  }
194 
195  $block = $status->value;
196 
197  $watchlistExpiry = $this->getExpiryFromParams( $params );
198  $userPage = Title::makeTitle( NS_USER, $block->getTargetName() );
199 
200  if ( $params['watchuser'] && $targetType !== AbstractBlock::TYPE_RANGE ) {
201  $this->setWatch( 'watch', $userPage, $this->getUser(), null, $watchlistExpiry );
202  }
203 
204  $res = [];
205 
206  $res['user'] = $block->getTargetName();
207  $res['userID'] = $target instanceof UserIdentity ? $target->getId() : 0;
208 
209  if ( $block instanceof DatabaseBlock ) {
210  $res['expiry'] = ApiResult::formatExpiry( $block->getExpiry(), 'infinite' );
211  $res['id'] = $block->getId();
212  } else {
213  # should be unreachable
214  $res['expiry'] = ''; // @codeCoverageIgnore
215  $res['id'] = ''; // @codeCoverageIgnore
216  }
217 
218  $res['reason'] = $params['reason'];
219  $res['anononly'] = $params['anononly'];
220  $res['nocreate'] = $params['nocreate'];
221  $res['autoblock'] = $params['autoblock'];
222  $res['noemail'] = $params['noemail'];
223  $res['hidename'] = $params['hidename'];
224  $res['allowusertalk'] = $params['allowusertalk'];
225  $res['watchuser'] = $params['watchuser'];
226  if ( $watchlistExpiry ) {
227  $expiry = $this->getWatchlistExpiry(
228  $this->watchedItemStore,
229  $userPage,
230  $this->getUser()
231  );
232  $res['watchlistexpiry'] = $expiry;
233  }
234  $res['partial'] = $params['partial'];
235  $res['pagerestrictions'] = $params['pagerestrictions'];
236  $res['namespacerestrictions'] = $params['namespacerestrictions'];
237  if ( $this->getConfig()->get( MainConfigNames::EnablePartialActionBlocks ) ) {
238  $res['actionrestrictions'] = $params['actionrestrictions'];
239  }
240 
241  $this->getResult()->addValue( null, $this->getModuleName(), $res );
242  }
243 
244  public function mustBePosted() {
245  return true;
246  }
247 
248  public function isWriteMode() {
249  return true;
250  }
251 
252  public function getAllowedParams() {
253  $params = [
254  'user' => [
255  ParamValidator::PARAM_TYPE => 'user',
256  UserDef::PARAM_ALLOWED_USER_TYPES => [ 'name', 'ip', 'cidr', 'id' ],
257  ],
258  'userid' => [
259  ParamValidator::PARAM_TYPE => 'integer',
260  ParamValidator::PARAM_DEPRECATED => true,
261  ],
262  'expiry' => 'never',
263  'reason' => '',
264  'anononly' => false,
265  'nocreate' => false,
266  'autoblock' => false,
267  'noemail' => false,
268  'hidename' => false,
269  'allowusertalk' => false,
270  'reblock' => false,
271  'watchuser' => false,
272  ];
273 
274  // Params appear in the docs in the order they are defined,
275  // which is why this is here and not at the bottom.
276  // @todo Find better way to support insertion at arbitrary position
277  if ( $this->watchlistExpiryEnabled ) {
278  $params += [
279  'watchlistexpiry' => [
280  ParamValidator::PARAM_TYPE => 'expiry',
281  ExpiryDef::PARAM_MAX => $this->watchlistMaxDuration,
282  ExpiryDef::PARAM_USE_MAX => true,
283  ]
284  ];
285  }
286 
287  $params += [
288  'tags' => [
289  ParamValidator::PARAM_TYPE => 'tags',
290  ParamValidator::PARAM_ISMULTI => true,
291  ],
292  'partial' => false,
293  'pagerestrictions' => [
294  ParamValidator::PARAM_TYPE => 'title',
295  TitleDef::PARAM_MUST_EXIST => true,
296 
297  // TODO: TitleDef returns instances of TitleValue when PARAM_RETURN_OBJECT is
298  // truthy. At the time of writing,
299  // MediaWiki\Block\Restriction\PageRestriction::newFromTitle accepts either
300  // string or instance of Title.
301  //TitleDef::PARAM_RETURN_OBJECT => true,
302 
303  ParamValidator::PARAM_ISMULTI => true,
304  ParamValidator::PARAM_ISMULTI_LIMIT1 => 10,
305  ParamValidator::PARAM_ISMULTI_LIMIT2 => 10,
306  ],
307  'namespacerestrictions' => [
308  ParamValidator::PARAM_ISMULTI => true,
309  ParamValidator::PARAM_TYPE => 'namespace',
310  ],
311  ];
312 
313  if ( $this->getConfig()->get( MainConfigNames::EnablePartialActionBlocks ) ) {
314  $params += [
315  'actionrestrictions' => [
316  ParamValidator::PARAM_ISMULTI => true,
317  ParamValidator::PARAM_TYPE => array_keys(
318  $this->blockActionInfo->getAllBlockActions()
319  ),
320  ],
321  ];
322  }
323 
324  return $params;
325  }
326 
327  public function needsToken() {
328  return 'csrf';
329  }
330 
331  protected function getExamplesMessages() {
332  // phpcs:disable Generic.Files.LineLength
333  return [
334  'action=block&user=192.0.2.5&expiry=3%20days&reason=First%20strike&token=123ABC'
335  => 'apihelp-block-example-ip-simple',
336  'action=block&user=Vandal&expiry=never&reason=Vandalism&nocreate=&autoblock=&noemail=&token=123ABC'
337  => 'apihelp-block-example-user-complex',
338  ];
339  // phpcs:enable
340  }
341 
342  public function getHelpUrls() {
343  return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Block';
344  }
345 }
getExpiryFromParams(array $params)
Get formatted expiry from the given parameters, or null if no expiry was provided.
setWatch(string $watch, Title $title, User $user, ?string $userOption=null, ?string $expiry=null)
Set a watch (or unwatch) based the based on a watchlist parameter.
getWatchlistExpiry(WatchedItemStoreInterface $store, Title $title, UserIdentity $user)
Get existing expiry from the database.
const NS_USER
Definition: Defines.php:66
This abstract class implements many basic API functions, and is the base of all API classes.
Definition: ApiBase.php:57
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
Definition: ApiBase.php:1455
checkUserRightsAny( $rights, $user=null)
Helper function for permission-denied errors.
Definition: ApiBase.php:1561
requireOnlyOneParameter( $params,... $required)
Die if none or more than one of a certain set of parameters is set and not false.
Definition: ApiBase.php:904
getResult()
Get the result object.
Definition: ApiBase.php:630
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:766
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:499
dieStatus(StatusValue $status)
Throw an ApiUsageException based on the Status object.
Definition: ApiBase.php:1516
API module that facilitates the blocking of users.
Definition: ApiBlock.php:49
needsToken()
Returns the token type this module requires in order to execute.
Definition: ApiBlock.php:327
getExamplesMessages()
Returns usage examples for this module.
Definition: ApiBlock.php:331
isWriteMode()
Indicates whether this module requires write mode.
Definition: ApiBlock.php:248
__construct(ApiMain $main, $action, BlockPermissionCheckerFactory $blockPermissionCheckerFactory, BlockUserFactory $blockUserFactory, TitleFactory $titleFactory, UserIdentityLookup $userIdentityLookup, WatchedItemStoreInterface $watchedItemStore, BlockUtils $blockUtils, BlockActionInfo $blockActionInfo, WatchlistManager $watchlistManager, UserOptionsLookup $userOptionsLookup)
Definition: ApiBlock.php:88
mustBePosted()
Indicates whether this module must be called with a POST request.
Definition: ApiBlock.php:244
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
Definition: ApiBlock.php:252
execute()
Blocks the user specified in the parameters for the given expiry, with the given reason,...
Definition: ApiBlock.php:125
getHelpUrls()
Return links to more detailed help pages about the module.
Definition: ApiBlock.php:342
This is the main API class, used for both external and internal processing.
Definition: ApiMain.php:55
static formatExpiry( $expiry, $infinity='infinity')
Format an expiry timestamp for API output.
Definition: ApiResult.php:1199
Defines the actions that can be blocked by a partial block.
Backend class for blocking utils.
Definition: BlockUtils.php:46
A DatabaseBlock (unlike a SystemBlock) is stored in the database, may give rise to autoblocks and may...
Restriction for partial blocks of actions.
A class containing constants representing the names of configuration variables.
Creates Title objects.
Provides access to user options.
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:641
Service for formatting and validating API parameters.
Type definition for expiry timestamps.
Definition: ExpiryDef.php:17
trait ApiBlockInfoTrait
trait ApiWatchlistTrait
An ApiWatchlistTrait adds class properties and convenience methods for APIs that allow you to watch a...
Interface for objects representing user identity.
getId( $wikiId=self::LOCAL)