Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add listKey argument to hooks #3420

Merged
merged 1 commit into from
Aug 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/big-jeans-itch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@keystonejs/keystone': minor
---

Added `listKey` as an argument to all hooks.
26 changes: 26 additions & 0 deletions docs/api/hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ The result is passed to [the next function in the execution order](/docs/guides/
| `originalInput` | `Object` | The data received by the GraphQL mutation |
| `resolvedData` | `Object` | The data received by the GraphQL mutation plus defaults values |
| `context` | `Apollo Context` | The [Apollo `context` object](https://www.apollographql.com/docs/apollo-server/data/data/#context-argument) for this request |
| `listKey` | `String` | The key for the list being operated on |

#### Usage

Expand All @@ -169,6 +170,7 @@ const resolveInput = ({
originalInput,
resolvedData,
context,
listKey,
}) => {
// Input resolution logic. Object returned is used in place of `resolvedData`.
return resolvedData;
Expand All @@ -195,6 +197,7 @@ Return values are ignored.
| `resolvedData` | `Object` | The data received by the GraphQL mutation plus defaults values |
| `context` | `Apollo Context` | The [Apollo `context` object](https://www.apollographql.com/docs/apollo-server/data/data/#context-argument) for this request |
| `addFieldValidationError` | `Function` | Used to set a field validation error; accepts a `String` |
| `listKey` | `String` | The key for the list being operated on |

#### Usage

Expand All @@ -208,6 +211,7 @@ const validateInput = ({
resolvedData,
context,
addFieldValidationError,
listKey,
}) => {
// Throw error objects or register validation errors with addFieldValidationError(<String>)
// Return values ignored
Expand All @@ -233,6 +237,7 @@ Return values are ignored.
| `originalInput` | `Object` | The data received by the GraphQL mutation |
| `resolvedData` | `Object` | The data received by the GraphQL mutation plus defaults values |
| `context` | `Apollo Context` | The [Apollo `context` object](https://www.apollographql.com/docs/apollo-server/data/data/#context-argument) for this request |
| `listKey` | `String` | The key for the list being operated on |

#### Usage

Expand All @@ -245,6 +250,7 @@ const beforeChange = ({
originalInput,
resolvedData,
context,
listKey,
}) => {
// Perform side effects
// Return values ignored
Expand Down Expand Up @@ -274,6 +280,7 @@ Return values are ignored.
| `originalInput` | `Object` | The data received by the GraphQL mutation |
| `updatedItem` | `Object` | The new/currently stored item |
| `context` | `Apollo Context` | The [Apollo `context` object](https://www.apollographql.com/docs/apollo-server/data/data/#context-argument) for this request |
| `listKey` | `String` | The key for the list being operated on |

#### Usage

Expand All @@ -286,6 +293,7 @@ const afterChange = ({
originalInput,
updatedItem,
context,
listKey,
}) => {
// Perform side effects
// Return values ignored
Expand All @@ -309,6 +317,7 @@ Should throw or register errors with `addFieldValidationError(<String>)` if the
| `existingItem` | `Object` | The current stored item |
| `context` | `Apollo Context` | The [Apollo `context` object](https://www.apollographql.com/docs/apollo-server/data/data/#context-argument) for this request |
| `addFieldValidationError` | `Function` | Used to set a field validation error; accepts a `String` |
| `listKey` | `String` | The key for the list being operated on |

#### Usage

Expand All @@ -320,6 +329,7 @@ const validateDelete = ({
existingItem,
context,
addFieldValidationError,
listKey,
}) => {
// Throw error objects or register validation errors with addFieldValidationError(<String>)
// Return values ignored
Expand All @@ -343,6 +353,7 @@ Return values are ignored.
| `operation` | `String` | The operation being performed (`delete` in this case) |
| `existingItem` | `Object` | The current stored item |
| `context` | `Apollo Context` | The [Apollo `context` object](https://www.apollographql.com/docs/apollo-server/data/data/#context-argument) for this request |
| `listKey` | `String` | The key for the list being operated on |

#### Usage

Expand All @@ -353,6 +364,7 @@ const beforeDelete = ({
operation,
existingItem,
context,
listKey,
}) => {
// Perform side effects
// Return values ignored
Expand All @@ -378,6 +390,7 @@ Return values are ignored.
| `operation` | `String` | The operation being performed (`delete` in this case) |
| `existingItem` | `Object` | The previously stored item, now deleted |
| `context` | `Apollo Context` | The [Apollo `context` object](https://www.apollographql.com/docs/apollo-server/data/data/#context-argument) for this request |
| `listKey` | `String` | The key for the list being operated on |

#### Usage

Expand All @@ -388,6 +401,7 @@ const afterDelete = ({
operation,
existingItem,
context,
listKey,
}) => {
// Perform side effects
// Return values ignored
Expand All @@ -412,6 +426,7 @@ The result is passed to [the next function in the execution order](/docs/guides/
| `operation` | `String` | The operation being performed (`authenticate` in this case) |
| `originalInput` | `Object` | The data received by the GraphQL mutation |
| `context` | `Apollo Context` | The [Apollo `context` object](https://www.apollographql.com/docs/apollo-server/essentials/data.html#context) for this request |
| `listKey` | `String` | The key for the list being operated on |

#### Usage

Expand All @@ -422,6 +437,7 @@ const resolveAuthInput = ({
operation,
originalInput,
context,
listKey,
}) => {
// Input resolution logic
// Object returned is used in place of resolvedData
Expand All @@ -448,6 +464,7 @@ Return values are ignored.
| `resolvedData` | `Object` | The data received by the GraphQL mutation or returned by `resolveAuthInput`, if defined |
| `context` | `Apollo Context` | The [Apollo `context` object](https://www.apollographql.com/docs/apollo-server/essentials/data.html#context) for this request |
| `addValidationError` | `Function` | Used to set a validation error; accepts a message `String` |
| `listKey` | `String` | The key for the list being operated on |

#### Usage

Expand All @@ -460,6 +477,7 @@ const validateAuthInput = ({
resolvedData,
context,
addFieldValidationError,
listKey,
}) => {
// Throw error objects or register validation errors with addValidationError(<String>)
// Return values ignored
Expand All @@ -484,6 +502,7 @@ Return values are ignored.
| `originalInput` | `Object` | The data received by the GraphQL mutation |
| `resolvedData` | `Object` | The data received by the GraphQL mutation or returned by `resolveAuthInput`, if defined |
| `context` | `Apollo Context` | The [Apollo `context` object](https://www.apollographql.com/docs/apollo-server/essentials/data.html#context) for this request |
| `listKey` | `String` | The key for the list being operated on |

#### Usage

Expand All @@ -495,6 +514,7 @@ const beforeAuth = ({
originalInput,
resolvedData,
context,
listKey,
}) => {
// Perform side effects
// Return values ignored
Expand Down Expand Up @@ -525,6 +545,7 @@ Return values are ignored.
| `originalInput` | `Object` | The data received by the GraphQL mutation |
| `resolvedData` | `Object` | The data received by the GraphQL mutation or returned by `resolveAuthInput`, if defined |
| `context` | `Apollo Context` | The [Apollo `context` object](https://www.apollographql.com/docs/apollo-server/essentials/data.html#context) for this request |
| `listKey` | `String` | The key for the list being operated on |

#### Usage

Expand All @@ -540,6 +561,7 @@ const afterAuth = ({
originalInput,
resolvedData,
context,
listKey,
}) => {
// Perform side effects
// Return values ignored
Expand All @@ -562,6 +584,7 @@ Return values are ignored.
| :---------- | :--------------- | :---------------------------------------------------------------------------------------------------------------------------- |
| `operation` | `String` | The operation being performed (`authenticate` in this case) |
| `context` | `Apollo Context` | The [Apollo `context` object](https://www.apollographql.com/docs/apollo-server/essentials/data.html#context) for this request |
| `listKey` | `String` | The key for the list being operated on |

#### Usage

Expand All @@ -571,6 +594,7 @@ Return values are ignored.
const beforeUnauth = ({
operation,
context,
listKey,
}) => {
// Perform side effects
// Return values ignored
Expand Down Expand Up @@ -598,6 +622,7 @@ Return values are ignored.
| `listKey` | `String` | The list key of the unauthenticated user (if there was one) |
| `itemid` | `String` | The item ID of the unauthenticated user (if there was one) |
| `context` | `Apollo Context` | The [Apollo `context` object](https://www.apollographql.com/docs/apollo-server/essentials/data.html#context) for this request |
| `listKey` | `String` | The key for the list being operated on |

#### Usage

Expand All @@ -613,6 +638,7 @@ const afterAuth = ({
originalInput,
resolvedData,
context,
listKey,
}) => {
// Perform side effects
// Return values ignored
Expand Down
21 changes: 14 additions & 7 deletions packages/keystone/lib/ListTypes/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ class HookManager {
}

async resolveInput({ resolvedData, existingItem, context, operation, originalInput }) {
const args = { resolvedData, existingItem, context, originalInput, operation };
const { listKey } = this;
const args = { resolvedData, existingItem, context, originalInput, operation, listKey };

// First we run the field type hooks
// NOTE: resolveInput is run on _every_ field, regardless if it has a value
Expand Down Expand Up @@ -70,7 +71,8 @@ class HookManager {
}

async validateInput({ resolvedData, existingItem, context, operation, originalInput }) {
const args = { resolvedData, existingItem, context, originalInput, operation };
const { listKey } = this;
const args = { resolvedData, existingItem, context, originalInput, operation, listKey };
// Check for isRequired
const fieldValidationErrors = this.fields
.filter(
Expand All @@ -97,7 +99,8 @@ class HookManager {
}

async validateDelete({ existingItem, context, operation }) {
const args = { existingItem, context, operation };
const { listKey } = this;
const args = { existingItem, context, operation, listKey };
const fields = this.fields;
await this._validateHook({ args, fields, operation, hookName: 'validateDelete' });
}
Expand Down Expand Up @@ -131,22 +134,26 @@ class HookManager {
}

async beforeChange({ resolvedData, existingItem, context, operation, originalInput }) {
const args = { resolvedData, existingItem, context, originalInput, operation };
const { listKey } = this;
const args = { resolvedData, existingItem, context, originalInput, operation, listKey };
await this._runHook({ args, fieldObject: resolvedData, hookName: 'beforeChange' });
}

async beforeDelete({ existingItem, context, operation }) {
const args = { existingItem, context, operation };
const { listKey } = this;
const args = { existingItem, context, operation, listKey };
await this._runHook({ args, fieldObject: existingItem, hookName: 'beforeDelete' });
}

async afterChange({ updatedItem, existingItem, context, operation, originalInput }) {
const args = { updatedItem, originalInput, existingItem, context, operation };
const { listKey } = this;
const args = { updatedItem, originalInput, existingItem, context, operation, listKey };
await this._runHook({ args, fieldObject: updatedItem, hookName: 'afterChange' });
}

async afterDelete({ existingItem, context, operation }) {
const args = { existingItem, context, operation };
const { listKey } = this;
const args = { existingItem, context, operation, listKey };
await this._runHook({ args, fieldObject: existingItem, hookName: 'afterDelete' });
}

Expand Down
35 changes: 28 additions & 7 deletions packages/keystone/lib/providers/listAuth.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,20 @@ const { throwAccessDenied, ValidationFailureError } = require('../ListTypes/grap
const graphqlLogger = logger('graphql');

class HookManager {
constructor({ name, hooks = {} }) {
constructor({ name, listKey, hooks = {} }) {
this.name = name;
this.hooks = hooks;
this.listKey = listKey;
}

async resolveAuthInput({ context, operation, originalInput }) {
const { listKey } = this;
let resolvedData = originalInput;

if (this.hooks.resolveAuthInput) {
const args = { context, originalInput, operation, listKey };
// And run any list-level hook
resolvedData = await this.hooks.resolveAuthInput({ context, originalInput, operation });
resolvedData = await this.hooks.resolveAuthInput(args);
if (typeof resolvedData !== 'object') {
const method = `${this.name}.hooks.resolveAuthInput()`;
throw new Error(
Expand All @@ -29,7 +32,8 @@ class HookManager {
}

async validateAuthInput({ resolvedData, context, operation, originalInput }) {
const args = { resolvedData, context, originalInput, operation };
const { listKey } = this;
const args = { resolvedData, context, originalInput, operation, listKey };

if (this.hooks['validateAuthInput']) {
const listValidationErrors = [];
Expand All @@ -55,7 +59,8 @@ class HookManager {
}

async beforeAuth({ resolvedData, context, operation, originalInput }) {
const args = { resolvedData, context, originalInput, operation };
const { listKey } = this;
const args = { resolvedData, context, originalInput, operation, listKey };
if (this.hooks.beforeAuth) await this.hooks.beforeAuth(args);
}

Expand All @@ -69,12 +74,24 @@ class HookManager {
resolvedData,
context,
}) {
const args = { resolvedData, context, operation, originalInput, item, success, message, token };
const { listKey } = this;
const args = {
resolvedData,
context,
operation,
originalInput,
item,
success,
message,
token,
listKey,
};
if (this.hooks.afterAuth) await this.hooks.afterAuth(args);
}

async beforeUnauth({ operation, context }) {
const args = { context, operation };
const { listKey } = this;
const args = { context, operation, listKey };
if (this.hooks.beforeUnauth) await this.hooks.beforeUnauth(args);
}

Expand All @@ -99,7 +116,11 @@ class ListAuthProvider {
unauthenticateOutputName: `unauthenticate${itemQueryName}Output`,
updateAuthenticatedMutationName: `updateAuthenticated${itemQueryName}`,
};
this.hookManager = new HookManager({ name: authStrategy.constructor.name, hooks });
this.hookManager = new HookManager({
name: authStrategy.constructor.name,
hooks,
listKey: list.key,
});
// Record GQL names in the strategy
authStrategy.gqlNames = this.gqlNames;
}
Expand Down