@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.
Files changed (28) hide show
  1. package/.env.ci.json +32 -16
  2. package/index.ts +7 -0
  3. package/jest.config.cjs +17 -0
  4. package/package.json +10 -10
  5. package/src/endpoints/auth/GetUserEndpoint.test.ts +0 -10
  6. package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.test.ts +726 -0
  7. package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.ts +31 -18
  8. package/src/endpoints/global/members/shouldCheckIfMemberIsDuplicate.ts +9 -21
  9. package/src/endpoints/global/organizations/CreateOrganizationEndpoint.test.ts +1 -1
  10. package/src/endpoints/global/organizations/GetOrganizationFromDomainEndpoint.test.ts +0 -4
  11. package/src/endpoints/global/organizations/SearchOrganizationEndpoint.test.ts +0 -4
  12. package/src/endpoints/global/registration/PatchUserMembersEndpoint.test.ts +288 -8
  13. package/src/endpoints/global/registration/PatchUserMembersEndpoint.ts +8 -13
  14. package/src/endpoints/global/registration/RegisterMembersEndpoint.test.ts +7 -7
  15. package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.test.ts +2 -217
  16. package/src/endpoints/organization/dashboard/payments/PatchBalanceItemsEndpoint.ts +2 -2
  17. package/src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.ts +6 -3
  18. package/src/endpoints/organization/shared/auth/GetOrganizationEndpoint.test.ts +4 -6
  19. package/src/endpoints/organization/webshops/GetWebshopEndpoint.test.ts +2 -20
  20. package/src/helpers/AdminPermissionChecker.ts +88 -140
  21. package/src/helpers/GlobalHelper.ts +6 -1
  22. package/src/services/FileSignService.ts +3 -3
  23. package/src/services/MemberRecordStore.ts +155 -0
  24. package/src/services/PlatformMembershipService.ts +17 -8
  25. package/tests/e2e/register.test.ts +49 -21
  26. package/tests/helpers/StripeMocker.ts +7 -2
  27. package/tests/jest.global.setup.ts +6 -1
  28. 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
+ });