Bump ember-ajax dependency (#902)

no issue
- upgrade `ember-ajax` to 3.0.0
- `ember-ajax` [now passes the payload through directly](https://github.com/ember-cli/ember-ajax/releases/tag/v3.0.0) rather than trying to normalize it so all our error handling needed to be updated
This commit is contained in:
Kevin Ansfield 2017-11-03 22:59:39 +00:00 committed by GitHub
parent 98aafd15e3
commit ddc7b857b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 130 additions and 126 deletions

View File

@ -178,8 +178,8 @@ export default Component.extend({
message = 'The file type you uploaded is not supported.';
} else if (isRequestEntityTooLargeError(error)) {
message = 'The file you uploaded was larger than the maximum file size your server allows.';
} else if (error.errors && !isBlank(error.errors[0].message)) {
message = htmlSafe(error.errors[0].message);
} else if (error.payload && error.payload.errors && !isBlank(error.payload.errors[0].message)) {
message = htmlSafe(error.payload.errors[0].message);
} else {
message = 'Something went wrong :(';
}

View File

@ -162,8 +162,8 @@ export default Component.extend({
message = `The image type you uploaded is not supported. Please use ${validExtensions}`;
} else if (isRequestEntityTooLargeError(error)) {
message = 'The image you uploaded was larger than the maximum file size your server allows.';
} else if (error.errors && !isBlank(error.errors[0].message)) {
message = error.errors[0].message;
} else if (error.payload.errors && !isBlank(error.payload.errors[0].message)) {
message = error.payload.errors[0].message;
} else {
message = 'Something went wrong :(';
}

View File

@ -229,7 +229,7 @@ export default Component.extend({
} catch (error) {
// grab custom error message if present
let message = error.errors && error.errors[0].message;
let message = error.payload.errors && error.payload.errors[0].message;
// fall back to EmberData/ember-ajax default message for error type
if (!message) {
@ -238,7 +238,7 @@ export default Component.extend({
let result = {
fileName: file.name,
message: error.errors[0].message
message: error.payload.errors[0].message
};
// TODO: check for or expose known error types?

View File

@ -13,7 +13,7 @@ export default ModalComponent.extend({
// TODO: server-side validation errors should be serialized
// properly so that errors are added to model.errors automatically
if (error && isInvalidError(error)) {
let [firstError] = error.errors;
let [firstError] = error.payload.errors;
let {message} = firstError;
if (message && message.match(/email/i)) {

View File

@ -49,8 +49,8 @@ export default ModalComponent.extend(ValidationEngine, {
this.send('closeModal');
return true;
}).catch((error) => {
if (error && error.errors) {
error.errors.forEach((err) => {
if (error && error.payload && error.payload.errors) {
error.payload.errors.forEach((err) => {
if (isVersionMismatchError(err)) {
return this.get('notifications').showAPIError(error);
}
@ -59,7 +59,7 @@ export default ModalComponent.extend(ValidationEngine, {
this.get('errors').add('password', 'Incorrect password');
this.get('hasValidated').pushObject('password');
this.set('authenticationError', error.errors[0].message);
this.set('authenticationError', error.payload.errors[0].message);
}
});
}, () => {

View File

@ -65,7 +65,7 @@ export default ModalComponent.extend({
}
if (file.name.match(/^casper\.zip$/i)) {
return {errors: [{message: 'Sorry, the default Casper theme cannot be overwritten.<br>Please rename your zip file and try again.'}]};
return {payload: {errors: [{message: 'Sorry, the default Casper theme cannot be overwritten.<br>Please rename your zip file and try again.'}]}};
}
if (!this._allowOverwrite && currentThemeNames.includes(themeName)) {
@ -120,7 +120,7 @@ export default ModalComponent.extend({
uploadFailed(error) {
if (isThemeValidationError(error)) {
let errors = error.errors[0].errorDetails;
let errors = error.payload.errors[0].errorDetails;
let fatalErrors = [];
let normalErrors = [];

View File

@ -196,7 +196,7 @@ export default Controller.extend({
}
}).catch((error) => {
if (isThemeValidationError(error)) {
let errors = error.errors[0].errorDetails;
let errors = error.payload.errors[0].errorDetails;
let fatalErrors = [];
let normalErrors = [];

View File

@ -209,7 +209,7 @@ export default Controller.extend({
if (invite.success) {
successCount++;
} else if (isInvalidError(invite.error)) {
message = `${invite.email} was invalid: ${invite.error.errors[0].message}`;
message = `${invite.email} was invalid: ${invite.error.payload.errors[0].message}`;
notifications.showAlert(message, {type: 'error', delayed: true, key: `signup.send-invitations.${invite.email}`});
} else {
erroredEmails.push(invite.email);

View File

@ -44,16 +44,16 @@ export default Controller.extend(ValidationEngine, {
return authResult;
} catch (error) {
if (error && error.errors) {
if (error && error.payload && error.payload.errors) {
if (isVersionMismatchError(error)) {
return this.get('notifications').showAPIError(error);
}
error.errors.forEach((err) => {
error.payload.errors.forEach((err) => {
err.message = err.message.htmlSafe();
});
this.set('flowErrors', error.errors[0].message.string);
this.set('flowErrors', error.payload.errors[0].message.string);
} else {
// Connection errors don't return proper status message, only req.body
this.get('notifications').showAlert('There was a problem on the server.', {type: 'error', key: 'session.authenticate.failed'});
@ -142,15 +142,15 @@ export default Controller.extend(ValidationEngine, {
_handleSaveError(resp) {
if (isInvalidError(resp)) {
this.set('flowErrors', resp.errors[0].message);
this.set('flowErrors', resp.payload.errors[0].message);
} else {
this.get('notifications').showAPIError(resp, {key: 'setup.blog-details'});
}
},
_handleAuthenticationError(error) {
if (error && error.errors) {
this.set('flowErrors', error.errors[0].message);
if (error && error.payload && error.payload.errors) {
this.set('flowErrors', error.payload.errors[0].message);
} else {
// Connection errors don't return proper status message, only req.body
this.get('notifications').showAlert('There was a problem on the server.', {type: 'error', key: 'setup.authenticate.failed'});

View File

@ -40,25 +40,22 @@ export default Controller.extend(ValidationEngine, {
return authResult;
} catch (error) {
if (error && error.errors) {
// we don't get back an ember-data/ember-ajax error object
// back so we need to pass in a null status in order to
// test against the payload
if (isVersionMismatchError(error)) {
return this.get('notifications').showAPIError(error);
}
if (isVersionMismatchError(error)) {
return this.get('notifications').showAPIError(error);
}
error.errors.forEach((err) => {
if (error && error.payload && error.payload.errors) {
error.payload.errors.forEach((err) => {
err.message = err.message.htmlSafe();
});
this.set('flowErrors', error.errors[0].message.string);
this.set('flowErrors', error.payload.errors[0].message.string);
if (error.errors[0].message.string.match(/user with that email/)) {
if (error.payload.errors[0].message.string.match(/user with that email/)) {
this.get('model.errors').add('identification', '');
}
if (error.errors[0].message.string.match(/password is incorrect/)) {
if (error.payload.errors[0].message.string.match(/password is incorrect/)) {
this.get('model.errors').add('password', '');
}
} else {
@ -118,8 +115,8 @@ export default Controller.extend(ValidationEngine, {
return notifications.showAPIError(error);
}
if (error && error.errors && isEmberArray(error.errors)) {
let [{message}] = error.errors;
if (error && error.payload && error.payload.errors && isEmberArray(error.payload.errors)) {
let [{message}] = error.payload.errors;
this.set('flowErrors', message);

View File

@ -38,7 +38,7 @@ export default Controller.extend(ValidationEngine, {
return authResult;
} catch (error) {
if (error && error.errors) {
if (error && error.payload && error.payload.errors) {
// we don't get back an ember-data/ember-ajax error object
// back so we need to pass in a null status in order to
// test against the payload
@ -47,17 +47,17 @@ export default Controller.extend(ValidationEngine, {
return this.get('notifications').showAPIError(versionMismatchError);
}
error.errors.forEach((err) => {
error.payload.errors.forEach((err) => {
err.message = err.message.htmlSafe();
});
this.set('flowErrors', error.errors[0].message.string);
this.set('flowErrors', error.payload.errors[0].message.string);
if (error.errors[0].message.string.match(/user with that email/)) {
if (error.payload.errors[0].message.string.match(/user with that email/)) {
this.get('model.errors').add('identification', '');
}
if (error.errors[0].message.string.match(/password is incorrect/)) {
if (error.payload.errors[0].message.string.match(/password is incorrect/)) {
this.get('model.errors').add('password', '');
}
} else {
@ -92,11 +92,11 @@ export default Controller.extend(ValidationEngine, {
this.set('flowErrors', 'Please fill out the form to complete your sign-up');
}
if (error && error.errors && isEmberArray(error.errors)) {
if (error && error.payload && error.payload.errors && isEmberArray(error.payload.errors)) {
if (isVersionMismatchError(error)) {
notifications.showAPIError(error);
}
this.set('flowErrors', error.errors[0].message);
this.set('flowErrors', error.payload.errors[0].message);
} else {
notifications.showAPIError(error, {key: 'signup.complete'});
}

View File

@ -515,8 +515,8 @@ export default Mixin.create({
// This is here because validation errors are returned as an array
// TODO: remove this once validations are fixed
errorMessage = error[0];
} else if (error && error.errors && error.errors[0].message) {
errorMessage = error.errors[0].message;
} else if (error && error.payload && error.payload.errors && error.payload.errors[0].message) {
errorMessage = error.payload.errors[0].message;
} else {
errorMessage = 'Unknown Error';
}

View File

@ -8,8 +8,16 @@ import ctrlOrCmd from 'ghost-admin/utils/ctrl-or-cmd';
import moment from 'moment';
import windowProxy from 'ghost-admin/utils/window-proxy';
import {htmlSafe} from '@ember/string';
import {
isAjaxError,
isNotFoundError,
isUnauthorizedError
} from 'ember-ajax/errors';
import {isArray as isEmberArray} from '@ember/array';
import {isUnauthorizedError} from 'ember-ajax/errors';
import {
isMaintenanceError,
isVersionMismatchError
} from 'ghost-admin/services/ajax';
import {observer} from '@ember/object';
import {run} from '@ember/runloop';
import {inject as service} from '@ember/service';
@ -210,47 +218,46 @@ export default Route.extend(ApplicationRouteMixin, ShortcutsRoute, {
return false;
}
if (error && isEmberArray(error.errors)) {
switch (error.errors[0].errorType) {
case 'NotFoundError': {
if (transition) {
transition.abort();
}
let routeInfo = transition.handlerInfos[transition.handlerInfos.length - 1];
let router = this.get('router');
let params = [];
for (let key of Object.keys(routeInfo.params)) {
params.push(routeInfo.params[key]);
}
return this.transitionTo('error404', router.generate(routeInfo.name, ...params).replace('/ghost/', '').replace(/^\//g, ''));
if (isNotFoundError(error)) {
if (transition) {
transition.abort();
}
case 'VersionMismatchError': {
if (transition) {
transition.abort();
}
this.get('upgradeStatus').requireUpgrade();
let routeInfo = transition.handlerInfos[transition.handlerInfos.length - 1];
let router = this.get('router');
let params = [];
for (let key of Object.keys(routeInfo.params)) {
params.push(routeInfo.params[key]);
}
return this.transitionTo('error404', router.generate(routeInfo.name, ...params).replace('/ghost/', '').replace(/^\//g, ''));
}
if (isVersionMismatchError(error)) {
if (transition) {
transition.abort();
}
this.get('upgradeStatus').requireUpgrade();
return false;
}
if (isMaintenanceError(error)) {
if (transition) {
transition.abort();
}
this.get('upgradeStatus').maintenanceAlert();
return false;
}
if (isAjaxError(error) || error && error.payload && isEmberArray(error.payload.errors)) {
this.get('notifications').showAPIError(error);
// don't show the 500 page if we weren't navigating
if (!transition) {
return false;
}
case 'Maintenance': {
if (transition) {
transition.abort();
}
this.get('upgradeStatus').maintenanceAlert();
return false;
}
default: {
this.get('notifications').showAPIError(error);
// don't show the 500 page if we weren't navigating
if (!transition) {
return false;
}
}
}
}
// fallback to 500 error page

View File

@ -18,8 +18,8 @@ function isJSONContentType(header) {
/* Version mismatch error */
export function VersionMismatchError(errors) {
AjaxError.call(this, errors, 'API server is running a newer version of Ghost, please upgrade.');
export function VersionMismatchError(payload) {
AjaxError.call(this, payload, 'API server is running a newer version of Ghost, please upgrade.');
}
VersionMismatchError.prototype = Object.create(AjaxError.prototype);
@ -34,8 +34,8 @@ export function isVersionMismatchError(errorOrStatus, payload) {
/* Request entity too large error */
export function ServerUnreachableError(errors) {
AjaxError.call(this, errors, 'Server was unreachable');
export function ServerUnreachableError(payload) {
AjaxError.call(this, payload, 'Server was unreachable');
}
ServerUnreachableError.prototype = Object.create(AjaxError.prototype);
@ -48,8 +48,8 @@ export function isServerUnreachableError(error) {
}
}
export function RequestEntityTooLargeError(errors) {
AjaxError.call(this, errors, 'Request is larger than the maximum file size the server allows');
export function RequestEntityTooLargeError(payload) {
AjaxError.call(this, payload, 'Request is larger than the maximum file size the server allows');
}
RequestEntityTooLargeError.prototype = Object.create(AjaxError.prototype);
@ -64,8 +64,8 @@ export function isRequestEntityTooLargeError(errorOrStatus) {
/* Unsupported media type error */
export function UnsupportedMediaTypeError(errors) {
AjaxError.call(this, errors, 'Request contains an unknown or unsupported file type.');
export function UnsupportedMediaTypeError(payload) {
AjaxError.call(this, payload, 'Request contains an unknown or unsupported file type.');
}
UnsupportedMediaTypeError.prototype = Object.create(AjaxError.prototype);
@ -80,8 +80,8 @@ export function isUnsupportedMediaTypeError(errorOrStatus) {
/* Maintenance error */
export function MaintenanceError(errors) {
AjaxError.call(this, errors, 'Ghost is currently undergoing maintenance, please wait a moment then retry.');
export function MaintenanceError(payload) {
AjaxError.call(this, payload, 'Ghost is currently undergoing maintenance, please wait a moment then retry.');
}
MaintenanceError.prototype = Object.create(AjaxError.prototype);
@ -96,8 +96,8 @@ export function isMaintenanceError(errorOrStatus) {
/* Theme validation error */
export function ThemeValidationError(errors) {
AjaxError.call(this, errors, 'Theme is not compatible or contains errors.');
export function ThemeValidationError(payload) {
AjaxError.call(this, payload, 'Theme is not compatible or contains errors.');
}
ThemeValidationError.prototype = Object.create(AjaxError.prototype);
@ -171,17 +171,17 @@ let ajaxService = AjaxService.extend({
handleResponse(status, headers, payload) {
if (this.isVersionMismatchError(status, headers, payload)) {
return new VersionMismatchError(payload.errors);
return new VersionMismatchError(payload);
} else if (this.isServerUnreachableError(status, headers, payload)) {
return new ServerUnreachableError(payload.errors);
return new ServerUnreachableError(payload);
} else if (this.isRequestEntityTooLargeError(status, headers, payload)) {
return new RequestEntityTooLargeError(payload.errors);
return new RequestEntityTooLargeError(payload);
} else if (this.isUnsupportedMediaTypeError(status, headers, payload)) {
return new UnsupportedMediaTypeError(payload.errors);
return new UnsupportedMediaTypeError(payload);
} else if (this.isMaintenanceError(status, headers, payload)) {
return new MaintenanceError(payload.errors);
return new MaintenanceError(payload);
} else if (this.isThemeValidationError(status, headers, payload)) {
return new ThemeValidationError(payload.errors);
return new ThemeValidationError(payload);
}
// TODO: we may want to check that we are hitting our own API before

View File

@ -94,8 +94,8 @@ export default Service.extend({
}
// loop over ember-ajax errors object
if (resp && isEmberArray(resp.errors)) {
return resp.errors.forEach((error) => {
if (resp && resp.payload && isEmberArray(resp.payload.errors)) {
return resp.payload.errors.forEach((error) => {
this._showAPIError(error, options);
});
}

View File

@ -8,14 +8,14 @@ import {
} from 'ghost-admin/services/ajax';
import {computed} from '@ember/object';
import {htmlSafe} from '@ember/string';
import {inject as service} from '@ember/service';
import {invokeAction} from 'ember-invoke-action';
import {isBlank} from '@ember/utils';
import {isArray as isEmberArray} from '@ember/array';
import {run} from '@ember/runloop';
import {inject as service} from '@ember/service';
export default Component.extend({
layout,
tagName: 'section',
@ -149,8 +149,8 @@ export default Component.extend({
message = 'The image type you uploaded is not supported. Please use .PNG, .JPG, .GIF, .SVG.';
} else if (isRequestEntityTooLargeError(error)) {
message = 'The image you uploaded was larger than the maximum file size your server allows.';
} else if (error.errors && !isBlank(error.errors[0].message)) {
message = error.errors[0].message;
} else if (error.payload && error.payload.errors && !isBlank(error.payload.errors[0].message)) {
message = error.payload.errors[0].message;
} else {
message = 'Something went wrong :(';
}

View File

@ -9,12 +9,12 @@ import {
} from 'ghost-admin/services/ajax';
import {computed} from '@ember/object';
import {formatMarkdown} from '../../lib/format-markdown';
import {inject as service} from '@ember/service';
import {invokeAction} from 'ember-invoke-action';
import {isBlank} from '@ember/utils';
import {isArray as isEmberArray} from '@ember/array';
import {observer} from '@ember/object';
import {run} from '@ember/runloop';
import {inject as service} from '@ember/service';
/* legacyConverter.makeHtml(_.toString(this.get('markdown'))) */
export default Component.extend({
@ -105,8 +105,8 @@ export default Component.extend({
message = 'The image type you uploaded is not supported. Please use .PNG, .JPG, .GIF, .SVG.';
} else if (isRequestEntityTooLargeError(error)) {
message = 'The image you uploaded was larger than the maximum file size your server allows.';
} else if (error.errors && !isBlank(error.errors[0].message)) {
message = error.errors[0].message;
} else if (error.payload && error.payload.errors && !isBlank(error.payload.errors[0].message)) {
message = error.payload.errors[0].message;
} else {
message = 'Something went wrong :(';
}

View File

@ -41,7 +41,7 @@
"coveralls": "3.0.0",
"csscomb": "4.2.0",
"cssnano": "4.0.0-rc.2",
"ember-ajax": "2.5.6",
"ember-ajax": "3.0.0",
"ember-assign-helper": "0.1.2",
"ember-browserify": "1.2.0",
"ember-cli": "2.16.2",

View File

@ -136,7 +136,7 @@ describe('Acceptance: Error Handling', function() {
andThen(() => {
expect(find('.gh-alert').length).to.equal(1);
expect(find('.gh-alert').text()).to.not.match(/html>/);
expect(find('.gh-alert').text()).to.match(/There was a problem on the server/);
expect(find('.gh-alert').text()).to.match(/Request was rejected due to server error/);
});
});
@ -150,7 +150,7 @@ describe('Acceptance: Error Handling', function() {
andThen(() => {
expect(find('.gh-alert').length).to.equal(1);
expect(find('.gh-alert').text()).to.not.match(/html>/);
expect(find('.gh-alert').text()).to.match(/There was a problem on the server/);
expect(find('.gh-alert').text()).to.match(/Request was rejected due to server error/);
});
});
});

View File

@ -62,8 +62,8 @@ describe('Integration: Service: ajax', function () {
ajax.request('/test/').then(() => {
expect(false).to.be.true();
}).catch((error) => {
expect(error.errors.length).to.equal(1);
expect(error.errors[0].message).to.equal('Test Error');
expect(error.payload.errors.length).to.equal(1);
expect(error.payload.errors[0].message).to.equal('Test Error');
done();
});
});
@ -77,8 +77,8 @@ describe('Integration: Service: ajax', function () {
ajax.request('/test/').then(() => {
expect(false).to.be.true();
}).catch((error) => {
expect(error.errors.length).to.equal(1);
expect(error.errors[0].message).to.equal('Test Error');
expect(error.payload.errors.length).to.equal(1);
expect(error.payload.errors[0].message).to.equal('Test Error');
done();
});
});
@ -92,9 +92,9 @@ describe('Integration: Service: ajax', function () {
ajax.request('/test/').then(() => {
expect(false).to.be.true();
}).catch((error) => {
expect(error.errors.length).to.equal(2);
expect(error.errors[0].message).to.equal('First Error');
expect(error.errors[1].message).to.equal('Second Error');
expect(error.payload.errors.length).to.equal(2);
expect(error.payload.errors[0].message).to.equal('First Error');
expect(error.payload.errors[1].message).to.equal('Second Error');
done();
});
});

View File

@ -150,7 +150,7 @@ describe('Unit: Service: notifications', function () {
it('#showAPIError handles single json response error', function () {
let notifications = this.subject();
let error = new AjaxError([{message: 'Single error'}]);
let error = new AjaxError({errors: [{message: 'Single error'}]});
run(() => {
notifications.showAPIError(error);
@ -165,10 +165,10 @@ describe('Unit: Service: notifications', function () {
it('#showAPIError handles multiple json response errors', function () {
let notifications = this.subject();
let error = new AjaxError([
let error = new AjaxError({errors: [
{title: 'First error', message: 'First error message'},
{title: 'Second error', message: 'Second error message'}
]);
]});
run(() => {
notifications.showAPIError(error);
@ -234,7 +234,7 @@ describe('Unit: Service: notifications', function () {
expect(get(notification, 'message')).to.equal('Request was rejected because it was invalid');
expect(get(notification, 'status')).to.equal('alert');
expect(get(notification, 'type')).to.equal('error');
expect(get(notification, 'key')).to.equal('api-error.ajax-error');
expect(get(notification, 'key')).to.equal('api-error');
});
it('#showAPIError parses custom ember-ajax errors correctly', function () {
@ -249,7 +249,7 @@ describe('Unit: Service: notifications', function () {
expect(get(notification, 'message')).to.equal('Server was unreachable');
expect(get(notification, 'status')).to.equal('alert');
expect(get(notification, 'type')).to.equal('error');
expect(get(notification, 'key')).to.equal('api-error.ajax-error');
expect(get(notification, 'key')).to.equal('api-error');
});
it('#displayDelayed moves delayed notifications into content', function () {

View File

@ -2979,11 +2979,11 @@ elliptic@^6.0.0:
minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.0"
ember-ajax@2.5.6:
version "2.5.6"
resolved "https://registry.yarnpkg.com/ember-ajax/-/ember-ajax-2.5.6.tgz#a75f743ccf1b95e979a5cf96013b3dba8fa625e4"
ember-ajax@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/ember-ajax/-/ember-ajax-3.0.0.tgz#8f21e9da0c1d433cf879aa855fce464d517e9ab5"
dependencies:
ember-cli-babel "^5.1.5"
ember-cli-babel "^6.0.0"
ember-assign-helper@0.1.2:
version "0.1.2"