@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
@@ -0,0 +1,188 @@
1
+ /* eslint-disable jest/no-conditional-expect */
2
+ import { Request } from '@simonbackx/simple-endpoints';
3
+ import { Organization, OrganizationFactory, Token, UserFactory } from '@stamhoofd/models';
4
+
5
+ import { PatchMap } from '@simonbackx/simple-encoding';
6
+ import { ApiUser, ApiUserRateLimits, PermissionLevel, Permissions, PermissionsResourceType, ResourcePermissions, UserMeta, UserPermissions } from '@stamhoofd/structures';
7
+ import { SHExpect, TestUtils } from '@stamhoofd/test-utils';
8
+ import { CreateApiUserEndpoint } from '../../src/endpoints/organization/dashboard/users/CreateApiUserEndpoint';
9
+ import { testServer } from '../helpers/TestServer';
10
+ import { GetUserEndpoint } from '../../src/endpoints/auth/GetUserEndpoint';
11
+
12
+ describe('E2E.APIRateLimits', () => {
13
+ // Test endpoint
14
+ const createEndpoint = new CreateApiUserEndpoint();
15
+ const getUserEndpoint = new GetUserEndpoint();
16
+ let organization: Organization;
17
+
18
+ beforeEach(async () => {
19
+ TestUtils.setEnvironment('userMode', 'platform');
20
+ organization = await new OrganizationFactory({}).create();
21
+ });
22
+
23
+ /**
24
+ * Note: we don't use a factory because this is an E2E test and
25
+ * we also want to check if the created tokens with the API are actually marked as API-keys and not normal users.
26
+ */
27
+ async function createAPIToken(rateLimits: ApiUserRateLimits | null) {
28
+ const user = await new UserFactory({
29
+ globalPermissions: Permissions.create({
30
+ level: PermissionLevel.Full,
31
+ }),
32
+ }).create();
33
+ const token = await Token.createToken(user);
34
+
35
+ const createRequest = Request.buildJson('POST', '/api-keys', organization.getApiHost(), ApiUser.create({
36
+ permissions: UserPermissions.create({
37
+ organizationPermissions: new Map([
38
+ [organization.id, Permissions.create({ level: PermissionLevel.Read })],
39
+ ]),
40
+ }),
41
+ meta: UserMeta.create({
42
+ rateLimits,
43
+ }),
44
+ }));
45
+ createRequest.headers.authorization = 'Bearer ' + token.accessToken;
46
+ const createResponse = await testServer.test(createEndpoint, createRequest);
47
+
48
+ expect(createResponse.body.meta?.rateLimits ?? undefined).toEqual(rateLimits ?? undefined);
49
+
50
+ return createResponse.body.token;
51
+ }
52
+
53
+ test('By default throws after 25 requests in less than 5s', async () => {
54
+ const token = await createAPIToken(null);
55
+
56
+ // Start firing
57
+ for (let i = 0; i < 30; i++) {
58
+ const request = Request.buildJson('GET', '/user', organization.getApiHost());
59
+ request.headers.authorization = 'Bearer ' + token;
60
+ const promise = testServer.test(getUserEndpoint, request);
61
+
62
+ if (i < 25) {
63
+ try {
64
+ await expect(promise).toResolve();
65
+ }
66
+ catch (e) {
67
+ let error: any = null;
68
+ try {
69
+ await promise;
70
+ }
71
+ catch (e) {
72
+ error = e;
73
+ }
74
+ throw new Error('The endpoint rejected at call ' + i + ' with error message ' + error?.message);
75
+ }
76
+ }
77
+ else {
78
+ await expect(promise).rejects.toThrow(
79
+ SHExpect.simpleError({
80
+ code: 'rate_limit',
81
+ }),
82
+ );
83
+ }
84
+ }
85
+ });
86
+
87
+ test('Normal rate limit throws after 25 requests in less than 5s', async () => {
88
+ const token = await createAPIToken(ApiUserRateLimits.Normal);
89
+
90
+ // Start firing
91
+ for (let i = 0; i < 30; i++) {
92
+ const request = Request.buildJson('GET', '/user', organization.getApiHost());
93
+ request.headers.authorization = 'Bearer ' + token;
94
+ const promise = testServer.test(getUserEndpoint, request);
95
+
96
+ if (i < 25) {
97
+ try {
98
+ await expect(promise).toResolve();
99
+ }
100
+ catch (e) {
101
+ let error: any = null;
102
+ try {
103
+ await promise;
104
+ }
105
+ catch (e) {
106
+ error = e;
107
+ }
108
+ throw new Error('The endpoint rejected at call ' + i + ' with error message ' + error?.message);
109
+ }
110
+ }
111
+ else {
112
+ await expect(promise).rejects.toThrow(
113
+ SHExpect.simpleError({
114
+ code: 'rate_limit',
115
+ }),
116
+ );
117
+ }
118
+ }
119
+ });
120
+
121
+ test('Medium rate limits throw after 50 requests in less than 5s', async () => {
122
+ const token = await createAPIToken(ApiUserRateLimits.Medium);
123
+
124
+ // Start firing
125
+ for (let i = 0; i < 60; i++) {
126
+ const request = Request.buildJson('GET', '/user', organization.getApiHost());
127
+ request.headers.authorization = 'Bearer ' + token;
128
+ const promise = testServer.test(getUserEndpoint, request);
129
+
130
+ if (i < 50) {
131
+ try {
132
+ await expect(promise).toResolve();
133
+ }
134
+ catch (e) {
135
+ let error: any = null;
136
+ try {
137
+ await promise;
138
+ }
139
+ catch (e) {
140
+ error = e;
141
+ }
142
+ throw new Error('The endpoint rejected at call ' + i + ' with error message ' + error?.message);
143
+ }
144
+ }
145
+ else {
146
+ await expect(promise).rejects.toThrow(
147
+ SHExpect.simpleError({
148
+ code: 'rate_limit',
149
+ }),
150
+ );
151
+ }
152
+ }
153
+ });
154
+
155
+ test('High rate limits throw after 125 requests in less than 5s', async () => {
156
+ const token = await createAPIToken(ApiUserRateLimits.High);
157
+
158
+ // Start firing
159
+ for (let i = 0; i < 140; i++) {
160
+ const request = Request.buildJson('GET', '/user', organization.getApiHost());
161
+ request.headers.authorization = 'Bearer ' + token;
162
+ const promise = testServer.test(getUserEndpoint, request);
163
+
164
+ if (i < 125) {
165
+ try {
166
+ await expect(promise).toResolve();
167
+ }
168
+ catch (e) {
169
+ let error: any = null;
170
+ try {
171
+ await promise;
172
+ }
173
+ catch (e) {
174
+ error = e;
175
+ }
176
+ throw new Error('The endpoint rejected at call ' + i + ' with error message ' + error?.message);
177
+ }
178
+ }
179
+ else {
180
+ await expect(promise).rejects.toThrow(
181
+ SHExpect.simpleError({
182
+ code: 'rate_limit',
183
+ }),
184
+ );
185
+ }
186
+ }
187
+ });
188
+ });
@@ -1,4 +1,4 @@
1
- import { File, MemberDetails, MemberWithRegistrationsBlob, RecordCategory, RecordFileAnswer, RecordSettings, RecordType, Version } from '@stamhoofd/structures';
1
+ import { File, MemberDetails, MemberWithRegistrationsBlob, RecordCategory, RecordFileAnswer, RecordSettings, RecordType, TranslatedString, Version } from '@stamhoofd/structures';
2
2
 
