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

Reply via email to