mirror of
https://github.com/strapi/strapi.git
synced 2025-09-26 17:00:55 +00:00
fix(content-manager): detect non existant relation on entity update
This commit is contained in:
parent
a2b035600d
commit
f6be2e2b66
@ -31,7 +31,7 @@ const LogoContainer = styled(Box)`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const HomePage = () => {
|
const HomePage = () => {
|
||||||
// // Temporary until we develop the menu API
|
// Temporary until we develop the menu API
|
||||||
const { collectionTypes, singleTypes, isLoading: isLoadingForModels } = useModels();
|
const { collectionTypes, singleTypes, isLoading: isLoadingForModels } = useModels();
|
||||||
const { guidedTourState, isGuidedTourVisible, isSkipped } = useGuidedTour();
|
const { guidedTourState, isGuidedTourVisible, isSkipped } = useGuidedTour();
|
||||||
|
|
||||||
|
@ -186,4 +186,133 @@ describe('Entity service', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Update', () => {
|
||||||
|
describe('assign default values', () => {
|
||||||
|
let instance;
|
||||||
|
|
||||||
|
const entityUID = 'api::entity.entity';
|
||||||
|
const relationUID = 'api::relation.relation';
|
||||||
|
const fakeEntities = {
|
||||||
|
0: {
|
||||||
|
id: 0,
|
||||||
|
Name: 'TestEntity',
|
||||||
|
createdAt: '2022-09-28T15:11:22.995Z',
|
||||||
|
updatedAt: '2022-09-29T09:01:02.949Z',
|
||||||
|
publishedAt: null,
|
||||||
|
},
|
||||||
|
1: {
|
||||||
|
id: 1,
|
||||||
|
Name: 'TestRelation',
|
||||||
|
createdAt: '2022-09-28T15:11:22.995Z',
|
||||||
|
updatedAt: '2022-09-29T09:01:02.949Z',
|
||||||
|
publishedAt: null,
|
||||||
|
},
|
||||||
|
2: null,
|
||||||
|
};
|
||||||
|
beforeAll(() => {
|
||||||
|
const fakeModel = {
|
||||||
|
kind: 'collectionType',
|
||||||
|
modelName: 'entity',
|
||||||
|
collectionName: 'entity',
|
||||||
|
uid: entityUID,
|
||||||
|
privateAttributes: [],
|
||||||
|
options: {},
|
||||||
|
info: {
|
||||||
|
singularName: 'entity',
|
||||||
|
pluralName: 'entities',
|
||||||
|
displayName: 'ENTITY',
|
||||||
|
},
|
||||||
|
attributes: {
|
||||||
|
Name: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
addresses: {
|
||||||
|
type: 'relation',
|
||||||
|
relation: 'oneToMany',
|
||||||
|
target: relationUID,
|
||||||
|
mappedBy: 'entity',
|
||||||
|
},
|
||||||
|
updatedBy: {
|
||||||
|
type: 'relation',
|
||||||
|
relation: 'oneToOne',
|
||||||
|
target: 'admin::user',
|
||||||
|
configurable: false,
|
||||||
|
writable: false,
|
||||||
|
visible: false,
|
||||||
|
useJoinTable: false,
|
||||||
|
private: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const fakeQuery = {
|
||||||
|
findOne: jest.fn(({ where }) => fakeEntities[where.id]),
|
||||||
|
update: jest.fn(({ where }) => ({
|
||||||
|
...fakeEntities[where.id],
|
||||||
|
addresses: {
|
||||||
|
count: 1,
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
|
||||||
|
const fakeDB = {
|
||||||
|
query: jest.fn(() => fakeQuery),
|
||||||
|
};
|
||||||
|
|
||||||
|
const fakeStrapi = {
|
||||||
|
getModel: jest.fn(() => fakeModel),
|
||||||
|
};
|
||||||
|
|
||||||
|
instance = createEntityService({
|
||||||
|
strapi: fakeStrapi,
|
||||||
|
db: fakeDB,
|
||||||
|
eventHub: null, // bypass event emission for update tests
|
||||||
|
entityValidator,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test(`should fail if the entity doesn't exist`, async () => {
|
||||||
|
expect(
|
||||||
|
await instance.update(entityUID, Math.random() * (10000 - 100) + 100, {})
|
||||||
|
).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should successfully update with an existing relation', async () => {
|
||||||
|
const data = {
|
||||||
|
Name: 'TestEntry',
|
||||||
|
addresses: {
|
||||||
|
connect: [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
updatedBy: 1,
|
||||||
|
};
|
||||||
|
expect(await instance.update(entityUID, 0, { data })).toMatchObject({
|
||||||
|
...fakeEntities[0],
|
||||||
|
addresses: {
|
||||||
|
count: 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should throw an error when trying to associate a relation that does not exist', async () => {
|
||||||
|
const data = {
|
||||||
|
Name: 'TestEntry',
|
||||||
|
addresses: {
|
||||||
|
connect: [
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
updatedBy: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
await expect(instance.update(entityUID, 0, { data })).rejects.toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -9,7 +9,7 @@ const {
|
|||||||
contentTypes: contentTypesUtils,
|
contentTypes: contentTypesUtils,
|
||||||
sanitize,
|
sanitize,
|
||||||
} = require('@strapi/utils');
|
} = require('@strapi/utils');
|
||||||
const { ValidationError } = require('@strapi/utils').errors;
|
const { ValidationError, ApplicationError } = require('@strapi/utils').errors;
|
||||||
const { transformParamsToQuery } = require('@strapi/utils').convertQueryParams;
|
const { transformParamsToQuery } = require('@strapi/utils').convertQueryParams;
|
||||||
const uploadFiles = require('../utils/upload-files');
|
const uploadFiles = require('../utils/upload-files');
|
||||||
|
|
||||||
@ -47,6 +47,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|||||||
},
|
},
|
||||||
|
|
||||||
async emitEvent(uid, event, entity) {
|
async emitEvent(uid, event, entity) {
|
||||||
|
if (!eventHub) return;
|
||||||
const model = strapi.getModel(uid);
|
const model = strapi.getModel(uid);
|
||||||
const sanitizedEntity = await sanitize.sanitizers.defaultSanitizeOutput(model, entity);
|
const sanitizedEntity = await sanitize.sanitizers.defaultSanitizeOutput(model, entity);
|
||||||
|
|
||||||
@ -168,6 +169,38 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
|
|||||||
entityToUpdate
|
entityToUpdate
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Create an array of the relations we are attempting to associate with this
|
||||||
|
// entity.
|
||||||
|
const relationChecks = [];
|
||||||
|
Object.keys(data).forEach((key) => {
|
||||||
|
const attribute = model.attributes[key];
|
||||||
|
if (attribute?.type !== 'relation') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!data[key]?.connect) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
relationChecks.push({ uid: attribute.target, data: data[key].connect });
|
||||||
|
});
|
||||||
|
|
||||||
|
// Confirm that these relations exists in the DB before performing the query.
|
||||||
|
await Promise.all(
|
||||||
|
relationChecks.map(async (check) => {
|
||||||
|
await Promise.all(
|
||||||
|
check.data.map(async (d) => {
|
||||||
|
const relationEntity = await db.query(check.uid).findOne({ where: { id: d.id } });
|
||||||
|
if (relationEntity) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Trying to associate a relation with this entity that does not exist
|
||||||
|
throw new ApplicationError(
|
||||||
|
`Relation of type ${check.uid} with id ${d.id} does not exist`
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
|
const query = transformParamsToQuery(uid, pickSelectionParams(wrappedParams));
|
||||||
|
|
||||||
// TODO: wrap in transaction
|
// TODO: wrap in transaction
|
||||||
|
@ -209,6 +209,7 @@ describe('File', () => {
|
|||||||
data.files[1] = file;
|
data.files[1] = file;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Move a file from root level to a folder', () => {
|
describe('Move a file from root level to a folder', () => {
|
||||||
test('when replacing the file', async () => {
|
test('when replacing the file', async () => {
|
||||||
const res = await rq({
|
const res = await rq({
|
||||||
|
Loading…
x
Reference in New Issue
Block a user