introduces field-level policies on find operations

This commit is contained in:
James
2020-06-17 15:49:01 -04:00
parent 155bb87f7a
commit ab36ba8e75
13 changed files with 160 additions and 49 deletions

View File

@@ -0,0 +1,41 @@
const createPolicyPromise = async (args, data, field, operation) => {
const resultingData = data;
const result = await field.policies[operation](args);
if (!result) {
delete resultingData[field.name];
}
};
const iterateFields = async (args, data, fields, operation, promises) => {
fields.forEach((field) => {
const dataToValidate = data || {};
if (data[field.name] || field.name === undefined) {
if (field.policies[operation]) {
promises.push(createPolicyPromise(args, data, field, operation));
} else if (field.fields) {
if (field.name === undefined) {
iterateFields(args, dataToValidate, field.fields, operation, promises);
} else if (field.type === 'repeater' || field.type === 'flexible') {
dataToValidate[field.name].forEach((rowData) => {
iterateFields(args, rowData, field.fields, operation, promises);
});
} else {
iterateFields(args, dataToValidate[field.name], field.fields, operation, promises);
}
}
}
});
};
module.exports = async (args, data, fields, operation) => {
try {
const promises = [];
iterateFields(args, data, fields, operation, promises);
await Promise.all(promises);
return data;
} catch (error) {
throw error;
}
};

View File

