0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-20 22:42:53 -05:00

Merge pull request #3312 from ErisDS/issue-2739-2

Wire permmissions for notifications, mail and tags
This commit is contained in:
Hannah Wolfe 2014-07-17 18:04:38 +01:00
commit 487844122d
14 changed files with 265 additions and 190 deletions

View file

@ -55,7 +55,7 @@ authentication = {
}] }]
}; };
return mail.send(payload); return mail.send(payload, {context: {internal: true}});
}).then(function () { }).then(function () {
return when.resolve({passwordreset: [{message: 'Check your email for further instructions.'}]}); return when.resolve({passwordreset: [{message: 'Check your email for further instructions.'}]});
}).otherwise(function (error) { }).otherwise(function (error) {
@ -197,7 +197,7 @@ authentication = {
}] }]
}; };
return mail.send(payload).otherwise(function (error) { return mail.send(payload, {context: {internal: true}}).otherwise(function (error) {
errors.logError( errors.logError(
error.message, error.message,
"Unable to send welcome email, your blog will continue to function.", "Unable to send welcome email, your blog will continue to function.",

View file

@ -2,6 +2,7 @@
// API for sending Mail // API for sending Mail
var when = require('when'), var when = require('when'),
config = require('../config'), config = require('../config'),
canThis = require('../permissions').canThis,
errors = require('../errors'), errors = require('../errors'),
mail; mail;
@ -21,23 +22,27 @@ mail = {
* @param {Mail} object details of the email to send * @param {Mail} object details of the email to send
* @returns {Promise} * @returns {Promise}
*/ */
send: function (object) { send: function (object, options) {
var mailer = require('../mail'); var mailer = require('../mail');
// TODO: permissions return canThis(options.context).send.mail().then(function () {
return mailer.send(object.mail[0].message) return mailer.send(object.mail[0].message)
.then(function (data) { .then(function (data) {
delete object.mail[0].options; delete object.mail[0].options;
// Sendmail returns extra details we don't need and that don't convert to JSON // Sendmail returns extra details we don't need and that don't convert to JSON
delete object.mail[0].message.transport; delete object.mail[0].message.transport;
object.mail[0].status = { object.mail[0].status = {
message: data.message message: data.message
}; };
return object; return object;
}) })
.otherwise(function (error) { .otherwise(function (error) {
return when.reject(new errors.EmailError(error.message)); return when.reject(new errors.EmailError(error.message));
}); });
}, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to send mail.'));
});
}, },
/** /**
@ -48,7 +53,7 @@ mail = {
* @param {Object} required property 'to' which contains the recipient address * @param {Object} required property 'to' which contains the recipient address
* @returns {Promise} * @returns {Promise}
*/ */
sendTest: function (object) { sendTest: function (object, options) {
var html = '<p><strong>Hello there!</strong></p>' + var html = '<p><strong>Hello there!</strong></p>' +
'<p>Excellent!' + '<p>Excellent!' +
' You\'ve successfully setup your email config for your Ghost blog over on ' + config().url + '</p>' + ' You\'ve successfully setup your email config for your Ghost blog over on ' + config().url + '</p>' +
@ -65,7 +70,7 @@ mail = {
} }
}]}; }]};
return mail.send(payload); return mail.send(payload, options);
} }
}; };

View file

