mediawiki.api: Add #badToken for invalidating bad cached tokens
[lhc/web/wiklou.git] / resources / src / mediawiki.api / mediawiki.api.js
index e5c85df..c1fe187 100644 (file)
         *         console.log( data );
         *     } );
         *
+        * Multiple values for a parameter can be specified using an array (since MW 1.25):
+        *
+        *     var api = new mw.Api();
+        *     api.get( {
+        *         action: 'query',
+        *         meta: [ 'userinfo', 'siteinfo' ] // same effect as 'userinfo|siteinfo'
+        *     } ).done ( function ( data ) {
+        *         console.log( data );
+        *     } );
+        *
         * @class
         *
         * @constructor
 
        mw.Api.prototype = {
 
-               /**
-                * Normalize the ajax options for compatibility and/or convenience methods.
-                *
-                * @param {Object} [arg] An object contaning one or more of options.ajax.
-                * @return {Object} Normalized ajax options.
-                */
-               normalizeAjaxOptions: function ( arg ) {
-                       // Arg argument is usually empty
-                       // (before MW 1.20 it was used to pass ok callbacks)
-                       var opts = arg || {};
-                       // Options can also be a success callback handler
-                       if ( typeof arg === 'function' ) {
-                               opts = { ok: arg };
-                       }
-                       return opts;
-               },
-
                /**
                 * Perform API get request
                 *
                 * @param {Object} parameters
-                * @param {Object|Function} [ajaxOptions]
+                * @param {Object} [ajaxOptions]
                 * @return {jQuery.Promise}
                 */
                get: function ( parameters, ajaxOptions ) {
-                       ajaxOptions = this.normalizeAjaxOptions( ajaxOptions );
+                       ajaxOptions = ajaxOptions || {};
                        ajaxOptions.type = 'GET';
                        return this.ajax( parameters, ajaxOptions );
                },
                 * TODO: Post actions for non-local hostnames will need proxy.
                 *
                 * @param {Object} parameters
-                * @param {Object|Function} [ajaxOptions]
+                * @param {Object} [ajaxOptions]
                 * @return {jQuery.Promise}
                 */
                post: function ( parameters, ajaxOptions ) {
-                       ajaxOptions = this.normalizeAjaxOptions( ajaxOptions );
+                       ajaxOptions = ajaxOptions || {};
                        ajaxOptions.type = 'POST';
                        return this.ajax( parameters, ajaxOptions );
                },
                ajax: function ( parameters, ajaxOptions ) {
                        var token,
                                apiDeferred = $.Deferred(),
-                               msg = 'Use of mediawiki.api callback params is deprecated. Use the Promise instead.',
                                xhr, key, formData;
 
                        parameters = $.extend( {}, this.defaults.parameters, parameters );
                                delete parameters.token;
                        }
 
+                       for ( key in parameters ) {
+                               if ( $.isArray( parameters[key] ) ) {
+                                       parameters[key] = parameters[key].join( '|' );
+                               }
+                       }
+
                        // If multipart/form-data has been requested and emulation is possible, emulate it
                        if (
                                ajaxOptions.type === 'POST' &&
                                }
                        }
 
-                       // Backwards compatibility: Before MediaWiki 1.20,
-                       // callbacks were done with the 'ok' and 'err' property in ajaxOptions.
-                       if ( ajaxOptions.ok ) {
-                               mw.track( 'mw.deprecate', 'api.cbParam' );
-                               mw.log.warn( msg );
-                               apiDeferred.done( ajaxOptions.ok );
-                               delete ajaxOptions.ok;
-                       }
-                       if ( ajaxOptions.err ) {
-                               mw.track( 'mw.deprecate', 'api.cbParam' );
-                               mw.log.warn( msg );
-                               apiDeferred.fail( ajaxOptions.err );
-                               delete ajaxOptions.err;
-                       }
-
                        // Make the AJAX request
                        xhr = $.ajax( ajaxOptions )
                                // If AJAX fails, reject API call with error code 'http'
                postWithToken: function ( tokenType, params, ajaxOptions ) {
                        var api = this;
 
-                       // Do not allow deprecated ok-callback
-                       // FIXME: Remove this check when the deprecated ok-callback is removed in #post
-                       if ( $.isFunction( ajaxOptions ) ) {
-                               ajaxOptions = undefined;
-                       }
-
                        return api.getToken( tokenType, params.assert ).then( function ( token ) {
                                params.token = token;
                                return api.post( params, ajaxOptions ).then(
                                        // Error handler
                                        function ( code ) {
                                                if ( code === 'badtoken' ) {
-                                                       // Clear from cache
-                                                       promises[ api.defaults.ajax.url ][ tokenType + 'Token' ] =
-                                                               params.token = undefined;
-
+                                                       api.badToken( tokenType );
                                                        // Try again, once
+                                                       params.token = undefined;
                                                        return api.getToken( tokenType, params.assert ).then( function ( token ) {
                                                                params.token = token;
                                                                return api.post( params, ajaxOptions );
 
                                d = apiPromise
                                        .then( function ( data ) {
-                                               // 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 token type is not available for this user,
+                                               // key '...token' is either missing or set to boolean false
                                                return $.Deferred().reject( 'token-missing', data );
                                        }, function () {
                                                // Clear promise. Do not cache errors.
                                                delete promiseGroup[ type + 'Token' ];
-
                                                // Pass on to allow the caller to handle the error
                                                return this;
                                        } )
                        }
 
                        return d;
+               },
+
+               /**
+                * Indicate that the cached token for a certain action of the API is bad.
+                *
+                * Call this if you get a 'badtoken' error when using the token returned by #getToken.
+                * You may also want to use #postWithToken instead, which invalidates bad cached tokens
+                * automatically.
+                *
+                * @param {string} type Token type
+                * @since 1.26
+                */
+               badToken: function ( type ) {
+                       var promiseGroup = promises[ this.defaults.ajax.url ];
+                       if ( promiseGroup ) {
+                               delete promiseGroup[ type + 'Token' ];
+                       }
                }
        };
 
                'nomodule',
                'mustbeposted',
                'badaccess-groups',
-               'stashfailed',
                'missingresult',
                'missingparam',
                'invalid-file-key',
                'fetchfileerror',
                'fileexists-shared-forbidden',
                'invalidtitle',
-               'notloggedin'
+               'notloggedin',
+
+               // Stash-specific errors - expanded
+               'stashfailed',
+               'stasherror',
+               'stashedfilenotfound',
+               'stashpathinvalid',
+               'stashfilestorage',
+               'stashzerolength',
+               'stashnotloggedin',
+               'stashwrongowner',
+               'stashnosuchfilekey'
        ];
 
        /**