@liminalfunctions/framework 1.0.51 → 1.0.53

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 (48) hide show
  1. package/dist/F_Collection.d.ts +2 -0
  2. package/dist/F_Collection.js +9 -0
  3. package/dist/F_Collection.js.map +1 -1
  4. package/dist/F_Compile.js +247 -0
  5. package/dist/F_Compile.js.map +1 -1
  6. package/dist/F_Security_Models/F_SM_Role_Membership.d.ts +2 -2
  7. package/dist/F_Security_Models/F_SM_Role_Membership.js +10 -6
  8. package/dist/F_Security_Models/F_SM_Role_Membership.js.map +1 -1
  9. package/dist/code_generation/generate_client_library.d.ts +1 -0
  10. package/dist/code_generation/generate_client_library.js +37 -16
  11. package/dist/code_generation/generate_client_library.js.map +1 -1
  12. package/dist/code_generation/templates/collection.mustache +79 -1
  13. package/dist/utils/array_children_from_zod.d.ts +3 -0
  14. package/dist/utils/array_children_from_zod.js +39 -0
  15. package/dist/utils/array_children_from_zod.js.map +1 -0
  16. package/dist/utils/mongoose_from_zod.js +7 -2
  17. package/dist/utils/mongoose_from_zod.js.map +1 -1
  18. package/package.json +1 -1
  19. package/src/F_Collection.ts +14 -3
  20. package/src/F_Compile.ts +288 -16
  21. package/src/F_Security_Models/F_SM_Role_Membership.ts +12 -8
  22. package/src/code_generation/generate_client_library.ts +35 -8
  23. package/src/code_generation/templates/collection.mustache +79 -1
  24. package/src/utils/array_children_from_zod.ts +44 -0
  25. package/src/utils/mongoose_from_zod.ts +7 -3
  26. package/test/0_1_mongoose_from_zod.test.ts +16 -10
  27. package/test/0_6_array_children.test.ts +127 -0
  28. package/test/1_0_basic_server.test.ts +107 -2
  29. package/test/1_1_security_ownership.test.ts +186 -6
  30. package/test/1_2_role_membership.test.ts +329 -9
  31. package/test/2_1_client_library_generation.test.ts +125 -1
  32. package/test/tmp/dist/Brief_News_Category.js.map +1 -1
  33. package/test/tmp/dist/Client.js.map +1 -1
  34. package/test/tmp/dist/Institution.js.map +1 -1
  35. package/test/tmp/dist/Project.d.ts +20 -0
  36. package/test/tmp/dist/Project.js +63 -0
  37. package/test/tmp/dist/Project.js.map +1 -1
  38. package/test/tmp/dist/types/project.d.ts +4 -0
  39. package/test/tmp/dist/types/project_post.d.ts +4 -0
  40. package/test/tmp/dist/types/project_put.d.ts +4 -0
  41. package/test/tmp/package-lock.json +111 -111
  42. package/test/tmp/src/Brief_News_Category.ts +3 -1
  43. package/test/tmp/src/Client.ts +3 -1
  44. package/test/tmp/src/Institution.ts +3 -1
  45. package/test/tmp/src/Project.ts +73 -1
  46. package/test/tmp/src/types/project.ts +4 -0
  47. package/test/tmp/src/types/project_post.ts +4 -0
  48. package/test/tmp/src/types/project_put.ts +4 -0
@@ -30,7 +30,12 @@ describe('Security Model Ownership', function () {
30
30
  _id: z_mongodb_id,
31
31
  user_id: z_mongodb_id,
32
32
  name: z.string(),
33
- email: z.string()
33
+ email: z.string(),
34
+ nicknames: z.array(z.object({
35
+ _id: z_mongodb_id,
36
+ server_key: z.string(),
37
+ name: z.string()
38
+ }))
34
39
  })
35
40
 
36
41
  // set up schema: user