@ -2,6 +2,7 @@
// RESTful API for creating notifications // RESTful API for creating notifications
var when = require('when'), var when = require('when'),
_ = require('lodash'), _ = require('lodash'),
canThis = require('../permissions').canThis,
errors = require('../errors'), errors = require('../errors'),
utils = require('./utils'), utils = require('./utils'),
@ -23,8 +24,56 @@ notifications = {
* Fetch all notifications * Fetch all notifications
* @returns {Promise(Notifications)} * @returns {Promise(Notifications)}
*/ */
browse: function browse() { browse: function browse(options) {
return when({ 'notifications': notificationsStore }); return canThis(options.context).browse.notification().then(function () {
return when({ 'notifications': notificationsStore });
}, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to browse notifications.'));
});
},
/**
* ### Add
*
*
* **takes:** a notification object of the form
* ```
* msg = { notifications: [{
* type: 'error', // this can be 'error', 'success', 'warn' and 'info'
* message: 'This is an error', // A string. Should fit in one line.
* location: 'bottom', // A string where this notification should appear. can be 'bottom' or 'top'
* dismissible: true // A Boolean. Whether the notification is dismissible or not.
* }] };
* ```
*/
add: function add(object, options) {
var defaults = {
dismissible: true,
location: 'bottom',
status: 'persistent'
},
addedNotifications = [];
return canThis(options.context).add.notification().then(function () {
return utils.checkObject(object, 'notifications').then(function (checkedNotificationData) {
_.each(checkedNotificationData.notifications, function (notification) {
notificationCounter = notificationCounter + 1;
notification = _.assign(defaults, notification, {
id: notificationCounter
//status: 'persistent'
});
notificationsStore.push(notification);
addedNotifications.push(notification);
});
return when({ notifications: addedNotifications});
});
}, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to add notifications.'));
});
}, },
/** /**
@ -35,24 +84,28 @@ notifications = {
* @returns {Promise(Notifications)} * @returns {Promise(Notifications)}
*/ */
destroy: function destroy(options) { destroy: function destroy(options) {
var notification = _.find(notificationsStore, function (element) { return canThis(options.context).destroy.notification().then(function () {
return element.id === parseInt(options.id, 10); var notification = _.find(notificationsStore, function (element) {
return element.id === parseInt(options.id, 10);
});
if (notification && !notification.dismissible) {
return when.reject(
new errors.NoPermissionError('You do not have permission to dismiss this notification.')
);
}
if (!notification) {
return when.reject(new errors.NotFoundError('Notification does not exist.'));
}
notificationsStore = _.reject(notificationsStore, function (element) {
return element.id === parseInt(options.id, 10);
});
return when({notifications: [notification]});
}, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to destroy notifications.'));
}); });
if (notification && !notification.dismissible) {
return when.reject(
new errors.NoPermissionError('You do not have permission to dismiss this notification.')
);
}
if (!notification) {
return when.reject(new errors.NotFoundError('Notification does not exist.'));
}
notificationsStore = _.reject(notificationsStore, function (element) {
return element.id === parseInt(options.id, 10);
});
return when({notifications: [notification]});
}, },
/** /**
@ -62,50 +115,13 @@ notifications = {
* @private Not exposed over HTTP * @private Not exposed over HTTP
* @returns {Promise} * @returns {Promise}
*/ */
destroyAll: function destroyAll() { destroyAll: function destroyAll(options) {
notificationsStore = []; return canThis(options.context).destroy.notification().then(function () {
notificationCounter = 0; notificationsStore = [];
return when(notificationsStore); notificationCounter = 0;
}, return when(notificationsStore);
}, function () {
/** return when.reject(new errors.NoPermissionError('You do not have permission to destroy notifications.'));
* ### Add
*
*
* **takes:** a notification object of the form
* ```
* msg = { notifications: [{
* type: 'error', // this can be 'error', 'success', 'warn' and 'info'
* message: 'This is an error', // A string. Should fit in one line.
* location: 'bottom', // A string where this notification should appear. can be 'bottom' or 'top'
* dismissible: true // A Boolean. Whether the notification is dismissible or not.
* }] };
* ```
*/
add: function add(object) {
var defaults = {
dismissible: true,
location: 'bottom',
status: 'persistent'
},
addedNotifications = [];
return utils.checkObject(object, 'notifications').then(function (checkedNotificationData) {
_.each(checkedNotificationData.notifications, function (notification) {
notificationCounter = notificationCounter + 1;
notification = _.assign(defaults, notification, {
id: notificationCounter
//status: 'persistent'
});
notificationsStore.push(notification);
addedNotifications.push(notification);
});
return when({ notifications: addedNotifications});
}); });
} }
}; };

View file

@ -1,6 +1,9 @@
// # Tag API // # Tag API
// RESTful API for the Tag resource // RESTful API for the Tag resource
var dataProvider = require('../models'), var when = require('when'),
canThis = require('../permissions').canThis,
dataProvider = require('../models'),
errors = require('../errors'),
tags; tags;
/** /**
@ -15,8 +18,13 @@ tags = {
* @returns {Promise(Tags)} * @returns {Promise(Tags)}
*/ */
browse: function browse(options) { browse: function browse(options) {
return dataProvider.Tag.findAll(options).then(function (result) { return canThis(options.context).browse.tag().then(function () {
return { tags: result.toJSON() }; return dataProvider.Tag.findAll(options).then(function (result) {
return { tags: result.toJSON() };
});
}, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to browse tags.'));
}); });
} }
}; };

