Skip to content

Commit

Permalink
add hook types
Browse files Browse the repository at this point in the history
  • Loading branch information
denolfe committed Nov 23, 2020
1 parent 7670a23 commit d10f3f1
Show file tree
Hide file tree
Showing 12 changed files with 142 additions and 54 deletions.
9 changes: 5 additions & 4 deletions src/auth/operations/forgotPassword.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import crypto from 'crypto';
import { AfterForgotPasswordHook, BeforeOperationHook } from '../../collections/config/types';
import { APIError } from '../../errors';

async function forgotPassword(incomingArgs) {
const { config, sendEmail: email } = this;

if (!Object.prototype.hasOwnProperty.call(incomingArgs.data, 'email')) {
throw new APIError('Missing email.');
throw new APIError('Missing email.', 400);
}

let args = incomingArgs;
Expand All @@ -14,7 +15,7 @@ async function forgotPassword(incomingArgs) {
// beforeOperation - Collection
// /////////////////////////////////////

await args.collection.config.hooks.beforeOperation.reduce(async (priorHook, hook) => {
await args.collection.config.hooks.beforeOperation.reduce(async (priorHook: BeforeOperationHook, hook: BeforeOperationHook) => {
await priorHook;

args = (await hook({
Expand All @@ -38,7 +39,7 @@ async function forgotPassword(incomingArgs) {
// Forget password
// /////////////////////////////////////

let token = crypto.randomBytes(20);
let token: string | Buffer = crypto.randomBytes(20);
token = token.toString('hex');

const user = await Model.findOne({ email: data.email.toLowerCase() });
Expand Down Expand Up @@ -90,7 +91,7 @@ async function forgotPassword(incomingArgs) {
// afterForgotPassword - Collection
// /////////////////////////////////////

await collectionConfig.hooks.afterForgotPassword.reduce(async (priorHook, hook) => {
await collectionConfig.hooks.afterForgotPassword.reduce(async (priorHook: AfterForgotPasswordHook, hook: AfterForgotPasswordHook) => {
await priorHook;
await hook({ args });
}, Promise.resolve());
Expand Down
3 changes: 2 additions & 1 deletion src/auth/operations/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { AuthenticationError, LockedAuth } from '../../errors';
import getCookieExpiration from '../../utilities/getCookieExpiration';
import isLocked from '../isLocked';
import removeInternalFields from '../../utilities/removeInternalFields';
import { BeforeLoginHook, BeforeOperationHook } from '../../collections/config/types';

async function login(incomingArgs) {
const { config, operations, secret } = this;
Expand All @@ -13,7 +14,7 @@ async function login(incomingArgs) {
// beforeOperation - Collection
// /////////////////////////////////////

await args.collection.config.hooks.beforeOperation.reduce(async (priorHook, hook) => {
await args.collection.config.hooks.beforeOperation.reduce(async (priorHook: BeforeOperationHook, hook: BeforeOperationHook) => {
await priorHook;

args = (await hook({
Expand Down
3 changes: 2 additions & 1 deletion src/auth/operations/refresh.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import jwt from 'jsonwebtoken';
import { BeforeOperationHook } from '../../collections/config/types';
import { Forbidden } from '../../errors';
import getCookieExpiration from '../../utilities/getCookieExpiration';

Expand All @@ -9,7 +10,7 @@ async function refresh(incomingArgs) {
// beforeOperation - Collection
// /////////////////////////////////////

await args.collection.config.hooks.beforeOperation.reduce(async (priorHook, hook) => {
await args.collection.config.hooks.beforeOperation.reduce(async (priorHook: BeforeOperationHook, hook: BeforeOperationHook) => {
await priorHook;

args = (await hook({
Expand Down
120 changes: 97 additions & 23 deletions src/collections/config/types.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import { Access, Hook } from '../../config/types';
/* eslint-disable no-use-before-define */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Access } from '../../config/types';
import { Field } from '../../fields/config/types';
import { PayloadRequest } from '../../express/types/payloadRequest';

export type ImageSize = {
name: string,
width: number,
height: number,
crop: string, // comes from sharp package
};

export type Collection = {
slug: string;
labels?: {
Expand All @@ -22,18 +17,17 @@ export type Collection = {
components?: any;
};
hooks?: {
beforeOperation?: Hook[];
beforeValidate?: Hook[];
beforeChange?: Hook[];
afterChange?: Hook[];
beforeRead?: Hook[];
afterRead?: Hook[];
beforeDelete?: Hook[];
afterDelete?: Hook[];
beforeLogin?: Hook[];
afterLogin?: Hook[];
afterForgotPassword?: Hook[];
forgotPassword?: Hook[];
beforeOperation?: BeforeOperationHook[];
beforeValidate?: BeforeValidateHook[];
beforeChange?: BeforeChangeHook[];
afterChange?: AfterChangeHook[];
beforeRead?: BeforeReadHook[];
afterRead?: AfterReadHook[];
beforeDelete?: BeforeDeleteHook[];
afterDelete?: AfterDeleteHook[];
beforeLogin?: BeforeLoginHook[];
afterLogin?: AfterLoginHook[];
afterForgotPassword?: AfterForgotPasswordHook[];
};
access?: {
create?: Access;
Expand All @@ -59,15 +53,95 @@ export type Collection = {
}
| boolean;
forgotPassword?: {
generateEmailHTML?: (args?: {token?: string, email?: string, req?: PayloadRequest}) => string,
generateEmailSubject?: (args?: {req?: PayloadRequest}) => string,
generateEmailHTML?: (args?: { token?: string, email?: string, req?: PayloadRequest }) => string,
generateEmailSubject?: (args?: { req?: PayloadRequest }) => string,
}
};
config: {[key: string]: any};
config: { [key: string]: any };
upload: {
imageSizes: ImageSize[];
staticURL: string;
staticDir: string;
adminThumbnail?: string;
};
};

export type ImageSize = {
name: string,
width: number,
height: number,
crop: string, // comes from sharp package
};

// Hooks

export type HookOperationType =
| 'create'
| 'read'
| 'update'
| 'delete'
| 'refresh'
| 'login'
| 'forgotPassword';

export type BeforeOperationHook = (args?: {
args?: any;
operation: HookOperationType;
}) => any;

export type BeforeValidateHook = (args?: {
data?: any;
req?: PayloadRequest;
operation: 'create' | 'update';
originalDoc?: any; // undefined on 'create' operation
}) => any;

export type BeforeChangeHook = (args?: {
data: any;
req: PayloadRequest;
operation: 'create' | 'update'
originalDoc?: any; // undefined on 'create' operation
}) => any;

export type AfterChangeHook = (args?: {
doc: any;
req: PayloadRequest;
operation: 'create' | 'update';
}) => any;

export type BeforeReadHook = (args?: {
doc: any;
req: PayloadRequest;
query: { [key: string]: any };
}) => any;

export type AfterReadHook = (args?: {
doc: any;
req: PayloadRequest;
query: { [key: string]: any };
}) => any;

export type BeforeDeleteHook = (args?: {
req: PayloadRequest;
id: string;
}) => any;

export type AfterDeleteHook = (args?: {
req: PayloadRequest;
id: string;
doc: any;
}) => any;

export type BeforeLoginHook = (args?: {
req: PayloadRequest;
}) => any;

export type AfterLoginHook = (args?: {
req: PayloadRequest;
user: any;
token: string;
}) => any;

export type AfterForgotPasswordHook = (args?: {
args?: any;
}) => any;
15 changes: 9 additions & 6 deletions src/collections/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ import mongoose from 'mongoose';
import express from 'express';
import passport from 'passport';
import passportLocalMongoose from 'passport-local-mongoose';
const LocalStrategy = require('passport-local').Strategy;
import Passport from 'passport-local';
import { UpdateQuery } from 'mongodb';
import apiKeyStrategy from '../auth/strategies/apiKey';
import buildSchema from './buildSchema';
import bindCollectionMiddleware from './bindCollection';
import { Collection } from './config/types';

function registerCollections() {
this.config.collections = this.config.collections.map((collection) => {
const LocalStrategy = Passport.Strategy;

export default function registerCollections(): void {
this.config.collections = this.config.collections.map((collection: Collection) => {
const formattedCollection = collection;

const schema = buildSchema(formattedCollection, this.config);
Expand All @@ -32,7 +36,8 @@ function registerCollections() {
}, cb);
}

const updates = { $inc: { loginAttempts: 1 } };
type LoginSchema = { loginAttempts: number; };
const updates: UpdateQuery<LoginSchema> = { $inc: { loginAttempts: 1 } };
// Lock the account if at max attempts and not already locked
if (this.loginAttempts + 1 >= maxLoginAttempts && !this.isLocked) {
updates.$set = { lockUntil: Date.now() + lockTime };
Expand Down Expand Up @@ -151,5 +156,3 @@ function registerCollections() {
return formattedCollection;
});
}

export default registerCollections;
7 changes: 4 additions & 3 deletions src/collections/operations/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import getImageSize from '../../uploads/getImageSize';
import imageMIMETypes from '../../uploads/imageMIMETypes';

import sendVerificationEmail from '../../auth/sendVerificationEmail';
import { AfterChangeHook, BeforeOperationHook, BeforeValidateHook } from '../config/types';

async function create(incomingArgs) {
const { performFieldOperations, config } = this;
Expand All @@ -22,7 +23,7 @@ async function create(incomingArgs) {
// beforeOperation - Collection
// /////////////////////////////////////

await args.collection.config.hooks.beforeOperation.reduce(async (priorHook, hook) => {
await args.collection.config.hooks.beforeOperation.reduce(async (priorHook: BeforeOperationHook, hook: BeforeOperationHook) => {
await priorHook;

args = (await hook({
Expand Down Expand Up @@ -73,7 +74,7 @@ async function create(incomingArgs) {
// beforeValidate - Collections
// /////////////////////////////////////

await collectionConfig.hooks.beforeValidate.reduce(async (priorHook, hook) => {
await collectionConfig.hooks.beforeValidate.reduce(async (priorHook: BeforeValidateHook, hook: BeforeValidateHook) => {
await priorHook;

data = (await hook({
Expand Down Expand Up @@ -214,7 +215,7 @@ async function create(incomingArgs) {
// afterChange - Collection
// /////////////////////////////////////

await collectionConfig.hooks.afterChange.reduce(async (priorHook, hook) => {
await collectionConfig.hooks.afterChange.reduce(async (priorHook: AfterChangeHook, hook: AfterChangeHook) => {
await priorHook;

result = await hook({
Expand Down
3 changes: 2 additions & 1 deletion src/collections/operations/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import removeInternalFields from '../../utilities/removeInternalFields';
import { NotFound, Forbidden, ErrorDeletingFile } from '../../errors';
import executeAccess from '../../auth/executeAccess';
import fileExists from '../../uploads/fileExists';
import { BeforeOperationHook } from '../config/types';

async function deleteQuery(incomingArgs) {
let args = incomingArgs;
Expand All @@ -13,7 +14,7 @@ async function deleteQuery(incomingArgs) {
// beforeOperation - Collection
// /////////////////////////////////////

await args.collection.config.hooks.beforeOperation.reduce(async (priorHook, hook) => {
await args.collection.config.hooks.beforeOperation.reduce(async (priorHook: BeforeOperationHook, hook: BeforeOperationHook) => {
await priorHook;

args = (await hook({
Expand Down
3 changes: 2 additions & 1 deletion src/collections/operations/find.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import executeAccess from '../../auth/executeAccess';
import removeInternalFields from '../../utilities/removeInternalFields';
import { BeforeOperationHook, BeforeReadHook } from '../config/types';

async function find(incomingArgs) {
let args = incomingArgs;
Expand All @@ -8,7 +9,7 @@ async function find(incomingArgs) {
// beforeOperation - Collection
// /////////////////////////////////////

await args.collection.config.hooks.beforeOperation.reduce(async (priorHook, hook) => {
await args.collection.config.hooks.beforeOperation.reduce(async (priorHook: BeforeOperationHook, hook: BeforeOperationHook) => {
await priorHook;

args = (await hook({
Expand Down
5 changes: 3 additions & 2 deletions src/collections/operations/findByID.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable no-underscore-dangle */
import memoize from 'micro-memoize';
import { BeforeOperationHook } from '../config/types';
/* eslint-disable no-underscore-dangle */
import removeInternalFields from '../../utilities/removeInternalFields';
import { Forbidden, NotFound } from '../../errors';
import executeAccess from '../../auth/executeAccess';
Expand All @@ -11,7 +12,7 @@ async function findByID(incomingArgs) {
// beforeOperation - Collection
// /////////////////////////////////////

await args.collection.config.hooks.beforeOperation.reduce(async (priorHook, hook) => {
await args.collection.config.hooks.beforeOperation.reduce(async (priorHook: BeforeOperationHook, hook: BeforeOperationHook) => {
await priorHook;

args = (await hook({
Expand Down
8 changes: 5 additions & 3 deletions src/collections/operations/update.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import httpStatus from 'http-status';
import deepmerge from 'deepmerge';
import path from 'path';
import { BeforeOperationHook, BeforeChangeHook, BeforeValidateHook } from '../config/types';

import removeInternalFields from '../../utilities/removeInternalFields';
import overwriteMerge from '../../utilities/overwriteMerge';
Expand All @@ -12,14 +13,15 @@ import getSafeFilename from '../../uploads/getSafeFilename';

import resizeAndSave from '../../uploads/imageResizer';


async function update(incomingArgs) {
let args = incomingArgs;

// /////////////////////////////////////
// beforeOperation - Collection
// /////////////////////////////////////

await args.collection.config.hooks.beforeOperation.reduce(async (priorHook, hook) => {
await args.collection.config.hooks.beforeOperation.reduce(async (priorHook: BeforeOperationHook, hook: BeforeOperationHook) => {
await priorHook;

args = (await hook({
Expand Down Expand Up @@ -111,7 +113,7 @@ async function update(incomingArgs) {
// beforeValidate - Collection
// /////////////////////////////////////

await collectionConfig.hooks.beforeValidate.reduce(async (priorHook, hook) => {
await collectionConfig.hooks.beforeValidate.reduce(async (priorHook: BeforeValidateHook, hook: BeforeValidateHook) => {
await priorHook;

data = (await hook({
Expand Down Expand Up @@ -140,7 +142,7 @@ async function update(incomingArgs) {
// beforeChange - Collection
// /////////////////////////////////////

await collectionConfig.hooks.beforeChange.reduce(async (priorHook, hook) => {
await collectionConfig.hooks.beforeChange.reduce(async (priorHook: BeforeChangeHook, hook: BeforeChangeHook) => {
await priorHook;

data = (await hook({
Expand Down
Loading

0 comments on commit d10f3f1

Please sign in to comment.