From 94fd642e5c141cd16edcd4d0b9e284aaf4f5754e Mon Sep 17 00:00:00 2001 From: James Date: Sun, 12 Apr 2020 15:54:21 -0400 Subject: [PATCH] enables User and Upload graphql CRUD --- demo/collections/Upload.js | 7 ++ src/auth/graphql/register.js | 100 ++++++++++++++++++++++++++ src/auth/register.js | 20 +++--- src/collections/graphql/register.js | 4 +- src/graphql/index.js | 10 ++- src/graphql/schema/buildObjectType.js | 5 +- src/index.js | 2 +- src/uploads/graphql/register.js | 92 ++++++++++++++++++++++++ src/uploads/register.js | 12 ++-- src/uploads/routes.js | 4 +- 10 files changed, 231 insertions(+), 25 deletions(-) create mode 100644 src/auth/graphql/register.js create mode 100644 src/uploads/graphql/register.js diff --git a/demo/collections/Upload.js b/demo/collections/Upload.js index 1b132499a2..b7bee88ad6 100644 --- a/demo/collections/Upload.js +++ b/demo/collections/Upload.js @@ -14,6 +14,13 @@ module.exports = { destroy: user => checkRole(['user', 'admin'], user), }, fields: [ + { + name: 'alt', + label: 'Alt Text', + type: 'text', + required: true, + localized: true, + }, ], timestamps: true, }; diff --git a/src/auth/graphql/register.js b/src/auth/graphql/register.js new file mode 100644 index 0000000000..32eb40f7a6 --- /dev/null +++ b/src/auth/graphql/register.js @@ -0,0 +1,100 @@ +const { + GraphQLString, + GraphQLNonNull, + GraphQLInt, +} = require('graphql'); + +const formatName = require('../../graphql/utilities/formatName'); +const { + getCreate, getFind, getFindByID, getDelete, getUpdate, +} = require('../../collections/graphql/resolvers'); + +const buildPaginatedListType = require('../../graphql/schema/buildPaginatedListType'); + +function registerUser() { + const { + config: { + labels: { + singular, + plural, + }, + fields, + }, + } = this.User; + + const singularLabel = formatName(singular); + const pluralLabel = formatName(plural); + + this.User.graphQL = {}; + + this.User.graphQL.type = this.buildObjectType( + singularLabel, + fields, + singularLabel, + { + id: { type: GraphQLString }, + }, + ); + + this.User.graphQL.whereInputType = this.buildWhereInputType( + singularLabel, + fields, + singularLabel, + ); + + this.User.graphQL.mutationInputType = this.buildMutationInputType( + singularLabel, + fields, + singularLabel, + ); + + this.Query.fields[singularLabel] = { + type: this.User.graphQL.type, + args: { + id: { type: GraphQLString }, + locale: { type: this.types.localeInputType }, + fallbackLocale: { type: this.types.fallbackLocaleInputType }, + }, + resolve: getFindByID(this.config, this.User), + }; + + this.Query.fields[pluralLabel] = { + type: buildPaginatedListType(pluralLabel, this.User.graphQL.type), + args: { + where: { type: this.User.graphQL.whereInputType }, + locale: { type: this.types.localeInputType }, + fallbackLocale: { type: this.types.fallbackLocaleInputType }, + page: { type: GraphQLInt }, + limit: { type: GraphQLInt }, + sort: { type: GraphQLString }, + }, + resolve: getFind(this.config, this.User), + }; + + this.Mutation.fields[`create${singularLabel}`] = { + type: this.User.graphQL.type, + args: { + data: { type: this.User.graphQL.mutationInputType }, + }, + resolve: getCreate(this.config, this.User), + }; + + this.Mutation.fields[`update${singularLabel}`] = { + type: this.User.graphQL.type, + args: { + id: { type: new GraphQLNonNull(GraphQLString) }, + data: { type: this.User.graphQL.mutationInputType }, + }, + resolve: getUpdate(this.config, this.User), + }; + + this.Mutation.fields[`delete${singularLabel}`] = { + type: this.User.graphQL.type, + args: { + id: { type: new GraphQLNonNull(GraphQLString) }, + }, + resolve: getDelete(this.User), + }; +} + +module.exports = registerUser; diff --git a/src/auth/register.js b/src/auth/register.js index 5118ed189f..9e9ad4197e 100644 --- a/src/auth/register.js +++ b/src/auth/register.js @@ -12,20 +12,20 @@ function registerUser() { this.config.user.fields.push(...baseUserFields); const userSchema = buildCollectionSchema(this.config.user, this.config); userSchema.plugin(passportLocalMongoose, { usernameField: this.config.user.auth.useAsUsername }); - this.User = mongoose.model(this.config.user.labels.singular, userSchema); + this.User = { + config: this.config.user, + model: mongoose.model(this.config.user.labels.singular, userSchema), + }; - passport.use(this.User.createStrategy()); - passport.use(jwtStrategy(this.User, this.config)); - passport.serializeUser(this.User.serializeUser()); - passport.deserializeUser(this.User.deserializeUser()); + passport.use(this.User.model.createStrategy()); + passport.use(jwtStrategy(this.User.model, this.config)); + passport.serializeUser(this.User.model.serializeUser()); + passport.deserializeUser(this.User.model.deserializeUser()); passport.use(new AnonymousStrategy.Strategy()); - this.router.use(authRoutes(this.config, this.User)); + this.router.use(authRoutes(this.config, this.User.model)); - this.router.use(collectionRoutes({ - model: this.User, - config: this.config.user, - })); + this.router.use(collectionRoutes(this.User)); } module.exports = registerUser; diff --git a/src/collections/graphql/register.js b/src/collections/graphql/register.js index 679e3b16f2..5e6dde281e 100644 --- a/src/collections/graphql/register.js +++ b/src/collections/graphql/register.js @@ -32,7 +32,9 @@ function registerCollections() { singularLabel, fields, singularLabel, - true, + { + id: { type: GraphQLString }, + }, ); collection.graphQL.whereInputType = this.buildWhereInputType( diff --git a/src/graphql/index.js b/src/graphql/index.js index d22ecb4b22..7c0a2e7602 100644 --- a/src/graphql/index.js +++ b/src/graphql/index.js @@ -7,11 +7,15 @@ const buildBlockType = require('./schema/buildBlockType'); const buildLocaleInputType = require('./schema/buildLocaleInputType'); const buildFallbackLocaleInputType = require('./schema/buildFallbackLocaleInputType'); const registerCollections = require('../collections/graphql/register'); +const registerUser = require('../auth/graphql/register'); +const registerUpload = require('../uploads/graphql/register'); const buildWhereInputType = require('./schema/buildWhereInputType'); class GraphQL { - constructor(config, collections) { + constructor(config, collections, User, Upload) { this.config = config; + this.User = User; + this.Upload = Upload; this.collections = collections; this.init = this.init.bind(this); @@ -30,10 +34,14 @@ class GraphQL { this.buildWhereInputType = buildWhereInputType; this.buildObjectType = buildObjectType.bind(this); this.registerCollections = registerCollections.bind(this); + this.registerUser = registerUser.bind(this); + this.registerUpload = registerUpload.bind(this); } init() { this.registerCollections(); + this.registerUser(); + this.registerUpload(); const query = new GraphQLObjectType(this.Query); const mutation = new GraphQLObjectType(this.Mutation); diff --git a/src/graphql/schema/buildObjectType.js b/src/graphql/schema/buildObjectType.js index a4948bc122..ee47db81c4 100644 --- a/src/graphql/schema/buildObjectType.js +++ b/src/graphql/schema/buildObjectType.js @@ -17,7 +17,7 @@ const combineParentName = require('../utilities/combineParentName'); const withNullableType = require('./withNullableType'); const find = require('../../collections/queries/find'); -function buildObjectType(name, fields, parentName, addID) { +function buildObjectType(name, fields, parentName, baseFields = {}) { const fieldToSchemaMap = { number: field => ({ type: withNullableType(field, GraphQLFloat) }), text: field => ({ type: withNullableType(field, GraphQLString) }), @@ -241,9 +241,6 @@ function buildObjectType(name, fields, parentName, addID) { }, }; - const baseFields = {}; - if (addID) baseFields.id = { type: GraphQLString }; - const objectSchema = { name, fields: () => fields.reduce((schema, field) => { diff --git a/src/index.js b/src/index.js index 7d33cb18f6..1f236b16dc 100644 --- a/src/index.js +++ b/src/index.js @@ -56,7 +56,7 @@ class Payload { next(); }, passport.authenticate(['jwt', 'anonymous'], { session: false }), - new GraphQL(this.config, this.collections).init(), + new GraphQL(this.config, this.collections, this.User, this.Upload).init(), ); } diff --git a/src/uploads/graphql/register.js b/src/uploads/graphql/register.js new file mode 100644 index 0000000000..d1229036e6 --- /dev/null +++ b/src/uploads/graphql/register.js @@ -0,0 +1,92 @@ +const { + GraphQLString, + GraphQLNonNull, + GraphQLInt, +} = require('graphql'); + +const formatName = require('../../graphql/utilities/formatName'); +const { + getCreate, getFind, getFindByID, getDelete, getUpdate, +} = require('../../collections/graphql/resolvers'); + +const buildPaginatedListType = require('../../graphql/schema/buildPaginatedListType'); + +function registerUpload() { + const { + config: { + labels: { + singular, + plural, + }, + fields, + }, + } = this.Upload; + + const singularLabel = formatName(singular); + const pluralLabel = formatName(plural); + + this.Upload.graphQL = {}; + + this.Upload.graphQL.type = this.buildObjectType( + singularLabel, + fields, + singularLabel, + { + id: { type: GraphQLString }, + }, + ); + + this.Upload.graphQL.whereInputType = this.buildWhereInputType( + singularLabel, + fields, + singularLabel, + ); + + this.Upload.graphQL.mutationInputType = this.buildMutationInputType( + singularLabel, + fields, + singularLabel, + ); + + this.Query.fields[singularLabel] = { + type: this.Upload.graphQL.type, + args: { + id: { type: GraphQLString }, + locale: { type: this.types.localeInputType }, + fallbackLocale: { type: this.types.fallbackLocaleInputType }, + }, + resolve: getFindByID(this.config, this.Upload), + }; + + this.Query.fields[pluralLabel] = { + type: buildPaginatedListType(pluralLabel, this.Upload.graphQL.type), + args: { + where: { type: this.Upload.graphQL.whereInputType }, + locale: { type: this.types.localeInputType }, + fallbackLocale: { type: this.types.fallbackLocaleInputType }, + page: { type: GraphQLInt }, + limit: { type: GraphQLInt }, + sort: { type: GraphQLString }, + }, + resolve: getFind(this.config, this.Upload), + }; + + this.Mutation.fields[`update${singularLabel}`] = { + type: this.Upload.graphQL.type, + args: { + id: { type: new GraphQLNonNull(GraphQLString) }, + data: { type: this.Upload.graphQL.mutationInputType }, + }, + resolve: getUpdate(this.config, this.Upload), + }; + + this.Mutation.fields[`delete${singularLabel}`] = { + type: this.Upload.graphQL.type, + args: { + id: { type: new GraphQLNonNull(GraphQLString) }, + }, + resolve: getDelete(this.Upload), + }; +} + +module.exports = registerUpload; diff --git a/src/uploads/register.js b/src/uploads/register.js index cc134e1fb2..18bac18bb4 100644 --- a/src/uploads/register.js +++ b/src/uploads/register.js @@ -19,17 +19,17 @@ function registerUpload() { discriminatorKey: 'type', }); - this.Upload = mongoose.model(this.config.upload.labels.singular, uploadSchema); + this.Upload = { + model: mongoose.model(this.config.upload.labels.singular, uploadSchema), + config: this.config.upload, + }; // TODO: image type hard coded, but in the future we need some way of customizing how uploads are handled in customizable pattern - this.Upload.discriminator('image', imageSchema); + this.Upload.model.discriminator('image', imageSchema); this.router.use(uploadRoutes(this.config, this.Upload)); - this.router.use(collectionRoutes({ - model: this.Upload, - config: this.config.upload, - })); + this.router.use(collectionRoutes(this.Upload)); } module.exports = registerUpload; diff --git a/src/uploads/routes.js b/src/uploads/routes.js index d3e58921d3..b5f3f317f1 100644 --- a/src/uploads/routes.js +++ b/src/uploads/routes.js @@ -7,12 +7,12 @@ const uploadMiddleware = require('./middleware'); const router = express.Router(); const uploadRoutes = (config, Upload) => { - const { upload: uploadConfig } = config; + const { config: uploadConfig, model } = Upload; router.all(`/${uploadConfig.slug}*`, fileUpload(), passport.authenticate('jwt', { session: false }), - uploadMiddleware(config, Upload)); + uploadMiddleware(config, model)); router.route(`/${uploadConfig.slug}`) .post(