diff --git a/graph/loaders/comments.js b/graph/loaders/comments.js index 24b66f4bd..a6b808ef2 100644 --- a/graph/loaders/comments.js +++ b/graph/loaders/comments.js @@ -68,6 +68,38 @@ const getCountsByParentID = (context, parent_ids) => { .then((results) => results.map((result) => result ? result.count : 0)); }; +/** + * Retrieves the count of comments based on the passed in query. + * @param {Object} context graph context + * @param {Object} query query to execute against the comments collection + * to compute the counts + * @return {Promise} resolves to the counts of the comments from the + * query + */ +const getCommentCountByQuery = (context, {ids, statuses, asset_id, parent_id}) => { + let query = CommentModel.find(); + + if (ids) { + query = query.where({id: {$in: ids}}); + } + + if (statuses) { + query = query.where({status: {$in: statuses}}); + } + + if (asset_id != null) { + query = query.where({asset_id}); + } + + if (parent_id !== undefined) { + query = query.where({parent_id}); + } + + return CommentModel + .find(query) + .count(); +}; + /** * Retrieves comments based on the passed in query that is filtered by the * current used passed in via the context. @@ -233,6 +265,7 @@ const genRecentComments = (_, ids) => { module.exports = (context) => ({ Comments: { getByQuery: (query) => getCommentsByQuery(context, query), + getCountByQuery: (query) => getCommentCountByQuery(context, query), countByAssetID: new util.SharedCacheDataLoader('Comments.countByAssetID', 3600, (ids) => getCountsByAssetID(context, ids)), countByParentID: new util.SharedCacheDataLoader('Comments.countByParentID', 3600, (ids) => getCountsByParentID(context, ids)), genRecentReplies: new DataLoader((ids) => genRecentReplies(context, ids)), diff --git a/graph/resolvers/root_query.js b/graph/resolvers/root_query.js index eb66274dd..ced4e65cf 100644 --- a/graph/resolvers/root_query.js +++ b/graph/resolvers/root_query.js @@ -39,6 +39,23 @@ const RootQuery = { return Comments.getByQuery(query); }, + commentCount(_, {query: {action_type, statuses, asset_id, parent_id}}, {user, loaders: {Actions, Comments}}) { + if (user == null || !user.hasRoles('ADMIN')) { + return null; + } + + if (action_type) { + return Actions.getByTypes({action_type, item_type: 'COMMENTS'}) + .then((ids) => { + + // Perform the query using the available resolver. + return Comments.getCountByQuery({ids, statuses, asset_id, parent_id}); + }); + } + + return Comments.getCountByQuery({statuses, asset_id, parent_id}); + }, + metrics(_, {from, to, sort, limit = 10}, {user, loaders: {Metrics}}) { if (user == null || !user.hasRoles('ADMIN')) { return null; diff --git a/graph/typeDefs.graphql b/graph/typeDefs.graphql index cabb50985..72a54a0cd 100644 --- a/graph/typeDefs.graphql +++ b/graph/typeDefs.graphql @@ -27,7 +27,7 @@ type User { # The ID of the User. id: ID! - # username of a user. + # Username of a user. username: String! # Action summaries against the user. @@ -96,10 +96,40 @@ enum ACTION_TYPE { # CommentsQuery allows the ability to query comments by a specific methods. input CommentsQuery { - # current status of a comment. + # Current status of a comment. Requires the `ADMIN` role. statuses: [COMMENT_STATUS!] - # asset that a comment is on. + # Asset that a comment is on. + asset_id: ID + + # The parent of the comment that we want to retrieve. + parent_id: ID + + # Comments returned will only be ones which have at least one action of this + # type. Requires the `ADMIN` role. + action_type: ACTION_TYPE + + # Limit the number of results to be returned. + limit: Int = 10 + + # Skip results from the last created_at timestamp. + cursor: Date + + # Filter by a specific tag name. + tag: [String] + + # Sort the results by created_at. + sort: SORT_ORDER = REVERSE_CHRONOLOGICAL +} + +# CommentCountQuery allows the ability to query comment counts by specific +# methods. +input CommentCountQuery { + + # Current status of a comment. Requires the `ADMIN` role. + statuses: [COMMENT_STATUS!] + + # Asset that a comment is on. asset_id: ID # the parent of the comment that we want to retrieve. @@ -109,17 +139,8 @@ input CommentsQuery { # type. action_type: ACTION_TYPE - # limit the number of results to be returned. - limit: Int = 10 - - # skip results from the last created_at timestamp. - cursor: Date - - # filter by a specific tag name. + # Filter by a specific tag name. tag: [String] - - # sort the results by created_at. - sort: SORT_ORDER = REVERSE_CHRONOLOGICAL } # Comment is the base representation of user interaction in Talk. @@ -146,7 +167,7 @@ type Comment { # The count of replies on a comment. replyCount: Int - # Actions completed on the parent. + # Actions completed on the parent. Requires the `ADMIN` role. actions: [Action] # Action summaries against a comment. @@ -350,7 +371,7 @@ type Asset { closedAt: Date # Summary of all Actions against all entities associated with the Asset. - # (likes, flags, etc.) + # (likes, flags, etc.). Requires the `ADMIN` role. action_summaries: [AssetActionSummary] # The date that the asset was created. @@ -418,7 +439,7 @@ type RootQuery { # Site wide settings and defaults. settings: Settings - # All assets. + # All assets. Requires the `ADMIN` role. assets: [Asset] # Find or create an asset by url, or just find with the ID. @@ -427,7 +448,12 @@ type RootQuery { # Comments returned based on a query. comments(query: CommentsQuery!): [Comment] - # The currently logged in user based on the request. + # Returne the count of comments satisfied by the query. Note that this edge is + # expensive as it is not batched. Requires the `ADMIN` role. + commentCount(query: CommentCountQuery!): Int + + # The currently logged in user based on the request. Requires any logged in + # role. me: User # Metrics related to user actions are saturated into the assets returned. The @@ -554,10 +580,10 @@ type RootMutation { # Delete an action based on the action id. deleteAction(id: ID!): DeleteActionResponse - # Sets User status + # Sets User status. Requires the `ADMIN` role. setUserStatus(id: ID!, status: USER_STATUS!): SetUserStatusResponse - # Sets Comment status + # Sets Comment status. Requires the `ADMIN` role. setCommentStatus(id: ID!, status: COMMENT_STATUS!): SetCommentStatusResponse } diff --git a/yarn.lock b/yarn.lock index f1c047be2..5413439fa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -175,11 +175,11 @@ anymatch@^1.3.0: arrify "^1.0.0" micromatch "^2.1.5" -apollo-client@^0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/apollo-client/-/apollo-client-0.7.3.tgz#f27702409ce4b90c3adbd78d8434c3e8d762c7dd" +apollo-client@^0.8.3: + version "0.8.6" + resolved "https://registry.yarnpkg.com/apollo-client/-/apollo-client-0.8.6.tgz#9aa18b03ec338f0a3804122df7f77493a10b72a0" dependencies: - graphql-anywhere "^2.0.0" + graphql-anywhere "^2.1.0" graphql-tag "^1.1.1" redux "^3.4.0" symbol-observable "^1.0.2" @@ -3303,7 +3303,7 @@ graceful-fs@~2.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" -graphql-anywhere@^2.0.0: +graphql-anywhere@^2.0.0, graphql-anywhere@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/graphql-anywhere/-/graphql-anywhere-2.1.0.tgz#888c0a1718db3ff866b313070747777380560f69" @@ -6375,9 +6375,9 @@ react-addons-test-utils@15.3.2: version "15.3.2" resolved "https://registry.yarnpkg.com/react-addons-test-utils/-/react-addons-test-utils-15.3.2.tgz#c09a44f583425a4a9c1b38444d7a6c3e6f0f41f6" -react-apollo@^0.8.1: - version "0.8.3" - resolved "https://registry.yarnpkg.com/react-apollo/-/react-apollo-0.8.3.tgz#e799bdc913948bb487dfa90921b2ea8d08464816" +react-apollo@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/react-apollo/-/react-apollo-0.10.1.tgz#97fd50855f8575672aa68330b9c64a201cd13343" dependencies: graphql-anywhere "^2.0.0" hoist-non-react-statics "^1.2.0"