From b393835bda6c6359dee4dfa5004d24319af262a3 Mon Sep 17 00:00:00 2001 From: Brad Jorsch Date: Thu, 10 Oct 2013 10:54:08 -0400 Subject: [PATCH] API: Handle "special" options in action=options There are certain preferences, such as realname and emailaddress, that are handled specially in Special:Preferences and are not accessible by User::getOptions or User::setOptions. But action=options was allowing a 'dummy' version to be set in User::setOptions. Change-Id: I4c1b3d8e1eae9520228d7b6da9c41ada80f7c387 --- includes/Preferences.php | 7 ++++++ includes/User.php | 12 ++++++++++ includes/api/ApiOptions.php | 3 +++ tests/phpunit/includes/api/ApiOptionsTest.php | 24 +++++++++++++++++++ 4 files changed, 46 insertions(+) diff --git a/includes/Preferences.php b/includes/Preferences.php index c9caf4f779..87118d6243 100644 --- a/includes/Preferences.php +++ b/includes/Preferences.php @@ -62,6 +62,13 @@ class Preferences { 'emailaddress', ); + /** + * @return array + */ + static function getSaveBlacklist() { + return self::$saveBlacklist; + } + /** * @throws MWException * @param $user User diff --git a/includes/User.php b/includes/User.php index 12912e1c0a..d6e0a515b4 100644 --- a/includes/User.php +++ b/includes/User.php @@ -2443,6 +2443,8 @@ class User { * - 'registered-checkmatrix' - as above, using the 'checkmatrix' type. * - 'userjs' - preferences with names starting with 'userjs-', intended to * be used by user scripts. + * - 'special' - "preferences" that are not accessible via User::getOptions + * or User::setOptions. * - 'unused' - preferences about which MediaWiki doesn't know anything. * These are usually legacy options, removed in newer versions. * @@ -2459,6 +2461,7 @@ class User { 'registered-multiselect', 'registered-checkmatrix', 'userjs', + 'special', 'unused' ); } @@ -2483,6 +2486,13 @@ class User { $prefs = Preferences::getPreferences( $this, $context ); $mapping = array(); + // Pull out the "special" options, so they don't get converted as + // multiselect or checkmatrix. + $specialOptions = array_fill_keys( Preferences::getSaveBlacklist(), true ); + foreach ( $specialOptions as $name => $value ) { + unset( $prefs[$name] ); + } + // Multiselect and checkmatrix options are stored in the database with // one key per option, each having a boolean value. Extract those keys. $multiselectOptions = array(); @@ -2525,6 +2535,8 @@ class User { $mapping[$key] = 'registered-multiselect'; } elseif ( isset( $checkmatrixOptions[$key] ) ) { $mapping[$key] = 'registered-checkmatrix'; + } elseif ( isset( $specialOptions[$key] ) ) { + $mapping[$key] = 'special'; } elseif ( substr( $key, 0, 7 ) === 'userjs-' ) { $mapping[$key] = 'userjs'; } else { diff --git a/includes/api/ApiOptions.php b/includes/api/ApiOptions.php index b5aec7716a..c9d63784e0 100644 --- a/includes/api/ApiOptions.php +++ b/includes/api/ApiOptions.php @@ -99,6 +99,9 @@ class ApiOptions extends ApiBase { $validation = true; } break; + case 'special': + $validation = "cannot be set by this module"; + break; case 'unused': default: $validation = "not a valid preference"; diff --git a/tests/phpunit/includes/api/ApiOptionsTest.php b/tests/phpunit/includes/api/ApiOptionsTest.php index ad1e73ab4a..e718957b27 100644 --- a/tests/phpunit/includes/api/ApiOptionsTest.php +++ b/tests/phpunit/includes/api/ApiOptionsTest.php @@ -102,6 +102,7 @@ class ApiOptionsTest extends MediaWikiLangTestCase { 'testmultiselect-opt2' => 'registered-multiselect', 'testmultiselect-opt3' => 'registered-multiselect', 'testmultiselect-opt4' => 'registered-multiselect', + 'special' => 'special', ); if ( $options === null ) { @@ -375,6 +376,29 @@ class ApiOptionsTest extends MediaWikiLangTestCase { $this->assertEquals( self::$Success, $response ); } + public function testSpecialOption() { + $this->mUserMock->expects( $this->never() ) + ->method( 'resetOptions' ); + + $this->mUserMock->expects( $this->never() ) + ->method( 'saveSettings' ); + + $request = $this->getSampleRequest( array( + 'change' => 'special=1' + ) ); + + $response = $this->executeQuery( $request ); + + $this->assertEquals( array( + 'options' => 'success', + 'warnings' => array( + 'options' => array( + '*' => "Validation error for 'special': cannot be set by this module" + ) + ) + ), $response ); + } + public function testUnknownOption() { $this->mUserMock->expects( $this->never() ) ->method( 'resetOptions' ); -- 2.20.1