3
3
  import { PatchableArray, PatchableArrayAutoEncoder } from '@simonbackx/simple-encoding';
4
4
  import { Request } from '@simonbackx/simple-endpoints';
@@ -16,7 +16,7 @@ const getMembersEndpoint = new GetUserMembersEndpoint();
16
16
  describe('E2E.PrivateFiles', () => {
17
17
  const recordSettings = RecordSettings.create({
18
18
  id: 'test',
19
- name: 'Bestand test',
19
+ name: TranslatedString.create('Bestand test'),
20
20
  type: RecordType.File,
21
21
  });
22
22
 
@@ -25,7 +25,7 @@ describe('E2E.PrivateFiles', () => {
25
25
 
26
26
  // Add record settings type
27
27
  const category = RecordCategory.create({
28
- name: 'Voorbeeld',
28
+ name: TranslatedString.create('Voorbeeld'),
29
29
  defaultEnabled: true,
30
30
  records: [
31
31
  recordSettings,
@@ -165,9 +165,15 @@ export class StripeMocker {
165
165
  const endpoint = new StripeWebookEndpoint();
166
166
 
167
167
  const r = Request.buildJson('POST', `/stripe/webhooks`, undefined, payload);
168
+ const secret = payload.account ? STAMHOOFD.STRIPE_CONNECT_ENDPOINT_SECRET : STAMHOOFD.STRIPE_ENDPOINT_SECRET;
169
+
170
+ if (!secret) {
171
+ throw new Error('No stripe secret set in env');
172
+ }
173
+
168
174
  r.headers['stripe-signature'] = stripe.webhooks.generateTestHeaderString({
169
175
  payload: await r.body,
170
- secret: payload.account ? STAMHOOFD.STRIPE_CONNECT_ENDPOINT_SECRET : STAMHOOFD.STRIPE_ENDPOINT_SECRET,
176
+ secret: secret,
171
177
  });
172
178
  await testServer.test(endpoint, r);
173
179
  }