From b82f1304542c1ab148bf8ce1f22dfa231682b6dc Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Tue, 6 Dec 2016 14:44:15 -0500 Subject: [PATCH] Adds a new closedAt time for assets to prevent new comments from being created --- models/asset.js | 15 +++++++ models/setting.js | 10 +++++ routes/api/comments/index.js | 15 ++++++- tests/routes/api/comments/index.js | 63 ++++++++++++++++++++++++++---- 4 files changed, 95 insertions(+), 8 deletions(-) diff --git a/models/asset.js b/models/asset.js index a0619576f..7b0717674 100644 --- a/models/asset.js +++ b/models/asset.js @@ -29,6 +29,14 @@ const AssetSchema = new Schema({ type: Schema.Types.Mixed, default: null }, + closedAt: { + type: Date, + default: null + }, + closedMessage: { + type: String, + default: null + }, title: String, description: String, image: String, @@ -60,6 +68,13 @@ AssetSchema.index({ background: true }); +/** + * Returns true if the asset is closed, false else. + */ +AssetSchema.virtual('isClosed').get(function() { + return this.closedAt && this.closedAt.getTime() <= new Date().getTime(); +}); + /** * Finds an asset by its id. * @param {String} id identifier of the asset (uuid). diff --git a/models/setting.js b/models/setting.js index 22b2b103f..5d71b8c97 100644 --- a/models/setting.js +++ b/models/setting.js @@ -28,6 +28,16 @@ const SettingSchema = new Schema({ type: String, default: '' }, + closedTimeout: { + type: Number, + + // Two weeks default expiry. + default: 60 * 60 * 24 * 7 * 2 + }, + closedMessage: { + type: String, + default: '' + }, wordlist: [String] }, { timestamps: { diff --git a/routes/api/comments/index.js b/routes/api/comments/index.js index b82c1faf3..748f64f5b 100644 --- a/routes/api/comments/index.js +++ b/routes/api/comments/index.js @@ -80,7 +80,20 @@ router.post('/', wordlist.filter('body'), (req, res, next) => { status = Promise.resolve('rejected'); } else { status = Asset - .rectifySettings(Asset.findById(asset_id)) + .rectifySettings(Asset.findById(asset_id).then((asset) => { + if (!asset) { + return Promise.reject(new Error('asset referenced is not found')); + } + + // Check to see if the asset has closed commenting... + if (asset.isClosed) { + + // They have, ensure that we send back an error. + return Promise.reject(new Error(`asset has commenting closed because: ${asset.closedMessage}`)); + } + + return asset; + })) // Return `premod` if pre-moderation is enabled and an empty "new" status // in the event that it is not in pre-moderation mode. diff --git a/tests/routes/api/comments/index.js b/tests/routes/api/comments/index.js index bf7a06ff6..70912eac7 100644 --- a/tests/routes/api/comments/index.js +++ b/tests/routes/api/comments/index.js @@ -19,6 +19,14 @@ const settings = {id: '1', moderation: 'pre'}; describe('/api/v1/comments', () => { + // Ensure that the settings are always available. + beforeEach(() => Promise.all([ + Setting.init(settings), + wordlist.insert([ + 'bad words' + ]) + ])); + describe('#get', () => { const comments = [{ body: 'comment 10', @@ -75,11 +83,7 @@ describe('/api/v1/comments', () => { return Action.create(actions); }), - User.createLocalUsers(users), - wordlist.insert([ - 'bad words' - ]), - Setting.init(settings) + User.createLocalUsers(users) ]); }); @@ -142,11 +146,19 @@ describe('/api/v1/comments', () => { describe('#post', () => { + let asset_id; + + beforeEach(() => Asset.findOrCreateByUrl('https://coralproject.net/section/article-is-the-best').then((asset) => { + + // Update the asset id. + asset_id = asset.id; + })); + it('should create a comment', () => { return chai.request(app) .post('/api/v1/comments') .set(passport.inject({roles: []})) - .send({'body': 'Something body.', 'author_id': '123', 'asset_id': '1', 'parent_id': ''}) + .send({'body': 'Something body.', 'author_id': '123', 'asset_id': asset_id, 'parent_id': ''}) .then((res) => { expect(res).to.have.status(201); expect(res.body).to.have.property('id'); @@ -157,7 +169,7 @@ describe('/api/v1/comments', () => { return chai.request(app) .post('/api/v1/comments') .set(passport.inject({roles: []})) - .send({'body': 'bad words are the baddest', 'author_id': '123', 'asset_id': '1', 'parent_id': ''}) + .send({'body': 'bad words are the baddest', 'author_id': '123', 'asset_id': asset_id, 'parent_id': ''}) .then((res) => { expect(res).to.have.status(201); expect(res.body).to.have.property('id'); @@ -188,6 +200,43 @@ describe('/api/v1/comments', () => { expect(res.body.status[0]).to.have.property('type', 'premod'); }); }); + + it('shouldn\'t create a comment when the asset has expired commenting', () => { + return Asset.create({ + closedAt: new Date().setDate(0), + closedMessage: 'tests said expired!' + }) + .then((asset) => { + return chai.request(app) + .post('/api/v1/comments') + .set(passport.inject({roles: []})) + .send({'body': 'Something body.', 'author_id': '123', 'asset_id': asset.id, 'parent_id': ''}); + }) + .then((res) => { + expect(res).to.have.status(500); + }) + .catch((err) => { + expect(err.response.body).to.not.be.null; + expect(err.response.body).to.have.property('message'); + expect(err.response.body.message).to.contain('tests said expired!'); + }); + }); + + it('should create a comment when the asset has not expired yet', () => { + return Asset.create({ + closedAt: new Date().setDate(32), + closedMessage: 'tests said expired!' + }) + .then((asset) => { + return chai.request(app) + .post('/api/v1/comments') + .set(passport.inject({roles: []})) + .send({'body': 'Something body.', 'author_id': '123', 'asset_id': asset.id, 'parent_id': ''}); + }) + .then((res) => { + expect(res).to.have.status(201); + }); + }); }); });