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