mirror of
https://github.com/wassname/talk.git
synced 2026-06-30 09:58:52 +08:00
Revert "Revert "Status history""
This commit is contained in:
@@ -96,6 +96,10 @@ function startApp() {
|
||||
server.listen(port);
|
||||
server.on('error', onError);
|
||||
server.on('listening', onListening);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
util.shutdown(1);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -76,6 +76,21 @@ 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.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const mongoose = require('../mongoose');
|
||||
const uuid = require('uuid');
|
||||
const _ = require('lodash');
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
const ActionSchema = new Schema({
|
||||
@@ -66,6 +67,34 @@ 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)
|
||||
|
||||
+21
-5
@@ -1,6 +1,8 @@
|
||||
const mongoose = require('../mongoose');
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
const Setting = require('./setting');
|
||||
|
||||
const uuid = require('uuid');
|
||||
|
||||
const AssetSchema = new Schema({
|
||||
@@ -58,11 +60,6 @@ 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).
|
||||
@@ -75,6 +72,25 @@ 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.
|
||||
*
|
||||
|
||||
+204
-92
@@ -1,9 +1,37 @@
|
||||
const mongoose = require('../mongoose');
|
||||
const Schema = mongoose.Schema;
|
||||
const uuid = require('uuid');
|
||||
const Action = require('./action');
|
||||
|
||||
const Schema = mongoose.Schema;
|
||||
/**
|
||||
* The Mongo schema for a Comment Status.
|
||||
* @type {Schema}
|
||||
*/
|
||||
const StatusSchema = new Schema({
|
||||
type: {
|
||||
type: String,
|
||||
enum: [
|
||||
'accepted',
|
||||
'rejected',
|
||||
'premod',
|
||||
],
|
||||
},
|
||||
|
||||
// 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,
|
||||
@@ -17,11 +45,7 @@ const CommentSchema = new Schema({
|
||||
},
|
||||
asset_id: String,
|
||||
author_id: String,
|
||||
status: {
|
||||
type: String,
|
||||
enum: ['accepted', 'rejected', ''],
|
||||
default: ''
|
||||
},
|
||||
status: [StatusSchema],
|
||||
parent_id: String
|
||||
}, {
|
||||
timestamps: {
|
||||
@@ -30,90 +54,168 @@ const CommentSchema = new Schema({
|
||||
}
|
||||
});
|
||||
|
||||
//==============================================================================
|
||||
// Find Statics
|
||||
//==============================================================================
|
||||
/**
|
||||
* 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();
|
||||
};
|
||||
|
||||
/**
|
||||
* Finds a comment by the id.
|
||||
* @param {String} id identifier of comment (uuid)
|
||||
* @return {Promise}
|
||||
*/
|
||||
CommentSchema.statics.findById = function(id) {
|
||||
return Comment.findOne({'id': id});
|
||||
};
|
||||
CommentSchema.statics.findById = (id) => Comment.findOne({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 = function(asset_id) {
|
||||
return Comment.find({asset_id});
|
||||
};
|
||||
CommentSchema.statics.findByAssetId = (asset_id) => 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 = function(asset_id) {
|
||||
return Comment.find({asset_id: asset_id, status:'accepted'});
|
||||
};
|
||||
CommentSchema.statics.findAcceptedByAssetId = (asset_id) => Comment.find({
|
||||
asset_id,
|
||||
'status.type': '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 = function(asset_id) {
|
||||
return Comment.find({asset_id: asset_id, status: {'$in': ['accepted', '']}});
|
||||
};
|
||||
CommentSchema.statics.findAcceptedAndNewByAssetId = (asset_id) => Comment.find({
|
||||
asset_id,
|
||||
$or: [
|
||||
{
|
||||
'status.type': 'accepted'
|
||||
},
|
||||
{
|
||||
status: {
|
||||
$size: 0
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
/**
|
||||
* 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 = function(action_type) {
|
||||
return Action
|
||||
.findCommentsIdByActionType(action_type, 'comment')
|
||||
.then((actions) => {
|
||||
return Comment.find({'id': {'$in': actions.map(function(a){
|
||||
return a.item_id;})}
|
||||
});
|
||||
});
|
||||
};
|
||||
CommentSchema.statics.findByActionType = (action_type) => Action
|
||||
.findCommentsIdByActionType(action_type, 'comment')
|
||||
.then((actions) => Comment.find({
|
||||
id: {
|
||||
$in: actions.map((a) => a.item_id)
|
||||
}
|
||||
}));
|
||||
|
||||
/**
|
||||
* Find not moderated comments by an action that was performed on them.
|
||||
* Find comment id's where the action type matches the argument.
|
||||
* @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.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)
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
CommentSchema.statics.findIdsByActionType = (action_type) => Action
|
||||
.findCommentsIdByActionType(action_type, 'comment')
|
||||
.then((actions) => 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 = function(status) {
|
||||
return Comment.find({
|
||||
status: status === 'new' ? '' : status
|
||||
});
|
||||
CommentSchema.statics.findByStatus = (status = false) => {
|
||||
let q = {};
|
||||
|
||||
if (status) {
|
||||
q['status.type'] = status;
|
||||
} else {
|
||||
q.status = {$size: 0};
|
||||
}
|
||||
|
||||
return Comment.find(q);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -121,39 +223,59 @@ CommentSchema.statics.findByStatus = function(status) {
|
||||
* @param {String} moderationValue pre or post moderation setting. If it is undefined then look at the settings.
|
||||
* @return {Promise}
|
||||
*/
|
||||
CommentSchema.statics.moderationQueue = function(moderation) {
|
||||
switch(moderation){
|
||||
CommentSchema.statics.moderationQueue = (moderation, asset_id = false) => {
|
||||
|
||||
// Pre-moderation: New comments are shown in the moderator queues immediately.
|
||||
case 'pre':
|
||||
return Comment.findByStatus('').then((comments) => {
|
||||
return comments;
|
||||
});
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
});
|
||||
return query;
|
||||
};
|
||||
|
||||
default:
|
||||
return Promise.reject(Error('Moderation setting not found.'));
|
||||
// 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
|
||||
}
|
||||
})));
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// Update Statics
|
||||
//==============================================================================
|
||||
return comments;
|
||||
};
|
||||
|
||||
/**
|
||||
* Change the status of a comment.
|
||||
* @param {String} id identifier of the comment (uuid)
|
||||
* @param {String} status the new status of the comment
|
||||
* 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
|
||||
* @return {Promise}
|
||||
*/
|
||||
CommentSchema.statics.changeStatus = function(id, status) {
|
||||
return Comment.findOneAndUpdate({'id': id}, {$set: {'status': status}});
|
||||
};
|
||||
CommentSchema.statics.pushStatus = (id, status, assigned_by = null) => Comment.update({id}, {
|
||||
$push: {
|
||||
status: {
|
||||
type: status,
|
||||
created_at: new Date(),
|
||||
assigned_by
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Add an action to the comment.
|
||||
@@ -169,19 +291,13 @@ 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 = function(id) {
|
||||
return Comment.remove({'id': id});
|
||||
};
|
||||
CommentSchema.statics.removeById = (id) => Comment.remove({id});
|
||||
|
||||
/**
|
||||
* Remove an action from the comment.
|
||||
@@ -190,22 +306,18 @@ CommentSchema.statics.removeById = function(id) {
|
||||
* @param {String} user_id the id of the user performing the action
|
||||
* @return {Promise}
|
||||
*/
|
||||
CommentSchema.statics.removeAction = function(item_id, user_id, action_type) {
|
||||
return Action.remove({
|
||||
action_type,
|
||||
item_type: 'comment',
|
||||
item_id,
|
||||
user_id
|
||||
});
|
||||
};
|
||||
CommentSchema.statics.removeAction = (item_id, user_id, action_type) => Action.remove({
|
||||
action_type,
|
||||
item_type: 'comment',
|
||||
item_id,
|
||||
user_id
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns all the comments in the collection.
|
||||
* @return {Promise}
|
||||
*/
|
||||
CommentSchema.statics.all = () => {
|
||||
return Comment.find();
|
||||
};
|
||||
CommentSchema.statics.all = () => Comment.find();
|
||||
|
||||
// Comment model.
|
||||
const Comment = mongoose.model('Comment', CommentSchema);
|
||||
|
||||
+77
-40
@@ -1,18 +1,33 @@
|
||||
const mongoose = require('../mongoose');
|
||||
const Schema = mongoose.Schema;
|
||||
const _ = require('lodash');
|
||||
const cache = require('../cache');
|
||||
|
||||
/**
|
||||
* 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
|
||||
* SettingSchema manages application settings that get used on front and backend.
|
||||
* @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: {
|
||||
@@ -22,48 +37,70 @@ const SettingSchema = new Schema({
|
||||
});
|
||||
|
||||
/**
|
||||
* this is run once when the app starts to ensure settings are populated
|
||||
* @return {Promise} null initialize the global settings object
|
||||
* The Mongo Mongoose object.
|
||||
*/
|
||||
SettingSchema.statics.init = function (defaults) {
|
||||
return this.update({id: '1'}, {$setOnInsert: defaults}, {upsert: true});
|
||||
};
|
||||
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;
|
||||
|
||||
/**
|
||||
* Gets the entire settings record and sends it back
|
||||
* @return {Promise} settings the whole settings record
|
||||
*/
|
||||
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');
|
||||
};
|
||||
SettingService.retrieve = () => cache.wrap('settings', EXPIRY_TIME, () => Setting.findOne(selector));
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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});
|
||||
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);
|
||||
};
|
||||
|
||||
const Setting = mongoose.model('Setting', SettingSchema);
|
||||
|
||||
module.exports = Setting;
|
||||
|
||||
+1
-2
@@ -9,7 +9,6 @@ const SALT_ROUNDS = 10;
|
||||
|
||||
// USER_ROLES is the array of roles that is permissible as a user role.
|
||||
const USER_ROLES = [
|
||||
'',
|
||||
'admin',
|
||||
'moderator'
|
||||
];
|
||||
@@ -106,7 +105,7 @@ UserSchema.index({
|
||||
* output.
|
||||
*/
|
||||
UserSchema.options.toJSON = {};
|
||||
UserSchema.options.toJSON.hide = 'password profiles roles disabled';
|
||||
UserSchema.options.toJSON.hide = '_id password profiles roles disabled';
|
||||
UserSchema.options.toJSON.transform = (doc, ret, options) => {
|
||||
if (options.hide) {
|
||||
options.hide.split(' ').forEach((prop) => {
|
||||
|
||||
@@ -89,6 +89,7 @@
|
||||
"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",
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
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');
|
||||
@@ -9,24 +10,45 @@ 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 (req.query.status) {
|
||||
query = Comment.findByStatus(req.query.status);
|
||||
} else if (req.query.action_type) {
|
||||
query = Comment.findByActionType(req.query.action_type);
|
||||
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
|
||||
},
|
||||
})));
|
||||
} else {
|
||||
query = Comment.all();
|
||||
query = assetIDWrap(Comment.all());
|
||||
}
|
||||
|
||||
query.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)
|
||||
]))
|
||||
Action.getActionSummariesFromComments(asset_id, comments, req.user ? req.user.id : false)
|
||||
]);
|
||||
})
|
||||
.then(([comments, users, actions])=>
|
||||
@@ -48,21 +70,38 @@ router.post('/', wordlist.filter('body'), (req, res, next) => {
|
||||
parent_id
|
||||
} = req.body;
|
||||
|
||||
Comment
|
||||
.create({
|
||||
body,
|
||||
asset_id,
|
||||
parent_id,
|
||||
status: req.wordlist.matched ? 'rejected' : '',
|
||||
author_id: req.user.id
|
||||
})
|
||||
.then((comment) => {
|
||||
// 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;
|
||||
|
||||
res.status(201).send(comment);
|
||||
})
|
||||
.catch((err) => {
|
||||
next(err);
|
||||
});
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
router.get('/:comment_id', authorization.needed('admin'), (req, res, next) => {
|
||||
@@ -99,7 +138,7 @@ router.put('/:comment_id/status', authorization.needed('admin'), (req, res, next
|
||||
} = req.body;
|
||||
|
||||
Comment
|
||||
.changeStatus(req.params.comment_id, status)
|
||||
.pushStatus(req.params.comment_id, status, req.user.id)
|
||||
.then(() => {
|
||||
res.status(204).end();
|
||||
})
|
||||
|
||||
+47
-21
@@ -3,6 +3,7 @@ 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();
|
||||
@@ -16,27 +17,52 @@ 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) => {
|
||||
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);
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@@ -4,19 +4,21 @@ const Setting = require('../../../models/setting');
|
||||
const router = express.Router();
|
||||
|
||||
router.get('/', (req, res, next) => {
|
||||
Setting
|
||||
.getSettings()
|
||||
.then(settings => {
|
||||
res.json(settings);
|
||||
})
|
||||
.catch(next);
|
||||
Setting.retrieve().then((settings) => {
|
||||
res.json(settings);
|
||||
})
|
||||
.catch((err) => {
|
||||
next(err);
|
||||
});
|
||||
});
|
||||
|
||||
router.put('/', (req, res, next) => {
|
||||
Setting
|
||||
.updateSettings(req.body)
|
||||
.then(() => res.status(204).end())
|
||||
.catch(next);
|
||||
Setting.update(req.body).then(() => {
|
||||
res.status(204).end();
|
||||
})
|
||||
.catch((err) => {
|
||||
next(err);
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@@ -26,14 +26,14 @@ router.get('/', (req, res, next) => {
|
||||
return asset;
|
||||
}),
|
||||
|
||||
// Get the public settings.
|
||||
Setting.getPublicSettings()
|
||||
// Get the moderation setting from the settings.
|
||||
Setting.retrieve()
|
||||
])
|
||||
.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.settings) {
|
||||
if (asset && asset.settings) {
|
||||
settings = Object.assign({}, settings, asset.settings);
|
||||
}
|
||||
|
||||
@@ -70,17 +70,7 @@ 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.getActionSummaries(_.uniq([
|
||||
|
||||
// Actions can be on assets...
|
||||
asset.id,
|
||||
|
||||
// Comments...
|
||||
...comments.map((comment) => comment.id),
|
||||
|
||||
// Or Authors...
|
||||
...userIDs
|
||||
]), req.user ? req.user.id : false);
|
||||
let actions = Action.getActionSummariesFromComments(asset.id, comments, req.user ? req.user.id : false);
|
||||
|
||||
return Promise.all([
|
||||
|
||||
@@ -108,7 +98,7 @@ router.get('/', (req, res, next) => {
|
||||
comments,
|
||||
users,
|
||||
actions,
|
||||
settings
|
||||
settings: Setting.public(settings)
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
@@ -20,7 +20,7 @@ const wordlist = {
|
||||
*/
|
||||
wordlist.init = () => {
|
||||
return Setting
|
||||
.getSettings()
|
||||
.retrieve()
|
||||
.then((settings) => {
|
||||
|
||||
// Insert the settings wordlist.
|
||||
|
||||
@@ -4,8 +4,12 @@
|
||||
"node": true,
|
||||
"mocha": true
|
||||
},
|
||||
"plugins": [
|
||||
"mocha"
|
||||
],
|
||||
"extends": "../.eslintrc.json",
|
||||
"rules": {
|
||||
"no-undef": [0]
|
||||
"no-undef": [0],
|
||||
"mocha/no-exclusive-tests": "warn"
|
||||
}
|
||||
}
|
||||
|
||||
+23
-24
@@ -1,35 +1,34 @@
|
||||
const Action = require('../../models/action');
|
||||
const expect = require('chai').expect;
|
||||
|
||||
describe('Action: models', () => {
|
||||
let mockActions;
|
||||
describe('models.Action', () => {
|
||||
let mockActions = [];
|
||||
|
||||
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;
|
||||
});
|
||||
});
|
||||
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;
|
||||
}));
|
||||
|
||||
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');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ const expect = chai.expect;
|
||||
// Use the chai should.
|
||||
chai.should();
|
||||
|
||||
describe('Asset: model', () => {
|
||||
describe('models.Asset', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
const defaults = {url:'http://test.com'};
|
||||
|
||||
+129
-23
@@ -7,35 +7,57 @@ const settings = {id: '1', moderation: 'pre'};
|
||||
|
||||
const expect = require('chai').expect;
|
||||
|
||||
describe('Comment: models', () => {
|
||||
describe('models.Comment', () => {
|
||||
const comments = [{
|
||||
body: 'comment 10',
|
||||
asset_id: '123',
|
||||
status: '',
|
||||
status: [],
|
||||
parent_id: '',
|
||||
author_id: '123',
|
||||
id: '1'
|
||||
}, {
|
||||
body: 'comment 20',
|
||||
asset_id: '123',
|
||||
status: 'accepted',
|
||||
status: [{
|
||||
type: '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: 'rejected',
|
||||
status: [{
|
||||
type: '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 = [{
|
||||
@@ -60,25 +82,69 @@ describe('Comment: models', () => {
|
||||
user_id: '456'
|
||||
}];
|
||||
|
||||
beforeEach(() => {
|
||||
return Promise.all([
|
||||
Setting.create(settings),
|
||||
Comment.create(comments),
|
||||
User.createLocalUsers(users),
|
||||
Action.create(actions)
|
||||
]);
|
||||
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');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
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);
|
||||
@@ -91,6 +157,7 @@ describe('Comment: models', () => {
|
||||
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);
|
||||
@@ -101,6 +168,7 @@ describe('Comment: models', () => {
|
||||
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);
|
||||
@@ -112,13 +180,16 @@ describe('Comment: models', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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;
|
||||
@@ -126,21 +197,56 @@ describe('Comment: models', () => {
|
||||
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');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
+9
-17
@@ -1,34 +1,29 @@
|
||||
const Setting = require('../../models/setting');
|
||||
const expect = require('chai').expect;
|
||||
|
||||
describe('Setting: model', () => {
|
||||
describe('models.Setting', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
const defaults = {
|
||||
id: 1
|
||||
};
|
||||
return Setting.update({id: '1'}, {$setOnInsert: defaults}, {upsert: true});
|
||||
});
|
||||
beforeEach(() => Setting.init({moderation: 'pre'}));
|
||||
|
||||
describe('#getSettings()', () => {
|
||||
describe('#retrieve()', () => {
|
||||
it('should have a moderation field defined', () => {
|
||||
return Setting.getSettings().then(settings => {
|
||||
return Setting.retrieve().then(settings => {
|
||||
expect(settings).to.have.property('moderation').and.to.equal('pre');
|
||||
});
|
||||
});
|
||||
|
||||
it('should have two infoBox fields defined', () => {
|
||||
return Setting.getSettings().then(settings => {
|
||||
return Setting.retrieve().then(settings => {
|
||||
expect(settings).to.have.property('infoBoxEnable').and.to.equal(false);
|
||||
expect(settings).to.have.property('infoBoxContent').and.to.equal('');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#updateSettings()', () => {
|
||||
describe('#update()', () => {
|
||||
it('should update the settings with a passed object', () => {
|
||||
const mockSettings = {moderation: 'post', infoBoxEnable: true, infoBoxContent: 'yeah'};
|
||||
return Setting.updateSettings(mockSettings).then(updatedSettings => {
|
||||
return Setting.update(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);
|
||||
@@ -37,13 +32,10 @@ describe('Setting: model', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getPublicSettings', () => {
|
||||
describe('#get', () => {
|
||||
it('should return the moderation settings', () => {
|
||||
return Setting.getPublicSettings().then(({moderation, infoBoxEnable, infoBoxContent, wordlist}) => {
|
||||
return Setting.retrieve().then(({moderation}) => {
|
||||
expect(moderation).not.to.be.null;
|
||||
expect(infoBoxEnable).not.to.be.null;
|
||||
expect(infoBoxContent).not.to.be.null;
|
||||
expect(wordlist).to.be.undefined;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const User = require('../../models/user');
|
||||
const expect = require('chai').expect;
|
||||
|
||||
describe('User: models', () => {
|
||||
describe('models.User', () => {
|
||||
let mockUsers;
|
||||
beforeEach(() => {
|
||||
return User.createLocalUsers([{
|
||||
|
||||
@@ -10,6 +10,7 @@ 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');
|
||||
|
||||
@@ -17,63 +18,71 @@ 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')
|
||||
@@ -91,7 +100,9 @@ describe('/api/v1/comments', () => {
|
||||
.set(passport.inject({roles: ['admin']}))
|
||||
.then((res) => {
|
||||
expect(res).to.have.status(200);
|
||||
expect(res.body.comments[0]).to.have.property('id', 'def-rejected');
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -102,7 +113,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', 'hij');
|
||||
expect(res.body.comments[0]).to.have.property('id', comments[3].id);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -124,8 +135,7 @@ 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', 'abc');
|
||||
|
||||
expect(res.body.comments[0]).to.have.property('id', comments[0].id);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -151,7 +161,31 @@ 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', 'rejected');
|
||||
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');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -267,18 +301,22 @@ 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: 'rejected'
|
||||
status: [{
|
||||
type: 'rejected'
|
||||
}]
|
||||
}, {
|
||||
id: 'hij',
|
||||
body: 'comment 30',
|
||||
asset_id: '456',
|
||||
status: 'accepted'
|
||||
status: [{
|
||||
type: 'accepted'
|
||||
}]
|
||||
}];
|
||||
|
||||
const users = [{
|
||||
@@ -316,10 +354,8 @@ 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');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,56 +15,54 @@ const User = require('../../../../models/user');
|
||||
const Setting = require('../../../../models/setting');
|
||||
const settings = {id: '1', moderation: 'pre'};
|
||||
|
||||
beforeEach(() => {
|
||||
return Setting.create(settings);
|
||||
});
|
||||
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'
|
||||
}]
|
||||
}];
|
||||
|
||||
describe('Get moderation queues rejected, pending, flags', () => {
|
||||
const users = [{
|
||||
displayName: 'Ana',
|
||||
email: 'ana@gmail.com',
|
||||
password: '123'
|
||||
}, {
|
||||
displayName: 'Maria',
|
||||
email: 'maria@gmail.com',
|
||||
password: '123'
|
||||
}];
|
||||
|
||||
describe('/api/v1/queue', () => {
|
||||
let comments;
|
||||
const actions = [{
|
||||
action_type: 'flag',
|
||||
item_id: 'abc',
|
||||
item_type: 'comment'
|
||||
}, {
|
||||
action_type: 'like',
|
||||
item_id: 'hij',
|
||||
item_type: 'comment'
|
||||
}];
|
||||
|
||||
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)
|
||||
beforeEach(() => {
|
||||
return User.createLocalUsers(users)
|
||||
.then((u) => {
|
||||
comments[0].author_id = u[0].id;
|
||||
comments[1].author_id = u[1].id;
|
||||
@@ -76,22 +74,24 @@ describe('Get moderation queues rejected, pending, flags', () => {
|
||||
actions[0].item_id = c[0].id;
|
||||
actions[1].item_id = c[1].id;
|
||||
|
||||
return Action.create(actions);
|
||||
return Promise.all([
|
||||
Action.create(actions),
|
||||
Setting.init(settings)
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -12,7 +12,7 @@ const defaults = {id: '1', moderation: 'pre'};
|
||||
|
||||
describe('/api/v1/settings', () => {
|
||||
|
||||
beforeEach(() => Setting.create(defaults));
|
||||
beforeEach(() => Setting.init(defaults));
|
||||
|
||||
describe('#get', () => {
|
||||
|
||||
@@ -40,7 +40,7 @@ describe('/api/v1/settings', () => {
|
||||
.then((res) => {
|
||||
expect(res).to.have.status(204);
|
||||
|
||||
return Setting.getSettings();
|
||||
return Setting.retrieve();
|
||||
})
|
||||
.then((settings) => {
|
||||
expect(settings).to.have.property('moderation', 'post');
|
||||
|
||||
@@ -20,7 +20,37 @@ describe('/api/v1/stream', () => {
|
||||
moderation: 'post'
|
||||
};
|
||||
|
||||
let comments;
|
||||
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'
|
||||
}]
|
||||
}];
|
||||
|
||||
const users = [{
|
||||
displayName: 'Ana',
|
||||
@@ -41,33 +71,6 @@ 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'),
|
||||
@@ -94,10 +97,11 @@ describe('/api/v1/stream', () => {
|
||||
return Promise.all([
|
||||
Comment.create(comments),
|
||||
Action.create(actions),
|
||||
Setting.init().then(() => Setting.updateSettings(settings))
|
||||
Setting.init(settings)
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return a stream with comments, users and actions for an existing asset', () => {
|
||||
return chai.request(app)
|
||||
.get('/api/v1/stream')
|
||||
|
||||
Reference in New Issue
Block a user