View file

@ -192,7 +192,7 @@ users = {
options: {} options: {}
}] }]
}; };
return mail.send(payload).then(function () { return mail.send(payload, {context: {internal: true}}).then(function () {
// If status was invited-pending and sending the invitation succeeded, set status to invited. // If status was invited-pending and sending the invitation succeeded, set status to invited.
if (user.status === 'invited-pending') { if (user.status === 'invited-pending') {
return dataProvider.User.edit({status: 'invited'}, {id: user.id}); return dataProvider.User.edit({status: 'invited'}, {id: user.id});
@ -211,7 +211,7 @@ users = {
return when.reject(error); return when.reject(error);
}); });
}, function () { }, function () {
return when.reject(new errors.NoPermissionError('You do not have permission to add a users.')); return when.reject(new errors.NoPermissionError('You do not have permission to add a user.'));
}); });
}, },

View file

@ -43,7 +43,7 @@ adminControllers = {
return api.notifications.browse().then(function (results) { return api.notifications.browse().then(function (results) {
if (!_.some(results.notifications, { message: notification.message })) { if (!_.some(results.notifications, { message: notification.message })) {
return api.notifications.add({ notifications: [notification] }); return api.notifications.add({ notifications: [notification] }, {context: {internal: true}});
} }
}); });
}).finally(function () { }).finally(function () {

View file

@ -48,7 +48,7 @@ function doFirstRun() {
return api.notifications.add({ notifications: [{ return api.notifications.add({ notifications: [{
type: 'info', type: 'info',
message: firstRunMessage.join(' ') message: firstRunMessage.join(' ')
}] }); }] }, {context: {internal: true}});
} }
function initDbHashAndFirstRun() { function initDbHashAndFirstRun() {
@ -176,7 +176,7 @@ function initNotifications() {
"It is recommended that you explicitly configure an e-mail service,", "It is recommended that you explicitly configure an e-mail service,",
"See <a href=\"http://docs.ghost.org/mail\">http://docs.ghost.org/mail</a> for instructions" "See <a href=\"http://docs.ghost.org/mail\">http://docs.ghost.org/mail</a> for instructions"
].join(' ') ].join(' ')
}] }); }] }, {context: {internal: true}});
} }
if (mailer.state && mailer.state.emailDisabled) { if (mailer.state && mailer.state.emailDisabled) {
api.notifications.add({ notifications: [{ api.notifications.add({ notifications: [{
@ -185,7 +185,7 @@ function initNotifications() {
"Ghost is currently unable to send e-mail.", "Ghost is currently unable to send e-mail.",
"See <a href=\"http://docs.ghost.org/mail\">http://docs.ghost.org/mail</a> for instructions" "See <a href=\"http://docs.ghost.org/mail\">http://docs.ghost.org/mail</a> for instructions"
].join(' ') ].join(' ')
}] }); }] }, {context: {internal: true}});
} }
} }

View file

