@stamhoofd/backend 2.39.1 → 2.40.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 (198) hide show
  1. package/eslint.config.mjs +5 -0
  2. package/index.ts +81 -74
  3. package/jest.config.cjs +10 -0
  4. package/migrations.ts +16 -14
  5. package/package.json +11 -11
  6. package/src/crons/clear-excel-cache.test.ts +48 -50
  7. package/src/crons/clear-excel-cache.ts +18 -18
  8. package/src/crons/setup-steps.ts +2 -2
  9. package/src/crons.ts +325 -306
  10. package/src/decoders/StringArrayDecoder.ts +7 -7
  11. package/src/decoders/StringNullableDecoder.ts +1 -2
  12. package/src/email-recipient-loaders/members.ts +22 -22
  13. package/src/endpoints/admin/memberships/ChargeMembershipsEndpoint.ts +8 -9
  14. package/src/endpoints/admin/memberships/GetChargeMembershipsSummaryEndpoint.ts +39 -40
  15. package/src/endpoints/admin/organizations/GetOrganizationsCountEndpoint.ts +8 -8
  16. package/src/endpoints/admin/organizations/GetOrganizationsEndpoint.ts +44 -45
  17. package/src/endpoints/admin/organizations/PatchOrganizationsEndpoint.ts +58 -57
  18. package/src/endpoints/auth/CreateAdminEndpoint.ts +48 -45
  19. package/src/endpoints/auth/CreateTokenEndpoint.test.ts +31 -31
  20. package/src/endpoints/auth/CreateTokenEndpoint.ts +146 -147
  21. package/src/endpoints/auth/DeleteTokenEndpoint.ts +7 -7
  22. package/src/endpoints/auth/DeleteUserEndpoint.ts +15 -15
  23. package/src/endpoints/auth/ForgotPasswordEndpoint.ts +17 -18
  24. package/src/endpoints/auth/GetOtherUserEndpoint.ts +9 -10
  25. package/src/endpoints/auth/GetUserEndpoint.test.ts +32 -35
  26. package/src/endpoints/auth/GetUserEndpoint.ts +5 -6
  27. package/src/endpoints/auth/PatchApiUserEndpoint.ts +35 -33
  28. package/src/endpoints/auth/PatchUserEndpoint.ts +55 -52
  29. package/src/endpoints/auth/PollEmailVerificationEndpoint.ts +9 -9
  30. package/src/endpoints/auth/RetryEmailVerificationEndpoint.ts +8 -8
  31. package/src/endpoints/auth/SignupEndpoint.ts +37 -36
  32. package/src/endpoints/auth/VerifyEmailEndpoint.ts +29 -28
  33. package/src/endpoints/global/addresses/SearchRegionsEndpoint.ts +33 -33
  34. package/src/endpoints/global/addresses/ValidateAddressEndpoint.ts +7 -7
  35. package/src/endpoints/global/caddy/CheckDomainCertEndpoint.ts +37 -37
  36. package/src/endpoints/global/email/CreateEmailEndpoint.ts +30 -30
  37. package/src/endpoints/global/email/GetEmailAddressEndpoint.ts +13 -13
  38. package/src/endpoints/global/email/GetEmailEndpoint.ts +13 -13
  39. package/src/endpoints/global/email/ManageEmailAddressEndpoint.ts +16 -16
  40. package/src/endpoints/global/email/PatchEmailEndpoint.ts +25 -25
  41. package/src/endpoints/global/events/GetEventsEndpoint.ts +43 -44
  42. package/src/endpoints/global/events/PatchEventsEndpoint.ts +127 -172
  43. package/src/endpoints/global/files/ExportToExcelEndpoint.ts +49 -50
  44. package/src/endpoints/global/files/GetFileCache.ts +13 -13
  45. package/src/endpoints/global/files/UploadFile.ts +51 -54
  46. package/src/endpoints/global/files/UploadImage.ts +53 -53
  47. package/src/endpoints/global/groups/GetGroupsEndpoint.ts +25 -25
  48. package/src/endpoints/global/members/GetMemberFamilyEndpoint.ts +24 -23
  49. package/src/endpoints/global/members/GetMembersCountEndpoint.ts +8 -8
  50. package/src/endpoints/global/members/GetMembersEndpoint.ts +105 -102
  51. package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.ts +240 -239
  52. package/src/endpoints/global/organizations/CheckRegisterCodeEndpoint.ts +12 -14
  53. package/src/endpoints/global/organizations/CreateOrganizationEndpoint.test.ts +32 -33
  54. package/src/endpoints/global/organizations/CreateOrganizationEndpoint.ts +48 -57
  55. package/src/endpoints/global/organizations/GetOrganizationFromDomainEndpoint.test.ts +21 -22
  56. package/src/endpoints/global/organizations/GetOrganizationFromDomainEndpoint.ts +28 -28
  57. package/src/endpoints/global/organizations/GetOrganizationFromUriEndpoint.ts +18 -18
  58. package/src/endpoints/global/organizations/SearchOrganizationEndpoint.test.ts +20 -20
  59. package/src/endpoints/global/organizations/SearchOrganizationEndpoint.ts +17 -17
  60. package/src/endpoints/global/payments/StripeWebhookEndpoint.ts +81 -75
  61. package/src/endpoints/global/platform/GetPlatformAdminsEndpoint.ts +14 -14
  62. package/src/endpoints/global/platform/GetPlatformEnpoint.ts +11 -11
  63. package/src/endpoints/global/platform/PatchPlatformEnpoint.ts +71 -68
  64. package/src/endpoints/global/registration/GetPaymentRegistrations.ts +27 -27
  65. package/src/endpoints/global/registration/GetUserBillingStatusEndpoint.ts +30 -30
  66. package/src/endpoints/global/registration/GetUserDetailedBillingStatusEndpoint.ts +34 -34
  67. package/src/endpoints/global/registration/GetUserDocumentsEndpoint.ts +26 -26
  68. package/src/endpoints/global/registration/GetUserMembersEndpoint.ts +12 -12
  69. package/src/endpoints/global/registration/PatchUserMembersEndpoint.ts +90 -90
  70. package/src/endpoints/global/registration/RegisterMembersEndpoint.test.ts +118 -121
  71. package/src/endpoints/global/registration/RegisterMembersEndpoint.ts +362 -350
  72. package/src/endpoints/global/registration-periods/GetRegistrationPeriodsEndpoint.ts +8 -9
  73. package/src/endpoints/global/registration-periods/PatchRegistrationPeriodsEndpoint.ts +21 -21
  74. package/src/endpoints/global/webshops/GetWebshopFromDomainEndpoint.ts +65 -65
  75. package/src/endpoints/organization/dashboard/billing/GetOrganizationBillingStatusEndpoint.ts +9 -9
  76. package/src/endpoints/organization/dashboard/billing/GetOrganizationDetailedBillingStatusEndpoint.ts +14 -14
  77. package/src/endpoints/organization/dashboard/documents/GetDocumentTemplateXML.ts +17 -17
  78. package/src/endpoints/organization/dashboard/documents/GetDocumentTemplatesEndpoint.ts +21 -21
  79. package/src/endpoints/organization/dashboard/documents/GetDocumentsEndpoint.ts +15 -15
  80. package/src/endpoints/organization/dashboard/documents/PatchDocumentEndpoint.ts +52 -52
  81. package/src/endpoints/organization/dashboard/documents/PatchDocumentTemplateEndpoint.ts +37 -37
  82. package/src/endpoints/organization/dashboard/email/CheckEmailBouncesEndpoint.ts +14 -14
  83. package/src/endpoints/organization/dashboard/email/EmailEndpoint.ts +113 -112
  84. package/src/endpoints/organization/dashboard/email-templates/GetEmailTemplatesEndpoint.ts +29 -29
  85. package/src/endpoints/organization/dashboard/email-templates/PatchEmailTemplatesEndpoint.ts +48 -47
  86. package/src/endpoints/organization/dashboard/mollie/CheckMollieEndpoint.ts +22 -21
  87. package/src/endpoints/organization/dashboard/mollie/ConnectMollieEndpoint.ts +13 -14
  88. package/src/endpoints/organization/dashboard/mollie/DisconnectMollieEndpoint.ts +12 -13
  89. package/src/endpoints/organization/dashboard/mollie/GetMollieDashboardEndpoint.ts +24 -24
  90. package/src/endpoints/organization/dashboard/nolt/CreateNoltTokenEndpoint.ts +10 -12
  91. package/src/endpoints/organization/dashboard/organization/GetOrganizationArchivedGroups.ts +14 -14
  92. package/src/endpoints/organization/dashboard/organization/GetOrganizationDeletedGroups.ts +13 -13
  93. package/src/endpoints/organization/dashboard/organization/GetOrganizationSSOEndpoint.ts +12 -12
  94. package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.test.ts +120 -124
  95. package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.ts +172 -173
  96. package/src/endpoints/organization/dashboard/organization/SetOrganizationDomainEndpoint.ts +88 -89
  97. package/src/endpoints/organization/dashboard/organization/SetOrganizationSSOEndpoint.ts +12 -12
  98. package/src/endpoints/organization/dashboard/payments/GetMemberBalanceEndpoint.ts +17 -17
  99. package/src/endpoints/organization/dashboard/payments/GetPaymentsCountEndpoint.ts +8 -8
  100. package/src/endpoints/organization/dashboard/payments/GetPaymentsEndpoint.ts +66 -67
  101. package/src/endpoints/organization/dashboard/payments/PatchBalanceItemsEndpoint.ts +47 -47
  102. package/src/endpoints/organization/dashboard/payments/PatchPaymentsEndpoint.ts +93 -91
  103. package/src/endpoints/organization/dashboard/registration-periods/GetOrganizationRegistrationPeriodsEndpoint.ts +16 -17
  104. package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.ts +170 -167
  105. package/src/endpoints/organization/dashboard/registration-periods/SetupStepReviewEndpoint.ts +25 -24
  106. package/src/endpoints/organization/dashboard/stripe/ConnectStripeEndpoint.ts +22 -23
  107. package/src/endpoints/organization/dashboard/stripe/DeleteStripeAccountEndpoint.ts +22 -22
  108. package/src/endpoints/organization/dashboard/stripe/GetStripeAccountLinkEndpoint.ts +17 -18
  109. package/src/endpoints/organization/dashboard/stripe/GetStripeAccountsEndpoint.ts +8 -9
  110. package/src/endpoints/organization/dashboard/stripe/GetStripeLoginLinkEndpoint.ts +17 -18
  111. package/src/endpoints/organization/dashboard/stripe/UpdateStripeAccountEndpoint.ts +14 -15
  112. package/src/endpoints/organization/dashboard/users/CreateApiUserEndpoint.ts +19 -19
  113. package/src/endpoints/organization/dashboard/users/DeleteUserEndpoint.ts +19 -19
  114. package/src/endpoints/organization/dashboard/users/GetApiUsersEndpoint.ts +14 -14
  115. package/src/endpoints/organization/dashboard/users/GetOrganizationAdminsEndpoint.ts +12 -12
  116. package/src/endpoints/organization/dashboard/webshops/CreateWebshopEndpoint.ts +103 -100
  117. package/src/endpoints/organization/dashboard/webshops/DeleteWebshopEndpoint.ts +11 -12
  118. package/src/endpoints/organization/dashboard/webshops/GetDiscountCodesEndpoint.ts +15 -15
  119. package/src/endpoints/organization/dashboard/webshops/GetWebshopOrdersEndpoint.ts +14 -14
  120. package/src/endpoints/organization/dashboard/webshops/GetWebshopTicketsEndpoint.ts +14 -14
  121. package/src/endpoints/organization/dashboard/webshops/GetWebshopUriAvailabilityEndpoint.ts +23 -23
  122. package/src/endpoints/organization/dashboard/webshops/PatchDiscountCodesEndpoint.ts +54 -52
  123. package/src/endpoints/organization/dashboard/webshops/PatchWebshopEndpoint.ts +84 -81
  124. package/src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.ts +120 -111
  125. package/src/endpoints/organization/dashboard/webshops/PatchWebshopTicketsEndpoint.ts +24 -24
  126. package/src/endpoints/organization/dashboard/webshops/VerifyWebshopDomainEndpoint.ts +18 -18
  127. package/src/endpoints/organization/shared/ExchangePaymentEndpoint.ts +141 -130
  128. package/src/endpoints/organization/shared/GetDocumentHtml.ts +25 -25
  129. package/src/endpoints/organization/shared/GetPaymentEndpoint.ts +18 -18
  130. package/src/endpoints/organization/shared/auth/GetOrganizationEndpoint.test.ts +36 -37
  131. package/src/endpoints/organization/shared/auth/GetOrganizationEndpoint.ts +9 -9
  132. package/src/endpoints/organization/shared/auth/OpenIDConnectCallbackEndpoint.ts +11 -11
  133. package/src/endpoints/organization/shared/auth/OpenIDConnectStartEndpoint.ts +28 -27
  134. package/src/endpoints/organization/webshops/CheckWebshopDiscountCodesEndpoint.ts +20 -20
  135. package/src/endpoints/organization/webshops/GetOrderByPaymentEndpoint.ts +22 -22
  136. package/src/endpoints/organization/webshops/GetOrderEndpoint.ts +14 -14
  137. package/src/endpoints/organization/webshops/GetTicketsEndpoint.ts +57 -56
  138. package/src/endpoints/organization/webshops/GetWebshopEndpoint.test.ts +65 -66
  139. package/src/endpoints/organization/webshops/GetWebshopEndpoint.ts +18 -17
  140. package/src/endpoints/organization/webshops/PlaceOrderEndpoint.test.ts +124 -128
  141. package/src/endpoints/organization/webshops/PlaceOrderEndpoint.ts +154 -145
  142. package/src/excel-loaders/members.ts +102 -103
  143. package/src/excel-loaders/payments.ts +155 -156
  144. package/src/helpers/AddressValidator.test.ts +32 -32
  145. package/src/helpers/AddressValidator.ts +128 -122
  146. package/src/helpers/AdminPermissionChecker.ts +339 -236
  147. package/src/helpers/AuthenticatedStructures.ts +233 -134
  148. package/src/helpers/BuckarooHelper.ts +134 -134
  149. package/src/helpers/CheckSettlements.ts +94 -88
  150. package/src/helpers/Context.ts +87 -86
  151. package/src/helpers/CookieHelper.ts +23 -22
  152. package/src/helpers/EmailResumer.ts +10 -10
  153. package/src/helpers/FileCache.ts +62 -62
  154. package/src/helpers/ForwardHandler.test.ts +122 -124
  155. package/src/helpers/ForwardHandler.ts +76 -70
  156. package/src/helpers/MemberUserSyncer.ts +101 -96
  157. package/src/helpers/MembershipCharger.ts +69 -69
  158. package/src/helpers/MembershipHelper.ts +11 -12
  159. package/src/helpers/OpenIDConnectHelper.ts +85 -82
  160. package/src/helpers/PeriodHelper.ts +65 -70
  161. package/src/helpers/StripeHelper.ts +146 -137
  162. package/src/helpers/StripePayoutChecker.ts +51 -52
  163. package/src/helpers/ViesHelper.ts +46 -44
  164. package/src/helpers/fetchToAsyncIterator.ts +14 -14
  165. package/src/helpers/xlsxAddressTransformerColumnFactory.ts +50 -52
  166. package/src/middleware/ContextMiddleware.ts +5 -5
  167. package/src/migrations/1646578856-validate-addresses.ts +6 -9
  168. package/src/seeds/0000000000-example.ts +3 -5
  169. package/src/seeds/1715028563-user-permissions.ts +16 -18
  170. package/src/seeds/1722256498-group-update-occupancy.ts +12 -12
  171. package/src/seeds/1722344162-sync-member-users.ts +14 -15
  172. package/src/seeds/1722344162-update-membership.ts +6 -6
  173. package/src/seeds/1726055544-balance-item-paid.ts +4 -4
  174. package/src/seeds/1726055545-balance-item-pending.ts +4 -4
  175. package/src/seeds/1726494419-update-cached-outstanding-balance.ts +16 -16
  176. package/src/seeds/1726494420-update-cached-outstanding-balance-from-items.ts +12 -12
  177. package/src/seeds/1726572303-schedule-stock-updates.ts +12 -12
  178. package/src/seeds/1726847064-setup-steps.ts +16 -0
  179. package/src/sql-filters/balance-item-payments.ts +7 -7
  180. package/src/sql-filters/events.ts +14 -14
  181. package/src/sql-filters/members.ts +96 -96
  182. package/src/sql-filters/organizations.ts +139 -75
  183. package/src/sql-filters/payments.ts +28 -28
  184. package/src/sql-filters/registrations.ts +14 -14
  185. package/src/sql-sorters/events.ts +25 -25
  186. package/src/sql-sorters/members.ts +26 -26
  187. package/src/sql-sorters/organizations.ts +36 -36
  188. package/src/sql-sorters/payments.ts +26 -26
  189. package/tests/e2e/stock.test.ts +616 -621
  190. package/tests/e2e/tickets.test.ts +255 -260
  191. package/tests/helpers/StripeMocker.ts +177 -179
  192. package/tests/helpers/TestServer.ts +9 -9
  193. package/tests/jest.global.setup.ts +14 -13
  194. package/tests/jest.setup.ts +33 -32
  195. package/.eslintrc.js +0 -61
  196. package/jest.config.js +0 -11
  197. package/src/helpers/SetupStepsUpdater.ts +0 -359
  198. package/src/seeds/1724076679-setup-steps.ts +0 -16