@@ -16,19 +16,25 @@ const register = async (args) => {
let options = { ...args };
// /////////////////////////////////////
// 2. Validate incoming data
// 2. Execute field-level policies
// /////////////////////////////////////
// Field-level policies here
// /////////////////////////////////////
// 3. Validate incoming data
// /////////////////////////////////////
await validateCreate(args.data, args.collection.config.fields);
// /////////////////////////////////////
// 3. Execute before register field-level hooks
// 4. Execute before register field-level hooks
// /////////////////////////////////////
options.data = await executeFieldHooks(options, args.collection.config.fields, args.data, 'beforeCreate');
// /////////////////////////////////////
// 4. Execute before register hook
// 5. Execute before register hook
// /////////////////////////////////////
const { beforeRegister } = args.collection.config.hooks;
@@ -38,7 +44,7 @@ const register = async (args) => {
}
// /////////////////////////////////////
// 5. Perform register
// 6. Perform register
// /////////////////////////////////////
const {
@@ -68,7 +74,7 @@ const register = async (args) => {
await passport.authenticate('local');
// /////////////////////////////////////
// 6. Execute after register hook
// 7. Execute after register hook
// /////////////////////////////////////
const afterRegister = args.collection.config.hooks;
@@ -78,7 +84,7 @@ const register = async (args) => {
}
// /////////////////////////////////////
// 7. Return user
// 8. Return user
// /////////////////////////////////////
return result.toJSON({ virtuals: true });

View File

@@ -1,6 +1,7 @@
const { NotFound } = require('../../errors');
const executePolicy = require('../executePolicy');
const validate = require('../../validation/validateUpdate');
const update = async (args) => {
try {
@@ -10,12 +11,23 @@ const update = async (args) => {
await executePolicy(args, args.config.policies.update);
// Await validation here
let options = { ...args };
// /////////////////////////////////////
// 1. Execute before update hook
// 2. Execute field-level policies
// /////////////////////////////////////
// Field-level policies here
// /////////////////////////////////////
// 3. Validate incoming data
// /////////////////////////////////////
await validate(args.data, args.config.fields);
// /////////////////////////////////////
// 4. Execute before update hook
// /////////////////////////////////////
const { beforeUpdate } = args.config.hooks;
@@ -25,7 +37,7 @@ const update = async (args) => {
}
// /////////////////////////////////////
// 2. Perform update
// 5. Perform update
// /////////////////////////////////////
const {
@@ -61,7 +73,7 @@ const update = async (args) => {
user = user.toJSON({ virtuals: true });
// /////////////////////////////////////
// 3. Execute after update hook
// 6. Execute after update hook
// /////////////////////////////////////
const afterUpdateHook = args.config.hooks && args.config.hooks.afterUpdate;
@@ -71,7 +83,7 @@ const update = async (args) => {
}
// /////////////////////////////////////
// 4. Return user
// 7. Return user
// /////////////////////////////////////
return user;

View File

@@ -19,20 +19,26 @@ const create = async (args) => {
let options = { ...args };
// /////////////////////////////////////
// 2. Validate incoming data
// 2. Execute field-level policies
// /////////////////////////////////////
// Field-level policies here
// /////////////////////////////////////
// 3. Validate incoming data
// /////////////////////////////////////
await validateCreate(args.data, args.config.fields);
// /////////////////////////////////////
// 3. Execute before create field-level hooks
// 4. Execute before create field-level hooks
// /////////////////////////////////////
options.data = await executeFieldHooks(options, args.config.fields, args.data, 'beforeCreate', args.data);
// /////////////////////////////////////
// 4. Upload and resize any files that may be present
// 5. Upload and resize any files that may be present
// /////////////////////////////////////
if (args.config.upload) {
@@ -65,7 +71,7 @@ const create = async (args) => {
}
// /////////////////////////////////////
// 5. Execute before collection hook
// 6. Execute before collection hook
// /////////////////////////////////////
const { beforeCreate } = args.config.hooks;
@@ -75,7 +81,7 @@ const create = async (args) => {
}
// /////////////////////////////////////
// 6. Perform database operation
// 7. Perform database operation
// /////////////////////////////////////
const {
@@ -99,7 +105,7 @@ const create = async (args) => {
result = result.toJSON({ virtuals: true });
// /////////////////////////////////////
// 7. Execute after collection hook
// 8. Execute after collection hook
// /////////////////////////////////////
const { afterCreate } = args.config.hooks;
@@ -109,7 +115,7 @@ const create = async (args) => {
}
// /////////////////////////////////////
// 8. Return results
// 9. Return results
// /////////////////////////////////////
return result;

View File

@@ -1,5 +1,6 @@
const merge = require('lodash.merge');
const executePolicy = require('../../auth/executePolicy');
const executeFieldPolicies = require('../../auth/executeFieldPolicies');
const executeFieldHooks = require('../../fields/executeHooks');
const find = async (args) => {
@@ -75,7 +76,7 @@ const find = async (args) => {
let result = await Model.paginate(query, optionsToExecute);
// /////////////////////////////////////
// 4. Execute field-level afterRead hooks
// 4. Execute field-level policies
// /////////////////////////////////////
result = {
@@ -84,12 +85,25 @@ const find = async (args) => {
if (locale && doc.setLocale) {
doc.setLocale(locale, fallbackLocale);
}
const json = doc.toJSON({ virtuals: true });
return executeFieldPolicies(args, json, args.config.fields, 'read');
})),
};
// /////////////////////////////////////
// 5. Execute field-level afterRead hooks
// /////////////////////////////////////
result = {
...result,
docs: await Promise.all(result.docs.map(async (doc) => {
return executeFieldHooks(options, args.config.fields, doc, 'afterRead', doc);
})),
};
// /////////////////////////////////////
// 5. Execute afterRead collection hook
// 6. Execute afterRead collection hook
// /////////////////////////////////////
const { afterRead } = args.config.hooks;
@@ -99,24 +113,19 @@ const find = async (args) => {
afterReadResult = {
...result,
docs: await Promise.all(result.docs.map(async (doc) => {
const json = doc.toJSON({ virtuals: true });
return afterRead({
options,
doc,
json,
}) || json;
}) || doc;
})),
};
}
// /////////////////////////////////////
// 6. Return results
// 7. Return results
// /////////////////////////////////////
return afterReadResult || {
...result,
docs: result.docs.map(doc => doc.toJSON({ virtuals: true })),
};
return afterReadResult || result;
} catch (err) {
throw err;
}

View File

@@ -87,7 +87,13 @@ const findByID = async (args) => {
result = await executeFieldHooks(options, options.config.fields, result, 'afterRead', result);
// /////////////////////////////////////
// 5. Execute after collection hook
// 5. Execute field-level policies
// /////////////////////////////////////
// Field-level policies here
// /////////////////////////////////////
// 6. Execute after collection hook
// /////////////////////////////////////
const { afterRead } = args.config.hooks;
@@ -96,12 +102,12 @@ const findByID = async (args) => {
json = await afterRead({
...options,
result,
json,
doc: json,
}) || json;
}
// /////////////////////////////////////
// 6. Return results
// 7. Return results
// /////////////////////////////////////
return json;

View File

@@ -17,19 +17,25 @@ const update = async (args) => {
let options = { ...args };
// /////////////////////////////////////
// 2. Validate incoming data
// 2. Execute field-level policies
// /////////////////////////////////////
// Field-level policies here
// /////////////////////////////////////
// 3. Validate incoming data
// /////////////////////////////////////
await validate(args.data, args.config.fields);
// /////////////////////////////////////
// 3. Execute before update field-level hooks
// 4. Execute before update field-level hooks
// /////////////////////////////////////
options.data = await executeFieldHooks(options, args.config.fields, args.data, 'beforeUpdate', args.data);
// /////////////////////////////////////
// 4. Execute before collection hook
// 5. Execute before collection hook
// /////////////////////////////////////
const { beforeUpdate } = args.config.hooks;
@@ -39,7 +45,7 @@ const update = async (args) => {
}
// /////////////////////////////////////
// 5. Perform database operation
// 6. Perform database operation
// /////////////////////////////////////
let {
@@ -74,7 +80,7 @@ const update = async (args) => {
}
// /////////////////////////////////////
// 6. Upload and resize any files that may be present
// 7. Upload and resize any files that may be present
// /////////////////////////////////////
if (args.config.upload) {
@@ -105,7 +111,7 @@ const update = async (args) => {
result = result.toJSON({ virtuals: true });
// /////////////////////////////////////
// 7. Execute after collection hook
// 8. Execute after collection hook
// /////////////////////////////////////
const { afterUpdate } = args.config.hooks;
@@ -115,7 +121,7 @@ const update = async (args) => {
}
// /////////////////////////////////////
// 8. Return results
// 9. Return results
// /////////////////////////////////////
return result;

View File

@@ -25,6 +25,7 @@ function initAdmin() {
this.express.use(this.config.routes.admin, router);
} else {
this.express.use(this.config.routes.admin, history());
this.express.use(this.initWebpack());
}
}

View File

@@ -16,6 +16,7 @@ const sanitizeFields = (fields) => {
}
if (!field.hooks) field.hooks = {};
if (!field.policies) field.policies = {};
if (field.fields) field.fields = sanitizeFields(field.fields);

View File

@@ -64,14 +64,21 @@ const findOne = async (args) => {
let json = result.toJSON({ virtuals: true });
// /////////////////////////////////////
// 4. Execute after collection field-level hooks
// 4. Execute field-level policies
// /////////////////////////////////////
// Field-level policies here
// /////////////////////////////////////
// 5. Execute after collection field-level hooks
// /////////////////////////////////////
result = await executeFieldHooks(options, args.config.fields, result, 'afterRead', result);
// /////////////////////////////////////
// 5. Execute after collection hook
// 6. Execute after collection hook
// /////////////////////////////////////
const { afterRead } = args.config.hooks;
@@ -81,7 +88,7 @@ const findOne = async (args) => {
}
// /////////////////////////////////////
// 6. Return results
// 7. Return results
// /////////////////////////////////////
return json;

View File

@@ -1,5 +1,6 @@
const executePolicy = require('../../auth/executePolicy');
const executeFieldHooks = require('../../fields/executeHooks');
const validate = require('../../validation/validateUpdate');
const update = async (args) => {
try {
@@ -11,16 +12,26 @@ const update = async (args) => {
let options = { ...args };
// Await validation here
// /////////////////////////////////////
// 2. Execute field-level policies
// /////////////////////////////////////
// Field-level policies here
// /////////////////////////////////////
// 2. Execute before update field-level hooks
// 3. Validate incoming data
// /////////////////////////////////////
await validate(args.data, args.config.fields);
// /////////////////////////////////////
// 4. Execute before update field-level hooks
// /////////////////////////////////////
options.data = await executeFieldHooks(options, args.config.fields, args.data, 'beforeUpdate', args.data);
// /////////////////////////////////////
// 2. Execute before global hook
// 5. Execute before global hook
// /////////////////////////////////////
const { beforeUpdate } = args.config.hooks;
@@ -30,7 +41,7 @@ const update = async (args) => {
}
// /////////////////////////////////////
// 3. Perform database operation
// 6. Perform database operation
// /////////////////////////////////////
const {
@@ -61,7 +72,7 @@ const update = async (args) => {
result = result.toJSON({ virtuals: true });
// /////////////////////////////////////
// 4. Execute after global hook
// 7. Execute after global hook
// /////////////////////////////////////
const { afterUpdate } = args.config.hooks;
@@ -71,7 +82,7 @@ const update = async (args) => {
}
// /////////////////////////////////////
// 5. Return results
// 8. Return results
// /////////////////////////////////////
return result;