@@ -99,7 +104,8 @@ describe('Security Model Ownership', function () {
99
104
  let user_display = await collection_user_display.mongoose_model.create({
100
105
  user_id: user._id,
101
106
  name: 'steve',
102
- email: 'steve@example.com'
107
+ email: 'steve@example.com',
108
+ nicknames: [],
103
109
  })
104
110
 
105
111
  return { user, user_display}
@@ -157,7 +163,8 @@ describe('Security Model Ownership', function () {
157
163
  user_displays.push(await collection_user_display.mongoose_model.create({
158
164
  user_id: user._id,
159
165
  name: 'steve',
160
- email: 'steve@example.com'
166
+ email: 'steve@example.com',
167
+ nicknames: [],
161
168
  }))
162
169
  }
163
170
 
@@ -185,7 +192,8 @@ describe('Security Model Ownership', function () {
185
192
  user_displays.push(await collection_user_display.mongoose_model.create({
186
193
  user_id: user._id,
187
194
  name: 'steve',
188
- email: 'steve@example.com'
195
+ email: 'steve@example.com',
196
+ nicknames: [],
189
197
  }))
190
198
  }
191
199
 
@@ -261,7 +269,8 @@ describe('Security Model Ownership', function () {
261
269
  json: {
262
270
  user_id: user._id,
263
271
  name: 'grogfurd',
264
- email: 'grogfurd@example.com'
272
+ email: 'grogfurd@example.com',
273
+ nicknames: [],
265
274
  }
266
275
  }).json();
267
276
 
@@ -284,7 +293,8 @@ describe('Security Model Ownership', function () {
284
293
  json: {
285
294
  user_id: user._id,
286
295
  name: 'grogfurd',
287
- email: 'grogfurd@example.com'
296
+ email: 'grogfurd@example.com',
297
+ nicknames: []
288
298
  }
289
299
  }).json();
290
300
  }, {
@@ -330,4 +340,174 @@ describe('Security Model Ownership', function () {
330
340
  message: 'Response code 403 (Forbidden)'
331
341
  })
332
342
  });
343
+
344
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
345
+ ///////////////////////////////////////////////////////////// ARRAY OPERATIONS //////////////////////////////////////////////////////////////////////////
346
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
347
+
348
+
349
+ it(`should authorize a POST operation on a child array`, async function () {
350
+ let { user, user_display } = await generate_user_and_display();
351
+
352
+ let results = await got.post(`http://localhost:${port}/api/user_display/${user_display._id}/nicknames`, {
353
+ headers: {
354
+ authorization: 'steve'
355
+ },
356
+ json: {
357
+ server_key: 'best_server',
358
+ name: 'steve the mighty'
359
+ }
360
+ }).json();
361
+
362
+ //@ts-ignore
363
+ assert.deepEqual(JSON.parse(JSON.stringify(await collection_user_display.mongoose_model.findById(user_display._id))), results.data);
364
+ assert.deepEqual(JSON.parse(JSON.stringify((await collection_user_display.mongoose_model.findById(user_display._id)))).nicknames.length, 1);
365
+ });
366
+
367
+ it(`should reject a POST operation on a child array authenticated to the wrong user`, async function () {
368
+ let { user, user_display } = await generate_user_and_display();
369
+
370
+ let user_2 = await collection_user.mongoose_model.create({
371
+ auth_id: 'sharon'
372
+ });
373
+
374
+ await assert.rejects(async () => {
375
+ let results = await got.post(`http://localhost:${port}/api/user_display/${user_display._id}/nicknames`, {
376
+ headers: {
377
+ authorization: 'sharon'
378
+ },
379
+ json: {
380
+ server_key: 'best_server',
381
+ name: 'steve the mighty'
382
+ }
383
+ }).json();
384
+ }, {
385
+ message: 'Response code 403 (Forbidden)'
386
+ })
387
+ });
388
+
389
+ it(`should authorize a PUT operation on a child array`, async function () {
390
+ let { user, user_display } = await generate_user_and_display();
391
+ await collection_user_display.mongoose_model.findByIdAndUpdate(user_display._id, {
392
+ $push: {
393
+ nicknames: {
394
+ server_key: 'best_server',
395
+ name: 'steve the mighty'
396
+ }
397
+ }
398
+ });
399
+ //@ts-ignore
400
+ user_display = await collection_user_display.mongoose_model.findById(user_display._id);
401
+
402
+ let nickname_id = user_display.nicknames[0]._id + '';
403
+
404
+ let results = await got.put(`http://localhost:${port}/api/user_display/${user_display._id}/nicknames/${nickname_id}`, {
405
+ headers: {
406
+ authorization: 'steve'
407
+ },
408
+ json: {
409
+ _id: nickname_id,
410
+ server_key: 'best_server',
411
+ name: 'ubersteve'
412
+ }
413
+ }).json();
414
+
415
+ //@ts-ignore
416
+ assert.deepEqual('ubersteve', results.data.nicknames[0].name);
417
+ //@ts-ignore
418
+ assert.deepEqual(JSON.parse(JSON.stringify(await collection_user_display.mongoose_model.findById(user_display._id))), JSON.parse(JSON.stringify(results.data)));
419
+ });
420
+
421
+ it(`should reject a PUT operation on a child array authenticated to the wrong user`, async function () {
422
+ let { user, user_display } = await generate_user_and_display();
423
+ await collection_user_display.mongoose_model.findByIdAndUpdate(user_display._id, {
424
+ $push: {
425
+ nicknames: {
426
+ server_key: 'best_server',
427
+ name: 'steve the mighty'
428
+ }
429
+ }
430
+ });
431
+
432
+ let user_2 = await collection_user.mongoose_model.create({
433
+ auth_id: 'sharon'
434
+ });
435
+
436
+
437
+ //@ts-ignore
438
+ user_display = await collection_user_display.mongoose_model.findById(user_display._id);
439
+
440
+ let nickname_id = user_display.nicknames[0]._id + '';
441
+
442
+ await assert.rejects(async () => {
443
+ let results = await got.put(`http://localhost:${port}/api/user_display/${user_display._id}/nicknames/${nickname_id}`, {
444
+ headers: {
445
+ authorization: 'sharon'
446
+ },
447
+ json: {
448
+ _id: nickname_id,
449
+ server_key: 'best_server',
450
+ name: 'ubersteve'
451
+ }
452
+ }).json();
453
+ }, {
454
+ message: 'Response code 403 (Forbidden)'
455
+ })
456
+ });
457
+
458
+ it(`should authorize a DELETE operation on a child array`, async function () {
459
+ let { user, user_display } = await generate_user_and_display();
460
+ await collection_user_display.mongoose_model.findByIdAndUpdate(user_display._id, {
461
+ $push: {
462
+ nicknames: {
463
+ server_key: 'best_server',
464
+ name: 'steve the mighty'
465
+ }
466
+ }
467
+ });
468
+ //@ts-ignore
469
+ user_display = await collection_user_display.mongoose_model.findById(user_display._id);
470
+ let nickname_id = user_display.nicknames[0]._id + '';
471
+
472
+ let results = await got.delete(`http://localhost:${port}/api/user_display/${user_display._id}/nicknames/${nickname_id}`, {
473
+ headers: {
474
+ authorization: 'steve'
475
+ },
476
+ }).json();
477
+
478
+ //@ts-ignore
479
+ assert.deepEqual(0, results.data.nicknames.length);
480
+ //@ts-ignore
481
+ assert.deepEqual(JSON.parse(JSON.stringify(await collection_user_display.mongoose_model.findById(user_display._id))), JSON.parse(JSON.stringify(results.data)));
482
+ });
483
+
484
+ it(`should reject a DELETE operation authenticated to the wrong user`, async function () {
485
+ let { user, user_display } = await generate_user_and_display();
486
+
487
+ let user_2 = await collection_user.mongoose_model.create({
488
+ auth_id: 'sharon'
489
+ });
490
+
491
+ await collection_user_display.mongoose_model.findByIdAndUpdate(user_display._id, {
492
+ $push: {
493
+ nicknames: {
494
+ server_key: 'best_server',
495
+ name: 'steve the mighty'
496
+ }
497
+ }
498
+ });
499
+ //@ts-ignore
500
+ user_display = await collection_user_display.mongoose_model.findById(user_display._id);
501
+ let nickname_id = user_display.nicknames[0]._id + '';
502
+
503
+ await assert.rejects(async () => {
504
+ let results = await got.delete(`http://localhost:${port}/api/user_display/${user_display._id}/nicknames/${nickname_id}`, {
505
+ headers: {
506
+ authorization: 'sharon'
507
+ },
508
+ }).json();
509
+ }, {
510
+ message: 'Response code 403 (Forbidden)'
511
+ })
512
+ });
333
513
  });