@@ -1,7 +1,5 @@
1
- /* eslint-disable @typescript-eslint/no-unsafe-member-access */
2
- /* eslint-disable @typescript-eslint/no-unsafe-assignment */
3
1
  import { MolliePayment, MollieToken, Order, Organization, PayconiqPayment, Payment, StripeAccount } from '@stamhoofd/models';
4
- import { Settlement } from '@stamhoofd/structures'
2
+ import { Settlement } from '@stamhoofd/structures';
5
3
  import axios from 'axios';
6
4
 
7
5
  import { StripePayoutChecker } from './StripePayoutChecker';
@@ -11,108 +9,112 @@ type MollieSettlement = {
11
9
  reference: string;
12
10
  createdAt: string;
13
11
  settledAt: string;
14
- status: "open" | "pending" | "paidout" | "failed";
12
+ status: 'open' | 'pending' | 'paidout' | 'failed';
15
13
  amount: {
16
14
  currenty: string;
17
15
  value: string;
18
- }
19
- }
16
+ };
17
+ };
20
18
 
21
19
  type MolliePaymentJSON = {
22
20
  id: string;
23
- }
21
+ };
24
22
 
25
- let lastSettlementCheck: Date | null = null
23
+ let lastSettlementCheck: Date | null = null;
26
24
 