@ -299,10 +299,6 @@ setupMiddleware = function (server) {
// local data // local data
expressServer.use(ghostLocals); expressServer.use(ghostLocals);
// So on every request we actually clean out redundant passive notifications from the server side
// ToDo: Remove when ember handles passive notifications.
expressServer.use(middleware.cleanNotifications);
// ### Routing // ### Routing
// Set up API routes // Set up API routes
expressServer.use(subdir + routes.apiBaseUri, routes.api(middleware)); expressServer.use(subdir + routes.apiBaseUri, routes.api(middleware));

View file

@ -79,23 +79,6 @@ var middleware = {
next(); next();
}, },
// While we're here, let's clean up on aisle 5
// That being ghost.notifications, and let's remove the passives from there
// plus the local messages, as they have already been added at this point
// otherwise they'd appear one too many times
// ToDo: Remove once ember handles passive notifications.
cleanNotifications: function (req, res, next) {
/*jslint unparam:true*/
api.notifications.browse().then(function (notifications) {
_.each(notifications.notifications, function (notification) {
if (notification.status === 'passive') {
api.notifications.destroy(notification);
}
});
next();
});
},
// ### CacheControl Middleware // ### CacheControl Middleware
// provide sensible cache control headers // provide sensible cache control headers
cacheControl: function (options) { cacheControl: function (options) {

View file

@ -36,6 +36,7 @@ describe('DB API', function () {
}); });
it('delete all content', function (done) { it('delete all content', function (done) {
var options = {context: {user: 1}};
permissions.init().then(function () { permissions.init().then(function () {
return dbAPI.deleteAllContent({context: {user: 1}}); return dbAPI.deleteAllContent({context: {user: 1}});
}).then(function (result) { }).then(function (result) {
@ -43,13 +44,13 @@ describe('DB API', function () {
result.db.should.be.instanceof(Array); result.db.should.be.instanceof(Array);
result.db.should.be.empty; result.db.should.be.empty;
}).then(function () { }).then(function () {
return TagsAPI.browse().then(function (results) { return TagsAPI.browse(options).then(function (results) {
should.exist(results); should.exist(results);
should.exist(results.tags); should.exist(results.tags);
results.tags.length.should.equal(0); results.tags.length.should.equal(0);
}); });
}).then(function () { }).then(function () {
return PostAPI.browse().then(function (results) { return PostAPI.browse(options).then(function (results) {
should.exist(results); should.exist(results);
results.posts.length.should.equal(0); results.posts.length.should.equal(0);
done(); done();
@ -102,17 +103,17 @@ describe('DB API', function () {
it('import content is denied', function (done) { it('import content is denied', function (done) {
permissions.init().then(function () { permissions.init().then(function () {
return dbAPI.importContent({context: {user: 2}}); return dbAPI.importContent({context: {user: 2}});
}).then(function (result){ }).then(function (result) {
done(new Error("Import content is not denied for editor.")); done(new Error("Import content is not denied for editor."));
}, function (error) { }, function (error) {
error.type.should.eql('NoPermissionError'); error.type.should.eql('NoPermissionError');
return dbAPI.importContent({context: {user: 3}}); return dbAPI.importContent({context: {user: 3}});
}).then(function (result){ }).then(function (result) {
done(new Error("Import content is not denied for author.")); done(new Error("Import content is not denied for author."));
}, function (error) { }, function (error) {
error.type.should.eql('NoPermissionError'); error.type.should.eql('NoPermissionError');
return dbAPI.importContent(); return dbAPI.importContent();
}).then(function (result){ }).then(function (result) {
done(new Error("Import content is not denied without authentication.")); done(new Error("Import content is not denied without authentication."));
}).catch(function (error) { }).catch(function (error) {
error.type.should.eql('NoPermissionError'); error.type.should.eql('NoPermissionError');

View file

@ -3,6 +3,7 @@ var testUtils = require('../../utils'),
should = require('should'), should = require('should'),
// Stuff we are testing // Stuff we are testing
permissions = require('../../../server/permissions'),
MailAPI = require('../../../server/api/mail'); MailAPI = require('../../../server/api/mail');
@ -22,11 +23,11 @@ describe('Mail API', function () {
testUtils.clearData() testUtils.clearData()
.then(function () { .then(function () {
return testUtils.initData(); return testUtils.initData();
}) }).then(function () {
.then(function () {
return testUtils.insertDefaultFixtures(); return testUtils.insertDefaultFixtures();
}) }).then(function () {
.then(function () { return permissions.init();
}).then(function () {
done(); done();
}).catch(done); }).catch(done);
}); });
@ -40,7 +41,8 @@ describe('Mail API', function () {
it('return correct failure message', function (done) { it('return correct failure message', function (done) {
MailAPI.send(mailData).then(function (response) { MailAPI.send(mailData, {context: {internal: true}}).then(function (response) {
/*jshint unused:false */
done(); done();
}).catch(function (error) { }).catch(function (error) {
error.type.should.eql('EmailError'); error.type.should.eql('EmailError');

View file

@ -3,6 +3,7 @@ var testUtils = require('../../utils'),
should = require('should'), should = require('should'),
// Stuff we are testing // Stuff we are testing
permissions = require('../../../server/permissions'),
DataGenerator = require('../../utils/fixtures/data-generator'), DataGenerator = require('../../utils/fixtures/data-generator'),
NotificationsAPI = require('../../../server/api/notifications'); NotificationsAPI = require('../../../server/api/notifications');
@ -18,8 +19,9 @@ describe('Notifications API', function () {
testUtils.initData() testUtils.initData()
.then(function () { .then(function () {
return testUtils.insertDefaultFixtures(); return testUtils.insertDefaultFixtures();
}) }).then(function () {
.then(function () { return permissions.init();
}).then(function () {
done(); done();
}).catch(done); }).catch(done);
}); });
@ -30,29 +32,13 @@ describe('Notifications API', function () {
}).catch(done); }).catch(done);
}); });
it('can browse', function (done) { it('can add, adds defaults (internal)', function (done) {
var msg = {
type: 'error', // this can be 'error', 'success', 'warn' and 'info'
message: 'This is an error', // A string. Should fit in one line.
};
NotificationsAPI.add({ notifications: [msg] }).then(function (notification) {
NotificationsAPI.browse().then(function (results) {
should.exist(results);
should.exist(results.notifications);
results.notifications.length.should.be.above(0);
testUtils.API.checkResponse(results.notifications[0], 'notification');
done();
}).catch(done);
});
});
it('can add, adds defaults', function (done) {
var msg = { var msg = {
type: 'info', type: 'info',
message: 'Hello, this is dog' message: 'Hello, this is dog'
}; };
NotificationsAPI.add({ notifications: [msg] }).then(function (result) { NotificationsAPI.add({ notifications: [msg] }, {context: {internal: true}}).then(function (result) {
var notification; var notification;
should.exist(result); should.exist(result);
@ -67,14 +53,35 @@ describe('Notifications API', function () {
}).catch(done); }).catch(done);
}); });
it('can add, adds id and status', function (done) { it('can add, adds defaults (owner)', function (done) {
var msg = {
type: 'info',
message: 'Hello, this is dog'
};
NotificationsAPI.add({ notifications: [msg] }, {context: {user: 1}}).then(function (result) {
var notification;
should.exist(result);
should.exist(result.notifications);
notification = result.notifications[0];
notification.dismissible.should.be.true;
should.exist(notification.location);
notification.location.should.equal('bottom');
done();
}).catch(done);
});
it('can add, adds id and status (internal)', function (done) {
var msg = { var msg = {
type: 'info', type: 'info',
message: 'Hello, this is dog', message: 'Hello, this is dog',
id: 99 id: 99
}; };
NotificationsAPI.add({ notifications: [msg] }).then(function (result) { NotificationsAPI.add({ notifications: [msg] }, {context: {internal: true}}).then(function (result) {
var notification; var notification;
should.exist(result); should.exist(result);
@ -84,22 +91,56 @@ describe('Notifications API', function () {
notification.id.should.be.a.Number; notification.id.should.be.a.Number;
notification.id.should.not.equal(99); notification.id.should.not.equal(99);
should.exist(notification.status); should.exist(notification.status);
notification.status.should.equal('persistent') notification.status.should.equal('persistent');
done(); done();
}).catch(done); }).catch(done);
}); });
it('can destroy', function (done) { it('can browse (internal)', function (done) {
var msg = {
type: 'error', // this can be 'error', 'success', 'warn' and 'info'
message: 'This is an error' // A string. Should fit in one line.
};
NotificationsAPI.add({ notifications: [msg] }, {context: {internal: true}}).then(function (notification) {
NotificationsAPI.browse({context: {internal: true}}).then(function (results) {
should.exist(results);
should.exist(results.notifications);
results.notifications.length.should.be.above(0);
testUtils.API.checkResponse(results.notifications[0], 'notification');
done();
}).catch(done);
});
});
it('can browse (owner)', function (done) {
var msg = {
type: 'error', // this can be 'error', 'success', 'warn' and 'info'
message: 'This is an error' // A string. Should fit in one line.
};
NotificationsAPI.add({ notifications: [msg] }, {context: {internal: true}}).then(function (notification) {
NotificationsAPI.browse({context: {user: 1}}).then(function (results) {
should.exist(results);
should.exist(results.notifications);
results.notifications.length.should.be.above(0);
testUtils.API.checkResponse(results.notifications[0], 'notification');
done();
}).catch(done);
});
});
it('can destroy (internal)', function (done) {
var msg = { var msg = {
type: 'error', type: 'error',
message: 'Goodbye, cruel world!' message: 'Goodbye, cruel world!'
}; };
NotificationsAPI.add({ notifications: [msg] }).then(function (result) { NotificationsAPI.add({ notifications: [msg] }, {context: {internal: true}}).then(function (result) {
var notification = result.notifications[0]; var notification = result.notifications[0];
NotificationsAPI.destroy({ id: notification.id }).then(function (result) { NotificationsAPI.destroy({ id: notification.id, context: {internal: true}}).then(function (result) {
should.exist(result); should.exist(result);
should.exist(result.notifications); should.exist(result.notifications);
result.notifications[0].id.should.equal(notification.id); result.notifications[0].id.should.equal(notification.id);
@ -108,4 +149,23 @@ describe('Notifications API', function () {
}).catch(done); }).catch(done);
}); });
}); });
it('can destroy (owner)', function (done) {
var msg = {
type: 'error',
message: 'Goodbye, cruel world!'
};
NotificationsAPI.add({ notifications: [msg] }, {context: {internal: true}}).then(function (result) {
var notification = result.notifications[0];
NotificationsAPI.destroy({ id: notification.id, context: {user: 1}}).then(function (result) {
should.exist(result);
should.exist(result.notifications);
result.notifications[0].id.should.equal(notification.id);
done();
}).catch(done);
});
});
}); });

View file

@ -3,6 +3,7 @@ var testUtils = require('../../utils'),
should = require('should'), should = require('should'),
// Stuff we are testing // Stuff we are testing
permissions = require('../../../server/permissions'),
DataGenerator = require('../../utils/fixtures/data-generator'), DataGenerator = require('../../utils/fixtures/data-generator'),
TagsAPI = require('../../../server/api/tags'); TagsAPI = require('../../../server/api/tags');
@ -18,8 +19,13 @@ describe('Tags API', function () {
testUtils.initData() testUtils.initData()
.then(function () { .then(function () {
return testUtils.insertDefaultFixtures(); return testUtils.insertDefaultFixtures();
}) }).then(function () {
.then(function () { return testUtils.insertEditorUser();
}).then(function () {
return testUtils.insertAuthorUser();
}).then(function () {
return permissions.init();
}).then(function () {
done(); done();
}).catch(done); }).catch(done);
}); });
@ -30,8 +36,44 @@ describe('Tags API', function () {
}).catch(done); }).catch(done);
}); });
it('can browse', function (done) { it('can browse (internal)', function (done) {
TagsAPI.browse().then(function (results) { TagsAPI.browse({context: {internal: true}}).then(function (results) {
should.exist(results);
should.exist(results.tags);
results.tags.length.should.be.above(0);
testUtils.API.checkResponse(results.tags[0], 'tag');
results.tags[0].created_at.should.be.an.instanceof(Date);
done();
}).catch(done);
});
it('can browse (admin)', function (done) {
TagsAPI.browse({context: {user: 1}}).then(function (results) {
should.exist(results);
should.exist(results.tags);
results.tags.length.should.be.above(0);
testUtils.API.checkResponse(results.tags[0], 'tag');
results.tags[0].created_at.should.be.an.instanceof(Date);
done();
}).catch(done);
});
it('can browse (editor)', function (done) {
TagsAPI.browse({context: {user: 2}}).then(function (results) {
should.exist(results);
should.exist(results.tags);
results.tags.length.should.be.above(0);
testUtils.API.checkResponse(results.tags[0], 'tag');
results.tags[0].created_at.should.be.an.instanceof(Date);
done();
}).catch(done);
});
it('can browse (author)', function (done) {
TagsAPI.browse({context: {user: 3}}).then(function (results) {
should.exist(results); should.exist(results);
should.exist(results.tags); should.exist(results.tags);
results.tags.length.should.be.above(0); results.tags.length.should.be.above(0);

View file

@ -39,44 +39,6 @@ describe('Middleware', function () {
// }); // });
// }); // });
describe('cleanNotifications', function () {
beforeEach(function (done) {
api.notifications.add({ notifications: [{
id: 0,
status: 'passive',
message: 'passive-one'
}] }).then(function () {
return api.notifications.add({ notifications: [{
id: 1,
status: 'passive',
message: 'passive-two'
}] });
}).then(function () {
return api.notifications.add({ notifications: [{
id: 2,
status: 'aggressive',
message: 'aggressive'
}] });
}).then(function () {
done();
}).catch(done);
});
it('should clean all passive messages', function (done) {
middleware.cleanNotifications(null, null, function () {
api.notifications.browse().then(function (notifications) {
should(notifications.notifications.length).eql(1);
var passiveMsgs = _.filter(notifications.notifications, function (notification) {
return notification.status === 'passive';
});
assert.equal(passiveMsgs.length, 0);
done();
}).catch(done);
});
});
});
describe('cacheControl', function () { describe('cacheControl', function () {
var res; var res;