From 3285a5ec29a7e6482f246ba9b5d53bfedcc0e015 Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Thu, 12 Jan 2017 12:16:13 -0700 Subject: [PATCH] add status to Comment. /comments/pending and /comments/rejected ONLY return the respective comments --- client/coral-admin/src/actions/comments.js | 45 +++++++++- .../ModerationQueue/ModerationContainer.js | 18 +++- models/comment.js | 80 ++++-------------- routes/api/queue/index.js | 83 ++++++++++--------- 4 files changed, 119 insertions(+), 107 deletions(-) diff --git a/client/coral-admin/src/actions/comments.js b/client/coral-admin/src/actions/comments.js index e8276a9da..d897af3a5 100644 --- a/client/coral-admin/src/actions/comments.js +++ b/client/coral-admin/src/actions/comments.js @@ -6,10 +6,11 @@ import * as actionTypes from '../constants/actions'; export const fetchModerationQueueComments = () => { return dispatch => { dispatch({type: commentTypes.COMMENTS_MODERATION_QUEUE_FETCH_REQUEST}); + return Promise.all([ coralApi('/queue/comments/pending'), - coralApi('/comments?status=rejected'), - coralApi('/comments?action_type=flag') + coralApi('/queue/comments/rejected'), + coralApi('/queue/comments/flagged') ]) .then(([pending, rejected, flagged]) => { @@ -27,11 +28,49 @@ export const fetchModerationQueueComments = () => { dispatch({type: commentTypes.USERS_MODERATION_QUEUE_FETCH_SUCCESS, users}); dispatch({type: commentTypes.COMMENTS_MODERATION_QUEUE_FETCH_SUCCESS, comments}); dispatch({type: actionTypes.ACTIONS_MODERATION_QUEUE_FETCH_SUCCESS, actions}); - }); }; }; +export const fetchPendingQueue = () => { + return dispatch => { + dispatch({type: commentTypes.COMMENTS_MODERATION_QUEUE_FETCH_REQUEST}); + + return coralApi('/queue/comments/pending') + .then(pending => { + dispatch({type: commentTypes.USERS_MODERATION_QUEUE_FETCH_SUCCESS, users: pending.users}); + dispatch({type: commentTypes.COMMENTS_MODERATION_QUEUE_FETCH_SUCCESS, comments: pending.comments}); + dispatch({type: actionTypes.ACTIONS_MODERATION_QUEUE_FETCH_SUCCESS, actions: pending.actions}); + }); + }; +}; + +export const fetchRejectedQueue = () => { + return dispatch => { + dispatch({type: commentTypes.COMMENTS_MODERATION_QUEUE_FETCH_REQUEST}); + + return coralApi('/queue/comments/rejected') + .then(rejected => { + dispatch({type: commentTypes.USERS_MODERATION_QUEUE_FETCH_SUCCESS, users: rejected.users}); + dispatch({type: commentTypes.COMMENTS_MODERATION_QUEUE_FETCH_SUCCESS, comments: rejected.comments}); + dispatch({type: actionTypes.ACTIONS_MODERATION_QUEUE_FETCH_SUCCESS, actions: rejected.actions}); + }); + }; +}; + +export const fetchFlaggedQueue = () => { + return dispatch => { + dispatch({type: commentTypes.COMMENTS_MODERATION_QUEUE_FETCH_REQUEST}); + + return coralApi('/queue/comments/flagged') + .then(flagged => { + dispatch({type: commentTypes.USERS_MODERATION_QUEUE_FETCH_SUCCESS, users: flagged.users}); + dispatch({type: commentTypes.COMMENTS_MODERATION_QUEUE_FETCH_SUCCESS, comments: flagged.comments}); + dispatch({type: actionTypes.ACTIONS_MODERATION_QUEUE_FETCH_SUCCESS, actions: flagged.actions}); + }); + }; +}; + // Create a new comment export const createComment = (name, body) => { return (dispatch) => { diff --git a/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js b/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js index 8a684184a..d2c888e9e 100644 --- a/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js +++ b/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js @@ -6,7 +6,10 @@ import { updateStatus, showBanUserDialog, hideBanUserDialog, - fetchModerationQueueComments + fetchPendingQueue, + fetchRejectedQueue, + fetchFlaggedQueue, + fetchModerationQueueComments, } from 'actions/comments'; import {userStatusUpdate} from 'actions/users'; import {fetchSettings} from 'actions/settings'; @@ -54,6 +57,16 @@ class ModerationContainer extends React.Component { onTabClick(activeTab) { this.setState({activeTab}); + + if (activeTab === 'pending') { + this.props.fetchPendingQueue(); + } else if (activeTab === 'rejected') { + this.props.fetchRejectedQueue(); + } else if (activeTab === 'flagged') { + this.props.fetchFlaggedQueue(); + } else { + this.props.fetchModerationQueueComments(); + } } onClose() { @@ -90,6 +103,9 @@ const mapDispatchToProps = dispatch => { return { fetchSettings: () => dispatch(fetchSettings()), fetchModerationQueueComments: () => dispatch(fetchModerationQueueComments()), + fetchPendingQueue: () => dispatch(fetchPendingQueue()), + fetchRejectedQueue: () => dispatch(fetchRejectedQueue()), + fetchFlaggedQueue: () => dispatch(fetchFlaggedQueue()), showBanUserDialog: (userId, userName, commentId) => dispatch(showBanUserDialog(userId, userName, commentId)), hideBanUserDialog: () => dispatch(hideBanUserDialog(false)), banUser: (userId, commentId) => dispatch(userStatusUpdate('banned', userId, commentId)).then(() => { diff --git a/models/comment.js b/models/comment.js index 3f9ae1a65..9bd9163c4 100644 --- a/models/comment.js +++ b/models/comment.js @@ -47,6 +47,7 @@ const CommentSchema = new Schema({ asset_id: String, author_id: String, status_history: [StatusSchema], + status: {type: String, default: null}, parent_id: String }, { timestamps: { @@ -84,24 +85,6 @@ CommentSchema.method('filterForUser', function(user = false) { return this.toJSON(); }); -/** - * 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_history. - */ -CommentSchema.virtual('status').get(function() { - - // Here we are taking advantage of the fact that when documents are inserted - // for the new status on a comment that they are always appended to the end - // of the list in the order that they are inserted, hence, the last status - // is always the most recent. - if (this.status_history && this.status_history.length > 0) { - return this.status_history[this.status_history.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. @@ -118,7 +101,7 @@ CommentSchema.statics.publicCreate = (comment) => { body, asset_id, parent_id, - status = false, + status = null, author_id } = comment; @@ -130,6 +113,7 @@ CommentSchema.statics.publicCreate = (comment) => { type: status, created_at: new Date() }] : [], + status, author_id }); @@ -160,7 +144,7 @@ CommentSchema.statics.findByAssetId = (asset_id) => Comment.find({ */ CommentSchema.statics.findAcceptedByAssetId = (asset_id) => Comment.find({ asset_id, - 'status_history.type': 'accepted' + status: 'accepted' }); /** @@ -171,14 +155,8 @@ CommentSchema.statics.findAcceptedByAssetId = (asset_id) => Comment.find({ CommentSchema.statics.findAcceptedAndNewByAssetId = (asset_id) => Comment.find({ asset_id, $or: [ - { - 'status_history.type': 'accepted' - }, - { - status_history: { - $size: 0 - } - } + {status: 'accepted'}, + {status: null} ] }); @@ -205,28 +183,20 @@ CommentSchema.statics.findIdsByActionType = (action_type) => Action .then((actions) => actions.map(a => a.item_id)); /** - * Find comments by their status_history. - * @param {String} status the status of the comment to search for - * @return {Promise} + * Find comments by current status + * @param {String} status status of the comment to search for + * @return {Promise} resovles to comment array */ -CommentSchema.statics.findByStatus = (status = false) => { - let q = {}; - - if (status) { - q['status_history.type'] = status; - } else { - q.status_history = {$size: 0}; - } - - return Comment.find(q); +CommentSchema.statics.findByStatus = (status = null) => { + return Comment.find({status}); }; /** * Find comments that need to be moderated (aka moderation queue). - * @param {String} moderationValue pre or post moderation setting. If it is undefined then look at the settings. + * @param {String} asset_id * @return {Promise} */ -CommentSchema.statics.moderationQueue = (moderation, asset_id = false) => { +CommentSchema.statics.moderationQueue = (status, asset_id = null) => { /** * This adds the asset_id requirement to the query if the asset_id is defined. @@ -239,25 +209,8 @@ CommentSchema.statics.moderationQueue = (moderation, asset_id = false) => { return query; }; - // 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 - } - }))); - } + // Pre-moderation: New comments are shown in the moderator queues immediately. + let comments = assetIDWrap(Comment.findByStatus(status)); return comments; }; @@ -277,7 +230,8 @@ CommentSchema.statics.pushStatus = (id, status, assigned_by = null) => Comment.u created_at: new Date(), assigned_by } - } + }, + $set: {status} }); /** diff --git a/routes/api/queue/index.js b/routes/api/queue/index.js index 9c85fbe94..c629233f1 100644 --- a/routes/api/queue/index.js +++ b/routes/api/queue/index.js @@ -4,10 +4,22 @@ const User = require('../../../models/user'); const Action = require('../../../models/action'); const Setting = require('../../../models/setting'); const Asset = require('../../../models/asset'); +const authorization = require('../../../middleware/authorization'); const _ = require('lodash'); const router = express.Router(); +function gatherActionsAndUsers (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) + ])) + ]); +} + //============================================================================== // Get Routes //============================================================================== @@ -16,49 +28,40 @@ const router = express.Router(); // depending on the settings. The :moderation overwrites this settings. // 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) => { +router.get('/comments/pending', authorization.needed('admin'), (req, res, next) => { - const { - asset_id - } = req.query; + 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) - ])) - ]); - }) + Comment.moderationQueue('premod', asset_id) + .then(gatherActionsAndUsers) .then(([comments, users, actions]) => { - res.json({ - comments, - users, - actions - }); + res.json({comments, users, actions}); + }) + .catch(error => { + next(error); + }); +}); + +router.get('/comments/rejected', /*authorization.needed('admin'),*/ (req, res, next) => { + const {asset_id} = req.query; + + Comment.moderationQueue('rejected', asset_id) + .then(gatherActionsAndUsers) + .then(([comments, users, actions]) => { + res.json({comments, users, actions}); + }) + .catch(error => { + next(error); + }); +}); + +router.get('/comments/flagged', authorization.needed('admin'), (req, res, next) => { + const {asset_id} = req.query; + + Comment.moderationQueue('rejected', asset_id) + .then(gatherActionsAndUsers) + .then(([comments, users, actions]) => { + res.json({comments, users, actions}) }) .catch(error => { next(error);