444 lines
14 KiB
TypeScript
444 lines
14 KiB
TypeScript
/* eslint-disable no-param-reassign */
|
|
import { DateTimeResolver } from 'graphql-scalars';
|
|
import {
|
|
GraphQLString,
|
|
GraphQLObjectType,
|
|
GraphQLBoolean,
|
|
GraphQLNonNull,
|
|
GraphQLInt,
|
|
} from 'graphql';
|
|
|
|
import formatName from '../../graphql/utilities/formatName';
|
|
import buildPaginatedListType from '../../graphql/schema/buildPaginatedListType';
|
|
import buildMutationInputType, { getCollectionIDType } from '../../graphql/schema/buildMutationInputType';
|
|
import { buildVersionCollectionFields } from '../../versions/buildCollectionFields';
|
|
import createResolver from './resolvers/create';
|
|
import updateResolver from './resolvers/update';
|
|
import findResolver from './resolvers/find';
|
|
import findByIDResolver from './resolvers/findByID';
|
|
import findVersionByIDResolver from './resolvers/findVersionByID';
|
|
import findVersionsResolver from './resolvers/findVersions';
|
|
import restoreVersionResolver from './resolvers/restoreVersion';
|
|
import me from '../../auth/graphql/resolvers/me';
|
|
import init from '../../auth/graphql/resolvers/init';
|
|
import login from '../../auth/graphql/resolvers/login';
|
|
import logout from '../../auth/graphql/resolvers/logout';
|
|
import forgotPassword from '../../auth/graphql/resolvers/forgotPassword';
|
|
import resetPassword from '../../auth/graphql/resolvers/resetPassword';
|
|
import verifyEmail from '../../auth/graphql/resolvers/verifyEmail';
|
|
import unlock from '../../auth/graphql/resolvers/unlock';
|
|
import refresh from '../../auth/graphql/resolvers/refresh';
|
|
import { Payload } from '../../payload';
|
|
import { Field, fieldAffectsData } from '../../fields/config/types';
|
|
import buildObjectType, { ObjectTypeConfig } from '../../graphql/schema/buildObjectType';
|
|
import buildWhereInputType from '../../graphql/schema/buildWhereInputType';
|
|
import getDeleteResolver from './resolvers/delete';
|
|
import { toWords, formatNames } from '../../utilities/formatLabels';
|
|
import { Collection, SanitizedCollectionConfig } from '../config/types';
|
|
import { buildPolicyType } from '../../graphql/schema/buildPoliciesType';
|
|
import { docAccessResolver } from './resolvers/docAccess';
|
|
|
|
function initCollectionsGraphQL(payload: Payload): void {
|
|
Object.keys(payload.collections).forEach((slug) => {
|
|
const collection: Collection = payload.collections[slug];
|
|
const {
|
|
config: {
|
|
graphQL = {} as SanitizedCollectionConfig['graphQL'],
|
|
fields,
|
|
timestamps,
|
|
versions,
|
|
},
|
|
} = collection;
|
|
|
|
let singularName;
|
|
let pluralName;
|
|
const fromSlug = formatNames(collection.config.slug);
|
|
if (graphQL.singularName) {
|
|
singularName = toWords(graphQL.singularName, true);
|
|
} else {
|
|
singularName = fromSlug.singular;
|
|
}
|
|
if (graphQL.pluralName) {
|
|
pluralName = toWords(graphQL.pluralName, true);
|
|
} else {
|
|
pluralName = fromSlug.plural;
|
|
}
|
|
|
|
// For collections named 'Media' or similar,
|
|
// there is a possibility that the singular name
|
|
// will equal the plural name. Append `all` to the beginning
|
|
// of potential conflicts
|
|
if (singularName === pluralName) {
|
|
pluralName = `all${singularName}`;
|
|
}
|
|
|
|
collection.graphQL = {} as Collection['graphQL'];
|
|
|
|
const idField = fields.find((field) => fieldAffectsData(field) && field.name === 'id');
|
|
const idType = getCollectionIDType(collection.config);
|
|
|
|
const baseFields: ObjectTypeConfig = {};
|
|
|
|
const whereInputFields = [
|
|
...fields,
|
|
];
|
|
|
|
if (!idField) {
|
|
baseFields.id = { type: idType };
|
|
whereInputFields.push({
|
|
name: 'id',
|
|
type: 'text',
|
|
});
|
|
}
|
|
|
|
if (timestamps) {
|
|
baseFields.createdAt = {
|
|
type: new GraphQLNonNull(DateTimeResolver),
|
|
};
|
|
|
|
baseFields.updatedAt = {
|
|
type: new GraphQLNonNull(DateTimeResolver),
|
|
};
|
|
|
|
whereInputFields.push({
|
|
name: 'createdAt',
|
|
label: 'Created At',
|
|
type: 'date',
|
|
});
|
|
|
|
whereInputFields.push({
|
|
name: 'updatedAt',
|
|
label: 'Updated At',
|
|
type: 'date',
|
|
});
|
|
}
|
|
|
|
const forceNullableObjectType = Boolean(versions?.drafts);
|
|
|
|
collection.graphQL.type = buildObjectType({
|
|
payload,
|
|
name: singularName,
|
|
parentName: singularName,
|
|
fields,
|
|
baseFields,
|
|
forceNullable: forceNullableObjectType,
|
|
});
|
|
|
|
collection.graphQL.whereInputType = buildWhereInputType(
|
|
singularName,
|
|
whereInputFields,
|
|
singularName,
|
|
);
|
|
|
|
if (collection.config.auth && !collection.config.auth.disableLocalStrategy) {
|
|
fields.push({
|
|
name: 'password',
|
|
label: 'Password',
|
|
type: 'text',
|
|
required: true,
|
|
});
|
|
}
|
|
|
|
collection.graphQL.mutationInputType = new GraphQLNonNull(buildMutationInputType(
|
|
payload,
|
|
singularName,
|
|
fields,
|
|
singularName,
|
|
));
|
|
|
|
collection.graphQL.updateMutationInputType = new GraphQLNonNull(buildMutationInputType(
|
|
payload,
|
|
`${singularName}Update`,
|
|
fields.filter((field) => !(fieldAffectsData(field) && field.name === 'id')),
|
|
`${singularName}Update`,
|
|
true,
|
|
));
|
|
|
|
payload.Query.fields[singularName] = {
|
|
type: collection.graphQL.type,
|
|
args: {
|
|
id: { type: new GraphQLNonNull(idType) },
|
|
draft: { type: GraphQLBoolean },
|
|
...(payload.config.localization ? {
|
|
locale: { type: payload.types.localeInputType },
|
|
fallbackLocale: { type: payload.types.fallbackLocaleInputType },
|
|
} : {}),
|
|
},
|
|
resolve: findByIDResolver(collection),
|
|
};
|
|
|
|
payload.Query.fields[pluralName] = {
|
|
type: buildPaginatedListType(pluralName, collection.graphQL.type),
|
|
args: {
|
|
where: { type: collection.graphQL.whereInputType },
|
|
draft: { type: GraphQLBoolean },
|
|
...(payload.config.localization ? {
|
|
locale: { type: payload.types.localeInputType },
|
|
fallbackLocale: { type: payload.types.fallbackLocaleInputType },
|
|
} : {}),
|
|
page: { type: GraphQLInt },
|
|
limit: { type: GraphQLInt },
|
|
sort: { type: GraphQLString },
|
|
},
|
|
resolve: findResolver(collection),
|
|
};
|
|
|
|
payload.Query.fields[`docAccess${singularName}`] = {
|
|
type: buildPolicyType({
|
|
typeSuffix: 'DocAccess',
|
|
entity: collection.config,
|
|
type: 'collection',
|
|
scope: 'docAccess',
|
|
}),
|
|
args: {
|
|
id: { type: new GraphQLNonNull(idType) },
|
|
},
|
|
resolve: docAccessResolver(),
|
|
};
|
|
|
|
payload.Mutation.fields[`create${singularName}`] = {
|
|
type: collection.graphQL.type,
|
|
args: {
|
|
data: { type: collection.graphQL.mutationInputType },
|
|
draft: { type: GraphQLBoolean },
|
|
...(payload.config.localization ? {
|
|
locale: { type: payload.types.localeInputType },
|
|
} : {}),
|
|
},
|
|
resolve: createResolver(collection),
|
|
};
|
|
|
|
payload.Mutation.fields[`update${singularName}`] = {
|
|
type: collection.graphQL.type,
|
|
args: {
|
|
id: { type: new GraphQLNonNull(idType) },
|
|
data: { type: collection.graphQL.updateMutationInputType },
|
|
draft: { type: GraphQLBoolean },
|
|
autosave: { type: GraphQLBoolean },
|
|
...(payload.config.localization ? {
|
|
locale: { type: payload.types.localeInputType },
|
|
} : {}),
|
|
},
|
|
resolve: updateResolver(collection),
|
|
};
|
|
|
|
payload.Mutation.fields[`delete${singularName}`] = {
|
|
type: collection.graphQL.type,
|
|
args: {
|
|
id: { type: new GraphQLNonNull(idType) },
|
|
},
|
|
resolve: getDeleteResolver(collection),
|
|
};
|
|
|
|
if (collection.config.versions) {
|
|
const versionCollectionFields: Field[] = [
|
|
...buildVersionCollectionFields(collection.config),
|
|
{
|
|
name: 'id',
|
|
type: 'text',
|
|
},
|
|
{
|
|
name: 'createdAt',
|
|
label: 'Created At',
|
|
type: 'date',
|
|
},
|
|
{
|
|
name: 'updatedAt',
|
|
label: 'Updated At',
|
|
type: 'date',
|
|
},
|
|
];
|
|
|
|
collection.graphQL.versionType = buildObjectType({
|
|
payload,
|
|
name: `${singularName}Version`,
|
|
fields: versionCollectionFields,
|
|
parentName: `${singularName}Version`,
|
|
forceNullable: forceNullableObjectType,
|
|
});
|
|
|
|
payload.Query.fields[`version${formatName(singularName)}`] = {
|
|
type: collection.graphQL.versionType,
|
|
args: {
|
|
id: { type: GraphQLString },
|
|
...(payload.config.localization ? {
|
|
locale: { type: payload.types.localeInputType },
|
|
fallbackLocale: { type: payload.types.fallbackLocaleInputType },
|
|
} : {}),
|
|
},
|
|
resolve: findVersionByIDResolver(collection),
|
|
};
|
|
payload.Query.fields[`versions${pluralName}`] = {
|
|
type: buildPaginatedListType(`versions${formatName(pluralName)}`, collection.graphQL.versionType),
|
|
args: {
|
|
where: {
|
|
type: buildWhereInputType(
|
|
`versions${singularName}`,
|
|
versionCollectionFields,
|
|
`versions${singularName}`,
|
|
),
|
|
},
|
|
...(payload.config.localization ? {
|
|
locale: { type: payload.types.localeInputType },
|
|
fallbackLocale: { type: payload.types.fallbackLocaleInputType },
|
|
} : {}),
|
|
page: { type: GraphQLInt },
|
|
limit: { type: GraphQLInt },
|
|
sort: { type: GraphQLString },
|
|
},
|
|
resolve: findVersionsResolver(collection),
|
|
};
|
|
payload.Mutation.fields[`restoreVersion${formatName(singularName)}`] = {
|
|
type: collection.graphQL.type,
|
|
args: {
|
|
id: { type: GraphQLString },
|
|
},
|
|
resolve: restoreVersionResolver(collection),
|
|
};
|
|
}
|
|
|
|
if (collection.config.auth) {
|
|
const authFields: Field[] = collection.config.auth.disableLocalStrategy ? [] : [{
|
|
name: 'email',
|
|
type: 'email',
|
|
required: true,
|
|
}];
|
|
collection.graphQL.JWT = buildObjectType({
|
|
payload,
|
|
name: formatName(`${slug}JWT`),
|
|
fields: [
|
|
...collection.config.fields.filter((field) => fieldAffectsData(field) && field.saveToJWT),
|
|
...authFields,
|
|
{
|
|
name: 'collection',
|
|
type: 'text',
|
|
required: true,
|
|
},
|
|
],
|
|
parentName: formatName(`${slug}JWT`),
|
|
});
|
|
|
|
payload.Query.fields[`me${singularName}`] = {
|
|
type: new GraphQLObjectType({
|
|
name: formatName(`${slug}Me`),
|
|
fields: {
|
|
token: {
|
|
type: GraphQLString,
|
|
},
|
|
user: {
|
|
type: collection.graphQL.type,
|
|
},
|
|
exp: {
|
|
type: GraphQLInt,
|
|
},
|
|
collection: {
|
|
type: GraphQLString,
|
|
},
|
|
},
|
|
}),
|
|
resolve: me(collection),
|
|
};
|
|
|
|
payload.Query.fields[`initialized${singularName}`] = {
|
|
type: GraphQLBoolean,
|
|
resolve: init(collection),
|
|
};
|
|
|
|
payload.Mutation.fields[`refreshToken${singularName}`] = {
|
|
type: new GraphQLObjectType({
|
|
name: formatName(`${slug}Refreshed${singularName}`),
|
|
fields: {
|
|
user: {
|
|
type: collection.graphQL.JWT,
|
|
},
|
|
refreshedToken: {
|
|
type: GraphQLString,
|
|
},
|
|
exp: {
|
|
type: GraphQLInt,
|
|
},
|
|
},
|
|
}),
|
|
args: {
|
|
token: { type: GraphQLString },
|
|
},
|
|
resolve: refresh(collection),
|
|
};
|
|
|
|
payload.Mutation.fields[`logout${singularName}`] = {
|
|
type: GraphQLString,
|
|
resolve: logout(collection),
|
|
};
|
|
|
|
if (!collection.config.auth.disableLocalStrategy) {
|
|
if (collection.config.auth.maxLoginAttempts > 0) {
|
|
payload.Mutation.fields[`unlock${singularName}`] = {
|
|
type: new GraphQLNonNull(GraphQLBoolean),
|
|
args: {
|
|
email: { type: new GraphQLNonNull(GraphQLString) },
|
|
},
|
|
resolve: unlock(collection),
|
|
};
|
|
}
|
|
|
|
payload.Mutation.fields[`login${singularName}`] = {
|
|
type: new GraphQLObjectType({
|
|
name: formatName(`${slug}LoginResult`),
|
|
fields: {
|
|
token: {
|
|
type: GraphQLString,
|
|
},
|
|
user: {
|
|
type: collection.graphQL.type,
|
|
},
|
|
exp: {
|
|
type: GraphQLInt,
|
|
},
|
|
},
|
|
}),
|
|
args: {
|
|
email: { type: GraphQLString },
|
|
password: { type: GraphQLString },
|
|
},
|
|
resolve: login(collection),
|
|
};
|
|
|
|
payload.Mutation.fields[`forgotPassword${singularName}`] = {
|
|
type: new GraphQLNonNull(GraphQLBoolean),
|
|
args: {
|
|
email: { type: new GraphQLNonNull(GraphQLString) },
|
|
disableEmail: { type: GraphQLBoolean },
|
|
expiration: { type: GraphQLInt },
|
|
},
|
|
resolve: forgotPassword(collection),
|
|
};
|
|
|
|
payload.Mutation.fields[`resetPassword${singularName}`] = {
|
|
type: new GraphQLObjectType({
|
|
name: formatName(`${slug}ResetPassword`),
|
|
fields: {
|
|
token: { type: GraphQLString },
|
|
user: { type: collection.graphQL.type },
|
|
},
|
|
}),
|
|
args: {
|
|
token: { type: GraphQLString },
|
|
password: { type: GraphQLString },
|
|
},
|
|
resolve: resetPassword(collection),
|
|
};
|
|
|
|
payload.Mutation.fields[`verifyEmail${singularName}`] = {
|
|
type: GraphQLBoolean,
|
|
args: {
|
|
token: { type: GraphQLString },
|
|
},
|
|
resolve: verifyEmail(collection),
|
|
};
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
export default initCollectionsGraphQL;
|