MediaWiki master
ApiProtect.php
Go to the documentation of this file.
1<?php
23namespace MediaWiki\Api;
24
25use ChangeTags;
26use InvalidArgumentException;
35
39class ApiProtect extends ApiBase {
40
42
43 private RestrictionStore $restrictionStore;
44
45 public function __construct(
46 ApiMain $mainModule,
47 string $moduleName,
48 WatchlistManager $watchlistManager,
49 UserOptionsLookup $userOptionsLookup,
50 RestrictionStore $restrictionStore
51 ) {
52 parent::__construct( $mainModule, $moduleName );
53 $this->restrictionStore = $restrictionStore;
54
55 // Variables needed in ApiWatchlistTrait trait
56 $this->watchlistExpiryEnabled = $this->getConfig()->get( MainConfigNames::WatchlistExpiry );
57 $this->watchlistMaxDuration =
59 $this->watchlistManager = $watchlistManager;
60 $this->userOptionsLookup = $userOptionsLookup;
61 }
62
63 public function execute() {
65
66 $pageObj = $this->getTitleOrPageId( $params, 'fromdbmaster' );
67 $titleObj = $pageObj->getTitle();
68 $this->getErrorFormatter()->setContextTitle( $titleObj );
69
70 $this->checkTitleUserPermissions( $titleObj, 'protect' );
71
72 $user = $this->getUser();
73 $tags = $params['tags'];
74
75 // Check if user can add tags
76 if ( $tags !== null ) {
77 $ableToTag = ChangeTags::canAddTagsAccompanyingChange( $tags, $this->getAuthority() );
78 if ( !$ableToTag->isOK() ) {
79 $this->dieStatus( $ableToTag );
80 }
81 }
82
83 $expiry = (array)$params['expiry'];
84 if ( count( $expiry ) != count( $params['protections'] ) ) {
85 if ( count( $expiry ) == 1 ) {
86 $expiry = array_fill( 0, count( $params['protections'] ), $expiry[0] );
87 } else {
88 $this->dieWithError( [
89 'apierror-toofewexpiries',
90 count( $expiry ),
91 count( $params['protections'] )
92 ] );
93 }
94 }
95
96 $restrictionTypes = $this->restrictionStore->listApplicableRestrictionTypes( $titleObj );
97 $levels = $this->getPermissionManager()->getNamespaceRestrictionLevels(
98 $titleObj->getNamespace(),
99 $user
100 );
101
102 $protections = [];
103 $expiries = [];
104 $resultProtections = [];
105 foreach ( $params['protections'] as $i => $prot ) {
106 $p = explode( '=', $prot );
107 $protections[$p[0]] = ( $p[1] == 'all' ? '' : $p[1] );
108
109 if ( $titleObj->exists() && $p[0] == 'create' ) {
110 $this->dieWithError( 'apierror-create-titleexists' );
111 }
112 if ( !$titleObj->exists() && $p[0] != 'create' ) {
113 $this->dieWithError( 'apierror-missingtitle-createonly' );
114 }
115
116 if ( !in_array( $p[0], $restrictionTypes ) && $p[0] != 'create' ) {
117 $this->dieWithError( [ 'apierror-protect-invalidaction', wfEscapeWikiText( $p[0] ) ] );
118 }
119 if ( !in_array( $p[1], $levels ) && $p[1] != 'all' ) {
120 $this->dieWithError( [ 'apierror-protect-invalidlevel', wfEscapeWikiText( $p[1] ) ] );
121 }
122
123 try {
124 $expiries[$p[0]] = ExpiryDef::normalizeExpiry( $expiry[$i], TS_MW );
125 } catch ( InvalidArgumentException $e ) {
126 $this->dieWithError( [ 'apierror-invalidexpiry', wfEscapeWikiText( $expiry[$i] ) ] );
127 }
128 if ( $expiries[$p[0]] < MWTimestamp::now( TS_MW ) ) {
129 $this->dieWithError( [ 'apierror-pastexpiry', wfEscapeWikiText( $expiry[$i] ) ] );
130 }
131
132 $resultProtections[] = [
133 $p[0] => $protections[$p[0]],
134 'expiry' => ApiResult::formatExpiry( $expiries[$p[0]], 'infinite' ),
135 ];
136 }
137
138 $cascade = $params['cascade'];
139
140 $watch = $params['watch'] ? 'watch' : $params['watchlist'];
141 $watchlistExpiry = $this->getExpiryFromParams( $params );
142 $this->setWatch( $watch, $titleObj, $user, 'watchdefault', $watchlistExpiry );
143
144 $status = $pageObj->doUpdateRestrictions(
145 $protections,
146 $expiries,
147 $cascade,
148 $params['reason'],
149 $user,
150 $tags ?? []
151 );
152
153 if ( !$status->isOK() ) {
154 $this->dieStatus( $status );
155 }
156 $res = [
157 'title' => $titleObj->getPrefixedText(),
158 'reason' => $params['reason']
159 ];
160 if ( $cascade ) {
161 $res['cascade'] = true;
162 }
163 $res['protections'] = $resultProtections;
164 $result = $this->getResult();
165 ApiResult::setIndexedTagName( $res['protections'], 'protection' );
166 $result->addValue( null, $this->getModuleName(), $res );
167 }
168
169 public function mustBePosted() {
170 return true;
171 }
172
173 public function isWriteMode() {
174 return true;
175 }
176
177 public function getAllowedParams() {
178 return [
179 'title' => [
180 ParamValidator::PARAM_TYPE => 'string',
181 ],
182 'pageid' => [
183 ParamValidator::PARAM_TYPE => 'integer',
184 ],
185 'protections' => [
186 ParamValidator::PARAM_ISMULTI => true,
187 ParamValidator::PARAM_REQUIRED => true,
188 ],
189 'expiry' => [
190 ParamValidator::PARAM_ISMULTI => true,
191 ParamValidator::PARAM_ALLOW_DUPLICATES => true,
192 ParamValidator::PARAM_DEFAULT => 'infinite',
193 ],
194 'reason' => '',
195 'tags' => [
196 ParamValidator::PARAM_TYPE => 'tags',
197 ParamValidator::PARAM_ISMULTI => true,
198 ],
199 'cascade' => false,
200 'watch' => [
201 ParamValidator::PARAM_DEFAULT => false,
202 ParamValidator::PARAM_DEPRECATED => true,
203 ],
204 ] + $this->getWatchlistParams();
205 }
206
207 public function needsToken() {
208 return 'csrf';
209 }
210
211 protected function getExamplesMessages() {
212 $title = Title::newMainPage()->getPrefixedText();
213 $mp = rawurlencode( $title );
214
215 return [
216 "action=protect&title={$mp}&token=123ABC&" .
217 'protections=edit=sysop|move=sysop&cascade=&expiry=20070901163000|never'
218 => 'apihelp-protect-example-protect',
219 "action=protect&title={$mp}&token=123ABC&" .
220 'protections=edit=all|move=all&reason=Lifting%20restrictions'
221 => 'apihelp-protect-example-unprotect',
222 "action=protect&title={$mp}&token=123ABC&" .
223 'protections=&reason=Lifting%20restrictions'
224 => 'apihelp-protect-example-unprotect2',
225 ];
226 }
227
228 public function getHelpUrls() {
229 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Protect';
230 }
231}
232
234class_alias( ApiProtect::class, 'ApiProtect' );
wfEscapeWikiText( $input)
Escapes the given text so that it may be output using addWikiText() without any linking,...
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:1565
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:1620
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:1703
getTitleOrPageId( $params, $load=false)
Attempts to load a WikiPage object from a title or pageid parameter, if possible.
Definition ApiBase.php:1172
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...
__construct(ApiMain $mainModule, string $moduleName, WatchlistManager $watchlistManager, UserOptionsLookup $userOptionsLookup, RestrictionStore $restrictionStore)
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
isWriteMode()
Indicates whether this module requires write access to the wiki.
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.
Library for creating and parsing MW-style timestamps.
Service for formatting and validating API parameters.
Type definition for expiry timestamps.
Definition ExpiryDef.php:17
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.