MediaWiki  master
ApiOptions.php
Go to the documentation of this file.
1 <?php
27 
34 class ApiOptions extends ApiBase {
36  private $userForUpdates;
37 
40 
43 
50  public function __construct(
51  ApiMain $main,
52  $action,
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' => [
254  ApiBase::PARAM_ISMULTI => true,
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 }
ApiMain
This is the main API class, used for both external and internal processing.
Definition: ApiMain.php:49
Message\numParam
static numParam( $num)
Definition: Message.php:1127
ContextSource\getContext
getContext()
Get the base IContextSource object.
Definition: ContextSource.php:47
ApiBase\addWarning
addWarning( $msg, $code=null, $data=null)
Add a warning for this module.
Definition: ApiBase.php:1354
ApiOptions\getUserForUpdates
getUserForUpdates()
Load the user from the primary to reduce CAS errors on double post (T95839)
Definition: ApiOptions.php:193
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:200
ApiOptions\commitChanges
commitChanges()
Applies changes to user preferences.
Definition: ApiOptions.php:230
ApiBase\dieWithError
dieWithError( $msg, $code=null, $data=null, $httpCode=null)
Abort execution with an error.
Definition: ApiBase.php:1436
ApiOptions\isWriteMode
isWriteMode()
Indicates whether this module requires write mode.
Definition: ApiOptions.php:238
true
return true
Definition: router.php:90
ApiOptions\getPreferences
getPreferences()
Returns preferences form descriptor.
Definition: ApiOptions.php:205
ApiBase\PARAM_TYPE
const PARAM_TYPE
Definition: ApiBase.php:81
ApiBase\getResult
getResult()
Get the result object.
Definition: ApiBase.php:628
ApiBase\checkUserRightsAny
checkUserRightsAny( $rights, $user=null)
Helper function for permission-denied errors.
Definition: ApiBase.php:1545
ApiOptions\$preferencesFactory
PreferencesFactory $preferencesFactory
Definition: ApiOptions.php:42
ContextSource\getUser
getUser()
Definition: ContextSource.php:136
ApiBase
This abstract class implements many basic API functions, and is the base of all API classes.
Definition: ApiBase.php:55
ApiOptions\setPreference
setPreference( $preference, $value)
Sets one user preference to be applied by commitChanges()
Definition: ApiOptions.php:223
MediaWiki\Logger\LoggerFactory
PSR-3 logger instance factory.
Definition: LoggerFactory.php:45
ApiOptions\getAllowedParams
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
Definition: ApiOptions.php:242
ApiOptions\execute
execute()
Changes preferences of the current user.
Definition: ApiOptions.php:69
ApiOptions\getExamplesMessages
getExamplesMessages()
Returns usage examples for this module.
Definition: ApiOptions.php:273
ApiOptions\mustBePosted
mustBePosted()
Indicates whether this module must be called with a POST request.
Definition: ApiOptions.php:234
ApiBase\extractRequestParams
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition: ApiBase.php:764
ApiOptions\__construct
__construct(ApiMain $main, $action, UserOptionsManager $userOptionsManager=null, PreferencesFactory $preferencesFactory=null)
Definition: ApiOptions.php:50
HTMLForm\loadInputFromParameters
static loadInputFromParameters( $fieldname, $descriptor, HTMLForm $parent=null)
Initialise a new Object for the field.
Definition: HTMLForm.php:534
ApiOptions\$userOptionsManager
UserOptionsManager $userOptionsManager
Definition: ApiOptions.php:39
ContextSource\msg
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
Definition: ContextSource.php:197
ApiOptions
API module that facilitates the changing of user's preferences.
Definition: ApiOptions.php:34
ApiOptions\needsToken
needsToken()
Returns the token type this module requires in order to execute.
Definition: ApiOptions.php:265
MediaWiki\Preferences\PreferencesFactory
A PreferencesFactory is a MediaWiki service that provides the definitions of preferences for a given ...
Definition: PreferencesFactory.php:54
wfEscapeWikiText
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking,...
Definition: GlobalFunctions.php:1456
MediaWiki\User\UserOptionsManager
A service class to control user options.
Definition: UserOptionsManager.php:43
ApiBase\PARAM_DFLT
const PARAM_DFLT
Definition: ApiBase.php:73
ApiBase\getModuleName
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:497
ApiBase\PARAM_ISMULTI
const PARAM_ISMULTI
Definition: ApiBase.php:77
ApiOptions\resetPreferences
resetPreferences(array $kinds)
Definition: ApiOptions.php:213
ApiBase\getHookRunner
getHookRunner()
Get an ApiHookRunner for running core API hooks.
Definition: ApiBase.php:710
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:67
ApiOptions\getHelpUrls
getHelpUrls()
Return links to more detailed help pages about the module.
Definition: ApiOptions.php:269
ApiOptions\$userForUpdates
User $userForUpdates
User account to modify.
Definition: ApiOptions.php:36
HTMLForm
Object handling generic submission, CSRF protection, layout and other logic for UI forms in a reusabl...
Definition: HTMLForm.php:143