From fb9bedc57b805e3ab14fb285a53445e47661cc9c Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 8 Feb 2017 17:41:11 -0700 Subject: [PATCH] Added new action rep, refactored mutations --- graph/loaders/actions.js | 10 + graph/mutators/action.js | 3 +- graph/resolvers/action.js | 8 + graph/resolvers/action_summary.js | 11 +- graph/resolvers/comment.js | 11 +- graph/resolvers/flag_action.js | 9 + graph/resolvers/flag_action_summary.js | 7 + graph/resolvers/generic_user_error.js | 3 + graph/resolvers/index.js | 18 +- graph/resolvers/like_action.js | 5 + graph/resolvers/root_mutation.js | 27 +- graph/resolvers/user.js | 10 +- graph/resolvers/user_error.js | 11 + graph/resolvers/validation_user_error.js | 3 + graph/schema.js | 7 + graph/typeDefs.graphql | 420 ++++++++++++++++++----- models/action.js | 6 + routes/api/comments/index.js | 17 - services/actions.js | 113 +++--- test/routes/api/comments/index.js | 76 ---- 20 files changed, 531 insertions(+), 244 deletions(-) create mode 100644 graph/resolvers/flag_action.js create mode 100644 graph/resolvers/flag_action_summary.js create mode 100644 graph/resolvers/generic_user_error.js create mode 100644 graph/resolvers/like_action.js create mode 100644 graph/resolvers/user_error.js create mode 100644 graph/resolvers/validation_user_error.js diff --git a/graph/loaders/actions.js b/graph/loaders/actions.js index c41f17219..2dd6472a0 100644 --- a/graph/loaders/actions.js +++ b/graph/loaders/actions.js @@ -5,6 +5,15 @@ const util = require('./util'); const ActionsService = require('../../services/actions'); const ActionModel = require('../../models/action'); +/** + * Gets actions based on their item id's. + */ +const genActionsByItemID = (_, item_ids) => { + return ActionsService + .findByItemIdArray(item_ids) + .then(util.arrayJoinBy(item_ids, 'item_id')); +}; + /** * Looks up actions based on the requested id's all bounded by the user. * @param {Object} context the context of the request @@ -35,6 +44,7 @@ const getItemIdsByActionTypeAndItemType = (_, action_type, item_type) => { */ module.exports = (context) => ({ Actions: { + getByID: new DataLoader((ids) => genActionsByItemID(context, ids)), getSummariesByItemID: new DataLoader((ids) => genActionSummariessByItemID(context, ids)), getByTypes: ({action_type, item_type}) => getItemIdsByActionTypeAndItemType(context, action_type, item_type) } diff --git a/graph/mutators/action.js b/graph/mutators/action.js index b5264fd49..12decd8cb 100644 --- a/graph/mutators/action.js +++ b/graph/mutators/action.js @@ -11,11 +11,12 @@ const UsersService = require('../../services/users'); * @param {String} action_type type of the action * @return {Promise} resolves to the action created */ -const createAction = ({user = {}}, {item_id, item_type, action_type, metadata = {}}) => { +const createAction = ({user = {}}, {item_id, item_type, action_type, group_id, metadata = {}}) => { return ActionsService.insertUserAction({ item_id, item_type, user_id: user.id, + group_id, action_type, metadata }).then((action) => { diff --git a/graph/resolvers/action.js b/graph/resolvers/action.js index f8aa60245..0962f59af 100644 --- a/graph/resolvers/action.js +++ b/graph/resolvers/action.js @@ -1,4 +1,12 @@ const Action = { + __resolveType({action_type}) { + switch (action_type) { + case 'FLAG': + return 'FlagAction'; + case 'LIKE': + return 'LikeAction'; + } + }, // This will load the user for the specific action. We'll limit this to the // admin users only or the current logged in user. diff --git a/graph/resolvers/action_summary.js b/graph/resolvers/action_summary.js index 48eff50c7..93848d285 100644 --- a/graph/resolvers/action_summary.js +++ b/graph/resolvers/action_summary.js @@ -1,3 +1,12 @@ -const ActionSummary = {}; +const ActionSummary = { + __resolveType({action_type}) { + switch (action_type) { + case 'FLAG': + return 'FlagActionSummary'; + case 'LIKE': + return 'LikeActionSummary'; + } + }, +}; module.exports = ActionSummary; diff --git a/graph/resolvers/comment.js b/graph/resolvers/comment.js index b3d79225e..41c10750b 100644 --- a/graph/resolvers/comment.js +++ b/graph/resolvers/comment.js @@ -13,7 +13,16 @@ const Comment = { replyCount({id}, _, {loaders: {Comments}}) { return Comments.countByParentID.load(id); }, - actions({id}, _, {loaders: {Actions}}) { + actions({id}, _, {user, loaders: {Actions}}) { + + // Only return the actions if the user is not an admin. + if (user && user.hasRoles('ADMIN')) { + return Actions.getByID.load(id); + } + + return null; + }, + action_summaries({id}, _, {loaders: {Actions}}) { return Actions.getSummariesByItemID.load(id); }, asset({asset_id}, _, {loaders: {Assets}}) { diff --git a/graph/resolvers/flag_action.js b/graph/resolvers/flag_action.js new file mode 100644 index 000000000..44cf7a410 --- /dev/null +++ b/graph/resolvers/flag_action.js @@ -0,0 +1,9 @@ +const FlagAction = { + + // Stored in the metadata, extract and return. + reason({metadata: {reason}}) { + return reason; + } +}; + +module.exports = FlagAction; diff --git a/graph/resolvers/flag_action_summary.js b/graph/resolvers/flag_action_summary.js new file mode 100644 index 000000000..58dda689e --- /dev/null +++ b/graph/resolvers/flag_action_summary.js @@ -0,0 +1,7 @@ +const FlagActionSummary = { + reason({group_id}) { + return group_id; + } +}; + +module.exports = FlagActionSummary; diff --git a/graph/resolvers/generic_user_error.js b/graph/resolvers/generic_user_error.js new file mode 100644 index 000000000..45b656f5b --- /dev/null +++ b/graph/resolvers/generic_user_error.js @@ -0,0 +1,3 @@ +const GenericUserError = {}; + +module.exports = GenericUserError; diff --git a/graph/resolvers/index.js b/graph/resolvers/index.js index f25664f34..84dd10fdc 100644 --- a/graph/resolvers/index.js +++ b/graph/resolvers/index.js @@ -1,21 +1,33 @@ -const Action = require('./action'); const ActionSummary = require('./action_summary'); +const Action = require('./action'); const Asset = require('./asset'); const Comment = require('./comment'); const Date = require('./date'); +const FlagActionSummary = require('./flag_action_summary'); +const FlagAction = require('./flag_action'); +const GenericUserError = require('./generic_user_error'); +const LikeAction = require('./like_action'); const RootMutation = require('./root_mutation'); const RootQuery = require('./root_query'); const Settings = require('./settings'); +const UserError = require('./user_error'); const User = require('./user'); +const ValidationUserError = require('./validation_user_error'); module.exports = { - Action, ActionSummary, + Action, Asset, Comment, Date, + FlagActionSummary, + FlagAction, + GenericUserError, + LikeAction, RootMutation, RootQuery, Settings, - User + UserError, + User, + ValidationUserError, }; diff --git a/graph/resolvers/like_action.js b/graph/resolvers/like_action.js new file mode 100644 index 000000000..12d10f81e --- /dev/null +++ b/graph/resolvers/like_action.js @@ -0,0 +1,5 @@ +const LikeAction = { + +}; + +module.exports = LikeAction; diff --git a/graph/resolvers/root_mutation.js b/graph/resolvers/root_mutation.js index ef46b839a..8369b7281 100644 --- a/graph/resolvers/root_mutation.js +++ b/graph/resolvers/root_mutation.js @@ -1,12 +1,31 @@ +/** + * Wraps up a promise to return an object with the resolution of the promise + * keyed at `key` or an error caught at `errors`. + */ +const wrapResponse = (key) => (promise) => { + return promise.then((value) => { + let res = {}; + if (key) { + res[key] = value; + } + return res; + }).catch((err) => ({ + errors: [err] + })); +}; + const RootMutation = { createComment(_, {asset_id, parent_id, body}, {mutators: {Comment}}) { - return Comment.create({asset_id, parent_id, body}); + return wrapResponse('comment')(Comment.create({asset_id, parent_id, body})); }, - createAction(_, {action}, {mutators: {Action}}) { - return Action.create(action); + createLike(_, {like: {item_id, item_type}}, {mutators: {Action}}) { + return wrapResponse('like')(Action.create({item_id, item_type, action_type: 'LIKE'})); + }, + createFlag(_, {flag: {item_id, item_type, reason, message}}, {mutators: {Action}}) { + return wrapResponse('flag')(Action.create({item_id, item_type, action_type: 'FLAG', group_id: reason, metadata: {message}})); }, deleteAction(_, {id}, {mutators: {Action}}) { - return Action.delete({id}); + return wrapResponse(null)(Action.delete({id})); }, }; diff --git a/graph/resolvers/user.js b/graph/resolvers/user.js index c75cdbf54..13efe29e9 100644 --- a/graph/resolvers/user.js +++ b/graph/resolvers/user.js @@ -1,7 +1,15 @@ const User = { - actions({id}, _, {loaders: {Actions}}) { + action_summaries({id}, _, {loaders: {Actions}}) { return Actions.getSummariesByItemID.load(id); }, + actions({id}, _, {user, loaders: {Actions}}) { + + // Only return the actions if the user is not an admin. + if (user && user.hasRoles('ADMIN')) { + return Actions.getByID.load(id); + } + + }, comments({id}, _, {loaders: {Comments}, user}) { // If the user is not an admin, only return comment list for the owner of diff --git a/graph/resolvers/user_error.js b/graph/resolvers/user_error.js new file mode 100644 index 000000000..3716fa126 --- /dev/null +++ b/graph/resolvers/user_error.js @@ -0,0 +1,11 @@ +const UserError = { + __resolveType({field_name}) { + if (field_name) { + return 'ValidationUserError'; + } + + return 'GenericUserError'; + } +}; + +module.exports = UserError; diff --git a/graph/resolvers/validation_user_error.js b/graph/resolvers/validation_user_error.js new file mode 100644 index 000000000..211a0e505 --- /dev/null +++ b/graph/resolvers/validation_user_error.js @@ -0,0 +1,3 @@ +const ValidationUserError = {}; + +module.exports = ValidationUserError; diff --git a/graph/schema.js b/graph/schema.js index b4b42b809..2fca1a87f 100644 --- a/graph/schema.js +++ b/graph/schema.js @@ -1,8 +1,15 @@ const tools = require('graphql-tools'); +const maskErrors = require('graphql-errors').maskErrors; const resolvers = require('./resolvers'); const typeDefs = require('./typeDefs'); const schema = tools.makeExecutableSchema({typeDefs, resolvers}); +if (process.env.NODE_ENV === 'production') { + + // Mask errors that are thrown if we are in a production environment. + maskErrors(schema); +} + module.exports = schema; diff --git a/graph/typeDefs.graphql b/graph/typeDefs.graphql index b1f9b82f7..a86596082 100644 --- a/graph/typeDefs.graphql +++ b/graph/typeDefs.graphql @@ -1,16 +1,82 @@ -# Establishes the ordering of the content by their created_at time stamp. -enum SORT_ORDER { - # newest to oldest order. - REVERSE_CHRONOLOGICAL - - # oldest to newer order. - CHRONOLOGICAL -} +################################################################################ +## Custom Scalar Types +################################################################################ # Date represented as an ISO8601 string. scalar Date +################################################################################ +## Users +################################################################################ + +# Roles that a user can have, these can be combined. +enum USER_ROLES { + + # an administrator of the site + ADMIN + + # a moderator of the site + MODERATOR +} + +# Any person who can author comments, create actions, and view comments on a +# stream. +type User { + + # The ID of the User. + id: ID! + + # display name of a user. + displayName: String! + + # Action summaries against the user. + action_summaries: [ActionSummary] + + # Actions completed on the parent. + actions: [Action] + + # the current roles of the user. + roles: [USER_ROLES] + + # determines whether the user can edit their username + canEditName: Boolean + + # returns all comments based on a query. + comments(query: CommentsQuery): [Comment] +} + +################################################################################ +## Comments +################################################################################ + +# The statuses that a comment may have. +enum COMMENT_STATUS { + + # The comment has been accepted by a moderator. + ACCEPTED + + # The comment has been rejected by a moderator. + REJECTED + + # The comment was created while the asset's premoderation option was on, and + # new comments that haven't been moderated yet are referred to as + # "premoderated" or "premod" comments. + PREMOD +} + +# The types of action there are as enum's. +enum ACTION_TYPE { + + # Represents a LikeAction. + LIKE + + # Represents a FlagAction. + FLAG +} + +# CommentsQuery allows the ability to query comments by a specific methods. input CommentsQuery { + # current status of a comment. statuses: [COMMENT_STATUS] @@ -34,109 +100,168 @@ input CommentsQuery { sort: SORT_ORDER = REVERSE_CHRONOLOGICAL } -enum USER_ROLES { - # an administrator of the site - ADMIN - - # a moderator of the site - MODERATOR -} - -# Any person who can author comments, create actions, and view comments on a -# stream. -type User { - id: ID! - - # display name of a user. - displayName: String! - - # actions against a specific user. - actions: [ActionSummary] - - # the current roles of the user. - roles: [USER_ROLES] - - # determines whether the user can edit their username - canEditName: Boolean - - # returns all comments based on a query. - comments(query: CommentsQuery): [Comment] -} - +# Comment is the base representation of user interaction in Talk. type Comment { + + # The ID of the comment. id: ID! - # the actual comment data. + # The actual comment data. body: String! - # the user who authored the comment. + # The user who authored the comment. user: User - # the replies that were made to the comment. + # The replies that were made to the comment. replies(sort: SORT_ORDER = CHRONOLOGICAL, limit: Int = 3): [Comment] - # the count of replies on a comment + # The count of replies on a comment. replyCount: Int - # the actions made against a comment. - actions: [ActionSummary] + # Actions completed on the parent. + actions: [Action] - # the asset that a comment was made on. + # Action summaries against a comment. + action_summaries: [ActionSummary] + + # The asset that a comment was made on. asset: Asset - # the current status of a comment. + # The current status of a comment. status: COMMENT_STATUS - # the time when the comment was created + # The time when the comment was created created_at: Date! } -enum ITEM_TYPE { - ASSETS - COMMENTS - USERS -} +################################################################################ +## Actions +################################################################################ -enum ACTION_TYPE { - LIKE - FLAG -} +# An action rendered against a parent enity item. +interface Action { -type Action { + # The ID of the action. id: ID! - action_type: ACTION_TYPE! - item_id: ID! - item_type: ITEM_TYPE! + # The author of the action. + user: User - user: User! + # The time when the Action was updated. updated_at: Date + + # The time when the Action was created. created_at: Date } -type ActionSummary { - action_type: ACTION_TYPE! - item_type: ITEM_TYPE! +# A summary of actions based on the specific grouping of the group_id. +interface ActionSummary { + + # The count of actions with this group. count: Int + + # The current user's action. current_user: Action } +# LikeAction is used by users who "like" a specific entity. +type LikeAction implements Action { + + # The ID of the action. + id: ID! + + # The author of the action. + user: User + + # The time when the Action was updated. + updated_at: Date + + # The time when the Action was created. + created_at: Date +} + +# LikeActionSummary is counts the amount of "likes" that a specific entity has. +type LikeActionSummary implements ActionSummary { + + # The count of likes against the parent entity. + count: Int! + + current_user: LikeAction +} + +# A FLAG action that contains flag metadata. +type FlagAction implements Action { + + # The ID of the Flag Action. + id: ID! + + # The reason for which the Flag Action was created. + reason: String + + # An optional message sent with the flagging action by the user. + message: String + + # The user who created the action. + user: User + + # The time when the Flag Action was updated. + updated_at: Date + + # The time when the Flag Action was created. + created_at: Date +} + +# Summary for Flag Action with a a unique reason. +type FlagActionSummary implements ActionSummary { + + # The total count of flags with this reason. + count: Int! + + # The reason for which the Flag Action was created. + reason: String + + # The flag by the current user against the parent entity with this reason. + current_user: FlagAction +} + +################################################################################ +## Settings +################################################################################ + +# The moderation mode of the site. enum MODERATION_MODE { + + # Comments posted while in `PRE` mode will be labeled with a `PREMOD` + # status and will require a moderator decision before being visible. PRE + + # Comments posted while in `POST` will be visible immediately. POST } +# Site wide global settings. type Settings { + + # Moderation mode for the site. moderation: MODERATION_MODE! + + # Enables a requirement for email confirmation before a user can login. + requireEmailConfirmation: Boolean + infoBoxEnable: Boolean infoBoxContent: String closeTimeout: Int closedMessage: String charCountEnable: Boolean charCount: Int - requireEmailConfirmation: Boolean + } +################################################################################ +## Assets +################################################################################ + +# Where comments are made on. type Asset { # The current ID of the asset. @@ -165,53 +290,178 @@ type Asset { created_at: Date } -enum COMMENT_STATUS { - ACCEPTED - REJECTED - PREMOD +################################################################################ +## Errors +################################################################################ + +# Any error rendered due to the user's input. +interface UserError { + + # Translation key relating to a translatable string containing details to be + # displayed to the end user. + translation_key: String! } +# A generic error not related to validation reasons. +type GenericUserError implements UserError { + + # Translation key relating to a translatable string containing details to be + # displayed to the end user. + translation_key: String! +} + +# A validation error that affects the input. +type ValidationUserError implements UserError { + + # Translation key relating to a translatable string containing details to be + # displayed to the end user. + translation_key: String! + + # The field in question that caused the error. + field_name: String! +} + +################################################################################ +## Queries +################################################################################ + +# Establishes the ordering of the content by their created_at time stamp. +enum SORT_ORDER { + + # newest to oldest order. + REVERSE_CHRONOLOGICAL + + # oldest to newer order. + CHRONOLOGICAL +} + +# All queries that can be executed. type RootQuery { - # retrieves site wide settings and defaults. + # Site wide settings and defaults. settings: Settings - # retrieves all assets. + # All assets. assets: [Asset] - # retrieves a specific asset. + # Find or create an asset by url, or just find with the ID. asset(id: ID, url: String): Asset - # retrieves comments based on the input query. + # Comments returned based on a query. comments(query: CommentsQuery!): [Comment] - # retrieves the current logged in user. + # The currently logged in user based on the request. me: User } -input CreateActionInput { - # the type of action. - action_type: ACTION_TYPE! +################################################################################ +## Mutations +################################################################################ - # the type of the item. - item_type: ITEM_TYPE! +# Response defines what can be expected from any response to a mutation action. +interface Response { - # the id of the item that is related to the action. + # An array of errors relating to the mutation that occured. + errors: [UserError] +} + +# CreateCommentResponse is returned with the comment that was created and any +# errors that may have occured in the attempt to create it. +type CreateCommentResponse implements Response { + + # The comment that was created. + comment: Comment + + # An array of errors relating to the mutation that occured. + errors: [UserError] +} + +# Used to represent the item type for an action. +enum ACTION_ITEM_TYPE { + + # The action references a entity of type Asset. + ASSETS + + # The action references a entity of type Comment. + COMMENTS + + # The action references a entity of type User. + USERS +} + +input CreateLikeInput { + + # The item's id for which we are to create a like. item_id: ID! + + # The type of the item for which we are to create the like. + item_type: ACTION_ITEM_TYPE! } +type CreateLikeResponse implements Response { + + # The like that was created. + like: LikeAction + + # An array of errors relating to the mutation that occured. + errors: [UserError] +} + +input CreateFlagInput { + + # The item's id for which we are to create a flag. + item_id: ID! + + # The type of the item for which we are to create the flag. + item_type: ACTION_ITEM_TYPE! + + # The reason for flagging the item. + reason: String! + + # An optional message sent with the flagging action by the user. + message: String +} + +# CreateFlagResponse is the response returned with possibly some errors +# relating to the creating the flag action attempt and possibly the flag that +# was created. +type CreateFlagResponse implements Response { + + # The like that was created. + flag: FlagAction + + # An array of errors relating to the mutation that occured. + errors: [UserError] +} + +# DeleteActionResponse is the response returned with possibly some errors +# relating to the delete action attempt. +type DeleteActionResponse implements Response { + + # An array of errors relating to the mutation that occured. + errors: [UserError] +} + +# All mutations for the application are defined on this object. type RootMutation { - # creates a comment on the asset. - createComment(asset_id: ID!, parent_id: ID, body: String!): Comment - # creates an action based on an input. - createAction(action: CreateActionInput!): Action + # Creates a comment on the asset. + createComment(asset_id: ID!, parent_id: ID, body: String!): CreateCommentResponse - # delete an action based on the action id. - deleteAction(id: ID!): Boolean + # Creates a like on an entity. + createLike(like: CreateLikeInput!): CreateLikeResponse + # Creates a flag on an entity. + createFlag(flag: CreateFlagInput!): CreateFlagResponse + + # Delete an action based on the action id. + deleteAction(id: ID!): DeleteActionResponse } +################################################################################ +## Schema +################################################################################ + schema { query: RootQuery mutation: RootMutation diff --git a/models/action.js b/models/action.js index ed871f56b..36d83574e 100644 --- a/models/action.js +++ b/models/action.js @@ -29,6 +29,12 @@ const ActionSchema = new Schema({ }, item_id: String, user_id: String, + + // The element that summaries will additionally group on in addtion to their action_type, item_type, and + // item_id. + group_id: String, + + // Additional metadata stored on the field. metadata: Schema.Types.Mixed }, { timestamps: { diff --git a/routes/api/comments/index.js b/routes/api/comments/index.js index 19346274d..96f3911d4 100644 --- a/routes/api/comments/index.js +++ b/routes/api/comments/index.js @@ -127,21 +127,4 @@ router.put('/:comment_id/status', authorization.needed('ADMIN'), (req, res, next }); }); -router.post('/:comment_id/actions', (req, res, next) => { - - const { - action_type, - metadata - } = req.body; - - CommentsService - .addAction(req.params.comment_id, req.user.id, action_type, metadata) - .then((action) => { - res.status(201).json(action); - }) - .catch((err) => { - next(err); - }); -}); - module.exports = router; diff --git a/services/actions.js b/services/actions.js index c336dd974..0bcb81af0 100644 --- a/services/actions.js +++ b/services/actions.js @@ -26,7 +26,8 @@ module.exports = class ActionsService { action_type: action.action_type, item_type: action.item_type, item_id: action.item_id, - user_id: action.user_id + user_id: action.user_id, + group_id: action.group_id }; // Create/Update the action. @@ -86,68 +87,70 @@ module.exports = class ActionsService { * @param {String} ids array of user identifiers (uuid) */ static getActionSummaries(item_ids, current_user_id = '') { - return ActionModel.aggregate([ - { - // only grab items that match the specified item id's - $match: { - item_id: { - $in: item_ids - } - } + // only grab items that match the specified item id's + let $match = { + item_id: { + $in: item_ids + } + }; + + let $group = { + + // group unique documents by these properties, we are leveraging the + // fact that each uuid is completly unique. + _id: { + item_id: '$item_id', + action_type: '$action_type', + group_id: '$group_id' }, - { - $group: { - // group unique documents by these properties, we are leveraging the - // fact that each uuid is completly unique. - _id: { - item_id: '$item_id', - action_type: '$action_type' - }, - - // and sum up all actions matching the above grouping criteria - count: { - $sum: 1 - }, - - // we are leveraging the fact that each uuid is completly unique and - // just grabbing the last instance of the item type here. - item_type: { - $last: '$item_type' - }, - - current_user: { - $max: { - $cond: { - if: { - $eq: ['$user_id', current_user_id], - }, - then: '$$CURRENT', - else: null - } - } - } - } + // and sum up all actions matching the above grouping criteria + count: { + $sum: 1 }, - { - $project: { - // suppress the _id field - _id: false, + // we are leveraging the fact that each uuid is completly unique and + // just grabbing the last instance of the item type here. + item_type: { + $first: '$item_type' + }, - // map the fields from the _id grouping down a level - item_id: '$_id.item_id', - action_type: '$_id.action_type', - - // map the field directly - count: '$count', - item_type: '$item_type', - - // set the current user to false here - current_user: '$current_user' + current_user: { + $max: { + $cond: { + if: { + $eq: ['$user_id', current_user_id], + }, + then: '$$CURRENT', + else: null + } } } + }; + + let $project = { + + // suppress the _id field + _id: false, + + // map the fields from the _id grouping down a level + item_id: '$_id.item_id', + action_type: '$_id.action_type', + group_id: '$_id.group_id', + + // map the field directly + count: '$count', + item_type: '$item_type', + + // set the current user to false here + current_user: '$current_user' + }; + + return ActionModel.aggregate([ + {$match}, + {$group}, + {$project} ]); } diff --git a/test/routes/api/comments/index.js b/test/routes/api/comments/index.js index c305f9f6b..0ee19fc5e 100644 --- a/test/routes/api/comments/index.js +++ b/test/routes/api/comments/index.js @@ -267,79 +267,3 @@ describe('/api/v1/comments/:comment_id', () => { }); }); }); - -describe('/api/v1/comments/:comment_id/actions', () => { - - const comments = [{ - id: 'abc', - body: 'comment 10', - asset_id: 'asset', - author_id: '123', - status_history: [] - }, { - id: 'def', - body: 'comment 20', - asset_id: 'asset', - author_id: '456', - status: 'REJECTED', - status_history: [{ - type: 'REJECTED' - }] - }, { - id: 'hij', - body: 'comment 30', - asset_id: '456', - status: 'ACCEPTED', - status_history: [{ - type: 'ACCEPTED' - }] - }]; - - const users = [{ - displayName: 'Ana', - email: 'ana@gmail.com', - password: '123456789' - }, { - displayName: 'Maria', - email: 'maria@gmail.com', - password: '123456789' - }]; - - const actions = [{ - action_type: 'FLAG', - item_type: 'COMMENTS', - item_id: 'abc' - }, { - action_type: 'LIKE', - item_type: 'COMMENTS', - item_id: 'hij' - }]; - - beforeEach(() => { - return SettingsService.init(settings).then(() => { - return Promise.all([ - CommentModel.create(comments), - UsersService.createLocalUsers(users), - ActionModel.create(actions) - ]); - }); - }); - - describe('#post', () => { - it('it should create an action', () => { - return chai.request(app) - .post('/api/v1/comments/abc/actions') - .set(passport.inject({id: '456', roles: ['ADMIN']})) - .send({'action_type': 'flag', 'metadata': {'reason': 'Comment is too awesome.'}}) - .then((res) => { - expect(res).to.have.status(201); - expect(res).to.have.body; - - expect(res.body).to.have.property('action_type', 'flag'); - expect(res.body).to.have.property('metadata'); - expect(res.body.metadata).to.deep.equal({'reason': 'Comment is too awesome.'}); - expect(res.body).to.have.property('item_id', 'abc'); - }); - }); - }); -});