Skip to content

Commit 91cf2fb

Browse files
[TECH] Migration de la route POST api/membership/me/disable (PIX-16733)
#11528
2 parents 71836a3 + e7ebc1d commit 91cf2fb

File tree

9 files changed

+130
-129
lines changed

9 files changed

+130
-129
lines changed

api/lib/application/memberships/index.js

-28
Original file line numberDiff line numberDiff line change
@@ -3,37 +3,9 @@ import Joi from 'joi';
33
import { securityPreHandlers } from '../../../src/shared/application/security-pre-handlers.js';
44
import { identifiersType } from '../../../src/shared/domain/types/identifiers-type.js';
55
import { membershipController } from '../../../src/team/application/membership/membership.controller.js';
6-
import { membershipController as libMembershipController } from './membership-controller.js';
76

87
const register = async function (server) {
98
server.route([
10-
{
11-
method: 'POST',
12-
path: '/api/memberships/me/disable',
13-
config: {
14-
pre: [
15-
{
16-
method: securityPreHandlers.checkUserIsAdminInOrganization,
17-
assign: 'isAdminInOrganization',
18-
},
19-
{
20-
method: securityPreHandlers.checkUserCanDisableHisOrganizationMembership,
21-
assign: 'canDisableHisOrganizationMembership',
22-
},
23-
],
24-
validate: {
25-
payload: Joi.object({
26-
organizationId: identifiersType.organizationId,
27-
}),
28-
},
29-
handler: libMembershipController.disableOwnOrganizationMembership,
30-
tags: ['api'],
31-
notes: [
32-
"- **Cette route est restreinte aux utilisateurs authentifiés en tant qu'administrateur de l'organisation\n" +
33-
"- Elle permet de se retirer d'une organisation",
34-
],
35-
},
36-
},
379
{
3810
method: 'POST',
3911
path: '/api/memberships/{id}/disable',

api/lib/application/memberships/membership-controller.js

-15
This file was deleted.

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

+16-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ const disable = async function (request, h) {
2121
return h.response().code(204);
2222
};
2323

24+
const disableOwnOrganizationMembership = async function (request, h) {
25+
const organizationId = request.payload.organizationId;
26+
const userId = requestResponseUtils.extractUserIdFromRequest(request);
27+
28+
await usecases.disableOwnOrganizationMembership({ organizationId, userId });
29+
30+
return h.response().code(204);
31+
};
32+
2433
const update = async function (request, h, dependencies = { requestResponseUtils, membershipSerializer }) {
2534
const membershipId = request.params.id;
2635
const userId = dependencies.requestResponseUtils.extractUserIdFromRequest(request);
@@ -50,6 +59,12 @@ const findPaginatedFilteredMemberships = async function (request) {
5059
return membershipSerializer.serialize(memberships, pagination);
5160
};
5261

53-
const membershipController = { create, disable, findPaginatedFilteredMemberships, update };
62+
const membershipController = {
63+
create,
64+
disable,
65+
disableOwnOrganizationMembership,
66+
findPaginatedFilteredMemberships,
67+
update,
68+
};
5469

5570
export { membershipController };

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

+27
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,33 @@ export const membershipRoutes = [
3535
tags: ['api', 'team', 'memberships'],
3636
},
3737
},
38+
{
39+
method: 'POST',
40+
path: '/api/memberships/me/disable',
41+
config: {
42+
pre: [
43+
{
44+
method: securityPreHandlers.checkUserIsAdminInOrganization,
45+
assign: 'isAdminInOrganization',
46+
},
47+
{
48+
method: securityPreHandlers.checkUserCanDisableHisOrganizationMembership,
49+
assign: 'canDisableHisOrganizationMembership',
50+
},
51+
],
52+
validate: {
53+
payload: Joi.object({
54+
organizationId: identifiersType.organizationId,
55+
}),
56+
},
57+
handler: (request, h) => membershipController.disableOwnOrganizationMembership(request, h),
58+
tags: ['api'],
59+
notes: [
60+
"- **Cette route est restreinte aux utilisateurs authentifiés en tant qu'administrateur de l'organisation\n" +
61+
"- Elle permet de se retirer d'une organisation",
62+
],
63+
},
64+
},
3865
{
3966
method: 'GET',
4067
path: '/api/organizations/{id}/memberships',

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

-37
Original file line numberDiff line numberDiff line change
@@ -96,41 +96,4 @@ describe('Acceptance | Controller | membership-controller', function () {
9696
});
9797
});
9898
});
99-
100-
describe('POST /api/memberships/me/disable', function () {
101-
context('when user is one of the admins of the organization', function () {
102-
it('disables user membership and returns a 204', async function () {
103-
// given
104-
const organizationId = databaseBuilder.factory.buildOrganization().id;
105-
const organizationAdminUserId = databaseBuilder.factory.buildUser().id;
106-
databaseBuilder.factory.buildMembership({
107-
userId: organizationAdminUserId,
108-
organizationId,
109-
organizationRole: Membership.roles.ADMIN,
110-
});
111-
databaseBuilder.factory.buildMembership({
112-
userId: databaseBuilder.factory.buildUser().id,
113-
organizationId,
114-
organizationRole: Membership.roles.ADMIN,
115-
});
116-
117-
await databaseBuilder.commit();
118-
119-
const options = {
120-
method: 'POST',
121-
url: '/api/memberships/me/disable',
122-
payload: {
123-
organizationId,
124-
},
125-
headers: generateAuthenticatedUserRequestHeaders({ userId: organizationAdminUserId }),
126-
};
127-
128-
// when
129-
const response = await server.inject(options);
130-
131-
// then
132-
expect(response.statusCode).to.equal(204);
133-
});
134-
});
135-
});
13699
});

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

