(bug 43959) Add ability to reset certain option kinds in API.
authorTyler Anthony Romeo <tylerromeo@gmail.com>
Tue, 15 Jan 2013 01:45:01 +0000 (20:45 -0500)
committerTyler Anthony Romeo <tylerromeo@gmail.com>
Fri, 18 Jan 2013 18:41:44 +0000 (13:41 -0500)
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
includes/User.php
includes/api/ApiOptions.php
tests/phpunit/includes/api/ApiOptionsTest.php

index d4ff54c..1f344d4 100644 (file)
@@ -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.
index 21f8dd0..ab3fd20 100644 (file)
@@ -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
index 6ed324c..eff05de 100644 (file)
@@ -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',
                );
index 2331459..902b7b8 100644 (file)
@@ -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' );