27
25
  export async function checkAllStripePayouts(checkAll = false) {
28
- if (STAMHOOFD.environment !== "production") {
29
- console.log("Skip settlement check")
30
- return
26
+ if (STAMHOOFD.environment !== 'production') {
27
+ console.log('Skip settlement check');
28
+ return;
31
29
  }
32
-
30
+
33
31
  // Stripe payouts
34
- const stripeAccounts = await StripeAccount.where({ status: 'active' })
32
+ const stripeAccounts = await StripeAccount.where({ status: 'active' });
35
33
  for (const account of stripeAccounts) {
36
34
  try {
37
- console.log("Checking settlements for ", account.accountId)
35
+ console.log('Checking settlements for ', account.accountId);
38
36
 
39
37
  const checker = new StripePayoutChecker({
40
38
  secretKey: STAMHOOFD.STRIPE_SECRET_KEY,
41
- stripeAccount: account.accountId
42
- })
43
- await checker.checkSettlements(checkAll)
44
- } catch (e) {
45
- console.error(e)
39
+ stripeAccount: account.accountId,
40
+ });
41
+ await checker.checkSettlements(checkAll);
42
+ }
43
+ catch (e) {
44
+ console.error(e);
46
45
  }
47
46
  }
48
47
  }
49
48
 
