MediaWiki REL1_37
ApiOptions.php
Go to the documentation of this file.
1<?php
27
34class ApiOptions extends ApiBase {
37
40
43
50 public function __construct(
51 ApiMain $main,
52 $action,
53 UserOptionsManager $userOptionsManager = null,
54 PreferencesFactory $preferencesFactory = null
55 ) {
56 parent::__construct( $main, $action );
61 $services = MediaWikiServices::getInstance();
62 $this->userOptionsManager = $userOptionsManager ?? $services->getUserOptionsManager();
63 $this->preferencesFactory = $preferencesFactory ?? $services->getPreferencesFactory();
64 }
65
69 public function execute() {
70 $user = $this->getUserForUpdates();
71 if ( !$user || !$user->isRegistered() ) {
72 $this->dieWithError(
73 [ 'apierror-mustbeloggedin', $this->msg( 'action-editmyoptions' ) ], 'notloggedin'
74 );
75 }
76
77 $this->checkUserRightsAny( 'editmyoptions' );
78
79 $params = $this->extractRequestParams();
80 $changed = false;
81
82 if ( isset( $params['optionvalue'] ) && !isset( $params['optionname'] ) ) {
83 $this->dieWithError( [ 'apierror-missingparam', 'optionname' ] );
84 }
85
86 $resetKinds = $params['resetkinds'];
87 if ( !$params['reset'] ) {
88 $resetKinds = [];
89 }
90
91 $changes = [];
92 if ( $params['change'] ) {
93 foreach ( $params['change'] as $entry ) {
94 $array = explode( '=', $entry, 2 );
95 $changes[$array[0]] = $array[1] ?? null;
96 }
97 }
98 if ( isset( $params['optionname'] ) ) {
99 $newValue = $params['optionvalue'] ?? null;
100 $changes[$params['optionname']] = $newValue;
101 }
102
103 $this->getHookRunner()->onApiOptions( $this, $user, $changes, $resetKinds );
104
105 if ( $resetKinds ) {
106 $this->resetPreferences( $resetKinds );
107 $changed = true;
108 }
109
110 if ( !$changed && !count( $changes ) ) {
111 $this->dieWithError( 'apierror-nochanges' );
112 }
113
114 $prefs = $this->getPreferences();
115 $prefsKinds = $this->userOptionsManager->getOptionKinds( $user, $this->getContext(), $changes );
116
117 $htmlForm = null;
118 foreach ( $changes as $key => $value ) {
119 switch ( $prefsKinds[$key] ) {
120 case 'registered':
121 // Regular option.
122 if ( $value === null ) {
123 // Reset it
124 $validation = true;
125 } else {
126 // Validate
127 if ( $htmlForm === null ) {
128 // We need a dummy HTMLForm for the validate callback...
129 $htmlForm = new HTMLForm( [], $this );
130 }
131 $field = HTMLForm::loadInputFromParameters( $key, $prefs[$key], $htmlForm );
132 $validation = $field->validate( $value, $this->userOptionsManager->getOptions( $user ) );
133 }
134 break;
135 case 'registered-multiselect':
136 case 'registered-checkmatrix':
137 // A key for a multiselect or checkmatrix option.
138 $validation = true;
139 $value = $value !== null ? (bool)$value : null;
140 break;
141 case 'userjs':
142 // Allow non-default preferences prefixed with 'userjs-', to be set by user scripts
143 if ( strlen( $key ) > 255 ) {
144 $validation = $this->msg( 'apiwarn-validationfailed-keytoolong', Message::numParam( 255 ) );
145 } elseif ( preg_match( '/[^a-zA-Z0-9_-]/', $key ) !== 0 ) {
146 $validation = $this->msg( 'apiwarn-validationfailed-badchars' );
147 } else {
148 $validation = true;
149 }
150
151 LoggerFactory::getInstance( 'api-warning' )->info(
152 'ApiOptions: Setting userjs option',
153 [
154 'phab' => 'T259073',
155 'OptionName' => substr( $key, 0, 255 ),
156 'OptionValue' => substr( $value ?? '', 0, 255 ),
157 'OptionSize' => strlen( $value ?? '' ),
158 'OptionValidation' => $validation,
159 'UserId' => $user->getId(),
160 'RequestIP' => $this->getRequest()->getIP(),
161 'RequestUA' => $this->getRequest()->getHeader( 'User-Agent' )
162 ]
163 );
164 break;
165 case 'special':
166 $validation = $this->msg( 'apiwarn-validationfailed-cannotset' );
167 break;
168 case 'unused':
169 default:
170 $validation = $this->msg( 'apiwarn-validationfailed-badpref' );
171 break;
172 }
173 if ( $validation === true ) {
174 $this->setPreference( $key, $value );
175 $changed = true;
176 } else {
177 $this->addWarning( [ 'apiwarn-validationfailed', wfEscapeWikiText( $key ), $validation ] );
178 }
179 }
180
181 if ( $changed ) {
182 $this->commitChanges();
183 }
184
185 $this->getResult()->addValue( null, $this->getModuleName(), 'success' );
186 }
187
193 protected function getUserForUpdates() {
194 if ( !$this->userForUpdates ) {
195 $this->userForUpdates = $this->getUser()->getInstanceForUpdate();
196 }
197
198 return $this->userForUpdates;
199 }
200
205 protected function getPreferences() {
206 return $this->preferencesFactory->getFormDescriptor( $this->getUserForUpdates(),
207 $this->getContext() );
208 }
209
213 protected function resetPreferences( array $kinds ) {
214 $this->userOptionsManager->resetOptions( $this->getUserForUpdates(), $this->getContext(), $kinds );
215 }
216
223 protected function setPreference( $preference, $value ) {
224 $this->userOptionsManager->setOption( $this->getUserForUpdates(), $preference, $value );
225 }
226
230 protected function commitChanges() {
231 $this->getUserForUpdates()->saveSettings();
232 }
233
234 public function mustBePosted() {
235 return true;
236 }
237
238 public function isWriteMode() {
239 return true;
240 }
241
242 public function getAllowedParams() {
243 $optionKinds = $this->userOptionsManager->listOptionKinds();
244 $optionKinds[] = 'all';
245
246 return [
247 'reset' => false,
248 'resetkinds' => [
249 ApiBase::PARAM_TYPE => $optionKinds,
250 ApiBase::PARAM_DFLT => 'all',
252 ],
253 'change' => [
255 ],
256 'optionname' => [
257 ApiBase::PARAM_TYPE => 'string',
258 ],
259 'optionvalue' => [
260 ApiBase::PARAM_TYPE => 'string',
261 ],
262 ];
263 }
264
265 public function needsToken() {
266 return 'csrf';
267 }
268
269 public function getHelpUrls() {
270 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Options';
271 }
272
273 protected function getExamplesMessages() {
274 return [
275 'action=options&reset=&token=123ABC'
276 => 'apihelp-options-example-reset',
277 'action=options&change=skin=vector|hideminor=1&token=123ABC'
278 => 'apihelp-options-example-change',
279 'action=options&reset=&change=skin=monobook&optionname=nickname&' .
280 'optionvalue=[[User:Beau|Beau]]%20([[User_talk:Beau|talk]])&token=123ABC'
281 => 'apihelp-options-example-complex',
282 ];
283 }
284}
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
getContext()
This abstract class implements many basic API functions, and is the base of all API classes.
Definition ApiBase.php:55
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
Definition ApiBase.php:1436
checkUserRightsAny( $rights, $user=null)
Helper function for permission-denied errors.
Definition ApiBase.php:1539
const PARAM_TYPE
Definition ApiBase.php:81
const PARAM_DFLT
Definition ApiBase.php:73
getResult()
Get the result object.
Definition ApiBase.php:628
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition ApiBase.php:764
addWarning( $msg, $code=null, $data=null)
Add a warning for this module.
Definition ApiBase.php:1354
getModuleName()
Get the name of the module being executed by this instance.
Definition ApiBase.php:497
getHookRunner()
Get an ApiHookRunner for running core API hooks.
Definition ApiBase.php:710
const PARAM_ISMULTI
Definition ApiBase.php:77
This is the main API class, used for both external and internal processing.
Definition ApiMain.php:49
API module that facilitates the changing of user's preferences.
resetPreferences(array $kinds)
commitChanges()
Applies changes to user preferences.
UserOptionsManager $userOptionsManager
isWriteMode()
Indicates whether this module requires write mode.
getExamplesMessages()
Returns usage examples for this module.
PreferencesFactory $preferencesFactory
setPreference( $preference, $value)
Sets one user preference to be applied by commitChanges()
needsToken()
Returns the token type this module requires in order to execute.
getHelpUrls()
Return links to more detailed help pages about the module.
User $userForUpdates
User account to modify.
execute()
Changes preferences of the current user.
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
__construct(ApiMain $main, $action, UserOptionsManager $userOptionsManager=null, PreferencesFactory $preferencesFactory=null)
getPreferences()
Returns preferences form descriptor.
mustBePosted()
Indicates whether this module must be called with a POST request.
getUserForUpdates()
Load the user from the primary to reduce CAS errors on double post (T95839)
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition HTMLForm.php:143
PSR-3 logger instance factory.
MediaWikiServices is the service locator for the application scope of MediaWiki.
A service class to control user options.
static numParam( $num)
Definition Message.php:1101
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition User.php:69
A PreferencesFactory is a MediaWiki service that provides the definitions of preferences for a given ...
return true
Definition router.php:92