From 3d563732478a1e796ef767b6bf646dbe428de74c Mon Sep 17 00:00:00 2001 From: James Date: Tue, 9 Jun 2020 13:32:23 -0400 Subject: [PATCH] adds secondary auth collection Customers, modifies GraphQL policies to suit multiple auth collections --- demo/collections/Customers.js | 46 ++++++++++++++++++++++++++ demo/payload.public.config.js | 2 ++ src/auth/graphql/resolvers/policies.js | 22 ++++++++++-- src/auth/operations/policies.js | 15 +++++---- src/auth/requestHandlers/policies.js | 1 - src/auth/routes.js | 5 --- src/collections/graphql/init.js | 14 ++++---- src/fields/sanitize.js | 2 ++ src/graphql/index.js | 6 ++++ src/index.js | 4 +++ 10 files changed, 95 insertions(+), 22 deletions(-) create mode 100644 demo/collections/Customers.js diff --git a/demo/collections/Customers.js b/demo/collections/Customers.js new file mode 100644 index 0000000000..7016feac80 --- /dev/null +++ b/demo/collections/Customers.js @@ -0,0 +1,46 @@ +const checkRole = require('../policies/checkRole'); + +module.exports = { + slug: 'customers', + labels: { + singular: 'Customer', + plural: 'Customers', + }, + useAsTitle: 'email', + policies: { + create: () => true, + read: ({ req: { user } }) => { + if (checkRole(['admin'], user)) { + return true; + } + + if (user) { + return { + id: { + equals: user.id, + }, + }; + } + + return false; + }, + update: ({ req: { user } }) => { + if (checkRole(['admin'], user)) { + return true; + } + + if (user) { + return { + id: user.id, + }; + } + + return false; + }, + delete: ({ req: { user } }) => checkRole(['admin'], user), + }, + auth: { + tokenExpiration: 300, + }, + timestamps: true, +}; diff --git a/demo/payload.public.config.js b/demo/payload.public.config.js index 5bb3ad133f..c551824e74 100644 --- a/demo/payload.public.config.js +++ b/demo/payload.public.config.js @@ -4,6 +4,7 @@ const AllFields = require('./collections/AllFields'); const Code = require('./collections/Code'); const Conditions = require('./collections/Conditions'); const CustomComponents = require('./collections/CustomComponents'); +const Customers = require('./collections/Customers'); const File = require('./collections/File'); const FlexibleContent = require('./collections/FlexibleContent'); const HiddenFields = require('./collections/HiddenFields'); @@ -32,6 +33,7 @@ module.exports = { Code, Conditions, CustomComponents, + Customers, File, FlexibleContent, HiddenFields, diff --git a/src/auth/graphql/resolvers/policies.js b/src/auth/graphql/resolvers/policies.js index faa9577aa2..afdc8c726a 100644 --- a/src/auth/graphql/resolvers/policies.js +++ b/src/auth/graphql/resolvers/policies.js @@ -1,13 +1,29 @@ const { policies } = require('../../operations'); +const formatName = require('../../../graphql/utilities/formatName'); -const policyResolver = (config, collection) => async (_, __, context) => { +const formatConfigNames = (results, configs) => { + const formattedResults = { ...results }; + + configs.forEach(({ slug }) => { + const result = { ...(formattedResults[slug] || {}) }; + delete formattedResults[slug]; + formattedResults[formatName(slug)] = result; + }); + + return formattedResults; +}; + +const policyResolver = config => async (_, __, context) => { const options = { config, - collection, req: context, }; - const policyResults = await policies(options); + let policyResults = await policies(options); + + policyResults = formatConfigNames(policyResults, config.collections); + policyResults = formatConfigNames(policyResults, config.globals); + return policyResults; }; diff --git a/src/auth/operations/policies.js b/src/auth/operations/policies.js index 38407514bb..bfbb01b139 100644 --- a/src/auth/operations/policies.js +++ b/src/auth/operations/policies.js @@ -4,15 +4,14 @@ const policies = async (args) => { try { const { config, - collection: { - config: collectionConfig, - }, req, req: { user }, } = args; const isLoggedIn = !!(user); + const collectionConfig = (user && user.collection) ? config.collections.find(collection => collection.slug === user.collection) : null; + const returnPolicyResults = (entity, operations) => { const results = {}; @@ -36,9 +35,13 @@ const policies = async (args) => { return results; }; - const policyResults = { - canAccessAdmin: collectionConfig.policies.admin ? collectionConfig.policies.admin(args) : isLoggedIn, - }; + const policyResults = {}; + + if (collectionConfig) { + policyResults.canAccessAdmin = collectionConfig.policies.admin ? collectionConfig.policies.admin(args) : isLoggedIn; + } else { + policyResults.canAccessAdmin = false; + } config.collections.forEach((collection) => { policyResults[collection.slug] = returnPolicyResults(collection, allOperations); diff --git a/src/auth/requestHandlers/policies.js b/src/auth/requestHandlers/policies.js index 6c156da398..783f62fda4 100644 --- a/src/auth/requestHandlers/policies.js +++ b/src/auth/requestHandlers/policies.js @@ -7,7 +7,6 @@ const policiesHandler = config => async (req, res) => { const policyResults = await policies({ req, config, - collection: req.collection, }); return res.status(httpStatus.OK) diff --git a/src/auth/routes.js b/src/auth/routes.js index 507496ea99..8ac7edae5c 100644 --- a/src/auth/routes.js +++ b/src/auth/routes.js @@ -11,7 +11,6 @@ const { forgotPassword, resetPassword, update, - policies, } = require('./requestHandlers'); const { @@ -44,10 +43,6 @@ const authRoutes = (collection, config, sendEmail) => { .route(`/${slug}/me`) .get(me); - router - .route(`/${slug}/policies`) - .get(policies(config)); - router .route(`/${slug}/first-register`) .post(registerFirstUser(config)); diff --git a/src/collections/graphql/init.js b/src/collections/graphql/init.js index e2fa198cbd..a77f9be512 100644 --- a/src/collections/graphql/init.js +++ b/src/collections/graphql/init.js @@ -12,7 +12,7 @@ const { } = require('./resolvers'); const { - login, me, init, refresh, register, forgotPassword, resetPassword, policies, + login, me, init, refresh, register, forgotPassword, resetPassword, } = require('../../auth/graphql/resolvers'); const buildPaginatedListType = require('../../graphql/schema/buildPaginatedListType'); @@ -129,21 +129,21 @@ function registerCollections() { if (collection.config.auth) { collection.graphQL.jwt = this.buildObjectType( - 'JWT', + formatName(`${slug}JWT`), collection.config.fields.filter(field => field.saveToJWT).concat([ { name: 'email', type: 'email', required: true, }, + { + name: 'collection', + type: 'text', + required: true, + }, ]), ); - this.Query.fields[`policies${singularLabel}`] = { - type: this.buildPoliciesType(), - resolve: policies(this.config, collection), - }; - this.Query.fields[`me${singularLabel}`] = { type: collection.graphQL.jwt, resolve: me, diff --git a/src/fields/sanitize.js b/src/fields/sanitize.js index 5dc5ec4e0a..3392349d9e 100644 --- a/src/fields/sanitize.js +++ b/src/fields/sanitize.js @@ -2,6 +2,8 @@ const { MissingFieldType } = require('../errors'); const validations = require('./validations'); const sanitizeFields = (fields) => { + if (!fields) return []; + return fields.map((unsanitizedField) => { const field = { ...unsanitizedField }; diff --git a/src/graphql/index.js b/src/graphql/index.js index 2710463f05..18a4a53223 100644 --- a/src/graphql/index.js +++ b/src/graphql/index.js @@ -11,6 +11,7 @@ const initCollections = require('../collections/graphql/init'); const initGlobals = require('../globals/graphql/init'); const buildWhereInputType = require('./schema/buildWhereInputType'); const errorHandler = require('./errorHandler'); +const { policies } = require('../auth/graphql/resolvers'); class GraphQL { constructor(init) { @@ -49,6 +50,11 @@ class GraphQL { this.initCollections(); this.initGlobals(); + this.Query.fields.Policies = { + type: this.buildPoliciesType(), + resolve: policies(this.config), + }; + this.Query = { ...this.Query, ...(this.config.queries), diff --git a/src/index.js b/src/index.js index 3a1a8ee8f2..efcfb823ec 100644 --- a/src/index.js +++ b/src/index.js @@ -17,6 +17,7 @@ const sanitizeConfig = require('./utilities/sanitizeConfig'); const buildEmail = require('./email/build'); const identifyAPI = require('./express/middleware/identifyAPI'); const errorHandler = require('./express/middleware/errorHandler'); +const { policies } = require('./auth/requestHandlers'); class Payload { constructor(options) { @@ -57,6 +58,9 @@ class Payload { this.express.use(initWebpack(this.config)); } + // Init policies route + this.router.get('/policies', policies(this.config)); + // Init GraphQL this.router.use( this.config.routes.graphQL,