@stamhoofd/backend 2.81.0 → 2.83.0

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 (108) hide show
  1. package/package.json +10 -10
  2. package/src/audit-logs/GroupLogger.ts +3 -3
  3. package/src/audit-logs/MemberResponsibilityRecordLogger.ts +1 -1
  4. package/src/audit-logs/OrderLogger.ts +1 -1
  5. package/src/audit-logs/RegistrationLogger.ts +1 -1
  6. package/src/endpoints/admin/members/ChargeMembersEndpoint.ts +4 -4
  7. package/src/endpoints/admin/memberships/ChargeMembershipsEndpoint.ts +1 -1
  8. package/src/endpoints/admin/organizations/ChargeOrganizationsEndpoint.ts +5 -5
  9. package/src/endpoints/admin/organizations/GetOrganizationsEndpoint.ts +1 -1
  10. package/src/endpoints/admin/organizations/PatchOrganizationsEndpoint.ts +8 -8
  11. package/src/endpoints/auth/CreateAdminEndpoint.ts +2 -2
  12. package/src/endpoints/auth/CreateTokenEndpoint.ts +10 -10
  13. package/src/endpoints/auth/ForgotPasswordEndpoint.ts +2 -2
  14. package/src/endpoints/auth/PatchUserEndpoint.ts +9 -9
  15. package/src/endpoints/auth/SignupEndpoint.ts +2 -2
  16. package/src/endpoints/auth/VerifyEmailEndpoint.ts +3 -3
  17. package/src/endpoints/global/audit-logs/GetAuditLogsEndpoint.ts +1 -1
  18. package/src/endpoints/global/email/GetEmailAddressEndpoint.ts +1 -1
  19. package/src/endpoints/global/email/GetEmailEndpoint.ts +1 -1
  20. package/src/endpoints/global/email/ManageEmailAddressEndpoint.ts +1 -1
  21. package/src/endpoints/global/email/PatchEmailEndpoint.test.ts +139 -0
  22. package/src/endpoints/global/email/PatchEmailEndpoint.ts +30 -7
  23. package/src/endpoints/global/events/GetEventNotificationsEndpoint.ts +1 -1
  24. package/src/endpoints/global/events/PatchEventNotificationsEndpoint.test.ts +16 -35
  25. package/src/endpoints/global/events/PatchEventNotificationsEndpoint.ts +1 -1
  26. package/src/endpoints/global/events/PatchEventsEndpoint.ts +22 -16
  27. package/src/endpoints/global/files/ExportToExcelEndpoint.ts +1 -1
  28. package/src/endpoints/global/files/UploadFile.ts +14 -2
  29. package/src/endpoints/global/files/UploadImage.ts +2 -2
  30. package/src/endpoints/global/members/GetMemberFamilyEndpoint.ts +2 -2
  31. package/src/endpoints/global/members/GetMembersEndpoint.ts +1 -1
  32. package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.test.ts +19 -19
  33. package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.ts +34 -34
  34. package/src/endpoints/global/organizations/CheckRegisterCodeEndpoint.ts +1 -1
  35. package/src/endpoints/global/organizations/CreateOrganizationEndpoint.ts +5 -5
  36. package/src/endpoints/global/payments/StripeWebhookEndpoint.ts +5 -1
  37. package/src/endpoints/global/platform/GetPlatformEndpoint.test.ts +68 -0
  38. package/src/endpoints/global/platform/PatchPlatformEnpoint.ts +1 -1
  39. package/src/endpoints/global/registration/GetPaymentRegistrations.ts +2 -2
  40. package/src/endpoints/global/registration/PatchUserMembersEndpoint.test.ts +15 -17
  41. package/src/endpoints/global/registration/PatchUserMembersEndpoint.ts +4 -4
  42. package/src/endpoints/global/registration/RegisterMembersEndpoint.ts +37 -37
  43. package/src/endpoints/global/registration-periods/PatchRegistrationPeriodsEndpoint.ts +2 -2
  44. package/src/endpoints/global/webshops/GetWebshopFromDomainEndpoint.ts +2 -2
  45. package/src/endpoints/organization/dashboard/documents/GetDocumentTemplateXML.ts +1 -1
  46. package/src/endpoints/organization/dashboard/documents/PatchDocumentEndpoint.ts +5 -5
  47. package/src/endpoints/organization/dashboard/documents/PatchDocumentTemplateEndpoint.ts +2 -2
  48. package/src/endpoints/organization/dashboard/email/CheckEmailBouncesEndpoint.ts +1 -1
  49. package/src/endpoints/organization/dashboard/email-templates/PatchEmailTemplatesEndpoint.ts +3 -3
  50. package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.ts +9 -9
  51. package/src/endpoints/organization/dashboard/organization/SetOrganizationDomainEndpoint.ts +4 -4
  52. package/src/endpoints/organization/dashboard/payments/GetMemberBalanceEndpoint.ts +1 -1
  53. package/src/endpoints/organization/dashboard/payments/GetPaymentsEndpoint.ts +1 -1
  54. package/src/endpoints/organization/dashboard/payments/PatchBalanceItemsEndpoint.ts +11 -11
  55. package/src/endpoints/organization/dashboard/payments/PatchPaymentsEndpoint.ts +13 -13
  56. package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.ts +16 -16
  57. package/src/endpoints/organization/dashboard/stripe/ConnectStripeEndpoint.ts +1 -1
  58. package/src/endpoints/organization/dashboard/stripe/DeleteStripeAccountEndpoint.ts +2 -2
  59. package/src/endpoints/organization/dashboard/stripe/GetStripeAccountLinkEndpoint.ts +1 -1
  60. package/src/endpoints/organization/dashboard/stripe/GetStripeLoginLinkEndpoint.ts +1 -1
  61. package/src/endpoints/organization/dashboard/stripe/UpdateStripeAccountEndpoint.ts +1 -1
  62. package/src/endpoints/organization/dashboard/users/CreateApiUserEndpoint.test.ts +106 -0
  63. package/src/endpoints/organization/dashboard/users/CreateApiUserEndpoint.ts +16 -3
  64. package/src/endpoints/organization/dashboard/users/DeleteUserEndpoint.ts +2 -2
  65. package/src/endpoints/organization/dashboard/users/PatchApiUserEndpoint.test.ts +247 -0
  66. package/src/endpoints/{auth → organization/dashboard/users}/PatchApiUserEndpoint.ts +25 -6
  67. package/src/endpoints/organization/dashboard/webshops/CreateWebshopEndpoint.ts +4 -4
  68. package/src/endpoints/organization/dashboard/webshops/PatchDiscountCodesEndpoint.ts +2 -2
  69. package/src/endpoints/organization/dashboard/webshops/PatchWebshopEndpoint.ts +8 -8
  70. package/src/endpoints/organization/dashboard/webshops/PatchWebshopTicketsEndpoint.ts +1 -1
  71. package/src/endpoints/organization/shared/ExchangePaymentEndpoint.ts +1 -1
  72. package/src/endpoints/organization/shared/GetDocumentHtml.ts +2 -2
  73. package/src/endpoints/organization/shared/GetPaymentEndpoint.ts +1 -1
  74. package/src/endpoints/organization/shared/auth/GetOrganizationEndpoint.test.ts +5 -0
  75. package/src/endpoints/organization/webshops/CheckWebshopDiscountCodesEndpoint.ts +1 -1
  76. package/src/endpoints/organization/webshops/GetOrderByPaymentEndpoint.ts +2 -2
  77. package/src/endpoints/organization/webshops/GetOrderEndpoint.ts +1 -1
  78. package/src/endpoints/organization/webshops/GetTicketsEndpoint.ts +3 -3
  79. package/src/endpoints/organization/webshops/GetWebshopEndpoint.test.ts +6 -1
  80. package/src/endpoints/organization/webshops/GetWebshopEndpoint.ts +1 -1
  81. package/src/endpoints/organization/webshops/PlaceOrderEndpoint.ts +10 -8
  82. package/src/excel-loaders/event-notifications.ts +11 -11
  83. package/src/excel-loaders/members.ts +34 -34
  84. package/src/excel-loaders/organizations.ts +23 -23
  85. package/src/excel-loaders/payments.ts +39 -39
  86. package/src/excel-loaders/receivable-balances.ts +21 -21
  87. package/src/helpers/AddressValidator.ts +6 -6
  88. package/src/helpers/AdminPermissionChecker.ts +7 -4
  89. package/src/helpers/AuthenticatedStructures.ts +16 -8
  90. package/src/helpers/BuckarooHelper.ts +1 -1
  91. package/src/helpers/CheckSettlements.ts +1 -1
  92. package/src/helpers/Context.ts +31 -15
  93. package/src/helpers/FileCache.ts +7 -7
  94. package/src/helpers/ForwardHandler.ts +1 -1
  95. package/src/helpers/GlobalHelper.ts +6 -4
  96. package/src/helpers/MembershipCharger.ts +2 -2
  97. package/src/helpers/SetupStepUpdater.ts +1 -1
  98. package/src/helpers/StripeHelper.ts +18 -7
  99. package/src/helpers/XlsxTransformerColumnHelper.ts +18 -18
  100. package/src/services/DocumentService.ts +1 -1
  101. package/src/services/EventNotificationService.ts +1 -1
  102. package/src/services/MemberNumberService.ts +3 -3
  103. package/src/services/SSOService.ts +5 -5
  104. package/src/sql-filters/members.ts +1 -1
  105. package/tests/e2e/api-rate-limits.test.ts +188 -0
  106. package/tests/e2e/private-files.test.ts +3 -3
  107. package/tests/helpers/StripeMocker.ts +7 -1
  108. /package/src/endpoints/global/platform/{GetPlatformEnpoint.ts → GetPlatformEndpoint.ts} +0 -0