50
49
  export async function checkSettlements(checkAll = false) {
51
- if (STAMHOOFD.environment !== "production") {
52
- return
50
+ if (STAMHOOFD.environment !== 'production') {
51
+ return;
53
52
  }
54
53
 
55
54
  if (!checkAll && lastSettlementCheck && (lastSettlementCheck > new Date(new Date().getTime() - 24 * 60 * 60 * 1000))) {
56
- console.log("Skip settlement check")
57
- return
55
+ console.log('Skip settlement check');
56
+ return;
58
57
  }
59
58
 
60
- console.log("Checking settlements...")
61
- lastSettlementCheck = new Date()
59
+ console.log('Checking settlements...');
60
+ lastSettlementCheck = new Date();
62
61
 
63
62
  // Mollie payment is required
64
- const token = STAMHOOFD.MOLLIE_ORGANIZATION_TOKEN
63
+ const token = STAMHOOFD.MOLLIE_ORGANIZATION_TOKEN;
65
64
  if (!token) {
66
- console.error("Missing mollie organization token")
67
- } else {
68
- await checkMollieSettlementsFor(token, checkAll)
65
+ console.error('Missing mollie organization token');
66
+ }
67
+ else {
68
+ await checkMollieSettlementsFor(token, checkAll);
69
69
  }
70
70
 
71
71
  // Loop all mollie tokens created after given date (when settlement permission was added)
72
72
  try {
73
73
  // Stripe payouts
74
- await checkAllStripePayouts(checkAll)
74
+ await checkAllStripePayouts(checkAll);
75
75
 
76
- const mollieTokens = await MollieToken.all()
76
+ const mollieTokens = await MollieToken.all();
77
77
  for (const token of mollieTokens) {
78
78
  if (token.createdAt < new Date(2021, 8 /* september! */, 8)) {
79
- console.log("Skipped mollie token that is too old")
80
- } else {
79
+ console.log('Skipped mollie token that is too old');
80
+ }
81
+ else {
81
82
  try {
82
- await token.refreshIfNeeded()
83
- await checkMollieSettlementsFor(token.accessToken, checkAll)
84
- } catch (e) {
85
- console.error(e)
83
+ await token.refreshIfNeeded();
84
+ await checkMollieSettlementsFor(token.accessToken, checkAll);
85
+ }
86
+ catch (e) {
87
+ console.error(e);
86
88
  }
87
89
  }
88
90
  }
89
- } catch (e) {
90
- console.error(e)
91
+ }
92
+ catch (e) {
93
+ console.error(e);
91
94
  }
92
95
  }
93
96
 
94
97
  // Check settlements once a week on tuesday morning/night
95
98
  export async function checkMollieSettlementsFor(token: string, checkAll = false) {
96
99
  // Check last 2 weeks + 3 day margin, unless we check them all
97
- const d = new Date()
98
- d.setDate(d.getDate() - 17)
100
+ const d = new Date();
101
+ d.setDate(d.getDate() - 17);
99
102
 
100
- console.log("Checking settlements for given token...")
103
+ console.log('Checking settlements for given token...');
101
104
 
102
105
  // Loop all organizations with online paymetns the last week
103
106
  try {
104
- const request = await axios.get("https://api.mollie.com/v2/settlements?limit="+(checkAll ? 250 : 14), {
107
+ const request = await axios.get('https://api.mollie.com/v2/settlements?limit=' + (checkAll ? 250 : 14), {
105
108
  headers: {
106
- "Authorization": "Bearer "+token
107
- }
108
- })
109
+ Authorization: 'Bearer ' + token,
110
+ },
111
+ });
109
112
  if (request.status === 200) {
110
113
  // get data
111
114
  try {
112
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
113
- const data = request.data
115
+ const data = request.data;
114
116
  // Read the data
115
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
117
+
116
118
  if (data._embedded?.settlements) {
117
119
  const settlements = data._embedded.settlements as MollieSettlement[];
118
120
 
@@ -122,66 +124,68 @@ export async function checkMollieSettlementsFor(token: string, checkAll = false)
122
124
  continue;
123
125
  }
124
126
 
125
- const settledAt = new Date(settlement.settledAt)
126
-
127
+ const settledAt = new Date(settlement.settledAt);
128
+
127
129
  if (isNaN(settledAt.getTime())) {
128
130
  console.error('Received an invalid settledAt from Mollie', settlement, 'for token', token);
129
131
  continue;
130
132
  }
131
133
 
132
134
  if (checkAll || settledAt > d) {
133
- await updateSettlement(token, settlement)
135
+ await updateSettlement(token, settlement);
134
136
  }
135
137
  }
136
- } else {
137
- console.error("Unreadable settlements")
138
138
  }
139
- } catch (e) {
140
- console.error(request.data)
139
+ else {
140
+ console.error('Unreadable settlements');
141
+ }
142
+ }
143
+ catch (e) {
144
+ console.error(request.data);
141
145
  throw e;
142
146
  }
143
-
144
- } else {
145
- console.error("Failed to fetch settlements")
146
- console.error(request.data)
147
147
  }
