Merge pull request #5928 from kevinansfield/notification-keys

Prevent duplicate alerts and clear on login
This commit is contained in:
Hannah Wolfe 2015-10-14 17:24:17 +01:00
commit b21b36a598
68 changed files with 688 additions and 500 deletions

View File

@ -66,7 +66,7 @@
"safeContextKeyword": ["self"],
"requireDotNotation": true,
"disallowYodaConditions": true,
"validateJSDoc": {
"jsDoc": {
"checkParamNames": true,
"checkRedundantParams": true,
"requireParamTypes": true

View File

@ -7,10 +7,9 @@ export default Ember.Component.extend({
notifications: Ember.inject.service(),
typeClass: Ember.computed(function () {
typeClass: Ember.computed('message.type', function () {
var classes = '',
message = this.get('message'),
type = Ember.get(message, 'type'),
type = this.get('message.type'),
typeMapping;
typeMapping = {

View File

@ -9,10 +9,9 @@ export default Ember.Component.extend({
notifications: Ember.inject.service(),
typeClass: Ember.computed(function () {
typeClass: Ember.computed('message.type', function () {
var classes = '',
message = this.get('message'),
type = Ember.get(message, 'type'),
type = this.get('message.type'),
typeMapping;
typeMapping = {

View File

@ -27,7 +27,7 @@ export default EmberSelectizeComponent.extend({
* Event callback that is triggered when user creates a tag
* - modified to pass the caret position to the action
*/
_create(input, callback) {
_create: function (input, callback) {
var caret = this._selectize.caretPos;
// Delete user entered text
@ -43,7 +43,7 @@ export default EmberSelectizeComponent.extend({
callback(null);
},
_addSelection(obj) {
_addSelection: function (obj) {
var _valuePath = this.get('_valuePath'),
val = Ember.get(obj, _valuePath),
caret = this._selectize.caretPos;

View File

@ -27,13 +27,14 @@ export default Ember.Component.extend({
// If sending the invitation email fails, the API will still return a status of 201
// but the user's status in the response object will be 'invited-pending'.
if (result.users[0].status === 'invited-pending') {
notifications.showAlert('Invitation email was not sent. Please try resending.', {type: 'error'});
notifications.showAlert('Invitation email was not sent. Please try resending.', {type: 'error', key: 'invite.resend.not-sent'});
} else {
user.set('status', result.users[0].status);
notifications.showNotification(notificationText);
notifications.closeAlerts('invite.resend');
}
}).catch(function (error) {
notifications.showAPIError(error);
notifications.showAPIError(error, {key: 'invite.resend'});
}).finally(function () {
self.set('isSending', false);
});
@ -50,15 +51,15 @@ export default Ember.Component.extend({
if (user.get('invited')) {
user.destroyRecord().then(function () {
var notificationText = 'Invitation revoked. (' + email + ')';
notifications.showNotification(notificationText);
notifications.closeAlerts('invite.revoke');
}).catch(function (error) {
notifications.showAPIError(error);
notifications.showAPIError(error, {key: 'invite.revoke'});
});
} else {
// if the user is no longer marked as "invited", then show a warning and reload the route
self.sendAction('reload');
notifications.showAlert('This user has already accepted the invitation.', {type: 'error', delayed: true});
notifications.showAlert('This user has already accepted the invitation.', {type: 'error', delayed: true, key: 'invite.revoke.already-accepted'});
}
});
}

View File

@ -12,11 +12,11 @@ export default Ember.Controller.extend({
ajax(this.get('ghostPaths.url').api('db'), {
type: 'DELETE'
}).then(function () {
self.get('notifications').showAlert('All content deleted from database.', {type: 'success'});
self.get('notifications').showAlert('All content deleted from database.', {type: 'success', key: 'all-content.delete.success'});
self.store.unloadAll('post');
self.store.unloadAll('tag');
}).catch(function (response) {
self.get('notifications').showAPIError(response);
self.get('notifications').showAPIError(response, {key: 'all-content.delete'});
});
},

View File

@ -14,9 +14,10 @@ export default Ember.Controller.extend({
model.destroyRecord().then(function () {
self.get('dropdown').closeDropdowns();
self.get('notifications').closeAlerts('post.delete');
self.transitionToRoute('posts.index');
}, function () {
self.get('notifications').showAlert('Your post could not be deleted. Please try again.', {type: 'error'});
self.get('notifications').showAlert('Your post could not be deleted. Please try again.', {type: 'error', key: 'post.delete.failed'});
});
},

View File

@ -15,7 +15,7 @@ export default Ember.Controller.extend({
this.send('closeMenus');
tag.destroyRecord().catch(function (error) {
self.get('notifications').showAPIError(error);
self.get('notifications').showAPIError(error, {key: 'tag.delete'});
});
},

View File

@ -29,10 +29,11 @@ export default Ember.Controller.extend({
user = this.get('model');
user.destroyRecord().then(function () {
self.get('notifications').closeAlerts('user.delete');
self.store.unloadAll('post');
self.transitionToRoute('team');
}, function () {
self.get('notifications').showAlert('The user could not be deleted. Please try again.', {type: 'error'});
self.get('notifications').showAlert('The user could not be deleted. Please try again.', {type: 'error', key: 'user.delete.failed'});
});
},

View File

@ -58,9 +58,9 @@ export default Ember.Controller.extend(ValidationEngine, {
if (invitedUser) {
if (invitedUser.get('status') === 'invited' || invitedUser.get('status') === 'invited-pending') {
self.get('notifications').showAlert('A user with that email address was already invited.', {type: 'warn'});
self.get('notifications').showAlert('A user with that email address was already invited.', {type: 'warn', key: 'invite.send.already-invited'});
} else {
self.get('notifications').showAlert('A user with that email address already exists.', {type: 'warn'});
self.get('notifications').showAlert('A user with that email address already exists.', {type: 'warn', key: 'invite.send.user-exists'});
}
} else {
newUser = self.store.createRecord('user', {
@ -75,8 +75,9 @@ export default Ember.Controller.extend(ValidationEngine, {
// If sending the invitation email fails, the API will still return a status of 201
// but the user's status in the response object will be 'invited-pending'.
if (newUser.get('status') === 'invited-pending') {
self.get('notifications').showAlert('Invitation email was not sent. Please try resending.', {type: 'error'});
self.get('notifications').showAlert('Invitation email was not sent. Please try resending.', {type: 'error', key: 'invite.send.failed'});
} else {
self.get('notifications').closeAlerts('invite.send');
self.get('notifications').showNotification(notificationText);
}
}).catch(function (errors) {
@ -86,9 +87,9 @@ export default Ember.Controller.extend(ValidationEngine, {
// want to use inline-validations here and only show an
// alert if we have an actual error
if (errors) {
self.get('notifications').showErrors(errors);
self.get('notifications').showErrors(errors, {key: 'invite.send'});
} else if (validationErrors) {
self.get('notifications').showAlert(validationErrors.toString(), {type: 'error'});
self.get('notifications').showAlert(validationErrors.toString(), {type: 'error', key: 'invite.send.validation-error'});
}
}).finally(function () {
self.get('errors').clear();

View File

@ -33,9 +33,9 @@ export default Ember.Controller.extend({
});
}
self.get('notifications').showAlert('Ownership successfully transferred to ' + user.get('name'), {type: 'success'});
self.get('notifications').showAlert('Ownership successfully transferred to ' + user.get('name'), {type: 'success', key: 'owner.transfer.success'});
}).catch(function (error) {
self.get('notifications').showAPIError(error);
self.get('notifications').showAPIError(error, {key: 'owner.transfer'});
});
},

View File

@ -12,7 +12,7 @@ export default Ember.Controller.extend({
this.get('model').save().then(function (model) {
return model;
}).catch(function (err) {
notifications.showAPIError(err);
notifications.showAPIError(err, {key: 'image.upload'});
});
},

View File

@ -45,13 +45,13 @@ export default Ember.Controller.extend(ValidationEngine, {
}
}).then(function (resp) {
self.toggleProperty('submitting');
self.get('notifications').showAlert(resp.passwordreset[0].message, {type: 'warn', delayed: true});
self.get('notifications').showAlert(resp.passwordreset[0].message, {type: 'warn', delayed: true, key: 'password.reset'});
self.get('session').authenticate('ghost-authenticator:oauth2-password-grant', {
identification: self.get('email'),
password: credentials.newPassword
});
}).catch(function (response) {
self.get('notifications').showAPIError(response);
self.get('notifications').showAPIError(response, {key: 'password.reset'});
self.toggleProperty('submitting');
});
}).catch(function () {

View File

@ -8,7 +8,7 @@ export default Ember.Controller.extend(SettingsSaveMixin, {
var notifications = this.get('notifications');
return this.get('model').save().catch(function (error) {
notifications.showAPIError(error);
notifications.showAPIError(error, {key: 'code-injection.save'});
});
}
});

View File

@ -74,7 +74,7 @@ export default Ember.Controller.extend(SettingsSaveMixin, {
return model;
}).catch(function (error) {
if (error) {
notifications.showAPIError(error);
notifications.showAPIError(error, {key: 'settings.save'});
}
});
},

View File

@ -54,12 +54,13 @@ export default Ember.Controller.extend({
self.set('session.user', self.store.findRecord('user', currentUserId));
// TODO: keep as notification, add link to view content
notifications.showNotification('Import successful.');
notifications.closeAlerts('import.upload');
}).catch(function (response) {
if (response && response.jqXHR && response.jqXHR.responseJSON && response.jqXHR.responseJSON.errors) {
self.set('importErrors', response.jqXHR.responseJSON.errors);
}
notifications.showAlert('Import Failed', {type: 'error'});
notifications.showAlert('Import Failed', {type: 'error', key: 'import.upload.failed'});
}).finally(function () {
self.set('uploadButtonText', 'Import');
});
@ -86,13 +87,13 @@ export default Ember.Controller.extend({
ajax(this.get('ghostPaths.url').api('mail', 'test'), {
type: 'POST'
}).then(function () {
notifications.showAlert('Check your email for the test message.', {type: 'info'});
notifications.showAlert('Check your email for the test message.', {type: 'info', key: 'test-email.send.success'});
self.toggleProperty('submitting');
}).catch(function (error) {
if (typeof error.jqXHR !== 'undefined') {
notifications.showAPIError(error);
notifications.showAPIError(error, {key: 'test-email.send'});
} else {
notifications.showErrors(error);
notifications.showErrors(error, {key: 'test-email.send'});
}
self.toggleProperty('submitting');
});

View File

@ -50,7 +50,7 @@ export default Ember.Controller.extend(SettingsMenuMixin, {
activeTag.save().catch(function (error) {
if (error) {
self.notifications.showAPIError(error);
self.notifications.showAPIError(error, {key: 'tag.save'});
}
});
},

View File

@ -175,13 +175,13 @@ export default Ember.Controller.extend({
invitationsString = erroredEmails.length > 1 ? ' invitations: ' : ' invitation: ';
message = 'Failed to send ' + erroredEmails.length + invitationsString;
message += erroredEmails.join(', ');
notifications.showAlert(message, {type: 'error', delayed: successCount > 0});
notifications.showAlert(message, {type: 'error', delayed: successCount > 0, key: 'signup.send-invitations.failed'});
}
if (successCount > 0) {
// pluralize
invitationsString = successCount > 1 ? 'invitations' : 'invitation';
notifications.showAlert(successCount + ' ' + invitationsString + ' sent!', {type: 'success', delayed: true});
notifications.showAlert(successCount + ' ' + invitationsString + ' sent!', {type: 'success', delayed: true, key: 'signup.send-invitations.success'});
}
self.send('loadServerNotifications');
self.toggleProperty('submitting');

View File

@ -99,7 +99,7 @@ export default Ember.Controller.extend(ValidationEngine, {
self.transitionToRoute('setup.three');
}).catch(function (resp) {
self.toggleProperty('submitting');
notifications.showAPIError(resp);
notifications.showAPIError(resp, {key: 'setup.blog-details'});
});
} else {
self.toggleProperty('submitting');
@ -111,7 +111,7 @@ export default Ember.Controller.extend(ValidationEngine, {
if (resp && resp.jqXHR && resp.jqXHR.responseJSON && resp.jqXHR.responseJSON.errors) {
self.set('flowErrors', resp.jqXHR.responseJSON.errors[0].message);
} else {
notifications.showAPIError(resp);
notifications.showAPIError(resp, {key: 'setup.blog-details'});
}
});
}).catch(function () {

View File

@ -58,7 +58,7 @@ export default Ember.Controller.extend(ValidationEngine, {
self.send('authenticate');
}).catch(function (error) {
if (error) {
self.get('notifications').showAPIError(error);
self.get('notifications').showAPIError(error, {key: 'signin.authenticate'});
} else {
self.set('flowErrors', 'Please fill out the form to sign in.');
}
@ -86,7 +86,7 @@ export default Ember.Controller.extend(ValidationEngine, {
}
}).then(function () {
self.toggleProperty('submitting');
notifications.showAlert('Please check your email for instructions.', {type: 'info'});
notifications.showAlert('Please check your email for instructions.', {type: 'info', key: 'forgot-password.send.success'});
}).catch(function (resp) {
self.toggleProperty('submitting');
if (resp && resp.jqXHR && resp.jqXHR.responseJSON && resp.jqXHR.responseJSON.errors) {
@ -98,7 +98,7 @@ export default Ember.Controller.extend(ValidationEngine, {
self.get('model.errors').add('identification', '');
}
} else {
notifications.showAPIError(resp, {defaultErrorText: 'There was a problem with the reset, please try again.'});
notifications.showAPIError(resp, {defaultErrorText: 'There was a problem with the reset, please try again.', key: 'forgot-password.send'});
}
});
}).catch(function () {

View File

@ -74,14 +74,14 @@ export default Ember.Controller.extend(ValidationEngine, {
self.sendImage();
}
}).catch(function (resp) {
notifications.showAPIError(resp);
notifications.showAPIError(resp, {key: 'signup.complete'});
});
}).catch(function (resp) {
self.toggleProperty('submitting');
if (resp && resp.jqXHR && resp.jqXHR.responseJSON && resp.jqXHR.responseJSON.errors) {
self.set('flowErrors', resp.jqXHR.responseJSON.errors[0].message);
} else {
notifications.showAPIError(resp);
notifications.showAPIError(resp, {key: 'signup.complete'});
}
});
}).catch(function () {

View File

@ -125,11 +125,12 @@ export default Ember.Controller.extend(ValidationEngine, {
}
self.toggleProperty('submitting');
self.get('notifications').closeAlerts('user.update');
return model;
}).catch(function (errors) {
if (errors) {
self.get('notifications').showErrors(errors);
self.get('notifications').showErrors(errors, {key: 'user.update'});
}
self.toggleProperty('submitting');
@ -151,15 +152,15 @@ export default Ember.Controller.extend(ValidationEngine, {
ne2Password: ''
});
self.get('notifications').showAlert('Password updated.', {type: 'success'});
self.get('notifications').showAlert('Password updated.', {type: 'success', key: 'user.change-password.success'});
return model;
}).catch(function (errors) {
self.get('notifications').showAPIError(errors);
self.get('notifications').showAPIError(errors, {key: 'user.change-password'});
});
} else {
// TODO: switch to in-line validation
self.get('notifications').showErrors(user.get('passwordValidationErrors'));
self.get('notifications').showErrors(user.get('passwordValidationErrors'), {key: 'user.change-password'});
}
},

View File

@ -246,7 +246,7 @@ export default Ember.Mixin.create({
message += '<br />' + error;
notifications.showAlert(message.htmlSafe(), {type: 'error', delayed: delay});
notifications.showAlert(message.htmlSafe(), {type: 'error', delayed: delay, key: 'post.save'});
},
actions: {

View File

@ -37,7 +37,7 @@ export default Ember.Mixin.create({
message += '.';
}
this.get('notifications').showAlert(message, {type: 'error'});
this.get('notifications').showAlert(message, {type: 'error', key: 'pagination.load.failed'});
},
loadFirstPage: function () {

View File

@ -52,6 +52,7 @@ export default Ember.Route.extend(ApplicationRouteMixin, ShortcutsRoute, {
},
signedIn: function () {
this.get('notifications').clearAll();
this.send('loadServerNotifications', true);
},
@ -67,7 +68,7 @@ export default Ember.Route.extend(ApplicationRouteMixin, ShortcutsRoute, {
});
} 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'});
this.get('notifications').showAlert('There was a problem on the server.', {type: 'error', key: 'session.authenticate.failed'});
}
},
@ -92,7 +93,7 @@ export default Ember.Route.extend(ApplicationRouteMixin, ShortcutsRoute, {
},
sessionInvalidationFailed: function (error) {
this.get('notifications').showAlert(error.message, {type: 'error'});
this.get('notifications').showAlert(error.message, {type: 'error', key: 'session.invalidate.failed'});
},
openModal: function (modalName, model, type) {

View File

@ -9,7 +9,7 @@ export default Ember.Route.extend(styleBody, {
beforeModel: function () {
if (this.get('session').isAuthenticated) {
this.get('notifications').showAlert('You can\'t reset your password while you\'re signed in.', {type: 'warn', delayed: true});
this.get('notifications').showAlert('You can\'t reset your password while you\'re signed in.', {type: 'warn', delayed: true, key: 'password.reset.signed-in'});
this.transitionTo(Configuration.routeAfterAuthentication);
}
},

View File

@ -10,7 +10,7 @@ export default AuthenticatedRoute.extend(styleBody, {
notifications: Ember.inject.service(),
afterModel: function (model, transition) {
this.get('notifications').closeAll();
this.get('notifications').clearAll();
if (Ember.canInvoke(transition, 'send')) {
transition.send('invalidateSession');
transition.abort();

View File

@ -12,7 +12,7 @@ export default Ember.Route.extend(styleBody, {
beforeModel: function () {
if (this.get('session').isAuthenticated) {
this.get('notifications').showAlert('You need to sign out to register as a new user.', {type: 'warn', delayed: true});
this.get('notifications').showAlert('You need to sign out to register as a new user.', {type: 'warn', delayed: true, key: 'signup.create.already-authenticated'});
this.transitionTo(Configuration.routeAfterAuthentication);
}
},
@ -26,7 +26,7 @@ export default Ember.Route.extend(styleBody, {
return new Ember.RSVP.Promise(function (resolve) {
if (!re.test(params.token)) {
self.get('notifications').showAlert('Invalid token.', {type: 'error', delayed: true});
self.get('notifications').showAlert('Invalid token.', {type: 'error', delayed: true, key: 'signup.create.invalid-token'});
return resolve(self.transitionTo('signin'));
}
@ -47,7 +47,7 @@ export default Ember.Route.extend(styleBody, {
}
}).then(function (response) {
if (response && response.invitation && response.invitation[0].valid === false) {
self.get('notifications').showAlert('The invitation does not exist or is no longer valid.', {type: 'warn', delayed: true});
self.get('notifications').showAlert('The invitation does not exist or is no longer valid.', {type: 'warn', delayed: true, key: 'signup.create.invalid-invitation'});
return resolve(self.transitionTo('signin'));
}

View File

@ -1,5 +1,14 @@
import Ember from 'ember';
// Notification keys take the form of "noun.verb.message", eg:
//
// "invite.resend.api-error"
// "user.invite.already-invited"
//
// The "noun.verb" part will be used as the "key base" in duplicate checks
// to avoid stacking of multiple error messages whilst leaving enough
// specificity to re-use keys for i18n lookups
export default Ember.Service.extend({
delayedNotifications: Ember.A(),
content: Ember.A(),
@ -24,6 +33,11 @@ export default Ember.Service.extend({
Ember.set(message, 'status', 'notification');
}
// close existing duplicate alerts/notifications to avoid stacking
if (Ember.get(message, 'key')) {
this._removeItems(Ember.get(message, 'status'), Ember.get(message, 'key'));
}
if (!delayed) {
this.get('content').pushObject(message);
} else {
@ -37,7 +51,8 @@ export default Ember.Service.extend({
this.handleNotification({
message: message,
status: 'alert',
type: options.type
type: options.type,
key: options.key
}, options.delayed);
},
@ -46,31 +61,43 @@ export default Ember.Service.extend({
if (!options.doNotCloseNotifications) {
this.closeNotifications();
} else {
// TODO: this should be removed along with showErrors
options.key = undefined;
}
this.handleNotification({
message: message,
status: 'notification',
type: options.type
type: options.type,
key: options.key
}, options.delayed);
},
// TODO: review whether this can be removed once no longer used by validations
showErrors: function (errors, options) {
options = options || {};
options.type = options.type || 'error';
// TODO: getting keys from the server would be useful here (necessary for i18n)
options.key = (options.key && `${options.key}.api-error`) || 'api-error';
if (!options.doNotCloseNotifications) {
this.closeNotifications();
}
// ensure all errors that are passed in get shown
options.doNotCloseNotifications = true;
for (var i = 0; i < errors.length; i += 1) {
this.showNotification(errors[i].message || errors[i], {type: 'error', doNotCloseNotifications: true});
this.showNotification(errors[i].message || errors[i], options);
}
},
showAPIError: function (resp, options) {
options = options || {};
options.type = options.type || 'error';
// TODO: getting keys from the server would be useful here (necessary for i18n)
options.key = (options.key && `${options.key}.api-error`) || 'api-error';
if (!options.doNotCloseNotifications) {
this.closeNotifications();
@ -85,7 +112,7 @@ export default Ember.Service.extend({
} else if (resp && resp.jqXHR && resp.jqXHR.responseJSON && resp.jqXHR.responseJSON.message) {
this.showAlert(resp.jqXHR.responseJSON.message, options);
} else {
this.showAlert(options.defaultErrorText, {type: options.type, doNotCloseNotifications: true});
this.showAlert(options.defaultErrorText, options);
}
},
@ -111,11 +138,40 @@ export default Ember.Service.extend({
}
},
closeNotifications: function () {
this.set('content', this.get('content').rejectBy('status', 'notification'));
closeNotifications: function (key) {
this._removeItems('notification', key);
},
closeAll: function () {
closeAlerts: function (key) {
this._removeItems('alert', key);
},
clearAll: function () {
this.get('content').clear();
},
_removeItems: function (status, key) {
if (key) {
let keyBase = this._getKeyBase(key),
// TODO: keys should only have . special char but we should
// probably use a better regexp escaping function/polyfill
escapedKeyBase = keyBase.replace('.', '\\.'),
keyRegex = new RegExp(`^${escapedKeyBase}`);
this.set('content', this.get('content').reject(function (item) {
let itemKey = Ember.get(item, 'key'),
itemStatus = Ember.get(item, 'status');
return itemStatus === status && (itemKey && itemKey.match(keyRegex));
}));
} else {
this.set('content', this.get('content').rejectBy('status', status));
}
},
// take a key and return the first two elements, eg:
// "invite.revoke.failed" => "invite.revoke"
_getKeyBase: function (key) {
return key.split('.').slice(0, 2).join('.');
}
});

View File

@ -8,7 +8,7 @@
"ember-cli-shims": "ember-cli/ember-cli-shims#0.0.3",
"ember-cli-test-loader": "0.1.3",
"ember-data": "1.13.13",
"ember-mocha": "0.8.2",
"ember-mocha": "0.8.4",
"ember-load-initializers": "ember-cli/ember-load-initializers#0.1.5",
"ember-resolver": "0.1.18",
"ember-simple-auth": "0.8.0",

View File

@ -13,7 +13,7 @@ import initializeTestHelpers from 'simple-auth-testing/test-helpers';
initializeTestHelpers();
const { run } = Ember,
const {run} = Ember,
// TODO: Pull this into a fixture or similar when required elsewhere
requiredSettings = [{
created_at: '2015-09-11T09:44:30.805Z',

View File

@ -0,0 +1,46 @@
/* jshint expr:true */
import { expect } from 'chai';
import {
describeComponent,
it
} from 'ember-mocha';
import hbs from 'htmlbars-inline-precompile';
describeComponent(
'gh-alert',
'Integration: Component: gh-alert',
{
integration: true
},
function () {
it('renders', function () {
this.set('message', {message: 'Test message', type: 'success'});
this.render(hbs`{{gh-alert message=message}}`);
expect(this.$('article.gh-alert')).to.have.length(1);
let $alert = this.$('.gh-alert');
expect($alert.text()).to.match(/Test message/);
});
it('maps message types to CSS classes', function () {
this.set('message', {message: 'Test message', type: 'success'});
this.render(hbs`{{gh-alert message=message}}`);
let $alert = this.$('.gh-alert');
this.set('message.type', 'success');
expect($alert.hasClass('gh-alert-green'), 'success class isn\'t green').to.be.true;
this.set('message.type', 'error');
expect($alert.hasClass('gh-alert-red'), 'success class isn\'t red').to.be.true;
this.set('message.type', 'warn');
expect($alert.hasClass('gh-alert-yellow'), 'success class isn\'t yellow').to.be.true;
this.set('message.type', 'info');
expect($alert.hasClass('gh-alert-blue'), 'success class isn\'t blue').to.be.true;
});
}
);

View File

@ -0,0 +1,56 @@
/* jshint expr:true */
import { expect } from 'chai';
import {
describeComponent,
it
} from 'ember-mocha';
import hbs from 'htmlbars-inline-precompile';
import Ember from 'ember';
const {run} = Ember,
notificationsStub = Ember.Service.extend({
alerts: Ember.A()
});
describeComponent(
'gh-alerts',
'Integration: Component: gh-alerts',
{
integration: true
},
function () {
beforeEach(function () {
this.register('service:notifications', notificationsStub);
this.inject.service('notifications', {as: 'notifications'});
this.set('notifications.alerts', [
{message: 'First', type: 'error'},
{message: 'Second', type: 'warn'}
]);
});
it('renders', function () {
this.render(hbs`{{gh-alerts}}`);
expect(this.$('.gh-alerts').length).to.equal(1);
expect(this.$('.gh-alerts').children().length).to.equal(2);
this.set('notifications.alerts', Ember.A());
expect(this.$('.gh-alerts').children().length).to.equal(0);
});
it('triggers "notify" action when message count changes', function () {
let expectedCount = 0;
// test double for notify action
this.set('notify', (count) => expect(count).to.equal(expectedCount));
this.render(hbs`{{gh-alerts notify=(action notify)}}`);
expectedCount = 3;
this.get('notifications.alerts').pushObject({message: 'Third', type: 'success'});
expectedCount = 0;
this.set('notifications.alerts', Ember.A());
});
}
);

View File

@ -5,7 +5,7 @@ import hbs from 'htmlbars-inline-precompile';
import Ember from 'ember';
import { NavItem } from 'ghost/controllers/settings/navigation';
const { run } = Ember;
const {run} = Ember;
describeComponent(
'gh-navigation',

View File

@ -5,7 +5,7 @@ import hbs from 'htmlbars-inline-precompile';
import Ember from 'ember';
import { NavItem } from 'ghost/controllers/settings/navigation';
const { run } = Ember;
const {run} = Ember;
describeComponent(
'gh-navitem',

View File

@ -7,7 +7,7 @@ import {
import hbs from 'htmlbars-inline-precompile';
import Ember from 'ember';
const { run } = Ember,
const {run} = Ember,
// we want baseUrl to match the running domain so relative URLs are
// handled as expected (browser auto-sets the domain when using a.href)
currentUrl = `${window.location.protocol}//${window.location.host}/`;

View File

@ -0,0 +1,44 @@
/* jshint expr:true */
import { expect } from 'chai';
import {
describeComponent,
it
} from 'ember-mocha';
import hbs from 'htmlbars-inline-precompile';
describeComponent(
'gh-notification',
'Integration: Component: gh-notification',
{
integration: true
},
function () {
it('renders', function () {
this.set('message', {message: 'Test message', type: 'success'});
this.render(hbs`{{gh-notification message=message}}`);
expect(this.$('article.gh-notification')).to.have.length(1);
let $notification = this.$('.gh-notification');
expect($notification.hasClass('gh-notification-passive')).to.be.true;
expect($notification.text()).to.match(/Test message/);
});
it('maps message types to CSS classes', function () {
this.set('message', {message: 'Test message', type: 'success'});
this.render(hbs`{{gh-notification message=message}}`);
let $notification = this.$('.gh-notification');
this.set('message.type', 'success');
expect($notification.hasClass('gh-notification-green'), 'success class isn\'t green').to.be.true;
this.set('message.type', 'error');
expect($notification.hasClass('gh-notification-red'), 'success class isn\'t red').to.be.true;
this.set('message.type', 'warn');
expect($notification.hasClass('gh-notification-yellow'), 'success class isn\'t yellow').to.be.true;
});
}
);

View File

@ -0,0 +1,42 @@
/* jshint expr:true */
import { expect } from 'chai';
import {
describeComponent,
it
} from 'ember-mocha';
import hbs from 'htmlbars-inline-precompile';
import Ember from 'ember';
const {run} = Ember,
notificationsStub = Ember.Service.extend({
notifications: Ember.A()
});
describeComponent(
'gh-notifications',
'Integration: Component: gh-notifications',
{
integration: true
},
function () {
beforeEach(function () {
this.register('service:notifications', notificationsStub);
this.inject.service('notifications', {as: 'notifications'});
this.set('notifications.notifications', [
{message: 'First', type: 'error'},
{message: 'Second', type: 'warn'}
]);
});
it('renders', function () {
this.render(hbs`{{gh-notifications}}`);
expect(this.$('.gh-notifications').length).to.equal(1);
expect(this.$('.gh-notifications').children().length).to.equal(2);
this.set('notifications.notifications', Ember.A());
expect(this.$('.gh-notifications').children().length).to.equal(0);
});
}
);

View File

@ -16,46 +16,6 @@ describeComponent(
// needs: ['component:foo', 'helper:bar']
},
function () {
it('renders', function () {
// creates the component instance
var component = this.subject();
expect(component._state).to.equal('preRender');
component.set('message', {message: 'Test message', type: 'success'});
// renders the component on the page
this.render();
expect(component._state).to.equal('inDOM');
expect(this.$().prop('tagName')).to.equal('ARTICLE');
expect(this.$().hasClass('gh-alert')).to.be.true;
expect(this.$().text()).to.match(/Test message/);
});
it('maps success alert type to correct class', function () {
var component = this.subject();
component.set('message', {message: 'Test message', type: 'success'});
expect(this.$().hasClass('gh-alert-green')).to.be.true;
});
it('maps error alert type to correct class', function () {
var component = this.subject();
component.set('message', {message: 'Test message', type: 'error'});
expect(this.$().hasClass('gh-alert-red')).to.be.true;
});
it('maps warn alert type to correct class', function () {
var component = this.subject();
component.set('message', {message: 'Test message', type: 'warn'});
expect(this.$().hasClass('gh-alert-yellow')).to.be.true;
});
it('maps info alert type to correct class', function () {
var component = this.subject();
component.set('message', {message: 'Test message', type: 'info'});
expect(this.$().hasClass('gh-alert-blue')).to.be.true;
});
it('closes notification through notifications service', function () {
var component = this.subject(),
notifications = {},

View File

@ -1,65 +0,0 @@
/* jshint expr:true */
import Ember from 'ember';
import { expect } from 'chai';
import {
describeComponent,
it
}
from 'ember-mocha';
import sinon from 'sinon';
describeComponent(
'gh-alerts',
'Unit: Component: gh-alerts',
{
unit: true,
// specify the other units that are required for this test
needs: ['component:gh-alert']
},
function () {
beforeEach(function () {
// Stub the notifications service
var notifications = Ember.Object.create();
notifications.alerts = Ember.A();
notifications.alerts.pushObject({message: 'First', type: 'error'});
notifications.alerts.pushObject({message: 'Second', type: 'warn'});
this.subject().set('notifications', notifications);
});
it('renders', function () {
// creates the component instance
var component = this.subject();
expect(component._state).to.equal('preRender');
// renders the component on the page
this.render();
expect(component._state).to.equal('inDOM');
expect(this.$().prop('tagName')).to.equal('ASIDE');
expect(this.$().hasClass('gh-alerts')).to.be.true;
expect(this.$().children().length).to.equal(2);
Ember.run(function () {
component.set('notifications.alerts', Ember.A());
});
expect(this.$().children().length).to.equal(0);
});
it('triggers "notify" action when message count changes', function () {
var component = this.subject();
component.sendAction = sinon.spy();
component.get('notifications.alerts')
.pushObject({message: 'New alert', type: 'info'});
expect(component.sendAction.calledWith('notify', 3)).to.be.true;
component.set('notifications.alerts', Ember.A());
expect(component.sendAction.calledWith('notify', 0)).to.be.true;
});
}
);

View File

@ -16,40 +16,6 @@ describeComponent(
// needs: ['component:foo', 'helper:bar']
},
function () {
it('renders', function () {
// creates the component instance
var component = this.subject();
expect(component._state).to.equal('preRender');
component.set('message', {message: 'Test message', type: 'success'});
// renders the component on the page
this.render();
expect(component._state).to.equal('inDOM');
expect(this.$().prop('tagName')).to.equal('ARTICLE');
expect(this.$().is('.gh-notification, .gh-notification-passive')).to.be.true;
expect(this.$().text()).to.match(/Test message/);
});
it('maps success alert type to correct class', function () {
var component = this.subject();
component.set('message', {message: 'Test message', type: 'success'});
expect(this.$().hasClass('gh-notification-green')).to.be.true;
});
it('maps error alert type to correct class', function () {
var component = this.subject();
component.set('message', {message: 'Test message', type: 'error'});
expect(this.$().hasClass('gh-notification-red')).to.be.true;
});
it('maps warn alert type to correct class', function () {
var component = this.subject();
component.set('message', {message: 'Test message', type: 'warn'});
expect(this.$().hasClass('gh-notification-yellow')).to.be.true;
});
it('closes notification through notifications service', function () {
var component = this.subject(),
notifications = {},

View File

@ -1,47 +0,0 @@
/* jshint expr:true */
import Ember from 'ember';
import { expect } from 'chai';
import {
describeComponent,
it
}
from 'ember-mocha';
describeComponent(
'gh-notifications',
'Unit: Component: gh-notifications', {
unit: true,
needs: ['component:gh-notification']
},
function () {
beforeEach(function () {
// Stub the notifications service
var notifications = Ember.Object.create();
notifications.notifications = Ember.A();
notifications.notifications.pushObject({message: 'First', type: 'error'});
notifications.notifications.pushObject({message: 'Second', type: 'warn'});
this.subject().set('notifications', notifications);
});
it('renders', function () {
// creates the component instance
var component = this.subject();
expect(component._state).to.equal('preRender');
// renders the component on the page
this.render();
expect(component._state).to.equal('inDOM');
expect(this.$().prop('tagName')).to.equal('ASIDE');
expect(this.$().hasClass('gh-notifications')).to.be.true;
expect(this.$().children().length).to.equal(2);
Ember.run(function () {
component.set('notifications.notifications', Ember.A());
});
expect(this.$().children().length).to.equal(0);
});
}
);

View File

@ -4,7 +4,7 @@ import { describeModule, it } from 'ember-mocha';
import Ember from 'ember';
import { NavItem } from 'ghost/controllers/settings/navigation';
const { run } = Ember;
const {run} = Ember;
var navSettingJSON = `[
{"label":"Home","url":"/"},

View File

@ -7,6 +7,8 @@ import {
it
} from 'ember-mocha';
const {run, get} = Ember;
describeModule(
'service:notifications',
'Unit: Service: notifications',
@ -23,16 +25,17 @@ describeModule(
it('filters alerts/notifications', function () {
var notifications = this.subject();
notifications.set('content', [
{message: 'Alert', status: 'alert'},
{message: 'Notification', status: 'notification'}
]);
// wrapped in run-loop to enure alerts/notifications CPs are updated
run(() => {
notifications.showAlert('Alert');
notifications.showNotification('Notification');
});
expect(notifications.get('alerts'))
.to.deep.equal([{message: 'Alert', status: 'alert'}]);
expect(notifications.get('alerts.length')).to.equal(1);
expect(notifications.get('alerts.firstObject.message')).to.equal('Alert');
expect(notifications.get('notifications'))
.to.deep.equal([{message: 'Notification', status: 'notification'}]);
expect(notifications.get('notifications.length')).to.equal(1);
expect(notifications.get('notifications.firstObject.message')).to.equal('Notification');
});
it('#handleNotification deals with DS.Notification notifications', function () {
@ -61,71 +64,106 @@ describeModule(
it('#showAlert adds POJO alerts', function () {
var notifications = this.subject();
notifications.showAlert('Test Alert', {type: 'error'});
run(() => {
notifications.showAlert('Test Alert', {type: 'error'});
});
expect(notifications.get('alerts'))
.to.deep.include({message: 'Test Alert', status: 'alert', type: 'error'});
.to.deep.include({message: 'Test Alert', status: 'alert', type: 'error', key: undefined});
});
it('#showAlert adds delayed notifications', function () {
var notifications = this.subject();
notifications.showNotification('Test Alert', {type: 'error', delayed: true});
run(() => {
notifications.showNotification('Test Alert', {type: 'error', delayed: true});
});
expect(notifications.get('delayedNotifications'))
.to.deep.include({message: 'Test Alert', status: 'notification', type: 'error'});
.to.deep.include({message: 'Test Alert', status: 'notification', type: 'error', key: undefined});
});
// in order to cater for complex keys that are suitable for i18n
// we split on the second period and treat the resulting base as
// the key for duplicate checking
it('#showAlert clears duplicates', function () {
var notifications = this.subject();
run(() => {
notifications.showAlert('Kept');
notifications.showAlert('Duplicate', {key: 'duplicate.key.fail'});
});
expect(notifications.get('alerts.length')).to.equal(2);
run(() => {
notifications.showAlert('Duplicate with new message', {key: 'duplicate.key.success'});
});
expect(notifications.get('alerts.length')).to.equal(2);
expect(notifications.get('alerts.lastObject.message')).to.equal('Duplicate with new message');
});
it('#showNotification adds POJO notifications', function () {
var notifications = this.subject();
notifications.showNotification('Test Notification', {type: 'success'});
run(() => {
notifications.showNotification('Test Notification', {type: 'success'});
});
expect(notifications.get('notifications'))
.to.deep.include({message: 'Test Notification', status: 'notification', type: 'success'});
.to.deep.include({message: 'Test Notification', status: 'notification', type: 'success', key: undefined});
});
it('#showNotification adds delayed notifications', function () {
var notifications = this.subject();
notifications.showNotification('Test Notification', {delayed: true});
run(() => {
notifications.showNotification('Test Notification', {delayed: true});
});
expect(notifications.get('delayedNotifications'))
.to.deep.include({message: 'Test Notification', status: 'notification', type: undefined});
.to.deep.include({message: 'Test Notification', status: 'notification', type: undefined, key: undefined});
});
it('#showNotification clears existing notifications', function () {
var notifications = this.subject();
notifications.showNotification('First');
notifications.showNotification('Second');
run(() => {
notifications.showNotification('First');
notifications.showNotification('Second');
});
expect(notifications.get('content.length')).to.equal(1);
expect(notifications.get('content'))
.to.deep.equal([{message: 'Second', status: 'notification', type: undefined}]);
expect(notifications.get('notifications.length')).to.equal(1);
expect(notifications.get('notifications'))
.to.deep.equal([{message: 'Second', status: 'notification', type: undefined, key: undefined}]);
});
it('#showNotification keeps existing notifications if doNotCloseNotifications option passed', function () {
var notifications = this.subject();
notifications.showNotification('First');
notifications.showNotification('Second', {doNotCloseNotifications: true});
run(() => {
notifications.showNotification('First');
notifications.showNotification('Second', {doNotCloseNotifications: true});
});
expect(notifications.get('content.length')).to.equal(2);
expect(notifications.get('notifications.length')).to.equal(2);
});
// TODO: review whether this can be removed once it's no longer used by validations
it('#showErrors adds multiple notifications', function () {
var notifications = this.subject();
notifications.showErrors([
{message: 'First'},
{message: 'Second'}
]);
run(() => {
notifications.showErrors([
{message: 'First'},
{message: 'Second'}
]);
});
expect(notifications.get('content')).to.deep.equal([
{message: 'First', status: 'notification', type: 'error'},
{message: 'Second', status: 'notification', type: 'error'}
expect(notifications.get('notifications')).to.deep.equal([
{message: 'First', status: 'notification', type: 'error', key: undefined},
{message: 'Second', status: 'notification', type: 'error', key: undefined}
]);
});
@ -133,11 +171,15 @@ describeModule(
var notifications = this.subject(),
resp = {jqXHR: {responseJSON: {error: 'Single error'}}};
notifications.showAPIError(resp);
run(() => {
notifications.showAPIError(resp);
});
expect(notifications.get('content')).to.deep.equal([
{message: 'Single error', status: 'alert', type: 'error'}
]);
let notification = notifications.get('alerts.firstObject');
expect(get(notification, 'message')).to.equal('Single error');
expect(get(notification, 'status')).to.equal('alert');
expect(get(notification, 'type')).to.equal('error');
expect(get(notification, 'key')).to.equal('api-error');
});
// used to display validation errors returned from the server
@ -145,11 +187,13 @@ describeModule(
var notifications = this.subject(),
resp = {jqXHR: {responseJSON: {errors: ['First error', 'Second error']}}};
notifications.showAPIError(resp);
run(() => {
notifications.showAPIError(resp);
});
expect(notifications.get('content')).to.deep.equal([
{message: 'First error', status: 'notification', type: 'error'},
{message: 'Second error', status: 'notification', type: 'error'}
expect(notifications.get('notifications')).to.deep.equal([
{message: 'First error', status: 'notification', type: 'error', key: undefined},
{message: 'Second error', status: 'notification', type: 'error', key: undefined}
]);
});
@ -157,43 +201,70 @@ describeModule(
var notifications = this.subject(),
resp = {jqXHR: {responseJSON: {message: 'Single message'}}};
notifications.showAPIError(resp);
run(() => {
notifications.showAPIError(resp);
});
expect(notifications.get('content')).to.deep.equal([
{message: 'Single message', status: 'alert', type: 'error'}
]);
let notification = notifications.get('alerts.firstObject');
expect(get(notification, 'message')).to.equal('Single message');
expect(get(notification, 'status')).to.equal('alert');
expect(get(notification, 'type')).to.equal('error');
expect(get(notification, 'key')).to.equal('api-error');
});
it('#showAPIError displays default error text if response has no error/message', function () {
var notifications = this.subject(),
resp = {};
notifications.showAPIError(resp);
run(() => { notifications.showAPIError(resp); });
expect(notifications.get('content')).to.deep.equal([
{message: 'There was a problem on the server, please try again.', status: 'alert', type: 'error'}
{message: 'There was a problem on the server, please try again.', status: 'alert', type: 'error', key: 'api-error'}
]);
notifications.set('content', Ember.A());
notifications.showAPIError(resp, {defaultErrorText: 'Overridden default'});
run(() => {
notifications.showAPIError(resp, {defaultErrorText: 'Overridden default'});
});
expect(notifications.get('content')).to.deep.equal([
{message: 'Overridden default', status: 'alert', type: 'error'}
{message: 'Overridden default', status: 'alert', type: 'error', key: 'api-error'}
]);
});
it('#showAPIError sets correct key when passed a base key', function () {
var notifications = this.subject();
run(() => {
notifications.showAPIError('Test', {key: 'test.alert'});
});
expect(notifications.get('alerts.firstObject.key')).to.equal('test.alert.api-error');
});
it('#showAPIError sets correct key when not passed a key', function () {
var notifications = this.subject();
run(() => {
notifications.showAPIError('Test');
});
expect(notifications.get('alerts.firstObject.key')).to.equal('api-error');
});
it('#displayDelayed moves delayed notifications into content', function () {
var notifications = this.subject();
notifications.showNotification('First', {delayed: true});
notifications.showNotification('Second', {delayed: true});
notifications.showNotification('Third', {delayed: false});
run(() => {
notifications.showNotification('First', {delayed: true});
notifications.showNotification('Second', {delayed: true});
notifications.showNotification('Third', {delayed: false});
notifications.displayDelayed();
});
notifications.displayDelayed();
expect(notifications.get('content')).to.deep.equal([
{message: 'Third', status: 'notification', type: undefined},
{message: 'First', status: 'notification', type: undefined},
{message: 'Second', status: 'notification', type: undefined}
expect(notifications.get('notifications')).to.deep.equal([
{message: 'Third', status: 'notification', type: undefined, key: undefined},
{message: 'First', status: 'notification', type: undefined, key: undefined},
{message: 'Second', status: 'notification', type: undefined, key: undefined}
]);
});
@ -201,12 +272,16 @@ describeModule(
var notification = {message: 'Close test', status: 'notification'},
notifications = this.subject();
notifications.handleNotification(notification);
run(() => {
notifications.handleNotification(notification);
});
expect(notifications.get('notifications'))
.to.include(notification);
notifications.closeNotification(notification);
run(() => {
notifications.closeNotification(notification);
});
expect(notifications.get('notifications'))
.to.not.include(notification);
@ -226,40 +301,59 @@ describeModule(
};
sinon.spy(notification, 'save');
notifications.handleNotification(notification);
run(() => { notifications.handleNotification(notification); });
expect(notifications.get('alerts')).to.include(notification);
notifications.closeNotification(notification);
run(() => { notifications.closeNotification(notification); });
expect(notification.deleteRecord.calledOnce).to.be.true;
expect(notification.save.calledOnce).to.be.true;
// wrap in runloop so filter updates
Ember.run.next(function () {
expect(notifications.get('alerts')).to.not.include(notification);
});
expect(notifications.get('alerts')).to.not.include(notification);
});
it('#closeNotifications only removes notifications', function () {
var notifications = this.subject();
notifications.showAlert('First alert');
notifications.showNotification('First notification');
notifications.showNotification('Second notification', {doNotCloseNotifications: true});
expect(notifications.get('alerts.length')).to.equal(1);
expect(notifications.get('notifications.length')).to.equal(2);
notifications.closeNotifications();
// wrap in runloop so filter updates
Ember.run.next(function () {
expect(notifications.get('alerts.length')).to.equal(1);
expect(notifications.get('notifications.length')).to.equal(1);
run(() => {
notifications.showAlert('First alert');
notifications.showNotification('First notification');
notifications.showNotification('Second notification', {doNotCloseNotifications: true});
});
expect(notifications.get('alerts.length'), 'alerts count').to.equal(1);
expect(notifications.get('notifications.length'), 'notifications count').to.equal(2);
run(() => { notifications.closeNotifications(); });
expect(notifications.get('alerts.length'), 'alerts count').to.equal(1);
expect(notifications.get('notifications.length'), 'notifications count').to.equal(0);
});
it('#closeAll removes everything without deletion', function () {
it('#closeNotifications only closes notifications with specified key', function () {
var notifications = this.subject();
run(() => {
notifications.showAlert('First alert');
// using handleNotification as showNotification will auto-prune
// duplicates and keys will be removed if doNotCloseNotifications
// is true
notifications.handleNotification({message: 'First notification', key: 'test.close', status: 'notification'});
notifications.handleNotification({message: 'Second notification', key: 'test.keep', status: 'notification'});
notifications.handleNotification({message: 'Third notification', key: 'test.close', status: 'notification'});
});
run(() => {
notifications.closeNotifications('test.close');
});
expect(notifications.get('notifications.length'), 'notifications count').to.equal(1);
expect(notifications.get('notifications.firstObject.message'), 'notification message').to.equal('Second notification');
expect(notifications.get('alerts.length'), 'alerts count').to.equal(1);
});
it('#clearAll removes everything without deletion', function () {
var notifications = this.subject(),
notificationModel = Ember.Object.create({message: 'model'});
@ -276,11 +370,43 @@ describeModule(
notifications.handleNotification(notificationModel);
notifications.handleNotification({message: 'pojo'});
notifications.closeAll();
notifications.clearAll();
expect(notifications.get('content')).to.be.empty;
expect(notificationModel.deleteRecord.called).to.be.false;
expect(notificationModel.save.called).to.be.false;
});
it('#closeAlerts only removes alerts', function () {
var notifications = this.subject();
notifications.showNotification('First notification');
notifications.showAlert('First alert');
notifications.showAlert('Second alert');
run(() => {
notifications.closeAlerts();
});
expect(notifications.get('alerts.length')).to.equal(0);
expect(notifications.get('notifications.length')).to.equal(1);
});
it('#closeAlerts closes only alerts with specified key', function () {
var notifications = this.subject();
notifications.showNotification('First notification');
notifications.showAlert('First alert', {key: 'test.close'});
notifications.showAlert('Second alert', {key: 'test.keep'});
notifications.showAlert('Third alert', {key: 'test.close'});
run(() => {
notifications.closeAlerts('test.close');
});
expect(notifications.get('alerts.length')).to.equal(1);
expect(notifications.get('alerts.firstObject.message')).to.equal('Second alert');
expect(notifications.get('notifications.length')).to.equal(1);
});
}
);

View File

@ -38,8 +38,7 @@ utils = {
/**
* ### Do Validate
* Validate the object and options passed to an endpoint
* @argument object
* @argument options
* @argument {...*} [arguments] object or object and options hash
*/
return function doValidate() {
var object, options, permittedOptions;

View File

@ -22,7 +22,7 @@ author = function (context, options) {
}
if (options.fn) {
return hbs.handlebars.helpers['with'].call(this, this.author, options);
return hbs.handlebars.helpers.with.call(this, this.author, options);
}
var autolink = _.isString(options.hash.autolink) && options.hash.autolink === 'false' ? false : true,

View File

@ -178,7 +178,7 @@ function init(options) {
// ##Configuration
// return the correct mime type for woff files
express['static'].mime.define({'application/font-woff': ['woff']});
express.static.mime.define({'application/font-woff': ['woff']});
// enabled gzip compression by default
if (config.server.compress !== false) {

View File

@ -24,7 +24,7 @@ cacheControl = function cacheControl(options) {
return function cacheControlHeaders(req, res, next) {
if (output) {
if (res.isPrivateBlog) {
res.set({'Cache-Control': profiles['private']});
res.set({'Cache-Control': profiles.private});
} else {
res.set({'Cache-Control': output});
}

View File

@ -78,9 +78,9 @@ setupMiddleware = function setupMiddleware(blogApp, adminApp) {
blogApp.use(serveSharedFile('favicon.ico', 'image/x-icon', utils.ONE_DAY_S));
// Static assets
blogApp.use('/shared', express['static'](path.join(corePath, '/shared'), {maxAge: utils.ONE_HOUR_MS}));
blogApp.use('/shared', express.static(path.join(corePath, '/shared'), {maxAge: utils.ONE_HOUR_MS}));
blogApp.use('/content/images', storage.getStorage().serve());
blogApp.use('/public', express['static'](path.join(corePath, '/built/public'), {maxAge: utils.ONE_YEAR_MS}));
blogApp.use('/public', express.static(path.join(corePath, '/built/public'), {maxAge: utils.ONE_YEAR_MS}));
// First determine whether we're serving admin or theme content
blogApp.use(decideIsAdmin);
@ -88,7 +88,7 @@ setupMiddleware = function setupMiddleware(blogApp, adminApp) {
blogApp.use(themeHandler.configHbsForContext);
// Admin only config
blogApp.use('/ghost', express['static'](config.paths.clientAssets, {maxAge: utils.ONE_YEAR_MS}));
blogApp.use('/ghost', express.static(config.paths.clientAssets, {maxAge: utils.ONE_YEAR_MS}));
// Force SSL
// NOTE: Importantly this is _after_ the check above for admin-theme static resources,

View File

@ -8,7 +8,7 @@ var _ = require('lodash'),
errors = require('../errors'),
session = require('cookie-session'),
utils = require('../utils'),
private;
privateBlogging;
function verifySessionHash(salt, hash) {
if (!salt || !hash) {
@ -24,7 +24,7 @@ function verifySessionHash(salt, hash) {
});
}
private = {
privateBlogging = {
checkIsPrivate: function checkIsPrivate(req, res, next) {
return api.settings.read({context: {internal: true}, key: 'isPrivate'}).then(function then(response) {
var pass = response.settings[0];
@ -64,7 +64,7 @@ private = {
res.end(buf);
});
} else {
return private.authenticatePrivateSession(req, res, next);
return privateBlogging.authenticatePrivateSession(req, res, next);
}
},
@ -133,4 +133,4 @@ private = {
}
};
module.exports = private;
module.exports = privateBlogging;

View File

@ -11,7 +11,7 @@ function isBlackListedFileType(file) {
}
function forwardToExpressStatic(req, res, next) {
express['static'](
express.static(
path.join(config.paths.themePath, req.app.get('activeTheme')),
{maxAge: utils.ONE_YEAR_MS}
)(req, res, next);

View File

@ -52,7 +52,7 @@ LocalFileStore.prototype.exists = function (filename) {
// middleware for serving the files
LocalFileStore.prototype.serve = function () {
// For some reason send divides the max age number by 1000
return express['static'](config.paths.imagesPath, {maxAge: utils.ONE_YEAR_MS});
return express.static(config.paths.imagesPath, {maxAge: utils.ONE_YEAR_MS});
};
module.exports = LocalFileStore;

View File

@ -291,7 +291,7 @@ casper.on('error', function (msg, trace) {
if (trace && trace[0]) {
casper.echoConcise('file: ' + trace[0].file, 'WARNING');
casper.echoConcise('line: ' + trace[0].line, 'WARNING');
casper.echoConcise('function: ' + trace[0]['function'], 'WARNING');
casper.echoConcise('function: ' + trace[0].function, 'WARNING');
}
jsErrors.push(msg);
});
@ -302,7 +302,7 @@ casper.on('page.error', function (msg, trace) {
if (trace && trace[0]) {
casper.echoConcise('file: ' + trace[0].file, 'WARNING');
casper.echoConcise('line: ' + trace[0].line, 'WARNING');
casper.echoConcise('function: ' + trace[0]['function'], 'WARNING');
casper.echoConcise('function: ' + trace[0].function, 'WARNING');
}
pageErrors.push(msg);
});

View File

@ -188,7 +188,7 @@ describe('Admin Routing', function () {
it('should redirect from /ghost/ to /ghost/setup/ when no user/not installed yet', function (done) {
request.get('/ghost/')
.expect('Location', /ghost\/setup/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(302)
.end(doEnd(done));
});
@ -196,7 +196,7 @@ describe('Admin Routing', function () {
it('should redirect from /ghost/signin/ to /ghost/setup/ when no user', function (done) {
request.get('/ghost/signin/')
.expect('Location', /ghost\/setup/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(302)
.end(doEnd(done));
});
@ -204,7 +204,7 @@ describe('Admin Routing', function () {
it('should respond with html for /ghost/setup/', function (done) {
request.get('/ghost/setup/')
.expect('Content-Type', /html/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(doEnd(done));
});

View File

@ -54,7 +54,7 @@ describe('Authentication API', function () {
request.post(testUtils.API.getApiQuery('authentication/token'))
.send({grant_type: 'password', username: 'invalid@email.com', password: user.password, client_id: 'ghost-admin', client_secret: 'not_available'})
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.end(function (err, res) {
if (err) {
@ -71,7 +71,7 @@ describe('Authentication API', function () {
request.post(testUtils.API.getApiQuery('authentication/token'))
.send({grant_type: 'password', username: user.email, password: 'invalid', client_id: 'ghost-admin', client_secret: 'not_available'})
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(401)
.end(function (err, res) {
if (err) {
@ -118,7 +118,7 @@ describe('Authentication API', function () {
request.post(testUtils.API.getApiQuery('authentication/token'))
.send({grant_type: 'refresh_token', refresh_token: 'invalid', client_id: 'ghost-admin', client_secret: 'not_available'})
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(403)
.end(function (err, res) {
if (err) {

View File

@ -32,7 +32,7 @@ describe('DB API', function () {
request.get(testUtils.API.getApiQuery('db/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.expect('Content-Disposition', /Attachment; filename="[A-Za-z0-9._-]+\.json"/)
.end(function (err, res) {

View File

@ -30,7 +30,7 @@ describe('Unauthorized', function () {
describe('Unauthorized API', function () {
it('can\'t retrieve posts', function (done) {
request.get(testUtils.API.getApiQuery('posts/'))
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(401)
.end(function firstRequest(err, res) {
if (err) {

View File

@ -40,7 +40,7 @@ describe('Notifications API', function () {
.set('Authorization', 'Bearer ' + accesstoken)
.send({notifications: [newNotification]})
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(201)
.end(function (err, res) {
if (err) {
@ -75,7 +75,7 @@ describe('Notifications API', function () {
.set('Authorization', 'Bearer ' + accesstoken)
.send({notifications: [newNotification]})
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(201)
.end(function (err, res) {
if (err) {

View File

@ -36,7 +36,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('posts/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -60,7 +60,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('posts/?staticPages=all'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -84,7 +84,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('posts/?staticPages=all&status=all'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -106,7 +106,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('posts/?staticPages=true'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -128,7 +128,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('posts/?featured=true'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -150,7 +150,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('posts/?status=draft'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -175,7 +175,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('posts/1/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -204,7 +204,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('posts/slug/welcome-to-ghost/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -232,7 +232,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('posts/1/?include=author,tags,created_by'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -258,7 +258,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('posts/3/?include=next,previous'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -284,7 +284,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('posts/7/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -306,7 +306,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('posts/99/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.end(function (err, res) {
if (err) {
@ -326,7 +326,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('posts/5/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.end(function (err, res) {
if (err) {
@ -346,7 +346,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('posts/8/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.end(function (err, res) {
if (err) {
@ -376,7 +376,7 @@ describe('Post API', function () {
.set('Authorization', 'Bearer ' + accesstoken)
.send(newPost)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(201)
.end(function (err, res) {
if (err) {
@ -400,7 +400,7 @@ describe('Post API', function () {
.set('Authorization', 'Bearer ' + accesstoken)
.send(draftPost)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -427,7 +427,7 @@ describe('Post API', function () {
.set('Authorization', 'Bearer ' + accesstoken)
.send(publishedPost)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -464,7 +464,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('posts/1/?include=tags'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.end(function (err, res) {
if (err) {
return done(err);
@ -481,7 +481,7 @@ describe('Post API', function () {
.set('Authorization', 'Bearer ' + accesstoken)
.send(jsonResponse)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -510,7 +510,7 @@ describe('Post API', function () {
.set('Authorization', 'Bearer ' + accesstoken)
.send(newPost)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(201)
.end(function (err, res) {
if (err) {
@ -530,7 +530,7 @@ describe('Post API', function () {
.set('Authorization', 'Bearer ' + accesstoken)
.send(draftPost)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -555,7 +555,7 @@ describe('Post API', function () {
.set('Authorization', 'Bearer ' + accesstoken)
.send(newPost)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(201)
.end(function (err, res) {
if (err) {
@ -576,7 +576,7 @@ describe('Post API', function () {
.set('Authorization', 'Bearer ' + accesstoken)
.send(draftPost)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -594,7 +594,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('posts/1/?include=tags'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.end(function (err, res) {
if (err) {
return done(err);
@ -610,7 +610,7 @@ describe('Post API', function () {
.set('Authorization', 'Bearer ' + accesstoken)
.send(jsonResponse)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -632,7 +632,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('posts/7/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.end(function (err, res) {
if (err) {
return done(err);
@ -648,7 +648,7 @@ describe('Post API', function () {
.set('Authorization', 'Bearer ' + accesstoken)
.send(jsonResponse)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -670,7 +670,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('posts/7/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.end(function (err, res) {
if (err) {
return done(err);
@ -686,7 +686,7 @@ describe('Post API', function () {
.set('Authorization', 'Bearer ' + accesstoken)
.send(jsonResponse)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(422)
.end(function (err, res) {
if (err) {
@ -706,7 +706,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('posts/1/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.end(function (err, res) {
/*jshint unused:false*/
if (err) {
@ -718,7 +718,7 @@ describe('Post API', function () {
.set('Authorization', 'Bearer ' + 'invalidtoken')
.send(jsonResponse)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(401)
.end(function (err, res) {
/*jshint unused:false*/
@ -735,7 +735,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('posts/1/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.end(function (err, res) {
if (err) {
return done(err);
@ -748,7 +748,7 @@ describe('Post API', function () {
.set('Authorization', 'Bearer ' + accesstoken)
.send(jsonResponse)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(400)
.end(function (err, res) {
/*jshint unused:false*/
@ -765,7 +765,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('posts/1/?include=tags'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.end(function (err, res) {
if (err) {
return done(err);
@ -781,7 +781,7 @@ describe('Post API', function () {
.set('Authorization', 'Bearer ' + accesstoken)
.send(jsonResponse)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -807,7 +807,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('posts/1/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.end(function (err, res) {
if (err) {
return done(err);
@ -822,7 +822,7 @@ describe('Post API', function () {
.set('Authorization', 'Bearer ' + accesstoken)
.send(jsonResponse)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.end(function (err, res) {
if (err) {
@ -846,7 +846,7 @@ describe('Post API', function () {
request.del(testUtils.API.getApiQuery('posts/' + deletePostId + '/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -867,7 +867,7 @@ describe('Post API', function () {
request.del(testUtils.API.getApiQuery('posts/99/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.end(function (err, res) {
if (err) {
@ -892,7 +892,7 @@ describe('Post API', function () {
.set('Authorization', 'Bearer ' + accesstoken)
.send(newPost)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(201)
.end(function (err, res) {
if (err) {
@ -909,7 +909,7 @@ describe('Post API', function () {
request.del(testUtils.API.getApiQuery('posts/' + draftPost.posts[0].id + '/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -931,7 +931,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('settings/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.end(function (err, res) {
if (err) {
return done(err);
@ -944,7 +944,7 @@ describe('Post API', function () {
.set('Authorization', 'Bearer ' + accesstoken)
.send(jsonResponse)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.end(function (err, res) {
/*jshint unused:false*/
if (err) {
@ -959,7 +959,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('settings/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.end(function (err, res) {
if (err) {
return done(err);
@ -971,7 +971,7 @@ describe('Post API', function () {
request.put(testUtils.API.getApiQuery('settings/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.send(jsonResponse)
.end(function (err, res) {
/*jshint unused:false*/
@ -989,7 +989,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('posts/2/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -1012,7 +1012,7 @@ describe('Post API', function () {
request.get(testUtils.API.getApiQuery('posts/2/?include=tags'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.end(function (err, res) {
if (err) {
return done(err);
@ -1027,7 +1027,7 @@ describe('Post API', function () {
request.put(testUtils.API.getApiQuery('posts/2/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.send(jsonResponse)
.expect(200)
.end(function (err, res) {

View File

@ -35,7 +35,7 @@ describe('Settings API', function () {
request.get(testUtils.API.getApiQuery('settings/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -55,7 +55,7 @@ describe('Settings API', function () {
request.get(testUtils.API.getApiQuery('settings/title/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -79,7 +79,7 @@ describe('Settings API', function () {
request.get(testUtils.API.getApiQuery('settings/testsetting/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.end(function (err, res) {
if (err) {
@ -99,7 +99,7 @@ describe('Settings API', function () {
request.get(testUtils.API.getApiQuery('settings/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.end(function (err, res) {
if (err) {
return done(err);
@ -120,7 +120,7 @@ describe('Settings API', function () {
.set('Authorization', 'Bearer ' + accesstoken)
.send(settingToChange)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -141,7 +141,7 @@ describe('Settings API', function () {
request.get(testUtils.API.getApiQuery('settings/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.end(function (err, res) {
if (err) {
return done(err);
@ -171,7 +171,7 @@ describe('Settings API', function () {
request.get(testUtils.API.getApiQuery('settings/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.end(function (err, res) {
if (err) {
return done(err);
@ -187,7 +187,7 @@ describe('Settings API', function () {
.set('Authorization', 'Bearer ' + accesstoken)
.send(jsonResponse)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.end(function (err, res) {
if (err) {

View File

@ -34,7 +34,7 @@ describe('Slug API', function () {
request.get(testUtils.API.getApiQuery('slugs/post/a post title/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -57,7 +57,7 @@ describe('Slug API', function () {
request.get(testUtils.API.getApiQuery('slugs/post/atag/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -80,7 +80,7 @@ describe('Slug API', function () {
request.get(testUtils.API.getApiQuery('slugs/user/user name/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -103,7 +103,7 @@ describe('Slug API', function () {
request.get(testUtils.API.getApiQuery('slugs/app/cool app/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -126,7 +126,7 @@ describe('Slug API', function () {
request.get(testUtils.API.getApiQuery('slugs/unknown/who knows/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(400)
.end(function (err, res) {
if (err) {

View File

@ -34,7 +34,7 @@ describe('Tag API', function () {
request.get(testUtils.API.getApiQuery('tags/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {

View File

@ -35,7 +35,7 @@ describe('User API', function () {
request.get(testUtils.API.getApiQuery('users/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -61,7 +61,7 @@ describe('User API', function () {
request.get(testUtils.API.getApiQuery('users/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -83,7 +83,7 @@ describe('User API', function () {
request.get(testUtils.API.getApiQuery('users/?include=roles'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -107,7 +107,7 @@ describe('User API', function () {
request.get(testUtils.API.getApiQuery('users/me/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -129,7 +129,7 @@ describe('User API', function () {
request.get(testUtils.API.getApiQuery('users/1/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -151,7 +151,7 @@ describe('User API', function () {
request.get(testUtils.API.getApiQuery('users/slug/joe-bloggs/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -173,7 +173,7 @@ describe('User API', function () {
request.get(testUtils.API.getApiQuery('users/email/jbloggs%40example.com/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -195,7 +195,7 @@ describe('User API', function () {
request.get(testUtils.API.getApiQuery('users/me/?include=roles'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -218,7 +218,7 @@ describe('User API', function () {
request.get(testUtils.API.getApiQuery('users/me/?include=roles,roles.permissions'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -243,7 +243,7 @@ describe('User API', function () {
request.get(testUtils.API.getApiQuery('users/slug/joe-bloggs/?include=roles,roles.permissions'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -268,7 +268,7 @@ describe('User API', function () {
request.get(testUtils.API.getApiQuery('users/99/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.end(function (err, res) {
if (err) {
@ -288,7 +288,7 @@ describe('User API', function () {
request.get(testUtils.API.getApiQuery('users/slug/blargh/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.end(function (err, res) {
if (err) {
@ -309,7 +309,7 @@ describe('User API', function () {
request.get(testUtils.API.getApiQuery('users/me/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.end(function (err, res) {
if (err) {
return done(err);
@ -329,7 +329,7 @@ describe('User API', function () {
.set('Authorization', 'Bearer ' + accesstoken)
.send(dataToSend)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(200)
.end(function (err, res) {
if (err) {
@ -351,7 +351,7 @@ describe('User API', function () {
request.get(testUtils.API.getApiQuery('users/me/'))
.set('Authorization', 'Bearer ' + accesstoken)
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.end(function (err, res) {
if (err) {
return done(err);

View File

@ -57,7 +57,7 @@ describe('Frontend Routing', function () {
describe('Error', function () {
it('should 404 for unknown post', function (done) {
request.get('/spectacular/')
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.expect(/Page not found/)
.end(doEnd(done));
@ -65,7 +65,7 @@ describe('Frontend Routing', function () {
it('should 404 for unknown post with invalid characters', function (done) {
request.get('/$pec+acular~/')
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.expect(/Page not found/)
.end(doEnd(done));
@ -73,7 +73,7 @@ describe('Frontend Routing', function () {
it('should 404 for unknown frontend route', function (done) {
request.get('/spectacular/marvellous/')
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.expect(/Page not found/)
.end(doEnd(done));
@ -81,7 +81,7 @@ describe('Frontend Routing', function () {
it('should 404 for unknown tag', function (done) {
request.get('/tag/spectacular/')
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.expect(/Page not found/)
.end(doEnd(done));
@ -89,7 +89,7 @@ describe('Frontend Routing', function () {
it('should 404 for unknown tag with invalid characters', function (done) {
request.get('/tag/~$pectacular~/')
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.expect(/Page not found/)
.end(doEnd(done));
@ -97,7 +97,7 @@ describe('Frontend Routing', function () {
it('should 404 for unknown author', function (done) {
request.get('/author/spectacular/')
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.expect(/Page not found/)
.end(doEnd(done));
@ -105,7 +105,7 @@ describe('Frontend Routing', function () {
it('should 404 for encoded char not 301 from uncapitalise', function (done) {
request.get('/|/')
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.expect(/Page not found/)
.end(doEnd(done));
@ -113,7 +113,7 @@ describe('Frontend Routing', function () {
it('should 404 for unknown author with invalid characters', function (done) {
request.get('/author/ghost!user^/')
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.expect(/Page not found/)
.end(doEnd(done));
@ -124,7 +124,7 @@ describe('Frontend Routing', function () {
it('should respond with html', function (done) {
request.get('/')
.expect('Content-Type', /html/)
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(200)
.end(function (err, res) {
if (err) {
@ -152,7 +152,7 @@ describe('Frontend Routing', function () {
it('should not have as second page', function (done) {
request.get('/page/2/')
.expect('Location', '/')
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(302)
.end(doEnd(done));
});
@ -178,7 +178,7 @@ describe('Frontend Routing', function () {
it('should respond with html for valid url', function (done) {
request.get('/welcome-to-ghost/')
.expect('Content-Type', /html/)
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(200)
.end(function (err, res) {
if (err) {
@ -209,7 +209,7 @@ describe('Frontend Routing', function () {
var date = moment().format('YYYY/MM/DD');
request.get('/' + date + '/welcome-to-ghost/')
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.expect(/Page not found/)
.end(doEnd(done));
@ -228,14 +228,14 @@ describe('Frontend Routing', function () {
it('should redirect to editor', function (done) {
request.get('/welcome-to-ghost/edit/')
.expect('Location', '/ghost/editor/1/')
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(302)
.end(doEnd(done));
});
it('should 404 for non-edit parameter', function (done) {
request.get('/welcome-to-ghost/notedit/')
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.expect(/Page not found/)
.end(doEnd(done));
@ -305,7 +305,7 @@ describe('Frontend Routing', function () {
it('should respond with xml', function (done) {
request.get('/static-page-test/')
.expect('Content-Type', /html/)
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(200)
.end(doEnd(done));
});
@ -366,7 +366,7 @@ describe('Frontend Routing', function () {
// Badly formed regexs can cause breakage if a post slug starts with the 5 letters ghost
it('should retrieve a blog post with ghost at the start of the url', function (done) {
request.get('/ghostly-kitchen-sink/')
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(200)
.end(doEnd(done));
});
@ -399,7 +399,7 @@ describe('Frontend Routing', function () {
it('should respond with html', function (done) {
request.get('/page/2/')
.expect('Content-Type', /html/)
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(200)
.end(doEnd(done));
});
@ -407,7 +407,7 @@ describe('Frontend Routing', function () {
it('should redirect page 1', function (done) {
request.get('/page/1/')
.expect('Location', '/')
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
// TODO: This should probably be a 301?
.expect(302)
.end(doEnd(done));
@ -416,7 +416,7 @@ describe('Frontend Routing', function () {
it('should redirect to last page if page too high', function (done) {
request.get('/page/4/')
.expect('Location', '/page/3/')
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(302)
.end(doEnd(done));
});
@ -424,7 +424,7 @@ describe('Frontend Routing', function () {
it('should redirect to first page if page too low', function (done) {
request.get('/page/0/')
.expect('Location', '/')
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(302)
.end(doEnd(done));
});
@ -457,7 +457,7 @@ describe('Frontend Routing', function () {
it('should respond with 200 & CC=public', function (done) {
request.get('/rss/')
.expect('Content-Type', 'text/xml; charset=utf-8')
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(200)
.end(function (err, res) {
if (err) {
@ -502,7 +502,7 @@ describe('Frontend Routing', function () {
it('should respond with xml', function (done) {
request.get('/rss/2/')
.expect('Content-Type', /xml/)
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(200)
.end(doEnd(done));
});
@ -528,7 +528,7 @@ describe('Frontend Routing', function () {
it('should 404 for /author/ route', function (done) {
request.get('/author/')
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.expect(/Page not found/)
.end(doEnd(done));
@ -545,7 +545,7 @@ describe('Frontend Routing', function () {
it('should respond with html', function (done) {
request.get('/author/ghost-owner/page/2/')
.expect('Content-Type', /html/)
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(200)
.end(doEnd(done));
});
@ -553,7 +553,7 @@ describe('Frontend Routing', function () {
it('should redirect page 1', function (done) {
request.get('/author/ghost-owner/page/1/')
.expect('Location', '/author/ghost-owner/')
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
// TODO: This should probably be a 301?
.expect(302)
.end(doEnd(done));
@ -562,7 +562,7 @@ describe('Frontend Routing', function () {
it('should redirect to last page if page too high', function (done) {
request.get('/author/ghost-owner/page/4/')
.expect('Location', '/author/ghost-owner/page/3/')
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(302)
.end(doEnd(done));
});
@ -570,7 +570,7 @@ describe('Frontend Routing', function () {
it('should redirect to first page if page too low', function (done) {
request.get('/author/ghost-owner/page/0/')
.expect('Location', '/author/ghost-owner/')
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(302)
.end(doEnd(done));
});
@ -587,7 +587,7 @@ describe('Frontend Routing', function () {
it('should respond with xml', function (done) {
request.get('/author/ghost-owner/rss/')
.expect('Content-Type', /xml/)
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(200)
.end(doEnd(done));
});
@ -595,7 +595,7 @@ describe('Frontend Routing', function () {
it('should redirect page 1', function (done) {
request.get('/author/ghost-owner/rss/1/')
.expect('Location', '/author/ghost-owner/rss/')
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
// TODO: This should probably be a 301?
.expect(302)
.end(doEnd(done));
@ -604,7 +604,7 @@ describe('Frontend Routing', function () {
it('should redirect to last page if page too high', function (done) {
request.get('/author/ghost-owner/rss/2/')
.expect('Location', '/author/ghost-owner/rss/1/')
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(302)
.end(doEnd(done));
});
@ -612,7 +612,7 @@ describe('Frontend Routing', function () {
it('should redirect to first page if page too low', function (done) {
request.get('/author/ghost-owner/rss/0/')
.expect('Location', '/author/ghost-owner/rss/')
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(302)
.end(doEnd(done));
});
@ -630,14 +630,14 @@ describe('Frontend Routing', function () {
it('should redirect to editor', function (done) {
request.get('/author/ghost-owner/edit/')
.expect('Location', '/ghost/team/ghost-owner/')
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(302)
.end(doEnd(done));
});
it('should 404 for something that isn\'t edit', function (done) {
request.get('/author/ghost-owner/notedit/')
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.expect(/Page not found/)
.end(doEnd(done));
@ -663,7 +663,7 @@ describe('Frontend Routing', function () {
it('should 404 for /tag/ route', function (done) {
request.get('/tag/')
.expect('Cache-Control', testUtils.cacheRules['private'])
.expect('Cache-Control', testUtils.cacheRules.private)
.expect(404)
.expect(/Page not found/)
.end(doEnd(done));
@ -680,7 +680,7 @@ describe('Frontend Routing', function () {
it('should respond with html', function (done) {
request.get('/tag/injection/page/2/')
.expect('Content-Type', /html/)
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(200)
.end(doEnd(done));
});
@ -688,7 +688,7 @@ describe('Frontend Routing', function () {
it('should redirect page 1', function (done) {
request.get('/tag/injection/page/1/')
.expect('Location', '/tag/injection/')
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
// TODO: This should probably be a 301?
.expect(302)
.end(doEnd(done));
@ -697,7 +697,7 @@ describe('Frontend Routing', function () {
it('should redirect to last page if page too high', function (done) {
request.get('/tag/injection/page/4/')
.expect('Location', '/tag/injection/page/3/')
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(302)
.end(doEnd(done));
});
@ -705,7 +705,7 @@ describe('Frontend Routing', function () {
it('should redirect to first page if page too low', function (done) {
request.get('/tag/injection/page/0/')
.expect('Location', '/tag/injection/')
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(302)
.end(doEnd(done));
});
@ -722,7 +722,7 @@ describe('Frontend Routing', function () {
it('should respond with xml', function (done) {
request.get('/tag/getting-started/rss/')
.expect('Content-Type', /xml/)
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(200)
.end(doEnd(done));
});
@ -730,7 +730,7 @@ describe('Frontend Routing', function () {
it('should redirect page 1', function (done) {
request.get('/tag/getting-started/rss/1/')
.expect('Location', '/tag/getting-started/rss/')
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
// TODO: This should probably be a 301?
.expect(302)
.end(doEnd(done));
@ -739,7 +739,7 @@ describe('Frontend Routing', function () {
it('should redirect to last page if page too high', function (done) {
request.get('/tag/getting-started/rss/2/')
.expect('Location', '/tag/getting-started/rss/1/')
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(302)
.end(doEnd(done));
});
@ -747,7 +747,7 @@ describe('Frontend Routing', function () {
it('should redirect to first page if page too low', function (done) {
request.get('/tag/getting-started/rss/0/')
.expect('Location', '/tag/getting-started/rss/')
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(302)
.end(doEnd(done));
});
@ -978,7 +978,7 @@ describe('Frontend Routing', function () {
it('should serve RSS with date permalink', function (done) {
request.get('/rss/')
.expect('Content-Type', 'text/xml; charset=utf-8')
.expect('Cache-Control', testUtils.cacheRules['public'])
.expect('Cache-Control', testUtils.cacheRules.public)
.expect(200)
.end(function (err, res) {
if (err) {

View File

@ -26,7 +26,7 @@ describe('Error handling', function () {
errors.throwError(toThrow);
};
runThrowError.should['throw']('test1');
runThrowError.should.throw('test1');
});
it('throws error strings', function () {
@ -35,7 +35,7 @@ describe('Error handling', function () {
errors.throwError(toThrow);
};
runThrowError.should['throw']('test2');
runThrowError.should.throw('test2');
});
it('throws error even if nothing passed', function () {
@ -43,7 +43,7 @@ describe('Error handling', function () {
errors.throwError();
};
runThrowError.should['throw']('An error occurred');
runThrowError.should.throw('An error occurred');
});
});

View File

@ -50,25 +50,25 @@ describe('Middleware: cacheControl', function () {
});
it('will not get confused between serving public and private', function (done) {
var public = middleware.cacheControl('public'),
private = middleware.cacheControl('private');
var publicCC = middleware.cacheControl('public'),
privateCC = middleware.cacheControl('private');
public(null, res, function () {
publicCC(null, res, function () {
res.set.calledOnce.should.be.true;
res.set.calledWith({'Cache-Control': 'public, max-age=0'});
private(null, res, function () {
privateCC(null, res, function () {
res.set.calledTwice.should.be.true;
res.set.calledWith({
'Cache-Control':
'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0'
});
public(null, res, function () {
publicCC(null, res, function () {
res.set.calledThrice.should.be.true;
res.set.calledWith({'Cache-Control': 'public, max-age=0'});
private(null, res, function () {
privateCC(null, res, function () {
res.set.calledWith({
'Cache-Control': 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0'
});

View File

@ -142,16 +142,16 @@ describe('Permissions', function () {
});
it('should return unchanged object for post with public context', function (done) {
var public = {context: {}};
var publicContext = {context: {}};
permissions.applyPublicRules('posts', 'browse', _.cloneDeep(public)).then(function (result) {
result.should.not.eql(public);
permissions.applyPublicRules('posts', 'browse', _.cloneDeep(publicContext)).then(function (result) {
result.should.not.eql(publicContext);
result.should.eql({
context: {},
status: 'published'
});
return permissions.applyPublicRules('posts', 'browse', _.extend({}, _.cloneDeep(public), {status: 'published'}));
return permissions.applyPublicRules('posts', 'browse', _.extend({}, _.cloneDeep(publicContext), {status: 'published'}));
}).then(function (result) {
result.should.eql({
context: {},
@ -243,16 +243,16 @@ describe('Permissions', function () {
});
it('should return unchanged object for user with public context', function (done) {
var public = {context: {}};
var publicContext = {context: {}};
permissions.applyPublicRules('users', 'browse', _.cloneDeep(public)).then(function (result) {
result.should.not.eql(public);
permissions.applyPublicRules('users', 'browse', _.cloneDeep(publicContext)).then(function (result) {
result.should.not.eql(publicContext);
result.should.eql({
context: {},
status: 'active'
});
return permissions.applyPublicRules('users', 'browse', _.extend({}, _.cloneDeep(public), {status: 'active'}));
return permissions.applyPublicRules('users', 'browse', _.extend({}, _.cloneDeep(publicContext), {status: 'active'}));
}).then(function (result) {
result.should.eql({
context: {},

View File

@ -82,7 +82,7 @@
"grunt-contrib-watch": "0.6.1",
"grunt-docker": "0.0.10",
"grunt-express-server": "0.5.1",
"grunt-jscs": "1.8.0",
"grunt-jscs": "2.1.0",
"grunt-mocha-cli": "1.13.0",
"grunt-mocha-istanbul": "2.4.0",
"grunt-shell": "1.1.2",