X-Git-Url: https://scripts.mit.edu/gitweb/autoinstallsdev/mediawiki.git/blobdiff_plain/19e297c21b10b1b8a3acad5e73fc71dcb35db44a..6932310fd58ebef145fa01eb76edf7150284d8ea:/includes/api/ApiOptions.php diff --git a/includes/api/ApiOptions.php b/includes/api/ApiOptions.php new file mode 100644 index 00000000..5b0d86a7 --- /dev/null +++ b/includes/api/ApiOptions.php @@ -0,0 +1,186 @@ +getUser()->isAnon() ) { + $this->dieWithError( + [ 'apierror-mustbeloggedin', $this->msg( 'action-editmyoptions' ) ], 'notloggedin' + ); + } + + $this->checkUserRightsAny( 'editmyoptions' ); + + $params = $this->extractRequestParams(); + $changed = false; + + if ( isset( $params['optionvalue'] ) && !isset( $params['optionname'] ) ) { + $this->dieWithError( [ 'apierror-missingparam', 'optionname' ] ); + } + + // Load the user from the master to reduce CAS errors on double post (T95839) + $user = $this->getUser()->getInstanceForUpdate(); + if ( !$user ) { + $this->dieWithError( + [ 'apierror-mustbeloggedin', $this->msg( 'action-editmyoptions' ) ], 'notloggedin' + ); + } + + if ( $params['reset'] ) { + $user->resetOptions( $params['resetkinds'], $this->getContext() ); + $changed = true; + } + + $changes = []; + if ( count( $params['change'] ) ) { + foreach ( $params['change'] as $entry ) { + $array = explode( '=', $entry, 2 ); + $changes[$array[0]] = isset( $array[1] ) ? $array[1] : null; + } + } + if ( isset( $params['optionname'] ) ) { + $newValue = isset( $params['optionvalue'] ) ? $params['optionvalue'] : null; + $changes[$params['optionname']] = $newValue; + } + if ( !$changed && !count( $changes ) ) { + $this->dieWithError( 'apierror-nochanges' ); + } + + $prefs = Preferences::getPreferences( $user, $this->getContext() ); + $prefsKinds = $user->getOptionKinds( $this->getContext(), $changes ); + + $htmlForm = null; + foreach ( $changes as $key => $value ) { + switch ( $prefsKinds[$key] ) { + case 'registered': + // Regular option. + if ( $htmlForm === null ) { + // We need a dummy HTMLForm for the validate callback... + $htmlForm = new HTMLForm( [], $this ); + } + $field = HTMLForm::loadInputFromParameters( $key, $prefs[$key], $htmlForm ); + $validation = $field->validate( $value, $user->getOptions() ); + break; + case 'registered-multiselect': + case 'registered-checkmatrix': + // A key for a multiselect or checkmatrix option. + $validation = true; + $value = $value !== null ? (bool)$value : null; + break; + case 'userjs': + // Allow non-default preferences prefixed with 'userjs-', to be set by user scripts + if ( strlen( $key ) > 255 ) { + $validation = $this->msg( 'apiwarn-validationfailed-keytoolong', Message::numParam( 255 ) ); + } elseif ( preg_match( '/[^a-zA-Z0-9_-]/', $key ) !== 0 ) { + $validation = $this->msg( 'apiwarn-validationfailed-badchars' ); + } else { + $validation = true; + } + break; + case 'special': + $validation = $this->msg( 'apiwarn-validationfailed-cannotset' ); + break; + case 'unused': + default: + $validation = $this->msg( 'apiwarn-validationfailed-badpref' ); + break; + } + if ( $validation === true ) { + $user->setOption( $key, $value ); + $changed = true; + } else { + $this->addWarning( [ 'apiwarn-validationfailed', wfEscapeWikitext( $key ), $validation ] ); + } + } + + if ( $changed ) { + // Commit changes + $user->saveSettings(); + } + + $this->getResult()->addValue( null, $this->getModuleName(), 'success' ); + } + + public function mustBePosted() { + return true; + } + + public function isWriteMode() { + return true; + } + + public function getAllowedParams() { + $optionKinds = User::listOptionKinds(); + $optionKinds[] = 'all'; + + return [ + 'reset' => false, + 'resetkinds' => [ + ApiBase::PARAM_TYPE => $optionKinds, + ApiBase::PARAM_DFLT => 'all', + ApiBase::PARAM_ISMULTI => true + ], + 'change' => [ + ApiBase::PARAM_ISMULTI => true, + ], + 'optionname' => [ + ApiBase::PARAM_TYPE => 'string', + ], + 'optionvalue' => [ + ApiBase::PARAM_TYPE => 'string', + ], + ]; + } + + public function needsToken() { + return 'csrf'; + } + + public function getHelpUrls() { + return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Options'; + } + + protected function getExamplesMessages() { + return [ + 'action=options&reset=&token=123ABC' + => 'apihelp-options-example-reset', + 'action=options&change=skin=vector|hideminor=1&token=123ABC' + => 'apihelp-options-example-change', + 'action=options&reset=&change=skin=monobook&optionname=nickname&' . + 'optionvalue=[[User:Beau|Beau]]%20([[User_talk:Beau|talk]])&token=123ABC' + => 'apihelp-options-example-complex', + ]; + } +}