@stamhoofd/backend 2.78.2 → 2.78.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.ci.json +32 -16
- package/index.ts +7 -0
- package/jest.config.cjs +17 -0
- package/package.json +10 -10
- package/src/endpoints/auth/GetUserEndpoint.test.ts +0 -10
- package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.test.ts +726 -0
- package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.ts +31 -18
- package/src/endpoints/global/members/shouldCheckIfMemberIsDuplicate.ts +9 -21
- package/src/endpoints/global/organizations/CreateOrganizationEndpoint.test.ts +1 -1
- package/src/endpoints/global/organizations/GetOrganizationFromDomainEndpoint.test.ts +0 -4
- package/src/endpoints/global/organizations/SearchOrganizationEndpoint.test.ts +0 -4
- package/src/endpoints/global/registration/PatchUserMembersEndpoint.test.ts +288 -8
- package/src/endpoints/global/registration/PatchUserMembersEndpoint.ts +8 -13
- package/src/endpoints/global/registration/RegisterMembersEndpoint.test.ts +7 -7
- package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.test.ts +2 -217
- package/src/endpoints/organization/dashboard/payments/PatchBalanceItemsEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.ts +6 -3
- package/src/endpoints/organization/shared/auth/GetOrganizationEndpoint.test.ts +4 -6
- package/src/endpoints/organization/webshops/GetWebshopEndpoint.test.ts +2 -20
- package/src/helpers/AdminPermissionChecker.ts +88 -140
- package/src/helpers/GlobalHelper.ts +6 -1
- package/src/services/FileSignService.ts +3 -3
- package/src/services/MemberRecordStore.ts +155 -0
- package/src/services/PlatformMembershipService.ts +17 -8
- package/tests/e2e/register.test.ts +49 -21
- package/tests/helpers/StripeMocker.ts +7 -2
- package/tests/jest.global.setup.ts +6 -1
- package/tests/jest.setup.ts +10 -2
|
@@ -0,0 +1,726 @@
|
|
|
1
|
+
import { Database } from '@simonbackx/simple-database';
|
|
2
|
+
import { PatchableArray, PatchMap } from '@simonbackx/simple-encoding';
|
|
3
|
+
import { Endpoint, Request } from '@simonbackx/simple-endpoints';
|
|
4
|
+
import { GroupFactory, MemberFactory, OrganizationFactory, OrganizationTagFactory, Platform, RegistrationFactory, Token, UserFactory } from '@stamhoofd/models';
|
|
5
|
+
import { MemberDetails, MemberWithRegistrationsBlob, OrganizationMetaData, OrganizationRecordsConfiguration, Parent, PatchAnswers, PermissionLevel, Permissions, PermissionsResourceType, RecordCategory, RecordSettings, RecordTextAnswer, ResourcePermissions, UserPermissions } from '@stamhoofd/structures';
|
|
6
|
+
import { TestUtils } from '@stamhoofd/test-utils';
|
|
7
|
+
import { testServer } from '../../../../tests/helpers/TestServer';
|
|
8
|
+
import { PatchOrganizationMembersEndpoint } from './PatchOrganizationMembersEndpoint';
|
|
9
|
+
|
|
10
|
+
const baseUrl = `/organization/members`;
|
|
11
|
+
const endpoint = new PatchOrganizationMembersEndpoint();
|
|
12
|
+
type EndpointType = typeof endpoint;
|
|
13
|
+
type Body = EndpointType extends Endpoint<any, any, infer B, any> ? B : never;
|
|
14
|
+
|
|
15
|
+
const firstName = 'John';
|
|
16
|
+
const lastName = 'Doe';
|
|
17
|
+
const birthDay = { year: 1993, month: 4, day: 5 };
|
|
18
|
+
|
|
19
|
+
const errorWithCode = (code: string) => expect.objectContaining({ code }) as jest.Constructable;
|
|
20
|
+
|
|
21
|
+
describe('Endpoint.PatchOrganizationMembersEndpoint', () => {
|
|
22
|
+
beforeEach(async () => {
|
|
23
|
+
TestUtils.setEnvironment('userMode', 'platform');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
afterEach(async () => {
|
|
27
|
+
// Delete all members (so the duplicate checks work as expected)
|
|
28
|
+
await Database.delete('DELETE FROM `members`');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('Duplicate members', () => {
|
|
32
|
+
test('The security code should be a requirement', async () => {
|
|
33
|
+
const organization = await new OrganizationFactory({ }).create();
|
|
34
|
+
const user = await new UserFactory({
|
|
35
|
+
permissions: Permissions.create({ level: PermissionLevel.Full }),
|
|
36
|
+
organization, // since we are in platform mode, this will only set the permissions for this organization
|
|
37
|
+
}).create();
|
|
38
|
+
|
|
39
|
+
const existingMember = await new MemberFactory({
|
|
40
|
+
firstName,
|
|
41
|
+
lastName,
|
|
42
|
+
birthDay,
|
|
43
|
+
generateData: true,
|
|
44
|
+
}).create();
|
|
45
|
+
|
|
46
|
+
const token = await Token.createToken(user);
|
|
47
|
+
|
|
48
|
+
const arr: Body = new PatchableArray();
|
|
49
|
+
const put = MemberWithRegistrationsBlob.create({
|
|
50
|
+
details: MemberDetails.create({
|
|
51
|
+
firstName,
|
|
52
|
+
lastName,
|
|
53
|
+
birthDay: new Date(existingMember.details.birthDay!.getTime() + 1),
|
|
54
|
+
}),
|
|
55
|
+
});
|
|
56
|
+
arr.addPut(put);
|
|
57
|
+
|
|
58
|
+
const request = Request.buildJson('PATCH', baseUrl, organization.getApiHost(), arr);
|
|
59
|
+
request.headers.authorization = 'Bearer ' + token.accessToken;
|
|
60
|
+
await expect(testServer.test(endpoint, request))
|
|
61
|
+
.rejects
|
|
62
|
+
.toThrow(errorWithCode('known_member_missing_rights'));
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('The security code is not a requirement for members without additional data', async () => {
|
|
66
|
+
const organization = await new OrganizationFactory({ }).create();
|
|
67
|
+
const user = await new UserFactory({
|
|
68
|
+
permissions: Permissions.create({ level: PermissionLevel.Full }),
|
|
69
|
+
organization, // since we are in platform mode, this will only set the permissions for this organization
|
|
70
|
+
}).create();
|
|
71
|
+
|
|
72
|
+
const existingMember = await new MemberFactory({
|
|
73
|
+
firstName,
|
|
74
|
+
lastName,
|
|
75
|
+
birthDay,
|
|
76
|
+
generateData: false,
|
|
77
|
+
}).create();
|
|
78
|
+
|
|
79
|
+
const token = await Token.createToken(user);
|
|
80
|
+
|
|
81
|
+
const arr: Body = new PatchableArray();
|
|
82
|
+
const put = MemberWithRegistrationsBlob.create({
|
|
83
|
+
details: MemberDetails.create({
|
|
84
|
+
firstName,
|
|
85
|
+
lastName,
|
|
86
|
+
birthDay: new Date(existingMember.details.birthDay!.getTime() + 1),
|
|
87
|
+
email: 'anewemail@example.com',
|
|
88
|
+
}),
|
|
89
|
+
});
|
|
90
|
+
arr.addPut(put);
|
|
91
|
+
|
|
92
|
+
const request = Request.buildJson('PATCH', baseUrl, organization.getApiHost(), arr);
|
|
93
|
+
request.headers.authorization = 'Bearer ' + token.accessToken;
|
|
94
|
+
const response = await testServer.test(endpoint, request);
|
|
95
|
+
expect(response.status).toBe(200);
|
|
96
|
+
|
|
97
|
+
// Check id of the returned memebr matches the existing member
|
|
98
|
+
expect(response.body.members.length).toBe(1);
|
|
99
|
+
expect(response.body.members[0].id).toBe(existingMember.id);
|
|
100
|
+
|
|
101
|
+
// Check data matches the original data + changes from the put
|
|
102
|
+
const member = response.body.members[0];
|
|
103
|
+
expect(member.details.firstName).toBe(firstName);
|
|
104
|
+
expect(member.details.lastName).toBe(lastName);
|
|
105
|
+
expect(member.details.birthDay).toEqual(existingMember.details.birthDay);
|
|
106
|
+
expect(member.details.email).toBe('anewemail@example.com'); // this has been merged
|
|
107
|
+
expect(member.details.alternativeEmails).toHaveLength(0);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test('A duplicate member with existing registrations returns those registrations after a merge', async () => {
|
|
111
|
+
const organization = await new OrganizationFactory({ }).create();
|
|
112
|
+
const user = await new UserFactory({
|
|
113
|
+
permissions: Permissions.create({ level: PermissionLevel.Full }),
|
|
114
|
+
organization, // since we are in platform mode, this will only set the permissions for this organization
|
|
115
|
+
}).create();
|
|
116
|
+
|
|
117
|
+
const details = MemberDetails.create({
|
|
118
|
+
firstName,
|
|
119
|
+
lastName,
|
|
120
|
+
securityCode: 'ABC-123',
|
|
121
|
+
email: 'original@example.com',
|
|
122
|
+
parents: [
|
|
123
|
+
Parent.create({
|
|
124
|
+
firstName: 'Jane',
|
|
125
|
+
lastName: 'Doe',
|
|
126
|
+
email: 'jane.doe@example.com',
|
|
127
|
+
}),
|
|
128
|
+
],
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
const existingMember = await new MemberFactory({
|
|
132
|
+
birthDay,
|
|
133
|
+
details,
|
|
134
|
+
}).create();
|
|
135
|
+
|
|
136
|
+
// Create a registration for this member
|
|
137
|
+
const group = await new GroupFactory({ organization }).create();
|
|
138
|
+
const registration = await new RegistrationFactory({
|
|
139
|
+
member: existingMember,
|
|
140
|
+
group,
|
|
141
|
+
}).create();
|
|
142
|
+
|
|
143
|
+
const token = await Token.createToken(user);
|
|
144
|
+
|
|
145
|
+
const arr: Body = new PatchableArray();
|
|
146
|
+
const put = MemberWithRegistrationsBlob.create({
|
|
147
|
+
details: MemberDetails.create({
|
|
148
|
+
firstName,
|
|
149
|
+
lastName,
|
|
150
|
+
birthDay: new Date(existingMember.details.birthDay!.getTime() + 1),
|
|
151
|
+
securityCode: existingMember.details.securityCode,
|
|
152
|
+
email: 'anewemail@example.com',
|
|
153
|
+
}),
|
|
154
|
+
});
|
|
155
|
+
arr.addPut(put);
|
|
156
|
+
|
|
157
|
+
const request = Request.buildJson('PATCH', baseUrl, organization.getApiHost(), arr);
|
|
158
|
+
request.headers.authorization = 'Bearer ' + token.accessToken;
|
|
159
|
+
const response = await testServer.test(endpoint, request);
|
|
160
|
+
expect(response.status).toBe(200);
|
|
161
|
+
|
|
162
|
+
// Check id of the returned memebr matches the existing member
|
|
163
|
+
expect(response.body.members.length).toBe(1);
|
|
164
|
+
expect(response.body.members[0].id).toBe(existingMember.id);
|
|
165
|
+
|
|
166
|
+
// Check data matches the original data + changes from the put
|
|
167
|
+
const member = response.body.members[0];
|
|
168
|
+
expect(member.details.firstName).toBe(firstName);
|
|
169
|
+
expect(member.details.lastName).toBe(lastName);
|
|
170
|
+
expect(member.details.birthDay).toEqual(existingMember.details.birthDay);
|
|
171
|
+
expect(member.details.email).toBe('original@example.com'); // this has been merged
|
|
172
|
+
expect(member.details.alternativeEmails).toEqual(['anewemail@example.com']); // this has been merged
|
|
173
|
+
|
|
174
|
+
// Check the registration is still there
|
|
175
|
+
expect(member.registrations.length).toBe(1);
|
|
176
|
+
expect(member.registrations[0].id).toBe(registration.id);
|
|
177
|
+
|
|
178
|
+
// Check parent is still there
|
|
179
|
+
expect(member.details.parents.length).toBe(1);
|
|
180
|
+
expect(member.details.parents[0]).toEqual(existingMember.details.parents[0]);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
describe('Permission checking', () => {
|
|
185
|
+
test('An admin cannot edit members of a different organization', async () => {
|
|
186
|
+
const organization = await new OrganizationFactory({}).create();
|
|
187
|
+
const otherOrganization = await new OrganizationFactory({}).create();
|
|
188
|
+
|
|
189
|
+
const user = await new UserFactory({
|
|
190
|
+
permissions: Permissions.create({
|
|
191
|
+
level: PermissionLevel.Full,
|
|
192
|
+
}),
|
|
193
|
+
organization, // since we are in platform mode, this will only set the permissions for this organization
|
|
194
|
+
}).create();
|
|
195
|
+
|
|
196
|
+
const member = await new MemberFactory({
|
|
197
|
+
firstName,
|
|
198
|
+
lastName,
|
|
199
|
+
birthDay,
|
|
200
|
+
generateData: false,
|
|
201
|
+
}).create();
|
|
202
|
+
|
|
203
|
+
// Register this member
|
|
204
|
+
await new RegistrationFactory({
|
|
205
|
+
member,
|
|
206
|
+
organization: otherOrganization,
|
|
207
|
+
}).create();
|
|
208
|
+
|
|
209
|
+
const token = await Token.createToken(user);
|
|
210
|
+
|
|
211
|
+
const arr: Body = new PatchableArray();
|
|
212
|
+
const patch = MemberWithRegistrationsBlob.patch({
|
|
213
|
+
id: member.id,
|
|
214
|
+
details: MemberDetails.patch({
|
|
215
|
+
firstName: 'Changed',
|
|
216
|
+
}),
|
|
217
|
+
});
|
|
218
|
+
arr.addPatch(patch);
|
|
219
|
+
|
|
220
|
+
const request = Request.buildJson('PATCH', baseUrl, organization.getApiHost(), arr);
|
|
221
|
+
request.headers.authorization = 'Bearer ' + token.accessToken;
|
|
222
|
+
await expect(testServer.test(endpoint, request)).rejects.toThrow(errorWithCode('not_found'));
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
test('An admin can edit members registered in its own organization', async () => {
|
|
226
|
+
const organization = await new OrganizationFactory({}).create();
|
|
227
|
+
|
|
228
|
+
const user = await new UserFactory({
|
|
229
|
+
permissions: Permissions.create({
|
|
230
|
+
level: PermissionLevel.Full,
|
|
231
|
+
}),
|
|
232
|
+
organization, // since we are in platform mode, this will only set the permissions for this organization
|
|
233
|
+
}).create();
|
|
234
|
+
|
|
235
|
+
const member = await new MemberFactory({
|
|
236
|
+
firstName,
|
|
237
|
+
lastName,
|
|
238
|
+
birthDay,
|
|
239
|
+
generateData: false,
|
|
240
|
+
}).create();
|
|
241
|
+
|
|
242
|
+
// Register this member
|
|
243
|
+
await new RegistrationFactory({
|
|
244
|
+
member,
|
|
245
|
+
organization,
|
|
246
|
+
}).create();
|
|
247
|
+
|
|
248
|
+
const token = await Token.createToken(user);
|
|
249
|
+
|
|
250
|
+
const arr: Body = new PatchableArray();
|
|
251
|
+
const patch = MemberWithRegistrationsBlob.patch({
|
|
252
|
+
id: member.id,
|
|
253
|
+
details: MemberDetails.patch({
|
|
254
|
+
firstName: 'Changed',
|
|
255
|
+
}),
|
|
256
|
+
});
|
|
257
|
+
arr.addPatch(patch);
|
|
258
|
+
|
|
259
|
+
const request = Request.buildJson('PATCH', baseUrl, organization.getApiHost(), arr);
|
|
260
|
+
request.headers.authorization = 'Bearer ' + token.accessToken;
|
|
261
|
+
const response = await testServer.test(endpoint, request);
|
|
262
|
+
|
|
263
|
+
// Check returned
|
|
264
|
+
expect(response.status).toBe(200);
|
|
265
|
+
expect(response.body.members.length).toBe(1);
|
|
266
|
+
const memberStruct = response.body.members[0];
|
|
267
|
+
expect(memberStruct.details).toMatchObject({
|
|
268
|
+
firstName: 'Changed',
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
test('A full platform admin can edit members without registrations', async () => {
|
|
273
|
+
const organization = await new OrganizationFactory({}).create();
|
|
274
|
+
|
|
275
|
+
const user = await new UserFactory({
|
|
276
|
+
globalPermissions: Permissions.create({
|
|
277
|
+
level: PermissionLevel.Full,
|
|
278
|
+
}),
|
|
279
|
+
}).create();
|
|
280
|
+
|
|
281
|
+
const member = await new MemberFactory({
|
|
282
|
+
firstName,
|
|
283
|
+
lastName,
|
|
284
|
+
birthDay,
|
|
285
|
+
generateData: false,
|
|
286
|
+
}).create();
|
|
287
|
+
|
|
288
|
+
const token = await Token.createToken(user);
|
|
289
|
+
|
|
290
|
+
const arr: Body = new PatchableArray();
|
|
291
|
+
const patch = MemberWithRegistrationsBlob.patch({
|
|
292
|
+
id: member.id,
|
|
293
|
+
details: MemberDetails.patch({
|
|
294
|
+
firstName: 'Changed',
|
|
295
|
+
}),
|
|
296
|
+
});
|
|
297
|
+
arr.addPatch(patch);
|
|
298
|
+
|
|
299
|
+
const request = Request.buildJson('PATCH', baseUrl, organization.getApiHost(), arr);
|
|
300
|
+
request.headers.authorization = 'Bearer ' + token.accessToken;
|
|
301
|
+
const response = await testServer.test(endpoint, request);
|
|
302
|
+
|
|
303
|
+
// Check returned
|
|
304
|
+
expect(response.status).toBe(200);
|
|
305
|
+
expect(response.body.members.length).toBe(1);
|
|
306
|
+
const memberStruct = response.body.members[0];
|
|
307
|
+
expect(memberStruct.details).toMatchObject({
|
|
308
|
+
firstName: 'Changed',
|
|
309
|
+
});
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
test('[Regression] A platform admin with all tag access can edit members without registrations', async () => {
|
|
313
|
+
const organization = await new OrganizationFactory({}).create();
|
|
314
|
+
|
|
315
|
+
const user = await new UserFactory({
|
|
316
|
+
globalPermissions: Permissions.create({
|
|
317
|
+
level: PermissionLevel.None,
|
|
318
|
+
resources: new Map([
|
|
319
|
+
// All Tags
|
|
320
|
+
[PermissionsResourceType.OrganizationTags, new Map(
|
|
321
|
+
[['', ResourcePermissions.create({ level: PermissionLevel.Full })]],
|
|
322
|
+
)],
|
|
323
|
+
]),
|
|
324
|
+
}),
|
|
325
|
+
}).create();
|
|
326
|
+
|
|
327
|
+
const member = await new MemberFactory({
|
|
328
|
+
firstName,
|
|
329
|
+
lastName,
|
|
330
|
+
birthDay,
|
|
331
|
+
generateData: false,
|
|
332
|
+
}).create();
|
|
333
|
+
|
|
334
|
+
const token = await Token.createToken(user);
|
|
335
|
+
|
|
336
|
+
const arr: Body = new PatchableArray();
|
|
337
|
+
const patch = MemberWithRegistrationsBlob.patch({
|
|
338
|
+
id: member.id,
|
|
339
|
+
details: MemberDetails.patch({
|
|
340
|
+
firstName: 'Changed',
|
|
341
|
+
}),
|
|
342
|
+
});
|
|
343
|
+
arr.addPatch(patch);
|
|
344
|
+
|
|
345
|
+
const request = Request.buildJson('PATCH', baseUrl, organization.getApiHost(), arr);
|
|
346
|
+
request.headers.authorization = 'Bearer ' + token.accessToken;
|
|
347
|
+
const response = await testServer.test(endpoint, request);
|
|
348
|
+
|
|
349
|
+
// Check returned
|
|
350
|
+
expect(response.status).toBe(200);
|
|
351
|
+
expect(response.body.members.length).toBe(1);
|
|
352
|
+
const memberStruct = response.body.members[0];
|
|
353
|
+
expect(memberStruct.details).toMatchObject({
|
|
354
|
+
firstName: 'Changed',
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
describe('Record answers', () => {
|
|
360
|
+
test('An admin can set records of its own organization', async () => {
|
|
361
|
+
const commentsRecord = RecordSettings.create({
|
|
362
|
+
name: 'Opmerkingen',
|
|
363
|
+
externalPermissionLevel: PermissionLevel.Read, // this should be ignored since we are an admin
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
const recordCategory = RecordCategory.create({
|
|
367
|
+
name: 'Medische fiche',
|
|
368
|
+
records: [
|
|
369
|
+
commentsRecord,
|
|
370
|
+
],
|
|
371
|
+
});
|
|
372
|
+
const organization = await new OrganizationFactory({
|
|
373
|
+
meta: OrganizationMetaData.create({
|
|
374
|
+
recordsConfiguration: OrganizationRecordsConfiguration.create({
|
|
375
|
+
recordCategories: [recordCategory],
|
|
376
|
+
}),
|
|
377
|
+
}),
|
|
378
|
+
}).create();
|
|
379
|
+
|
|
380
|
+
const user = await new UserFactory({
|
|
381
|
+
permissions: Permissions.create({ level: PermissionLevel.Full }),
|
|
382
|
+
organization, // since we are in platform mode, this will only set the permissions for this organization
|
|
383
|
+
}).create();
|
|
384
|
+
|
|
385
|
+
const member = await new MemberFactory({
|
|
386
|
+
firstName,
|
|
387
|
+
lastName,
|
|
388
|
+
birthDay,
|
|
389
|
+
generateData: false,
|
|
390
|
+
}).create();
|
|
391
|
+
|
|
392
|
+
// Register this member
|
|
393
|
+
await new RegistrationFactory({
|
|
394
|
+
member,
|
|
395
|
+
organization,
|
|
396
|
+
}).create();
|
|
397
|
+
|
|
398
|
+
const token = await Token.createToken(user);
|
|
399
|
+
|
|
400
|
+
const recordAnswers = new PatchMap() as PatchAnswers;
|
|
401
|
+
|
|
402
|
+
recordAnswers.set(commentsRecord.id, RecordTextAnswer.create({
|
|
403
|
+
settings: commentsRecord,
|
|
404
|
+
value: 'Some comments',
|
|
405
|
+
}));
|
|
406
|
+
|
|
407
|
+
const arr: Body = new PatchableArray();
|
|
408
|
+
const patch = MemberWithRegistrationsBlob.patch({
|
|
409
|
+
id: member.id,
|
|
410
|
+
details: MemberDetails.patch({
|
|
411
|
+
recordAnswers,
|
|
412
|
+
}),
|
|
413
|
+
});
|
|
414
|
+
arr.addPatch(patch);
|
|
415
|
+
|
|
416
|
+
const request = Request.buildJson('PATCH', baseUrl, organization.getApiHost(), arr);
|
|
417
|
+
request.headers.authorization = 'Bearer ' + token.accessToken;
|
|
418
|
+
const response = await testServer.test(endpoint, request);
|
|
419
|
+
|
|
420
|
+
// Check returned
|
|
421
|
+
expect(response.status).toBe(200);
|
|
422
|
+
expect(response.body.members.length).toBe(1);
|
|
423
|
+
const struct = response.body.members[0];
|
|
424
|
+
expect(struct.details.recordAnswers.get(commentsRecord.id)).toMatchObject({
|
|
425
|
+
value: 'Some comments',
|
|
426
|
+
});
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
test('An admin with read only record category permission cannot set the records in that category', async () => {
|
|
430
|
+
const commentsRecord = RecordSettings.create({
|
|
431
|
+
name: 'Opmerkingen',
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
const recordCategory = RecordCategory.create({
|
|
435
|
+
name: 'Medische fiche',
|
|
436
|
+
records: [
|
|
437
|
+
commentsRecord,
|
|
438
|
+
],
|
|
439
|
+
});
|
|
440
|
+
const organization = await new OrganizationFactory({
|
|
441
|
+
meta: OrganizationMetaData.create({
|
|
442
|
+
recordsConfiguration: OrganizationRecordsConfiguration.create({
|
|
443
|
+
recordCategories: [recordCategory],
|
|
444
|
+
}),
|
|
445
|
+
}),
|
|
446
|
+
}).create();
|
|
447
|
+
|
|
448
|
+
const group = await new GroupFactory({ organization }).create();
|
|
449
|
+
|
|
450
|
+
const user = await new UserFactory({
|
|
451
|
+
permissions: Permissions.create({
|
|
452
|
+
level: PermissionLevel.None,
|
|
453
|
+
resources: new Map([
|
|
454
|
+
[PermissionsResourceType.RecordCategories, new Map([
|
|
455
|
+
[recordCategory.id, ResourcePermissions.create({ level: PermissionLevel.Read })],
|
|
456
|
+
])],
|
|
457
|
+
[PermissionsResourceType.Groups, new Map([
|
|
458
|
+
[group.id, ResourcePermissions.create({ level: PermissionLevel.Full })],
|
|
459
|
+
])],
|
|
460
|
+
]),
|
|
461
|
+
}),
|
|
462
|
+
organization, // since we are in platform mode, this will only set the permissions for this organization
|
|
463
|
+
}).create();
|
|
464
|
+
|
|
465
|
+
const member = await new MemberFactory({
|
|
466
|
+
firstName,
|
|
467
|
+
lastName,
|
|
468
|
+
birthDay,
|
|
469
|
+
generateData: false,
|
|
470
|
+
}).create();
|
|
471
|
+
|
|
472
|
+
// Register this member
|
|
473
|
+
await new RegistrationFactory({
|
|
474
|
+
member,
|
|
475
|
+
group,
|
|
476
|
+
}).create();
|
|
477
|
+
|
|
478
|
+
const token = await Token.createToken(user);
|
|
479
|
+
|
|
480
|
+
const recordAnswers = new PatchMap() as PatchAnswers;
|
|
481
|
+
|
|
482
|
+
recordAnswers.set(commentsRecord.id, RecordTextAnswer.create({
|
|
483
|
+
settings: commentsRecord,
|
|
484
|
+
value: 'Some comments',
|
|
485
|
+
}));
|
|
486
|
+
|
|
487
|
+
const arr: Body = new PatchableArray();
|
|
488
|
+
const patch = MemberWithRegistrationsBlob.patch({
|
|
489
|
+
id: member.id,
|
|
490
|
+
details: MemberDetails.patch({
|
|
491
|
+
recordAnswers,
|
|
492
|
+
}),
|
|
493
|
+
});
|
|
494
|
+
arr.addPatch(patch);
|
|
495
|
+
|
|
496
|
+
const request = Request.buildJson('PATCH', baseUrl, organization.getApiHost(), arr);
|
|
497
|
+
request.headers.authorization = 'Bearer ' + token.accessToken;
|
|
498
|
+
await expect(testServer.test(endpoint, request)).rejects.toThrow(errorWithCode('permission_denied'));
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
test('An admin without record category permission cannot set the records in that category', async () => {
|
|
502
|
+
const commentsRecord = RecordSettings.create({
|
|
503
|
+
name: 'Opmerkingen',
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
const recordCategory = RecordCategory.create({
|
|
507
|
+
name: 'Medische fiche',
|
|
508
|
+
records: [
|
|
509
|
+
commentsRecord,
|
|
510
|
+
],
|
|
511
|
+
});
|
|
512
|
+
const organization = await new OrganizationFactory({
|
|
513
|
+
meta: OrganizationMetaData.create({
|
|
514
|
+
recordsConfiguration: OrganizationRecordsConfiguration.create({
|
|
515
|
+
recordCategories: [recordCategory],
|
|
516
|
+
}),
|
|
517
|
+
}),
|
|
518
|
+
}).create();
|
|
519
|
+
|
|
520
|
+
const group = await new GroupFactory({ organization }).create();
|
|
521
|
+
|
|
522
|
+
const user = await new UserFactory({
|
|
523
|
+
permissions: Permissions.create({
|
|
524
|
+
level: PermissionLevel.None,
|
|
525
|
+
resources: new Map([
|
|
526
|
+
[PermissionsResourceType.Groups, new Map([
|
|
527
|
+
[group.id, ResourcePermissions.create({ level: PermissionLevel.Full })],
|
|
528
|
+
])],
|
|
529
|
+
]),
|
|
530
|
+
}),
|
|
531
|
+
organization, // since we are in platform mode, this will only set the permissions for this organization
|
|
532
|
+
}).create();
|
|
533
|
+
|
|
534
|
+
const member = await new MemberFactory({
|
|
535
|
+
firstName,
|
|
536
|
+
lastName,
|
|
537
|
+
birthDay,
|
|
538
|
+
generateData: false,
|
|
539
|
+
}).create();
|
|
540
|
+
|
|
541
|
+
// Register this member
|
|
542
|
+
await new RegistrationFactory({
|
|
543
|
+
member,
|
|
544
|
+
group,
|
|
545
|
+
}).create();
|
|
546
|
+
|
|
547
|
+
const token = await Token.createToken(user);
|
|
548
|
+
|
|
549
|
+
const recordAnswers = new PatchMap() as PatchAnswers;
|
|
550
|
+
|
|
551
|
+
recordAnswers.set(commentsRecord.id, RecordTextAnswer.create({
|
|
552
|
+
settings: commentsRecord,
|
|
553
|
+
value: 'Some comments',
|
|
554
|
+
}));
|
|
555
|
+
|
|
556
|
+
const arr: Body = new PatchableArray();
|
|
557
|
+
const patch = MemberWithRegistrationsBlob.patch({
|
|
558
|
+
id: member.id,
|
|
559
|
+
details: MemberDetails.patch({
|
|
560
|
+
recordAnswers,
|
|
561
|
+
}),
|
|
562
|
+
});
|
|
563
|
+
arr.addPatch(patch);
|
|
564
|
+
|
|
565
|
+
const request = Request.buildJson('PATCH', baseUrl, organization.getApiHost(), arr);
|
|
566
|
+
request.headers.authorization = 'Bearer ' + token.accessToken;
|
|
567
|
+
await expect(testServer.test(endpoint, request)).rejects.toThrow(errorWithCode('permission_denied'));
|
|
568
|
+
});
|
|
569
|
+
|
|
570
|
+
test('An admin can set records of the platform', async () => {
|
|
571
|
+
const commentsRecord = RecordSettings.create({
|
|
572
|
+
name: 'Opmerkingen',
|
|
573
|
+
});
|
|
574
|
+
|
|
575
|
+
const recordCategory = RecordCategory.create({
|
|
576
|
+
name: 'Medische fiche',
|
|
577
|
+
records: [
|
|
578
|
+
commentsRecord,
|
|
579
|
+
],
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
const platform = await Platform.getShared();
|
|
583
|
+
platform.config.recordsConfiguration.recordCategories.push(recordCategory);
|
|
584
|
+
await platform.save();
|
|
585
|
+
|
|
586
|
+
const organization = await new OrganizationFactory({}).create();
|
|
587
|
+
const group = await new GroupFactory({ organization }).create();
|
|
588
|
+
|
|
589
|
+
const user = await new UserFactory({
|
|
590
|
+
permissions: Permissions.create({
|
|
591
|
+
level: PermissionLevel.None,
|
|
592
|
+
resources: new Map([
|
|
593
|
+
[PermissionsResourceType.RecordCategories, new Map([
|
|
594
|
+
[recordCategory.id, ResourcePermissions.create({ level: PermissionLevel.Write })],
|
|
595
|
+
])],
|
|
596
|
+
[PermissionsResourceType.Groups, new Map([
|
|
597
|
+
[group.id, ResourcePermissions.create({ level: PermissionLevel.Full })],
|
|
598
|
+
])],
|
|
599
|
+
]),
|
|
600
|
+
}),
|
|
601
|
+
organization, // since we are in platform mode, this will only set the permissions for this organization
|
|
602
|
+
}).create();
|
|
603
|
+
|
|
604
|
+
const member = await new MemberFactory({
|
|
605
|
+
firstName,
|
|
606
|
+
lastName,
|
|
607
|
+
birthDay,
|
|
608
|
+
generateData: false,
|
|
609
|
+
}).create();
|
|
610
|
+
|
|
611
|
+
// Register this member
|
|
612
|
+
await new RegistrationFactory({
|
|
613
|
+
member,
|
|
614
|
+
group,
|
|
615
|
+
}).create();
|
|
616
|
+
|
|
617
|
+
const token = await Token.createToken(user);
|
|
618
|
+
|
|
619
|
+
const recordAnswers = new PatchMap() as PatchAnswers;
|
|
620
|
+
|
|
621
|
+
recordAnswers.set(commentsRecord.id, RecordTextAnswer.create({
|
|
622
|
+
settings: commentsRecord,
|
|
623
|
+
value: 'Some comments',
|
|
624
|
+
}));
|
|
625
|
+
|
|
626
|
+
const arr: Body = new PatchableArray();
|
|
627
|
+
const patch = MemberWithRegistrationsBlob.patch({
|
|
628
|
+
id: member.id,
|
|
629
|
+
details: MemberDetails.patch({
|
|
630
|
+
recordAnswers,
|
|
631
|
+
}),
|
|
632
|
+
});
|
|
633
|
+
arr.addPatch(patch);
|
|
634
|
+
|
|
635
|
+
const request = Request.buildJson('PATCH', baseUrl, organization.getApiHost(), arr);
|
|
636
|
+
request.headers.authorization = 'Bearer ' + token.accessToken;
|
|
637
|
+
const response = await testServer.test(endpoint, request);
|
|
638
|
+
|
|
639
|
+
// Check returned
|
|
640
|
+
expect(response.status).toBe(200);
|
|
641
|
+
expect(response.body.members.length).toBe(1);
|
|
642
|
+
const struct = response.body.members[0];
|
|
643
|
+
expect(struct.details.recordAnswers.get(commentsRecord.id)).toMatchObject({
|
|
644
|
+
value: 'Some comments',
|
|
645
|
+
});
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
test('[Regression] A platform admin with tag-access to an organization can change platform records', async () => {
|
|
649
|
+
const commentsRecord = RecordSettings.create({
|
|
650
|
+
name: 'Opmerkingen',
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
const recordCategory = RecordCategory.create({
|
|
654
|
+
name: 'Medische fiche',
|
|
655
|
+
records: [
|
|
656
|
+
commentsRecord,
|
|
657
|
+
],
|
|
658
|
+
});
|
|
659
|
+
|
|
660
|
+
const platform = await Platform.getShared();
|
|
661
|
+
platform.config.recordsConfiguration.recordCategories.push(recordCategory);
|
|
662
|
+
await platform.save();
|
|
663
|
+
|
|
664
|
+
const tag = await new OrganizationTagFactory({}).create();
|
|
665
|
+
const organization = await new OrganizationFactory({
|
|
666
|
+
tags: [tag.id],
|
|
667
|
+
}).create();
|
|
668
|
+
const group = await new GroupFactory({ organization }).create();
|
|
669
|
+
|
|
670
|
+
const user = await new UserFactory({
|
|
671
|
+
globalPermissions: Permissions.create({
|
|
672
|
+
level: PermissionLevel.None,
|
|
673
|
+
resources: new Map([
|
|
674
|
+
[PermissionsResourceType.OrganizationTags, new Map([
|
|
675
|
+
[tag.id, ResourcePermissions.create({ level: PermissionLevel.Full })],
|
|
676
|
+
])],
|
|
677
|
+
]),
|
|
678
|
+
}),
|
|
679
|
+
organization, // since we are in platform mode, this will only set the permissions for this organization
|
|
680
|
+
}).create();
|
|
681
|
+
|
|
682
|
+
const member = await new MemberFactory({
|
|
683
|
+
firstName,
|
|
684
|
+
lastName,
|
|
685
|
+
birthDay,
|
|
686
|
+
generateData: false,
|
|
687
|
+
}).create();
|
|
688
|
+
|
|
689
|
+
// Register this member
|
|
690
|
+
await new RegistrationFactory({
|
|
691
|
+
member,
|
|
692
|
+
group,
|
|
693
|
+
}).create();
|
|
694
|
+
|
|
695
|
+
const token = await Token.createToken(user);
|
|
696
|
+
|
|
697
|
+
const recordAnswers = new PatchMap() as PatchAnswers;
|
|
698
|
+
|
|
699
|
+
recordAnswers.set(commentsRecord.id, RecordTextAnswer.create({
|
|
700
|
+
settings: commentsRecord,
|
|
701
|
+
value: 'Some comments',
|
|
702
|
+
}));
|
|
703
|
+
|
|
704
|
+
const arr: Body = new PatchableArray();
|
|
705
|
+
const patch = MemberWithRegistrationsBlob.patch({
|
|
706
|
+
id: member.id,
|
|
707
|
+
details: MemberDetails.patch({
|
|
708
|
+
recordAnswers,
|
|
709
|
+
}),
|
|
710
|
+
});
|
|
711
|
+
arr.addPatch(patch);
|
|
712
|
+
|
|
713
|
+
const request = Request.buildJson('PATCH', baseUrl, organization.getApiHost(), arr);
|
|
714
|
+
request.headers.authorization = 'Bearer ' + token.accessToken;
|
|
715
|
+
const response = await testServer.test(endpoint, request);
|
|
716
|
+
|
|
717
|
+
// Check returned
|
|
718
|
+
expect(response.status).toBe(200);
|
|
719
|
+
expect(response.body.members.length).toBe(1);
|
|
720
|
+
const struct = response.body.members[0];
|
|
721
|
+
expect(struct.details.recordAnswers.get(commentsRecord.id)).toMatchObject({
|
|
722
|
+
value: 'Some comments',
|
|
723
|
+
});
|
|
724
|
+
});
|
|
725
|
+
});
|
|
726
|
+
});
|