+37
Original file line numberDiff line numberDiff line change
@@ -278,4 +278,41 @@ describe('Acceptance | Team | Application | Route | membership', function () {
278278
});
279279
});
280280
});
281+
282+
describe('POST /api/memberships/me/disable', function () {
283+
context('when user is one of the admins of the organization', function () {
284+
it('disables user membership and returns a 204', async function () {
285+
// given
286+
const organizationId = databaseBuilder.factory.buildOrganization().id;
287+
const organizationAdminUserId = databaseBuilder.factory.buildUser().id;
288+
databaseBuilder.factory.buildMembership({
289+
userId: organizationAdminUserId,
290+
organizationId,
291+
organizationRole: Membership.roles.ADMIN,
292+
});
293+
databaseBuilder.factory.buildMembership({
294+
userId: databaseBuilder.factory.buildUser().id,
295+
organizationId,
296+
organizationRole: Membership.roles.ADMIN,
297+
});
298+
299+
await databaseBuilder.commit();
300+
301+
const options = {
302+
method: 'POST',
303+
url: '/api/memberships/me/disable',
304+
payload: {
305+
organizationId,
306+
},
307+
headers: generateAuthenticatedUserRequestHeaders({ userId: organizationAdminUserId }),
308+
};
309+
310+
// when
311+
const response = await server.inject(options);
312+
313+
// then
314+
expect(response.statusCode).to.equal(204);
315+
});
316+
});
317+
});
281318
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { usecases } from '../../../../../src/team/domain/usecases/index.js';
2+
import * as membershipRepository from '../../../../../src/team/infrastructure/repositories/membership.repository.js';
3+
import { databaseBuilder, expect, knex, sinon } from '../../../../test-helper.js';
4+
5+
describe('Integration | Team | Domain | UseCase | disable-own-membership', function () {
6+
let clock;
7+
8+
beforeEach(function () {
9+
clock = sinon.useFakeTimers({ now: new Date('2023-08-01T11:15:00Z'), toFake: ['Date'] });
10+
});
11+
12+
afterEach(function () {
13+
clock.restore();
14+
});
15+
16+
context('success', function () {
17+
it('disables membership', async function () {
18+
// given
19+
const userId = databaseBuilder.factory.buildUser().id;
20+
21+
const organizationId1 = databaseBuilder.factory.buildOrganization().id;
22+
databaseBuilder.factory.buildMembership({
23+
organizationId: organizationId1,
24+
userId,
25+
disabledAt: null,
26+
});
27+
28+
const organizationId2 = databaseBuilder.factory.buildOrganization().id;
29+
databaseBuilder.factory.buildMembership({
30+
organizationId: organizationId2,
31+
userId,
32+
disabledAt: null,
33+
});
34+
35+
await databaseBuilder.commit();
36+
37+
// when
38+
await usecases.disableOwnOrganizationMembership({
39+
organizationId: organizationId1,
40+
userId,
41+
membershipRepository: membershipRepository,
42+
});
43+
44+
// then
45+
const userMemberships = await knex('memberships').where('userId', userId).whereNull('disabledAt');
46+
expect(userMemberships).to.have.length(1);
47+
expect(userMemberships[0].organizationId).to.equal(organizationId2);
48+
});
49+
});
50+
});

api/tests/unit/domain/usecases/disable-own-organization-membership_test.js

-48
This file was deleted.

0 commit comments

Comments
 (0)