@@ -2,8 +2,8 @@ import { Database } from '@simonbackx/simple-database';
2
2
  import { PatchableArray, PatchableArrayAutoEncoder, PatchMap } from '@simonbackx/simple-encoding';
3
3
  import { Endpoint, Request } from '@simonbackx/simple-endpoints';
4
4
  import { GroupFactory, MemberFactory, OrganizationFactory, OrganizationTagFactory, Platform, RegistrationFactory, Token, UserFactory } from '@stamhoofd/models';
5
- import { Address, Country, EmergencyContact, MemberDetails, MemberWithRegistrationsBlob, OrganizationMetaData, OrganizationRecordsConfiguration, Parent, PatchAnswers, PermissionLevel, Permissions, PermissionsResourceType, RecordCategory, RecordSettings, RecordTextAnswer, ResourcePermissions, ReviewTime, ReviewTimes } from '@stamhoofd/structures';
6
- import { TestUtils } from '@stamhoofd/test-utils';
5
+ import { Address, Country, EmergencyContact, MemberDetails, MemberWithRegistrationsBlob, OrganizationMetaData, OrganizationRecordsConfiguration, Parent, PatchAnswers, PermissionLevel, Permissions, PermissionsResourceType, RecordCategory, RecordSettings, RecordTextAnswer, ResourcePermissions, ReviewTime, ReviewTimes, TranslatedString } from '@stamhoofd/structures';
6
+ import { SHExpect, TestUtils } from '@stamhoofd/test-utils';
7
7
  import { testServer } from '../../../../tests/helpers/TestServer';
