add many relations preview route

This commit is contained in:
Pierre Noël 2020-12-01 16:38:47 +01:00
parent 66dd23deab
commit 0d9812db95
6 changed files with 94 additions and 22 deletions

View File

@ -24,6 +24,8 @@ const RESERVED_ATTRIBUTE_NAMES = [
'attributes',
'relations',
'changed',
'page',
'pageSize',
// list found here https://mongoosejs.com/docs/api.html#schema_Schema.reserved
'_posts',

View File

@ -66,7 +66,6 @@
"policies": []
}
},
{
"method": "GET",
"path": "/relations/:model/:targetField",
@ -85,7 +84,6 @@
]
}
},
{
"method": "GET",
"path": "/single-types/:model",
@ -155,7 +153,18 @@
]
}
},
{
"method": "GET",
"path": "/collection-types/:model/:id/:targetField",
"handler": "collection-types.previewManyRelations",
"config": {
"policies": [
"routing",
"admin::isAuthenticatedAdmin",
["plugins::content-manager.hasPermissions", ["plugins::content-manager.explorer.read"]]
]
}
},
{
"method": "GET",
"path": "/collection-types/:model",
@ -245,7 +254,7 @@
{
"method": "POST",
"path": "/collection-types/:model/actions/bulkDelete",
"handler": "collection-types.bulkdDelete",
"handler": "collection-types.bulkDelete",
"config": {
"policies": [
"routing",

View File

@ -1,6 +1,6 @@
'use strict';
const { has, pipe } = require('lodash/fp');
const { has, pipe, prop, pick } = require('lodash/fp');
const {
getService,
@ -8,6 +8,7 @@ const {
setCreatorFields,
pickWritableAttributes,
} = require('../utils');
const { MANY_RELATIONS } = require('../services/constants');
const { validateBulkDeleteInput } = require('./validation');
module.exports = {
@ -198,7 +199,7 @@ module.exports = {
ctx.body = permissionChecker.sanitizeOutput(result);
},
async bulkdDelete(ctx) {
async bulkDelete(ctx) {
const { userAbility } = ctx.state;
const { model } = ctx.params;
const { query, body } = ctx.request;
@ -225,4 +226,57 @@ module.exports = {
ctx.body = results.map(result => permissionChecker.sanitizeOutput(result));
},
async previewManyRelations(ctx) {
const { userAbility } = ctx.state;
const { model, id, targetField } = ctx.params;
const { pageSize = 10, page = 1 } = ctx.request.query;
const contentTypeService = getService('content-types');
const entityManager = getService('entity-manager');
const permissionChecker = getService('permission-checker').create({ userAbility, model });
if (permissionChecker.cannot.read()) {
return ctx.forbidden();
}
const modelDef = strapi.getModel(model);
const assoc = modelDef.associations.find(a => a.alias === targetField);
if (!assoc || !MANY_RELATIONS.includes(assoc.nature)) {
return ctx.badRequest('Invalid target field');
}
const entity = await entityManager.findOneWithCreatorRoles(id, model);
if (!entity) {
return ctx.notFound();
}
if (permissionChecker.cannot.read(entity, targetField)) {
return ctx.forbidden();
}
let relationList;
if (assoc.nature === 'manyWay') {
const populatedEntity = await entityManager.findOne(id, model, [targetField]);
const relationsListIds = populatedEntity[targetField].map(prop('id'));
relationList = await entityManager.findPage(
{ page, pageSize, id_in: relationsListIds },
assoc.targetUid
);
} else {
relationList = await entityManager.findPage(
{ page, pageSize, [assoc.via]: entity.id },
assoc.targetUid
);
}
const { settings } = await contentTypeService.findConfiguration({ uid: assoc.targetUid });
ctx.body = {
pagination: relationList.pagination,
results: relationList.results.map(pick(['id', 'ids', settings.mainField])),
};
},
};

View File

@ -0,0 +1,7 @@
'use strict';
const MANY_RELATIONS = ['oneToMany', 'manyToMany', 'manyWay'];
module.exports = {
MANY_RELATIONS,
};

View File

@ -44,32 +44,32 @@ module.exports = {
return assoc(`${CREATED_BY_ATTRIBUTE}.roles`, roles, entity);
},
find(params, model) {
return strapi.entityService.find({ params }, { model });
find(params, model, populate) {
return strapi.entityService.find({ params, populate }, { model });
},
findPage(params, model) {
return strapi.entityService.findPage({ params }, { model });
findPage(params, model, populate) {
return strapi.entityService.findPage({ params, populate }, { model });
},
search(params, model) {
return strapi.entityService.search({ params }, { model });
search(params, model, populate) {
return strapi.entityService.search({ params, populate }, { model });
},
searchPage(params, model) {
return strapi.entityService.searchPage({ params }, { model });
searchPage(params, model, populate) {
return strapi.entityService.searchPage({ params, populate }, { model });
},
count(params, model) {
return strapi.entityService.count({ params }, { model });
},
async findOne(id, model) {
return strapi.entityService.findOne({ params: { id } }, { model });
async findOne(id, model, populate) {
return strapi.entityService.findOne({ params: { id }, populate }, { model });
},
async findOneWithCreatorRoles(id, model) {
const entity = await this.findOne(id, model);
async findOneWithCreatorRoles(id, model, populate) {
const entity = await this.findOne(id, model, populate);
if (!entity) {
return entity;

View File

@ -17,12 +17,12 @@ const createPermissionChecker = ({ userAbility, model }) => {
const toSubject = entity => (entity ? permissionsManager.toSubject(entity, model) : model);
const can = (action, entity) => {
return userAbility.can(action, toSubject(entity));
const can = (action, entity, field) => {
return userAbility.can(action, toSubject(entity), field);
};
const cannot = (action, entity) => {
return userAbility.cannot(action, toSubject(entity));
const cannot = (action, entity, field) => {
return userAbility.cannot(action, toSubject(entity), field);
};
const sanitizeOutput = (data, { action = ACTIONS.read } = {}) => {