MediaWiki master
ApiUserrights.php
Go to the documentation of this file.
1<?php
2
37
41class ApiUserrights extends ApiBase {
42
44
46 private $mUser = null;
47
48 private UserGroupManager $userGroupManager;
49 private WatchedItemStoreInterface $watchedItemStore;
50
59 public function __construct(
60 ApiMain $mainModule,
61 $moduleName,
62 UserGroupManager $userGroupManager,
63 WatchedItemStoreInterface $watchedItemStore,
64 WatchlistManager $watchlistManager,
65 UserOptionsLookup $userOptionsLookup
66 ) {
67 parent::__construct( $mainModule, $moduleName );
68 $this->userGroupManager = $userGroupManager;
69 $this->watchedItemStore = $watchedItemStore;
70
71 // Variables needed in ApiWatchlistTrait trait
72 $this->watchlistExpiryEnabled = $this->getConfig()->get( MainConfigNames::WatchlistExpiry );
73 $this->watchlistMaxDuration =
74 $this->getConfig()->get( MainConfigNames::WatchlistExpiryMaxDuration );
75 $this->watchlistManager = $watchlistManager;
76 $this->userOptionsLookup = $userOptionsLookup;
77 }
78
79 public function execute() {
80 $pUser = $this->getUser();
81
82 // Deny if the user is blocked and doesn't have the full 'userrights' permission.
83 // This matches what Special:UserRights does for the web UI.
84 if ( !$this->getAuthority()->isAllowed( 'userrights' ) ) {
85 $block = $pUser->getBlock( Authority::READ_LATEST );
86 if ( $block && $block->isSitewide() ) {
87 $this->dieBlocked( $block );
88 }
89 }
90
91 $params = $this->extractRequestParams();
92
93 // Figure out expiry times from the input
94 $expiry = (array)$params['expiry'];
95 $add = (array)$params['add'];
96 if ( !$add ) {
97 $expiry = [];
98 } elseif ( count( $expiry ) !== count( $add ) ) {
99 if ( count( $expiry ) === 1 ) {
100 $expiry = array_fill( 0, count( $add ), $expiry[0] );
101 } else {
102 $this->dieWithError( [
103 'apierror-toofewexpiries',
104 count( $expiry ),
105 count( $add )
106 ] );
107 }
108 }
109
110 // Validate the expiries
111 $groupExpiries = [];
112 foreach ( $expiry as $index => $expiryValue ) {
113 $group = $add[$index];
114 $groupExpiries[$group] = SpecialUserRights::expiryToTimestamp( $expiryValue );
115
116 if ( $groupExpiries[$group] === false ) {
117 $this->dieWithError( [ 'apierror-invalidexpiry', wfEscapeWikiText( $expiryValue ) ] );
118 }
119
120 // not allowed to have things expiring in the past
121 if ( $groupExpiries[$group] && $groupExpiries[$group] < wfTimestampNow() ) {
122 $this->dieWithError( [ 'apierror-pastexpiry', wfEscapeWikiText( $expiryValue ) ] );
123 }
124 }
125
126 $user = $this->getUrUser( $params );
127
128 $tags = $params['tags'];
129
130 // Check if user can add tags
131 if ( $tags !== null ) {
132 $ableToTag = ChangeTags::canAddTagsAccompanyingChange( $tags, $this->getAuthority() );
133 if ( !$ableToTag->isOK() ) {
134 $this->dieStatus( $ableToTag );
135 }
136 }
137
138 $form = new SpecialUserRights();
139 $form->setContext( $this->getContext() );
140 $r = [];
141 $r['user'] = $user->getName();
142 $r['userid'] = $user->getId();
143 [ $r['added'], $r['removed'] ] = $form->doSaveUserGroups(
144 // Don't pass null to doSaveUserGroups() for array params, cast to empty array
145 $user, $add, (array)$params['remove'],
146 $params['reason'], (array)$tags, $groupExpiries
147 );
148
149 $watchlistExpiry = $this->getExpiryFromParams( $params );
150 $watchuser = $params['watchuser'];
151 $userPage = Title::makeTitle( NS_USER, $user->getName() );
152 if ( $watchuser && $user->getWikiId() === UserIdentity::LOCAL ) {
153 $this->setWatch( 'watch', $userPage, $this->getUser(), null, $watchlistExpiry );
154 } else {
155 $watchuser = false;
156 $watchlistExpiry = null;
157 }
158 $r['watchuser'] = $watchuser;
159 if ( $watchlistExpiry !== null ) {
160 $r['watchlistexpiry'] = $this->getWatchlistExpiry(
161 $this->watchedItemStore,
162 $userPage,
163 $this->getUser()
164 );
165 }
166
167 $result = $this->getResult();
168 ApiResult::setIndexedTagName( $r['added'], 'group' );
169 ApiResult::setIndexedTagName( $r['removed'], 'group' );
170 $result->addValue( null, $this->getModuleName(), $r );
171 }
172
177 private function getUrUser( array $params ) {
178 if ( $this->mUser !== null ) {
179 return $this->mUser;
180 }
181
182 $this->requireOnlyOneParameter( $params, 'user', 'userid' );
183
184 $user = $params['user'] ?? '#' . $params['userid'];
185
186 $form = new SpecialUserRights();
187 $form->setContext( $this->getContext() );
188 $status = $form->fetchUser( $user );
189 if ( !$status->isOK() ) {
190 $this->dieStatus( $status );
191 }
192
193 $this->mUser = $status->value;
194
195 return $status->value;
196 }
197
198 public function mustBePosted() {
199 return true;
200 }
201
202 public function isWriteMode() {
203 return true;
204 }
205
206 public function getAllowedParams( $flags = 0 ) {
207 $allGroups = $this->userGroupManager->listAllGroups();
208
209 if ( $flags & ApiBase::GET_VALUES_FOR_HELP ) {
210 sort( $allGroups );
211 }
212
213 $params = [
214 'user' => [
215 ParamValidator::PARAM_TYPE => 'user',
216 UserDef::PARAM_ALLOWED_USER_TYPES => [ 'name', 'id' ],
217 ],
218 'userid' => [
219 ParamValidator::PARAM_TYPE => 'integer',
220 ParamValidator::PARAM_DEPRECATED => true,
221 ],
222 'add' => [
223 ParamValidator::PARAM_TYPE => $allGroups,
224 ParamValidator::PARAM_ISMULTI => true
225 ],
226 'expiry' => [
227 ParamValidator::PARAM_ISMULTI => true,
228 ParamValidator::PARAM_ALLOW_DUPLICATES => true,
229 ParamValidator::PARAM_DEFAULT => 'infinite',
230 ],
231 'remove' => [
232 ParamValidator::PARAM_TYPE => $allGroups,
233 ParamValidator::PARAM_ISMULTI => true
234 ],
235 'reason' => [
236 ParamValidator::PARAM_DEFAULT => ''
237 ],
238 'token' => [
239 // Standard definition automatically inserted
240 ApiBase::PARAM_HELP_MSG_APPEND => [ 'api-help-param-token-webui' ],
241 ],
242 'tags' => [
243 ParamValidator::PARAM_TYPE => 'tags',
244 ParamValidator::PARAM_ISMULTI => true
245 ],
246 'watchuser' => false,
247 ];
248
249 // Params appear in the docs in the order they are defined,
250 // which is why this is here and not at the bottom.
251 // @todo Find better way to support insertion at arbitrary position
252 if ( $this->watchlistExpiryEnabled ) {
253 $params += [
254 'watchlistexpiry' => [
255 ParamValidator::PARAM_TYPE => 'expiry',
256 ExpiryDef::PARAM_MAX => $this->watchlistMaxDuration,
257 ExpiryDef::PARAM_USE_MAX => true,
258 ]
259 ];
260 }
261
262 return $params;
263 }
264
265 public function needsToken() {
266 return 'userrights';
267 }
268
269 protected function getWebUITokenSalt( array $params ) {
270 return $this->getUrUser( $params )->getName();
271 }
272
273 protected function getExamplesMessages() {
274 return [
275 'action=userrights&user=FooBot&add=bot&remove=sysop|bureaucrat&token=123ABC'
276 => 'apihelp-userrights-example-user',
277 'action=userrights&userid=123&add=bot&remove=sysop|bureaucrat&token=123ABC'
278 => 'apihelp-userrights-example-userid',
279 'action=userrights&user=SometimeSysop&add=sysop&expiry=1%20month&token=123ABC'
280 => 'apihelp-userrights-example-expiry',
281 ];
282 }
283
284 public function getHelpUrls() {
285 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:User_group_membership';
286 }
287}
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
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
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:62
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
Definition ApiBase.php:1529
const PARAM_HELP_MSG_APPEND
((string|array|Message)[]) Specify additional i18n messages to append to the normal message for this ...
Definition ApiBase.php:176
requireOnlyOneParameter( $params,... $required)
Die if 0 or more than one of a certain set of parameters is set and not false.
Definition ApiBase.php:946
getResult()
Get the result object.
Definition ApiBase.php:667
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition ApiBase.php:807
const GET_VALUES_FOR_HELP
getAllowedParams() flag: When this is set, the result could take longer to generate,...
Definition ApiBase.php:247
getModuleName()
Get the name of the module being executed by this instance.
Definition ApiBase.php:528
dieStatus(StatusValue $status)
Throw an ApiUsageException based on the Status object.
Definition ApiBase.php:1584
dieBlocked(Block $block)
Throw an ApiUsageException, which will (if uncaught) call the main module's error handler and die wit...
Definition ApiBase.php:1558
This is the main API class, used for both external and internal processing.
Definition ApiMain.php:64
getHelpUrls()
Return links to more detailed help pages about the module.
getAllowedParams( $flags=0)
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
mustBePosted()
Indicates whether this module must be called with a POST request.
__construct(ApiMain $mainModule, $moduleName, UserGroupManager $userGroupManager, WatchedItemStoreInterface $watchedItemStore, WatchlistManager $watchlistManager, UserOptionsLookup $userOptionsLookup)
needsToken()
Returns the token type this module requires in order to execute.
isWriteMode()
Indicates whether this module requires write mode.
getExamplesMessages()
Returns usage examples for this module.
getWebUITokenSalt(array $params)
Fetch the salt used in the Web UI corresponding to this module.
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...
getContext()
Get the base IContextSource object.
A class containing constants representing the names of configuration variables.
Type definition for user types.
Definition UserDef.php:27
Special page to allow managing user group membership.
Represents a title within MediaWiki.
Definition Title.php:79
Provides access to user options.
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...
This interface represents the authority associated the current execution context, such as a web reque...
Definition Authority.php:37
Interface for objects representing user identity.
return true
Definition router.php:92