diff --git a/bin/cli-serve b/bin/cli-serve index dd682f5ad..a6790c6a0 100755 --- a/bin/cli-serve +++ b/bin/cli-serve @@ -96,10 +96,6 @@ function startApp() { server.listen(port); server.on('error', onError); server.on('listening', onListening); - }) - .catch((err) => { - console.error(err); - util.shutdown(1); }); } diff --git a/cache.js b/cache.js index 1d090e46d..9345f8cde 100644 --- a/cache.js +++ b/cache.js @@ -76,21 +76,6 @@ cache.get = (key) => new Promise((resolve, reject) => { }); }); -/** - * This invalidates a cached entry in the cache. - * @param {Mixed} key Either an array of items composing a key or a string - * @return {Promise} - */ -cache.invalidate = (key) => new Promise((resolve, reject) => { - cache.client.del(keyfunc(key), (err) => { - if (err) { - return reject(err); - } - - resolve(); - }); -}); - /** * This sets a value on the key with the expiry and then resolves once it is * done. diff --git a/models/action.js b/models/action.js index b5d2ab8b6..891dbd4f5 100644 --- a/models/action.js +++ b/models/action.js @@ -1,6 +1,5 @@ const mongoose = require('../mongoose'); const uuid = require('uuid'); -const _ = require('lodash'); const Schema = mongoose.Schema; const ActionSchema = new Schema({ @@ -67,34 +66,6 @@ ActionSchema.statics.findByItemIdArray = function(item_ids) { }); }; -/** - * Fetches the action summaries for the given asset, and comments around the - * given user id. - * @param {[type]} asset_id [description] - * @param {[type]} comments [description] - * @param {String} [current_user_id=''] [description] - * @return {[type]} [description] - */ -ActionSchema.statics.getActionSummariesFromComments = (asset_id = '', comments, current_user_id = '') => { - - // Get the user id's from the author id's as a unique array that gets - // sorted. - let userIDs = _.uniq(comments.map((comment) => comment.author_id)).sort(); - - // Fetch the actions for pretty much everything at this point. - return Action.getActionSummaries(_.uniq([ - - // Actions can be on assets... - asset_id, - - // Comments... - ...comments.map((comment) => comment.id), - - // Or Authors... - ...userIDs - ].filter((e) => e)), current_user_id); -}; - /** * Returns summaries of actions for an array of ids * @param {String} ids array of user identifiers (uuid) diff --git a/models/asset.js b/models/asset.js index a0619576f..165ebbc6c 100644 --- a/models/asset.js +++ b/models/asset.js @@ -1,8 +1,6 @@ const mongoose = require('../mongoose'); const Schema = mongoose.Schema; -const Setting = require('./setting'); - const uuid = require('uuid'); const AssetSchema = new Schema({ @@ -60,6 +58,11 @@ AssetSchema.index({ background: true }); +/** + * Search for assets. Currently only returns all. + */ +AssetSchema.statics.search = (query) => Asset.find(query); + /** * Finds an asset by its id. * @param {String} id identifier of the asset (uuid). @@ -72,25 +75,6 @@ AssetSchema.statics.findById = (id) => Asset.findOne({id}); */ AssetSchema.statics.findByUrl = (url) => Asset.findOne({url}); -/** - * Retrieves the settings given an asset query and rectifies it against the - * global settings. - * @param {Promise} assetQuery an asset query that returns a single asset. - * @return {Promise} - */ -AssetSchema.statics.rectifySettings = (assetQuery) => Promise.all([ - Setting.retrieve(), - assetQuery -]).then(([settings, asset]) => { - - // If the asset exists and has settings then return the merged object. - if (asset && asset.settings) { - return Object.assign({}, settings, asset.settings); - } - - return settings; -}); - /** * Finds a asset by its url. * diff --git a/models/comment.js b/models/comment.js index af9aa4cb1..c1a32cf1b 100644 --- a/models/comment.js +++ b/models/comment.js @@ -1,37 +1,9 @@ const mongoose = require('../mongoose'); -const Schema = mongoose.Schema; const uuid = require('uuid'); const Action = require('./action'); -/** - * The Mongo schema for a Comment Status. - * @type {Schema} - */ -const StatusSchema = new Schema({ - type: { - type: String, - enum: [ - 'accepted', - 'rejected', - 'premod', - ], - }, +const Schema = mongoose.Schema; - // The User ID of the user that assigned the status. - assigned_by: { - type: String, - default: null - }, - - created_at: Date -}, { - _id: false -}); - -/** - * The Mongo schema for a Comment. - * @type {Schema} - */ const CommentSchema = new Schema({ id: { type: String, @@ -45,7 +17,11 @@ const CommentSchema = new Schema({ }, asset_id: String, author_id: String, - status: [StatusSchema], + status: { + type: String, + enum: ['accepted', 'rejected', ''], + default: '' + }, parent_id: String }, { timestamps: { @@ -54,168 +30,90 @@ const CommentSchema = new Schema({ } }); -/** - * toJSON overrides to remove fields from the json - * output. - */ -CommentSchema.options.toJSON = {}; -CommentSchema.options.toJSON.hide = '_id status'; -CommentSchema.options.toJSON.transform = (doc, ret, options) => { - if (options.hide) { - options.hide.split(' ').forEach((prop) => { - delete ret[prop]; - }); - } - - return ret; -}; - -/** - * toJSON overrides to remove fields from the json - * output. - */ -CommentSchema.options.toJSON = {}; -CommentSchema.options.toJSON.hide = '_id'; -CommentSchema.options.toJSON.transform = (doc, ret, options) => { - if (options.hide) { - options.hide.split(' ').forEach((prop) => { - delete ret[prop]; - }); - } - - return ret; -}; - -/** - * Sets up a virtual getter function on a comment such that when you try and - * access the `comment.last_status` it returns the last status in the array - * of status's on the comment, or `null` if there was no status. - */ -CommentSchema.virtual('last_status').get(function() { - if (this.status && this.status.length > 0) { - return this.status[this.status.length - 1].type; - } - - return null; -}); - -/** - * Creates a new Comment that came from a public source. - * @param {Mixed} comment either a single comment or an array of comments. - * @return {Promise} - */ -CommentSchema.statics.publicCreate = (comment) => { - - // Check to see if this is an array of comments, if so map it out. - if (Array.isArray(comment)) { - return Promise.all(comment.map(Comment.publicCreate)); - } - - const { - body, - asset_id, - parent_id, - status = false, - author_id - } = comment; - - comment = new Comment({ - body, - asset_id, - parent_id, - status: status ? [{ - type: status, - created_at: new Date() - }] : [], - author_id - }); - - return comment.save(); -}; +//============================================================================== +// Find Statics +//============================================================================== /** * Finds a comment by the id. * @param {String} id identifier of comment (uuid) * @return {Promise} */ -CommentSchema.statics.findById = (id) => Comment.findOne({id}); +CommentSchema.statics.findById = function(id) { + return Comment.findOne({'id': id}); +}; /** * Finds ALL the comments by the asset_id. * @param {String} asset_id identifier of the asset which owns this comment (uuid) * @return {Promise} */ -CommentSchema.statics.findByAssetId = (asset_id) => Comment.find({ - asset_id -}); +CommentSchema.statics.findByAssetId = function(asset_id) { + return Comment.find({asset_id}); +}; /** - * Finds the accepted comments by the asset_id get the comments that are - * accepted. + * Finds the accepted comments by the asset_id. + * get the comments that are accepted. * @param {String} asset_id identifier of the asset which owns the comments (uuid) * @return {Promise} */ -CommentSchema.statics.findAcceptedByAssetId = (asset_id) => Comment.find({ - asset_id, - 'status.type': 'accepted' -}); +CommentSchema.statics.findAcceptedByAssetId = function(asset_id) { + return Comment.find({asset_id: asset_id, status:'accepted'}); +}; /** * Finds the new and accepted comments by the asset_id. * @param {String} asset_id identifier of the asset which owns the comments (uuid) * @return {Promise} */ -CommentSchema.statics.findAcceptedAndNewByAssetId = (asset_id) => Comment.find({ - asset_id, - $or: [ - { - 'status.type': 'accepted' - }, - { - status: { - $size: 0 - } - } - ] -}); +CommentSchema.statics.findAcceptedAndNewByAssetId = function(asset_id) { + return Comment.find({asset_id: asset_id, status: {'$in': ['accepted', '']}}); +}; /** * Find comments by an action that was performed on them. * @param {String} action_type the type of action that was performed on the comment * @return {Promise} */ -CommentSchema.statics.findByActionType = (action_type) => Action - .findCommentsIdByActionType(action_type, 'comment') - .then((actions) => Comment.find({ - id: { - $in: actions.map((a) => a.item_id) - } - })); +CommentSchema.statics.findByActionType = function(action_type) { + return Action + .findCommentsIdByActionType(action_type, 'comment') + .then((actions) => { + return Comment.find({'id': {'$in': actions.map(function(a){ + return a.item_id;})} + }); + }); +}; /** - * Find comment id's where the action type matches the argument. + * Find not moderated comments by an action that was performed on them. * @param {String} action_type the type of action that was performed on the comment + * @param {String} status the status of the comment to search for * @return {Promise} */ -CommentSchema.statics.findIdsByActionType = (action_type) => Action - .findCommentsIdByActionType(action_type, 'comment') - .then((actions) => actions.map(a => a.item_id)); +CommentSchema.statics.findByStatusByActionType = function(status, action_type) { + return Action + .findCommentsIdByActionType(action_type, 'comment') + .then((actions) => { + return Comment.find({ + status: status, + id: { + $in: actions.map(a => a.item_id) + } + }); + }); +}; /** * Find comments by their status. * @param {String} status the status of the comment to search for * @return {Promise} */ -CommentSchema.statics.findByStatus = (status = false) => { - let q = {}; - - if (status) { - q['status.type'] = status; - } else { - q.status = {$size: 0}; - } - - return Comment.find(q); +CommentSchema.statics.findByStatus = function(status) { + return Comment.find({ + status: status === 'new' ? '' : status + }); }; /** @@ -223,59 +121,39 @@ CommentSchema.statics.findByStatus = (status = false) => { * @param {String} moderationValue pre or post moderation setting. If it is undefined then look at the settings. * @return {Promise} */ -CommentSchema.statics.moderationQueue = (moderation, asset_id = false) => { +CommentSchema.statics.moderationQueue = function(moderation) { + switch(moderation){ - /** - * This adds the asset_id requirement to the query if the asset_id is defined. - */ - const assetIDWrap = (query) => { - if (asset_id) { - query = query.where('asset_id', asset_id); - } + // Pre-moderation: New comments are shown in the moderator queues immediately. + case 'pre': + return Comment.findByStatus('').then((comments) => { + return comments; + }); - return query; - }; + // Post-moderation: New comments do not appear in moderation queues unless they are flagged by other users. + case 'post': + return Comment.findByStatusByActionType('', 'flag').then((comments) => { + return comments; + }); - // Decide on whether or not we need to load extended options for the - // moderation based on the moderation options. - let comments; - - if (moderation === 'pre') { - - // Pre-moderation: New comments are shown in the moderator queues immediately. - comments = assetIDWrap(CommentSchema.statics.findByStatus('premod')); - - } else { - - // Post-moderation: New comments do not appear in moderation queues unless they are flagged by other users. - comments = CommentSchema.statics.findIdsByActionType('flag') - .then((ids) => assetIDWrap(Comment.find({ - id: { - $in: ids - } - }))); + default: + return Promise.reject(Error('Moderation setting not found.')); } - - return comments; }; +//============================================================================== +// Update Statics +//============================================================================== + /** - * Pushes a new status in for the user. - * @param {String} id identifier of the comment (uuid) - * @param {String} status the new status of the comment - * @param {String} assigned_by the user id for the user who performed the - * moderation action + * Change the status of a comment. + * @param {String} id identifier of the comment (uuid) + * @param {String} status the new status of the comment * @return {Promise} */ -CommentSchema.statics.pushStatus = (id, status, assigned_by = null) => Comment.update({id}, { - $push: { - status: { - type: status, - created_at: new Date(), - assigned_by - } - } -}); +CommentSchema.statics.changeStatus = function(id, status) { + return Comment.findOneAndUpdate({'id': id}, {$set: {'status': status}}); +}; /** * Add an action to the comment. @@ -291,13 +169,19 @@ CommentSchema.statics.addAction = (item_id, user_id, action_type) => Action.inse action_type }); +//============================================================================== +// Remove Statics +//============================================================================== + /** * Change the status of a comment. * @param {String} id identifier of the comment (uuid) * @param {String} status the new status of the comment * @return {Promise} */ -CommentSchema.statics.removeById = (id) => Comment.remove({id}); +CommentSchema.statics.removeById = function(id) { + return Comment.remove({'id': id}); +}; /** * Remove an action from the comment. @@ -306,18 +190,22 @@ CommentSchema.statics.removeById = (id) => Comment.remove({id}); * @param {String} user_id the id of the user performing the action * @return {Promise} */ -CommentSchema.statics.removeAction = (item_id, user_id, action_type) => Action.remove({ - action_type, - item_type: 'comment', - item_id, - user_id -}); +CommentSchema.statics.removeAction = function(item_id, user_id, action_type) { + return Action.remove({ + action_type, + item_type: 'comment', + item_id, + user_id + }); +}; /** * Returns all the comments in the collection. * @return {Promise} */ -CommentSchema.statics.all = () => Comment.find(); +CommentSchema.statics.all = () => { + return Comment.find(); +}; // Comment model. const Comment = mongoose.model('Comment', CommentSchema); diff --git a/models/setting.js b/models/setting.js index 22b2b103f..bf5ac290a 100644 --- a/models/setting.js +++ b/models/setting.js @@ -1,33 +1,18 @@ const mongoose = require('../mongoose'); const Schema = mongoose.Schema; -const _ = require('lodash'); -const cache = require('../cache'); /** - * SettingSchema manages application settings that get used on front and backend. + * this Schema manages application settings that get used on front and backend + * NOTE: when you set a setting here, it will not automatically be exposed to + * the front end. You must add it to the whitelist in the settings route + * in /routes/api/settings/index.js * @type {Schema} */ const SettingSchema = new Schema({ - id: { - type: String, - default: '1' - }, - moderation: { - type: String, - enum: [ - 'pre', - 'post' - ], - default: 'pre' - }, - infoBoxEnable: { - type: Boolean, - default: false - }, - infoBoxContent: { - type: String, - default: '' - }, + id: {type: String, default: '1'}, + moderation: {type: String, enum: ['pre', 'post'], default: 'pre'}, + infoBoxEnable: {type: Boolean, default: false}, + infoBoxContent: {type: String, default: ''}, wordlist: [String] }, { timestamps: { @@ -37,70 +22,48 @@ const SettingSchema = new Schema({ }); /** - * The Mongo Mongoose object. + * this is run once when the app starts to ensure settings are populated + * @return {Promise} null initialize the global settings object */ -const Setting = mongoose.model('Setting', SettingSchema); - -/** - * The Setting Service object exposing the Setting model. - * @type {Object} - */ -const SettingService = module.exports = {}; - -/** - * The selector used to uniquely identify the settings document. - */ -const selector = {id: '1'}; - -/** - * Cache expiry time in seconds for when the cached entry of the settings object - * expires. 2 minutes. - */ -const EXPIRY_TIME = 60 * 2; +SettingSchema.statics.init = function (defaults) { + return this.update({id: '1'}, {$setOnInsert: defaults}, {upsert: true}); +}; /** * Gets the entire settings record and sends it back * @return {Promise} settings the whole settings record */ -SettingService.retrieve = () => cache.wrap('settings', EXPIRY_TIME, () => Setting.findOne(selector)); +SettingSchema.statics.getSettings = function () { + return this.findOne({id: '1'}); +}; + +/** + * Gets the settings visible to the public + * @return {Promise} moderation the settings for how to moderate comments + */ +SettingSchema.statics.getPublicSettings = function () { + return this.findOne({id: '1'}).select('moderation infoBoxEnable infoBoxContent'); +}; + +/** + * Gets the info box settings and sends it back + * @return {Promise} content the content of the info Box + */ +SettingSchema.statics.getInfoBoxSetting = function () { + return this.findOne({id: '1'}).select('infoBoxEnable infoBoxContent'); +}; /** * This will update the settings object with whatever you pass in * @param {object} setting a hash of whatever settings you want to update * @return {Promise} settings Promise that resolves to the entire (updated) settings object. */ -SettingService.update = (settings) => Setting.findOneAndUpdate(selector, { - $set: settings -}, { - upsert: true, - new: true, - setDefaultsOnInsert: true -}).then((settings) => { - - // Invalidate the settings cache. - return cache - .set('settings', settings, EXPIRY_TIME) - .then(() => settings); -}); - -/** - * Filters the document to ensure that the resulting document is indeed ready - * for non authenticated users. - * @param {Object} settings the source settings object - * @return {Object} the filtered settings object - */ -SettingService.public = (settings) => _.pick(settings, ['moderation', 'infoBoxEnable', 'infoBoxContent']); - -/** - * This is run once when the app starts to ensure settings are populated. - * @return {Promise} null initialize the global settings object - */ -SettingService.init = (defaults) => { - - // Inject the defaults on top of the passed in defaults to ensure that the new - // settings conform to the required selector. - defaults = Object.assign({}, defaults, selector); - - // Actually update the settings collection. - return SettingService.update(defaults); +SettingSchema.statics.updateSettings = function (setting) { + // There should only ever be one record unless something has gone wrong. + // In the future we may have multiple records for custom settings for objects/users. + return this.findOneAndUpdate({id: '1'}, {$set: setting}, {new: true}); }; + +const Setting = mongoose.model('Setting', SettingSchema); + +module.exports = Setting; diff --git a/models/user.js b/models/user.js index 336486a54..86908ab42 100644 --- a/models/user.js +++ b/models/user.js @@ -9,6 +9,7 @@ const SALT_ROUNDS = 10; // USER_ROLES is the array of roles that is permissible as a user role. const USER_ROLES = [ + '', 'admin', 'moderator' ]; @@ -105,7 +106,7 @@ UserSchema.index({ * output. */ UserSchema.options.toJSON = {}; -UserSchema.options.toJSON.hide = '_id password profiles roles disabled'; +UserSchema.options.toJSON.hide = 'password profiles roles disabled'; UserSchema.options.toJSON.transform = (doc, ret, options) => { if (options.hide) { options.hide.split(' ').forEach((prop) => { diff --git a/package.json b/package.json index c54bd6723..be6c2b153 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,6 @@ "eslint-config-standard": "^6.2.1", "eslint-plugin-flowtype": "^2.25.0", "eslint-plugin-import": "^2.2.0", - "eslint-plugin-mocha": "^4.7.0", "eslint-plugin-promise": "^3.3.1", "eslint-plugin-react": "^6.6.0", "eslint-plugin-standard": "^2.0.1", diff --git a/routes/api/comments/index.js b/routes/api/comments/index.js index b82c1faf3..3bdf4afc6 100644 --- a/routes/api/comments/index.js +++ b/routes/api/comments/index.js @@ -1,6 +1,5 @@ const express = require('express'); const Comment = require('../../../models/comment'); -const Asset = require('../../../models/asset'); const User = require('../../../models/user'); const Action = require('../../../models/action'); const wordlist = require('../../../services/wordlist'); @@ -10,45 +9,24 @@ const _ = require('lodash'); const router = express.Router(); router.get('/', authorization.needed('admin'), (req, res, next) => { - - const { - status = null, - action_type = null, - asset_id = null - } = req.query; - - /** - * This adds the asset_id requirement to the query if the asset_id is defined. - */ - const assetIDWrap = (query) => { - if (asset_id) { - query = query.where('asset_id', asset_id); - } - - return query; - }; - let query; - if (status) { - query = assetIDWrap(Comment.findByStatus(status === 'new' ? null : status)); - } else if (action_type) { - query = Comment - .findIdsByActionType(action_type) - .then((ids) => assetIDWrap(Comment.find({ - id: { - $in: ids - }, - }))); + if (req.query.status) { + query = Comment.findByStatus(req.query.status); + } else if (req.query.action_type) { + query = Comment.findByActionType(req.query.action_type); } else { - query = assetIDWrap(Comment.all()); + query = Comment.all(); } query.then((comments) => { return Promise.all([ comments, User.findByIdArray(_.uniq(comments.map((comment) => comment.author_id))), - Action.getActionSummariesFromComments(asset_id, comments, req.user ? req.user.id : false) + Action.getActionSummaries(_.uniq([ + ...comments.map((comment) => comment.id), + ...comments.map((comment) => comment.author_id) + ])) ]); }) .then(([comments, users, actions])=> @@ -70,38 +48,21 @@ router.post('/', wordlist.filter('body'), (req, res, next) => { parent_id } = req.body; - // Decide the status based on whether or not the current asset/settings - // has pre-mod enabled or not. If the comment was rejected based on the - // wordlist, then reject it, otherwise if the moderation setting is - // premod, set it to `premod`. - let status; + Comment + .create({ + body, + asset_id, + parent_id, + status: req.wordlist.matched ? 'rejected' : '', + author_id: req.user.id + }) + .then((comment) => { - if (req.wordlist.matched) { - status = Promise.resolve('rejected'); - } else { - status = Asset - .rectifySettings(Asset.findById(asset_id)) - - // Return `premod` if pre-moderation is enabled and an empty "new" status - // in the event that it is not in pre-moderation mode. - .then(({moderation}) => moderation === 'pre' ? 'premod' : ''); - } - - status.then((status) => Comment.publicCreate({ - body, - asset_id, - parent_id, - status, - author_id: req.user.id - })) - .then((comment) => { - - // The comment was created! Send back the created comment. - res.status(201).send(comment); - }) - .catch((err) => { - next(err); - }); + res.status(201).send(comment); + }) + .catch((err) => { + next(err); + }); }); router.get('/:comment_id', authorization.needed('admin'), (req, res, next) => { @@ -138,7 +99,7 @@ router.put('/:comment_id/status', authorization.needed('admin'), (req, res, next } = req.body; Comment - .pushStatus(req.params.comment_id, status, req.user.id) + .changeStatus(req.params.comment_id, status) .then(() => { res.status(204).end(); }) diff --git a/routes/api/queue/index.js b/routes/api/queue/index.js index 9c85fbe94..b38d1b763 100644 --- a/routes/api/queue/index.js +++ b/routes/api/queue/index.js @@ -3,7 +3,6 @@ const Comment = require('../../../models/comment'); const User = require('../../../models/user'); const Action = require('../../../models/action'); const Setting = require('../../../models/setting'); -const Asset = require('../../../models/asset'); const _ = require('lodash'); const router = express.Router(); @@ -17,52 +16,27 @@ const router = express.Router(); // Pre-moderation: New comments are shown in the moderator queues immediately. // Post-moderation: New comments do not appear in moderation queues unless they are flagged by other users. router.get('/comments/pending', (req, res, next) => { - - const { - asset_id - } = req.query; - - let settings = Setting.retrieve(); - - if (asset_id) { - - // In the event that we have an asset_id, we should fetch the asset settings - // in order to actually determine if there is additional comments to parse. - settings = Promise.all([ - settings, - Asset.findById(asset_id).select('settings') - ]).then(([{moderation}, asset]) => { - if (asset.settings && asset.settings.moderation) { - return {moderation: asset.settings.moderation}; - } - - return {moderation}; - }); - } - - settings - .then(({moderation}) => { - return Comment.moderationQueue(moderation); - }).then((comments) => { - return Promise.all([ - comments, - User.findByIdArray(_.uniq(comments.map((comment) => comment.author_id))), - Action.getActionSummaries(_.uniq([ - ...comments.map((comment) => comment.id), - ...comments.map((comment) => comment.author_id) - ])) - ]); - }) - .then(([comments, users, actions]) => { - res.json({ - comments, - users, - actions - }); - }) - .catch(error => { - next(error); - }); + Setting.getPublicSettings().then(({moderation}) => + Comment.moderationQueue(moderation)) + .then((comments) => { + return Promise.all([ + comments, + User.findByIdArray(_.uniq(comments.map((comment) => comment.author_id))), + Action.getActionSummaries(_.uniq([ + ...comments.map((comment) => comment.id), + ...comments.map((comment) => comment.author_id) + ])) + ]); + }) + .then(([comments, users, actions])=> + res.status(200).json({ + comments, + users, + actions + })) + .catch(error => { + next(error); + }); }); module.exports = router; diff --git a/routes/api/settings/index.js b/routes/api/settings/index.js index 76d16c7ec..910524fb2 100644 --- a/routes/api/settings/index.js +++ b/routes/api/settings/index.js @@ -4,21 +4,19 @@ const Setting = require('../../../models/setting'); const router = express.Router(); router.get('/', (req, res, next) => { - Setting.retrieve().then((settings) => { - res.json(settings); - }) - .catch((err) => { - next(err); - }); + Setting + .getSettings() + .then(settings => { + res.json(settings); + }) + .catch(next); }); router.put('/', (req, res, next) => { - Setting.update(req.body).then(() => { - res.status(204).end(); - }) - .catch((err) => { - next(err); - }); + Setting + .updateSettings(req.body) + .then(() => res.status(204).end()) + .catch(next); }); module.exports = router; diff --git a/routes/api/stream/index.js b/routes/api/stream/index.js index 26947be09..4e8373999 100644 --- a/routes/api/stream/index.js +++ b/routes/api/stream/index.js @@ -26,14 +26,14 @@ router.get('/', (req, res, next) => { return asset; }), - // Get the moderation setting from the settings. - Setting.retrieve() + // Get the public settings. + Setting.getPublicSettings() ]) .then(([asset, settings]) => { // Merge the asset specific settings with the returned settings object in // the event that the asset that was returned also had settings. - if (asset && asset.settings) { + if (asset.settings) { settings = Object.assign({}, settings, asset.settings); } @@ -70,7 +70,17 @@ router.get('/', (req, res, next) => { let users = userIDs.length > 0 ? User.findByIdArray(userIDs) : []; // Fetch the actions for pretty much everything at this point. - let actions = Action.getActionSummariesFromComments(asset.id, comments, req.user ? req.user.id : false); + let actions = Action.getActionSummaries(_.uniq([ + + // Actions can be on assets... + asset.id, + + // Comments... + ...comments.map((comment) => comment.id), + + // Or Authors... + ...userIDs + ]), req.user ? req.user.id : false); return Promise.all([ @@ -98,7 +108,7 @@ router.get('/', (req, res, next) => { comments, users, actions, - settings: Setting.public(settings) + settings }); }) .catch(error => { diff --git a/services/wordlist.js b/services/wordlist.js index 59a842817..e6f2ad668 100644 --- a/services/wordlist.js +++ b/services/wordlist.js @@ -20,7 +20,7 @@ const wordlist = { */ wordlist.init = () => { return Setting - .retrieve() + .getSettings() .then((settings) => { // Insert the settings wordlist. diff --git a/tests/.eslintrc.json b/tests/.eslintrc.json index b188e92cf..363ef5a28 100644 --- a/tests/.eslintrc.json +++ b/tests/.eslintrc.json @@ -4,12 +4,8 @@ "node": true, "mocha": true }, - "plugins": [ - "mocha" - ], "extends": "../.eslintrc.json", "rules": { - "no-undef": [0], - "mocha/no-exclusive-tests": "warn" + "no-undef": [0] } } diff --git a/tests/models/action.js b/tests/models/action.js index 5f05dea71..c354b8f83 100644 --- a/tests/models/action.js +++ b/tests/models/action.js @@ -1,34 +1,35 @@ const Action = require('../../models/action'); const expect = require('chai').expect; -describe('models.Action', () => { - let mockActions = []; +describe('Action: models', () => { + let mockActions; - beforeEach(() => Action.create([{ - action_type: 'flag', - item_id: '123', - item_type: 'comment', - user_id: 'flagginguserid' - }, { - action_type: 'flag', - item_id: '456', - item_type: 'comment' - }, { - action_type: 'flag', - item_id: '123', - item_type: 'comment' - }, { - action_type: 'like', - item_id: '123', - item_type: 'comment' - }]).then((actions) => { - mockActions = actions; - })); + beforeEach(() => { + return Action.create([{ + action_type: 'flag', + item_id: '123', + item_type: 'comment', + user_id: 'flagginguserid' + }, { + action_type: 'flag', + item_id: '456', + item_type: 'comment' + }, { + action_type: 'flag', + item_id: '123', + item_type: 'comment' + }, { + action_type: 'like', + item_id: '123', + item_type: 'comment' + }]).then((actions) => { + mockActions = actions; + }); + }); describe('#findById()', () => { it('should find an action by id', () => { return Action.findById(mockActions[0].id).then((result) => { - expect(result).to.not.be.null; expect(result).to.have.property('action_type', 'flag'); }); }); diff --git a/tests/models/asset.js b/tests/models/asset.js index c9eff819e..69bf99f9d 100644 --- a/tests/models/asset.js +++ b/tests/models/asset.js @@ -6,7 +6,7 @@ const expect = chai.expect; // Use the chai should. chai.should(); -describe('models.Asset', () => { +describe('Asset: model', () => { beforeEach(() => { const defaults = {url:'http://test.com'}; diff --git a/tests/models/comment.js b/tests/models/comment.js index a9c2f4787..07834a186 100644 --- a/tests/models/comment.js +++ b/tests/models/comment.js @@ -7,57 +7,35 @@ const settings = {id: '1', moderation: 'pre'}; const expect = require('chai').expect; -describe('models.Comment', () => { +describe('Comment: models', () => { const comments = [{ body: 'comment 10', asset_id: '123', - status: [], + status: '', parent_id: '', author_id: '123', id: '1' }, { body: 'comment 20', asset_id: '123', - status: [{ - type: 'accepted' - }], + status: 'accepted', parent_id: '', author_id: '123', id: '2' }, { body: 'comment 30', asset_id: '456', - status: [], + status: '', parent_id: '', author_id: '456', id: '3' }, { body: 'comment 40', asset_id: '123', - status: [{ - type: 'rejected' - }], + status: 'rejected', parent_id: '', author_id: '456', id: '4' - }, { - body: 'comment 50', - asset_id: '1234', - status: [{ - type: 'premod' - }], - parent_id: '', - author_id: '456', - id: '5' - }, { - body: 'comment 60', - asset_id: '1234', - status: [{ - type: 'premod' - }], - parent_id: '', - author_id: '456', - id: '6' }]; const users = [{ @@ -82,69 +60,25 @@ describe('models.Comment', () => { user_id: '456' }]; - beforeEach(() => Promise.all([ - Setting.init(settings), - Comment.create(comments), - User.createLocalUsers(users), - Action.create(actions) - ])); - - describe('#publicCreate()', () => { - - it('creates a new comment', () => { - return Comment.publicCreate({ - body: 'This is a comment!', - status: 'accepted' - }).then((c) => { - expect(c).to.not.be.null; - expect(c.id).to.not.be.null; - expect(c.id).to.be.uuid; - expect(c.status).to.have.length(1); - expect(c.status[0]).to.have.property('type', 'accepted'); - }); - }); - - it('creates many new comments', () => { - return Comment.publicCreate([{ - body: 'This is a comment!', - status: 'accepted' - }, { - body: 'This is another comment!' - }, { - body: 'This is a rejected comment!', - status: 'rejected' - }]).then(([c1, c2, c3]) => { - expect(c1).to.not.be.null; - expect(c1.id).to.be.uuid; - expect(c1.status).to.have.length(1); - expect(c1.status[0]).to.have.property('type', 'accepted'); - - expect(c2).to.not.be.null; - expect(c2.id).to.be.uuid; - expect(c2.status).to.have.length(0); - - expect(c3).to.not.be.null; - expect(c3.id).to.be.uuid; - expect(c3.status).to.have.length(1); - expect(c3.status[0]).to.have.property('type', 'rejected'); - }); - }); - + beforeEach(() => { + return Promise.all([ + Setting.create(settings), + Comment.create(comments), + User.createLocalUsers(users), + Action.create(actions) + ]); }); describe('#findById()', () => { - it('should find a comment by id', () => { return Comment.findById('1').then((result) => { expect(result).to.not.be.null; expect(result).to.have.property('body', 'comment 10'); }); }); - }); describe('#findByAssetId()', () => { - it('should find an array of all comments by asset id', () => { return Comment.findByAssetId('123').then((result) => { expect(result).to.have.length(3); @@ -157,7 +91,6 @@ describe('models.Comment', () => { expect(result[2]).to.have.property('body', 'comment 40'); }); }); - it('should find an array of accepted comments by asset id', () => { return Comment.findAcceptedByAssetId('123').then((result) => { expect(result).to.have.length(1); @@ -168,7 +101,6 @@ describe('models.Comment', () => { expect(result[0]).to.have.property('body', 'comment 20'); }); }); - it('should find an array of new and accepted comments by asset id', () => { return Comment.findAcceptedAndNewByAssetId('123').then((result) => { expect(result).to.have.length(2); @@ -180,16 +112,13 @@ describe('models.Comment', () => { }); }); }); - describe('#moderationQueue()', () => { - it('should find an array of new comments to moderate when pre-moderation', () => { return Comment.moderationQueue('pre').then((result) => { expect(result).to.not.be.null; expect(result).to.have.lengthOf(2); }); }); - it('should find an array of new comments to moderate when post-moderation', () => { return Comment.moderationQueue('post').then((result) => { expect(result).to.not.be.null; @@ -197,56 +126,21 @@ describe('models.Comment', () => { expect(result[0]).to.have.property('body', 'comment 30'); }); }); - + // it('should fail when the moderation is not pre or post', () => { + // return Comment.moderationQueue('any').catch(function(error) { + // expect(error).to.not.be.null; + // }); + // }); }); describe('#removeAction', () => { - it('should remove an action', () => { - return Comment.removeAction('3', '123', 'flag') - .then(() => { - return Action.findByItemIdArray(['123']); - }) - .then((actions) => { - expect(actions.length).to.equal(0); - }); + return Comment.removeAction('3', '123', 'flag').then(() => { + return Action.findByItemIdArray(['123']); + }) + .then((actions) => { + expect(actions.length).to.equal(0); + }); }); }); - - describe('#changeStatus', () => { - - it('should change the status of a comment from no status', () => { - let comment_id = comments[0].id; - - return Comment.findById(comment_id) - .then((c) => { - expect(c).to.have.property('status'); - expect(c.status).to.have.length(0); - - return Comment.pushStatus(comment_id, 'rejected', '123'); - }) - .then(() => Comment.findById(comment_id)) - .then((c) => { - expect(c).to.have.property('status'); - expect(c.status).to.have.length(1); - expect(c.status[0]).to.have.property('type', 'rejected'); - expect(c.status[0]).to.have.property('assigned_by', '123'); - }); - }); - - it('should change the status of a comment from accepted', () => { - return Comment.pushStatus(comments[1].id, 'rejected', '123') - .then(() => Comment.findById(comments[1].id)) - .then((c) => { - expect(c).to.have.property('status'); - expect(c.status).to.have.length(2); - expect(c.status[0]).to.have.property('type', 'accepted'); - expect(c.status[0]).to.have.property('assigned_by', null); - - expect(c.status[1]).to.have.property('type', 'rejected'); - expect(c.status[1]).to.have.property('assigned_by', '123'); - }); - }); - - }); }); diff --git a/tests/models/setting.js b/tests/models/setting.js index 3e77297fc..186a65245 100644 --- a/tests/models/setting.js +++ b/tests/models/setting.js @@ -1,29 +1,34 @@ const Setting = require('../../models/setting'); const expect = require('chai').expect; -describe('models.Setting', () => { +describe('Setting: model', () => { - beforeEach(() => Setting.init({moderation: 'pre'})); + beforeEach(() => { + const defaults = { + id: 1 + }; + return Setting.update({id: '1'}, {$setOnInsert: defaults}, {upsert: true}); + }); - describe('#retrieve()', () => { + describe('#getSettings()', () => { it('should have a moderation field defined', () => { - return Setting.retrieve().then(settings => { + return Setting.getSettings().then(settings => { expect(settings).to.have.property('moderation').and.to.equal('pre'); }); }); it('should have two infoBox fields defined', () => { - return Setting.retrieve().then(settings => { + return Setting.getSettings().then(settings => { expect(settings).to.have.property('infoBoxEnable').and.to.equal(false); expect(settings).to.have.property('infoBoxContent').and.to.equal(''); }); }); }); - describe('#update()', () => { + describe('#updateSettings()', () => { it('should update the settings with a passed object', () => { const mockSettings = {moderation: 'post', infoBoxEnable: true, infoBoxContent: 'yeah'}; - return Setting.update(mockSettings).then(updatedSettings => { + return Setting.updateSettings(mockSettings).then(updatedSettings => { expect(updatedSettings).to.be.an('object'); expect(updatedSettings).to.have.property('moderation').and.to.equal('post'); expect(updatedSettings).to.have.property('infoBoxEnable', true); @@ -32,10 +37,13 @@ describe('models.Setting', () => { }); }); - describe('#get', () => { + describe('#getPublicSettings', () => { it('should return the moderation settings', () => { - return Setting.retrieve().then(({moderation}) => { + return Setting.getPublicSettings().then(({moderation, infoBoxEnable, infoBoxContent, wordlist}) => { expect(moderation).not.to.be.null; + expect(infoBoxEnable).not.to.be.null; + expect(infoBoxContent).not.to.be.null; + expect(wordlist).to.be.undefined; }); }); }); diff --git a/tests/models/user.js b/tests/models/user.js index 5e1677016..c8af92054 100644 --- a/tests/models/user.js +++ b/tests/models/user.js @@ -1,7 +1,7 @@ const User = require('../../models/user'); const expect = require('chai').expect; -describe('models.User', () => { +describe('User: models', () => { let mockUsers; beforeEach(() => { return User.createLocalUsers([{ diff --git a/tests/routes/api/comments/index.js b/tests/routes/api/comments/index.js index bf7a06ff6..bc8b67bc1 100644 --- a/tests/routes/api/comments/index.js +++ b/tests/routes/api/comments/index.js @@ -10,7 +10,6 @@ chai.use(require('chai-http')); const wordlist = require('../../../../services/wordlist'); const Comment = require('../../../../models/comment'); -const Asset = require('../../../../models/asset'); const Action = require('../../../../models/action'); const User = require('../../../../models/user'); @@ -18,71 +17,63 @@ const Setting = require('../../../../models/setting'); const settings = {id: '1', moderation: 'pre'}; describe('/api/v1/comments', () => { + const comments = [{ + id: 'abc', + body: 'comment 10', + asset_id: 'asset', + author_id: '123' + }, { + id: 'def', + body: 'comment 20', + asset_id: 'asset', + author_id: '456' + }, { + id: 'def-rejected', + body: 'comment 20', + asset_id: 'asset', + author_id: '456', + status: 'rejected' + }, { + id: 'hij', + body: 'comment 30', + asset_id: '456', + author_id: '456', + status: 'accepted' + }]; + + const users = [{ + displayName: 'Ana', + email: 'ana@gmail.com', + password: '123' + }, { + displayName: 'Maria', + email: 'maria@gmail.com', + password: '123' + }]; + + const actions = [{ + action_type: 'flag', + item_id: 'abc', + item_type: 'comment' + }, { + action_type: 'like', + item_id: 'hij', + item_type: 'comment' + }]; + + beforeEach(() => { + return Promise.all([ + Comment.create(comments), + User.createLocalUsers(users), + Action.create(actions), + wordlist.insert([ + 'bad words' + ]), + Setting.create(settings) + ]); + }); describe('#get', () => { - const comments = [{ - body: 'comment 10', - asset_id: 'asset', - author_id: '123' - }, { - body: 'comment 20', - asset_id: 'asset', - author_id: '456' - }, { - body: 'comment 20', - asset_id: 'asset', - author_id: '456', - status: [{ - type: 'rejected' - }] - }, { - body: 'comment 30', - asset_id: '456', - status: [{ - type: 'accepted' - }] - }]; - - const users = [{ - displayName: 'Ana', - email: 'ana@gmail.com', - password: '123' - }, { - displayName: 'Maria', - email: 'maria@gmail.com', - password: '123' - }]; - - const actions = [{ - action_type: 'flag', - item_id: 'abc', - item_type: 'comment' - }, { - action_type: 'like', - item_id: 'hij', - item_type: 'comment' - }]; - - beforeEach(() => { - return Promise.all([ - Comment.create(comments).then((newComments) => { - newComments.forEach((comment, i) => { - comments[i].id = comment.id; - }); - - actions[0].item_id = comments[0].id; - actions[1].item_id = comments[1].id; - - return Action.create(actions); - }), - User.createLocalUsers(users), - wordlist.insert([ - 'bad words' - ]), - Setting.init(settings) - ]); - }); - it('should return all the comments', () => { return chai.request(app) .get('/api/v1/comments') @@ -100,9 +91,7 @@ describe('/api/v1/comments', () => { .set(passport.inject({roles: ['admin']})) .then((res) => { expect(res).to.have.status(200); - expect(res.body).to.have.property('comments'); - expect(res.body.comments).to.have.length(1); - expect(res.body.comments[0]).to.have.property('id', comments[2].id); + expect(res.body.comments[0]).to.have.property('id', 'def-rejected'); }); }); @@ -113,7 +102,7 @@ describe('/api/v1/comments', () => { .then((res) => { expect(res).to.have.status(200); expect(res.body.comments).to.have.length(1); - expect(res.body.comments[0]).to.have.property('id', comments[3].id); + expect(res.body.comments[0]).to.have.property('id', 'hij'); }); }); @@ -135,7 +124,8 @@ describe('/api/v1/comments', () => { expect(res).to.have.status(200); expect(res.body.comments).to.have.length(1); - expect(res.body.comments[0]).to.have.property('id', comments[0].id); + expect(res.body.comments[0]).to.have.property('id', 'abc'); + }); }); }); @@ -161,31 +151,7 @@ describe('/api/v1/comments', () => { .then((res) => { expect(res).to.have.status(201); expect(res.body).to.have.property('id'); - expect(res.body).to.have.property('status').and.to.have.length(1); - expect(res.body.status[0]).to.have.property('type', 'rejected'); - }); - }); - - it('should create a comment with a premod status if it\'s asset is has pre-moderation enabled', () => { - return Asset - .findOrCreateByUrl('https://coralproject.net/article1') - .then((asset) => { - return Asset - .overrideSettings(asset.id, {moderation: 'pre'}) - .then(() => asset); - }) - .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); - expect(res.body).to.have.property('id'); - expect(res.body).to.have.property('asset_id'); - expect(res.body).to.have.property('status').and.to.have.length(1); - expect(res.body.status[0]).to.have.property('type', 'premod'); + expect(res.body).to.have.property('status', 'rejected'); }); }); }); @@ -301,22 +267,18 @@ describe('/api/v1/comments/:comment_id/actions', () => { body: 'comment 10', asset_id: 'asset', author_id: '123', - status: [] + status: '' }, { id: 'def', body: 'comment 20', asset_id: 'asset', author_id: '456', - status: [{ - type: 'rejected' - }] + status: 'rejected' }, { id: 'hij', body: 'comment 30', asset_id: '456', - status: [{ - type: 'accepted' - }] + status: 'accepted' }]; const users = [{ @@ -354,8 +316,10 @@ describe('/api/v1/comments/:comment_id/actions', () => { .then((res) => { expect(res).to.have.status(201); expect(res).to.have.body; + expect(res.body).to.have.property('item_type', 'comment'); expect(res.body).to.have.property('action_type', 'flag'); expect(res.body).to.have.property('item_id', 'abc'); + expect(res.body).to.have.property('user_id', '456'); }); }); }); diff --git a/tests/routes/api/queue/index.js b/tests/routes/api/queue/index.js index d64423013..1e99ae61e 100644 --- a/tests/routes/api/queue/index.js +++ b/tests/routes/api/queue/index.js @@ -15,54 +15,56 @@ const User = require('../../../../models/user'); const Setting = require('../../../../models/setting'); const settings = {id: '1', moderation: 'pre'}; -describe('/api/v1/queue', () => { - const comments = [{ - id: 'abc', - body: 'comment 10', - asset_id: 'asset', - author_id: '123', - status: [{ - type: 'rejected' - }] - }, { - id: 'def', - body: 'comment 20', - asset_id: 'asset', - author_id: '456', - status: [{ - type: 'premod' - }] - }, { - id: 'hij', - body: 'comment 30', - asset_id: '456', - status: [{ - type: 'accepted' - }] - }]; +beforeEach(() => { + return Setting.create(settings); +}); - const users = [{ - displayName: 'Ana', - email: 'ana@gmail.com', - password: '123' - }, { - displayName: 'Maria', - email: 'maria@gmail.com', - password: '123' - }]; +describe('Get moderation queues rejected, pending, flags', () => { - const actions = [{ - action_type: 'flag', - item_id: 'abc', - item_type: 'comment' - }, { - action_type: 'like', - item_id: 'hij', - item_type: 'comment' - }]; + describe('/api/v1/queue', () => { + let comments; - beforeEach(() => { - return User.createLocalUsers(users) + const users = [{ + id: '456', + displayName: 'Ana', + email: 'ana@gmail.com', + password: '123' + }, { + id: '123', + displayName: 'Maria', + email: 'maria@gmail.com', + password: '123' + }]; + + let actions; + + beforeEach(() => { + + comments = [{ + id: 'abc', + body: 'comment 10', + asset_id: 'asset', + status: 'rejected' + }, { + id: 'def', + body: 'comment 20', + asset_id: 'asset' + }, { + id: 'hij', + body: 'comment 30', + asset_id: '456', + status: 'accepted' + }]; + + actions = [{ + action_type: 'flag', + item_type: 'comment' + }, { + action_type: 'like', + item_type: 'comment' + }]; + + return User.createLocalUsers(users) .then((u) => { comments[0].author_id = u[0].id; comments[1].author_id = u[1].id; @@ -74,24 +76,22 @@ describe('/api/v1/queue', () => { actions[0].item_id = c[0].id; actions[1].item_id = c[1].id; - return Promise.all([ - Action.create(actions), - Setting.init(settings) - ]); + return Action.create(actions); }); - }); + }); - it('should return all the pending comments, users and actions', function(done){ - chai.request(app) - .get('/api/v1/queue/comments/pending') - .set(passport.inject({roles: ['admin']})) - .end(function(err, res){ - expect(err).to.be.null; - expect(res).to.have.status(200); - expect(res.body.comments[0]).to.have.property('body'); - expect(res.body.users[0]).to.have.property('displayName'); - expect(res.body.actions[0]).to.have.property('action_type'); - done(); - }); + it('should return all the pending comments, users and actions', function(done){ + chai.request(app) + .get('/api/v1/queue/comments/pending') + .set(passport.inject({roles: ['admin']})) + .end(function(err, res){ + expect(err).to.be.null; + expect(res).to.have.status(200); + expect(res.body.comments[0]).to.have.property('body'); + expect(res.body.users[0]).to.have.property('displayName'); + expect(res.body.actions[0]).to.have.property('action_type'); + done(); + }); + }); }); }); diff --git a/tests/routes/api/settings/index.js b/tests/routes/api/settings/index.js index 318af81f4..d1a7ba81b 100644 --- a/tests/routes/api/settings/index.js +++ b/tests/routes/api/settings/index.js @@ -12,7 +12,7 @@ const defaults = {id: '1', moderation: 'pre'}; describe('/api/v1/settings', () => { - beforeEach(() => Setting.init(defaults)); + beforeEach(() => Setting.create(defaults)); describe('#get', () => { @@ -40,7 +40,7 @@ describe('/api/v1/settings', () => { .then((res) => { expect(res).to.have.status(204); - return Setting.retrieve(); + return Setting.getSettings(); }) .then((settings) => { expect(settings).to.have.property('moderation', 'post'); diff --git a/tests/routes/api/stream/index.js b/tests/routes/api/stream/index.js index a128938ba..6484fdc12 100644 --- a/tests/routes/api/stream/index.js +++ b/tests/routes/api/stream/index.js @@ -20,37 +20,7 @@ describe('/api/v1/stream', () => { moderation: 'post' }; - const comments = [{ - id: 'abc', - body: 'comment 10', - author_id: '', - parent_id: '', - status: [{ - type: 'accepted' - }] - }, { - id: 'def', - body: 'comment 20', - author_id: '', - parent_id: '', - status: [] - }, { - id: 'uio', - body: 'comment 30', - asset_id: 'asset', - author_id: '456', - parent_id: '', - status: [{ - type: 'accepted' - }] - }, { - id: 'hij', - body: 'comment 40', - asset_id: '456', - status: [{ - type: 'rejected' - }] - }]; + let comments; const users = [{ displayName: 'Ana', @@ -71,6 +41,33 @@ describe('/api/v1/stream', () => { }]; beforeEach(() => { + + comments = [{ + id: 'abc', + body: 'comment 10', + author_id: '', + parent_id: '', + status: 'accepted' + }, { + id: 'def', + body: 'comment 20', + author_id: '', + parent_id: '', + status: '' + }, { + id: 'uio', + body: 'comment 30', + asset_id: 'asset', + author_id: '456', + parent_id: '', + status: 'accepted' + }, { + id: 'hij', + body: 'comment 40', + asset_id: '456', + status: 'rejected' + }]; + return Promise.all([ User.createLocalUsers(users), Asset.findOrCreateByUrl('http://test.com'), @@ -97,11 +94,10 @@ describe('/api/v1/stream', () => { return Promise.all([ Comment.create(comments), Action.create(actions), - Setting.init(settings) + Setting.init().then(() => Setting.updateSettings(settings)) ]); }); }); - it('should return a stream with comments, users and actions for an existing asset', () => { return chai.request(app) .get('/api/v1/stream')