From a45b2f01133accc6759c41c6b612b3767d3393e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anne=20L=27H=C3=B4te?= Date: Wed, 2 Oct 2024 16:39:55 +0200 Subject: [PATCH 1/2] feat(structures): Can not add identifier to a structure if a same type and value already exist, see #115 --- .../structures/__tests__/identifiers.test.js | 21 ++++++++++++++++++- .../identifiers/identifiers.middlewares.js | 8 +++++++ .../identifiers/identifiers.routes.js | 4 +++- src/openapi/paths/structures/identifiers.yml | 2 ++ 4 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 src/api/structures/identifiers/identifiers.middlewares.js diff --git a/src/api/structures/__tests__/identifiers.test.js b/src/api/structures/__tests__/identifiers.test.js index 33b51980..0c77b4e8 100644 --- a/src/api/structures/__tests__/identifiers.test.js +++ b/src/api/structures/__tests__/identifiers.test.js @@ -1,4 +1,7 @@ -import { structures as resource, identifiers as subresource } from '../../resources'; +import { + structures as resource, + identifiers as subresource, +} from '../../resources'; let authorization; let id; @@ -77,6 +80,22 @@ describe('API > structures > identifiers > create', () => { .send(rest) .expect(400); }); + + it('should return 204 if an identifier with same type and same value already exists', async () => { + const paylod = { type: 'siret', value: '12345678912346' }; + + await global.superapp + .post(`/${resource}/${resourceId}/${subresource}`) + .set('Authorization', authorization) + .send(paylod) + .expect(201); + + await global.superapp + .post(`/${resource}/${resourceId}/${subresource}`) + .set('Authorization', authorization) + .send(paylod) + .expect(204); + }); }); describe('API > structures > identifiers > update', () => { diff --git a/src/api/structures/identifiers/identifiers.middlewares.js b/src/api/structures/identifiers/identifiers.middlewares.js new file mode 100644 index 00000000..36728c47 --- /dev/null +++ b/src/api/structures/identifiers/identifiers.middlewares.js @@ -0,0 +1,8 @@ +import { identifiersRepository } from '../../commons/repositories'; + +export const validateStructureIdentifierCreatePayload = async (req, res, next) => { + const { type, value } = req.body; + const { resourceId } = req.params; + const check = await identifiersRepository.findOne({ resourceId, type, value }); + return check ? res.status(204).json() : next(); +}; diff --git a/src/api/structures/identifiers/identifiers.routes.js b/src/api/structures/identifiers/identifiers.routes.js index 967698f6..81730b6d 100644 --- a/src/api/structures/identifiers/identifiers.routes.js +++ b/src/api/structures/identifiers/identifiers.routes.js @@ -6,7 +6,8 @@ import { saveInElastic, saveInStore } from '../../commons/middlewares/event.midd import { readQuery, readQueryWithLookup } from '../../commons/queries/identifiers.query'; import elasticQuery from '../../commons/queries/structures.elastic'; import { identifiersRepository as repository, structuresRepository } from '../../commons/repositories'; -import { identifiers as subresource, structures as resource } from '../../resources'; +import { structures as resource, identifiers as subresource } from '../../resources'; +import { validateStructureIdentifierCreatePayload } from './identifiers.middlewares'; const router = new express.Router(); @@ -14,6 +15,7 @@ router.route(`/${resource}/:resourceId/${subresource}`) .get(controllers.list(repository, readQuery)) .post([ createContext, + validateStructureIdentifierCreatePayload, setGeneratedInternalIdInContext(subresource), controllers.create(repository, readQueryWithLookup), saveInStore(subresource), diff --git a/src/openapi/paths/structures/identifiers.yml b/src/openapi/paths/structures/identifiers.yml index 7849b1f4..8216cfcc 100644 --- a/src/openapi/paths/structures/identifiers.yml +++ b/src/openapi/paths/structures/identifiers.yml @@ -57,6 +57,8 @@ collectionMethods: application/json: schema: $ref: '../../api.yml#/components/schemas/StructureIdentifier' + '204': + description: 'No content' '400': $ref: '../../api.yml#/components/responses/BadRequest' '401': From d56aff1eb55de51468854c1efe12ea33612e077d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anne=20L=27H=C3=B4te?= Date: Wed, 2 Oct 2024 17:25:49 +0200 Subject: [PATCH 2/2] fix(ci/cd): Correct tests about structures identifiers --- .../structures/__tests__/identifiers.test.js | 67 +++++++++++-------- 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/src/api/structures/__tests__/identifiers.test.js b/src/api/structures/__tests__/identifiers.test.js index 0c77b4e8..c76bfe13 100644 --- a/src/api/structures/__tests__/identifiers.test.js +++ b/src/api/structures/__tests__/identifiers.test.js @@ -4,7 +4,6 @@ import { } from '../../resources'; let authorization; -let id; let resourceId; const payload = { @@ -28,20 +27,16 @@ beforeAll(async () => { resourceId = body.id; }); -beforeEach(async () => { +afterEach(async () => { + // Delete all structures identifiers const { body } = await global.superapp - .post(`/${resource}/${resourceId}/${subresource}`) - .set('Authorization', authorization) - .send(payload); - id = body.id; -}); + .get(`/${resource}/${resourceId}/${subresource}`) + .set('Authorization', authorization); + const promises = body.data.map((identifier) => global.superapp + .delete(`/${resource}/${resourceId}/${subresource}/${identifier.id}`) + .set('Authorization', authorization)); -afterEach(async () => { - if (id) { - await global.superapp - .delete(`/${resource}/${resourceId}/${subresource}/${id}`) - .set('Authorization', authorization); - } + await Promise.all(promises); }); describe('API > structures > identifiers > create', () => { @@ -100,13 +95,18 @@ describe('API > structures > identifiers > create', () => { describe('API > structures > identifiers > update', () => { it('should update an existing identifier', async () => { + const { body: { id } } = await global.superapp + .post(`/${resource}/${resourceId}/${subresource}`) + .set('Authorization', authorization) + .send(payload); + const type = 'wikidata'; - const { body } = await global.superapp + const { body: updatedBody } = await global.superapp .patch(`/${resource}/${resourceId}/${subresource}/${id}`) .set('Authorization', authorization) .send({ type }) .expect(200); - expect(body.type).toBe(type); + expect(updatedBody.type).toBe(type); }); it('should throw bad request if id too short', async () => { @@ -126,6 +126,11 @@ describe('API > structures > identifiers > update', () => { }); it('should throw bad request with badly formatted payload', async () => { + const { body: { id } } = await global.superapp + .post(`/${resource}/${resourceId}/${subresource}`) + .set('Authorization', authorization) + .send(payload); + await global.superapp .patch(`/${resource}/${resourceId}/${subresource}/${id}`) .set('Authorization', authorization) @@ -134,6 +139,11 @@ describe('API > structures > identifiers > update', () => { }); it('should accept empty dates', async () => { + const { body: { id } } = await global.superapp + .post(`/${resource}/${resourceId}/${subresource}`) + .set('Authorization', authorization) + .send(payload); + await global.superapp .patch(`/${resource}/${resourceId}/${subresource}/${id}`) .set('Authorization', authorization) @@ -145,13 +155,19 @@ describe('API > structures > identifiers > update', () => { describe('API > structures > identifiers > read', () => { it('should read existing identifier', async () => { const { body } = await global.superapp + .post(`/${resource}/${resourceId}/${subresource}`) + .set('Authorization', authorization) + .send(payload); + const { id } = body; + + const { body: readBody } = await global.superapp .get(`/${resource}/${resourceId}/${subresource}/${id}`) .set('Authorization', authorization) .expect(200); - expect(body.type).toBe(payload.type); - expect(body.value).toBe(payload.value); - expect(body.active).toBeFalsy(); - expect(body.createdBy.lastName).toBe('user'); + expect(readBody.type).toBe(payload.type); + expect(readBody.value).toBe(payload.value); + expect(readBody.active).toBeFalsy(); + expect(readBody.createdBy.lastName).toBe('user'); }); it('should throw bad request if id too short', async () => { @@ -185,6 +201,11 @@ describe('API > structures > identifiers > delete', () => { }); it('should delete existing identifier', async () => { + const { body: { id } } = await global.superapp + .post(`/${resource}/${resourceId}/${subresource}`) + .set('Authorization', authorization) + .send(payload); + await global.superapp .delete(`/${resource}/${resourceId}/${subresource}/${id}`) .set('Authorization', authorization) @@ -226,14 +247,6 @@ describe('API > structures > identifiers > list', () => { }); }); - beforeEach(async () => { - if (id) { - await global.superapp - .delete(`/${resource}/${resourceId}/${subresource}/${id}`) - .set('Authorization', authorization); - } - }); - it('should list', async () => { const { body } = await global.superapp .get(`/${resource}/${resourceId}/${subresource}`)