mirror of
https://github.com/wassname/talk.git
synced 2026-08-16 11:29:31 +08:00
Revert "Revert "Status history""
This commit is contained in:
@@ -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) => {
|
||||
|
||||
Reference in New Issue
Block a user