mirror of
https://github.com/strapi/strapi.git
synced 2025-10-29 17:04:13 +00:00
implement new findAvailable route
This commit is contained in:
parent
1200e43618
commit
241393eaa3
@ -26,57 +26,52 @@ module.exports = {
|
|||||||
|
|
||||||
// idsToOmit: used to exclude relations that the front already added but that were not saved yet
|
// idsToOmit: used to exclude relations that the front already added but that were not saved yet
|
||||||
// idsToInclude: used to include relations that the front removed but not saved yes
|
// idsToInclude: used to include relations that the front removed but not saved yes
|
||||||
const { component, entityId, idsToOmit, idsToInclude, _q, ...query } = ctx.request.query;
|
const { entityId, idsToOmit, idsToInclude, _q, ...query } = ctx.request.query;
|
||||||
|
|
||||||
const sourceModelUid = component || model;
|
const modelSchema = strapi.getModel(model);
|
||||||
|
if (!modelSchema) {
|
||||||
const sourceModel = strapi.getModel(sourceModelUid);
|
|
||||||
if (!sourceModel) {
|
|
||||||
return ctx.badRequest("The model doesn't exist");
|
return ctx.badRequest("The model doesn't exist");
|
||||||
}
|
}
|
||||||
|
|
||||||
const permissionChecker = getService('permission-checker').create({
|
const attribute = modelSchema.attributes[targetField];
|
||||||
userAbility,
|
|
||||||
model,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (permissionChecker.cannot.read()) {
|
|
||||||
return ctx.forbidden();
|
|
||||||
}
|
|
||||||
|
|
||||||
const attribute = sourceModel.attributes[targetField];
|
|
||||||
if (!attribute || attribute.type !== 'relation') {
|
if (!attribute || attribute.type !== 'relation') {
|
||||||
return ctx.badRequest("This relational field doesn't exist");
|
return ctx.badRequest("This relational field doesn't exist");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: find a way to check field permission for component
|
const isComponent = modelSchema.modelType === 'component';
|
||||||
if (!component && permissionChecker.cannot.read(null, targetField)) {
|
|
||||||
return ctx.forbidden();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entityId) {
|
// RBAC checks when it's a content-type
|
||||||
const entityManager = getService('entity-manager');
|
// TODO: do RBAC check for components too
|
||||||
|
if (!isComponent) {
|
||||||
|
const permissionChecker = getService('permission-checker').create({
|
||||||
|
userAbility,
|
||||||
|
model,
|
||||||
|
});
|
||||||
|
|
||||||
const entity = await entityManager.findOneWithCreatorRoles(entityId, model);
|
if (permissionChecker.cannot.read(null, targetField)) {
|
||||||
|
|
||||||
if (!entity) {
|
|
||||||
return ctx.notFound();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!component && permissionChecker.cannot.read(entity, targetField)) {
|
|
||||||
return ctx.forbidden();
|
return ctx.forbidden();
|
||||||
}
|
}
|
||||||
// TODO: find a way to check field permission for component
|
|
||||||
if (component && permissionChecker.cannot.read(entity)) {
|
if (entityId) {
|
||||||
return ctx.forbidden();
|
const entityManager = getService('entity-manager');
|
||||||
|
|
||||||
|
const entity = await entityManager.findOneWithCreatorRoles(entityId, model);
|
||||||
|
|
||||||
|
if (!entity) {
|
||||||
|
return ctx.notFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (permissionChecker.cannot.read(entity, targetField)) {
|
||||||
|
return ctx.forbidden();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const targetedModel = strapi.getModel(attribute.target);
|
const targetedModel = strapi.getModel(attribute.target);
|
||||||
|
|
||||||
const modelConfig = component
|
const modelConfig = isComponent
|
||||||
? await getService('components').findConfiguration(sourceModel)
|
? await getService('components').findConfiguration(modelSchema)
|
||||||
: await getService('content-types').findConfiguration(sourceModel);
|
: await getService('content-types').findConfiguration(modelSchema);
|
||||||
const mainField = prop(`metadatas.${targetField}.edit.mainField`, modelConfig) || 'id';
|
const mainField = prop(`metadatas.${targetField}.edit.mainField`, modelConfig) || 'id';
|
||||||
|
|
||||||
const fieldsToSelect = ['id', mainField];
|
const fieldsToSelect = ['id', mainField];
|
||||||
@ -101,7 +96,7 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (entityId) {
|
if (entityId) {
|
||||||
const subQuery = strapi.db.queryBuilder(sourceModel.uid);
|
const subQuery = strapi.db.queryBuilder(modelSchema.uid);
|
||||||
|
|
||||||
const alias = subQuery.getAlias();
|
const alias = subQuery.getAlias();
|
||||||
|
|
||||||
@ -153,10 +148,6 @@ module.exports = {
|
|||||||
model,
|
model,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (permissionChecker.cannot.read()) {
|
|
||||||
return ctx.forbidden();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (permissionChecker.cannot.read(null, targetField)) {
|
if (permissionChecker.cannot.read(null, targetField)) {
|
||||||
return ctx.forbidden();
|
return ctx.forbidden();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -84,19 +84,7 @@ module.exports = {
|
|||||||
path: '/relations/:model/:targetField',
|
path: '/relations/:model/:targetField',
|
||||||
handler: 'relations.findAvailable',
|
handler: 'relations.findAvailable',
|
||||||
config: {
|
config: {
|
||||||
policies: [
|
policies: ['admin::isAuthenticatedAdmin'],
|
||||||
'admin::isAuthenticatedAdmin',
|
|
||||||
{
|
|
||||||
name: 'plugin::content-manager.hasPermissions',
|
|
||||||
config: {
|
|
||||||
actions: [
|
|
||||||
'plugin::content-manager.explorer.create',
|
|
||||||
'plugin::content-manager.explorer.update',
|
|
||||||
],
|
|
||||||
hasAtLeastOne: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -180,25 +180,25 @@ describe.each([[false], [true]])('Relations, with d&p: %p', (withDraftAndPublish
|
|||||||
['products_mw', false],
|
['products_mw', false],
|
||||||
['compo_products_ow', true],
|
['compo_products_ow', true],
|
||||||
['compo_products_mw', true],
|
['compo_products_mw', true],
|
||||||
])('Relation not in a component (%s)', (fieldName, isComponent) => {
|
])('Relation (%s) (is in component: %s)', (fieldName, isComponent) => {
|
||||||
let entityId;
|
let entityId;
|
||||||
let entityIdEmptyShop;
|
let entityIdEmptyShop;
|
||||||
|
let modelUID;
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
entityId = isComponent ? data.shops[0].myCompo.id : data.shops[0].id;
|
entityId = isComponent ? data.shops[0].myCompo.id : data.shops[0].id;
|
||||||
entityIdEmptyShop = isComponent ? data.shops[1].myCompo.id : data.shops[1].id;
|
entityIdEmptyShop = isComponent ? data.shops[1].myCompo.id : data.shops[1].id;
|
||||||
|
modelUID = isComponent ? 'default.compo' : 'api::shop.shop';
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Can retrieve available relation(s) for an entity that have some relations', async () => {
|
test('Can retrieve available relation(s) for an entity that have some relations', async () => {
|
||||||
let res = await rq({
|
let res = await rq({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: `/content-manager/relations/api::shop.shop/${fieldName}`,
|
url: `/content-manager/relations/${modelUID}/${fieldName}`,
|
||||||
qs: {
|
qs: {
|
||||||
entityId,
|
entityId,
|
||||||
...(isComponent ? { component: 'default.compo' } : {}),
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(res.status).toBe(200);
|
expect(res.status).toBe(200);
|
||||||
|
|
||||||
expect(res.body.results).toMatchObject([
|
expect(res.body.results).toMatchObject([
|
||||||
@ -212,11 +212,10 @@ describe.each([[false], [true]])('Relations, with d&p: %p', (withDraftAndPublish
|
|||||||
// can omitIds
|
// can omitIds
|
||||||
res = await rq({
|
res = await rq({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: `/content-manager/relations/api::shop.shop/${fieldName}`,
|
url: `/content-manager/relations/${modelUID}/${fieldName}`,
|
||||||
qs: {
|
qs: {
|
||||||
entityId,
|
entityId,
|
||||||
idsToOmit: [data.products[1].id],
|
idsToOmit: [data.products[1].id],
|
||||||
...(isComponent ? { component: 'default.compo' } : {}),
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -226,10 +225,9 @@ describe.each([[false], [true]])('Relations, with d&p: %p', (withDraftAndPublish
|
|||||||
test("Can retrieve available relation(s) for an entity that don't have relations yet", async () => {
|
test("Can retrieve available relation(s) for an entity that don't have relations yet", async () => {
|
||||||
let res = await rq({
|
let res = await rq({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: `/content-manager/relations/api::shop.shop/${fieldName}`,
|
url: `/content-manager/relations/${modelUID}/${fieldName}`,
|
||||||
qs: {
|
qs: {
|
||||||
entityId: entityIdEmptyShop,
|
entityId: entityIdEmptyShop,
|
||||||
...(isComponent ? { component: 'default.compo' } : {}),
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -251,11 +249,10 @@ describe.each([[false], [true]])('Relations, with d&p: %p', (withDraftAndPublish
|
|||||||
// can omitIds
|
// can omitIds
|
||||||
res = await rq({
|
res = await rq({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: `/content-manager/relations/api::shop.shop/${fieldName}`,
|
url: `/content-manager/relations/${modelUID}/${fieldName}`,
|
||||||
qs: {
|
qs: {
|
||||||
entityId,
|
entityId,
|
||||||
idsToOmit: [data.products[1].id],
|
idsToOmit: [data.products[1].id],
|
||||||
...(isComponent ? { component: 'default.compo' } : {}),
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -265,10 +262,7 @@ describe.each([[false], [true]])('Relations, with d&p: %p', (withDraftAndPublish
|
|||||||
test('Can retrieve available relation(s) without entity', async () => {
|
test('Can retrieve available relation(s) without entity', async () => {
|
||||||
let res = await rq({
|
let res = await rq({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: `/content-manager/relations/api::shop.shop/${fieldName}`,
|
url: `/content-manager/relations/${modelUID}/${fieldName}`,
|
||||||
qs: {
|
|
||||||
...(isComponent ? { component: 'default.compo' } : {}),
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(res.status).toBe(200);
|
expect(res.status).toBe(200);
|
||||||
@ -289,10 +283,9 @@ describe.each([[false], [true]])('Relations, with d&p: %p', (withDraftAndPublish
|
|||||||
// can omitIds
|
// can omitIds
|
||||||
res = await rq({
|
res = await rq({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: `/content-manager/relations/api::shop.shop/${fieldName}`,
|
url: `/content-manager/relations/${modelUID}/${fieldName}`,
|
||||||
qs: {
|
qs: {
|
||||||
idsToOmit: [data.products[0].id],
|
idsToOmit: [data.products[0].id],
|
||||||
...(isComponent ? { component: 'default.compo' } : {}),
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -311,11 +304,10 @@ describe.each([[false], [true]])('Relations, with d&p: %p', (withDraftAndPublish
|
|||||||
test("search ''", async () => {
|
test("search ''", async () => {
|
||||||
const res = await rq({
|
const res = await rq({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: `/content-manager/relations/api::shop.shop/${fieldName}`,
|
url: `/content-manager/relations/${modelUID}/${fieldName}`,
|
||||||
qs: {
|
qs: {
|
||||||
_q: '',
|
_q: '',
|
||||||
...(withEntity ? { entityId } : {}),
|
...(withEntity ? { entityId } : {}),
|
||||||
...(isComponent ? { component: 'default.compo' } : {}),
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -331,11 +323,10 @@ describe.each([[false], [true]])('Relations, with d&p: %p', (withDraftAndPublish
|
|||||||
test("search 'Can'", async () => {
|
test("search 'Can'", async () => {
|
||||||
const res = await rq({
|
const res = await rq({
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: `/content-manager/relations/api::shop.shop/${fieldName}`,
|
url: `/content-manager/relations/${modelUID}/${fieldName}`,
|
||||||
qs: {
|
qs: {
|
||||||
_q: 'Can',
|
_q: 'Can',
|
||||||
...(withEntity ? { entityId } : {}),
|
...(withEntity ? { entityId } : {}),
|
||||||
...(isComponent ? { component: 'default.compo' } : {}),
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user