mediawiki.api: Use action=query&meta=tokens instead of action=tokens
authorFomafix <fomafix@googlemail.com>
Wed, 15 Oct 2014 20:48:35 +0000 (20:48 +0000)
committerOri.livneh <ori@wikimedia.org>
Fri, 21 Nov 2014 21:14:26 +0000 (21:14 +0000)
api.php?action=query&meta=tokens has different token types.
A mapping keeps the JavaScript API stable.

Bug: 72094
Change-Id: I429b609b626af35ae0abcdf6f1c13e8afb6503b9

includes/resourceloader/ResourceLoaderUserTokensModule.php
resources/src/mediawiki.api/mediawiki.api.js
tests/qunit/suites/resources/mediawiki.api/mediawiki.api.test.js

index ccd1dfd..9eb6ee9 100644 (file)
@@ -47,6 +47,7 @@ class ResourceLoaderUserTokensModule extends ResourceLoaderModule {
                        'editToken' => $user->getEditToken(),
                        'patrolToken' => $user->getEditToken( 'patrol' ),
                        'watchToken' => $user->getEditToken( 'watch' ),
+                       'csrfToken' => $user->getEditToken()
                );
        }
 
index 3a19e02..1a9c1b5 100644 (file)
@@ -1,5 +1,11 @@
 ( function ( mw, $ ) {
 
+       function getTokenType( action ) {
+               // Token types from `action=tokens` that need to be mapped to the 'csrf' token type for backward-compatibility.
+               var csrfActions = [ 'block', 'delete', 'edit', 'email', 'import', 'move', 'options', 'protect', 'unblock' ];
+               return $.inArray( action, csrfActions ) === -1 ? action : 'csrf';
+       }
+
        // We allow people to omit these default parameters from API requests
        // there is very customizable error handling here, on a per-call basis
        // wondering, would it be simpler to make it easy to clone the api object,
                 * @return {string} return.done.token Received token.
                 * @since 1.22
                 */
-               getToken: function ( type, assert ) {
+               getToken: function ( action, assert ) {
                        var apiPromise,
+                               type = getTokenType( action ),
                                promiseGroup = promises[ this.defaults.ajax.url ],
-                               d = promiseGroup && promiseGroup[ type + 'Token' ];
+                               d = promiseGroup && promiseGroup[ action + 'Token' ];
 
                        if ( !d ) {
-                               apiPromise = this.get( { action: 'tokens', type: type, assert: assert } );
+                               apiPromise = this.get( {
+                                       action: 'query',
+                                       meta: 'tokens',
+                                       type: type,
+                                       assert: assert
+                               } );
 
                                d = apiPromise
-                                       .then( function ( data ) {
+                                       .then( function ( res ) {
                                                // If token type is not available for this user,
                                                // key '...token' is either missing or set to boolean false
-                                               if ( data.tokens && data.tokens[type + 'token'] ) {
-                                                       return data.tokens[type + 'token'];
+                                               if ( res.query && res.query.tokens && res.query.tokens[type + 'token'] ) {
+                                                       return res.query.tokens[type + 'token'];
                                                }
 
-                                               return $.Deferred().reject( 'token-missing', data );
+                                               return $.Deferred().reject( 'token-missing', res );
                                        }, function () {
                                                // Clear promise. Do not cache errors.
-                                               delete promiseGroup[ type + 'Token' ];
+                                               delete promiseGroup[ action + 'Token' ];
 
                                                // Pass on to allow the caller to handle the error
                                                return this;
                                if ( !promiseGroup ) {
                                        promiseGroup = promises[ this.defaults.ajax.url ] = {};
                                }
-                               promiseGroup[ type + 'Token' ] = d;
+                               promiseGroup[ action + 'Token' ] = d;
                        }
 
                        return d;
index b89526f..61c9772 100644 (file)
                                assert.equal( test.server.requests.length, 3, 'Requests made' );
 
                                test.server.requests[2].respond( 200, { 'Content-Type': 'application/json' },
-                                       '{ "tokens": { "testaction2token": "0123abc" } }'
+                                       '{ "query": { "tokens": { "testaction2token": "0123abc" } } }'
                                );
                        } );
 
                this.server.requests[0].respond( 200, { 'Content-Type': 'application/json' },
-                       '{ "tokens": { "testactiontoken": "0123abc" } }'
+                       '{ "query": { "tokens": { "testactiontoken": "0123abc" } } }'
                );
 
                this.server.requests[1].respond( 200, { 'Content-Type': 'application/json' },
                        } );
 
                this.server.requests[0].respond( 200, { 'Content-Type': 'application/json' },
-                       '{ "tokens": { "testsimpletokentoken": "a-bad-token" } }'
+                       '{ "query": { "tokens": { "testsimpletokentoken": "a-bad-token" } } }'
                );
 
                this.server.requests[1].respond( 200, { 'Content-Type': 'application/json' },
                        } );
 
                this.server.requests[0].respond( 200, { 'Content-Type': 'application/json' },
-                       '{ "tokens": { "testbadtokentoken": "a-bad-token" } }'
+                       '{ "query": { "tokens": { "testbadtokentoken": "a-bad-token" } } }'
                );
 
                this.server.requests[1].respond( 200, { 'Content-Type': 'application/json' },
                );
 
                this.server.requests[2].respond( 200, { 'Content-Type': 'application/json' },
-                       '{ "tokens": { "testbadtokentoken": "a-good-token" } }'
+                       '{ "query": { "tokens": { "testbadtokentoken": "a-good-token" } } }'
                );
 
                this.server.requests[3].respond( 200, { 'Content-Type': 'application/json' },
                        } );
 
                this.server.requests[0].respond( 200, { 'Content-Type': 'application/json' },
-                       '{ "tokens": { "testbadtokencachetoken": "a-good-token-once" } }'
+                       '{ "query": { "tokens": { "testbadtokencachetoken": "a-good-token-once" } } }'
                );
 
                this.server.requests[1].respond( 200, { 'Content-Type': 'application/json' },
                );
 
                this.server.requests[3].respond( 200, { 'Content-Type': 'application/json' },
-                       '{ "tokens": { "testbadtokencachetoken": "a-good-new-token" } }'
+                       '{ "query": { "tokens": { "testbadtokencachetoken": "a-good-new-token" } } }'
                );
 
                this.server.requests[4].respond( 200, { 'Content-Type': 'application/json' },