diff --git a/includes/api/ApiOptions.php b/includes/api/ApiOptions.php index 265c2ccb674..01a376073f3 100644 --- a/includes/api/ApiOptions.php +++ b/includes/api/ApiOptions.php @@ -74,13 +74,36 @@ class ApiOptions extends ApiBase { } $prefs = Preferences::getPreferences( $user, $this->getContext() ); + + // Multiselect options are stored in the database with one key per + // option, each having a boolean value. Extract those keys. + $multiselectOptions = array(); + foreach ( $prefs as $name => $info ) { + if ( ( isset( $info['type'] ) && $info['type'] == 'multiselect' ) || + ( isset( $info['class'] ) && $info['class'] == 'HTMLMultiSelectField' ) ) { + $options = HTMLFormField::flattenOptions( $info['options'] ); + $prefix = isset( $info['prefix'] ) ? $info['prefix'] : $name; + + foreach ( $options as $value ) { + $multiselectOptions["$prefix$value"] = true; + } + + unset( $prefs[$name] ); + } + } + foreach ( $changes as $key => $value ) { - if ( !isset( $prefs[$key] ) ) { + if ( isset( $prefs[$key] ) ) { + $field = HTMLForm::loadInputFromParameters( $key, $prefs[$key] ); + $validation = $field->validate( $value, $user->getOptions() ); + } elseif( isset( $multiselectOptions[$key] ) ) { + // A key for a multiselect option. + $validation = true; + $value = (bool)$value; + } else { $this->setWarning( "Not a valid preference: $key" ); continue; } - $field = HTMLForm::loadInputFromParameters( $key, $prefs[$key] ); - $validation = $field->validate( $value, $user->getOptions() ); if ( $validation === true ) { $user->setOption( $key, $value ); $changed = true; diff --git a/tests/phpunit/includes/api/ApiOptionsTest.php b/tests/phpunit/includes/api/ApiOptionsTest.php index ac18afe7aa8..b30b356e46b 100644 --- a/tests/phpunit/includes/api/ApiOptionsTest.php +++ b/tests/phpunit/includes/api/ApiOptionsTest.php @@ -63,6 +63,22 @@ class ApiOptionsTest extends MediaWikiLangTestCase { ); } + $preferences['testmultiselect'] = array( + 'type' => 'multiselect', + 'options' => array( + 'Test' => array( + 'Some HTML here for option 1' => 'opt1', + 'Some HTML here for option 2' => 'opt2', + 'Some HTML here for option 3' => 'opt3', + 'Some HTML here for option 4' => 'opt4', + ), + ), + 'section' => 'test', + 'label' => ' ', + 'prefix' => 'testmultiselect-', + 'default' => array(), + ); + return true; } @@ -262,4 +278,36 @@ class ApiOptionsTest extends MediaWikiLangTestCase { $this->assertEquals( self::$Success, $response ); } + + public function testMultiSelect() { + $this->mUserMock->expects( $this->never() ) + ->method( 'resetOptions' ); + + $this->mUserMock->expects( $this->at( 1 ) ) + ->method( 'setOption' ) + ->with( $this->equalTo( 'testmultiselect-opt1' ), $this->equalTo( true ) ); + + $this->mUserMock->expects( $this->at( 2 ) ) + ->method( 'setOption' ) + ->with( $this->equalTo( 'testmultiselect-opt2' ), $this->equalTo( false ) ); + + $this->mUserMock->expects( $this->at( 3 ) ) + ->method( 'setOption' ) + ->with( $this->equalTo( 'testmultiselect-opt3' ), $this->equalTo( false ) ); + + $this->mUserMock->expects( $this->at( 4 ) ) + ->method( 'setOption' ) + ->with( $this->equalTo( 'testmultiselect-opt4' ), $this->equalTo( false ) ); + + $this->mUserMock->expects( $this->once() ) + ->method( 'saveSettings' ); + + $request = $this->getSampleRequest( array( + 'change' => 'testmultiselect-opt1=1|testmultiselect-opt2|testmultiselect-opt3=|testmultiselect-opt4=0' + ) ); + + $response = $this->executeQuery( $request ); + + $this->assertEquals( self::$Success, $response ); + } }