Compare commits

...

3 Commits

Author SHA1 Message Date
Dan Ribbens
df5e2f7d4c eslint ignore 2023-06-26 12:56:03 -04:00
Dan Ribbens
5dbc24d8da chore: WIP migrations 2023-06-26 12:54:43 -04:00
Dan Ribbens
4b7c60b6c1 feat: allow disabling graphql and rest APIs for collections and globals 2023-06-19 16:49:52 -04:00
21 changed files with 688 additions and 45 deletions

View File

@@ -13,7 +13,7 @@ It's often best practice to write your Collections in separate files and then im
## Options ## Options
| Option | Description | | Option | Description |
|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| |--------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`slug`** * | Unique, URL-friendly string that will act as an identifier for this Collection. | | **`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. | | **`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. | | **`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. | | **`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. | | **`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) | | **`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) | | **`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. | | **`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. | | **`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. | | **`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) | | **`pagination`** | Set pagination-specific options for this collection. [More](#pagination) |

View File

@@ -25,6 +25,10 @@ import deleteByID from './requestHandlers/deleteByID';
const buildEndpoints = (collection: SanitizedCollectionConfig): Endpoint[] => { const buildEndpoints = (collection: SanitizedCollectionConfig): Endpoint[] => {
let { endpoints } = collection; let { endpoints } = collection;
if (endpoints === false) {
return [];
}
if (collection.auth) { if (collection.auth) {
if (!collection.auth.disableLocalStrategy) { if (!collection.auth.disableLocalStrategy) {
if (collection.auth.verify) { if (collection.auth.verify) {

View File

@@ -29,10 +29,13 @@ const collectionSchema = joi.object().keys({
admin: joi.func(), admin: joi.func(),
}), }),
defaultSort: joi.string(), defaultSort: joi.string(),
graphQL: joi.object().keys({ graphQL: joi.alternatives().try(
singularName: joi.string(), joi.object().keys({
pluralName: joi.string(), singularName: joi.string(),
}), pluralName: joi.string(),
}),
joi.boolean(),
),
typescript: joi.object().keys({ typescript: joi.object().keys({
interface: joi.string(), interface: joi.string(),
}), }),

View File

@@ -267,7 +267,7 @@ export type CollectionConfig = {
graphQL?: { graphQL?: {
singularName?: string singularName?: string
pluralName?: string pluralName?: string
} } | false;
/** /**
* Options used in typescript generation * Options used in typescript generation
*/ */
@@ -307,9 +307,9 @@ export type CollectionConfig = {
afterForgotPassword?: AfterForgotPasswordHook[]; afterForgotPassword?: AfterForgotPasswordHook[];
}; };
/** /**
* Custom rest api endpoints * Custom rest api endpoints, set false to disable all rest endpoints for this collection.
*/ */
endpoints?: Omit<Endpoint, 'root'>[] endpoints?: Omit<Endpoint, 'root'>[] | false;
/** /**
* Access control * Access control
*/ */
@@ -355,7 +355,7 @@ export interface SanitizedCollectionConfig extends Omit<DeepRequired<CollectionC
upload: Upload; upload: Upload;
fields: Field[]; fields: Field[];
versions: SanitizedCollectionVersions; versions: SanitizedCollectionVersions;
endpoints: Omit<Endpoint, 'root'>[]; endpoints: Omit<Endpoint, 'root'>[] | false;
} }
export type Collection = { export type Collection = {

View File

@@ -37,11 +37,15 @@ function initCollectionsGraphQL(payload: Payload): void {
const { const {
config, config,
config: { config: {
fields,
graphQL = {} as SanitizedCollectionConfig['graphQL'], graphQL = {} as SanitizedCollectionConfig['graphQL'],
versions, versions,
}, },
} = collection; } = collection;
const { fields } = config;
if (graphQL === false) {
return;
}
let singularName; let singularName;
let pluralName; let pluralName;

View File

@@ -5,16 +5,19 @@ const component = joi.alternatives().try(
joi.func(), joi.func(),
); );
export const endpointsSchema = joi.array().items(joi.object({ export const endpointsSchema = joi.alternatives().try(
path: joi.string(), joi.array().items(joi.object({
method: joi.string().valid('get', 'head', 'post', 'put', 'patch', 'delete', 'connect', 'options'), path: joi.string(),
root: joi.bool(), method: joi.string().valid('get', 'head', 'post', 'put', 'patch', 'delete', 'connect', 'options'),
handler: joi.alternatives().try( root: joi.bool(),
joi.array().items(joi.func()), handler: joi.alternatives().try(
joi.func(), joi.array().items(joi.func()),
), joi.func(),
custom: joi.object().pattern(joi.string(), joi.any()), ),
})); custom: joi.object().pattern(joi.string(), joi.any()),
})),
joi.boolean(),
);
export default joi.object({ export default joi.object({
serverURL: joi.string() serverURL: joi.string()

View File

@@ -0,0 +1,25 @@
import { DatabaseAdapter } from '../types';
import { readMigrationFiles } from './readMigrationFiles';
export async function migrateStatus(this: DatabaseAdapter) {
const { payload } = this;
const files = readMigrationFiles({ payload });
const { docs: migrations } = await payload.db.find<{name: string, batch: number}>({
collection: 'payload-migrations',
limit: 0,
pagination: false,
});
const result = (await files).map((file) => {
const migration = migrations.find((doc) => (doc.name === file.name));
return {
ran: !!migration,
migration: file.name,
batch: migration.batch ?? null,
};
});
// TODO: log as table format
this.payload.logger.info(result);
}

View File

@@ -0,0 +1,43 @@
import type { CollectionConfig } from '../../collections/config/types';
export const migrationCollection = ({ payload: Payload }): CollectionConfig => {
return {
slug: 'payload-migrations',
admin: {
hidden: true,
},
graphQL: false,
endpoints: false,
fields: [
{
name: 'migration',
type: 'text',
},
{
name: 'batch',
type: 'number',
},
// TODO: determine how schema will impact migration workflow
// {
// name: 'schema',
// type: 'json',
// },
// TODO: do we need to persist the indexes separate from the schema?
// {
// name: 'indexes',
// type: 'array',
// fields: [
// {
// name: 'index',
// type: 'text',
// },
// {
// name: 'value',
// type: 'json',
// },
// ],
// },
],
};
};

View File

@@ -0,0 +1,15 @@
import fs from 'fs';
import { Migration } from '../types';
import { Payload } from '../../index';
/**
* Read the migration files from disk
*/
export const readMigrationFiles = async ({ payload }: { payload: Payload }): Promise<Migration[]> => {
const { config } = payload;
const files = fs.readdirSync(config.db.migrationDir);
return files.map((path) => {
// eslint-disable-next-line @typescript-eslint/no-var-requires,import/no-dynamic-require
return require(path);
});
};

View File

@@ -54,6 +54,11 @@ export interface DatabaseAdapter {
webpack?: (config: Configuration) => Configuration; webpack?: (config: Configuration) => Configuration;
// migrations // migrations
/**
* Path to read and write migration files from
*/
migrationDir: string
/** /**
* Output a migration file * Output a migration file
*/ */
@@ -230,6 +235,12 @@ type DeleteManyArgs = {
type DeleteMany = (args: DeleteManyArgs) => Promise<Document> type DeleteMany = (args: DeleteManyArgs) => Promise<Document>
export type Migration = {
name: string
up: ({ payload }: { payload }) => Promise<boolean>
down: ({ payload }: { payload }) => Promise<boolean>
}
export type BuildSchema<TSchema> = (args: { export type BuildSchema<TSchema> = (args: {
config: SanitizedConfig, config: SanitizedConfig,
fields: Field[], fields: Field[],

View File

@@ -10,6 +10,10 @@ import docAccessRequestHandler from './requestHandlers/docAccess';
const buildEndpoints = (global: SanitizedGlobalConfig): Endpoint[] => { const buildEndpoints = (global: SanitizedGlobalConfig): Endpoint[] => {
const { endpoints, slug } = global; const { endpoints, slug } = global;
if (endpoints === false) {
return [];
}
if (global.versions) { if (global.versions) {
endpoints.push(...[ endpoints.push(...[
{ {

View File

@@ -18,8 +18,8 @@ const sanitizeGlobals = (collections: CollectionConfig[], globals: GlobalConfig[
// Ensure that collection has required object structure // Ensure that collection has required object structure
// ///////////////////////////////// // /////////////////////////////////
sanitizedGlobal.endpoints = sanitizedGlobal.endpoints ?? [];
if (!sanitizedGlobal.hooks) sanitizedGlobal.hooks = {}; if (!sanitizedGlobal.hooks) sanitizedGlobal.hooks = {};
if (!sanitizedGlobal.endpoints) sanitizedGlobal.endpoints = [];
if (!sanitizedGlobal.access) sanitizedGlobal.access = {}; if (!sanitizedGlobal.access) sanitizedGlobal.access = {};
if (!sanitizedGlobal.admin) sanitizedGlobal.admin = {}; if (!sanitizedGlobal.admin) sanitizedGlobal.admin = {};

View File

@@ -38,9 +38,12 @@ const globalSchema = joi.object().keys({
typescript: joi.object().keys({ typescript: joi.object().keys({
interface: joi.string(), interface: joi.string(),
}), }),
graphQL: joi.object().keys({ graphQL: joi.alternatives().try(
name: joi.string(), joi.object().keys({
}), name: joi.string(),
}),
joi.boolean(),
),
hooks: joi.object({ hooks: joi.object({
beforeValidate: joi.array().items(joi.func()), beforeValidate: joi.array().items(joi.func()),
beforeChange: joi.array().items(joi.func()), beforeChange: joi.array().items(joi.func()),

View File

@@ -110,7 +110,7 @@ export type GlobalConfig = {
label?: Record<string, string> | string label?: Record<string, string> | string
graphQL?: { graphQL?: {
name?: string name?: string
} } | false
/** /**
* Options used in typescript generation * Options used in typescript generation
*/ */
@@ -128,7 +128,7 @@ export type GlobalConfig = {
beforeRead?: BeforeReadHook[] beforeRead?: BeforeReadHook[]
afterRead?: AfterReadHook[] afterRead?: AfterReadHook[]
} }
endpoints?: Omit<Endpoint, 'root'>[], endpoints?: Omit<Endpoint, 'root'>[] | false
access?: { access?: {
read?: Access; read?: Access;
readDrafts?: Access; readDrafts?: Access;
@@ -143,7 +143,7 @@ export type GlobalConfig = {
export interface SanitizedGlobalConfig extends Omit<DeepRequired<GlobalConfig>, 'fields' | 'versions' | 'endpoints'> { export interface SanitizedGlobalConfig extends Omit<DeepRequired<GlobalConfig>, 'fields' | 'versions' | 'endpoints'> {
fields: Field[] fields: Field[]
endpoints: Omit<Endpoint, 'root'>[], endpoints: Omit<Endpoint, 'root'>[] | false
versions: SanitizedGlobalVersions versions: SanitizedGlobalVersions
} }
@@ -156,5 +156,5 @@ export type Globals = {
mutationInputType: GraphQLNonNull<any> mutationInputType: GraphQLNonNull<any>
versionType?: GraphQLObjectType versionType?: GraphQLObjectType
} }
} } | false
} }

View File

@@ -25,9 +25,14 @@ function initGlobalsGraphQL(payload: Payload): void {
const { const {
fields, fields,
versions, versions,
graphQL,
} = global; } = 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); const forceNullableObjectType = Boolean(versions?.drafts);

View File

@@ -1,4 +1,3 @@
import { GraphQLJSONObject } from 'graphql-type-json'; import { GraphQLJSONObject } from 'graphql-type-json';
import { GraphQLBoolean, GraphQLNonNull, GraphQLObjectType } from 'graphql'; import { GraphQLBoolean, GraphQLNonNull, GraphQLObjectType } from 'graphql';
import formatName from '../utilities/formatName'; import formatName from '../utilities/formatName';
@@ -128,10 +127,12 @@ type BuildPolicyType = {
}) })
export function buildPolicyType(args: BuildPolicyType): GraphQLObjectType { export function buildPolicyType(args: BuildPolicyType): GraphQLObjectType {
const { typeSuffix, entity, type, scope } = args; const { typeSuffix, entity, type, scope } = args;
const { slug } = entity; const { slug, graphQL, fields, versions } = entity;
let operations = []; let operations = [];
if (graphQL === false) return null;
if (type === 'collection') { if (type === 'collection') {
operations = ['create', 'read', 'update', 'delete']; operations = ['create', 'read', 'update', 'delete'];
@@ -139,7 +140,7 @@ export function buildPolicyType(args: BuildPolicyType): GraphQLObjectType {
operations.push('unlock'); operations.push('unlock');
} }
if (entity.versions) { if (versions) {
operations.push('readVersions'); operations.push('readVersions');
} }
@@ -149,7 +150,7 @@ export function buildPolicyType(args: BuildPolicyType): GraphQLObjectType {
name: collectionTypeName, name: collectionTypeName,
fields: buildEntityPolicy({ fields: buildEntityPolicy({
name: slug, name: slug,
entityFields: entity.fields, entityFields: fields,
operations, operations,
scope, scope,
}), }),
@@ -168,7 +169,7 @@ export function buildPolicyType(args: BuildPolicyType): GraphQLObjectType {
return new GraphQLObjectType({ return new GraphQLObjectType({
name: globalTypeName, name: globalTypeName,
fields: buildEntityPolicy({ fields: buildEntityPolicy({
name: entity?.graphQL?.name || slug, name: (entity.graphQL) ? entity?.graphQL?.name || slug : slug,
entityFields: entity.fields, entityFields: entity.fields,
operations, operations,
scope, scope,
@@ -184,6 +185,9 @@ export default function buildPoliciesType(payload: Payload): GraphQLObjectType {
}; };
Object.values(payload.config.collections).forEach((collection: SanitizedCollectionConfig) => { Object.values(payload.config.collections).forEach((collection: SanitizedCollectionConfig) => {
if (collection.graphQL === false) {
return;
}
const collectionPolicyType = buildPolicyType({ const collectionPolicyType = buildPolicyType({
typeSuffix: 'Access', typeSuffix: 'Access',
entity: collection, entity: collection,

View File

@@ -233,7 +233,7 @@ export class BasePayload<TGeneratedTypes extends GeneratedTypes> {
registerGraphQLSchema(this); registerGraphQLSchema(this);
} }
if (this.db.init) { if (this.db?.init) {
await this.db?.init({ config: this.config }); await this.db?.init({ config: this.config });
} }

View File

@@ -11,6 +11,8 @@ export const globalSlug = 'global-endpoints';
export const globalEndpoint = 'global'; export const globalEndpoint = 'global';
export const applicationEndpoint = 'path'; export const applicationEndpoint = 'path';
export const rootEndpoint = 'root'; export const rootEndpoint = 'root';
export const noEndpointsCollectionSlug = 'no-endpoints';
export const noEndpointsGlobalSlug = 'global-no-endpoints';
const MyConfig: Config = { const MyConfig: Config = {
collections: [ collections: [
@@ -57,6 +59,17 @@ const MyConfig: Config = {
}, },
], ],
}, },
{
slug: noEndpointsCollectionSlug,
graphQL: false,
endpoints: false,
fields: [
{
name: 'name',
type: 'text',
},
],
},
], ],
globals: [ globals: [
{ {
@@ -70,6 +83,17 @@ const MyConfig: Config = {
}], }],
fields: [], fields: [],
}, },
{
slug: noEndpointsGlobalSlug,
graphQL: false,
endpoints: false,
fields: [
{
name: 'name',
type: 'text',
},
],
},
], ],
endpoints: [ endpoints: [
{ {

View File

@@ -1,6 +1,14 @@
import { initPayloadTest } from '../helpers/configHelpers'; import { initPayloadTest } from '../helpers/configHelpers';
import { RESTClient } from '../helpers/rest'; 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'); require('isomorphic-fetch');
@@ -34,6 +42,16 @@ describe('Endpoints', () => {
expect(data.name).toStrictEqual(params.name); expect(data.name).toStrictEqual(params.name);
expect(data.age).toStrictEqual(params.age); 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', () => { describe('Globals', () => {
@@ -44,6 +62,15 @@ describe('Endpoints', () => {
expect(status).toBe(200); expect(status).toBe(200);
expect(params).toMatchObject(data); 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', () => { describe('API', () => {

View File

@@ -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',
},
],
},
], ],
}); });

View File

@@ -10,7 +10,9 @@ type Query {
docAccessUser(id: String!): usersDocAccess docAccessUser(id: String!): usersDocAccess
meUser: usersMe meUser: usersMe
initializedUser: Boolean 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 Access: Access
} }
@@ -1096,23 +1098,292 @@ type usersMe {
collection: String collection: String
} }
type Preference { type PayloadPreference {
key: String! id: String
user: PayloadPreference_User_Relationship!
key: String
value: JSON 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). 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 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 { type Access {
canAccessAdmin: Boolean! canAccessAdmin: Boolean!
collection1: collection1Access collection1: collection1Access
collection2: collection2Access collection2: collection2Access
users: usersAccess users: usersAccess
payload_preferences: payload_preferencesAccess
} }
type collection1Access { type collection1Access {
@@ -1758,6 +2029,157 @@ type UsersUnlockAccess {
where: JSONObject 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 { type Mutation {
createCollection1(data: mutationCollection1Input!, draft: Boolean): Collection1 createCollection1(data: mutationCollection1Input!, draft: Boolean): Collection1
updateCollection1(id: String!, data: mutationCollection1UpdateInput!, draft: Boolean, autosave: 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! forgotPasswordUser(email: String!, disableEmail: Boolean, expiration: Int): Boolean!
resetPasswordUser(token: String, password: String): usersResetPassword resetPasswordUser(token: String, password: String): usersResetPassword
verifyEmailUser(token: String): Boolean verifyEmailUser(token: String): Boolean
updatePreference(key: String!, value: JSON): Preference createPayloadPreference(data: mutationPayloadPreferenceInput!, draft: Boolean): PayloadPreference
deletePreference(key: String!): Preference updatePayloadPreference(id: String!, data: mutationPayloadPreferenceUpdateInput!, draft: Boolean, autosave: Boolean): PayloadPreference
deletePayloadPreference(id: String!): PayloadPreference
} }
input mutationCollection1Input { input mutationCollection1Input {
@@ -1897,4 +2320,38 @@ type usersLoginResult {
type usersResetPassword { type usersResetPassword {
token: String token: String
user: User 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
} }