From 52ed18a9b8fb37ea6233a1e5e616033dd322a8e9 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 18 Jan 2017 11:23:47 -0700 Subject: [PATCH] Added comments --- routes/api/graph/index.js | 9 ++++---- routes/api/graph/loaders.js | 42 +++++++++++++++++++++++++++++++++++- routes/api/graph/mutators.js | 32 +++++++++++++++++++++++++-- routes/api/graph/schema.js | 8 +++++++ routes/api/graph/typeDefs.js | 2 +- 5 files changed, 85 insertions(+), 8 deletions(-) create mode 100644 routes/api/graph/schema.js diff --git a/routes/api/graph/index.js b/routes/api/graph/index.js index e97cfcadb..1e737fd53 100644 --- a/routes/api/graph/index.js +++ b/routes/api/graph/index.js @@ -1,14 +1,13 @@ const express = require('express'); const apollo = require('graphql-server-express'); -const tools = require('graphql-tools'); -const resolvers = require('./resolvers'); -const typeDefs = require('./typeDefs'); + const loaders = require('./loaders'); const mutators = require('./mutators'); +const schema = require('./schema'); -const schema = tools.makeExecutableSchema({typeDefs, resolvers}); const router = express.Router(); +// GraphQL endpoint. router.use('/ql', apollo.graphqlExpress((req) => { let context = {req}; @@ -21,6 +20,8 @@ router.use('/ql', apollo.graphqlExpress((req) => { context }; })); + +// Interactive graphiql interface. router.use('/iql', apollo.graphiqlExpress({endpointURL: '/api/v1/graph/ql'})); module.exports = router; diff --git a/routes/api/graph/loaders.js b/routes/api/graph/loaders.js index 2d7ed4f69..d6534450c 100644 --- a/routes/api/graph/loaders.js +++ b/routes/api/graph/loaders.js @@ -7,6 +7,9 @@ const Action = require('../../../models/action'); const Asset = require('../../../models/asset'); const Settings = require('../../../models/setting'); +/** + * SingletonResolver is a cached loader for a single result. + */ class SingletonResolver { constructor(resolver) { this._cache = null; @@ -29,6 +32,13 @@ class SingletonResolver { } } +/** + * This joins a set of results with a specific keys and sets an empty array in + * place if it was not found. + * @param {Array} ids ids to locate + * @param {String} key key to group by + * @return {Array} array of results + */ const arrayJoinBy = (ids, key) => (items) => { const itemsByKey = _.groupBy(items, key); return ids.map((id) => { @@ -40,6 +50,13 @@ const arrayJoinBy = (ids, key) => (items) => { }); }; +/** + * This joins a set of results with a specific keys and sets null in place if it + * was not found. + * @param {Array} ids ids to locate + * @param {String} key key to group by + * @return {Array} array of results + */ const singleJoinBy = (ids, key) => (items) => { const itemsByKey = _.groupBy(items, key); return ids.map((id) => { @@ -51,14 +68,26 @@ const singleJoinBy = (ids, key) => (items) => { }); }; +/** + * Retrieves assets by an array of ids. + * @param {Array} ids array of ids to lookup + */ const genAssetByID = (ids) => Asset.find({ id: { $in: ids } }).then(singleJoinBy(ids, 'id')); +/** + * Retrieves actions by an array of ids. + * @param {Array} ids array of ids to lookup + */ const genActionsByID = (ids, user = {}) => Action.getActionSummaries(ids, user.id).then(arrayJoinBy(ids, 'item_id')); +/** + * Retrieves comments by an array of asset id's. + * @param {Array} ids array of ids to lookup + */ const genCommentsByAssetID = (ids) => Comment.find({ asset_id: { $in: ids @@ -69,6 +98,10 @@ const genCommentsByAssetID = (ids) => Comment.find({ } }).then(arrayJoinBy(ids, 'asset_id')); +/** + * Retrieves comments by an array of parent ids. + * @param {Array} ids array of ids to lookup + */ const genCommentsByParentID = (ids) => Comment.find({ parent_id: { $in: ids @@ -78,7 +111,12 @@ const genCommentsByParentID = (ids) => Comment.find({ } }).then(arrayJoinBy(ids, 'parent_id')); -module.exports = (context) => ({ +/** + * Creates a set of loaders based on a GraphQL context. + * @param {Object} context the context of the GraphQL request + * @return {Object} object of loaders + */ +const createLoaders = (context) => ({ Comments: { getByParentID: new DataLoader((ids) => genCommentsByParentID(ids)), getByAssetID: new DataLoader((ids) => genCommentsByAssetID(ids)), @@ -95,3 +133,5 @@ module.exports = (context) => ({ }, Settings: new SingletonResolver(() => Settings.retrieve()) }); + +module.exports = createLoaders; diff --git a/routes/api/graph/mutators.js b/routes/api/graph/mutators.js index 157d715db..3d97cc1bd 100644 --- a/routes/api/graph/mutators.js +++ b/routes/api/graph/mutators.js @@ -3,7 +3,18 @@ const errors = require('../../../errors'); const Asset = require('../../../models/asset'); const Comment = require('../../../models/comment'); -const createComment = (context, {body, asset_id, parent_id}, wordlist = {}) => { +const Wordlist = require('../../../services/wordlist'); + +/** + * Creates a new comment. + * @param {Object} context a GraphQL context + * @param {String} body body of the comment + * @param {String} asset_id asset for the comment + * @param {String} parent_id optional parent of the comment + * @param {Object} [wordlist={}] results for the wordlist analysis + * @return {Promise} resolves to the created comment + */ +const createComment = (context, {body, asset_id, parent_id = null}, wordlist = {}) => { // 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 @@ -60,6 +71,23 @@ const createComment = (context, {body, asset_id, parent_id}, wordlist = {}) => { }); }; +/** + * Filters the comment and outputs the wordlist results. + * @param {[type]} context [description] + * @param {[type]} comment [description] + * @return {[type]} [description] + */ +const filterNewComment = (context, comment) => { + + // Create a new instance of the Wordlist. + const wl = new Wordlist(); + + // Load the wordlist and filter the comment content. + return wl.load().then(() => wl.filter(comment, 'body')); +}; + module.exports = (context) => ({ - createComment: (comment) => createComment(context, comment) + createComment: (comment) => filterNewComment(context, comment).then((wordlist) => { + return createComment(context, comment, wordlist); + }) }); diff --git a/routes/api/graph/schema.js b/routes/api/graph/schema.js new file mode 100644 index 000000000..b4b42b809 --- /dev/null +++ b/routes/api/graph/schema.js @@ -0,0 +1,8 @@ +const tools = require('graphql-tools'); + +const resolvers = require('./resolvers'); +const typeDefs = require('./typeDefs'); + +const schema = tools.makeExecutableSchema({typeDefs, resolvers}); + +module.exports = schema; diff --git a/routes/api/graph/typeDefs.js b/routes/api/graph/typeDefs.js index ba4a5c7f1..51e74b5d3 100644 --- a/routes/api/graph/typeDefs.js +++ b/routes/api/graph/typeDefs.js @@ -50,7 +50,7 @@ type Asset { type Query { settings: Settings assets: [Asset] - asset(id: ID!): Asset! + asset(id: ID!): Asset } type Mutation {