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