From dc26fb1d2089706ae7589d0bd957bcddd55260f2 Mon Sep 17 00:00:00 2001 From: James Date: Sat, 4 Apr 2020 16:09:12 -0400 Subject: [PATCH] builds where input query type --- src/auth/jwt.js | 1 - src/graphql/buildQueryInputObjectType.js | 244 ------------------ src/graphql/init.js | 35 ++- src/graphql/resolvers/withPolicy.js | 21 ++ src/graphql/{ => schema}/buildObjectType.js | 28 +- src/graphql/schema/buildWhereInputType.js | 163 ++++++++++++ .../withNullableType.js} | 0 .../withTypeOperators.js} | 12 +- .../{ => utilities}/combineParentName.js | 0 src/graphql/{ => utilities}/formatName.js | 0 10 files changed, 228 insertions(+), 276 deletions(-) delete mode 100644 src/graphql/buildQueryInputObjectType.js create mode 100644 src/graphql/resolvers/withPolicy.js rename src/graphql/{ => schema}/buildObjectType.js (88%) create mode 100644 src/graphql/schema/buildWhereInputType.js rename src/graphql/{getTypeWithNullable.js => schema/withNullableType.js} (100%) rename src/graphql/{getTypeWithOperators.js => schema/withTypeOperators.js} (51%) rename src/graphql/{ => utilities}/combineParentName.js (100%) rename src/graphql/{ => utilities}/formatName.js (100%) diff --git a/src/auth/jwt.js b/src/auth/jwt.js index e3de69aaa5..6b547beed1 100644 --- a/src/auth/jwt.js +++ b/src/auth/jwt.js @@ -9,7 +9,6 @@ module.exports = (User, config) => { opts.secretOrKey = config.user.auth.secretKey; return new JwtStrategy(opts, (token, done) => { - console.log(`Token authenticated for user: ${token.email}`); User.findByUsername(token.email, (err, user) => { if (err || !user) done(null, false); return done(null, user); diff --git a/src/graphql/buildQueryInputObjectType.js b/src/graphql/buildQueryInputObjectType.js deleted file mode 100644 index bea06c5251..0000000000 --- a/src/graphql/buildQueryInputObjectType.js +++ /dev/null @@ -1,244 +0,0 @@ -const { - GraphQLString, - GraphQLFloat, - GraphQLBoolean, - GraphQLList, - GraphQLInterfaceType, - GraphQLEnumType, - GraphQLObjectType, -} = require('graphql'); - -const formatName = require('./formatName'); -const combineParentName = require('./combineParentName'); -const getTypeWithOperators = require('./getTypeWithOperators'); - -const buildQueryInputObjectType = ({ name, fields, parent }) => { - const fieldToSchemaMap = { - number: (field) => { - const type = GraphQLFloat; - return { - type: getTypeWithOperators( - field, - type, - parent, - ['equals', 'gte', 'gt', 'lte', 'lt', 'ne'], - ), - }; - }, - text: (field) => { - const type = GraphQLString; - return { - type: getTypeWithOperators( - field, - type, - parent, - ['equals', 'like', 'ne'], - ), - }; - }, - email: (field) => { - const type = GraphQLString; - return { - type: getTypeWithOperators( - field, - type, - parent, - ['equals', 'like', 'ne'], - ), - }; - }, - textarea: (field) => { - const type = GraphQLString; - return { - type: getTypeWithOperators( - field, - type, - parent, - ['equals', 'like', 'ne'], - ), - }; - }, - WYSIWYG: (field) => { - const type = GraphQLString; - return { - type: getTypeWithOperators( - field, - type, - parent, - ['equals', 'like', 'ne'], - ), - }; - }, - code: (field) => { - const type = GraphQLString; - return { - type: getTypeWithOperators( - field, - type, - parent, - ['equals', 'like', 'ne'], - ), - }; - }, - date: (field) => { - const type = GraphQLString; - return { - type: getTypeWithOperators( - field, - type, - parent, - ['equals', 'like', 'ne'], - ), - }; - }, - upload: () => { - const type = GraphQLString; - return { - type, - }; - }, - checkbox: field => ({ - type: getTypeWithOperators( - field, - GraphQLBoolean, - parent, - ['equals', 'ne'], - ), - }), - relationship: (field) => { - const type = GraphQLString; - const typeWithLocale = getLocalizedType( - field, - getTypeWithNullable(field, type), - ); - - return { - type: field.hasMany ? new GraphQLList(typeWithLocale) : typeWithLocale, - }; - }, - repeater: (field) => { - const fullName = combineParentName(parent, field.label); - - const type = buildObjectType(config, { - name: fullName, - fields: field.fields, - parent: fullName, - }); - - const typeWithNullable = new GraphQLList(getTypeWithNullable(field, type)); - - return { - type: getLocalizedType( - field, - typeWithNullable, - ), - }; - }, - group: (field) => { - const fullName = combineParentName(parent, field.label); - - const type = buildObjectType(config, { - name: fullName, - fields: field.fields, - parent: fullName, - }); - - return { - type, - }; - }, - select: (field) => { - const fullName = combineParentName(parent, field.label); - - const type = new GraphQLEnumType({ - name: fullName, - values: field.options.reduce((values, option) => { - if (typeof option === 'object' && option.value) { - return { - ...values, - [formatName(option.label)]: { - value: option.value, - }, - }; - } - - if (typeof option === 'string') { - return { - ...values, - [option]: { - value: option, - }, - }; - } - - return values; - }, {}), - }); - - const typeWithList = field.hasMany ? new GraphQLList(type) : type; - const typeWithNullable = getTypeWithNullable(field, typeWithList); - - return { - type: getLocalizedType( - field, - typeWithNullable, - ), - }; - }, - flexible: (field) => { - const blockTypes = field.blocks.reduce((blocks, block) => { - const formattedBlockName = formatName(block.labels.singular); - const fullName = `${combineParentName(parent, field.label)}_${formattedBlockName}`; - return { - ...blocks, - [block.slug]: buildObjectType(config, { - name: fullName, - fields: block.fields, - parent: fullName, - }), - }; - }, {}); - - return { - type: getLocalizedType( - field, - new GraphQLList(new GraphQLInterfaceType({ - name: combineParentName(parent, field.label), - fields: { - blockType: { - type: new GraphQLEnumType({ - name: `${combineParentName(parent, field.label)}_BlockType`, - values: field.blocks.reduce((values, block) => { - return { - ...values, - [block.slug]: { - value: block.slug, - }, - }; - }, {}), - }), - }, - blockName: { type: GraphQLString }, - }, - resolveType(value) { - return blockTypes[value.blockType]; - }, - })), - ), - }; - }, - }; - - return new GraphQLObjectType({ - name, - fields: fields.reduce((schema, field) => { - const fieldName = formatName(field.label); - return { - ...schema, - [fieldName]: fieldToSchemaMap[field.type](field), - }; - }, {}), - }); -}; - -module.exports = buildQueryInputObjectType; diff --git a/src/graphql/init.js b/src/graphql/init.js index 10832edfe1..c42da90c6c 100644 --- a/src/graphql/init.js +++ b/src/graphql/init.js @@ -1,7 +1,9 @@ const graphQLHTTP = require('express-graphql'); const { GraphQLObjectType, GraphQLString, GraphQLSchema } = require('graphql'); -const buildType = require('./buildObjectType'); -const buildInputObjectType = require('./buildInputObjectType'); +const buildType = require('./schema/buildObjectType'); +const buildWhereInputType = require('./schema/buildWhereInputType'); +const formatName = require('./utilities/formatName'); +const withPolicy = require('./resolvers/withPolicy'); const Query = { name: 'Query', @@ -38,30 +40,41 @@ function init() { Object.keys(this.collections).forEach((collectionKey) => { const collection = this.collections[collectionKey]; - const label = collection.config.labels.singular.replace(' ', ''); + const { + config: { + policies, + fields, + labels: { + singular: singularLabel, + }, + }, + } = collection; + + const label = formatName(singularLabel); collection.graphQLType = buildType(this.config, { name: label, - fields: collection.config.fields, + fields, parent: label, }); - collection.graphQLInputType = buildInputObjectType({ + collection.graphQLWhereInputType = buildWhereInputType({ name: label, - fields: collection.config.fields, + fields, + parent: label, }); Query.fields[label] = { type: collection.graphQLType, args: { - data: collection.graphQLInputType, + where: { type: collection.graphQLWhereInputType }, }, - resolve: async (_, { id }, context) => { + resolve: withPolicy(policies.read, async (_, args, context) => { + console.log(JSON.stringify(args); return { - id, - email: 'test', + image: 'test', }; - }, + }), }; }); diff --git a/src/graphql/resolvers/withPolicy.js b/src/graphql/resolvers/withPolicy.js new file mode 100644 index 0000000000..eb8a068935 --- /dev/null +++ b/src/graphql/resolvers/withPolicy.js @@ -0,0 +1,21 @@ +const { Forbidden } = require('../../errors'); + +const withPolicy = (policy, resolver) => (_, args, context) => { + const { user } = context; + + if (policy) { + if (!policy(user)) { + throw new Forbidden(); + } + + return resolver(_, args, context); + } + + if (user) { + return resolver(_, args, context); + } + + throw new Forbidden(); +}; + +module.exports = withPolicy; diff --git a/src/graphql/buildObjectType.js b/src/graphql/schema/buildObjectType.js similarity index 88% rename from src/graphql/buildObjectType.js rename to src/graphql/schema/buildObjectType.js index cabc2ebe72..6df4c7d1fd 100644 --- a/src/graphql/buildObjectType.js +++ b/src/graphql/schema/buildObjectType.js @@ -9,9 +9,9 @@ const { GraphQLObjectType, } = require('graphql'); -const formatName = require('./formatName'); -const combineParentName = require('./combineParentName'); -const getTypeWithNullable = require('./combineParentName'); +const formatName = require('../utilities/formatName'); +const combineParentName = require('../utilities/combineParentName'); +const withNullableType = require('./withNullableType'); const buildObjectType = (config, { name, fields, parent }) => { const getLocalizedType = (field, type) => { @@ -36,7 +36,7 @@ const buildObjectType = (config, { name, fields, parent }) => { return { type: getLocalizedType( field, - getTypeWithNullable(field, type), + withNullableType(field, type), ), }; }, @@ -45,7 +45,7 @@ const buildObjectType = (config, { name, fields, parent }) => { return { type: getLocalizedType( field, - getTypeWithNullable(field, type), + withNullableType(field, type), ), }; }, @@ -54,7 +54,7 @@ const buildObjectType = (config, { name, fields, parent }) => { return { type: getLocalizedType( field, - getTypeWithNullable(field, type), + withNullableType(field, type), ), }; }, @@ -63,7 +63,7 @@ const buildObjectType = (config, { name, fields, parent }) => { return { type: getLocalizedType( field, - getTypeWithNullable(field, type), + withNullableType(field, type), ), }; }, @@ -72,7 +72,7 @@ const buildObjectType = (config, { name, fields, parent }) => { return { type: getLocalizedType( field, - getTypeWithNullable(field, type), + withNullableType(field, type), ), }; }, @@ -81,7 +81,7 @@ const buildObjectType = (config, { name, fields, parent }) => { return { type: getLocalizedType( field, - getTypeWithNullable(field, type), + withNullableType(field, type), ), }; }, @@ -90,7 +90,7 @@ const buildObjectType = (config, { name, fields, parent }) => { return { type: getLocalizedType( field, - getTypeWithNullable(field, type), + withNullableType(field, type), ), }; }, @@ -99,7 +99,7 @@ const buildObjectType = (config, { name, fields, parent }) => { return { type: getLocalizedType( field, - getTypeWithNullable(field, type), + withNullableType(field, type), ), }; }, @@ -113,7 +113,7 @@ const buildObjectType = (config, { name, fields, parent }) => { const type = GraphQLString; const typeWithLocale = getLocalizedType( field, - getTypeWithNullable(field, type), + withNullableType(field, type), ); return { @@ -129,7 +129,7 @@ const buildObjectType = (config, { name, fields, parent }) => { parent: fullName, }); - const typeWithNullable = new GraphQLList(getTypeWithNullable(field, type)); + const typeWithNullable = new GraphQLList(withNullableType(field, type)); return { type: getLocalizedType( @@ -180,7 +180,7 @@ const buildObjectType = (config, { name, fields, parent }) => { }); const typeWithList = field.hasMany ? new GraphQLList(type) : type; - const typeWithNullable = getTypeWithNullable(field, typeWithList); + const typeWithNullable = withNullableType(field, typeWithList); return { type: getLocalizedType( diff --git a/src/graphql/schema/buildWhereInputType.js b/src/graphql/schema/buildWhereInputType.js new file mode 100644 index 0000000000..c8903765ec --- /dev/null +++ b/src/graphql/schema/buildWhereInputType.js @@ -0,0 +1,163 @@ +const { + GraphQLString, + GraphQLFloat, + GraphQLBoolean, + GraphQLList, + // GraphQLInterfaceType, + // GraphQLEnumType, + GraphQLInputObjectType, +} = require('graphql'); + +const formatName = require('../utilities/formatName'); +// const combineParentName = require('./combineParentName'); +const withTypeOperators = require('./withTypeOperators'); + +const buildWhereInputType = ({ name, fields, parent }) => { + const fieldToSchemaMap = { + number: (field) => { + const type = GraphQLFloat; + return { + type: withTypeOperators( + field, + type, + parent, + ['equals', 'gte', 'gt', 'lte', 'lt', 'not_equals'], + ), + }; + }, + text: (field) => { + const type = GraphQLString; + return { + type: withTypeOperators( + field, + type, + parent, + ['equals', 'like', 'not_equals'], + ), + }; + }, + email: (field) => { + const type = GraphQLString; + return { + type: withTypeOperators( + field, + type, + parent, + ['equals', 'like', 'not_equals'], + ), + }; + }, + textarea: (field) => { + const type = GraphQLString; + return { + type: withTypeOperators( + field, + type, + parent, + ['equals', 'like', 'not_equals'], + ), + }; + }, + WYSIWYG: (field) => { + const type = GraphQLString; + return { + type: withTypeOperators( + field, + type, + parent, + ['equals', 'like', 'not_equals'], + ), + }; + }, + code: (field) => { + const type = GraphQLString; + return { + type: withTypeOperators( + field, + type, + parent, + ['equals', 'like', 'not_equals'], + ), + }; + }, + date: (field) => { + const type = GraphQLString; + return { + type: withTypeOperators( + field, + type, + parent, + ['equals', 'like', 'not_equals'], + ), + }; + }, + upload: () => { + const type = GraphQLString; + return { + type, + }; + }, + checkbox: field => ({ + type: withTypeOperators( + field, + GraphQLBoolean, + parent, + ['equals', 'not_equals'], + ), + }), + }; + + const fieldTypes = fields.reduce((schema, field) => { + const getFieldSchema = fieldToSchemaMap[field.type]; + + if (getFieldSchema) { + return { + ...schema, + [formatName(field.label)]: getFieldSchema(field), + }; + } + + return schema; + }, {}); + + // fieldTypes.id = { + // text: (field) => { + // const type = GraphQLString; + // return { + // type: withTypeOperators( + // field, + // type, + // parent, + // ['equals', 'not_equals'], + // ), + // }; + // }, + // }; + + const fieldName = formatName(name); + + return new GraphQLInputObjectType({ + name: `${fieldName}Where`, + fields: { + ...fieldTypes, + OR: { + type: new GraphQLList(new GraphQLInputObjectType({ + name: `${fieldName}WhereOr`, + fields: { + ...fieldTypes, + }, + })), + }, + AND: { + type: new GraphQLList(new GraphQLInputObjectType({ + name: `${fieldName}WhereAnd`, + fields: { + ...fieldTypes, + }, + })), + }, + }, + }); +}; + +module.exports = buildWhereInputType; diff --git a/src/graphql/getTypeWithNullable.js b/src/graphql/schema/withNullableType.js similarity index 100% rename from src/graphql/getTypeWithNullable.js rename to src/graphql/schema/withNullableType.js diff --git a/src/graphql/getTypeWithOperators.js b/src/graphql/schema/withTypeOperators.js similarity index 51% rename from src/graphql/getTypeWithOperators.js rename to src/graphql/schema/withTypeOperators.js index 966c7233a9..ae65699517 100644 --- a/src/graphql/getTypeWithOperators.js +++ b/src/graphql/schema/withTypeOperators.js @@ -1,17 +1,17 @@ -const { GraphQLObjectType } = require('graphql'); -const combineParentName = require('./combineParentName'); +const { GraphQLInputObjectType } = require('graphql'); +const combineParentName = require('../utilities/combineParentName'); const getTypeWithOperators = (field, type, parent, operators) => { - const fullName = combineParentName(parent, field.label); - return new GraphQLObjectType({ + const fullName = `${combineParentName(parent, field.label)}_Operator`; + return new GraphQLInputObjectType({ name: fullName, fields: operators.reduce((fields, operator) => { return { ...fields, [operator]: { type }, - }, + }; }, {}), }); -} +}; module.exports = getTypeWithOperators; diff --git a/src/graphql/combineParentName.js b/src/graphql/utilities/combineParentName.js similarity index 100% rename from src/graphql/combineParentName.js rename to src/graphql/utilities/combineParentName.js diff --git a/src/graphql/formatName.js b/src/graphql/utilities/formatName.js similarity index 100% rename from src/graphql/formatName.js rename to src/graphql/utilities/formatName.js