@@ -8,7 +8,7 @@ import { F_SM_Open_Access } from '../dist/F_Security_Models/F_SM_Open_Access.js'
8
8
  import { F_SM_Role_Membership } from '../dist/F_Security_Models/F_SM_Role_Membership.js'
9
9
  import { F_Security_Model } from '../dist/F_Security_Models/F_Security_Model.js'
10
10
  import { Cache } from '../dist/utils/cache.js'
11
- import { z, ZodBoolean, ZodDate, ZodNumber, ZodString } from 'zod'
11
+ import { z, ZodAny, ZodBoolean, ZodDate, ZodNumber, ZodString } from 'zod'
12
12
 
13
13
  import got from 'got'
14
14
  import express, { Express, Request, Response, NextFunction } from 'express'
@@ -38,6 +38,10 @@ describe.skip('Security Model Role Membership', function () {
38
38
  institution_id: z_mongodb_id,
39
39
  client_id: z_mongodb_id,
40
40
  name: z.string(),
41
+ steps: z.array(z.object({
42
+ _id: z_mongodb_id,
43
+ name: z.string()
44
+ }))
41
45
  });
42
46
  let validate_user = z.object({
43
47
  _id: z_mongodb_id,
@@ -255,25 +259,29 @@ describe.skip('Security Model Role Membership', function () {
255
259
  let steve_project = await collection_project.mongoose_model.create({
256
260
  institution_id: steve_institution._id,
257
261
  client_id: steve_client,
258
- name: 'steve project'
262
+ name: 'steve project',
263
+ steps: [],
259
264
  })
260
265
 
261
266
  let joe_project = await collection_project.mongoose_model.create({
262
267
  institution_id: steve_institution._id,
263
268
  client_id: joe_client,
264
- name: 'joe project'
269
+ name: 'joe project',
270
+ steps: [],
265
271
  })
266
272
 
267
273
  let nathan_project = await collection_project.mongoose_model.create({
268
274
  institution_id: edwin_institution._id,
269
275
  client_id: nathan_client,
270
- name: 'nathan project'
276
+ name: 'nathan project',
277
+ steps: [],
271
278
  })
272
279
 
273
280
  let edna_project = await collection_project.mongoose_model.create({
274
281
  institution_id: edwin_institution._id,
275
282
  client_id: edna_client,
276
- name: 'edna project'
283
+ name: 'edna project',
284
+ steps: [],
277
285
  })
278
286
 
279
287
  let access_role_steve_institution_grants_project = await collection_role.mongoose_model.create({
@@ -460,7 +468,8 @@ describe.skip('Security Model Role Membership', function () {
460
468
  projects.push(await collection_project.mongoose_model.create({
461
469
  institution_id: steve_institution._id,
462
470
  client_id: steve_client,
463
- name: `additional project ${q}`
471
+ name: `additional project ${q}`,
472
+ steps: [],
464
473
  }))
465
474
  }
466
475
 
@@ -482,7 +491,8 @@ describe.skip('Security Model Role Membership', function () {
482
491
  projects.push(await collection_project.mongoose_model.create({
483
492
  institution_id: edwin_institution._id,
484
493
  client_id: nathan_client,
485
- name: `additional project ${q}`
494
+ name: `additional project ${q}`,
495
+ steps: [],
486
496
  }))
487
497
  }
488
498
 
@@ -504,7 +514,8 @@ describe.skip('Security Model Role Membership', function () {
504
514
  projects.push(await collection_project.mongoose_model.create({
505
515
  institution_id: edwin_institution._id,
506
516
  client_id: edna_client,
507
- name: `additional project ${q}`
517
+ name: `additional project ${q}`,
518
+ steps: [],
508
519
  }))
509
520
  }
510
521
 
@@ -526,7 +537,8 @@ describe.skip('Security Model Role Membership', function () {
526
537
  projects.push(await collection_project.mongoose_model.create({
527
538
  institution_id: steve_institution._id,
528
539
  client_id: steve_client,
529
- name: `additional project ${q}`
540
+ name: `additional project ${q}`,
541
+ steps: [],
530
542
  }))
531
543
  }
532
544
 
@@ -631,6 +643,7 @@ describe.skip('Security Model Role Membership', function () {
631
643
  name: 'Flammable Project',
632
644
  institution_id: steve_institution._id,
633
645
  client_id: steve_client._id,
646
+ steps: [],
634
647
  }
635
648
  }).json();
636
649
 
@@ -649,6 +662,7 @@ describe.skip('Security Model Role Membership', function () {
649
662
  name: 'Flammable Project',
650
663
  institution_id: edwin_institution._id,
651
664
  client_id: nathan_client._id,
665
+ steps: [],
652
666
  }
653
667
  }).json();
654
668
 
@@ -668,6 +682,7 @@ describe.skip('Security Model Role Membership', function () {
668
682
  name: 'Flammable Project',
669
683
  institution_id: edwin_institution._id,
670
684
  client_id: edna_client._id,
685
+ steps: [],
671
686
  }
672
687
  }).json();
673
688
  },
@@ -752,4 +767,309 @@ describe.skip('Security Model Role Membership', function () {
752
767
  },
753
768
  { message: 'Response code 403 (Forbidden)' })
754
769
  });
770
+
771
+
772
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
773
+ ///////////////////////////////////////////////////////////// ARRAY OPERATIONS //////////////////////////////////////////////////////////////////////////
774
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
775
+
776
+ it(`should authorize a basic POST operation on a document's array children where the user has a T1 role membership`, async function () {
777
+ let { steve_institution, steve_client, steve_project } = await generate_test_setup();
778
+
779
+ let results = await got.post(`http://localhost:${port}/api/institution/${steve_institution._id}/client/${steve_client._id}/project/${steve_project._id}/steps`, {
780
+ headers: {
781
+ authorization: 'steve'
782
+ },
783
+ json: {
784
+ name: 'Fancy Step'
785
+ }
786
+ }).json();
787
+
788
+ //@ts-ignore
789
+ assert.deepEqual(JSON.parse(JSON.stringify(await collection_project.mongoose_model.findById(steve_project._id))), results.data);
790
+ assert.equal((await collection_project.mongoose_model.findById(steve_project._id))?.steps.length, 1)
791
+ });
792
+
793
+ it(`should authorize a basic PUT operation on a document's array children where the user has a T1 role membership`, async function () {
794
+ let { steve_institution, steve_client, steve_project } = await generate_test_setup();
795
+
796
+ //@ts-ignore
797
+ steve_project = await collection_project.mongoose_model.findByIdAndUpdate(steve_project._id, {
798
+ $push: {
799
+ steps: {
800
+ name: 'Fancy Step'
801
+ }
802
+ }
803
+ }, {new: true}).lean();
804
+ let step_id = steve_project.steps[0]._id;
805
+
806
+ let results = await got.put(`http://localhost:${port}/api/institution/${steve_institution._id}/client/${steve_client._id}/project/${steve_project._id}/steps/${step_id}`, {
807
+ headers: {
808
+ authorization: 'steve'
809
+ },
810
+ json: {
811
+ _id: step_id,
812
+ name: 'Somber Step'
813
+ }
814
+ }).json();
815
+
816
+ //@ts-ignore
817
+ assert.deepEqual(JSON.parse(JSON.stringify(await collection_project.mongoose_model.findById(steve_project._id))), results.data);
818
+ assert.equal((await collection_project.mongoose_model.findById(steve_project._id))?.steps[0].name, 'Somber Step')
819
+ });
820
+
821
+ it(`should authorize a basic DELETE operation on a document's array children where the user has a T1 role membership`, async function () {
822
+ let { steve_institution, steve_client, steve_project } = await generate_test_setup();
823
+
824
+ //@ts-ignore
825
+ steve_project = await collection_project.mongoose_model.findByIdAndUpdate(steve_project._id, {
826
+ $push: {
827
+ steps: {
828
+ name: 'Fancy Step'
829
+ }
830
+ }
831
+ }, {new: true}).lean();
832
+ let step_id = steve_project.steps[0]._id;
833
+
834
+ let results = await got.delete(`http://localhost:${port}/api/institution/${steve_institution._id}/client/${steve_client._id}/project/${steve_project._id}/steps/${step_id}`, {
835
+ headers: {
836
+ authorization: 'steve'
837
+ }
838
+ }).json();
839
+
840
+ //@ts-ignore
841
+ assert.deepEqual(JSON.parse(JSON.stringify(await collection_project.mongoose_model.findById(steve_project._id))), results.data);
842
+ assert.equal((await collection_project.mongoose_model.findById(steve_project._id))?.steps.length, 0)
843
+ });
844
+
845
+ it(`should authorize a basic POST operation on a document's array children where the user has a T2 role membership`, async function () {
846
+ let { edwin_institution, nathan_client, nathan_project } = await generate_test_setup();
847
+
848
+ let results = await got.post(`http://localhost:${port}/api/institution/${edwin_institution._id}/client/${nathan_client._id}/project/${nathan_project._id}/steps`, {
849
+ headers: {
850
+ authorization: 'steve'
851
+ },
852
+ json: {
853
+ name: 'Fancy Step'
854
+ }
855
+ }).json();
856
+
857
+ //@ts-ignore
858
+ assert.deepEqual(JSON.parse(JSON.stringify(await collection_project.mongoose_model.findById(nathan_project._id))), results.data);
859
+ assert.equal((await collection_project.mongoose_model.findById(nathan_project._id))?.steps.length, 1)
860
+ });
861
+
862
+ it(`should authorize a basic PUT operation on a document's array children where the user has a T2 role membership`, async function () {
863
+ let { edwin_institution, nathan_client, nathan_project } = await generate_test_setup();
864
+
865
+ //@ts-ignore
866
+ nathan_project = await collection_project.mongoose_model.findByIdAndUpdate(nathan_project._id, {
867
+ $push: {
868
+ steps: {
869
+ name: 'Fancy Step'
870
+ }
871
+ }
872
+ }, {new: true}).lean();
873
+ let step_id = nathan_project.steps[0]._id;
874
+
875
+ let results = await got.put(`http://localhost:${port}/api/institution/${edwin_institution._id}/client/${nathan_client._id}/project/${nathan_project._id}/steps/${step_id}`, {
876
+ headers: {
877
+ authorization: 'steve'
878
+ },
879
+ json: {
880
+ _id: step_id,
881
+ name: 'Somber Step'
882
+ }
883
+ }).json();
884
+
885
+ //@ts-ignore
886
+ assert.deepEqual(JSON.parse(JSON.stringify(await collection_project.mongoose_model.findById(nathan_project._id))), results.data);
887
+ assert.equal((await collection_project.mongoose_model.findById(nathan_project._id))?.steps[0].name, 'Somber Step')
888
+ });
889
+
890
+ it(`should authorize a basic DELETE operation on a document's array children where the user has a T2 role membership`, async function () {
891
+ let { edwin_institution, nathan_client, nathan_project } = await generate_test_setup();
892
+
893
+ //@ts-ignore
894
+ nathan_project = await collection_project.mongoose_model.findByIdAndUpdate(nathan_project._id, {
895
+ $push: {
896
+ steps: {
897
+ name: 'Fancy Step'
898
+ }
899
+ }
900
+ }, {new: true}).lean();
901
+ let step_id = nathan_project.steps[0]._id;
902
+
903
+ let results = await got.delete(`http://localhost:${port}/api/institution/${edwin_institution._id}/client/${nathan_client._id}/project/${nathan_project._id}/steps/${step_id}`, {
904
+ headers: {
905
+ authorization: 'steve'
906
+ }
907
+ }).json();
908
+
909
+ //@ts-ignore
910
+ assert.deepEqual(JSON.parse(JSON.stringify(await collection_project.mongoose_model.findById(nathan_project._id))), results.data);
911
+ assert.equal((await collection_project.mongoose_model.findById(nathan_project._id))?.steps.length, 0)
912
+ });
913
+
914
+ it(`should reject a basic POST operation on a document's array children where the user has a role membership without permission`, async function () {
915
+ let { edwin_institution, edna_client, edna_project } = await generate_test_setup();
916
+
917
+ await assert.rejects(async () => {
918
+ let results = await got.post(`http://localhost:${port}/api/institution/${edwin_institution._id}/client/${edna_client._id}/project/${edna_project._id}/steps`, {
919
+ headers: {
920
+ authorization: 'steve'
921
+ },
922
+ json: {
923
+ name: 'Fancy Step'
924
+ }
925
+ }).json();
926
+ },
927
+ { message: 'Response code 403 (Forbidden)' })
928
+ });
929
+
930
+ it(`should reject a basic PUT operation on a document's array children where the user has a role membership without permission`, async function () {
931
+ let { edwin_institution, edna_client, edna_project } = await generate_test_setup();
932
+
933
+ //@ts-ignore
934
+ edna_project = await collection_project.mongoose_model.findByIdAndUpdate(edna_project._id, {
935
+ $push: {
936
+ steps: {
937
+ name: 'Fancy Step'
938
+ }
939
+ }
940
+ }, {new: true}).lean();
941
+ let step_id = edna_project.steps[0]._id;
942
+
943
+ await assert.rejects(async () => {
944
+ let results = await got.put(`http://localhost:${port}/api/institution/${edwin_institution._id}/client/${edna_client._id}/project/${edna_project._id}/steps/${step_id}`, {
945
+ headers: {
946
+ authorization: 'steve'
947
+ },
948
+ json: {
949
+ _id: step_id,
950
+ name: 'Somber Step'
951
+ }
952
+ }).json();
953
+ },
954
+ { message: 'Response code 403 (Forbidden)' })
955
+ });
956
+
957
+ it(`should reject a basic DELETE operation on a document's array children where the user has a role membership without permission`, async function () {
958
+ let { edwin_institution, edna_client, edna_project } = await generate_test_setup();
959
+
960
+ //@ts-ignore
961
+ edna_project = await collection_project.mongoose_model.findByIdAndUpdate(edna_project._id, {
962
+ $push: {
963
+ steps: {
964
+ name: 'Fancy Step'
965
+ }
966
+ }
967
+ }, {new: true}).lean();
968
+ let step_id = edna_project.steps[0]._id;
969
+
970
+ await assert.rejects(async () => {
971
+ let results = await got.delete(`http://localhost:${port}/api/institution/${edwin_institution._id}/client/${edna_client._id}/project/${edna_project._id}/steps/${step_id}`, {
972
+ headers: {
973
+ authorization: 'steve'
974
+ }
975
+ }).json();
976
+ },
977
+ { message: 'Response code 403 (Forbidden)' })
978
+ });
979
+
980
+ it(`should reject a basic POST operation on a document's array children where the user has POST permission but not PUT permission`, async function () {
981
+ let { steve_institution, steve_client, steve_project } = await generate_test_setup();
982
+
983
+ let user_barnabus = await collection_user.mongoose_model.create({
984
+ auth_id: 'barnabus'
985
+ });
986
+
987
+ let access_role_steve_institution_grants_project_no_update = await collection_role.mongoose_model.create({
988
+ name: 'steve full access',
989
+ institution_id: steve_institution._id,
990
+ permissions: {
991
+ institutions: ['read', 'create', 'update', 'delete'],
992
+ clients: ['read', 'create', 'update', 'delete'],
993
+ projects: ['read', 'create', 'delete'],
994
+ roles: ['read', 'create', 'update', 'delete'],
995
+ }
996
+ });
997
+
998
+ let barnabus_institution_role_membership = await collection_institution_role_membership.mongoose_model.create({
999
+ role_id: access_role_steve_institution_grants_project_no_update._id,
1000
+ user_id: user_barnabus._id,
1001
+ institution_id: steve_institution._id,
1002
+ })
1003
+
1004
+ await assert.rejects(async () => {
1005
+ let results = await got.post(`http://localhost:${port}/api/institution/${steve_institution._id}/client/${steve_client._id}/project/${steve_project._id}/steps`, {
1006
+ headers: {
1007
+ authorization: 'barnabus'
1008
+ },
1009
+ json: {
1010
+ name: 'Fancy Step'
1011
+ }
1012
+ }).json();
1013
+ },
1014
+ { message: 'Response code 403 (Forbidden)' })
1015
+ });
1016
+
1017
+ it(`should reject a basic DELETE operation on a document's array children where the user has DELETE permission but not PUT permission`, async function () {
1018
+ let { steve_institution, steve_client, steve_project, steve_steve_institution_role_membership } = await generate_test_setup();
1019
+
1020
+ let user_barnabus = await collection_user.mongoose_model.create({
1021
+ auth_id: 'barnabus'
1022
+ });
1023
+
1024
+ let access_role_steve_institution_grants_project_no_update = await collection_role.mongoose_model.create({
1025
+ name: 'steve full access',
1026
+ institution_id: steve_institution._id,
1027
+ permissions: {
1028
+ institutions: ['read', 'create', 'update', 'delete'],
1029
+ clients: ['read', 'create', 'update', 'delete'],
1030
+ projects: ['read', 'create', 'delete'],
1031
+ roles: ['read', 'create', 'update', 'delete'],
1032
+ }
1033
+ });
1034
+
1035
+ let barnabus_institution_role_membership = await collection_institution_role_membership.mongoose_model.create({
1036
+ role_id: access_role_steve_institution_grants_project_no_update._id,
1037
+ user_id: user_barnabus._id,
1038
+ institution_id: steve_institution._id,
1039
+ })
1040
+
1041
+ let steve_new_access_role = await collection_role.mongoose_model.create({
1042
+ name: 'steve no project update',
1043
+ institution_id: steve_institution._id,
1044
+ permissions: {
1045
+ institutions: ['read', 'create', 'update', 'delete'],
1046
+ clients: ['read', 'create', 'update', 'delete'],
1047
+ projects: ['read', 'create', 'delete'],
1048
+ roles: ['read', 'create', 'update', 'delete'],
1049
+ }
1050
+ });
1051
+
1052
+ await collection_client_role_membership.mongoose_model.findByIdAndUpdate(steve_steve_institution_role_membership._id, {
1053
+ role_id: steve_new_access_role._id
1054
+ })
1055
+
1056
+ //@ts-ignore
1057
+ steve_project = await collection_project.mongoose_model.findByIdAndUpdate(steve_project._id, {
1058
+ $push: {
1059
+ steps: {
1060
+ name: 'Fancy Step'
1061
+ }
1062
+ }
1063
+ }, {new: true}).lean();
1064
+ let step_id = steve_project.steps[0]._id;
1065
+
1066
+ await assert.rejects(async () => {
1067
+ let results = await got.delete(`http://localhost:${port}/api/institution/${steve_institution._id}/client/${steve_client._id}/project/${steve_project._id}/steps/${step_id}`, {
1068
+ headers: {
1069
+ authorization: 'barnabus'
1070
+ }
1071
+ }).json();
1072
+ },
1073
+ { message: 'Response code 403 (Forbidden)' })
1074
+ });
755
1075
  });