MediaWiki  master
ApiOptions.php
Go to the documentation of this file.
1 <?php
24 
31 class ApiOptions extends ApiBase {
33  private $userForUpdates;
34 
38  public function execute() {
39  $user = $this->getUserForUpdates();
40  if ( !$user || $user->isAnon() ) {
41  $this->dieWithError(
42  [ 'apierror-mustbeloggedin', $this->msg( 'action-editmyoptions' ) ], 'notloggedin'
43  );
44  }
45 
46  $this->checkUserRightsAny( 'editmyoptions' );
47 
48  $params = $this->extractRequestParams();
49  $changed = false;
50 
51  if ( isset( $params['optionvalue'] ) && !isset( $params['optionname'] ) ) {
52  $this->dieWithError( [ 'apierror-missingparam', 'optionname' ] );
53  }
54 
55  $resetKinds = $params['resetkinds'];
56  if ( !$params['reset'] ) {
57  $resetKinds = [];
58  }
59 
60  $changes = [];
61  if ( $params['change'] ) {
62  foreach ( $params['change'] as $entry ) {
63  $array = explode( '=', $entry, 2 );
64  $changes[$array[0]] = $array[1] ?? null;
65  }
66  }
67  if ( isset( $params['optionname'] ) ) {
68  $newValue = $params['optionvalue'] ?? null;
69  $changes[$params['optionname']] = $newValue;
70  }
71 
72  Hooks::run( 'ApiOptions', [ $this, $user, $changes, $resetKinds ] );
73 
74  if ( $resetKinds ) {
75  $this->resetPreferences( $resetKinds );
76  $changed = true;
77  }
78 
79  if ( !$changed && !count( $changes ) ) {
80  $this->dieWithError( 'apierror-nochanges' );
81  }
82 
83  $prefs = $this->getPreferences();
84  $prefsKinds = $user->getOptionKinds( $this->getContext(), $changes );
85 
86  $htmlForm = null;
87  foreach ( $changes as $key => $value ) {
88  switch ( $prefsKinds[$key] ) {
89  case 'registered':
90  // Regular option.
91  if ( $value === null ) {
92  // Reset it
93  $validation = true;
94  } else {
95  // Validate
96  if ( $htmlForm === null ) {
97  // We need a dummy HTMLForm for the validate callback...
98  $htmlForm = new HTMLForm( [], $this );
99  }
100  $field = HTMLForm::loadInputFromParameters( $key, $prefs[$key], $htmlForm );
101  $validation = $field->validate( $value, $user->getOptions() );
102  }
103  break;
104  case 'registered-multiselect':
105  case 'registered-checkmatrix':
106  // A key for a multiselect or checkmatrix option.
107  $validation = true;
108  $value = $value !== null ? (bool)$value : null;
109  break;
110  case 'userjs':
111  // Allow non-default preferences prefixed with 'userjs-', to be set by user scripts
112  if ( strlen( $key ) > 255 ) {
113  $validation = $this->msg( 'apiwarn-validationfailed-keytoolong', Message::numParam( 255 ) );
114  } elseif ( preg_match( '/[^a-zA-Z0-9_-]/', $key ) !== 0 ) {
115  $validation = $this->msg( 'apiwarn-validationfailed-badchars' );
116  } else {
117  $validation = true;
118  }
119  break;
120  case 'special':
121  $validation = $this->msg( 'apiwarn-validationfailed-cannotset' );
122  break;
123  case 'unused':
124  default:
125  $validation = $this->msg( 'apiwarn-validationfailed-badpref' );
126  break;
127  }
128  if ( $validation === true ) {
129  $this->setPreference( $key, $value );
130  $changed = true;
131  } else {
132  $this->addWarning( [ 'apiwarn-validationfailed', wfEscapeWikiText( $key ), $validation ] );
133  }
134  }
135 
136  if ( $changed ) {
137  $this->commitChanges();
138  }
139 
140  $this->getResult()->addValue( null, $this->getModuleName(), 'success' );
141  }
142 
148  protected function getUserForUpdates() {
149  if ( !$this->userForUpdates ) {
150  $this->userForUpdates = $this->getUser()->getInstanceForUpdate();
151  }
152 
153  return $this->userForUpdates;
154  }
155 
160  protected function getPreferences() {
161  $preferencesFactory = MediaWikiServices::getInstance()->getPreferencesFactory();
162  return $preferencesFactory->getFormDescriptor( $this->getUserForUpdates(),
163  $this->getContext() );
164  }
165 
169  protected function resetPreferences( array $kinds ) {
170  $this->getUserForUpdates()->resetOptions( $kinds, $this->getContext() );
171  }
172 
179  protected function setPreference( $preference, $value ) {
180  $this->getUserForUpdates()->setOption( $preference, $value );
181  }
182 
186  protected function commitChanges() {
187  $this->getUserForUpdates()->saveSettings();
188  }
189 
190  public function mustBePosted() {
191  return true;
192  }
193 
194  public function isWriteMode() {
195  return true;
196  }
197 
198  public function getAllowedParams() {
199  $optionKinds = User::listOptionKinds();
200  $optionKinds[] = 'all';
201 
202  return [
203  'reset' => false,
204  'resetkinds' => [
205  ApiBase::PARAM_TYPE => $optionKinds,
206  ApiBase::PARAM_DFLT => 'all',
208  ],
209  'change' => [
210  ApiBase::PARAM_ISMULTI => true,
211  ],
212  'optionname' => [
213  ApiBase::PARAM_TYPE => 'string',
214  ],
215  'optionvalue' => [
216  ApiBase::PARAM_TYPE => 'string',
217  ],
218  ];
219  }
220 
221  public function needsToken() {
222  return 'csrf';
223  }
224 
225  public function getHelpUrls() {
226  return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Options';
227  }
228 
229  protected function getExamplesMessages() {
230  return [
231  'action=options&reset=&token=123ABC'
232  => 'apihelp-options-example-reset',
233  'action=options&change=skin=vector|hideminor=1&token=123ABC'
234  => 'apihelp-options-example-change',
235  'action=options&reset=&change=skin=monobook&optionname=nickname&' .
236  'optionvalue=[[User:Beau|Beau]]%20([[User_talk:Beau|talk]])&token=123ABC'
237  => 'apihelp-options-example-complex',
238  ];
239  }
240 }
const PARAM_TYPE
(string|string[]) Either an array of allowed value strings, or a string type as described below...
Definition: ApiBase.php:94
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking, formatting, etc.
execute()
Changes preferences of the current user.
Definition: ApiOptions.php:38
getResult()
Get the result object.
Definition: ApiBase.php:640
setPreference( $preference, $value)
Sets one user preference to be applied by commitChanges()
Definition: ApiOptions.php:179
const PARAM_DFLT
(null|boolean|integer|string) Default value of the parameter.
Definition: ApiBase.php:55
getAllowedParams()
Definition: ApiOptions.php:198
dieWithError( $msg, $code=null, $data=null, $httpCode=null)
Abort execution with an error.
Definition: ApiBase.php:2005
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user...
Definition: ApiBase.php:761
static numParam( $num)
Definition: Message.php:1038
static listOptionKinds()
Return a list of the types of user options currently returned by User::getOptionKinds().
Definition: User.php:3085
User $userForUpdates
User account to modify.
Definition: ApiOptions.php:33
static loadInputFromParameters( $fieldname, $descriptor, HTMLForm $parent=null)
Initialise a new Object for the field.
Definition: HTMLForm.php:512
commitChanges()
Applies changes to user preferences.
Definition: ApiOptions.php:186
getUserForUpdates()
Load the user from the master to reduce CAS errors on double post (T95839)
Definition: ApiOptions.php:148
getContext()
Get the base IContextSource object.
getModuleName()
Get the name of the module being executed by this instance.
Definition: ApiBase.php:520
resetPreferences(array $kinds)
Definition: ApiOptions.php:169
API module that facilitates the changing of user&#39;s preferences.
Definition: ApiOptions.php:31
msg( $key,... $params)
Get a Message object with context set Parameters are the same as wfMessage()
addWarning( $msg, $code=null, $data=null)
Add a warning for this module.
Definition: ApiBase.php:1924
const PARAM_ISMULTI
(boolean) Accept multiple pipe-separated values for this parameter (e.g.
Definition: ApiBase.php:58
getExamplesMessages()
Definition: ApiOptions.php:229
getPreferences()
Returns preferences form descriptor.
Definition: ApiOptions.php:160
This abstract class implements many basic API functions, and is the base of all API classes...
Definition: ApiBase.php:42
checkUserRightsAny( $rights, $user=null)
Helper function for permission-denied errors.
Definition: ApiBase.php:2121
return true
Definition: router.php:92
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:200