Skip to content

Commit fae6ecb

Browse files
[TECH] Migration de la route POST /api/memberships/{id}/disable dans /src/team
#11554
2 parents 4a9cd5c + 413bc2f commit fae6ecb

File tree

8 files changed

+152
-212
lines changed

8 files changed

+152
-212
lines changed

api/lib/application/memberships/index.js

Lines changed: 0 additions & 36 deletions
This file was deleted.

api/lib/routes.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import * as campaignParticipations from './application/campaign-participations/i
44
import * as certificationCenterMemberships from './application/certification-center-memberships/index.js';
55
import * as certificationCenters from './application/certification-centers/index.js';
66
import * as frameworks from './application/frameworks/index.js';
7-
import * as memberships from './application/memberships/index.js';
87
import * as organizations from './application/organizations/index.js';
98
import * as scoOrganizationLearners from './application/sco-organization-learners/index.js';
109
import * as users from './application/users/index.js';
@@ -15,7 +14,6 @@ const routes = [
1514
certificationCenters,
1615
certificationCenterMemberships,
1716
healthcheck,
18-
memberships,
1917
organizations,
2018
scoOrganizationLearners,
2119
frameworks,

api/src/team/application/membership/membership.route.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,29 @@ export const membershipRoutes = [
6262
],
6363
},
6464
},
65+
{
66+
method: 'POST',
67+
path: '/api/memberships/{id}/disable',
68+
config: {
69+
pre: [
70+
{
71+
method: (request, h) => securityPreHandlers.checkUserIsAdminInOrganization(request, h),
72+
assign: 'isAdminInOrganization',
73+
},
74+
],
75+
validate: {
76+
params: Joi.object({
77+
id: identifiersType.membershipId,
78+
}),
79+
},
80+
handler: (request, h) => membershipController.disable(request, h),
81+
tags: ['api'],
82+
notes: [
83+
"- **Cette route est restreinte aux utilisateurs authentifiés en tant qu'administrateur de l'organisation\n" +
84+
"- Elle permet la désactivation d'un membre",
85+
],
86+
},
87+
},
6588
{
6689
method: 'GET',
6790
path: '/api/organizations/{id}/memberships',

api/tests/acceptance/application/memberships/membership-controller_test.js

Lines changed: 0 additions & 99 deletions
This file was deleted.

api/tests/integration/application/memberships/membership-controller_test.js

Lines changed: 0 additions & 31 deletions
This file was deleted.

api/tests/team/acceptance/application/membership/membership.route.test.js

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,4 +315,95 @@ describe('Acceptance | Team | Application | Route | membership', function () {
315315
});
316316
});
317317
});
318+
319+
describe('POST /api/memberships/{id}/disable', function () {
320+
let options;
321+
let membershipId;
322+
let organizationId;
323+
324+
beforeEach(async function () {
325+
organizationId = databaseBuilder.factory.buildOrganization().id;
326+
const userId = databaseBuilder.factory.buildUser().id;
327+
membershipId = databaseBuilder.factory.buildMembership({ organizationId, userId }).id;
328+
const organizationAdminUserId = databaseBuilder.factory.buildUser().id;
329+
databaseBuilder.factory.buildMembership({
330+
userId: organizationAdminUserId,
331+
organizationId,
332+
organizationRole: Membership.roles.ADMIN,
333+
});
334+
335+
await databaseBuilder.commit();
336+
337+
options = {
338+
method: 'POST',
339+
url: `/api/memberships/${membershipId}/disable`,
340+
payload: {
341+
data: {
342+
id: membershipId.toString(),
343+
type: 'memberships',
344+
relationships: {
345+
user: {
346+
data: {
347+
type: 'users',
348+
id: userId,
349+
},
350+
},
351+
organization: {
352+
data: {
353+
type: 'organizations',
354+
id: organizationId,
355+
},
356+
},
357+
},
358+
},
359+
},
360+
headers: generateAuthenticatedUserRequestHeaders({ userId: organizationAdminUserId }),
361+
};
362+
});
363+
364+
context('Success cases', function () {
365+
context('When user is admin of the organization', function () {
366+
it('should return a 204', async function () {
367+
// when
368+
const response = await server.inject(options);
369+
370+
// then
371+
expect(response.statusCode).to.equal(204);
372+
});
373+
});
374+
});
375+
376+
context('Error cases', function () {
377+
it('should respond with a 403 if user does not have the role Admin in organization', async function () {
378+
// given
379+
const notOrganizationAdminUserId = databaseBuilder.factory.buildUser().id;
380+
databaseBuilder.factory.buildMembership({
381+
userId: notOrganizationAdminUserId,
382+
organizationId,
383+
organizationRole: Membership.roles.MEMBER,
384+
});
385+
await databaseBuilder.commit();
386+
387+
options.headers = generateAuthenticatedUserRequestHeaders({ userId: notOrganizationAdminUserId });
388+
389+
// when
390+
const response = await server.inject(options);
391+
392+
// then
393+
expect(response.statusCode).to.equal(403);
394+
});
395+
396+
it('should respond with a 400 if membership does not exist', async function () {
397+
// given
398+
const unknownMembershipId = 9999;
399+
options.url = `/api/memberships/${unknownMembershipId}/disable`;
400+
401+
// when
402+
const response = await server.inject(options);
403+
404+
// then
405+
expect(response.statusCode).to.equal(400);
406+
});
407+
});
408+
});
318409
});

api/tests/team/unit/application/membership/membership.route.test.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,42 @@ describe('Unit | Team | Application | Route | Membership', function () {
4141
expect(membershipController.update).to.have.not.been.called;
4242
});
4343
});
44+
45+
describe('POST /api/memberships/{id}/disable', function () {
46+
it('should return 204 if user is admin in organization', async function () {
47+
// given
48+
sinon.stub(securityPreHandlers, 'checkUserIsAdminInOrganization').callsFake((request, h) => h.response(true));
49+
sinon.stub(membershipController, 'disable').callsFake((request, h) => h.response().code(204));
50+
51+
const httpTestServer = new HttpTestServer();
52+
await httpTestServer.register(teamRoutes);
53+
const membershipId = 123;
54+
55+
// when
56+
const response = await httpTestServer.request('POST', `/api/memberships/${membershipId}/disable`);
57+
58+
// then
59+
expect(response.statusCode).to.equal(204);
60+
expect(membershipController.disable).to.have.been.called;
61+
});
62+
63+
it('should return 403 if user is not admin in organization', async function () {
64+
// given
65+
sinon
66+
.stub(securityPreHandlers, 'checkUserIsAdminInOrganization')
67+
.callsFake((request, h) => h.response().code(403).takeover());
68+
sinon.stub(membershipController, 'disable');
69+
70+
const httpTestServer = new HttpTestServer();
71+
await httpTestServer.register(teamRoutes);
72+
const membershipId = 123;
73+
74+
// when
75+
const response = await httpTestServer.request('POST', `/api/memberships/${membershipId}/disable`);
76+
77+
// then
78+
expect(response.statusCode).to.equal(403);
79+
expect(membershipController.disable).to.have.not.been.called;
80+
});
81+
});
4482
});

api/tests/unit/application/memberships/index_test.js

Lines changed: 0 additions & 44 deletions
This file was deleted.

0 commit comments

Comments
 (0)