MediaWiki  master
ApiProtect.php
Go to the documentation of this file.
1 <?php
28 
32 class ApiProtect extends ApiBase {
33 
35 
37  private $restrictionStore;
38 
46  public function __construct(
47  ApiMain $mainModule,
48  $moduleName,
49  WatchlistManager $watchlistManager,
50  UserOptionsLookup $userOptionsLookup,
51  RestrictionStore $restrictionStore
52  ) {
53  parent::__construct( $mainModule, $moduleName );
54  $this->restrictionStore = $restrictionStore;
55 
56  // Variables needed in ApiWatchlistTrait trait
57  $this->watchlistExpiryEnabled = $this->getConfig()->get( MainConfigNames::WatchlistExpiry );
58  $this->watchlistMaxDuration =
59  $this->getConfig()->get( MainConfigNames::WatchlistExpiryMaxDuration );
60  $this->watchlistManager = $watchlistManager;
61  $this->userOptionsLookup = $userOptionsLookup;
62  }
63 
64  public function execute() {
65  $params = $this->extractRequestParams();
66 
67  $pageObj = $this->getTitleOrPageId( $params, 'fromdbmaster' );
68  $titleObj = $pageObj->getTitle();
69  $this->getErrorFormatter()->setContextTitle( $titleObj );
70 
71  $this->checkTitleUserPermissions( $titleObj, 'protect' );
72 
73  $user = $this->getUser();
74  $tags = $params['tags'];
75 
76  // Check if user can add tags
77  if ( $tags !== null ) {
78  $ableToTag = ChangeTags::canAddTagsAccompanyingChange( $tags, $this->getAuthority() );
79  if ( !$ableToTag->isOK() ) {
80  $this->dieStatus( $ableToTag );
81  }
82  }
83 
84  $expiry = (array)$params['expiry'];
85  if ( count( $expiry ) != count( $params['protections'] ) ) {
86  if ( count( $expiry ) == 1 ) {
87  $expiry = array_fill( 0, count( $params['protections'] ), $expiry[0] );
88  } else {
89  $this->dieWithError( [
90  'apierror-toofewexpiries',
91  count( $expiry ),
92  count( $params['protections'] )
93  ] );
94  }
95  }
96 
97  $restrictionTypes = $this->restrictionStore->listApplicableRestrictionTypes( $titleObj );
98  $levels = $this->getPermissionManager()->getNamespaceRestrictionLevels(
99  $titleObj->getNamespace(),
100  $user
101  );
102 
103  $protections = [];
104  $expiryarray = [];
105  $resultProtections = [];
106  foreach ( $params['protections'] as $i => $prot ) {
107  $p = explode( '=', $prot );
108  $protections[$p[0]] = ( $p[1] == 'all' ? '' : $p[1] );
109 
110  if ( $titleObj->exists() && $p[0] == 'create' ) {
111  $this->dieWithError( 'apierror-create-titleexists' );
112  }
113  if ( !$titleObj->exists() && $p[0] != 'create' ) {
114  $this->dieWithError( 'apierror-missingtitle-createonly' );
115  }
116 
117  if ( !in_array( $p[0], $restrictionTypes ) && $p[0] != 'create' ) {
118  $this->dieWithError( [ 'apierror-protect-invalidaction', wfEscapeWikiText( $p[0] ) ] );
119  }
120  if ( !in_array( $p[1], $levels ) && $p[1] != 'all' ) {
121  $this->dieWithError( [ 'apierror-protect-invalidlevel', wfEscapeWikiText( $p[1] ) ] );
122  }
123 
124  if ( wfIsInfinity( $expiry[$i] ) ) {
125  $expiryarray[$p[0]] = 'infinity';
126  } else {
127  $exp = strtotime( $expiry[$i] );
128  if ( $exp < 0 || !$exp ) {
129  $this->dieWithError( [ 'apierror-invalidexpiry', wfEscapeWikiText( $expiry[$i] ) ] );
130  }
131 
132  $exp = wfTimestamp( TS_MW, $exp );
133  if ( $exp < wfTimestampNow() ) {
134  $this->dieWithError( [ 'apierror-pastexpiry', wfEscapeWikiText( $expiry[$i] ) ] );
135  }
136  $expiryarray[$p[0]] = $exp;
137  }
138  $resultProtections[] = [
139  $p[0] => $protections[$p[0]],
140  'expiry' => ApiResult::formatExpiry( $expiryarray[$p[0]], 'infinite' ),
141  ];
142  }
143 
144  $cascade = $params['cascade'];
145 
146  $watch = $params['watch'] ? 'watch' : $params['watchlist'];
147  $watchlistExpiry = $this->getExpiryFromParams( $params );
148  $this->setWatch( $watch, $titleObj, $user, 'watchdefault', $watchlistExpiry );
149 
150  $status = $pageObj->doUpdateRestrictions(
151  $protections,
152  $expiryarray,
153  $cascade,
154  $params['reason'],
155  $user,
156  $tags ?? []
157  );
158 
159  if ( !$status->isOK() ) {
160  $this->dieStatus( $status );
161  }
162  $res = [
163  'title' => $titleObj->getPrefixedText(),
164  'reason' => $params['reason']
165  ];
166  if ( $cascade ) {
167  $res['cascade'] = true;
168  }
169  $res['protections'] = $resultProtections;
170  $result = $this->getResult();
171  ApiResult::setIndexedTagName( $res['protections'], 'protection' );
172  $result->addValue( null, $this->getModuleName(), $res );
173  }
174 
175  public function mustBePosted() {
176  return true;
177  }
178 
179  public function isWriteMode() {
180  return true;
181  }
182 
183  public function getAllowedParams() {
184  return [
185  'title' => [
186  ParamValidator::PARAM_TYPE => 'string',
187  ],
188  'pageid' => [
189  ParamValidator::PARAM_TYPE => 'integer',
190  ],
191  'protections' => [
192  ParamValidator::PARAM_ISMULTI => true,
193  ParamValidator::PARAM_REQUIRED => true,
194  ],
195  'expiry' => [
196  ParamValidator::PARAM_ISMULTI => true,
197  ParamValidator::PARAM_ALLOW_DUPLICATES => true,
198  ParamValidator::PARAM_DEFAULT => 'infinite',
199  ],
200  'reason' => '',
201  'tags' => [
202  ParamValidator::PARAM_TYPE => 'tags',
203  ParamValidator::PARAM_ISMULTI => true,
204  ],
205  'cascade' => false,
206  'watch' => [
207  ParamValidator::PARAM_DEFAULT => false,
208  ParamValidator::PARAM_DEPRECATED => true,
209  ],
210  ] + $this->getWatchlistParams();
211  }
212 
213  public function needsToken() {
214  return 'csrf';
215  }
216 
217  protected function getExamplesMessages() {
218  return [
219  'action=protect&title=Main%20Page&token=123ABC&' .
220  'protections=edit=sysop|move=sysop&cascade=&expiry=20070901163000|never'
221  => 'apihelp-protect-example-protect',
222  'action=protect&title=Main%20Page&token=123ABC&' .
223  'protections=edit=all|move=all&reason=Lifting%20restrictions'
224  => 'apihelp-protect-example-unprotect',
225  'action=protect&title=Main%20Page&token=123ABC&' .
226  'protections=&reason=Lifting%20restrictions'
227  => 'apihelp-protect-example-unprotect2',
228  ];
229  }
230 
231  public function getHelpUrls() {
232  return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Protect';
233  }
234 }
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.
getWatchlistParams(array $watchOptions=[])
Get additional allow params specific to watchlisting.
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
wfIsInfinity( $str)
Determine input string is represents as infinity.
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
This abstract class implements many basic API functions, and is the base of all API classes.
Definition: ApiBase.php:56
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
Definition: ApiBase.php:1453
getErrorFormatter()
Definition: ApiBase.php:640
getPermissionManager()
Obtain a PermissionManager instance that subclasses may use in their authorization checks.
Definition: ApiBase.php:686
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
checkTitleUserPermissions( $pageIdentity, $actions, array $options=[])
Helper function for permission-denied errors.
Definition: ApiBase.php:1588
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:498
getTitleOrPageId( $params, $load=false)
Get a WikiPage object from a title or pageid param, if possible.
Definition: ApiBase.php:1036
dieStatus(StatusValue $status)
Throw an ApiUsageException based on the Status object.
Definition: ApiBase.php:1516
This is the main API class, used for both external and internal processing.
Definition: ApiMain.php:52
isWriteMode()
Indicates whether this module requires write mode.
Definition: ApiProtect.php:179
getExamplesMessages()
Returns usage examples for this module.
Definition: ApiProtect.php:217
needsToken()
Returns the token type this module requires in order to execute.
Definition: ApiProtect.php:213
__construct(ApiMain $mainModule, $moduleName, WatchlistManager $watchlistManager, UserOptionsLookup $userOptionsLookup, RestrictionStore $restrictionStore)
Definition: ApiProtect.php:46
mustBePosted()
Indicates whether this module must be called with a POST request.
Definition: ApiProtect.php:175
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
Definition: ApiProtect.php:183
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
Definition: ApiProtect.php:64
getHelpUrls()
Return links to more detailed help pages about the module.
Definition: ApiProtect.php:231
static setIndexedTagName(array &$arr, $tag)
Set the tag name for numeric-keyed values in XML format.
Definition: ApiResult.php:604
static formatExpiry( $expiry, $infinity='infinity')
Format an expiry timestamp for API output.
Definition: ApiResult.php:1199
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...
Definition: ChangeTags.php:635
A class containing constants representing the names of configuration variables.
Provides access to user options.
Service for formatting and validating API parameters.
trait ApiWatchlistTrait
An ApiWatchlistTrait adds class properties and convenience methods for APIs that allow you to watch a...