From e521f0680e9abc812aff5faaeda121e6249bbf5f Mon Sep 17 00:00:00 2001 From: Tyler Anthony Romeo Date: Mon, 14 Jan 2013 20:45:01 -0500 Subject: [PATCH] (bug 43959) Add ability to reset certain option kinds in API. Added the "resetkinds" option to action=options, so that when the "reset" option is set, the user can control which kinds of options are reset, rather than having to do all or none. Also added documentation to the "change" parameter, since passing it option keys without any "=value" after it will result in resetting that specific option to its default value. Change-Id: Id5bc1fffa0d487c0f152b79115205d2722f380d3 --- RELEASE-NOTES-1.21 | 2 ++ includes/User.php | 30 +++++++++++++++-- includes/api/ApiOptions.php | 17 +++++++--- tests/phpunit/includes/api/ApiOptionsTest.php | 33 +++++++++++++++---- 4 files changed, 68 insertions(+), 14 deletions(-) diff --git a/RELEASE-NOTES-1.21 b/RELEASE-NOTES-1.21 index d4ff54ca6e..1f344d4396 100644 --- a/RELEASE-NOTES-1.21 +++ b/RELEASE-NOTES-1.21 @@ -179,6 +179,8 @@ production. for all query modules. * ApiQueryBase adds 'badcontinue' error code if module has 'continue' parameter. * (bug 35885) Removed version parameter and all getVersion() methods. +* action=options now takes a "resetkinds" option, which allows only resetting + certain types of preferences when the "reset" option is set. === API internal changes in 1.21 === * For debugging only, a new global $wgDebugAPI removes many API restrictions when true. diff --git a/includes/User.php b/includes/User.php index 21f8dd09d5..ab3fd203bc 100644 --- a/includes/User.php +++ b/includes/User.php @@ -2310,10 +2310,10 @@ class User { } /** - * Return an associative array mapping preferences keys to the kind of a preference they're - * used for. Different kinds are handled differently when setting or reading preferences. + * Return a list of the types of user options currently returned by + * User::getOptionKinds(). * - * Currently, the kind is one of: + * Currently, the option kinds are: * - 'registered' - preferences which are registered in core MediaWiki or * by extensions using the UserGetDefaultOptions hook. * - 'registered-multiselect' - as above, using the 'multiselect' type. @@ -2322,6 +2322,29 @@ class User { * - 'unused' - preferences about which MediaWiki doesn't know anything. * These are usually legacy options, removed in newer versions. * + * The API (and possibly others) use this function to determine the possible + * option types for validation purposes, so make sure to update this when a + * new option kind is added. + * + * @see User::getOptionKinds + * @return array Option kinds + */ + public static function listOptionKinds() { + return array( + 'registered', + 'registered-multiselect', + 'userjs', + 'unused' + ); + } + + /** + * Return an associative array mapping preferences keys to the kind of a preference they're + * used for. Different kinds are handled differently when setting or reading preferences. + * + * See User::listOptionKinds for the list of valid option types that can be provided. + * + * @see User::listOptionKinds * @param $context IContextSource * @param $options array assoc. array with options keys to check as keys. Defaults to $this->mOptions. * @return array the key => kind mapping data @@ -2401,6 +2424,7 @@ class User { } $optionKinds = $this->getOptionKinds( $context ); + $resetKinds = array_intersect( $resetKinds, self::listOptionKinds() ); $newOptions = array(); // Use default values for the options that should be deleted, and diff --git a/includes/api/ApiOptions.php b/includes/api/ApiOptions.php index 6ed324c004..eff05debd3 100644 --- a/includes/api/ApiOptions.php +++ b/includes/api/ApiOptions.php @@ -54,7 +54,7 @@ class ApiOptions extends ApiBase { } if ( $params['reset'] ) { - $user->resetOptions( 'all' ); + $user->resetOptions( $params['resetkinds'] ); $changed = true; } @@ -86,7 +86,7 @@ class ApiOptions extends ApiBase { case 'registered-multiselect': // A key for a multiselect option. $validation = true; - $value = (bool)$value; + $value = $value !== null ? (bool) $value : null; break; case 'userjs': // Allow non-default preferences prefixed with 'userjs-', to be set by user scripts @@ -128,12 +128,20 @@ class ApiOptions extends ApiBase { } public function getAllowedParams() { + $optionKinds = User::listOptionKinds(); + $optionKinds[] = 'all'; + return array( 'token' => array( ApiBase::PARAM_TYPE => 'string', ApiBase::PARAM_REQUIRED => true ), 'reset' => false, + 'resetkinds' => array( + ApiBase::PARAM_TYPE => $optionKinds, + ApiBase::PARAM_DFLT => 'all', + ApiBase::PARAM_ISMULTI => true + ), 'change' => array( ApiBase::PARAM_ISMULTI => true, ), @@ -161,8 +169,9 @@ class ApiOptions extends ApiBase { public function getParamDescription() { return array( 'token' => 'An options token previously obtained through the action=tokens', - 'reset' => 'Resets all preferences to the site defaults', - 'change' => 'List of changes, formatted name=value (e.g. skin=vector), value cannot contain pipe characters', + 'reset' => 'Resets preferences to the site defaults', + 'resetkinds' => 'List of types of options to reset when the "reset" option is set', + 'change' => 'List of changes, formatted name=value (e.g. skin=vector), value cannot contain pipe characters. If no value is given (not even an equals sign), e.g., optionname|otheroption|..., the option will be reset to its default value', 'optionname' => 'A name of a option which should have an optionvalue set', 'optionvalue' => 'A value of the option specified by the optionname, can contain pipe characters', ); diff --git a/tests/phpunit/includes/api/ApiOptionsTest.php b/tests/phpunit/includes/api/ApiOptionsTest.php index 23314598e8..902b7b8550 100644 --- a/tests/phpunit/includes/api/ApiOptionsTest.php +++ b/tests/phpunit/includes/api/ApiOptionsTest.php @@ -198,7 +198,8 @@ class ApiOptionsTest extends MediaWikiLangTestCase { public function testReset() { $this->mUserMock->expects( $this->once() ) - ->method( 'resetOptions' ); + ->method( 'resetOptions' ) + ->with( $this->equalTo( array( 'all' ) ) ); $this->mUserMock->expects( $this->never() ) ->method( 'setOption' ); @@ -213,6 +214,24 @@ class ApiOptionsTest extends MediaWikiLangTestCase { $this->assertEquals( self::$Success, $response ); } + public function testResetKinds() { + $this->mUserMock->expects( $this->once() ) + ->method( 'resetOptions' ) + ->with( $this->equalTo( array( 'registered' ) ) ); + + $this->mUserMock->expects( $this->never() ) + ->method( 'setOption' ); + + $this->mUserMock->expects( $this->once() ) + ->method( 'saveSettings' ); + + $request = $this->getSampleRequest( array( 'reset' => '', 'resetkinds' => 'registered' ) ); + + $response = $this->executeQuery( $request ); + + $this->assertEquals( self::$Success, $response ); + } + public function testOptionWithValue() { $this->mUserMock->expects( $this->never() ) ->method( 'resetOptions' ); @@ -237,7 +256,7 @@ class ApiOptionsTest extends MediaWikiLangTestCase { $this->mUserMock->expects( $this->once() ) ->method( 'setOption' ) - ->with( $this->equalTo( 'name' ), $this->equalTo( null ) ); + ->with( $this->equalTo( 'name' ), $this->identicalTo( null ) ); $this->mUserMock->expects( $this->once() ) ->method( 'saveSettings' ); @@ -257,7 +276,7 @@ class ApiOptionsTest extends MediaWikiLangTestCase { $this->mUserMock->expects( $this->at( 3 ) ) ->method( 'setOption' ) - ->with( $this->equalTo( 'willBeNull' ), $this->equalTo( null ) ); + ->with( $this->equalTo( 'willBeNull' ), $this->identicalTo( null ) ); $this->mUserMock->expects( $this->at( 4 ) ) ->method( 'getOptions' ); @@ -322,19 +341,19 @@ class ApiOptionsTest extends MediaWikiLangTestCase { $this->mUserMock->expects( $this->at( 2 ) ) ->method( 'setOption' ) - ->with( $this->equalTo( 'testmultiselect-opt1' ), $this->equalTo( true ) ); + ->with( $this->equalTo( 'testmultiselect-opt1' ), $this->identicalTo( true ) ); $this->mUserMock->expects( $this->at( 3 ) ) ->method( 'setOption' ) - ->with( $this->equalTo( 'testmultiselect-opt2' ), $this->equalTo( false ) ); + ->with( $this->equalTo( 'testmultiselect-opt2' ), $this->identicalTo( null ) ); $this->mUserMock->expects( $this->at( 4 ) ) ->method( 'setOption' ) - ->with( $this->equalTo( 'testmultiselect-opt3' ), $this->equalTo( false ) ); + ->with( $this->equalTo( 'testmultiselect-opt3' ), $this->identicalTo( false ) ); $this->mUserMock->expects( $this->at( 5 ) ) ->method( 'setOption' ) - ->with( $this->equalTo( 'testmultiselect-opt4' ), $this->equalTo( false ) ); + ->with( $this->equalTo( 'testmultiselect-opt4' ), $this->identicalTo( false ) ); $this->mUserMock->expects( $this->once() ) ->method( 'saveSettings' ); -- 2.20.1