Auto gen UUID field on create

This commit is contained in:
rijkvanzanten
2020-06-25 17:21:42 -04:00
parent a2512e49d4
commit b1790a666f
5 changed files with 61 additions and 39 deletions

34
package-lock.json generated
View File

@@ -22,6 +22,13 @@
"tunnel": "0.0.6",
"uuid": "^3.2.1",
"xml2js": "^0.4.19"
},
"dependencies": {
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
}
}
},
"@azure/ms-rest-nodeauth": {
@@ -316,6 +323,12 @@
"@types/node": "*"
}
},
"@types/uuid": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.0.0.tgz",
"integrity": "sha512-xSQfNcvOiE5f9dyd4Kzxbof1aTrLobL278pGLKOZI6esGfZ7ts9Ka16CzIN6Y8hFHE1C7jIBZokULhK1bOgjRw==",
"dev": true
},
"abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@@ -362,6 +375,11 @@
"version": "8.10.61",
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.61.tgz",
"integrity": "sha512-l+zSbvT8TPRaCxL1l9cwHCb0tSqGAGcjPJFItGGYat5oCTiq1uQQKYg5m7AF1mgnEBzFXGLJ2LRmNjtreRX76Q=="
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
}
}
},
@@ -4623,6 +4641,11 @@
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
}
}
},
@@ -4645,6 +4668,11 @@
"version": "6.9.4",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz",
"integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ=="
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
}
}
},
@@ -5737,9 +5765,9 @@
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.2.0.tgz",
"integrity": "sha512-CYpGiFTUrmI6OBMkAdjSDM0k5h8SkkiTP4WAjQgDgNB1S3Ou9VBEvr6q0Kv2H1mMk7IWfxYGpMH5sd5AvcIV2Q=="
},
"v8-compile-cache": {
"version": "2.1.1",

View File

@@ -38,6 +38,7 @@
"@types/lodash": "^4.14.156",
"@types/nodemailer": "^6.4.0",
"@types/pino": "^6.3.0",
"@types/uuid": "^8.0.0",
"copyfiles": "^2.3.0",
"eslint": "^7.3.1",
"eslint-plugin-prettier": "^3.1.4",
@@ -85,6 +86,7 @@
"pg": "^8.2.1",
"pino": "^6.3.2",
"sqlite3": "^4.2.0",
"ts-node-dev": "^1.0.0-pre.49"
"ts-node-dev": "^1.0.0-pre.49",
"uuid": "^8.2.0"
}
}

View File

@@ -17,26 +17,17 @@ async function getCollections(keys: string[]) {
return keys.map((key) => records.find((collection) => collection.collection === key));
}
async function getFields(keys: { collection: string; field: string }[]) {
const records = await database
.select('*')
.from('directus_fields')
.whereIn(
['collection', 'field'],
keys.map((key) => [key.collection, key.field])
);
return keys.map<FieldInfo>((key) =>
records.find((record) => record.collection === key.collection && record.field === key.field)
);
}
export default function createSystemLoaders() {
return {
collections: new DataLoader(getCollections),
fields: new DataLoader(getFields, {
cacheKeyFn: (key: { collection: string; field: string }) =>
key.collection + '__' + key.field,
}),
fieldsByCollection: new DataLoader<string, FieldInfo[]>((collections: string[]) =>
database
.select('*')
.from('directus_fields')
.whereIn('collection', collections)
.then((rows) =>
collections.map((collection) => rows.filter((x) => x.collection === collection))
)
),
};
}

View File

@@ -4,6 +4,9 @@ import isJWT from '../utils/is-jwt';
import database from '../database';
import asyncHandler from 'express-async-handler';
/**
* Verify the passed JWT and assign the user ID and role to `req`
*/
const authenticate: RequestHandler = asyncHandler(async (req, res, next) => {
if (!req.token) return next();

View File

@@ -7,34 +7,24 @@ import { RequestHandler } from 'express';
import asyncHandler from 'express-async-handler';
import { FieldInfo } from '../types/field';
import bcrypt from 'bcrypt';
import { v4 as uuidv4 } from 'uuid';
type Operation = 'create' | 'update';
/**
* @TODO
*
* This needs a bit of extra thinking.
* - There's a difference between update / create payload processing
* - Some processing types need the whole payload (slug)
* - What happens for fields that aren't in the payload but need to be set on create?
* Move this out of the middleware into a service
*/
const processPayload = (operation: Operation) => {
const middleware: RequestHandler = asyncHandler(async (req, res, next) => {
// Get the fields that have a special operation associated with them
const fieldsInPayload = Object.keys(req.body);
const fieldsInCollection = await req.loaders.fieldsByCollection.load(req.collection);
const fieldInfoForFields = await req.loaders.fields.loadMany(
fieldsInPayload.map((field) => ({
collection: req.collection,
field: field,
}))
);
const specialFields = fieldInfoForFields.filter((field) => {
const specialFields = fieldsInCollection.filter((field) => {
if (field instanceof Error) return false;
return field.special !== null;
}) as FieldInfo[];
});
for (const field of specialFields) {
req.body[field.field] = await processField(req.collection, field, req.body, operation);
@@ -54,12 +44,20 @@ async function processField(
) {
switch (field.special) {
case 'hash':
return await hash(payload[field.field]);
return await genHash(payload[field.field]);
case 'uuid':
return await genUUID(operation);
}
}
async function hash(value: string | number) {
async function genHash(value: string | number) {
return await bcrypt.hash(value, Number(process.env.SALT_ROUNDS));
}
async function genUUID(operation: Operation) {
if (operation === 'create') {
return uuidv4();
}
}
export default processPayload;