diff --git a/modules/ve-mw-collab/ve.ui.MWExportWikitextDialog.js b/modules/ve-mw-collab/ve.ui.MWExportWikitextDialog.js index 5f29e8151d..427be8a8b5 100644 --- a/modules/ve-mw-collab/ve.ui.MWExportWikitextDialog.js +++ b/modules/ve-mw-collab/ve.ui.MWExportWikitextDialog.js @@ -155,7 +155,7 @@ ve.ui.MWExportWikitextDialog.prototype.export = function () { format: 'text/x-wiki', model: 'wikitext', wpTextbox1: wikitext, - wpEditToken: ve.init.target.editToken, + wpEditToken: mw.user.tokens.get( 'csrfToken' ), // MediaWiki function-verification parameters, mostly relevant to the // classic editpage, but still required here: wpUnicodeCheck: 'ℳ𝒲β™₯π“Šπ“ƒπ’Ύπ’Έβ„΄π’Ήβ„―', diff --git a/modules/ve-mw/init/targets/ve.init.mw.ArticleTarget.js b/modules/ve-mw/init/targets/ve.init.mw.ArticleTarget.js index 24be8e6800..3929f88c5d 100644 --- a/modules/ve-mw/init/targets/ve.init.mw.ArticleTarget.js +++ b/modules/ve-mw/init/targets/ve.init.mw.ArticleTarget.js @@ -694,23 +694,13 @@ ve.init.mw.ArticleTarget.prototype.saveFail = function ( doc, saveData, wasRetry for ( i = 0; i < data.errors.length; i++ ) { error = data.errors[ i ]; - // Handle token errors if ( error.code === 'badtoken' ) { - if ( wasRetry ) { - this.saveErrorBadToken( null, true ); - return; - } - this.refreshEditToken().done( function ( userChanged ) { - // target.editToken has been refreshed - if ( userChanged ) { - target.saveErrorBadToken( mw.user.isAnon() ? null : mw.user.getName(), false ); - } else { - // New session is the same user still; retry - target.emit( 'saveErrorBadToken', true ); - target.save( doc, saveData, true ); - } - } ).fail( function () { - target.saveErrorBadToken( null, true ); + this.saveErrorBadTokenOrNewUser( null, true ); + } else if ( error.code === 'assertanonfailed' || error.code === 'assertuserfailed' || error.code === 'assertnameduserfailed' ) { + this.refreshUser().then( function ( username ) { + target.saveErrorBadTokenOrNewUser( username, false ); + }, function () { + target.saveErrorUnknown( data ); } ); return; } else if ( error.code === 'editconflict' ) { @@ -794,14 +784,14 @@ ve.init.mw.ArticleTarget.prototype.saveErrorHookAborted = function ( data ) { }; /** - * Handle token fetch indicating another user is logged in, and token fetch errors. + * Handle assert error indicating another user is logged in, and token fetch errors. * * @param {string|null} username Name of newly logged-in user, or null if anonymous - * @param {boolean} [error=false] Whether there was an error trying to figure out who we're logged in as + * @param {boolean} [error=false] Whether this is a token fetch error * @fires saveErrorBadToken * @fires saveErrorNewUser */ -ve.init.mw.ArticleTarget.prototype.saveErrorBadToken = function ( username, error ) { +ve.init.mw.ArticleTarget.prototype.saveErrorBadTokenOrNewUser = function ( username, error ) { var $msg = $( document.createTextNode( mw.msg( 'visualeditor-savedialog-error-badtoken' ) + ' ' ) ); if ( error ) { @@ -1480,8 +1470,8 @@ ve.init.mw.ArticleTarget.prototype.save = function ( doc, options, isRetry ) { basetimestamp: this.baseTimeStamp, starttimestamp: this.startTimeStamp, etag: this.etag, - // Pass in token to prevent automatic badtoken retries - token: this.editToken + assert: mw.user.isAnon() ? 'anon' : 'user', + assertuser: mw.user.getName() || undefined } ); if ( mw.config.get( 'wgVisualEditorConfig' ).useChangeTagging && !data.vetags ) { @@ -1588,7 +1578,7 @@ ve.init.mw.ArticleTarget.prototype.submit = function ( wikitext, fields ) { wpStarttime: this.startTimeStamp, wpEdittime: this.baseTimeStamp, wpTextbox1: wikitext, - wpEditToken: this.editToken, + wpEditToken: mw.user.tokens.get( 'csrfToken' ), // MediaWiki function-verification parameters, mostly relevant to the // classic editpage, but still required here: wpUnicodeCheck: 'ℳ𝒲β™₯π“Šπ“ƒπ’Ύπ’Έβ„΄π’Ήβ„―', diff --git a/modules/ve-mw/init/targets/ve.init.mw.Target.js b/modules/ve-mw/init/targets/ve.init.mw.Target.js index d38739a0f7..fc55c3fd38 100644 --- a/modules/ve-mw/init/targets/ve.init.mw.Target.js +++ b/modules/ve-mw/init/targets/ve.init.mw.Target.js @@ -20,7 +20,6 @@ ve.init.mw.Target = function VeInitMwTarget( config ) { this.active = false; this.pageName = mw.config.get( 'wgRelevantPageName' ); - this.editToken = mw.user.tokens.get( 'csrfToken' ); this.recovered = false; this.fromEditedState = false; this.originalHtml = null; @@ -459,26 +458,21 @@ ve.init.mw.Target.prototype.teardown = function () { * the current user. * * @param {ve.dm.Document} [doc] Document to associate with the API request - * @return {jQuery.Promise} Promise resolved with whether we switched users + * @return {jQuery.Promise} Promise resolved with new username, or null if anonymous */ -ve.init.mw.Target.prototype.refreshEditToken = function ( doc ) { +ve.init.mw.Target.prototype.refreshUser = function ( doc ) { var api = this.getContentApi( doc ), - deferred = ve.createDeferred(), - target = this; + deferred = ve.createDeferred(); api.get( { action: 'query', - meta: 'tokens|userinfo', - type: 'csrf' + meta: 'userinfo' } ) .done( function ( data ) { var userInfo = data.query && data.query.userinfo, - editToken = data.query && data.query.tokens && data.query.tokens.csrftoken, isAnon = mw.user.isAnon(); - if ( userInfo && editToken ) { - target.editToken = editToken; - + if ( userInfo ) { if ( ( isAnon && userInfo.anon !== undefined ) || // Comparing id instead of name to protect against possible @@ -486,7 +480,7 @@ ve.init.mw.Target.prototype.refreshEditToken = function ( doc ) { mw.config.get( 'wgUserId' ) === userInfo.id ) { // New session is the same user still - deferred.resolve( false ); + deferred.resolve( mw.user.getName() ); } else { // The now current session is a different user if ( userInfo.anon !== undefined ) { @@ -502,7 +496,7 @@ ve.init.mw.Target.prototype.refreshEditToken = function ( doc ) { // New session is a different user mw.config.set( { wgUserId: userInfo.id, wgUserName: userInfo.name } ); } - deferred.resolve( true ); + deferred.resolve( mw.user.getName() ); } } else { deferred.reject(); @@ -519,15 +513,12 @@ ve.init.mw.Target.prototype.refreshEditToken = function ( doc ) { * * @param {ve.dm.Document} doc Document * @param {boolean} [useRevision=true] Whether to use the revision ID + ETag - * @param {boolean} [isRetry=false] Whether this call is retrying a prior call * @return {jQuery.Promise} Abortable promise which resolves with a wikitext string */ -ve.init.mw.Target.prototype.getWikitextFragment = function ( doc, useRevision, isRetry ) { +ve.init.mw.Target.prototype.getWikitextFragment = function ( doc, useRevision ) { var promise, xhr, - target = this, params = { action: 'visualeditoredit', - token: this.editToken, paction: 'serialize', html: ve.dm.converter.getDomFromModel( doc ).body.innerHTML, page: this.getPageName() @@ -543,7 +534,7 @@ ve.init.mw.Target.prototype.getWikitextFragment = function ( doc, useRevision, i params.etag = this.etag; } - xhr = this.getContentApi( doc ).post( + xhr = this.getContentApi( doc ).postWithToken( 'csrf', params, { contentType: 'multipart/form-data' } ); @@ -553,12 +544,6 @@ ve.init.mw.Target.prototype.getWikitextFragment = function ( doc, useRevision, i return response.visualeditoredit.content; } return ve.createDeferred().reject(); - }, function ( error ) { - if ( error === 'badtoken' && !isRetry ) { - return target.refreshEditToken( doc ).then( function () { - return target.getWikitextFragment( doc, useRevision, true ); - } ); - } } ); promise.abort = function () {