Skip to content

Commit

Permalink
share the error between methods
Browse files Browse the repository at this point in the history
  • Loading branch information
dcousens committed Oct 5, 2022
1 parent be5e789 commit 6ca572b
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 45 deletions.
13 changes: 13 additions & 0 deletions packages/core/src/lib/core/access-control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,19 @@ import { accessReturnError, extensionError } from './graphql-errors';
import { InitialisedList } from './types-for-lists';
import { InputFilter } from './where-inputs';

export function cannotForItem(operation: string, list: InitialisedList) {
return (
`You cannot '${operation}' that ${list.listKey}` +
(operation === 'create' ? '' : ' - it may not exist')
);
}

export function cannotForItemFields(operation: string, list: InitialisedList, fieldsDenied: string[]) {
return `You cannot '${operation}' that ${
list.listKey
} - you cannot '${operation}' the fields ${JSON.stringify(fieldsDenied)}`;
}

export async function getOperationAccess(
list: InitialisedList,
context: KeystoneContext,
Expand Down
18 changes: 3 additions & 15 deletions packages/core/src/lib/core/mutations/access-control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { accessDeniedError, accessReturnError, extensionError } from '../graphql
import { mapUniqueWhereToWhere } from '../queries/resolvers';
import { InitialisedList } from '../types-for-lists';
import { runWithPrisma } from '../utils';
import { cannotForItem, cannotForItemFields } from '../access-control';
import {
InputFilter,
resolveUniqueWhereInput,
Expand All @@ -11,19 +12,6 @@ import {
UniquePrismaFilter,
} from '../where-inputs';

function cannotForItemFields(operation: string, list: InitialisedList, fieldsDenied: string[]) {
return `You cannot '${operation}' that ${
list.listKey
} - you cannot '${operation}' the fields ${JSON.stringify(fieldsDenied)}`;
}

function cannotForItem(operation: string, list: InitialisedList) {
return (
`You cannot '${operation}' that ${list.listKey}` +
(operation === 'create' ? '' : ' - it may not exist')
);
}

async function getFilteredItem(
list: InitialisedList,
context: KeystoneContext,
Expand Down Expand Up @@ -235,7 +223,7 @@ export async function getAccessControlledItemForUpdate(
accessFilters: boolean | InputFilter,
inputData: Record<string, any>
) {
// apply filter access control - throws accessDeniedError on item not found
// apply access.filter.* controls
const item = await getFilteredItem(list, context, uniqueWhere!, accessFilters, 'update');

await enforceListLevelAccessControl({
Expand Down Expand Up @@ -263,7 +251,7 @@ export async function getAccessControlledItemForDelete(
uniqueWhere: UniquePrismaFilter,
accessFilters: boolean | InputFilter
) {
// apply filter access control - throws accessDeniedError on item not found
// apply access.filter.* controls
const item = await getFilteredItem(list, context, uniqueWhere!, accessFilters, 'delete');

await enforceListLevelAccessControl({
Expand Down
45 changes: 15 additions & 30 deletions packages/core/src/lib/core/mutations/create-update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
relationshipError,
resolverError,
} from '../graphql-errors';
import { getOperationAccess, getAccessFilters } from '../access-control';
import { cannotForItem, getOperationAccess, getAccessFilters } from '../access-control';
import { checkFilterOrderAccess } from '../filter-order-access';
import {
RelationshipErrors,
Expand All @@ -34,16 +34,8 @@ import { validateUpdateCreate } from './validation';
async function createSingle(
{ data: rawData }: { data: Record<string, any> },
list: InitialisedList,
context: KeystoneContext,
operationAccess: boolean
context: KeystoneContext
) {
// Operation level access control
if (!operationAccess) {
throw accessDeniedError(
`You cannot perform the 'create' operation on the list '${list.listKey}'.`
);
}

// Item access control. Will throw an accessDeniedError if not allowed.
await applyAccessControlForCreate(list, context, rawData);

Expand Down Expand Up @@ -74,10 +66,10 @@ export class NestedMutationState {
async create(data: Record<string, any>, list: InitialisedList) {
const context = this.#context;

// Check operation permission to pass into single operation
const operationAccess = await getOperationAccess(list, context, 'create');
if (!operationAccess) throw accessDeniedError(cannotForItem('create', list));

const { item, afterOperation } = await createSingle({ data }, list, context, operationAccess);
const { item, afterOperation } = await createSingle({ data }, list, context);

this.#afterOperations.push(() => afterOperation(item));
return { id: item.id as IdType };
Expand All @@ -95,8 +87,9 @@ export async function createOne(
) {
// Check operation permission to pass into single operation
const operationAccess = await getOperationAccess(list, context, 'create');
if (!operationAccess) throw accessDeniedError(cannotForItem('create', list));

const { item, afterOperation } = await createSingle(createInput, list, context, operationAccess);
const { item, afterOperation } = await createSingle(createInput, list, context);

await afterOperation(item);

Expand All @@ -112,10 +105,10 @@ export async function createMany(
const operationAccess = await getOperationAccess(list, context, 'create');

return createInputs.data.map(async data => {
const { item, afterOperation } = await createSingle({ data }, list, context, operationAccess);
if (!operationAccess) throw accessDeniedError(cannotForItem('create', list));

const { item, afterOperation } = await createSingle({ data }, list, context);
await afterOperation(item);

return item;
});
}
Expand All @@ -124,16 +117,8 @@ async function updateSingle(
updateInput: { where: UniqueInputFilter; data: Record<string, any> },
list: InitialisedList,
context: KeystoneContext,
accessFilters: boolean | InputFilter,
operationAccess: boolean
accessFilters: boolean | InputFilter
) {
// Operation level access control
if (!operationAccess) {
throw accessDeniedError(
`You cannot perform the 'update' operation on the list '${list.listKey}'.`
);
}

const { where: uniqueInput, data: rawData } = updateInput;
// Validate and resolve the input filter
const uniqueWhere = await resolveUniqueWhereInput(uniqueInput, list, context);
Expand Down Expand Up @@ -174,29 +159,29 @@ export async function updateOne(
list: InitialisedList,
context: KeystoneContext
) {
// Check operation permission to pass into single operation
const operationAccess = await getOperationAccess(list, context, 'update');
if (!operationAccess) throw accessDeniedError(cannotForItem('update', list));

// Get list-level access control filters
const accessFilters = await getAccessFilters(list, context, 'update');

return updateSingle(updateInput, list, context, accessFilters, operationAccess);
return updateSingle(updateInput, list, context, accessFilters);
}

export async function updateMany(
{ data }: { data: { where: UniqueInputFilter; data: Record<string, any> }[] },
list: InitialisedList,
context: KeystoneContext
) {
// Check operation permission to pass into single operation
const operationAccess = await getOperationAccess(list, context, 'update');
if (!operationAccess) throw accessDeniedError(cannotForItem('update', list));

// Get list-level access control filters
const accessFilters = await getAccessFilters(list, context, 'update');

return data.map(async updateInput =>
updateSingle(updateInput, list, context, accessFilters, operationAccess)
);
return data.map(async updateInput => {
return updateSingle(updateInput, list, context, accessFilters)
});
}

async function getResolvedData(
Expand Down

0 comments on commit 6ca572b

Please sign in to comment.