mirror of
https://github.com/strapi/strapi.git
synced 2025-12-26 14:44:31 +00:00
Apply policy for each query and use generated API business logic
This commit is contained in:
parent
0f581fa5c3
commit
3daf7523c8
@ -95,6 +95,8 @@ module.exports = strapi => {
|
||||
resolver
|
||||
});
|
||||
}, strapi.plugins.graphql.config._schema.graphql);
|
||||
|
||||
const { Query = {}, Mutation = {} } = _.get(strapi.plugins.graphql, 'config._schema.graphql.resolver', {});
|
||||
},
|
||||
|
||||
initialize: function(cb) {
|
||||
|
||||
@ -50,4 +50,4 @@
|
||||
"npm": ">= 3.0.0"
|
||||
},
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,7 +16,6 @@ const graphql = require('graphql');
|
||||
const { makeExecutableSchema } = require('graphql-tools');
|
||||
const GraphQLJSON = require('graphql-type-json');
|
||||
|
||||
|
||||
module.exports = {
|
||||
|
||||
/**
|
||||
@ -174,6 +173,10 @@ module.exports = {
|
||||
|
||||
const queryOpts = plugin ? { source: plugin } : {};
|
||||
|
||||
const model = plugin ?
|
||||
strapi.plugins[plugin].models[name]:
|
||||
strapi.models[name];
|
||||
|
||||
// Retrieve generic service from the Content Manager plugin.
|
||||
const resolvers = strapi.plugins['content-manager'].services['contentmanager'];
|
||||
|
||||
@ -186,58 +189,105 @@ module.exports = {
|
||||
|
||||
// Retrieve policies.
|
||||
const policies = isSingular ?
|
||||
_.get(handler, `Query.${pluralize.singular(name)}.policy`, []):
|
||||
_.get(handler, `Query.${pluralize.plural(name)}.policy`, []);
|
||||
_.get(handler, `Query.${pluralize.singular(name)}.policies`, []):
|
||||
_.get(handler, `Query.${pluralize.plural(name)}.policies`, []);
|
||||
|
||||
// Boolean to define if the resolver is going to be a resolver or not.
|
||||
let isController = false;
|
||||
|
||||
// Retrieve resolver. It could be the custom resolver of the user
|
||||
// or the shadow CRUD resolver (aka Content-Manager).
|
||||
const resolver = (() => {
|
||||
if (isSingular) {
|
||||
return _.get(handler, `Query.${pluralize.singular(name)}.resolver`,
|
||||
async () => {
|
||||
const value = await resolvers.fetch({ ...params, id: options.id }, plugin, []);
|
||||
// Try to retrieve custom resolver.
|
||||
const resolver = isSingular ?
|
||||
_.get(handler, `Query.${pluralize.singular(name)}.resolver`):
|
||||
_.get(handler, `Query.${pluralize.plural(name)}.resolver`);
|
||||
|
||||
return value.toJSON ? value.toJSON() : value;
|
||||
}
|
||||
);
|
||||
if (resolver) {
|
||||
return resolver;
|
||||
}
|
||||
|
||||
const resolver = _.get(handler, `Query.${pluralize.plural(name)}.resolver`,
|
||||
async () => {
|
||||
const convertedParams = strapi.utils.models.convertParams(name, this.convertToParams(options));
|
||||
const where = strapi.utils.models.convertParams(name, options.where || {});
|
||||
// We're going to return a controller instead.
|
||||
isController = true;
|
||||
|
||||
// Content-Manager specificity.
|
||||
convertedParams.skip = convertedParams.start;
|
||||
convertedParams.query = where.where;
|
||||
// Try to find the controller that should be related to this model.
|
||||
const controller = isSingular ?
|
||||
_.get(strapi.controllers, `${name}.findOne`):
|
||||
_.get(strapi.controllers, `${name}.find`);
|
||||
|
||||
const value = await resolvers.fetchAll(params, { ...queryOpts, ...convertedParams, populate: [] });
|
||||
if (!controller) {
|
||||
return new Error(`Cannot find the controller's action ${name}.${isSingular ? 'findOne' : 'find'}`);
|
||||
}
|
||||
|
||||
return value.toJSON ? value.toJSON() : value;
|
||||
// Make the query compatible with our controller by
|
||||
// setting in the context the parameters.
|
||||
if (isSingular) {
|
||||
return async (ctx, next) => {
|
||||
ctx.params = {
|
||||
...params,
|
||||
[model.primaryKey]: options.id
|
||||
};
|
||||
|
||||
// Return the controller.
|
||||
return controller(ctx, next);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return resolver;
|
||||
// Plural.
|
||||
return async (ctx, next) => {
|
||||
ctx.query = this.convertToParams(options);
|
||||
// console.log(strapi.utils.models.convertParams(name, options.where || {}));
|
||||
|
||||
return controller(ctx, next);
|
||||
}
|
||||
})();
|
||||
|
||||
const policiesFn = [];
|
||||
|
||||
// Push global policy to make sure the permissions will work as expected.
|
||||
// We're trying to detect the controller name.
|
||||
policiesFn.push(
|
||||
policyUtils.globalPolicy(undefined, {
|
||||
handler: `${name}.${isSingular ? 'findOne' : 'find'}`
|
||||
}, undefined, plugin)
|
||||
);
|
||||
|
||||
if (strapi.plugins['users-permissions']) {
|
||||
policies.push('plugins.users-permissions.permissions');
|
||||
}
|
||||
|
||||
// Populate policies.
|
||||
policies.forEach(policy => policyUtils.get(policy, plugin, policiesFn, `GraphQL query "${queryName}"`, name));
|
||||
|
||||
// Hack to be able to handle permissions for each query.
|
||||
const ctx = Object.assign(_.clone(context), {
|
||||
request: {
|
||||
graphql: null
|
||||
}
|
||||
});
|
||||
|
||||
// Execute policies stack.
|
||||
const policy = await strapi.koaMiddlewares.compose(policiesFn)(context);
|
||||
const policy = await strapi.koaMiddlewares.compose(policiesFn)(ctx);
|
||||
|
||||
// Policy doesn't always return errors but they update the current context.
|
||||
if (_.isError(context.response.body) || _.get(context.response.body, 'isBoom')) {
|
||||
return context.response.body;
|
||||
if (_.isError(ctx.request.graphql) || _.get(ctx.request.graphql, 'isBoom')) {
|
||||
return ctx.request.graphql;
|
||||
}
|
||||
|
||||
// When everything is okay, the policy variable should be undefined
|
||||
// so it will return the resolver instead.
|
||||
// Something went wrong in the policy.
|
||||
if (policy) {
|
||||
return policy;
|
||||
}
|
||||
|
||||
// Note: The resolver can be a function or promise.
|
||||
return policy || _.isFunction(resolver) ? resolver.call(null, obj, options, context) : resolver;
|
||||
// Resolver can be a function. Be also a native resolver or a controller's action.
|
||||
if (_.isFunction(resolver)) {
|
||||
return isController ?
|
||||
resolver.call(null, context):
|
||||
resolver.call(null, obj, options, context);
|
||||
}
|
||||
|
||||
// Resolver can be a promise.
|
||||
return resolver;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -503,9 +553,6 @@ module.exports = {
|
||||
// Write schema.
|
||||
this.writeGenerateSchema(graphql.printSchema(schema));
|
||||
|
||||
// Temporary variable to store the entire GraphQL configuration.
|
||||
delete strapi.plugins.graphql.config._schema.graphql;
|
||||
|
||||
return schema;
|
||||
},
|
||||
|
||||
|
||||
@ -39,7 +39,9 @@ module.exports = async (ctx, next) => {
|
||||
}, []);
|
||||
|
||||
if (!permission) {
|
||||
return ctx.unauthorized();
|
||||
ctx.unauthorized();
|
||||
|
||||
return ctx.request.graphql = ctx.body;
|
||||
}
|
||||
|
||||
// Execute the policies.
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
const _ = require('lodash');
|
||||
|
||||
module.exports = {
|
||||
get: (policy, plugin, policies = [], endpoint, currentApiName) => {
|
||||
get: function (policy, plugin, policies = [], endpoint, currentApiName) {
|
||||
// Define global policy prefix.
|
||||
const globalPolicyPrefix = 'global.';
|
||||
const pluginPolicyPrefix = 'plugins.';
|
||||
@ -19,9 +19,9 @@ module.exports = {
|
||||
) {
|
||||
// Global policy.
|
||||
return policies.push(
|
||||
strapi.config.policies[
|
||||
this.parsePolicy(strapi.config.policies[
|
||||
policy.replace(globalPolicyPrefix, '').toLowerCase()
|
||||
]
|
||||
])
|
||||
);
|
||||
} else if (
|
||||
_.startsWith(policy, pluginPolicyPrefix, 0) &&
|
||||
@ -37,12 +37,12 @@ module.exports = {
|
||||
) {
|
||||
// Plugin's policies can be used from app APIs with a specific syntax (`plugins.pluginName.policyName`).
|
||||
return policies.push(
|
||||
_.get(
|
||||
this.parsePolicy(_.get(
|
||||
strapi.plugins,
|
||||
policySplited[1] +
|
||||
'.config.policies.' +
|
||||
policySplited[2].toLowerCase()
|
||||
)
|
||||
))
|
||||
);
|
||||
} else if (
|
||||
!_.startsWith(policy, globalPolicyPrefix, 0) &&
|
||||
@ -56,10 +56,10 @@ module.exports = {
|
||||
) {
|
||||
// Plugin policy used in the plugin itself.
|
||||
return policies.push(
|
||||
_.get(
|
||||
this.parsePolicy(_.get(
|
||||
strapi.plugins,
|
||||
plugin + '.config.policies.' + policy.toLowerCase()
|
||||
)
|
||||
))
|
||||
);
|
||||
} else if (
|
||||
!_.startsWith(policy, globalPolicyPrefix, 0) &&
|
||||
@ -72,13 +72,40 @@ module.exports = {
|
||||
) {
|
||||
// API policy used in the API itself.
|
||||
return policies.push(
|
||||
_.get(
|
||||
this.parsePolicy(_.get(
|
||||
strapi.api,
|
||||
currentApiName + '.config.policies.' + policy.toLowerCase()
|
||||
)
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
strapi.log.error(`Ignored attempt to bind to ${endpoint} with unknown policy "${policy}"`);
|
||||
},
|
||||
|
||||
parsePolicy: (policy) => {
|
||||
if (_.isFunction(policy)) {
|
||||
return policy;
|
||||
}
|
||||
|
||||
return policy.handler;
|
||||
},
|
||||
|
||||
// Middleware used for every routes.
|
||||
// Expose the endpoint in `this`.
|
||||
globalPolicy: (endpoint, value, route = {}, plugin) => {
|
||||
return async (ctx, next) => {
|
||||
ctx.request.route = {
|
||||
endpoint: _.trim(endpoint),
|
||||
controller: value.handler.split('.')[0].toLowerCase(),
|
||||
action: value.handler.split('.')[1].toLowerCase(),
|
||||
splittedEndpoint: _.trim(route.endpoint),
|
||||
verb: route.verb && _.trim(route.verb.toLowerCase()),
|
||||
plugin
|
||||
};
|
||||
|
||||
console.log("CTX", ctx.request.route);
|
||||
|
||||
await next();
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@ -13,23 +13,6 @@ const regex = require('strapi-utils').regex;
|
||||
const joijson = require('strapi-utils').joijson;
|
||||
const policyUtils = require('strapi-utils').policy;
|
||||
|
||||
// Middleware used for every routes.
|
||||
// Expose the endpoint in `this`.
|
||||
function globalPolicy(endpoint, value, route, plugin) {
|
||||
return async (ctx, next) => {
|
||||
ctx.request.route = {
|
||||
endpoint: _.trim(endpoint),
|
||||
controller: value.handler.split('.')[0].toLowerCase(),
|
||||
action: value.handler.split('.')[1].toLowerCase(),
|
||||
splittedEndpoint: _.trim(route.endpoint),
|
||||
verb: route.verb && _.trim(route.verb.toLowerCase()),
|
||||
plugin
|
||||
};
|
||||
|
||||
await next();
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = strapi => function routerChecker(value, endpoint, plugin) {
|
||||
const Joi = strapi.koaMiddlewares.routerJoi.Joi;
|
||||
const builder = joijson.builder(Joi);
|
||||
@ -52,7 +35,7 @@ module.exports = strapi => function routerChecker(value, endpoint, plugin) {
|
||||
const policies = [];
|
||||
|
||||
// Add the `globalPolicy`.
|
||||
policies.push(globalPolicy(endpoint, value, route, plugin));
|
||||
policies.push(policyUtils.globalPolicy(endpoint, value, route, plugin));
|
||||
|
||||
// Allow string instead of array of policies.
|
||||
if (
|
||||
@ -71,6 +54,17 @@ module.exports = strapi => function routerChecker(value, endpoint, plugin) {
|
||||
});
|
||||
}
|
||||
|
||||
policies.push(async (ctx, next) => {
|
||||
// Set body.
|
||||
console.log("coucou");
|
||||
const values = await next();
|
||||
|
||||
if (!ctx.body) {
|
||||
ctx.body = values
|
||||
}
|
||||
console.log(ctx.body);
|
||||
});
|
||||
|
||||
// Init validate.
|
||||
const validate = {};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user