From: Niklas Laxström Date: Mon, 20 May 2013 15:36:48 +0000 (+0000) Subject: mediawiki.api: add postWithToken and getToken X-Git-Tag: 1.31.0-rc.0~18484^2 X-Git-Url: http://git.cyclocoop.org/?a=commitdiff_plain;h=f851c58e747fdbde392bced145d7ddb2208766db;p=lhc%2Fweb%2Fwiklou.git mediawiki.api: add postWithToken and getToken Similar to postWithEditToken in mw.api.edit, but more generic. Change-Id: Ic2af66b91a996bc9b46dc3e999b4099541573b08 --- diff --git a/resources/mediawiki.api/mediawiki.api.edit.js b/resources/mediawiki.api/mediawiki.api.edit.js index 381e172c33..cc83a4b819 100644 --- a/resources/mediawiki.api/mediawiki.api.edit.js +++ b/resources/mediawiki.api/mediawiki.api.edit.js @@ -3,9 +3,6 @@ */ ( function ( mw, $ ) { - // Cache token so we don't have to keep fetching new ones for every single request. - var cachedToken = null; - $.extend( mw.Api.prototype, { /** @@ -19,32 +16,7 @@ * @return {jQuery.Promise} See #post */ postWithEditToken: function ( params, ok, err ) { - var useTokenToPost, getTokenIfBad, - api = this; - if ( cachedToken === null ) { - // We don't have a valid cached token, so get a fresh one and try posting. - // We do not trap any 'badtoken' or 'notoken' errors, because we don't want - // an infinite loop. If this fresh token is bad, something else is very wrong. - useTokenToPost = function ( token ) { - params.token = token; - api.post( params, { ok: ok, err: err } ); - }; - return api.getEditToken( useTokenToPost, err ); - } else { - // We do have a token, but it might be expired. So if it is 'bad' then - // start over with a new token. - params.token = cachedToken; - getTokenIfBad = function ( code, result ) { - if ( code === 'badtoken' ) { - // force a new token, clear any old one - cachedToken = null; - api.postWithEditToken( params, ok, err ); - } else { - err( code, result ); - } - }; - return api.post( params, { ok: ok, err: getTokenIfBad } ); - } + return this.postWithToken( 'edit', params ).done( ok ).fail( err ); }, /** @@ -57,38 +29,7 @@ * @return {string} return.done.token Received token. */ getEditToken: function ( ok, err ) { - var d = $.Deferred(), - apiPromise; - - // Backwards compatibility (< MW 1.20) - d.done( ok ).fail( err ); - - apiPromise = this.get( { - action: 'tokens', - type: 'edit' - }, { - // Due to the API assuming we're logged out if we pass the callback-parameter, - // we have to disable jQuery's callback system, and instead parse JSON string, - // by setting 'jsonp' to false. - // TODO: This concern seems genuine but no other module has it. Is it still - // needed and/or should we pass this by default? - jsonp: false - } ) - .done( function ( data ) { - var token; - // If token type is not available for this user, - // key 'edittoken' is missing or can contain Boolean false - if ( data.tokens && data.tokens.edittoken ) { - token = data.tokens.edittoken; - cachedToken = token; - d.resolve( token ); - } else { - d.reject( 'token-missing', data ); - } - } ) - .fail( d.reject ); - - return d.promise( { abort: apiPromise.abort } ); + return this.getToken( 'edit' ).done( ok ).fail( err ); }, /** @@ -111,8 +52,7 @@ text: message }, ok, err ); } - - } ); + } ); /** * @class mw.Api diff --git a/resources/mediawiki.api/mediawiki.api.js b/resources/mediawiki.api/mediawiki.api.js index 142c454183..f9a14b075d 100644 --- a/resources/mediawiki.api/mediawiki.api.js +++ b/resources/mediawiki.api/mediawiki.api.js @@ -20,7 +20,8 @@ dataType: 'json' } - }; + }, + tokenCache = {}; /** * Constructor to create an object to interact with the API of a particular MediaWiki server. @@ -176,8 +177,80 @@ return apiDeferred.promise( { abort: xhr.abort } ).fail( function ( code, details ) { mw.log( 'mw.Api error: ', code, details ); } ); - } + }, + + /** + * Post to API with specified type of token. If we have no token, get one and try to post. + * If we have a cached token try using that, and if it fails, blank out the + * cached token and start over. For example to change an user option you could do: + * + * new mw.Api().postWithToken( 'options', { + * action: 'options', + * optionname: 'gender', + * optionvalue: 'female' + * } ); + * + * @param {string} tokenType The name of the token, like options or edit. + * @param {Object} params API parameters + * @return {jQuery.Promise} See #post + */ + postWithToken: function ( tokenType, params ) { + var api = this, hasOwn = tokenCache.hasOwnProperty; + if ( hasOwn.call( tokenCache, tokenType ) && tokenCache[tokenType] !== undefined ) { + params.token = tokenCache[tokenType]; + return api.post( params ).then( + null, + function ( code ) { + if ( code === 'badtoken' ) { + // force a new token, clear any old one + tokenCache[tokenType] = params.token = undefined; + return api.post( params ); + } + } + ); + } else { + return api.getToken( tokenType ).then( function ( token ) { + tokenCache[tokenType] = params.token = token; + return api.post( params ); + } ); + } + }, + /** + * Api helper to grab any token. + * + * @param {string} type Token type. + * @return {jQuery.Promise} + * @return {Function} return.done + * @return {string} return.done.token Received token. + */ + getToken: function ( type ) { + var apiPromise, + d = $.Deferred(); + + apiPromise = this.get( { + action: 'tokens', + type: type + }, { + // Due to the API assuming we're logged out if we pass the callback-parameter, + // we have to disable jQuery's callback system, and instead parse JSON string, + // by setting 'jsonp' to false. + // TODO: This concern seems genuine but no other module has it. Is it still + // needed and/or should we pass this by default? + } ) + .done( function ( data ) { + // If token type is not available for this user, + // key '...token' is missing or can contain Boolean false + if ( data.tokens && data.tokens[type + 'token'] ) { + d.resolve( data.tokens[type + 'token'] ); + } else { + d.reject( 'token-missing', data ); + } + } ) + .fail( d.reject ); + + return d.promise( { abort: apiPromise.abort } ); + } }; /**