From fc1f4c494f1208e7592f6bedda4b3f8f471a2942 Mon Sep 17 00:00:00 2001 From: Dan Ribbens Date: Mon, 19 Jun 2023 00:16:07 -0400 Subject: [PATCH] chore: cherry pick missing from migrations --- docs/configuration/collections.mdx | 6 +- src/collections/buildEndpoints.ts | 4 + src/collections/config/types.ts | 6 +- src/collections/graphql/init.ts | 3 +- src/config/schema.ts | 23 +- src/globals/buildEndpoints.ts | 4 + src/globals/config/sanitize.ts | 2 +- src/globals/config/schema.ts | 9 +- src/globals/config/types.ts | 8 +- src/globals/graphql/init.ts | 7 +- src/graphql/schema/buildPoliciesType.ts | 14 +- src/payload.ts | 2 +- test/endpoints/config.ts | 24 ++ test/endpoints/int.spec.ts | 29 +- test/graphql-schema-gen/config.ts | 11 + test/graphql-schema-gen/schema.graphql | 471 +++++++++++++++++++++++- 16 files changed, 582 insertions(+), 41 deletions(-) diff --git a/docs/configuration/collections.mdx b/docs/configuration/collections.mdx index 93804537fb..6b6f3c0286 100644 --- a/docs/configuration/collections.mdx +++ b/docs/configuration/collections.mdx @@ -13,7 +13,7 @@ It's often best practice to write your Collections in separate files and then im ## Options | Option | Description | -|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **`slug`** * | Unique, URL-friendly string that will act as an identifier for this Collection. | | **`fields`** * | Array of field types that will determine the structure and functionality of the data stored within this Collection. [Click here](/docs/fields/overview) for a full list of field types as well as how to configure them. | | **`indexes`** * | Array of database indexes to create, including compound indexes that have multiple fields. | @@ -25,8 +25,8 @@ It's often best practice to write your Collections in separate files and then im | **`upload`** | Specify options if you would like this Collection to support file uploads. For more, consult the [Uploads](/docs/upload/overview) documentation. | | **`timestamps`** | Set to false to disable documents' automatically generated `createdAt` and `updatedAt` timestamps. | | **`versions`** | Set to true to enable default options, or configure with object properties. [More](/docs/versions/overview#collection-config) | -| **`endpoints`** | Add custom routes to the REST API. [More](/docs/rest-api/overview#custom-endpoints) | -| **`graphQL`** | An object with `singularName` and `pluralName` strings used in schema generation. Auto-generated from slug if not defined. | +| **`endpoints`** | Add custom routes to the REST API. Set to `false` to disable routes. [More](/docs/rest-api/overview#custom-endpoints) | +| **`graphQL`** | An object with `singularName` and `pluralName` strings used in schema generation. Auto-generated from slug if not defined. Set to `false` to disable GraphQL. | | **`typescript`** | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. | | **`defaultSort`** | Pass a top-level field to sort by default in the collection List view. Prefix the name of the field with a minus symbol ("-") to sort in descending order. | | **`pagination`** | Set pagination-specific options for this collection. [More](#pagination) | diff --git a/src/collections/buildEndpoints.ts b/src/collections/buildEndpoints.ts index 7790b66dba..d43c69e0b2 100644 --- a/src/collections/buildEndpoints.ts +++ b/src/collections/buildEndpoints.ts @@ -25,6 +25,10 @@ import deleteByID from './requestHandlers/deleteByID'; const buildEndpoints = (collection: SanitizedCollectionConfig): Endpoint[] => { const endpoints = [...collection.endpoints]; + if (endpoints === false) { + return []; + } + if (collection.auth) { if (!collection.auth.disableLocalStrategy) { if (collection.auth.verify) { diff --git a/src/collections/config/types.ts b/src/collections/config/types.ts index fdd9fcd0de..85d81d1dd7 100644 --- a/src/collections/config/types.ts +++ b/src/collections/config/types.ts @@ -309,9 +309,9 @@ export type CollectionConfig = { afterForgotPassword?: AfterForgotPasswordHook[]; }; /** - * Custom rest api endpoints + * Custom rest api endpoints, set false to disable all rest endpoints for this collection. */ - endpoints?: Omit[] + endpoints?: Omit[] | false; /** * Access control */ @@ -357,7 +357,7 @@ export interface SanitizedCollectionConfig extends Omit[]; + endpoints: Omit[] | false; } export type Collection = { diff --git a/src/collections/graphql/init.ts b/src/collections/graphql/init.ts index 1f130b4f33..f606570071 100644 --- a/src/collections/graphql/init.ts +++ b/src/collections/graphql/init.ts @@ -37,6 +37,7 @@ function initCollectionsGraphQL(payload: Payload): void { const { config, config: { + fields, graphQL = {} as SanitizedCollectionConfig['graphQL'], versions, }, @@ -44,8 +45,6 @@ function initCollectionsGraphQL(payload: Payload): void { if (!graphQL) return; - const { fields } = config; - let singularName; let pluralName; const fromSlug = formatNames(collection.config.slug); diff --git a/src/config/schema.ts b/src/config/schema.ts index 2cc9cb1781..6e6d68b544 100644 --- a/src/config/schema.ts +++ b/src/config/schema.ts @@ -5,16 +5,19 @@ const component = joi.alternatives().try( joi.func(), ); -export const endpointsSchema = joi.array().items(joi.object({ - path: joi.string(), - method: joi.string().valid('get', 'head', 'post', 'put', 'patch', 'delete', 'connect', 'options'), - root: joi.bool(), - handler: joi.alternatives().try( - joi.array().items(joi.func()), - joi.func(), - ), - custom: joi.object().pattern(joi.string(), joi.any()), -})); +export const endpointsSchema = joi.alternatives().try( + joi.array().items(joi.object({ + path: joi.string(), + method: joi.string().valid('get', 'head', 'post', 'put', 'patch', 'delete', 'connect', 'options'), + root: joi.bool(), + handler: joi.alternatives().try( + joi.array().items(joi.func()), + joi.func(), + ), + custom: joi.object().pattern(joi.string(), joi.any()), + })), + joi.boolean(), +); export default joi.object({ serverURL: joi.string() diff --git a/src/globals/buildEndpoints.ts b/src/globals/buildEndpoints.ts index d601b36244..5bb9275c8f 100644 --- a/src/globals/buildEndpoints.ts +++ b/src/globals/buildEndpoints.ts @@ -10,6 +10,10 @@ import docAccessRequestHandler from './requestHandlers/docAccess'; const buildEndpoints = (global: SanitizedGlobalConfig): Endpoint[] => { const endpoints = [...global.endpoints]; + if (endpoints === false) { + return []; + } + if (global.versions) { endpoints.push( { diff --git a/src/globals/config/sanitize.ts b/src/globals/config/sanitize.ts index e9fbe5abe5..ac6453b9f2 100644 --- a/src/globals/config/sanitize.ts +++ b/src/globals/config/sanitize.ts @@ -18,8 +18,8 @@ const sanitizeGlobals = (collections: CollectionConfig[], globals: GlobalConfig[ // Ensure that collection has required object structure // ///////////////////////////////// + sanitizedGlobal.endpoints = sanitizedGlobal.endpoints ?? []; if (!sanitizedGlobal.hooks) sanitizedGlobal.hooks = {}; - if (!sanitizedGlobal.endpoints) sanitizedGlobal.endpoints = []; if (!sanitizedGlobal.access) sanitizedGlobal.access = {}; if (!sanitizedGlobal.admin) sanitizedGlobal.admin = {}; diff --git a/src/globals/config/schema.ts b/src/globals/config/schema.ts index 3a68a61e7c..966ca2cf57 100644 --- a/src/globals/config/schema.ts +++ b/src/globals/config/schema.ts @@ -38,9 +38,12 @@ const globalSchema = joi.object().keys({ typescript: joi.object().keys({ interface: joi.string(), }), - graphQL: joi.object().keys({ - name: joi.string(), - }), + graphQL: joi.alternatives().try( + joi.object().keys({ + name: joi.string(), + }), + joi.boolean(), + ), hooks: joi.object({ beforeValidate: joi.array().items(joi.func()), beforeChange: joi.array().items(joi.func()), diff --git a/src/globals/config/types.ts b/src/globals/config/types.ts index 60554d30c7..e6e2cf50d5 100644 --- a/src/globals/config/types.ts +++ b/src/globals/config/types.ts @@ -111,7 +111,7 @@ export type GlobalConfig = { label?: Record | string graphQL?: { name?: string - } + } | false /** * Options used in typescript generation */ @@ -129,7 +129,7 @@ export type GlobalConfig = { beforeRead?: BeforeReadHook[] afterRead?: AfterReadHook[] } - endpoints?: Omit[], + endpoints?: Omit[] | false access?: { read?: Access; readDrafts?: Access; @@ -144,7 +144,7 @@ export type GlobalConfig = { export interface SanitizedGlobalConfig extends Omit, 'fields' | 'versions' | 'endpoints'> { fields: Field[] - endpoints: Omit[], + endpoints: Omit[] | false versions: SanitizedGlobalVersions } @@ -157,5 +157,5 @@ export type Globals = { mutationInputType: GraphQLNonNull versionType?: GraphQLObjectType } - } + } | false } diff --git a/src/globals/graphql/init.ts b/src/globals/graphql/init.ts index 2e9ad5105c..6c1d6109d5 100644 --- a/src/globals/graphql/init.ts +++ b/src/globals/graphql/init.ts @@ -25,9 +25,14 @@ function initGlobalsGraphQL(payload: Payload): void { const { fields, versions, + graphQL, } = global; - const formattedName = global.graphQL?.name ? global.graphQL.name : singular(toWords(global.slug, true)); + if (graphQL === false) { + return; + } + + const formattedName = graphQL?.name ? graphQL.name : singular(toWords(global.slug, true)); const forceNullableObjectType = Boolean(versions?.drafts); diff --git a/src/graphql/schema/buildPoliciesType.ts b/src/graphql/schema/buildPoliciesType.ts index e84ebe8cbd..0ed668f5dd 100644 --- a/src/graphql/schema/buildPoliciesType.ts +++ b/src/graphql/schema/buildPoliciesType.ts @@ -1,4 +1,3 @@ - import { GraphQLJSONObject } from 'graphql-type-json'; import { GraphQLBoolean, GraphQLNonNull, GraphQLObjectType } from 'graphql'; import formatName from '../utilities/formatName'; @@ -128,10 +127,12 @@ type BuildPolicyType = { }) export function buildPolicyType(args: BuildPolicyType): GraphQLObjectType { const { typeSuffix, entity, type, scope } = args; - const { slug } = entity; + const { slug, graphQL, fields, versions } = entity; let operations = []; + if (graphQL === false) return null; + if (type === 'collection') { operations = ['create', 'read', 'update', 'delete']; @@ -139,7 +140,7 @@ export function buildPolicyType(args: BuildPolicyType): GraphQLObjectType { operations.push('unlock'); } - if (entity.versions) { + if (versions) { operations.push('readVersions'); } @@ -149,7 +150,7 @@ export function buildPolicyType(args: BuildPolicyType): GraphQLObjectType { name: collectionTypeName, fields: buildEntityPolicy({ name: slug, - entityFields: entity.fields, + entityFields: fields, operations, scope, }), @@ -168,7 +169,7 @@ export function buildPolicyType(args: BuildPolicyType): GraphQLObjectType { return new GraphQLObjectType({ name: globalTypeName, fields: buildEntityPolicy({ - name: entity?.graphQL?.name || slug, + name: (entity.graphQL) ? entity?.graphQL?.name || slug : slug, entityFields: entity.fields, operations, scope, @@ -184,6 +185,9 @@ export default function buildPoliciesType(payload: Payload): GraphQLObjectType { }; Object.values(payload.config.collections).forEach((collection: SanitizedCollectionConfig) => { + if (collection.graphQL === false) { + return; + } const collectionPolicyType = buildPolicyType({ typeSuffix: 'Access', entity: collection, diff --git a/src/payload.ts b/src/payload.ts index ada70fbe58..4bafe9563f 100644 --- a/src/payload.ts +++ b/src/payload.ts @@ -232,7 +232,7 @@ export class BasePayload { this.email = buildEmail(this.emailOptions, this.logger); this.sendEmail = sendEmail.bind(this); - if (!this.config.graphQL.disable && !this.config.graphQL) { + if (!this.config.graphQL.disable) { registerGraphQLSchema(this); } diff --git a/test/endpoints/config.ts b/test/endpoints/config.ts index df3e64ad90..54bada2fb9 100644 --- a/test/endpoints/config.ts +++ b/test/endpoints/config.ts @@ -11,6 +11,8 @@ export const globalSlug = 'global-endpoints'; export const globalEndpoint = 'global'; export const applicationEndpoint = 'path'; export const rootEndpoint = 'root'; +export const noEndpointsCollectionSlug = 'no-endpoints'; +export const noEndpointsGlobalSlug = 'global-no-endpoints'; const MyConfig: Config = { collections: [ @@ -57,6 +59,17 @@ const MyConfig: Config = { }, ], }, + { + slug: noEndpointsCollectionSlug, + graphQL: false, + endpoints: false, + fields: [ + { + name: 'name', + type: 'text', + }, + ], + }, ], globals: [ { @@ -70,6 +83,17 @@ const MyConfig: Config = { }], fields: [], }, + { + slug: noEndpointsGlobalSlug, + graphQL: false, + endpoints: false, + fields: [ + { + name: 'name', + type: 'text', + }, + ], + }, ], endpoints: [ { diff --git a/test/endpoints/int.spec.ts b/test/endpoints/int.spec.ts index 00c3380d55..4633c43ff3 100644 --- a/test/endpoints/int.spec.ts +++ b/test/endpoints/int.spec.ts @@ -1,6 +1,14 @@ import { initPayloadTest } from '../helpers/configHelpers'; import { RESTClient } from '../helpers/rest'; -import { applicationEndpoint, collectionSlug, globalEndpoint, globalSlug, rootEndpoint } from './config'; +import { + applicationEndpoint, + collectionSlug, + globalEndpoint, + globalSlug, + noEndpointsCollectionSlug, + noEndpointsGlobalSlug, + rootEndpoint, +} from './config'; require('isomorphic-fetch'); @@ -34,6 +42,16 @@ describe('Endpoints', () => { expect(data.name).toStrictEqual(params.name); expect(data.age).toStrictEqual(params.age); }); + + it('should disable built-in endpoints when false', async () => { + let result; + try { + result = await client.endpoint(`/api/${noEndpointsCollectionSlug}`, 'get'); + } catch (err: unknown) { + result = err; + } + expect(result instanceof Error).toBe(true); + }); }); describe('Globals', () => { @@ -44,6 +62,15 @@ describe('Endpoints', () => { expect(status).toBe(200); expect(params).toMatchObject(data); }); + it('should disable built-in endpoints when false', async () => { + let result; + try { + result = await client.endpoint(`/api/globals/${noEndpointsGlobalSlug}`, 'get'); + } catch (err: unknown) { + result = err; + } + expect(result instanceof Error).toBe(true); + }); }); describe('API', () => { diff --git a/test/graphql-schema-gen/config.ts b/test/graphql-schema-gen/config.ts index 497a1ea766..022f434276 100644 --- a/test/graphql-schema-gen/config.ts +++ b/test/graphql-schema-gen/config.ts @@ -141,5 +141,16 @@ export default buildConfig({ }, ], }, + { + // this should not be written to the generated schema + slug: 'no-graphql', + graphQL: false, + fields: [ + { + name: 'name', + type: 'text', + }, + ], + }, ], }); diff --git a/test/graphql-schema-gen/schema.graphql b/test/graphql-schema-gen/schema.graphql index 149edd2b6d..0998d39cce 100644 --- a/test/graphql-schema-gen/schema.graphql +++ b/test/graphql-schema-gen/schema.graphql @@ -10,7 +10,9 @@ type Query { docAccessUser(id: String!): usersDocAccess meUser: usersMe initializedUser: Boolean - Preference(key: String): Preference + PayloadPreference(id: String!, draft: Boolean): PayloadPreference + PayloadPreferences(where: PayloadPreference_where, draft: Boolean, page: Int, limit: Int, sort: String): PayloadPreferences + docAccessPayloadPreference(id: String!): payload_preferencesDocAccess Access: Access } @@ -1096,23 +1098,292 @@ type usersMe { collection: String } -type Preference { - key: String! +type PayloadPreference { + id: String + user: PayloadPreference_User_Relationship! + key: String value: JSON - createdAt: DateTime! - updatedAt: DateTime! + updatedAt: DateTime + createdAt: DateTime } +type PayloadPreference_User_Relationship { + relationTo: PayloadPreference_User_RelationTo + value: PayloadPreference_User +} + +enum PayloadPreference_User_RelationTo { + users +} + +union PayloadPreference_User = User + """ The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). """ scalar JSON +type PayloadPreferences { + docs: [PayloadPreference] + totalDocs: Int + offset: Int + limit: Int + totalPages: Int + page: Int + pagingCounter: Int + hasPrevPage: Boolean + hasNextPage: Boolean + prevPage: Int + nextPage: Int +} + +input PayloadPreference_where { + user: PayloadPreference_user_Relation + key: PayloadPreference_key_operator + value: PayloadPreference_value_operator + updatedAt: PayloadPreference_updatedAt_operator + createdAt: PayloadPreference_createdAt_operator + id: PayloadPreference_id_operator + OR: [PayloadPreference_where_or] + AND: [PayloadPreference_where_and] +} + +input PayloadPreference_user_Relation { + relationTo: PayloadPreference_user_Relation_RelationTo + value: String +} + +enum PayloadPreference_user_Relation_RelationTo { + users +} + +input PayloadPreference_key_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input PayloadPreference_value_operator { + equals: JSON + not_equals: JSON + like: JSON + contains: JSON + exists: Boolean +} + +input PayloadPreference_updatedAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input PayloadPreference_createdAt_operator { + equals: DateTime + not_equals: DateTime + greater_than_equal: DateTime + greater_than: DateTime + less_than_equal: DateTime + less_than: DateTime + like: DateTime + exists: Boolean +} + +input PayloadPreference_id_operator { + equals: String + not_equals: String + like: String + contains: String + in: [String] + not_in: [String] + all: [String] + exists: Boolean +} + +input PayloadPreference_where_or { + user: PayloadPreference_user_Relation + key: PayloadPreference_key_operator + value: PayloadPreference_value_operator + updatedAt: PayloadPreference_updatedAt_operator + createdAt: PayloadPreference_createdAt_operator + id: PayloadPreference_id_operator +} + +input PayloadPreference_where_and { + user: PayloadPreference_user_Relation + key: PayloadPreference_key_operator + value: PayloadPreference_value_operator + updatedAt: PayloadPreference_updatedAt_operator + createdAt: PayloadPreference_createdAt_operator + id: PayloadPreference_id_operator +} + +type payload_preferencesDocAccess { + fields: PayloadPreferencesDocAccessFields + create: PayloadPreferencesCreateDocAccess + read: PayloadPreferencesReadDocAccess + update: PayloadPreferencesUpdateDocAccess + delete: PayloadPreferencesDeleteDocAccess +} + +type PayloadPreferencesDocAccessFields { + user: PayloadPreferencesDocAccessFields_user + key: PayloadPreferencesDocAccessFields_key + value: PayloadPreferencesDocAccessFields_value + updatedAt: PayloadPreferencesDocAccessFields_updatedAt + createdAt: PayloadPreferencesDocAccessFields_createdAt +} + +type PayloadPreferencesDocAccessFields_user { + create: PayloadPreferencesDocAccessFields_user_Create + read: PayloadPreferencesDocAccessFields_user_Read + update: PayloadPreferencesDocAccessFields_user_Update + delete: PayloadPreferencesDocAccessFields_user_Delete +} + +type PayloadPreferencesDocAccessFields_user_Create { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_user_Read { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_user_Update { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_user_Delete { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_key { + create: PayloadPreferencesDocAccessFields_key_Create + read: PayloadPreferencesDocAccessFields_key_Read + update: PayloadPreferencesDocAccessFields_key_Update + delete: PayloadPreferencesDocAccessFields_key_Delete +} + +type PayloadPreferencesDocAccessFields_key_Create { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_key_Read { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_key_Update { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_key_Delete { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_value { + create: PayloadPreferencesDocAccessFields_value_Create + read: PayloadPreferencesDocAccessFields_value_Read + update: PayloadPreferencesDocAccessFields_value_Update + delete: PayloadPreferencesDocAccessFields_value_Delete +} + +type PayloadPreferencesDocAccessFields_value_Create { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_value_Read { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_value_Update { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_value_Delete { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_updatedAt { + create: PayloadPreferencesDocAccessFields_updatedAt_Create + read: PayloadPreferencesDocAccessFields_updatedAt_Read + update: PayloadPreferencesDocAccessFields_updatedAt_Update + delete: PayloadPreferencesDocAccessFields_updatedAt_Delete +} + +type PayloadPreferencesDocAccessFields_updatedAt_Create { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_updatedAt_Read { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_updatedAt_Update { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_updatedAt_Delete { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_createdAt { + create: PayloadPreferencesDocAccessFields_createdAt_Create + read: PayloadPreferencesDocAccessFields_createdAt_Read + update: PayloadPreferencesDocAccessFields_createdAt_Update + delete: PayloadPreferencesDocAccessFields_createdAt_Delete +} + +type PayloadPreferencesDocAccessFields_createdAt_Create { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_createdAt_Read { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_createdAt_Update { + permission: Boolean! +} + +type PayloadPreferencesDocAccessFields_createdAt_Delete { + permission: Boolean! +} + +type PayloadPreferencesCreateDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreferencesReadDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreferencesUpdateDocAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreferencesDeleteDocAccess { + permission: Boolean! + where: JSONObject +} + type Access { canAccessAdmin: Boolean! collection1: collection1Access collection2: collection2Access users: usersAccess + payload_preferences: payload_preferencesAccess } type collection1Access { @@ -1758,6 +2029,157 @@ type UsersUnlockAccess { where: JSONObject } +type payload_preferencesAccess { + fields: PayloadPreferencesFields + create: PayloadPreferencesCreateAccess + read: PayloadPreferencesReadAccess + update: PayloadPreferencesUpdateAccess + delete: PayloadPreferencesDeleteAccess +} + +type PayloadPreferencesFields { + user: PayloadPreferencesFields_user + key: PayloadPreferencesFields_key + value: PayloadPreferencesFields_value + updatedAt: PayloadPreferencesFields_updatedAt + createdAt: PayloadPreferencesFields_createdAt +} + +type PayloadPreferencesFields_user { + create: PayloadPreferencesFields_user_Create + read: PayloadPreferencesFields_user_Read + update: PayloadPreferencesFields_user_Update + delete: PayloadPreferencesFields_user_Delete +} + +type PayloadPreferencesFields_user_Create { + permission: Boolean! +} + +type PayloadPreferencesFields_user_Read { + permission: Boolean! +} + +type PayloadPreferencesFields_user_Update { + permission: Boolean! +} + +type PayloadPreferencesFields_user_Delete { + permission: Boolean! +} + +type PayloadPreferencesFields_key { + create: PayloadPreferencesFields_key_Create + read: PayloadPreferencesFields_key_Read + update: PayloadPreferencesFields_key_Update + delete: PayloadPreferencesFields_key_Delete +} + +type PayloadPreferencesFields_key_Create { + permission: Boolean! +} + +type PayloadPreferencesFields_key_Read { + permission: Boolean! +} + +type PayloadPreferencesFields_key_Update { + permission: Boolean! +} + +type PayloadPreferencesFields_key_Delete { + permission: Boolean! +} + +type PayloadPreferencesFields_value { + create: PayloadPreferencesFields_value_Create + read: PayloadPreferencesFields_value_Read + update: PayloadPreferencesFields_value_Update + delete: PayloadPreferencesFields_value_Delete +} + +type PayloadPreferencesFields_value_Create { + permission: Boolean! +} + +type PayloadPreferencesFields_value_Read { + permission: Boolean! +} + +type PayloadPreferencesFields_value_Update { + permission: Boolean! +} + +type PayloadPreferencesFields_value_Delete { + permission: Boolean! +} + +type PayloadPreferencesFields_updatedAt { + create: PayloadPreferencesFields_updatedAt_Create + read: PayloadPreferencesFields_updatedAt_Read + update: PayloadPreferencesFields_updatedAt_Update + delete: PayloadPreferencesFields_updatedAt_Delete +} + +type PayloadPreferencesFields_updatedAt_Create { + permission: Boolean! +} + +type PayloadPreferencesFields_updatedAt_Read { + permission: Boolean! +} + +type PayloadPreferencesFields_updatedAt_Update { + permission: Boolean! +} + +type PayloadPreferencesFields_updatedAt_Delete { + permission: Boolean! +} + +type PayloadPreferencesFields_createdAt { + create: PayloadPreferencesFields_createdAt_Create + read: PayloadPreferencesFields_createdAt_Read + update: PayloadPreferencesFields_createdAt_Update + delete: PayloadPreferencesFields_createdAt_Delete +} + +type PayloadPreferencesFields_createdAt_Create { + permission: Boolean! +} + +type PayloadPreferencesFields_createdAt_Read { + permission: Boolean! +} + +type PayloadPreferencesFields_createdAt_Update { + permission: Boolean! +} + +type PayloadPreferencesFields_createdAt_Delete { + permission: Boolean! +} + +type PayloadPreferencesCreateAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreferencesReadAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreferencesUpdateAccess { + permission: Boolean! + where: JSONObject +} + +type PayloadPreferencesDeleteAccess { + permission: Boolean! + where: JSONObject +} + type Mutation { createCollection1(data: mutationCollection1Input!, draft: Boolean): Collection1 updateCollection1(id: String!, data: mutationCollection1UpdateInput!, draft: Boolean, autosave: Boolean): Collection1 @@ -1775,8 +2197,9 @@ type Mutation { forgotPasswordUser(email: String!, disableEmail: Boolean, expiration: Int): Boolean! resetPasswordUser(token: String, password: String): usersResetPassword verifyEmailUser(token: String): Boolean - updatePreference(key: String!, value: JSON): Preference - deletePreference(key: String!): Preference + createPayloadPreference(data: mutationPayloadPreferenceInput!, draft: Boolean): PayloadPreference + updatePayloadPreference(id: String!, data: mutationPayloadPreferenceUpdateInput!, draft: Boolean, autosave: Boolean): PayloadPreference + deletePayloadPreference(id: String!): PayloadPreference } input mutationCollection1Input { @@ -1897,4 +2320,38 @@ type usersLoginResult { type usersResetPassword { token: String user: User +} + +input mutationPayloadPreferenceInput { + user: PayloadPreference_UserRelationshipInput + key: String + value: JSON + updatedAt: String + createdAt: String +} + +input PayloadPreference_UserRelationshipInput { + relationTo: PayloadPreference_UserRelationshipInputRelationTo + value: JSON +} + +enum PayloadPreference_UserRelationshipInputRelationTo { + users +} + +input mutationPayloadPreferenceUpdateInput { + user: PayloadPreferenceUpdate_UserRelationshipInput + key: String + value: JSON + updatedAt: String + createdAt: String +} + +input PayloadPreferenceUpdate_UserRelationshipInput { + relationTo: PayloadPreferenceUpdate_UserRelationshipInputRelationTo + value: JSON +} + +enum PayloadPreferenceUpdate_UserRelationshipInputRelationTo { + users } \ No newline at end of file