8
8
  import { PatchOrganizationMembersEndpoint } from './PatchOrganizationMembersEndpoint';
9
9
 
@@ -16,8 +16,6 @@ const firstName = 'John';
16
16
  const lastName = 'Doe';
17
17
  const birthDay = { year: 1993, month: 4, day: 5 };
18
18
 
19
- const errorWithCode = (code: string) => expect.objectContaining({ code }) as jest.Constructable;
20
-
21
19
  describe('Endpoint.PatchOrganizationMembersEndpoint', () => {
22
20
  beforeEach(async () => {
23
21
  TestUtils.setEnvironment('userMode', 'platform');
@@ -59,7 +57,7 @@ describe('Endpoint.PatchOrganizationMembersEndpoint', () => {
59
57
  request.headers.authorization = 'Bearer ' + token.accessToken;
60
58
  await expect(testServer.test(endpoint, request))
61
59
  .rejects
62
- .toThrow(errorWithCode('known_member_missing_rights'));
60
+ .toThrow(SHExpect.errorWithCode('known_member_missing_rights'));
63
61
  });
64
62
 
65
63
  test('The security code is not a requirement for members without additional data', async () => {
@@ -219,7 +217,7 @@ describe('Endpoint.PatchOrganizationMembersEndpoint', () => {
219
217
 
220
218
  const request = Request.buildJson('PATCH', baseUrl, organization.getApiHost(), arr);
221
219
  request.headers.authorization = 'Bearer ' + token.accessToken;
222
- await expect(testServer.test(endpoint, request)).rejects.toThrow(errorWithCode('not_found'));
220
+ await expect(testServer.test(endpoint, request)).rejects.toThrow(SHExpect.errorWithCode('not_found'));
223
221
  });
224
222
 
225
223
  test('An admin can edit members registered in its own organization', async () => {
@@ -359,12 +357,12 @@ describe('Endpoint.PatchOrganizationMembersEndpoint', () => {
359
357
  describe('Record answers', () => {
360
358
  test('An admin can set records of its own organization', async () => {
361
359
  const commentsRecord = RecordSettings.create({
362
- name: 'Opmerkingen',
360
+ name: TranslatedString.create('Opmerkingen'),
363
361
  externalPermissionLevel: PermissionLevel.Read, // this should be ignored since we are an admin
364
362
  });
365
363
 
366
364
  const recordCategory = RecordCategory.create({
367
- name: 'Medische fiche',
365
+ name: TranslatedString.create('Medische fiche'),
368
366
  records: [
369
367
  commentsRecord,
370
368
  ],
@@ -428,11 +426,11 @@ describe('Endpoint.PatchOrganizationMembersEndpoint', () => {
428
426
 
429
427
  test('An admin with read only record category permission cannot set the records in that category', async () => {
430
428
  const commentsRecord = RecordSettings.create({
431
- name: 'Opmerkingen',
429
+ name: TranslatedString.create('Opmerkingen'),
432
430
  });
433
431
 
434
432
  const recordCategory = RecordCategory.create({
435
- name: 'Medische fiche',
433
+ name: TranslatedString.create('Medische fiche'),
436
434
  records: [
437
435
  commentsRecord,
438
436
  ],
@@ -495,16 +493,16 @@ describe('Endpoint.PatchOrganizationMembersEndpoint', () => {
495
493
 
496
494
  const request = Request.buildJson('PATCH', baseUrl, organization.getApiHost(), arr);
497
495
  request.headers.authorization = 'Bearer ' + token.accessToken;
498
- await expect(testServer.test(endpoint, request)).rejects.toThrow(errorWithCode('permission_denied'));
496
+ await expect(testServer.test(endpoint, request)).rejects.toThrow(SHExpect.errorWithCode('permission_denied'));
499
497
  });
500
498
 
501
499
  test('An admin without record category permission cannot set the records in that category', async () => {
502
500
  const commentsRecord = RecordSettings.create({
503
- name: 'Opmerkingen',
501
+ name: TranslatedString.create('Opmerkingen'),
504
502
  });
505
503
 
506
504
  const recordCategory = RecordCategory.create({
507
- name: 'Medische fiche',
505
+ name: TranslatedString.create('Medische fiche'),
508
506
  records: [
509
507
  commentsRecord,
510
508
  ],
@@ -564,16 +562,16 @@ describe('Endpoint.PatchOrganizationMembersEndpoint', () => {
564
562
 
565
563
  const request = Request.buildJson('PATCH', baseUrl, organization.getApiHost(), arr);
566
564
  request.headers.authorization = 'Bearer ' + token.accessToken;
567
- await expect(testServer.test(endpoint, request)).rejects.toThrow(errorWithCode('permission_denied'));
565
+ await expect(testServer.test(endpoint, request)).rejects.toThrow(SHExpect.errorWithCode('permission_denied'));
568
566
  });
569
567
 
570
568
  test('An admin can set records of the platform', async () => {
571
569
  const commentsRecord = RecordSettings.create({
572
- name: 'Opmerkingen',
570
+ name: TranslatedString.create('Opmerkingen'),
573
571
  });
574
572
 
575
573
  const recordCategory = RecordCategory.create({
576
- name: 'Medische fiche',
574
+ name: TranslatedString.create('Medische fiche'),
577
575
  records: [
578
576
  commentsRecord,
579
577
  ],
@@ -647,11 +645,11 @@ describe('Endpoint.PatchOrganizationMembersEndpoint', () => {
647
645
 
648
646
  test('[Regression] A platform admin with tag-access to an organization can change platform records', async () => {
649
647
  const commentsRecord = RecordSettings.create({
650
- name: 'Opmerkingen',
648
+ name: TranslatedString.create('Opmerkingen'),
651
649
  });
652
650
 
653
651
  const recordCategory = RecordCategory.create({
654
- name: 'Medische fiche',
652
+ name: TranslatedString.create('Medische fiche'),
655
653
  records: [
656
654
  commentsRecord,
657
655
  ],
@@ -1458,7 +1456,9 @@ describe('Endpoint.PatchOrganizationMembersEndpoint', () => {
1458
1456
  await member3.refresh();
1459
1457
 
1460
1458
  // Check all parents equal
1461
- const expectedParent = parent3;
1459
+ const expectedParent = parent3.patch({
1460
+ createdAt: parent1.createdAt, // parent1 created at can be 1ms smaller, and oldest will be used
1461
+ });
1462
1462
 
1463
1463
  expect(member1.details.parents).toEqual([expectedParent]);
1464
1464
  expect(member2.details.parents).toEqual([expectedParent]);
@@ -122,7 +122,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
122
122
  throw new SimpleError({
123
123
  code: 'missing_organization',
124
124
  message: 'Missing organization',
125
- human: 'Je moet een organisatie selecteren voor dit lid',
125
+ human: $t(`2bb4647b-a3b8-453e-8b75-41c290910fc8`),
126
126
  statusCode: 400,
127
127
  });
128
128
  }
@@ -173,7 +173,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
173
173
  throw new SimpleError({
174
174
  code: 'not_allowed',
175
175
  message: 'Cannot override details',
176
- human: 'Er ging iets mis bij het aanpassen van de gegevens van dit lid. Probeer het later opnieuw en neem contact op als het probleem zich blijft voordoen.',
176
+ human: $t(`b66ef4c3-9931-4fc3-9da1-c023857684fa`),
177
177
  field: 'details',
178
178
  });
179
179
  }
@@ -218,7 +218,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
218
218
  // Update responsibilities
219
219
  for (const patchResponsibility of patch.responsibilities.getPatches()) {
220
220
  if (!Context.auth.hasPlatformFullAccess() && !(organization && await Context.auth.hasFullAccess(organization.id))) {
221
- throw Context.auth.error('Je hebt niet voldoende rechten om functies van leden aan te passen');
221
+ throw Context.auth.error($t(`1d1b5807-af39-400b-8dea-2f222ee668ae`));
222
222
  }
223
223
 
224
224
  const responsibilityRecord = await MemberResponsibilityRecord.getByID(patchResponsibility.id);
@@ -226,21 +226,21 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
226
226
  throw new SimpleError({
227
227
  code: 'permission_denied',
228
228
  message: "You don't have permissions to access this endpoint",
229
- human: 'Je hebt geen toegang om deze functie te wijzigen',
229
+ human: $t(`738fc35a-da77-4e1a-8233-9ff651781f65`),
230
230
  });
231
231
  }
232
232
 
233
233
  const responsibility = platform.config.responsibilities.find(r => r.id === patchResponsibility.responsibilityId);
234
234
 
235
235
  if (responsibility && !responsibility.organizationBased && !Context.auth.hasPlatformFullAccess()) {
236
- throw Context.auth.error('Je hebt niet voldoende rechten om deze functie aan te passen');
236
+ throw Context.auth.error($t(`e2ceec71-367c-4cfd-98f3-b0ec0c83e2c2`));
237
237
  }
238
238
 
239
239
  // Allow patching begin and end date
240
240
  if (patchResponsibility.endDate !== undefined) {
241
241
  if (responsibilityRecord.endDate) {
242
242
  if (!Context.auth.hasPlatformFullAccess()) {
243
- throw Context.auth.error('Je hebt niet voldoende rechten om reeds beëindigde functies aan te passen');
243
+ throw Context.auth.error($t(`fd88b6ba-1f0b-4e82-9c5b-7c7a3ac8f4fa`));
244
244
  }
245
245
  }
246
246
  responsibilityRecord.endDate = patchResponsibility.endDate;
@@ -248,7 +248,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
248
248
 
249
249
  if (patchResponsibility.startDate !== undefined) {
250
250
  if (patchResponsibility.startDate.getTime() > Date.now() + 5 * 60 * 1000) {
251
- throw Context.auth.error('Je kan de startdatum van een functie niet in de toekomst zetten');
251
+ throw Context.auth.error($t(`84c2346e-40b2-4b38-9b2d-e1fcba6f1202`));
252
252
  }
253
253
  if (patchResponsibility.startDate.getTime() > Date.now()) {
254
254
  patchResponsibility.startDate = new Date(); // force now
@@ -257,7 +257,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
257
257
  const daysDiff = Math.abs((new Date().getTime() - patchResponsibility.startDate.getTime()) / (1000 * 60 * 60 * 24));
258
258
 
259
259
  if (daysDiff > 60 && !Context.auth.hasPlatformFullAccess()) {
260
- throw Context.auth.error('Je kan de startdatum van een functie niet zoveel verplaatsen');
260
+ throw Context.auth.error($t(`dc0c8bff-7b16-4597-adfb-cd6a4d7d4bf1`));
261
261
  }
262
262
  responsibilityRecord.startDate = patchResponsibility.startDate;
263
263
  }
@@ -274,7 +274,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
274
274
  // Create responsibilities
275
275
  for (const { put } of patch.responsibilities.getPuts()) {
276
276
  if (!Context.auth.hasPlatformFullAccess() && !(organization && await Context.auth.hasFullAccess(organization.id))) {
277
- throw Context.auth.error('Je hebt niet voldoende rechten om functies van leden aan te passen');
277
+ throw Context.auth.error($t(`1d1b5807-af39-400b-8dea-2f222ee668ae`));
278
278
  }
279
279
 
280
280
  const platformResponsibility = platform.config.responsibilities.find(r => r.id === put.responsibilityId);
@@ -284,7 +284,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
284
284
  throw new SimpleError({
285
285
  code: 'invalid_field',
286
286
  message: 'Invalid organization',
287
- human: 'Deze vereniging bestaat niet',
287
+ human: $t(`31757907-4cdd-4f0e-bb9d-cba9c1d997e4`),
288
288
  field: 'organizationId',
289
289
  });
290
290
  }
@@ -294,7 +294,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
294
294
  throw new SimpleError({
295
295
  code: 'invalid_field',
296
296
  message: 'Invalid responsibility',
297
- human: 'Deze functie bestaat niet',
297
+ human: $t(`03114785-acf5-4bba-a3b5-15d3ac4ae17c`),
298
298
  field: 'responsibilityId',
299
299
  });
300
300
  }
@@ -303,7 +303,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
303
303
  throw new SimpleError({
304
304
  code: 'invalid_field',
305
305
  message: 'Invalid organization',
306
- human: 'Deze functie kan niet worden toegewezen aan deze vereniging',
306
+ human: $t(`ed22b0bb-8ae7-4ef0-a139-1bc11b2a719e`),
307
307
  field: 'organizationId',
308
308
  });
309
309
  }
@@ -345,7 +345,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
345
345
  throw new SimpleError({
346
346
  code: 'invalid_field',
347
347
  message: 'Invalid organization',
348
- human: 'Deze functie is niet beschikbaar voor deze vereniging',
348
+ human: $t(`aa39f949-6fe5-4ed2-acb7-ff3d138cf243`),
349
349
  field: 'organizationId',
350
350
  });
351
351
  }
@@ -355,7 +355,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
355
355
  throw new SimpleError({
356
356
  code: 'invalid_field',
357
357
  message: 'Missing groupId',
358
- human: 'Kies een leeftijdsgroep waarvoor je deze functie wilt toekennen',
358
+ human: $t(`8bfe005a-a98a-48d6-afbf-bcca487b064b`),
359
359
  field: 'groupId',
360
360
  });
361
361
  }
@@ -365,7 +365,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
365
365
  throw new SimpleError({
366
366
  code: 'invalid_field',
367
367
  message: 'Invalid groupId',
368
- human: 'Deze leeftijdsgroep bestaat niet',
368
+ human: $t(`ca86d6ef-990e-42a4-834c-1c94622c95ef`),
369
369
  field: 'groupId',
370
370
  });
371
371
  }
@@ -374,7 +374,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
374
374
  throw new SimpleError({
375
375
  code: 'invalid_field',
376
376
  message: 'Invalid groupId',
377
- human: 'Deze leeftijdsgroep komt niet in aanmerking voor deze functie',
377
+ human: $t(`aed1d5e3-1d42-46d4-a9c1-ac13bdffc2bd`),
378
378
  field: 'groupId',
379
379
  });
380
380
  }
@@ -386,7 +386,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
386
386
  model.endDate = put.endDate;
387
387
 
388
388
  if (put.startDate.getTime() > Date.now() + 5 * 60 * 1000) {
389
- throw Context.auth.error('Je kan de startdatum van een functie niet in de toekomst zetten');
389
+ throw Context.auth.error($t(`84c2346e-40b2-4b38-9b2d-e1fcba6f1202`));
390
390
  }
391
391
 
392
392
  if (put.startDate.getTime() > Date.now()) {
@@ -394,7 +394,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
394
394
  }
395
395
 
396
396
  if (put.endDate && put.endDate > new Date(Date.now() + 60 * 1000)) {
397
- throw Context.auth.error('Je kan de einddatum van een functie niet in de toekomst zetten - kijk indien nodig je systeemtijd na');
397
+ throw Context.auth.error($t(`5c6106e8-6785-4f72-b0c7-00a940240019`));
398
398
  }
399
399
 
400
400
  model.startDate = put.startDate;
@@ -421,7 +421,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
421
421
  throw new SimpleError({
422
422
  code: 'invalid_field',
423
423
  message: 'Invalid email',
424
- human: 'Je kan een account niet de toegang ontzeggen tot een lid als het e-mailadres nog steeds is opgeslagen als onderdeel van de gegevens van dat lid. Verwijder eerst het e-mailadres uit de gegevens van het lid en ontkoppel daarna het account.',
424
+ human: $t(`dcb9cd60-ddfe-403d-bfb7-d1c7b63e2fdf`),
425
425
  });
426
426
  }
427
427
 
@@ -457,13 +457,13 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
457
457
  throw new SimpleError({
458
458
  code: 'invalid_field',
459
459
  message: 'Invalid organization',
460
- human: 'Je kan geen aansluitingen maken voor een andere vereniging',
460
+ human: $t(`601c15e5-cfb0-4c34-af03-7dfc55e39d36`),
461
461
  field: 'organizationId',
462
462
  });
463
463
  }
464
464
 
465
465
  if (!await Context.auth.hasFullAccess(put.organizationId)) {
466
- throw Context.auth.error('Je hebt niet voldoende rechten om deze aansluiting toe te voegen');
466
+ throw Context.auth.error($t(`9c632c7f-242e-44a1-b8ad-335b613075d8`));
467
467
  }
468
468
 
469
469
  const putForOrganization = await Context.auth.getOrganization(put.organizationId);
@@ -475,7 +475,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
475
475
  code: 'invalid_field',
476
476
  field: 'membershipTypeId',
477
477
  message: 'Invalid membership type',
478
- human: 'Dit aansluitingstype bestaat niet',
478
+ human: $t(`fa79b34e-deef-4379-9c80-8795b0f5eaa3`),
479
479
  });
480
480
  }
481
481
 
@@ -497,7 +497,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
497
497
  code: 'invalid_field',
498
498
  field: 'membershipTypeId',
499
499
  message: 'Invalid membership type',
500
- human: 'Dit aansluitingstype is niet toegestaan voor dit lid',
500
+ human: $t(`a17551ff-5097-4f09-a8bb-19fe377f2b98`),
501
501
  });
502
502
  }
503
503
 
@@ -543,7 +543,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
543
543
  code: 'invalid_field',
544
544
  field: 'startDate',
545
545
  message: 'Invalid start date',
546
- human: 'Je kan geen aansluiting toevoegen die overlapt met een bestaande aansluiting van hetzelfde type',
546
+ human: $t(`faf8b6bb-2727-4d2f-847f-203cf3979dfb`),
547
547
  });
548
548
  }
549
549
 
@@ -561,12 +561,12 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
561
561
  code: 'invalid_field',
562
562
  field: 'id',
563
563
  message: 'Invalid id',
564
- human: 'Deze aansluiting bestaat niet',
564
+ human: $t(`ee79372d-c14d-41ab-afb1-336acbe52687`),
565
565
  });
566
566
  }
567
567
 
568
568
  if (!await Context.auth.hasFullAccess(membership.organizationId)) {
569
- throw Context.auth.error('Je hebt niet voldoende rechten om deze aansluiting aan te passen');
569
+ throw Context.auth.error($t(`fa5797d7-dafb-469a-a75c-b3b8a6a08737`));
570
570
  }
571
571
 
572
572
  if (membership.periodId !== platform.periodId) {
@@ -619,12 +619,12 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
619
619
  code: 'invalid_field',
620
620
  field: 'id',
621
621
  message: 'Invalid id',
622
- human: 'Deze aansluiting bestaat niet',
622
+ human: $t(`ee79372d-c14d-41ab-afb1-336acbe52687`),
623
623
  });
624
624
  }
625
625
 
626
626
  if (!await Context.auth.hasFullAccess(membership.organizationId)) {
627
- throw Context.auth.error('Je hebt niet voldoende rechten om deze aansluiting te verwijderen');
627
+ throw Context.auth.error($t(`c3cca571-d543-4ca7-9da1-1e5570f5063a`));
628
628
  }
629
629
 
630
630
  if (membership.periodId !== platform.periodId) {
@@ -654,14 +654,14 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
654
654
  throw new SimpleError({
655
655
  code: 'invalid_field',
656
656
  message: 'Invalid invoice',
657
- human: 'Je kan geen aansluiting verwijderen die vergrendeld is',
657
+ human: $t(`be7d7286-9c3f-41f9-9378-b028754c8533`),
658
658
  });
659
659
  }
660
660
 
661
661
  throw new SimpleError({
662
662
  code: 'invalid_field',
663
663
  message: 'Invalid invoice',
664
- human: 'Je kan geen aansluiting verwijderen die al werd gefactureerd',
664
+ human: $t(`1a7b41da-9bd3-4019-9ed4-39e742f99f41`),
665
665
  });
666
666
  }
667
667
 
@@ -709,7 +709,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
709
709
  for (const id of ids) {
710
710
  const member = await Member.getWithRegistrations(id);
711
711
  if (!member || !await Context.auth.canDeleteMember(member)) {
712
- throw Context.auth.error('Je hebt niet voldoende rechten om dit lid te verwijderen');
712
+ throw Context.auth.error($t(`39f5696c-3755-429f-b0da-a0ca920ed11e`));
713
713
  }
714
714
 
715
715
  await MemberUserSyncer.onDeleteMember(member);
@@ -901,14 +901,14 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
901
901
  }
902
902
  catch (e) {
903
903
  Email.sendWebmaster({
904
- subject: '[Limiet] Limiet bereikt voor aantal beveiligingscodes',
905
- text: 'Beste, \nDe limiet werd bereikt voor het aantal beveiligingscodes per dag. \nNaam lid: ' + member.details.name + ' (ID: ' + member.id + ')' + '\n\n' + e.message + '\n\nStamhoofd',
904
+ subject: $t(`04cb945a-28aa-4f3e-95b3-16455cdd8892`),
905
+ text: $t(`5f7b1766-eb58-4471-bff7-60f3fc66fe41`) + ' ' + member.details.name + ' ' + $t(`7254f2f6-0d15-4e81-85cf-cff6438c9e98`) + ' ' + member.id + ')' + '\n\n' + e.message + '\n\nStamhoofd',
906
906
  });
907
907
 
908
908
  throw new SimpleError({
909
909
  code: 'too_many_tries',
910
910
  message: 'Too many securityCodes limited',
911
- human: 'Oeps! Om spam te voorkomen limiteren we het aantal beveiligingscodes die je kan proberen. Probeer morgen opnieuw.',
911
+ human: $t(`ddb1b9de-cc00-4960-ba36-fa70429cbac1`),
912
912
  field: 'details.securityCode',
913
913
  });
914
914
  }
@@ -36,7 +36,7 @@ export class CheckRegisterCodeEndpoint extends Endpoint<Params, Query, Body, Res
36
36
  throw new SimpleError({
37
37
  code: 'invalid_code',
38
38
  message: 'Invalid code',
39
- human: 'Deze code is niet geldig',
39
+ human: $t(`d46c176d-780c-4484-a510-7fcbe0e31555`),
40
40
  field: 'registerCode',
41
41
  });
42
42
  }
@@ -31,7 +31,7 @@ export class CreateOrganizationEndpoint extends Endpoint<Params, Query, Body, Re
31
31
  throw new SimpleError({
32
32
  code: 'invalid_field',
33
33
  message: 'Not allowed',
34
- human: 'Je kan geen vereniging aanmaken',
34
+ human: $t(`a010c110-bf4e-4c12-a324-6b84c992e728`),
35
35
  });
36
36
  }
37
37
 
@@ -40,7 +40,7 @@ export class CreateOrganizationEndpoint extends Endpoint<Params, Query, Body, Re
40
40
  throw new SimpleError({
41
41
  code: 'invalid_field',
42
42
  message: 'Should not be empty',
43
- human: 'Je bent de naam van je organisatie vergeten in te vullen',
43
+ human: $t(`3f37782a-c07f-457d-994f-f1cc075cff44`),
44
44
  field: 'organization.name',
45
45
  });
46
46
  }
@@ -48,7 +48,7 @@ export class CreateOrganizationEndpoint extends Endpoint<Params, Query, Body, Re
48
48
  throw new SimpleError({
49
49
  code: 'invalid_field',
50
50
  message: 'Field is too short',
51
- human: 'Kijk de naam van je organisatie na, deze is te kort. Vul eventueel aan met de gemeente.',
51
+ human: $t(`0e82abec-5467-45d8-ba89-9b9fd10c085d`),
52
52
  field: 'organization.name',
53
53
  });
54
54
  }
@@ -59,7 +59,7 @@ export class CreateOrganizationEndpoint extends Endpoint<Params, Query, Body, Re
59
59
  throw new SimpleError({
60
60
  code: 'invalid_field',
61
61
  message: 'Field is too long',
62
- human: 'De naam van de vereniging is te lang. Probeer de naam wat te verkorten en probeer opnieuw.',
62
+ human: $t(`c4d225ea-8e41-4829-bf0c-bc04755492de`),
63
63
  field: 'organization.name',
64
64
  });
65
65
  }
@@ -69,7 +69,7 @@ export class CreateOrganizationEndpoint extends Endpoint<Params, Query, Body, Re
69
69
  throw new SimpleError({
70
70
  code: 'name_taken',
71
71
  message: 'An organization with the same name already exists',
72
- human: 'Er bestaat al een vereniging met dezelfde naam. Voeg bijvoorbeeld de naam van je gemeente toe.',
72
+ human: $t(`19e5262f-9dc1-40d9-b905-bda8462b6046`),
73
73
  field: 'name',
74
74
  });
75
75
  }
@@ -52,6 +52,11 @@ export class StripeWebookEndpoint extends Endpoint<Params, Query, Body, Response
52
52
 
53
53
  async handle(request: DecodedRequest<Params, Query, Body>) {
54
54
  console.log('Received Stripe Webhook', request.body.type);
55
+ const secret = request.body.account ? STAMHOOFD.STRIPE_CONNECT_ENDPOINT_SECRET : STAMHOOFD.STRIPE_ENDPOINT_SECRET;
56
+
57
+ if (!secret) {
58
+ throw StripeHelper.notConfiguredError;
59
+ }
55
60
 
56
61
  // Verify webhook signature and extract the event.
57
62
  // See https://stripe.com/docs/webhooks/signatures for more information.
@@ -66,7 +71,6 @@ export class StripeWebookEndpoint extends Endpoint<Params, Query, Body, Response
66
71
  statusCode: 400,
67
72
  });
68
73
  }
69
- const secret = request.body.account ? STAMHOOFD.STRIPE_CONNECT_ENDPOINT_SECRET : STAMHOOFD.STRIPE_ENDPOINT_SECRET;
70
74
  event = await stripe.webhooks.constructEventAsync(await request.request.bodyPromise!, sig, secret);
71
75
  }
72
76
  catch (err) {
@@ -0,0 +1,68 @@
1
+ import { Request } from '@simonbackx/simple-endpoints';
2
+ import { Token, UserFactory } from '@stamhoofd/models';
3
+ import { PermissionLevel, Permissions, Version } from '@stamhoofd/structures';
4
+
5
+ import { TestUtils } from '@stamhoofd/test-utils';
6
+ import { testServer } from '../../../../tests/helpers/TestServer';
7
+ import { GetPlatformEndpoint } from './GetPlatformEndpoint';
8
+
9
+ describe('Endpoint.GetPlatformEndpoint', () => {
10
+ const endpoint = new GetPlatformEndpoint();
11
+
12
+ const getPlatform = async (token?: Token) => {
13
+ const request = Request.buildJson('GET', `/v${Version}/platform`);
14
+ if (token) {
15
+ request.headers.authorization = 'Bearer ' + token.accessToken;
16
+ }
17
+ return await testServer.test(endpoint, request);
18
+ };
19
+
20
+ beforeEach(async () => {
21
+ TestUtils.setEnvironment('userMode', 'platform');
22
+ });
23
+
24
+ test('Should return platform without private config if not authenticated', async () => {
25
+ const platform = await getPlatform();
26
+ expect(platform.body.privateConfig).toBeNull();
27
+ });
28
+
29
+ test('Should return platform without private config if no platform access', async () => {
30
+ const user = await new UserFactory({
31
+ globalPermissions: Permissions.create({
32
+ level: PermissionLevel.None,
33
+ }),
34
+ })
35
+ .create();
36
+
37
+ const token = await Token.createToken(user);
38
+ const platform = await getPlatform(token);
39
+ expect(platform.body.privateConfig).toBeNull();
40
+ });
41
+
42
+ test('Should return platform with private config if authenticated and has platform access', async () => {
43
+ const user = await new UserFactory({
44
+ globalPermissions: Permissions.create({
45
+ level: PermissionLevel.Full,
46
+ }),
47
+ })
48
+ .create();
49
+
50
+ const token = await Token.createToken(user);
51
+ const platform = await getPlatform(token);
52
+ expect(platform.body.privateConfig).not.toBeNull();
53
+ });
54
+
55
+ test('Should throw if invalid token', async () => {
56
+ const user = await new UserFactory({
57
+ globalPermissions: Permissions.create({
58
+ level: PermissionLevel.Full,
59
+ }),
60
+ })
61
+ .create();
62
+
63
+ const token = await Token.createToken(user);
64
+ token.accessToken = 'invalid-token';
65
+ await token.save();
66
+ await expect(getPlatform(token)).rejects.toThrow('The access token is invalid');
67
+ });
68
+ });
@@ -161,7 +161,7 @@ export class PatchPlatformEndpoint extends Endpoint<
161
161
  throw new SimpleError({
162
162
  code: 'cannot_set_locked_period',
163
163
  message: 'Platform period cannot be set to a locked period',
164
- human: 'Er kan niet overgeschakeld worden naar een vergrendeld werkjaar',
164
+ human: $t(`fdd15119-b950-4282-9413-fd6973afde07`),
165
165
  });
166
166
  }
167
167
  platform.periodId = period.id;
@@ -33,7 +33,7 @@ export class GetPaymentRegistrations extends Endpoint<Params, Query, Body, Respo
33
33
  if (!payment) {
34
34
  throw new SimpleError({
35
35
  code: '',
36
- message: 'Deze link is ongeldig',
36
+ message: $t(`35b369bd-5766-41d1-8da3-3d362e316c1a`),
37
37
  });
38
38
  }
39
39
  const registrations = await Member.getRegistrationWithMembersForPayment(payment.id);
@@ -45,7 +45,7 @@ export class GetPaymentRegistrations extends Endpoint<Params, Query, Body, Respo
45
45
  if (!authorizedMembers.includes(registration.member.id)) {
46
46
  throw new SimpleError({
47
47
  code: '',
48
- message: 'Deze link is ongeldig',
48
+ message: $t(`35b369bd-5766-41d1-8da3-3d362e316c1a`),
49
49
  });
50
50
  }
51
51
  }