Hotfix mongo aggregate policy verifications

This commit is contained in:
Alexandre Bodin 2019-11-28 18:29:35 +01:00
parent f36a5cf096
commit 7a3b64016c
2 changed files with 194 additions and 133 deletions

View File

@ -7,6 +7,8 @@
const _ = require('lodash'); const _ = require('lodash');
const pluralize = require('pluralize'); const pluralize = require('pluralize');
const { convertRestQueryParams, buildQuery } = require('strapi-utils'); const { convertRestQueryParams, buildQuery } = require('strapi-utils');
const policyUtils = require('strapi-utils').policy;
const compose = require('koa-compose');
const Schema = require('./Schema.js'); const Schema = require('./Schema.js');
const GraphQLQuery = require('./Query.js'); const GraphQLQuery = require('./Query.js');
@ -470,7 +472,13 @@ const formatConnectionAggregator = function(fields, model, modelName) {
* } * }
* *
*/ */
const formatModelConnectionsGQL = function(fields, model, name, modelResolver) { const formatModelConnectionsGQL = function(
fields,
model,
name,
modelResolver,
plugin
) {
const { globalId } = model; const { globalId } = model;
const connectionGlobalId = `${globalId}Connection`; const connectionGlobalId = `${globalId}Connection`;
@ -501,7 +509,50 @@ const formatModelConnectionsGQL = function(fields, model, name, modelResolver) {
}, },
resolver: { resolver: {
Query: { Query: {
[`${pluralName}Connection`](obj, options, context) { async [`${pluralName}Connection`](obj, options, { context }) {
// need to check
const ctx = Object.assign(_.clone(context), {
request: Object.assign(_.clone(context.request), {
graphql: null,
}),
});
const policiesFn = [
policyUtils.globalPolicy(
undefined,
{
handler: `${name}.find`,
},
undefined,
plugin
),
];
policyUtils.get(
'plugins.users-permissions.permissions',
plugin,
policiesFn,
`GraphQL connection "${name}" `,
name
);
// Execute policies stack.
const policy = await compose(policiesFn)(ctx);
// Policy doesn't always return errors but they update the current context.
if (
_.isError(ctx.request.graphql) ||
_.get(ctx.request.graphql, 'isBoom')
) {
return ctx.request.graphql;
}
// Something went wrong in the policy.
if (policy) {
return policy;
}
return options; return options;
}, },
}, },

View File

@ -60,152 +60,161 @@ const buildAssocResolvers = (model, name, { plugin }) => {
const { primaryKey, associations = [] } = model; const { primaryKey, associations = [] } = model;
return associations return associations
.filter(association => model.attributes[association.alias].private !== true) .filter(association => model.attributes[association.alias].private !== true)
.reduce((resolver, association) => { .reduce((resolver, association) => {
switch (association.nature) { switch (association.nature) {
case 'oneToManyMorph': { case 'oneToManyMorph': {
resolver[association.alias] = async obj => { resolver[association.alias] = async obj => {
const entry = await contentManager.fetch( const entry = await contentManager.fetch(
{
id: obj[primaryKey],
model: name,
},
plugin,
[association.alias]
);
// Set the _type only when the value is defined
if (entry[association.alias]) {
entry[association.alias]._type = _.upperFirst(association.model);
}
return entry[association.alias];
};
break;
}
case 'manyMorphToOne':
case 'manyMorphToMany':
case 'manyToManyMorph': {
resolver[association.alias] = async obj => {
// eslint-disable-line no-unused-vars
const [withRelated, withoutRelated] = await Promise.all([
contentManager.fetch(
{ {
id: obj[primaryKey], id: obj[primaryKey],
model: name, model: name,
}, },
plugin, plugin,
[association.alias], [association.alias]
false
),
contentManager.fetch(
{
id: obj[primaryKey],
model: name,
},
plugin,
[]
),
]);
const entry =
withRelated && withRelated.toJSON
? withRelated.toJSON()
: withRelated;
entry[association.alias].map((entry, index) => {
const type =
_.get(withoutRelated, `${association.alias}.${index}.kind`) ||
_.upperFirst(
_.camelCase(
_.get(
withoutRelated,
`${association.alias}.${index}.${association.alias}_type`
)
)
) ||
_.upperFirst(_.camelCase(association[association.type]));
entry._type = type;
return entry;
});
return entry[association.alias];
};
break;
}
default: {
resolver[association.alias] = async (obj, options) => {
// Construct parameters object to retrieve the correct related entries.
const params = {
model: association.model || association.collection,
};
let queryOpts = {
source: association.plugin,
};
// Get refering model.
const ref = association.plugin
? strapi.plugins[association.plugin].models[params.model]
: strapi.models[params.model];
if (association.type === 'model') {
params[ref.primaryKey] = _.get(
obj,
[association.alias, ref.primaryKey],
obj[association.alias]
); );
} else {
const queryParams = Query.amountLimiting(options); // Set the _type only when the value is defined
queryOpts = { if (entry[association.alias]) {
...queryOpts, entry[association.alias]._type = _.upperFirst(association.model);
...Query.convertToParams(_.omit(queryParams, 'where')), // Convert filters (sort, limit and start/skip) }
...Query.convertToQuery(queryParams.where),
return entry[association.alias];
};
break;
}
case 'manyMorphToOne':
case 'manyMorphToMany':
case 'manyToManyMorph': {
resolver[association.alias] = async obj => {
// eslint-disable-line no-unused-vars
const [withRelated, withoutRelated] = await Promise.all([
contentManager.fetch(
{
id: obj[primaryKey],
model: name,
},
plugin,
[association.alias],
false
),
contentManager.fetch(
{
id: obj[primaryKey],
model: name,
},
plugin,
[]
),
]);
const entry =
withRelated && withRelated.toJSON
? withRelated.toJSON()
: withRelated;
entry[association.alias].map((entry, index) => {
const type =
_.get(withoutRelated, `${association.alias}.${index}.kind`) ||
_.upperFirst(
_.camelCase(
_.get(
withoutRelated,
`${association.alias}.${index}.${association.alias}_type`
)
)
) ||
_.upperFirst(_.camelCase(association[association.type]));
entry._type = type;
return entry;
});
return entry[association.alias];
};
break;
}
default: {
resolver[association.alias] = async (obj, options) => {
// Construct parameters object to retrieve the correct related entries.
const params = {
model: association.model || association.collection,
}; };
if ( let queryOpts = {
((association.nature === 'manyToMany' && association.dominant) || source: association.plugin,
association.nature === 'manyWay') && };
_.has(obj, association.alias) // if populated
) { // Get refering model.
_.set( const ref = association.plugin
queryOpts, ? strapi.plugins[association.plugin].models[params.model]
['query', ref.primaryKey], : strapi.models[params.model];
if (association.type === 'model') {
params[ref.primaryKey] = _.get(
obj,
[association.alias, ref.primaryKey],
obj[association.alias] obj[association.alias]
? obj[association.alias]
.map(val => val[ref.primaryKey] || val)
.sort()
: []
); );
} else { } else {
_.set(queryOpts, ['query', association.via], obj[ref.primaryKey]); const queryParams = Query.amountLimiting(options);
queryOpts = {
...queryOpts,
...Query.convertToParams(_.omit(queryParams, 'where')), // Convert filters (sort, limit and start/skip)
...Query.convertToQuery(queryParams.where),
};
if (
((association.nature === 'manyToMany' &&
association.dominant) ||
association.nature === 'manyWay') &&
_.has(obj, association.alias) // if populated
) {
_.set(
queryOpts,
['query', ref.primaryKey],
obj[association.alias]
? obj[association.alias]
.map(val => val[ref.primaryKey] || val)
.sort()
: []
);
} else {
_.set(
queryOpts,
['query', association.via],
obj[ref.primaryKey]
);
}
} }
}
const loaderName = association.plugin const loaderName = association.plugin
? `${association.plugin}__${params.model}` ? `${association.plugin}__${params.model}`
: params.model; : params.model;
return association.model return association.model
? strapi.plugins.graphql.services.loaders.loaders[loaderName].load({ ? strapi.plugins.graphql.services.loaders.loaders[
params, loaderName
options: queryOpts, ].load({
single: true, params,
}) options: queryOpts,
: strapi.plugins.graphql.services.loaders.loaders[loaderName].load({ single: true,
options: queryOpts, })
association, : strapi.plugins.graphql.services.loaders.loaders[
}); loaderName
}; ].load({
break; options: queryOpts,
association,
});
};
break;
}
} }
}
return resolver; return resolver;
}, {}); }, {});
}; };
const buildModel = (model, name, { plugin, isGroup = false } = {}) => { const buildModel = (model, name, { plugin, isGroup = false } = {}) => {
@ -475,7 +484,8 @@ const buildShadowCRUD = (models, plugin) => {
attributes, attributes,
model, model,
name, name,
queries.plural queries.plural,
plugin
); );
if (modelAggregator) { if (modelAggregator) {
acc.definition += modelAggregator.type; acc.definition += modelAggregator.type;