fix(content-manager): detect non existant relation on entity update

This commit is contained in:
Jamie Howard 2022-09-30 11:02:59 +01:00
parent a2b035600d
commit f6be2e2b66
4 changed files with 165 additions and 2 deletions

View File

@ -31,7 +31,7 @@ const LogoContainer = styled(Box)`
`;
const HomePage = () => {
// // Temporary until we develop the menu API
// Temporary until we develop the menu API
const { collectionTypes, singleTypes, isLoading: isLoadingForModels } = useModels();
const { guidedTourState, isGuidedTourVisible, isSkipped } = useGuidedTour();

View File

@ -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();
});
});
});
});

View File

@ -9,7 +9,7 @@ const {
contentTypes: contentTypesUtils,
sanitize,
} = require('@strapi/utils');
const { ValidationError } = require('@strapi/utils').errors;
const { ValidationError, ApplicationError } = require('@strapi/utils').errors;
const { transformParamsToQuery } = require('@strapi/utils').convertQueryParams;
const uploadFiles = require('../utils/upload-files');
@ -47,6 +47,7 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
},
async emitEvent(uid, event, entity) {
if (!eventHub) return;
const model = strapi.getModel(uid);
const sanitizedEntity = await sanitize.sanitizers.defaultSanitizeOutput(model, entity);
@ -168,6 +169,38 @@ const createDefaultImplementation = ({ strapi, db, eventHub, entityValidator })
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));
// TODO: wrap in transaction

View File

@ -209,6 +209,7 @@ describe('File', () => {
data.files[1] = file;
});
});
describe('Move a file from root level to a folder', () => {
test('when replacing the file', async () => {
const res = await rq({