Skip to content

Commit

Permalink
Consolidate concept of sudo internally (#6520)
Browse files Browse the repository at this point in the history
  • Loading branch information
timleslie authored Sep 10, 2021
1 parent e84f8f6 commit 1b0a2f5
Show file tree
Hide file tree
Showing 9 changed files with 42 additions and 31 deletions.
5 changes: 5 additions & 0 deletions .changeset/nine-coins-yawn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@keystone-next/keystone': major
---

Removed `context.schemaName` from the `context` object. This value was an internal API which is no longer required.
6 changes: 6 additions & 0 deletions .changeset/short-jokes-hug.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@keystone-next/auth': major
'@keystone-next/keystone': major
---

Renamed the `skipAccessControl` argument to `createContext` to `sudo` for consistency with `context.sudo()`.
3 changes: 0 additions & 3 deletions docs/pages/docs/apis/context.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ context = {
// Internal state
totalResults,
maxTotalResults,
schemaName,

// Deprecated
gqlNames,
Expand Down Expand Up @@ -155,8 +154,6 @@ These properties are used internally by Keystone and generally do not need to be

`maxTotalResults`: The maximum number of results which can be returned before a query limit error is triggered. See [`config.graphql.queryLimits`](./apis/config#graphql).

`schemaName`: The internal name used by Keystone to refer to the GraphQL schema.

### Deprecated

The following properties are deprecated and should not be used.
Expand Down
2 changes: 1 addition & 1 deletion packages/auth/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ export function createAuth<GeneratedListTypes extends BaseGeneratedListTypes>({
...sessionStrategy,
get: async ({ req, createContext }) => {
const session = await get({ req, createContext });
const sudoContext = createContext({}).sudo();
const sudoContext = createContext({ sudo: true });
if (
!session ||
!session.listKey ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ export function createListsAPI(config: KeystoneConfig, prismaClient: any) {
const { getKeystone } = createSystem(initConfig(config));
const keystone = getKeystone(prismaClient);
keystone.connect();
return keystone.createContext().sudo().lists;
return keystone.createContext({ sudo: true }).lists;
}
26 changes: 11 additions & 15 deletions packages/keystone/src/lib/context/createContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ import { createFilesContext } from './createFilesContext';

export function makeCreateContext({
graphQLSchema,
internalSchema,
sudoGraphQLSchema,
prismaClient,
gqlNamesByList,
config,
lists,
}: {
graphQLSchema: GraphQLSchema;
internalSchema: GraphQLSchema;
sudoGraphQLSchema: GraphQLSchema;
config: KeystoneConfig;
prismaClient: PrismaClient;
gqlNamesByList: Record<string, GqlNames>;
Expand All @@ -44,23 +44,21 @@ export function makeCreateContext({
publicDbApiFactories[listKey] = getDbAPIFactory(gqlNames, graphQLSchema);
}

const internalDbApiFactories: Record<string, ReturnType<typeof getDbAPIFactory>> = {};
const sudoDbApiFactories: Record<string, ReturnType<typeof getDbAPIFactory>> = {};
for (const [listKey, gqlNames] of Object.entries(gqlNamesByList)) {
internalDbApiFactories[listKey] = getDbAPIFactory(gqlNames, internalSchema);
sudoDbApiFactories[listKey] = getDbAPIFactory(gqlNames, sudoGraphQLSchema);
}

const createContext = ({
sessionContext,
skipAccessControl = false,
sudo = false,
req,
schemaName = 'public',
}: {
sessionContext?: SessionContext<any>;
skipAccessControl?: boolean;
sudo?: Boolean;
req?: IncomingMessage;
schemaName?: 'public' | 'internal';
} = {}): KeystoneContext => {
const schema = schemaName === 'public' ? graphQLSchema : internalSchema;
const schema = sudo ? sudoGraphQLSchema : graphQLSchema;

const rawGraphQL: KeystoneGraphQLAPI<any>['raw'] = ({ query, variables }) => {
const source = typeof query === 'string' ? query : print(query);
Expand All @@ -78,20 +76,18 @@ export function makeCreateContext({
const dbAPI: KeystoneContext['db']['lists'] = {};
const itemAPI: KeystoneContext['lists'] = {};
const contextToReturn: KeystoneContext = {
schemaName,
db: { lists: dbAPI },
lists: itemAPI,
totalResults: 0,
prisma: prismaClient,
graphql: { raw: rawGraphQL, run: runGraphQL, schema },
maxTotalResults: config.graphql?.queryLimits?.maxTotalResults ?? Infinity,
sudo: () =>
createContext({ sessionContext, skipAccessControl: true, req, schemaName: 'internal' }),
exitSudo: () => createContext({ sessionContext, skipAccessControl: false, req }),
sudo: () => createContext({ sessionContext, sudo: true, req }),
exitSudo: () => createContext({ sessionContext, sudo: false, req }),
withSession: session =>
createContext({
sessionContext: { ...sessionContext, session } as SessionContext<any>,
skipAccessControl,
sudo,
req,
}),
req,
Expand All @@ -106,7 +102,7 @@ export function makeCreateContext({
contextToReturn.experimental = { initialisedLists: lists };
}

const dbAPIFactories = schemaName === 'public' ? publicDbApiFactories : internalDbApiFactories;
const dbAPIFactories = sudo ? sudoDbApiFactories : publicDbApiFactories;
for (const listKey of Object.keys(gqlNamesByList)) {
dbAPI[listKey] = dbAPIFactories[listKey](contextToReturn);
itemAPI[listKey] = itemAPIForList(listKey, contextToReturn, dbAPI[listKey]);
Expand Down
26 changes: 17 additions & 9 deletions packages/keystone/src/lib/createSystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,26 @@ import { makeCreateContext } from './context/createContext';
import { initialiseLists } from './core/types-for-lists';

export function getDBProvider(db: KeystoneConfig['db']): DatabaseProvider {
if (db.provider === 'postgresql') {
return 'postgresql';
} else if (db.provider === 'sqlite') {
return 'sqlite';
} else {
if (!['postgresql', 'sqlite'].includes(db.provider)) {
throw new Error(
'Invalid db configuration. Please specify db.provider as either "sqlite" or "postgresql"'
);
}
return db.provider;
}

function getInternalGraphQLSchema(config: KeystoneConfig, provider: DatabaseProvider) {
function getSudoGraphQLSchema(config: KeystoneConfig, provider: DatabaseProvider) {
// This function creates a GraphQLSchema based on a modified version of the provided config.
// The modifications are:
// * All list level access control is disabled
// * All field level access control is disabled
// * All graphql.omit configuration is disabled
// * All fields are explicitly made filterable and orderable
//
// These changes result in a schema without any restrictions on the CRUD
// operations that can be run.
//
// The resulting schema is used as the GraphQL schema when calling `context.sudo()`.
const transformedConfig: KeystoneConfig = {
...config,
lists: Object.fromEntries(
Expand Down Expand Up @@ -63,7 +71,7 @@ export function createSystem(config: KeystoneConfig) {

const graphQLSchema = createGraphQLSchema(config, lists, adminMeta);

const internalGraphQLSchema = getInternalGraphQLSchema(config, provider);
const sudoGraphQLSchema = getSudoGraphQLSchema(config, provider);

return {
graphQLSchema,
Expand All @@ -83,7 +91,7 @@ export function createSystem(config: KeystoneConfig) {

const createContext = makeCreateContext({
graphQLSchema,
internalSchema: internalGraphQLSchema,
sudoGraphQLSchema,
config,
prismaClient,
gqlNamesByList: Object.fromEntries(
Expand All @@ -95,7 +103,7 @@ export function createSystem(config: KeystoneConfig) {
return {
async connect() {
await prismaClient.$connect();
const context = createContext({ skipAccessControl: true, schemaName: 'internal' });
const context = createContext({ sudo: true });
await config.db.onConnect?.(context);
},
async disconnect() {
Expand Down
1 change: 0 additions & 1 deletion packages/keystone/src/types/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ export type KeystoneContext = {
images: ImagesContext | undefined;
totalResults: number;
maxTotalResults: number;
schemaName: 'public' | 'internal';
/** @deprecated */
gqlNames: (listKey: string) => GqlNames;
experimental?: {
Expand Down
2 changes: 1 addition & 1 deletion packages/keystone/src/types/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export type FieldDefaultValue<T, TGeneratedListTypes extends BaseGeneratedListTy

export type CreateContext = (args: {
sessionContext?: SessionContext<any>;
skipAccessControl?: boolean;
sudo?: boolean;
req?: IncomingMessage;
}) => KeystoneContext;

Expand Down

0 comments on commit 1b0a2f5

Please sign in to comment.