148
-
149
- } catch (e) {
150
- console.error(e)
148
+ else {
149
+ console.error('Failed to fetch settlements');
150
+ console.error(request.data);
151
+ }
152
+ }
153
+ catch (e) {
154
+ console.error(e);
151
155
  }
152
156
  }
153
157
 
154
158
  async function updateSettlement(token: string, settlement: MollieSettlement, fromPaymentId?: string) {
155
- const limit = 250
159
+ const limit = 250;
156
160
 
157
161
  // Loop all payments of this settlement
158
- const request = await axios.get("https://api.mollie.com/v2/settlements/"+settlement.id+"/payments?limit="+limit+(fromPaymentId ? ("&from="+encodeURIComponent(fromPaymentId)) : ""), {
162
+ const request = await axios.get('https://api.mollie.com/v2/settlements/' + settlement.id + '/payments?limit=' + limit + (fromPaymentId ? ('&from=' + encodeURIComponent(fromPaymentId)) : ''), {
159
163
  headers: {
160
- "Authorization": "Bearer "+token
161
- }
162
- })
164
+ Authorization: 'Bearer ' + token,
165
+ },
166
+ });
163
167
 
164
168
  if (request.status === 200) {
165
- const molliePayments = request.data._embedded.payments as MolliePaymentJSON[]
169
+ const molliePayments = request.data._embedded.payments as MolliePaymentJSON[];
166
170
 
167
171
  for (const mollie of molliePayments) {
168
172
  // Search payment
169
- const mps = await MolliePayment.where({ mollieId: mollie.id })
173
+ const mps = await MolliePayment.where({ mollieId: mollie.id });
170
174
  if (mps.length == 1) {
171
- const mp = mps[0]
172
- const payment = await Payment.getByID(mp.paymentId)
175
+ const mp = mps[0];
176
+ const payment = await Payment.getByID(mp.paymentId);
173
177
  if (payment) {
174
178
  payment.settlement = Settlement.create({
175
179
  id: settlement.id,
176
180
  reference: settlement.reference,
177
181
  settledAt: new Date(settlement.settledAt),
178
- amount: Math.round(parseFloat(settlement.amount.value)*100)
179
- })
180
- const saved = await payment.save()
182
+ amount: Math.round(parseFloat(settlement.amount.value) * 100),
183
+ });
184
+ const saved = await payment.save();
181
185
 
182
186
  if (saved) {
183
187
  // Mark order as 'updated', or the frontend won't pull in the updates
184
- const order = await Order.getForPayment(null, payment.id)
188
+ const order = await Order.getForPayment(null, payment.id);
185
189
  if (order) {
186
190
  order.updatedAt = new Date();
187
191
  order.forceSaveProperty('updatedAt');
@@ -190,26 +194,28 @@ async function updateSettlement(token: string, settlement: MollieSettlement, fro
190
194
 
191
195
  // TODO: Mark registrations as 'saved'
192
196
  }
193
-
194
197
 
195
- if (STAMHOOFD.environment === "development") {
196
- console.log("Updated settlement of payment "+payment.id)
197
- console.log(payment.settlement)
198
+ if (STAMHOOFD.environment === 'development') {
199
+ console.log('Updated settlement of payment ' + payment.id);
200
+ console.log(payment.settlement);
198
201
  }
199
- } else {
200
- console.log("Missing payment "+mp.paymentId)
201
202
  }
202
- } else {
203
+ else {
204
+ console.log('Missing payment ' + mp.paymentId);
205
+ }
206
+ }
207
+ else {
203
208
  // Probably a payment in a different system/platform
204
- //console.log("No mollie payment found for id "+mollie.id)
209
+ // console.log("No mollie payment found for id "+mollie.id)
205
210
  }
206
211
  }
207
212
 
208
213
  // Check next page
209
214
  if (request.data._links.next) {
210
- await updateSettlement(token, settlement, molliePayments[molliePayments.length - 1].id)
215
+ await updateSettlement(token, settlement, molliePayments[molliePayments.length - 1].id);
211
216
  }
212
- } else {
213
- console.error(request.data)
214
217
  }
215
- }
218
+ else {
219
+ console.error(request.data);
220
+ }
221
+ }
@@ -1,44 +1,44 @@
1
- import { Request } from "@simonbackx/simple-endpoints";
2
- import { SimpleError } from "@simonbackx/simple-errors";
3
- import { I18n } from "@stamhoofd/backend-i18n";
4
- import { Organization, Platform, RateLimiter, Token, User } from "@stamhoofd/models";
5
- import { AsyncLocalStorage } from "async_hooks";
1
+ import { Request } from '@simonbackx/simple-endpoints';
2
+ import { SimpleError } from '@simonbackx/simple-errors';
3
+ import { I18n } from '@stamhoofd/backend-i18n';
4
+ import { Organization, Platform, RateLimiter, Token, User } from '@stamhoofd/models';
5
+ import { AsyncLocalStorage } from 'async_hooks';
6
6
 
7
- import { AdminPermissionChecker } from "./AdminPermissionChecker";
7
+ import { AdminPermissionChecker } from './AdminPermissionChecker';
8
8
 
9
9
  export const apiUserRateLimiter = new RateLimiter({
10
10
  limits: [
11
- {
11
+ {
12
12
  // Block heavy bursts (5req/s for 5s)
13
13
  limit: 25,
14
- duration: 5 * 1000
14
+ duration: 5 * 1000,
15
15
  },
16
- {
16
+ {
17
17
  // max 1req/s during 150s
18
18
  limit: 150,
19
- duration: 150 * 1000
19
+ duration: 150 * 1000,
20
20
  },
21
- {
21
+ {
22
22
  // 1000 requests per hour
23
23
  limit: 1000,
24
- duration: 60 * 1000 * 60
24
+ duration: 60 * 1000 * 60,
25
25
  },
26
- {
26
+ {
27
27
  // 2000 requests per day
28
28
  limit: 2000,
29
- duration: 24 * 60 * 1000 * 60
30
- }
31
- ]
29
+ duration: 24 * 60 * 1000 * 60,
30
+ },
31
+ ],
32
32
  });
33
33
 
34
34
  export class ContextInstance {
35
- request: Request
35
+ request: Request;
36
36
 
37
- user?: User
38
- organization?: Organization
37
+ user?: User;
38
+ organization?: Organization;
39
39
 
40
- #i18n: I18n|null = null
41
- #auth: AdminPermissionChecker|null = null
40
+ #i18n: I18n | null = null;
41
+ #auth: AdminPermissionChecker | null = null;
42
42
 
43
43
  constructor(request: Request) {
44
44
  this.request = request;
@@ -53,31 +53,31 @@ export class ContextInstance {
53
53
  throw new SimpleError({
54
54
  code: 'no_context',
55
55
  message: 'No context found',
56
- statusCode: 500
57
- })
56
+ statusCode: 500,
57
+ });
58
58
  }
59
59
 
60
60
  return c;
61
61
  }
62
62
 
63
- static async startForUser<T>(user: User, organization: Organization|null, handler: () => Promise<T>): Promise<T> {
63
+ static async startForUser<T>(user: User, organization: Organization | null, handler: () => Promise<T>): Promise<T> {
64
64
  const request = new Request({
65
65
  method: 'GET',
66
66
  url: '/',
67
- host: ''
68
- })
67
+ host: '',
68
+ });
69
69
  const context = new ContextInstance(request);
70
70
 
71
71
  if (organization) {
72
- context.organization = organization
73
- context.i18n.switchToLocale({ country: organization.address.country })
72
+ context.organization = organization;
73
+ context.i18n.switchToLocale({ country: organization.address.country });
74
74
  }
75
75
 
76
- context.user = user
76
+ context.user = user;
77
77
  context.#auth = new AdminPermissionChecker(user, await Platform.getSharedPrivateStruct(), context.organization);
78
78
 
79
79
  return await this.asyncLocalStorage.run(context, async () => {
80
- return await handler()
80
+ return await handler();
81
81
  });
82
82
  }
83
83
 
@@ -85,19 +85,19 @@ export class ContextInstance {
85
85
  const context = new ContextInstance(request);
86
86
 
87
87
  return await this.asyncLocalStorage.run(context, async () => {
88
- return await handler()
88
+ return await handler();
89
89
  });
90
90
  }
91
91
 
92
92
  get version() {
93
- return this.request.getVersion()
93
+ return this.request.getVersion();
94
94
  }
95
95
 
96
96
  get i18n() {
97
97
  if (!this.#i18n) {
98
- this.#i18n = I18n.fromRequest(this.request)
98
+ this.#i18n = I18n.fromRequest(this.request);
99
99
  }
100
- return this.#i18n
100
+ return this.#i18n;
101
101
  }
102
102
 
103
103
  get auth() {
@@ -105,21 +105,22 @@ export class ContextInstance {
105
105
  throw new SimpleError({
106
106
  code: 'internal_error',
107
107
  statusCode: 500,
108
- message: 'AdminPermissionChecker not set in RequestContext: make sure the request is authenticated before using the permissionChecker'
109
- })
108
+ message: 'AdminPermissionChecker not set in RequestContext: make sure the request is authenticated before using the permissionChecker',
109
+ });
110
110
  }
111
- return this.#auth
111
+ return this.#auth;
112
112
  }
113
113
 
114
114
  get optionalAuth() {
115
- return this.#auth
115
+ return this.#auth;
116
116
  }
117
117
 
118
118
  async setOptionalOrganizationScope() {
119
119
  try {
120
- return await this.setOrganizationScope()
121
- } catch (e) {
122
- return null
120
+ return await this.setOrganizationScope();
121
+ }
122
+ catch (e) {
123
+ return null;
123
124
  }
124
125
  }
125
126
 
@@ -130,89 +131,89 @@ export class ContextInstance {
130
131
  if (STAMHOOFD.userMode === 'platform') {
131
132
  return null;
132
133
  }
133
- return await this.setOrganizationScope()
134
+ return await this.setOrganizationScope();
134
135
  }
135
136
 
136
- async setOrganizationScope(options?: {allowInactive?: boolean}) {
137
+ async setOrganizationScope(options?: { allowInactive?: boolean }) {
137
138
  const organization = await Organization.fromApiHost(this.request.host, options);
138
139
 
139
- this.organization = organization
140
- this.i18n.switchToLocale({ country: organization.address.country })
140
+ this.organization = organization;
141
+ this.i18n.switchToLocale({ country: organization.address.country });
141
142
 
142
- return organization
143
+ return organization;
143
144
  }
144
145
 
145
- async optionalAuthenticate({allowWithoutAccount = false}: {allowWithoutAccount?: boolean} = {}): Promise<{user?: User}> {
146
- const header = this.request.headers.authorization
146
+ async optionalAuthenticate({ allowWithoutAccount = false }: { allowWithoutAccount?: boolean } = {}): Promise<{ user?: User }> {
147
+ const header = this.request.headers.authorization;
147
148
  if (!header) {
148
- return {}
149
+ return {};
149
150
  }
150
- return this.authenticate({allowWithoutAccount})
151
+ return this.authenticate({ allowWithoutAccount });
151
152
  }
152
153
 
153
- async authenticate({allowWithoutAccount = false}: {allowWithoutAccount?: boolean} = {}): Promise<{user: User, token: Token}> {
154
- const header = this.request.headers.authorization
154
+ async authenticate({ allowWithoutAccount = false }: { allowWithoutAccount?: boolean } = {}): Promise<{ user: User; token: Token }> {
155
+ const header = this.request.headers.authorization;
155
156
  if (!header) {
156
157
  throw new SimpleError({
157
- code: "not_authenticated",
158
- message: "Missing required authorization header",
159
- statusCode: 401
160
- })
158
+ code: 'not_authenticated',
159
+ message: 'Missing required authorization header',
160
+ statusCode: 401,
161
+ });
161
162
  }
162
163
 
163
- if (!header.startsWith("Bearer ")) {
164
+ if (!header.startsWith('Bearer ')) {
164
165
  throw new SimpleError({
165
- code: "not_supported_authentication",
166
- message: "Authentication method not supported. Please authenticate with OAuth2",
167
- statusCode: 401
168
- })
166
+ code: 'not_supported_authentication',
167
+ message: 'Authentication method not supported. Please authenticate with OAuth2',
168
+ statusCode: 401,
169
+ });
169
170
  }
170
171
 
171
- const accessToken = header.substring("Bearer ".length);
172
+ const accessToken = header.substring('Bearer '.length);
173
+
174
+ const token = await Token.getByAccessToken(accessToken, true);
172
175
 
173
- const token = await Token.getByAccessToken(accessToken, true)
174
-
175
176
  if (!token || (this.organization && token.user.organizationId !== null && token.user.organizationId !== this.organization.id) || (!this.organization && token.user.organizationId)) {
176
177
  throw new SimpleError({
177
- code: "invalid_access_token",
178
- message: "The access token is invalid",
179
- human: "Je bent automatisch uitgelogd, log opnieuw in om verder te gaan",
180
- statusCode: 401
181
- })
178
+ code: 'invalid_access_token',
179
+ message: 'The access token is invalid',
180
+ human: 'Je bent automatisch uitgelogd, log opnieuw in om verder te gaan',
181
+ statusCode: 401,
182
+ });
182
183
  }
183
-
184
+
184
185
  if (token.isAccessTokenExpired()) {
185
186
  throw new SimpleError({
186
- code: "expired_access_token",
187
- message: "The access token is expired",
188
- human: "Je bent automatisch uitgelogd, log opnieuw in om verder te gaan",
189
- statusCode: 401
190
- })
187
+ code: 'expired_access_token',
188
+ message: 'The access token is expired',
189
+ human: 'Je bent automatisch uitgelogd, log opnieuw in om verder te gaan',
190
+ statusCode: 401,
191
+ });
191
192
  }
192
193
 
193
194
  if (!token.user.hasAccount() && !allowWithoutAccount) {
194
195
  throw new SimpleError({
195
- code: "not_activated",
196
- message: "This user is not yet activated",
197
- human: "Maak een account aan op dit e-mailadres om een wachtwoord in te stellen voor je inlogt.",
198
- statusCode: 401
199
- })
196
+ code: 'not_activated',
197
+ message: 'This user is not yet activated',
198
+ human: 'Maak een account aan op dit e-mailadres om een wachtwoord in te stellen voor je inlogt.',
199
+ statusCode: 401,
200
+ });
200
201
  }
201
202
 
202
203
  // Rate limits for api users
203
204
  if (token.user.isApiUser) {
204
- apiUserRateLimiter.track(this.organization?.id ?? token.user.id)
205
+ apiUserRateLimiter.track(this.organization?.id ?? token.user.id);
205
206
  }
206
207
 
207
- const user = token.user
208
- this.user = user
208
+ const user = token.user;
209
+ this.user = user;
209
210
 
210
211
  // Load member of user
211
212
  // todo
212
213
 
213
214
  this.#auth = new AdminPermissionChecker(user, await Platform.getSharedPrivateStruct(), this.organization);
214
215
 
215
- return {user, token};
216
+ return { user, token };
216
217
  }
217
218
  }
218
219
 
@@ -220,8 +221,8 @@ export const Context = new Proxy(ContextInstance, {
220
221
  get(target, prop, receiver) {
221
222
  const c = target.current[prop];
222
223
  if (c && typeof c == 'function') {
223
- return c.bind(target.current)
224
+ return c.bind(target.current);
224
225
  }
225
226
  return c;
226
- }
227
+ },
227
228
  }) as unknown as ContextInstance;