jenkins-bot has submitted this change and it was merged. ( https://gerrit.wikimedia.org/r/328373 )
Change subject: Use parsed error messages straight from API ...................................................................... Use parsed error messages straight from API Since recent API error reporting refactorings, it is now possible to request better error handling from the API, in whatever format you prefer. Bug: T32095 Bug: T152607 Change-Id: I1e8d8dee5b75ac9a0b08a4190153d26e0908bd9a --- M extension.json M i18n/en.json M i18n/qqq.json M resources/handlers/mw.ApiUploadFormDataHandler.js M resources/handlers/mw.ApiUploadPostHandler.js M resources/handlers/mw.FirefoggHandler.js M resources/mw.UploadWizard.js M resources/mw.UploadWizardDetails.js M resources/mw.UploadWizardLicenseInput.js M resources/mw.UploadWizardUpload.js M resources/mw.UploadWizardUploadInterface.js M resources/transports/mw.FirefoggTransport.js M resources/transports/mw.FormDataTransport.js M resources/uw.FieldLayout.js M tests/qunit/transports/mw.FormDataTransport.test.js 15 files changed, 138 insertions(+), 249 deletions(-) Approvals: Bartosz Dziewoński: Looks good to me, approved jenkins-bot: Verified diff --git a/extension.json b/extension.json index 51f9333..74d15ea 100644 --- a/extension.json +++ b/extension.json @@ -248,7 +248,6 @@ "resources/details/uw.LocationDetailsWidget.less" ], "messages": [ - "comma-separator", "uploadwizard", "uploadwizard-desc", "mwe-upwiz-step-tutorial", @@ -256,58 +255,17 @@ "mwe-upwiz-step-deeds", "mwe-upwiz-step-details", "mwe-upwiz-step-thanks", - "api-error-autoblocked", - "api-error-blocked", - "api-error-http", - "api-error-ok-but-empty", - "api-error-unknown-code", - "api-error-uploaddisabled", - "api-error-nomodule", - "api-error-mustbeposted", - "api-error-badaccess-groups", - "api-error-ratelimited", - "api-error-stashfailed", - "api-error-missingresult", - "api-error-missingparam", - "api-error-invalid-file-key", - "api-error-copyuploaddisabled", - "api-error-mustbeloggedin", - "api-error-empty-file", - "api-error-file-too-large", - "api-error-filetype-missing", - "api-error-filetype-banned", - "api-error-filetype-banned-type", - "api-error-filename-tooshort", - "api-error-illegal-filename", - "api-error-verification-error", - "api-error-hookaborted", - "api-error-unknown-error", - "api-error-internal-error", - "api-error-overwrite", - "api-error-badtoken", - "api-error-fetchfileerror", + "api-error-aborted", "api-error-duplicate", "api-error-duplicate-archive", - "api-error-unknown-warning", - "api-error-timeout", - "api-error-noimageinfo", - "api-error-fileexists-shared-forbidden", - "api-error-unclassified", - "api-error-stasherror", - "api-error-stashedfilenotfound", - "api-error-stashpathinvalid", - "api-error-stashfilestorage", - "api-error-stashzerolength", - "api-error-stashnotloggedin", - "api-error-stashwrongowner", - "api-error-stashnosuchfilekey", - "api-error-abusefilter-warning", - "api-error-abusefilter-disallowed", - "api-error-spamblacklist", - "api-error-offline", - "api-error-parsererror", "api-error-firefogg", - "api-error-aborted", + "api-error-noimageinfo", + "api-error-offline", + "api-error-timeout", + "api-error-unknown-warning", + "unknown-error", + "apierror-unknownerror", + "apierror-stashfailed-complete", "mwe-upwiz-api-warning-was-deleted", "mwe-upwiz-api-warning-exists", "mwe-upwiz-tutorial-error-localized-file-missing", diff --git a/i18n/en.json b/i18n/en.json index 9369e94..5b58105 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -13,13 +13,14 @@ "accesskey-cancel-upload-campaign": "c", "group-upwizcampeditors.css": "/* CSS placed here will affect upload wizard campaign editors only */", "group-upwizcampeditors.js": "/* JS placed here will affect upload wizard campaign editors only */", - "api-error-abusefilter-warning": "This action has been automatically identified as harmful ([$1 more info]).\nUnconstructive edits will be quickly reverted,\nand egregious or repeated unconstructive editing will result in your account or IP address being blocked.", - "api-error-abusefilter-disallowed": "This action has been automatically identified as harmful, and therefore disallowed ([$1 more info]).", - "api-error-spamblacklist": "The text you wanted to save was blocked by the spam filter.\nThis is probably caused by a link to a blacklisted external site.", - "api-error-offline": "Could not proceed due to network connectivity issues. Make sure you have a working internet connection and try again.", - "api-error-parsererror": "The server responded with an invalid JSON document. This could be a problem with the API, or you could be using a proxy server that prevents you from uploading files.", - "api-error-firefogg": "Encoding failed.", "api-error-aborted": "Upload aborted.", + "api-error-duplicate": "There {{PLURAL:$1|is another file|are some other files}} already on the site with the same content.", + "api-error-duplicate-archive": "There {{PLURAL:$1|was another file|were some other files}} already on the site with the same content, but {{PLURAL:$1|it was|they were}} deleted.", + "api-error-firefogg": "Encoding failed.", + "api-error-noimageinfo": "The upload succeeded, but the server did not give us any information about the file.", + "api-error-offline": "Could not proceed due to network connectivity issues. Make sure you have a working internet connection and try again.", + "api-error-timeout": "The server did not respond within the expected time.", + "api-error-unknown-warning": "Unknown warning: \"$1\".", "mwe-upwiz-unavailable": "Your browser is not compatible with UploadWizard or has JavaScript turned off, so we are showing you a simple upload form. ([https://www.mediawiki.org/wiki/UploadWizard#Compatibility View compatibility requirements].)", "mwe-upwiz-extension-disabled": "This page has been disabled due to temporary technical problems. In the meantime try the standard upload form.", "mwe-upwiz-step-tutorial": "Learn", diff --git a/i18n/qqq.json b/i18n/qqq.json index 2cababe..06ba7f3 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -39,13 +39,14 @@ "accesskey-cancel-upload-campaign": "{{doc-accesskey}}", "group-upwizcampeditors.css": "{{doc-group|upwizcampeditors|css}}", "group-upwizcampeditors.js": "{{doc-group|upwizcampeditors|js}}", - "api-error-abusefilter-warning": "API error message that can be used for client side localisation of API errors. This is a shorter version of {{msg-mw|abusefilter-warning}} that is specific to file uploads. Parameters:\n* $1 - link that displays a more complete error information when clicked", - "api-error-abusefilter-disallowed": "API error message that can be used for client side localisation of API errors. This is a shorter version of {{msg-mw|abusefilter-disallowed}} that is specific to file uploads. Parameters:\n* $1 - link that displays a more complete error information when clicked", - "api-error-spamblacklist": "API error message that can be used for client side localisation of API errors. This is a shorter version of {{msg-mw|spamprotectiontext}} that is specific to file uploads.", - "api-error-offline": "Error message for when files could not be uploaded as a result of bad/lost internet connection.", - "api-error-parsererror": "Error message for when, for an unknown reason, the server sent the client an invalid response.", - "api-error-firefogg": "Error message for when encoding of ogg files fails.", "api-error-aborted": "Error message for when an upload was aborted.", + "api-error-duplicate": "API error message that can be used for client side localisation of API errors. Parameters:\n* $1 - a number of files", + "api-error-duplicate-archive": "API error message that can be used for client side localisation of API errors. Parameters:\n* $1 - a number of files", + "api-error-firefogg": "Error message for when encoding of ogg files fails.", + "api-error-noimageinfo": "API error message that can be used for client side localisation of API errors.", + "api-error-offline": "Error message for when files could not be uploaded as a result of bad/lost internet connection.", + "api-error-timeout": "API error message that can be used for client side localisation of API errors.", + "api-error-unknown-warning": "API error message that can be used for client side localisation of API errors. Parameters:\n* $1 is an unknown warning.", "mwe-upwiz-unavailable": "Shown if the user visits Special:UploadWizard using a browser that can't display the wizard due to JavaScript being disabled or lack of support for modern features.", "mwe-upwiz-extension-disabled": "Shown if the UploadWizard page has been disabled.", "mwe-upwiz-step-tutorial": "{| align=\"right\"\n| [[file:commons-uw-L524.png|Initial \"{{MediaWiki:mwe-upwiz-step-file/en}}\" page|thumb|right]]\n| [[file:commons-uw-L521.png|Beginning of \"{{MediaWiki:mwe-upwiz-step-tutorial/en}}\" page|thumb|right]]\n| [[file:commons-uw-L522.png|Center of \"{{MediaWiki:mwe-upwiz-step-tutorial/en}}\" page|thumb|right]]\n| [[file:commons-uw-L523.png|End of \"{{MediaWiki:mwe-upwiz-step-tutorial/en}}\" page|thumb|right]]\n|} This is a short greyed or bolded label, in the top bar of all pages of the [[:mw:Extension:UploadWizard|MediaWiki Upload Wizard]].", diff --git a/resources/handlers/mw.ApiUploadFormDataHandler.js b/resources/handlers/mw.ApiUploadFormDataHandler.js index fcc5174..19f9d61 100644 --- a/resources/handlers/mw.ApiUploadFormDataHandler.js +++ b/resources/handlers/mw.ApiUploadFormDataHandler.js @@ -68,14 +68,12 @@ handler.upload.setTransportProgress( fraction ); } } ).then( function ( result ) { - if ( !result || result.error || ( result.upload && result.upload.warnings ) ) { + if ( result.upload && result.upload.warnings ) { uw.eventFlowLogger.logApiError( 'file', result ); } handler.upload.setTransported( result ); }, function ( code, result ) { - if ( result.upload && result.upload.warnings ) { - uw.eventFlowLogger.logApiError( 'file', result ); - } + uw.eventFlowLogger.logApiError( 'file', result ); handler.upload.setTransportError( code, result ); } ); }, function ( code, result ) { diff --git a/resources/handlers/mw.ApiUploadPostHandler.js b/resources/handlers/mw.ApiUploadPostHandler.js index cce7082..5ef6b0a 100644 --- a/resources/handlers/mw.ApiUploadPostHandler.js +++ b/resources/handlers/mw.ApiUploadPostHandler.js @@ -25,15 +25,15 @@ url: this.upload.file.url, filename: this.beginTime.toString() + this.upload.getFilename() } ) - .fail( function ( code, result ) { - uw.eventFlowLogger.logApiError( 'file', result ); - handler.upload.setTransportError( code, result ); - } ) .done( function ( result ) { if ( result.upload && result.upload.warnings ) { uw.eventFlowLogger.logApiError( 'file', result ); } handler.upload.setTransported( result ); + } ) + .fail( function ( code, result ) { + uw.eventFlowLogger.logApiError( 'file', result ); + handler.upload.setTransportError( code, result ); } ); } }; diff --git a/resources/handlers/mw.FirefoggHandler.js b/resources/handlers/mw.FirefoggHandler.js index 0887191..5568d3a 100644 --- a/resources/handlers/mw.FirefoggHandler.js +++ b/resources/handlers/mw.FirefoggHandler.js @@ -66,7 +66,7 @@ return $.Deferred().reject( 'firefogg', { error: { code: 'firefogg', - info: 'Encoding failed: non-ASCII filename' + html: mw.message( 'api-error-firefogg' ).parse() } } ); } diff --git a/resources/mw.UploadWizard.js b/resources/mw.UploadWizard.js index 0c5e036..0378659 100644 --- a/resources/mw.UploadWizard.js +++ b/resources/mw.UploadWizard.js @@ -86,6 +86,13 @@ }, /** + * mw.Api's ajax calls are not very consistent in their error handling. + * As long as the response comes back, the response will be fine: it'll + * get rejected with the error details there. However, if no response + * comes back for whatever reason, things can get confusing. + * I'll monkeypatch around such cases so that we can always rely on the + * error response the way we want it to be. + * * @param {Object} options * @return {mw.Api} */ @@ -93,25 +100,30 @@ var api = new mw.Api( options ); api.ajax = function ( parameters, ajaxOptions ) { + $.extend( parameters, { + errorformat: 'html', + errorlang: mw.config.get( 'wgUserLanguage' ), + errorsuselocal: 1, + formatversion: 2 + } ); + return mw.Api.prototype.ajax.apply( this, [ parameters, ajaxOptions ] ).then( null, // done handler - doesn't need overriding function ( code, result ) { // fail handler - var response = { error: { + var response = { errors: [ { code: code, - info: result.textStatus || 'unknown' - } }; + html: result.textStatus || mw.message( 'apierror-unknownerror' ).parse() + } ] }; - if ( result.error && result.error.info ) { + if ( result.errors && result.errors[ 0 ] ) { // in case of success-but-has-errors, we have a valid result response = result; - } else if ( result.textStatus && result.textStatus === 'timeout' ) { - code = 'timeout'; - response.error.code = 'timeout'; - response.error.info = 'timeout'; - } else if ( code === 'http' && result.xhr && result.xhr.status === 0 ) { - code = 'offline'; - response.error.code = 'offline'; - response.error.info = 'offline'; + } else if ( result && result.textStatus === 'timeout' ) { + // in case of $.ajax.fail(), there is no response json + response.errors[ 0 ].html = mw.message( 'api-error-timeout' ).parse(); + } else if ( code === 'http' && result && result.xhr && result.xhr.status === 0 ) { + // failed to even connect to server + response.errors[ 0 ].html = mw.message( 'api-error-offline' ).parse(); } return $.Deferred().reject( code, response, response ); diff --git a/resources/mw.UploadWizardDetails.js b/resources/mw.UploadWizardDetails.js index 0f02092..1c9a940 100644 --- a/resources/mw.UploadWizardDetails.js +++ b/resources/mw.UploadWizardDetails.js @@ -772,7 +772,7 @@ return apiPromise .then( function ( result ) { - if ( !result || result.error || ( result.upload && result.upload.warnings ) ) { + if ( result.upload && result.upload.warnings ) { uw.eventFlowLogger.logApiError( 'details', result ); } return details.handleSubmitResult( result, params ); @@ -806,13 +806,13 @@ if ( ( ( new Date() ).getTime() - this.firstPoll ) > 10 * 60 * 1000 ) { return deferred.reject( 'server-error', { error: { code: 'server-error', - info: 'unknown server error' + html: 'Unknown server error' } } ); } else { if ( result.upload.stage === undefined && window.console ) { return deferred.reject( 'no-stage', { error: { code: 'no-stage', - info: 'Unable to check file\'s status' + html: 'Unable to check file\'s status' } } ); } else { // Messages that can be returned: @@ -873,16 +873,16 @@ return this.submitInternal( params ); } else if ( result && result.upload && result.upload.warnings ) { if ( warnings.thumb || warnings[ 'thumb-name' ] ) { - this.recoverFromError( 'error-title-thumbnail', mw.message( 'mwe-upwiz-error-title-thumbnail' ) ); + this.recoverFromError( 'error-title-thumbnail', mw.message( 'mwe-upwiz-error-title-thumbnail' ).parse() ); } else if ( warnings.badfilename ) { - this.recoverFromError( 'title-invalid', mw.message( 'mwe-upwiz-error-title-invalid' ) ); + this.recoverFromError( 'title-invalid', mw.message( 'mwe-upwiz-error-title-invalid' ).parse() ); } else if ( warnings[ 'bad-prefix' ] ) { - this.recoverFromError( 'title-senselessimagename', mw.message( 'mwe-upwiz-error-title-senselessimagename' ) ); + this.recoverFromError( 'title-senselessimagename', mw.message( 'mwe-upwiz-error-title-senselessimagename' ).parse() ); } else if ( existingFile ) { existingFileUrl = mw.config.get( 'wgServer' ) + mw.Title.makeTitle( NS_FILE, existingFile ).getUrl(); - this.recoverFromError( 'api-warning-exists', mw.message( 'mwe-upwiz-api-warning-exists', existingFileUrl ) ); + this.recoverFromError( 'api-warning-exists', mw.message( 'mwe-upwiz-api-warning-exists', existingFileUrl ).parse() ); } else if ( warnings.duplicate ) { - this.recoverFromError( 'upload-error-duplicate', mw.message( 'mwe-upwiz-upload-error-duplicate' ) ); + this.recoverFromError( 'upload-error-duplicate', mw.message( 'mwe-upwiz-upload-error-duplicate' ).parse() ); } else if ( warnings[ 'duplicate-archive' ] !== undefined ) { // warnings[ 'duplicate-archive' ] may be '' (empty string) for revdeleted files if ( this.upload.ignoreWarning[ 'duplicate-archive' ] ) { @@ -892,7 +892,7 @@ return this.submitInternal( params ); } else { // This should _never_ happen, but just in case.... - this.recoverFromError( 'upload-error-duplicate-archive', mw.message( 'mwe-upwiz-upload-error-duplicate-archive' ) ); + this.recoverFromError( 'upload-error-duplicate-archive', mw.message( 'mwe-upwiz-upload-error-duplicate-archive' ).parse() ); } } else { warningsKeys = []; @@ -900,7 +900,7 @@ warningsKeys.push( key ); } ); this.upload.state = 'error'; - this.recoverFromError( 'api-error-unknown-warning', mw.message( 'api-error-unknown-warning', warningsKeys.join( ', ' ) )); + this.recoverFromError( 'unknown-warning', mw.message( 'api-error-unknown-warning', warningsKeys.join( ', ' ) ).parse() ); } return $.Deferred().resolve(); @@ -913,66 +913,46 @@ * Create a recoverable error -- show the form again, and highlight the problematic field. * * @param {string} code - * @param {mw.Message} message Error message to show. + * @param {string} html Error message to show. */ - recoverFromError: function ( code, message ) { - uw.eventFlowLogger.logError( 'details', { code: code, message: message } ); + recoverFromError: function ( code, html ) { + uw.eventFlowLogger.logError( 'details', { code: code, message: html } ); this.upload.state = 'recoverable-error'; this.dataDiv.morphCrossfade( '.detailsForm' ); - this.titleDetailsField.setErrors( [ message ] ); + this.titleDetailsField.setErrors( [ { code: code, html: html } ] ); }, /** * Show error state, possibly using a recoverable error form * * @param {string} code Error code - * @param {string} statusLine Status line + * @param {string} html Error message */ - showError: function ( code, statusLine ) { - uw.eventFlowLogger.logError( 'details', { code: code, message: statusLine } ); + showError: function ( code, html ) { + uw.eventFlowLogger.logError( 'details', { code: code, message: html } ); this.showIndicator( 'error' ); - this.setStatus( statusLine ); + this.setStatus( html ); }, /** * Decide how to treat various errors * * @param {string} code Error code - * @param {Mixed} result Result from ajax call + * @param {Object} result Result from ajax call */ processError: function ( code, result ) { - var statusKey, comma, promise, - statusLine = mw.message( 'api-error-unclassified' ).text(), - titleBlacklistMessageMap = { - senselessimagename: 'senselessimagename', // TODO This is probably never hit? - 'titleblacklist-custom-filename': 'hosting', - 'titleblacklist-custom-SVG-thumbnail': 'thumbnail', - 'titleblacklist-custom-thumbnail': 'thumbnail', - 'titleblacklist-custom-double-apostrophe': 'double-apostrophe' - }, - titleErrorMap = { - 'fileexists-shared-forbidden': 'fileexists-shared-forbidden', - protectedpage: 'protected' - }; + var recoverable = [ + 'abusefilter-disallowed', + 'abusefilter-warning', + 'spamblacklist', + 'fileexists-shared-forbidden', + 'protectedpage', + 'titleblacklist-forbidden' + ]; if ( code === 'badtoken' ) { this.api.badToken( 'csrf' ); // TODO Automatically try again instead of requiring the user to bonk the button - } - - if ( code === 'abusefilter-disallowed' || code === 'abusefilter-warning' || code === 'spamblacklist' ) { - // 'amenableparser' will expand templates and parser functions server-side. - // We still do the rest of wikitext parsing here (throught jqueryMsg). - promise = this.api.loadMessagesIfMissing( [ result.error.message.key ], { amenableparser: true } ); - this.recoverFromError( code, mw.message( 'api-error-' + code, function () { - promise.done( function () { - mw.errorDialog( $( '<div>' ).msg( - result.error.message.key, - result.error.message.params - ) ); - } ); - } ) ); - return; } if ( code === 'ratelimited' ) { @@ -986,36 +966,16 @@ code = 'ratelimited'; } - if ( result && code ) { - if ( titleErrorMap[ code ] ) { - this.recoverFromError( 'title-' + titleErrorMap[ code ], mw.message( 'mwe-upwiz-error-title-' + titleErrorMap[ code ] ) ); - return; - } else if ( code === 'titleblacklist-forbidden' ) { - this.recoverFromError( 'title-' + titleBlacklistMessageMap[ result.error.message.key ], mw.message( 'mwe-upwiz-error-title-' + titleBlacklistMessageMap[ result.error.message.key ] ) ); - return; - } else { - statusKey = 'api-error-' + code; - if ( code === 'filetype-banned' && result.error.blacklisted ) { - comma = mw.message( 'comma-separator' ).text(); - code = 'filetype-banned-type'; - statusLine = mw.message( 'api-error-filetype-banned-type', - result.error.blacklisted.join( comma ), - result.error.allowed.join( comma ), - result.error.allowed.length, - result.error.blacklisted.length - ).text(); - } else if ( result.error && result.error.info ) { - statusLine = mw.message( statusKey, result.error.info ).text(); - } else { - statusLine = mw.message( statusKey, '[no error info]' ).text(); - } - } + if ( recoverable.indexOf( code ) > -1 ) { + this.recoverFromError( code, result.errors[ 0 ].html ); + return; } - this.showError( code, statusLine ); + + this.showError( code, result.errors[ 0 ].html ); }, setStatus: function ( s ) { - this.div.find( '.mwe-upwiz-file-status-line' ).text( s ).show(); + this.div.find( '.mwe-upwiz-file-status-line' ).html( s ).show(); }, showIndicator: function ( statusStr ) { diff --git a/resources/mw.UploadWizardLicenseInput.js b/resources/mw.UploadWizardLicenseInput.js index 664aa50..09768fc 100644 --- a/resources/mw.UploadWizardLicenseInput.js +++ b/resources/mw.UploadWizardLicenseInput.js @@ -631,7 +631,7 @@ } function error( code, result ) { - var message = result.error.info; + var message = result.errors[ 0 ].html; uw.eventFlowLogger.logError( 'license', { code: code, message: message } ); show( $( '<div></div>' ).append( diff --git a/resources/mw.UploadWizardUpload.js b/resources/mw.UploadWizardUpload.js index 40a7aaa..3faf57b 100644 --- a/resources/mw.UploadWizardUpload.js +++ b/resources/mw.UploadWizardUpload.js @@ -117,18 +117,18 @@ * Stop the upload -- we have failed for some reason * * @param {string} code Error code from API - * @param {string|Object} info Extra info + * @param {string} html Error message * @param {jQuery} [$additionalStatus] */ - mw.UploadWizardUpload.prototype.setError = function ( code, info, $additionalStatus ) { + mw.UploadWizardUpload.prototype.setError = function ( code, html, $additionalStatus ) { if ( this.state === 'aborted' ) { // There's no point in reporting an error anymore. return; } this.state = 'error'; this.transportProgress = 0; - this.ui.showError( code, info, $additionalStatus ); - uw.eventFlowLogger.logError( 'file', { code: code, message: info } ); + this.ui.showError( code, html, $additionalStatus ); + uw.eventFlowLogger.logError( 'file', { code: code, message: html } ); }; /** @@ -148,8 +148,7 @@ * @param {Object} result The API result in parsed JSON form */ mw.UploadWizardUpload.prototype.setTransported = function ( result ) { - // default error state - var warnCode, info; + var warnCode, param; if ( this.state === 'aborted' ) { return; @@ -179,14 +178,14 @@ } return; default: - // we have an unknown warning, so let's say what we know + param = warnCode; if ( typeof result.upload.warnings[ warnCode ] === 'string' ) { - // tack the original error code onto the warning info - info = warnCode + mw.message( 'colon-separator' ).text() + result.upload.warnings[ warnCode ]; - } else { - info = result.upload.warnings[ warnCode ]; + // tack the original error code onto the warning message + param += mw.message( 'colon-separator' ).text() + result.upload.warnings[ warnCode ]; } - this.setError( 'unknown-warning', info ); + + // we have an unknown warning, so let's say what we know + this.setError( warnCode, mw.message( 'api-error-unknown-warning', param ).parse() ); return; } } @@ -196,12 +195,12 @@ if ( result.upload.imageinfo ) { this.setSuccess( result ); } else { - this.setError( 'noimageinfo', 'unknown' ); + this.setError( 'noimageinfo', mw.message( 'api-error-noimageinfo' ).parse() ); } } else if ( result.upload && result.upload.result === 'Warning' ) { throw new Error( 'Your browser got back a Warning result from the server. Please file a bug.' ); } else { - this.setError( 'unknown', 'unknown' ); + this.setError( 'unknown', mw.message( 'unknown-error' ).parse() ); } }; @@ -212,9 +211,7 @@ * @param {Object} result The API result in parsed JSON form */ mw.UploadWizardUpload.prototype.setTransportError = function ( code, result ) { - var comma, promise, - info = result.error.info, - $extra; + var $extra; if ( this.state === 'aborted' ) { return; @@ -229,44 +226,19 @@ } } - if ( code === 'filetype-banned' && result.error.blacklisted ) { - code = 'filetype-banned-type'; - comma = mw.message( 'comma-separator' ).text(); - info = [ - result.error.blacklisted.join( comma ), - result.error.allowed.join( comma ), - result.error.allowed.length, - result.error.blacklisted.length - ]; - } else if ( code === 'abusefilter-disallowed' || code === 'abusefilter-warning' || code === 'spamblacklist' ) { - // 'amenableparser' will expand templates and parser functions server-side. - // We still do the rest of wikitext parsing here (throught jqueryMsg). - promise = this.api.loadMessagesIfMissing( [ result.error.message.key ], { amenableparser: true } ); - info = [ - function () { - promise.done( function () { - mw.errorDialog( $( '<div>' ).msg( - result.error.message.key, - result.error.message.params - ) ); - } ); - } - ]; - - if ( code === 'abusefilter-warning' ) { - $extra = new OO.ui.ButtonWidget( { - label: mw.message( 'mwe-upwiz-override' ).text(), - title: mw.message( 'mwe-upwiz-override-upload' ).text(), - flags: 'progressive', - framed: false - } ).on( 'click', function () { - // No need to ignore the error, AbuseFilter will only return it once - this.start(); - }.bind( this ) ).$element; - } + if ( code === 'abusefilter-warning' ) { + $extra = new OO.ui.ButtonWidget( { + label: mw.message( 'mwe-upwiz-override' ).text(), + title: mw.message( 'mwe-upwiz-override-upload' ).text(), + flags: 'progressive', + framed: false + } ).on( 'click', function () { + // No need to ignore the error, AbuseFilter will only return it once + this.start(); + }.bind( this ) ).$element; } - this.setError( code, info, $extra ); + this.setError( code, result.errors[ 0 ].html, $extra ); }; /** @@ -322,7 +294,8 @@ $extra = $extra.add( uploadDuplicate.$element ); } - this.setError( code, [ duplicates.length ], $extra ); + // possible messages: api-error-duplicate & api-error-duplicate-archive + this.setError( code, mw.message( 'api-error-' + code, duplicates.length ).parse(), $extra ); }; /** diff --git a/resources/mw.UploadWizardUploadInterface.js b/resources/mw.UploadWizardUploadInterface.js index 6e7973c..6176d72 100644 --- a/resources/mw.UploadWizardUploadInterface.js +++ b/resources/mw.UploadWizardUploadInterface.js @@ -115,10 +115,10 @@ /** * Set status line directly with a string * - * @param {string} s + * @param {string} html */ - mw.UploadWizardUploadInterface.prototype.setStatusString = function ( s ) { - $( this.div ).find( '.mwe-upwiz-file-status' ).text( s ).show(); + mw.UploadWizardUploadInterface.prototype.setStatusString = function ( html ) { + $( this.div ).find( '.mwe-upwiz-file-status' ).html( html ).show(); }; /** @@ -169,30 +169,12 @@ * Show that transport has failed * * @param {string} code Error code from API - * @param {string|Object} info Extra info + * @param {string} html Error message * @param {jQuery} [$additionalStatus] */ - mw.UploadWizardUploadInterface.prototype.showError = function ( code, info, $additionalStatus ) { - var msgKey, args, moreErrorCodes = [ - 'unknown-warning', - 'abusefilter-disallowed', - 'abusefilter-warning', - 'spamblacklist', - 'offline', - 'parsererror' - ]; - + mw.UploadWizardUploadInterface.prototype.showError = function ( code, html, $additionalStatus ) { this.showIndicator( 'error' ); - - // is this an error that we expect to have a message for? - if ( $.inArray( code, mw.Api.errors ) !== -1 || $.inArray( code, moreErrorCodes ) !== -1 ) { - msgKey = 'api-error-' + code; - args = $.makeArray( info ); - } else { - msgKey = 'api-error-unknown-code'; - args = [ code ].concat( $.makeArray( info ) ); - } - this.setStatus( msgKey, args ); + this.setStatusString( html ); this.setAdditionalStatus( $additionalStatus ); }; diff --git a/resources/transports/mw.FirefoggTransport.js b/resources/transports/mw.FirefoggTransport.js index 3215974..0666085 100644 --- a/resources/transports/mw.FirefoggTransport.js +++ b/resources/transports/mw.FirefoggTransport.js @@ -43,7 +43,7 @@ deferred.reject( 'firefogg', { error: { code: 'firefogg', - info: 'Encoding failed' + html: mw.message( 'api-error-firefogg' ).parse() } } ); } diff --git a/resources/transports/mw.FormDataTransport.js b/resources/transports/mw.FormDataTransport.js index ce78bb0..1ac8629 100644 --- a/resources/transports/mw.FormDataTransport.js +++ b/resources/transports/mw.FormDataTransport.js @@ -201,7 +201,7 @@ return $.Deferred().reject( 'aborted', { error: { code: 'aborted', - info: 'Aborted' + html: mw.message( 'api-error-aborted' ).parse() } } ); } @@ -251,9 +251,9 @@ } else { // Ain't this some great machine readable output eh if ( - response.error && - response.error.code === 'stashfailed' && - response.error.info === 'Chunked upload is already completed, check status for details.' + response.errors && + response.errors[ 0 ].code === 'stashfailed' && + response.errors[ 0 ].html === mw.message( 'apierror-stashfailed-complete' ).parse() ) { return transport.retryWithMethod( 'checkStatus' ); } @@ -353,7 +353,7 @@ return $.Deferred().reject( 'aborted', { error: { code: 'aborted', - info: 'Aborted' + html: mw.message( 'api-error-aborted' ).parse() } } ); } @@ -373,14 +373,14 @@ if ( ( ( new Date() ).getTime() - transport.firstPoll ) > 10 * 60 * 1000 ) { return $.Deferred().reject( 'server-error', { error: { code: 'server-error', - info: 'Unknown server error' + html: mw.message( 'apierror-unknownerror' ).parse() } } ); } else { if ( response.upload.stage === undefined && window.console ) { window.console.log( 'Unable to check file\'s status' ); return $.Deferred().reject( 'server-error', { error: { code: 'server-error', - info: 'Unknown server error' + html: mw.message( 'apierror-unknownerror' ).parse() } } ); } else { // Statuses that can be returned: diff --git a/resources/uw.FieldLayout.js b/resources/uw.FieldLayout.js index be8535f..c886a06 100644 --- a/resources/uw.FieldLayout.js +++ b/resources/uw.FieldLayout.js @@ -83,13 +83,17 @@ }; /** - * @inheritdoc + * @protected + * @param {string} kind 'error' or 'notice' + * @param {Object} error Object in { key: ..., html: ... } format + * @return {jQuery} */ - uw.FieldLayout.prototype.makeMessage = function ( kind, msg ) { + uw.FieldLayout.prototype.makeMessage = function ( kind, error ) { var - content = msg.parseDom(), - $listItem = uw.FieldLayout.parent.prototype.makeMessage.call( this, kind, content ); - $listItem.addClass( 'mwe-upwiz-fieldLayout-' + kind + '-' + msg.key ); + code = error.code, + html = error.html, + $listItem = uw.FieldLayout.parent.prototype.makeMessage.call( this, kind, html ); + $listItem.addClass( 'mwe-upwiz-fieldLayout-' + kind + '-' + code ); return $listItem; }; diff --git a/tests/qunit/transports/mw.FormDataTransport.test.js b/tests/qunit/transports/mw.FormDataTransport.test.js index d9828b5..bb2ab28 100644 --- a/tests/qunit/transports/mw.FormDataTransport.test.js +++ b/tests/qunit/transports/mw.FormDataTransport.test.js @@ -146,7 +146,7 @@ postd.resolve( { upload: { result: 'Poll' } } ); assert.ok( tstub.calledWith( 'server-error', { error: { code: 'server-error', - info: 'Unknown server error' + html: mw.message( 'apierror-unknownerror' ).parse() } } ) ); postd = $.Deferred(); -- To view, visit https://gerrit.wikimedia.org/r/328373 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I1e8d8dee5b75ac9a0b08a4190153d26e0908bd9a Gerrit-PatchSet: 4 Gerrit-Project: mediawiki/extensions/UploadWizard Gerrit-Branch: master Gerrit-Owner: Matthias Mullie <mmul...@wikimedia.org> Gerrit-Reviewer: Bartosz Dziewoński <matma....@gmail.com> Gerrit-Reviewer: Matthias Mullie <mmul...@wikimedia.org> Gerrit-Reviewer: Siebrand <siebr...@kitano.nl> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits