@stamhoofd/backend 2.118.1 → 2.120.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 (362) hide show
  1. package/package.json +32 -22
  2. package/src/audit-logs/ModelLogger.ts +4 -2
  3. package/src/audit-logs/OrderLogger.ts +1 -1
  4. package/src/boot.ts +32 -14
  5. package/src/crons/balance-emails.ts +4 -2
  6. package/src/crons/clearExcelCache.test.ts +8 -8
  7. package/src/crons/update-cached-balances.ts +40 -14
  8. package/src/debug.ts +3 -2
  9. package/src/decoders/StringArrayDecoder.ts +1 -1
  10. package/src/decoders/StringNullableDecoder.ts +1 -1
  11. package/src/email-recipient-loaders/documents.ts +2 -1
  12. package/src/email-recipient-loaders/members.ts +2 -1
  13. package/src/email-recipient-loaders/orders.ts +2 -1
  14. package/src/email-recipient-loaders/payments.ts +6 -3
  15. package/src/email-recipient-loaders/receivable-balances.ts +2 -1
  16. package/src/email-recipient-loaders/registrations.ts +2 -1
  17. package/src/email-replacements/getEmailReplacementsForPayment.ts +8 -7
  18. package/src/endpoints/admin/members/ChargeMembersEndpoint.ts +7 -6
  19. package/src/endpoints/admin/memberships/ChargeMembershipsEndpoint.ts +3 -2
  20. package/src/endpoints/admin/memberships/GetChargeMembershipsSummaryEndpoint.ts +2 -1
  21. package/src/endpoints/admin/organizations/ChargeOrganizationsEndpoint.ts +4 -3
  22. package/src/endpoints/admin/organizations/GetOrganizationsCountEndpoint.ts +3 -2
  23. package/src/endpoints/admin/organizations/GetOrganizationsEndpoint.ts +7 -5
  24. package/src/endpoints/admin/organizations/PatchOrganizationsEndpoint.ts +12 -10
  25. package/src/endpoints/admin/registrations/ChargeRegistrationsEndpoint.ts +4 -3
  26. package/src/endpoints/auth/CreateAdminEndpoint.ts +8 -6
  27. package/src/endpoints/auth/CreateTokenEndpoint.ts +14 -12
  28. package/src/endpoints/auth/DeleteTokenEndpoint.ts +2 -1
  29. package/src/endpoints/auth/DeleteUserEndpoint.ts +2 -1
  30. package/src/endpoints/auth/ForgotPasswordEndpoint.ts +5 -4
  31. package/src/endpoints/auth/GetOtherUserEndpoint.ts +3 -2
  32. package/src/endpoints/auth/GetUserEndpoint.ts +3 -2
  33. package/src/endpoints/auth/OpenIDConnectAuthTokenEndpoint.ts +2 -1
  34. package/src/endpoints/auth/OpenIDConnectCallbackEndpoint.ts +4 -2
  35. package/src/endpoints/auth/OpenIDConnectStartEndpoint.ts +3 -2
  36. package/src/endpoints/auth/PatchUserEndpoint.ts +15 -12
  37. package/src/endpoints/auth/PollEmailVerificationEndpoint.ts +3 -2
  38. package/src/endpoints/auth/RetryEmailVerificationEndpoint.ts +3 -2
  39. package/src/endpoints/auth/SignupEndpoint.ts +5 -4
  40. package/src/endpoints/auth/VerifyEmailEndpoint.ts +6 -5
  41. package/src/endpoints/frontend/FrontendEnvironmentEndpoint.ts +3 -2
  42. package/src/endpoints/global/addresses/SearchRegionsEndpoint.ts +8 -5
  43. package/src/endpoints/global/addresses/ValidateAddressEndpoint.ts +5 -3
  44. package/src/endpoints/global/audit-logs/GetAuditLogsEndpoint.ts +8 -5
  45. package/src/endpoints/global/billing/ActivatePackagesEndpoint.ts +9 -7
  46. package/src/endpoints/global/billing/DeactivatePackageEndpoint.ts +4 -3
  47. package/src/endpoints/global/caddy/CheckDomainCertEndpoint.ts +4 -2
  48. package/src/endpoints/global/email/CreateEmailEndpoint.ts +9 -7
  49. package/src/endpoints/global/email/GetAdminEmailsEndpoint.test.ts +2 -1
  50. package/src/endpoints/global/email/GetAdminEmailsEndpoint.ts +22 -19
  51. package/src/endpoints/global/email/GetEmailAddressEndpoint.ts +6 -4
  52. package/src/endpoints/global/email/GetEmailEndpoint.ts +4 -3
  53. package/src/endpoints/global/email/GetUserEmailsEndpoint.test.ts +3 -2
  54. package/src/endpoints/global/email/GetUserEmailsEndpoint.ts +7 -4
  55. package/src/endpoints/global/email/ManageEmailAddressEndpoint.ts +7 -5
  56. package/src/endpoints/global/email/PatchEmailEndpoint.test.ts +11 -11
  57. package/src/endpoints/global/email/PatchEmailEndpoint.ts +14 -11
  58. package/src/endpoints/global/email-recipients/GetEmailRecipientsCountEndpoint.ts +3 -2
  59. package/src/endpoints/global/email-recipients/GetEmailRecipientsEndpoint.test.ts +2 -1
  60. package/src/endpoints/global/email-recipients/GetEmailRecipientsEndpoint.ts +8 -5
  61. package/src/endpoints/global/email-recipients/RetryEmailRecipientEndpoint.ts +7 -5
  62. package/src/endpoints/global/email-recipients/helpers/validateEmailRecipientFilter.ts +4 -3
  63. package/src/endpoints/global/events/GetEventNotificationsCountEndpoint.ts +3 -2
  64. package/src/endpoints/global/events/GetEventNotificationsEndpoint.ts +9 -6
  65. package/src/endpoints/global/events/GetEventsEndpoint.ts +7 -4
  66. package/src/endpoints/global/events/PatchEventNotificationsEndpoint.test.ts +4 -2
  67. package/src/endpoints/global/events/PatchEventNotificationsEndpoint.ts +17 -15
  68. package/src/endpoints/global/events/PatchEventsEndpoint.test.ts +4 -2
  69. package/src/endpoints/global/events/PatchEventsEndpoint.ts +28 -26
  70. package/src/endpoints/global/files/ExportToExcelEndpoint.ts +8 -5
  71. package/src/endpoints/global/files/GetFileCache.ts +5 -3
  72. package/src/endpoints/global/files/UploadFile.ts +10 -4
  73. package/src/endpoints/global/files/UploadImage.ts +4 -2
  74. package/src/endpoints/global/groups/GetGroupsEndpoint.test.ts +4 -2
  75. package/src/endpoints/global/groups/GetGroupsEndpoint.ts +8 -5
  76. package/src/endpoints/global/members/GetMemberFamilyEndpoint.ts +7 -5
  77. package/src/endpoints/global/members/GetMembersCountEndpoint.ts +3 -2
  78. package/src/endpoints/global/members/GetMembersEndpoint.test.ts +4 -2
  79. package/src/endpoints/global/members/GetMembersEndpoint.ts +10 -8
  80. package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.test.ts +257 -6
  81. package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.ts +162 -107
  82. package/src/endpoints/global/members/helpers/validateGroupFilter.ts +4 -3
  83. package/src/endpoints/global/members/shouldCheckIfMemberIsDuplicate.ts +3 -2
  84. package/src/endpoints/global/organizations/CheckRegisterCodeEndpoint.ts +3 -2
  85. package/src/endpoints/global/organizations/CreateOrganizationEndpoint.test.ts +3 -2
  86. package/src/endpoints/global/organizations/CreateOrganizationEndpoint.ts +8 -7
  87. package/src/endpoints/global/organizations/GetOrganizationFromDomainEndpoint.ts +5 -3
  88. package/src/endpoints/global/organizations/GetOrganizationFromUriEndpoint.ts +5 -3
  89. package/src/endpoints/global/organizations/SearchOrganizationEndpoint.ts +8 -5
  90. package/src/endpoints/global/payments/StripeWebhookEndpoint.ts +4 -2
  91. package/src/endpoints/global/platform/GetPlatformAdminsEndpoint.ts +2 -1
  92. package/src/endpoints/global/platform/GetPlatformEndpoint.ts +3 -2
  93. package/src/endpoints/global/platform/PatchPlatformEnpoint.test.ts +3 -2
  94. package/src/endpoints/global/platform/PatchPlatformEnpoint.ts +7 -4
  95. package/src/endpoints/global/platform-memberships/GetPlatformMembershipsCountEndpoint.ts +47 -0
  96. package/src/endpoints/global/platform-memberships/GetPlatformMembershipsEndpoint.ts +206 -0
  97. package/src/endpoints/global/registration/GetRegistrationsCountEndpoint.ts +3 -2
  98. package/src/endpoints/global/registration/GetRegistrationsEndpoint.test.ts +2 -1
  99. package/src/endpoints/global/registration/GetRegistrationsEndpoint.ts +10 -7
  100. package/src/endpoints/global/registration/GetUserDetailedPayableBalanceEndpoint.ts +4 -2
  101. package/src/endpoints/global/registration/GetUserDocumentsEndpoint.ts +4 -2
  102. package/src/endpoints/global/registration/GetUserMembersEndpoint.ts +3 -2
  103. package/src/endpoints/global/registration/GetUserPayableBalanceEndpoint.ts +2 -1
  104. package/src/endpoints/global/registration/PatchUserMembersEndpoint.test.ts +5 -3
  105. package/src/endpoints/global/registration/PatchUserMembersEndpoint.ts +13 -9
  106. package/src/endpoints/global/registration/RegisterMembersEndpoint.test.ts +50 -49
  107. package/src/endpoints/global/registration/RegisterMembersEndpoint.ts +25 -22
  108. package/src/endpoints/global/registration-periods/GetRegistrationPeriodsEndpoint.ts +8 -5
  109. package/src/endpoints/global/registration-periods/PatchRegistrationPeriodsEndpoint.ts +9 -7
  110. package/src/endpoints/global/sso/GetSSOEndpoint.ts +4 -2
  111. package/src/endpoints/global/sso/SetSSOEndpoint.ts +3 -2
  112. package/src/endpoints/global/webshops/GetWebshopFromDomainEndpoint.ts +4 -2
  113. package/src/endpoints/global/webshops/GetWebshopsCountEndpoint.ts +43 -0
  114. package/src/endpoints/global/webshops/GetWebshopsEndpoint.test.ts +808 -0
  115. package/src/endpoints/global/webshops/GetWebshopsEndpoint.ts +221 -0
  116. package/src/endpoints/organization/dashboard/balance-items/GetBalanceItemEndpoint.ts +4 -3
  117. package/src/endpoints/organization/dashboard/balance-items/GetBalanceItemsCountEndpoint.ts +3 -2
  118. package/src/endpoints/organization/dashboard/balance-items/GetBalanceItemsEndpoint.ts +6 -4
  119. package/src/endpoints/organization/dashboard/balance-items/PatchBalanceItemsEndpoint.ts +15 -13
  120. package/src/endpoints/organization/dashboard/billing/GetOrganizationDetailedPayableBalanceEndpoint.ts +4 -2
  121. package/src/endpoints/organization/dashboard/billing/GetOrganizationPayableBalanceEndpoint.ts +4 -2
  122. package/src/endpoints/organization/dashboard/billing/GetPackagesEndpoint.ts +2 -1
  123. package/src/endpoints/organization/dashboard/documents/GetDocumentTemplateXML.ts +3 -2
  124. package/src/endpoints/organization/dashboard/documents/GetDocumentTemplatesCountEndpoint.ts +3 -2
  125. package/src/endpoints/organization/dashboard/documents/GetDocumentTemplatesEndpoint.ts +7 -4
  126. package/src/endpoints/organization/dashboard/documents/GetDocumentsCountEndpoint.ts +3 -2
  127. package/src/endpoints/organization/dashboard/documents/GetDocumentsEndpoint.ts +7 -4
  128. package/src/endpoints/organization/dashboard/documents/PatchDocumentEndpoint.ts +9 -7
  129. package/src/endpoints/organization/dashboard/documents/PatchDocumentTemplatesEndpoint.test.ts +4 -2
  130. package/src/endpoints/organization/dashboard/documents/PatchDocumentTemplatesEndpoint.ts +7 -5
  131. package/src/endpoints/organization/dashboard/email/CheckEmailBouncesEndpoint.ts +3 -2
  132. package/src/endpoints/organization/dashboard/email-templates/GetEmailTemplatesEndpoint.test.ts +36 -1
  133. package/src/endpoints/organization/dashboard/email-templates/GetEmailTemplatesEndpoint.ts +13 -4
  134. package/src/endpoints/organization/dashboard/email-templates/PatchEmailTemplatesEndpoint.test.ts +4 -2
  135. package/src/endpoints/organization/dashboard/email-templates/PatchEmailTemplatesEndpoint.ts +7 -5
  136. package/src/endpoints/organization/dashboard/invoices/GetInvoicesCountEndpoint.ts +3 -2
  137. package/src/endpoints/organization/dashboard/invoices/GetInvoicesEndpoint.ts +6 -4
  138. package/src/endpoints/organization/dashboard/invoices/PatchInvoicesEndpoint.ts +5 -3
  139. package/src/endpoints/organization/dashboard/mollie/CheckMollieEndpoint.ts +4 -2
  140. package/src/endpoints/organization/dashboard/mollie/ConnectMollieEndpoint.ts +6 -3
  141. package/src/endpoints/organization/dashboard/mollie/DisconnectMollieEndpoint.ts +4 -2
  142. package/src/endpoints/organization/dashboard/mollie/GetMollieDashboardEndpoint.ts +2 -1
  143. package/src/endpoints/organization/dashboard/nolt/CreateNoltTokenEndpoint.ts +2 -1
  144. package/src/endpoints/organization/dashboard/organization/GetOrganizationArchivedGroups.ts +4 -2
  145. package/src/endpoints/organization/dashboard/organization/GetOrganizationDeletedGroups.ts +3 -2
  146. package/src/endpoints/organization/dashboard/organization/GetUitpasClientIdEndpoint.ts +2 -1
  147. package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.test.ts +5 -3
  148. package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.ts +22 -19
  149. package/src/endpoints/organization/dashboard/organization/SearchUitpasOrganizersEndpoint.ts +5 -3
  150. package/src/endpoints/organization/dashboard/organization/SetOrganizationDomainEndpoint.ts +11 -9
  151. package/src/endpoints/organization/dashboard/organization/SetUitpasClientCredentialsEndpoint.ts +8 -7
  152. package/src/endpoints/organization/dashboard/payments/GetMemberBalanceEndpoint.ts +2 -1
  153. package/src/endpoints/organization/dashboard/payments/GetPaymentsCountEndpoint.ts +3 -2
  154. package/src/endpoints/organization/dashboard/payments/GetPaymentsEndpoint.ts +7 -5
  155. package/src/endpoints/organization/dashboard/payments/PatchPaymentsEndpoint.ts +18 -16
  156. package/src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalanceEndpoint.ts +2 -1
  157. package/src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalancesCountEndpoint.ts +3 -2
  158. package/src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalancesEndpoint.ts +5 -3
  159. package/src/endpoints/organization/dashboard/registration-periods/GetOrganizationRegistrationPeriodsEndpoint.test.ts +2 -1
  160. package/src/endpoints/organization/dashboard/registration-periods/GetOrganizationRegistrationPeriodsEndpoint.ts +8 -5
  161. package/src/endpoints/organization/dashboard/registration-periods/MoveRegistrationPeriods.test.ts +4 -2
  162. package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.test.ts +4 -2
  163. package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.ts +32 -29
  164. package/src/endpoints/organization/dashboard/registration-periods/SetupStepReviewEndpoint.ts +6 -3
  165. package/src/endpoints/organization/dashboard/stripe/ConnectStripeEndpoint.ts +3 -2
  166. package/src/endpoints/organization/dashboard/stripe/DeleteStripeAccountEndpoint.ts +3 -2
  167. package/src/endpoints/organization/dashboard/stripe/GetStripeAccountLinkEndpoint.ts +5 -3
  168. package/src/endpoints/organization/dashboard/stripe/GetStripeAccountsEndpoint.ts +2 -1
  169. package/src/endpoints/organization/dashboard/stripe/GetStripeLoginLinkEndpoint.ts +5 -3
  170. package/src/endpoints/organization/dashboard/stripe/UpdateStripeAccountEndpoint.ts +3 -2
  171. package/src/endpoints/organization/dashboard/users/CreateApiUserEndpoint.ts +4 -3
  172. package/src/endpoints/organization/dashboard/users/DeleteUserEndpoint.ts +4 -3
  173. package/src/endpoints/organization/dashboard/users/GetApiUsersEndpoint.ts +3 -2
  174. package/src/endpoints/organization/dashboard/users/GetOrganizationAdminsEndpoint.ts +2 -1
  175. package/src/endpoints/organization/dashboard/users/PatchApiUserEndpoint.ts +6 -4
  176. package/src/endpoints/organization/dashboard/webshops/CreateWebshopEndpoint.ts +7 -6
  177. package/src/endpoints/organization/dashboard/webshops/DeleteWebshopEndpoint.ts +3 -2
  178. package/src/endpoints/organization/dashboard/webshops/GetDiscountCodesEndpoint.ts +4 -2
  179. package/src/endpoints/organization/dashboard/webshops/GetWebshopOrdersCountEndpoint.ts +3 -2
  180. package/src/endpoints/organization/dashboard/webshops/GetWebshopOrdersEndpoint.ts +7 -4
  181. package/src/endpoints/organization/dashboard/webshops/{GetWebshopTicketsCountEndpoint → GetWebshopTicketsCountEndpoint.ts} +7 -7
  182. package/src/endpoints/organization/dashboard/webshops/GetWebshopTicketsEndpoint.ts +9 -6
  183. package/src/endpoints/organization/dashboard/webshops/GetWebshopUriAvailabilityEndpoint.ts +4 -2
  184. package/src/endpoints/organization/dashboard/webshops/PatchDiscountCodesEndpoint.ts +6 -4
  185. package/src/endpoints/organization/dashboard/webshops/PatchWebshopEndpoint.ts +13 -12
  186. package/src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.ts +4 -2
  187. package/src/endpoints/organization/dashboard/webshops/PatchWebshopTicketsEndpoint.ts +5 -3
  188. package/src/endpoints/organization/dashboard/webshops/SearchUitpasEventsEndpoint.ts +6 -4
  189. package/src/endpoints/organization/dashboard/webshops/VerifyWebshopDomainEndpoint.ts +2 -1
  190. package/src/endpoints/organization/shared/ExchangePaymentEndpoint.ts +6 -4
  191. package/src/endpoints/organization/shared/GetDocumentHtml.ts +4 -3
  192. package/src/endpoints/organization/shared/GetPaymentEndpoint.ts +4 -3
  193. package/src/endpoints/organization/shared/GetUitpasNumberDetailsEndpoint.ts +3 -2
  194. package/src/endpoints/organization/shared/auth/GetOrganizationEndpoint.ts +3 -2
  195. package/src/endpoints/organization/webshops/CheckWebshopDiscountCodesEndpoint.ts +4 -3
  196. package/src/endpoints/organization/webshops/GetOrderByPaymentEndpoint.ts +5 -4
  197. package/src/endpoints/organization/webshops/GetOrderEndpoint.ts +4 -3
  198. package/src/endpoints/organization/webshops/GetTicketsEndpoint.ts +7 -5
  199. package/src/endpoints/organization/webshops/GetWebshopEndpoint.ts +4 -3
  200. package/src/endpoints/organization/webshops/PlaceOrderEndpoint.test.ts +7 -3
  201. package/src/endpoints/organization/webshops/PlaceOrderEndpoint.ts +11 -10
  202. package/src/endpoints/organization/webshops/RetrieveUitpasSocialTariffPriceEndpoint.ts +5 -4
  203. package/src/endpoints/system/HealthEndpoint.test.ts +44 -0
  204. package/src/endpoints/system/HealthEndpoint.ts +14 -6
  205. package/src/excel-loaders/balance-items.ts +19 -17
  206. package/src/excel-loaders/event-notifications.ts +15 -13
  207. package/src/excel-loaders/index.ts +1 -0
  208. package/src/excel-loaders/members.ts +45 -43
  209. package/src/excel-loaders/organizations.ts +26 -25
  210. package/src/excel-loaders/payments.ts +44 -42
  211. package/src/excel-loaders/platform-memberships.ts +202 -0
  212. package/src/excel-loaders/receivable-balances.ts +25 -23
  213. package/src/excel-loaders/registrations.ts +30 -28
  214. package/src/helpers/AddressValidator.test.ts +2 -1
  215. package/src/helpers/AddressValidator.ts +13 -10
  216. package/src/helpers/AdminPermissionChecker.ts +193 -95
  217. package/src/helpers/AuthenticatedStructures.ts +13 -11
  218. package/src/helpers/BuckarooHelper.ts +3 -2
  219. package/src/helpers/Context.ts +8 -6
  220. package/src/helpers/CookieHelper.ts +2 -2
  221. package/src/helpers/FileCache.ts +9 -9
  222. package/src/helpers/ForwardHandler.ts +3 -2
  223. package/src/helpers/GlobalHelper.ts +2 -0
  224. package/src/helpers/GroupBuilder.ts +2 -1
  225. package/src/helpers/GroupedThrottledQueue.test.ts +19 -19
  226. package/src/helpers/LimitedFilteredRequestHelper.ts +1 -1
  227. package/src/helpers/MemberCharger.ts +2 -1
  228. package/src/helpers/MemberUserSyncer.ts +6 -3
  229. package/src/helpers/MembershipCharger.ts +2 -2
  230. package/src/helpers/OrganizationCharger.ts +2 -1
  231. package/src/helpers/PeriodHelper.ts +2 -1
  232. package/src/helpers/SQLTranslatedString.ts +3 -2
  233. package/src/helpers/ServiceFeeHelper.ts +1 -1
  234. package/src/helpers/SetupStepUpdater.ts +6 -5
  235. package/src/helpers/StripeHelper.ts +9 -8
  236. package/src/helpers/TagHelper.test.ts +5 -5
  237. package/src/helpers/TagHelper.ts +2 -1
  238. package/src/helpers/TemporaryMemberAccess.ts +2 -1
  239. package/src/helpers/ThrottledQueue.test.ts +20 -20
  240. package/src/helpers/UitpasTokenRepository.ts +7 -7
  241. package/src/helpers/ViesHelper.ts +5 -4
  242. package/src/helpers/XlsxTransformerColumnHelper.ts +21 -19
  243. package/src/helpers/email-html-helpers.ts +13 -12
  244. package/src/helpers/fetchToAsyncIterator.ts +1 -1
  245. package/src/helpers/outstandingBalanceJoin.ts +2 -1
  246. package/src/helpers/updateMemberDetailsUitpasNumber.ts +5 -4
  247. package/src/middleware/ContextMiddleware.ts +1 -1
  248. package/src/migrate.ts +21 -4
  249. package/src/seeds/0000000003-default-email-templates.ts +1 -1
  250. package/src/seeds/0000000004-single-organization.ts +2 -1
  251. package/src/seeds/1752848561-groups-registration-periods.ts +3 -2
  252. package/src/seeds/1754560914-groups-prices.test.ts +2 -1
  253. package/src/seeds/1754560914-groups-prices.ts +2 -1
  254. package/src/seeds/1755790070-fill-email-recipient-errors.ts +6 -6
  255. package/src/seeds/1755876819-remove-duplicate-members.ts +2 -1
  256. package/src/seeds/1765896674-document-update-year.test.ts +2 -1
  257. package/src/seeds/1773754928-force-save-members.ts +15 -0
  258. package/src/services/AuditLogService.ts +3 -2
  259. package/src/services/BalanceItemPaymentService.ts +2 -2
  260. package/src/services/BalanceItemService.ts +2 -1
  261. package/src/services/BootChecksService.test.ts +33 -0
  262. package/src/services/BootChecksService.ts +21 -0
  263. package/src/services/DatabaseCollationService.test.ts +18 -0
  264. package/src/services/DatabaseCollationService.ts +81 -0
  265. package/src/services/DocumentService.ts +1 -1
  266. package/src/services/EventNotificationService.ts +5 -4
  267. package/src/services/FileSignService.ts +2 -2
  268. package/src/services/InvoiceService.ts +3 -3
  269. package/src/services/MemberNumberService.ts +6 -4
  270. package/src/services/MemberRecordStore.ts +28 -19
  271. package/src/services/PaymentReallocationService.test.ts +2 -1
  272. package/src/services/PaymentReallocationService.ts +2 -1
  273. package/src/services/PaymentService.ts +28 -26
  274. package/src/services/RegistrationService.ts +65 -3
  275. package/src/services/SSOService.ts +13 -9
  276. package/src/services/STPackageService.ts +7 -5
  277. package/src/services/StartupHealthService.ts +15 -0
  278. package/src/services/uitpas/PassholderEndpoints.ts +2 -2
  279. package/src/services/uitpas/UitpasService.ts +11 -8
  280. package/src/services/uitpas/cancelTicketSales.ts +1 -1
  281. package/src/services/uitpas/checkPermissionsFor.ts +9 -9
  282. package/src/services/uitpas/getSocialTariffForEvent.ts +4 -4
  283. package/src/services/uitpas/getSocialTariffForUitpasNumbers.ts +5 -5
  284. package/src/services/uitpas/handleUitpasResponse.ts +1 -1
  285. package/src/services/uitpas/registerTicketSales.ts +4 -4
  286. package/src/services/uitpas/searchUitpasEvents.ts +3 -3
  287. package/src/services/uitpas/searchUitpasOrganizers.ts +3 -3
  288. package/src/sql-filters/audit-logs.ts +2 -1
  289. package/src/sql-filters/balance-item-payments.ts +2 -1
  290. package/src/sql-filters/balance-items.ts +2 -1
  291. package/src/sql-filters/base-registration-filter-compilers.ts +6 -4
  292. package/src/sql-filters/document-templates.ts +2 -1
  293. package/src/sql-filters/documents.ts +2 -1
  294. package/src/sql-filters/email-recipients.ts +2 -1
  295. package/src/sql-filters/emails.ts +2 -1
  296. package/src/sql-filters/event-notifications.ts +2 -1
  297. package/src/sql-filters/events.ts +2 -1
  298. package/src/sql-filters/groups.ts +2 -1
  299. package/src/sql-filters/invoiced-balance-items.ts +2 -1
  300. package/src/sql-filters/invoices.ts +2 -1
  301. package/src/sql-filters/member-responsibility-records.ts +2 -1
  302. package/src/sql-filters/members.ts +8 -7
  303. package/src/sql-filters/orders.ts +3 -2
  304. package/src/sql-filters/organization-registration-periods.ts +2 -1
  305. package/src/sql-filters/organizations.ts +2 -1
  306. package/src/sql-filters/payments.ts +2 -1
  307. package/src/sql-filters/platform-memberships.ts +67 -0
  308. package/src/sql-filters/receivable-balances.ts +2 -1
  309. package/src/sql-filters/registration-periods.ts +2 -1
  310. package/src/sql-filters/registrations.ts +2 -1
  311. package/src/sql-filters/tickets.ts +2 -1
  312. package/src/sql-filters/users.ts +2 -1
  313. package/src/sql-filters/webshops.ts +38 -0
  314. package/src/sql-sorters/audit-logs.ts +3 -2
  315. package/src/sql-sorters/balance-items.ts +3 -2
  316. package/src/sql-sorters/document-templates.ts +3 -2
  317. package/src/sql-sorters/documents.ts +3 -2
  318. package/src/sql-sorters/email-recipients.ts +3 -2
  319. package/src/sql-sorters/emails.ts +3 -2
  320. package/src/sql-sorters/event-notifications.ts +3 -2
  321. package/src/sql-sorters/events.ts +3 -2
  322. package/src/sql-sorters/groups.ts +3 -2
  323. package/src/sql-sorters/invoices.ts +3 -2
  324. package/src/sql-sorters/members.ts +3 -2
  325. package/src/sql-sorters/orders.ts +3 -2
  326. package/src/sql-sorters/organization-registration-periods.ts +3 -2
  327. package/src/sql-sorters/organizations.ts +3 -2
  328. package/src/sql-sorters/payments.ts +3 -2
  329. package/src/sql-sorters/platform-memberships.ts +40 -0
  330. package/src/sql-sorters/receivable-balances.ts +3 -2
  331. package/src/sql-sorters/registration-periods.ts +3 -2
  332. package/src/sql-sorters/registrations.ts +3 -2
  333. package/src/sql-sorters/tickets.ts +3 -2
  334. package/src/sql-sorters/webshops.ts +40 -0
  335. package/tests/actions/patchOrganizationMember.ts +5 -4
  336. package/tests/actions/patchPaymentStatus.ts +2 -2
  337. package/tests/actions/patchUserMember.ts +6 -4
  338. package/tests/e2e/api-rate-limits.test.ts +4 -5
  339. package/tests/e2e/bundle-discounts.test.ts +3 -2
  340. package/tests/e2e/charge-members.test.ts +7 -5
  341. package/tests/e2e/documents.test.ts +3 -2
  342. package/tests/e2e/private-files.test.ts +11 -13
  343. package/tests/e2e/register.test.ts +6 -5
  344. package/tests/e2e/stock.test.ts +6 -8
  345. package/tests/e2e/tickets.test.ts +4 -2
  346. package/tests/helpers/StripeMocker.ts +3 -3
  347. package/tests/init/initAdmin.ts +4 -2
  348. package/tests/init/initBundleDiscount.ts +3 -2
  349. package/tests/init/initPayconiq.ts +1 -1
  350. package/tests/init/initPermissionRole.ts +4 -2
  351. package/tests/init/initPlatformRecordCategory.ts +1 -1
  352. package/tests/init/initStripe.ts +1 -1
  353. package/tests/vitest.global.setup.ts +26 -0
  354. package/tests/{jest.setup.ts → vitest.setup.ts} +4 -3
  355. package/tsconfig.build.json +17 -0
  356. package/tsconfig.json +10 -41
  357. package/tsconfig.test.json +17 -0
  358. package/vitest.config.js +13 -0
  359. package/eslint.config.mjs +0 -5
  360. package/jest.config.cjs +0 -27
  361. package/tests/jest.global.setup.ts +0 -33
  362. package/tests/toMatchMap.ts +0 -68
@@ -1,9 +1,13 @@
1
- import { OneToManyRelation } from '@simonbackx/simple-database';
2
- import { AutoEncoderPatchType, ConvertArrayToPatchableArray, Decoder, isEmptyPatch, isPatchableArray, PatchableArray, PatchableArrayAutoEncoder, PatchableArrayDecoder, StringDecoder } from '@simonbackx/simple-encoding';
3
- import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
1
+ import type { OneToManyRelation } from '@simonbackx/simple-database';
2
+ import type { AutoEncoderPatchType, ConvertArrayToPatchableArray, Decoder, PatchableArrayAutoEncoder } from '@simonbackx/simple-encoding';
3
+ import { isEmptyPatch, isPatchableArray, PatchableArray, PatchableArrayDecoder, StringDecoder } from '@simonbackx/simple-encoding';
4
+ import type { DecodedRequest, Request } from '@simonbackx/simple-endpoints';
5
+ import { Endpoint, Response } from '@simonbackx/simple-endpoints';
4
6
  import { SimpleError } from '@simonbackx/simple-errors';
5
- import { AuditLog, BalanceItem, Document, Group, Member, MemberFactory, MemberPlatformMembership, MemberResponsibilityRecord, MemberWithRegistrations, MemberWithUsersAndRegistrations, MemberWithUsersRegistrationsAndGroups, mergeTwoMembers, Organization, Platform, RateLimiter, Registration, RegistrationPeriod, User } from '@stamhoofd/models';
6
- import { AuditLogReplacement, AuditLogReplacementType, AuditLogSource, AuditLogType, EmergencyContact, GroupType, MemberDetails, MemberResponsibility, MembersBlob, MemberWithRegistrationsBlob, Parent, PermissionLevel, PlatformMembershipTypeBehaviour, SetupStepType } from '@stamhoofd/structures';
7
+ import type { MemberWithUsersRegistrationsAndGroups, Registration } from '@stamhoofd/models';
8
+ import { AuditLog, BalanceItem, Document, Group, Member, MemberFactory, MemberPlatformMembership, MemberResponsibilityRecord, mergeTwoMembers, Organization, Platform, RateLimiter, RegistrationPeriod, User } from '@stamhoofd/models';
9
+ import type { MemberResponsibility, MembersBlob } from '@stamhoofd/structures';
10
+ import { AuditLogReplacement, AuditLogReplacementType, AuditLogSource, AuditLogType, EmergencyContact, GroupType, MemberDetails, MemberWithRegistrationsBlob, Parent, PermissionLevel, PlatformMembershipTypeBehaviour, SetupStepType } from '@stamhoofd/structures';
7
11
  import { Formatter } from '@stamhoofd/utility';
8
12
 
9
13
  import { Email } from '@stamhoofd/email';
@@ -56,6 +60,18 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
56
60
  return [false];
57
61
  }
58
62
 
63
+ private static throwDuplicateMemberNumberError(error: unknown): never {
64
+ if (error && typeof error === 'object' && 'code' in error && error.code === 'ER_DUP_ENTRY' && 'message' in error && typeof error.message === 'string' && error.message.includes('memberNumber')) {
65
+ throw new SimpleError({
66
+ code: 'invalid_field',
67
+ message: 'Member number already in use',
68
+ human: $t('Dit lidnummer is al in gebruik'),
69
+ field: 'details.memberNumber',
70
+ });
71
+ }
72
+ throw error;
73
+ }
74
+
59
75
  async handle(request: DecodedRequest<Params, Query, Body>) {
60
76
  const organization = await Context.setOptionalOrganizationScope();
61
77
  await Context.authenticate();
@@ -111,7 +127,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
111
127
  throw new SimpleError({
112
128
  code: 'missing_organization',
113
129
  message: 'Missing organization',
114
- human: $t(`2bb4647b-a3b8-453e-8b75-41c290910fc8`),
130
+ human: $t(`%Di`),
115
131
  statusCode: 400,
116
132
  });
117
133
  }
@@ -129,7 +145,12 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
129
145
  }
130
146
  }
131
147
 
132
- await member.save();
148
+ try {
149
+ await member.save();
150
+ }
151
+ catch (error) {
152
+ PatchOrganizationMembersEndpoint.throwDuplicateMemberNumberError(error);
153
+ }
133
154
  members.push(member);
134
155
  updateMembershipMemberIds.add(member.id);
135
156
 
@@ -148,9 +169,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
148
169
  throw Context.auth.memberNotFoundOrNoAccess();
149
170
  }
150
171
 
151
- if (!(await Context.auth.canAccessMember(member, PermissionLevel.Write))) {
152
- await PatchOrganizationMembersEndpoint.checkSecurityCode(member, securityCode, 'patch');
153
- }
172
+ await PatchOrganizationMembersEndpoint.checkCanAccessMember(member, securityCode, 'patch');
154
173
 
155
174
  patch = await Context.auth.filterMemberPatch(member, patch);
156
175
  const originalDetails = member.details.clone();
@@ -162,7 +181,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
162
181
  throw new SimpleError({
163
182
  code: 'not_allowed',
164
183
  message: 'Cannot override details',
165
- human: $t(`b66ef4c3-9931-4fc3-9da1-c023857684fa`),
184
+ human: $t(`%Dj`),
166
185
  field: 'details',
167
186
  });
168
187
  }
@@ -202,7 +221,12 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
202
221
  }
203
222
  }
204
223
 
205
- await member.save();
224
+ try {
225
+ await member.save();
226
+ }
227
+ catch (error) {
228
+ PatchOrganizationMembersEndpoint.throwDuplicateMemberNumberError(error);
229
+ }
206
230
 
207
231
  // If parents changed or emergeny contacts: fetch family and merge data
208
232
  if (patch.details && (!isEmptyPatch(patch.details?.parents) || !isEmptyPatch(patch.details?.emergencyContacts))) {
@@ -215,7 +239,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
215
239
  // Update responsibilities
216
240
  for (const patchResponsibility of patch.responsibilities.getPatches()) {
217
241
  if (!Context.auth.hasPlatformFullAccess() && !(organization && await Context.auth.hasFullAccess(organization.id))) {
218
- throw Context.auth.error($t(`1d1b5807-af39-400b-8dea-2f222ee668ae`));
242
+ throw Context.auth.error($t(`%Dk`));
219
243
  }
220
244
 
221
245
  const responsibilityRecord = await MemberResponsibilityRecord.getByID(patchResponsibility.id);
@@ -223,21 +247,21 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
223
247
  throw new SimpleError({
224
248
  code: 'permission_denied',
225
249
  message: "You don't have permissions to access this endpoint",
226
- human: $t(`738fc35a-da77-4e1a-8233-9ff651781f65`),
250
+ human: $t(`%Dl`),
227
251
  });
228
252
  }
229
253
 
230
254
  const responsibility = platform.config.responsibilities.find(r => r.id === patchResponsibility.responsibilityId);
231
255
 
232
256
  if (responsibility && !responsibility.organizationBased && !Context.auth.hasPlatformFullAccess()) {
233
- throw Context.auth.error($t(`e2ceec71-367c-4cfd-98f3-b0ec0c83e2c2`));
257
+ throw Context.auth.error($t(`%Dm`));
234
258
  }
235
259
 
236
260
  // Allow patching begin and end date
237
261
  if (patchResponsibility.endDate !== undefined) {
238
262
  if (responsibilityRecord.endDate) {
239
263
  if (!Context.auth.hasPlatformFullAccess()) {
240
- throw Context.auth.error($t(`fd88b6ba-1f0b-4e82-9c5b-7c7a3ac8f4fa`));
264
+ throw Context.auth.error($t(`%Dn`));
241
265
  }
242
266
  }
243
267
  responsibilityRecord.endDate = patchResponsibility.endDate;
@@ -245,7 +269,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
245
269
 
246
270
  if (patchResponsibility.startDate !== undefined) {
247
271
  if (patchResponsibility.startDate.getTime() > Date.now() + 5 * 60 * 1000) {
248
- throw Context.auth.error($t(`84c2346e-40b2-4b38-9b2d-e1fcba6f1202`));
272
+ throw Context.auth.error($t(`%Do`));
249
273
  }
250
274
  if (patchResponsibility.startDate.getTime() > Date.now()) {
251
275
  patchResponsibility.startDate = new Date(); // force now
@@ -254,7 +278,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
254
278
  const daysDiff = Math.abs((new Date().getTime() - patchResponsibility.startDate.getTime()) / (1000 * 60 * 60 * 24));
255
279
 
256
280
  if (daysDiff > 60 && !Context.auth.hasPlatformFullAccess()) {
257
- throw Context.auth.error($t(`dc0c8bff-7b16-4597-adfb-cd6a4d7d4bf1`));
281
+ throw Context.auth.error($t(`%Dp`));
258
282
  }
259
283
  responsibilityRecord.startDate = patchResponsibility.startDate;
260
284
  }
@@ -271,7 +295,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
271
295
  // Create responsibilities
272
296
  for (const { put } of patch.responsibilities.getPuts()) {
273
297
  if (!Context.auth.hasPlatformFullAccess() && !(organization && await Context.auth.hasFullAccess(organization.id))) {
274
- throw Context.auth.error($t(`1d1b5807-af39-400b-8dea-2f222ee668ae`));
298
+ throw Context.auth.error($t(`%Dk`));
275
299
  }
276
300
 
277
301
  const platformResponsibility = platform.config.responsibilities.find(r => r.id === put.responsibilityId);
@@ -281,7 +305,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
281
305
  throw new SimpleError({
282
306
  code: 'invalid_field',
283
307
  message: 'Invalid organization',
284
- human: $t(`31757907-4cdd-4f0e-bb9d-cba9c1d997e4`),
308
+ human: $t(`%Dq`),
285
309
  field: 'organizationId',
286
310
  });
287
311
  }
@@ -291,7 +315,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
291
315
  throw new SimpleError({
292
316
  code: 'invalid_field',
293
317
  message: 'Invalid responsibility',
294
- human: $t(`03114785-acf5-4bba-a3b5-15d3ac4ae17c`),
318
+ human: $t(`%Dr`),
295
319
  field: 'responsibilityId',
296
320
  });
297
321
  }
@@ -300,7 +324,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
300
324
  throw new SimpleError({
301
325
  code: 'invalid_field',
302
326
  message: 'Invalid organization',
303
- human: $t(`ed22b0bb-8ae7-4ef0-a139-1bc11b2a719e`),
327
+ human: $t(`%Ds`),
304
328
  field: 'organizationId',
305
329
  });
306
330
  }
@@ -329,7 +353,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
329
353
  throw new SimpleError({
330
354
  code: 'invalid_field',
331
355
  message: 'Invalid organization',
332
- human: platformResponsibility ? $t('ec6a555e-6bb1-4b5f-b17e-38eaa8a478b5') : $t('d41cdbe3-57e3-4a2e-83bc-cb9e65c9c840'),
356
+ human: platformResponsibility ? $t('%1B9') : $t('%8G'),
333
357
  });
334
358
  }
335
359
 
@@ -342,7 +366,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
342
366
  throw new SimpleError({
343
367
  code: 'invalid_field',
344
368
  message: 'Invalid organization',
345
- human: $t(`aa39f949-6fe5-4ed2-acb7-ff3d138cf243`),
369
+ human: $t(`%Dt`),
346
370
  field: 'organizationId',
347
371
  });
348
372
  }
@@ -352,7 +376,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
352
376
  throw new SimpleError({
353
377
  code: 'invalid_field',
354
378
  message: 'Missing groupId',
355
- human: $t(`8bfe005a-a98a-48d6-afbf-bcca487b064b`),
379
+ human: $t(`%Du`),
356
380
  field: 'groupId',
357
381
  });
358
382
  }
@@ -362,7 +386,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
362
386
  throw new SimpleError({
363
387
  code: 'invalid_field',
364
388
  message: 'Invalid groupId',
365
- human: $t(`ca86d6ef-990e-42a4-834c-1c94622c95ef`),
389
+ human: $t(`%Dv`),
366
390
  field: 'groupId',
367
391
  });
368
392
  }
@@ -371,7 +395,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
371
395
  throw new SimpleError({
372
396
  code: 'invalid_field',
373
397
  message: 'Invalid groupId',
374
- human: $t(`aed1d5e3-1d42-46d4-a9c1-ac13bdffc2bd`),
398
+ human: $t(`%Dw`),
375
399
  field: 'groupId',
376
400
  });
377
401
  }
@@ -383,7 +407,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
383
407
  model.endDate = put.endDate;
384
408
 
385
409
  if (put.startDate.getTime() > Date.now() + 5 * 60 * 1000) {
386
- throw Context.auth.error($t(`84c2346e-40b2-4b38-9b2d-e1fcba6f1202`));
410
+ throw Context.auth.error($t(`%Do`));
387
411
  }
388
412
 
389
413
  if (put.startDate.getTime() > Date.now()) {
@@ -391,7 +415,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
391
415
  }
392
416
 
393
417
  if (put.endDate && put.endDate > new Date(Date.now() + 60 * 1000)) {
394
- throw Context.auth.error($t(`5c6106e8-6785-4f72-b0c7-00a940240019`));
418
+ throw Context.auth.error($t(`%Dx`));
395
419
  }
396
420
 
397
421
  model.startDate = put.startDate;
@@ -418,7 +442,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
418
442
  throw new SimpleError({
419
443
  code: 'invalid_field',
420
444
  message: 'Invalid email',
421
- human: $t(`dcb9cd60-ddfe-403d-bfb7-d1c7b63e2fdf`),
445
+ human: $t(`%Dy`),
422
446
  });
423
447
  }
424
448
 
@@ -435,7 +459,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
435
459
  throw new SimpleError({
436
460
  code: 'invalid_field',
437
461
  message: 'Invalid period',
438
- human: Context.i18n.$t(`62103514-05f5-4dc0-a5cc-c9321f21c63d`),
462
+ human: Context.i18n.$t(`%A9`),
439
463
  field: 'periodId',
440
464
  });
441
465
  }
@@ -444,7 +468,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
444
468
  throw new SimpleError({
445
469
  code: 'invalid_field',
446
470
  message: 'Invalid period',
447
- human: Context.i18n.$t(`745f5355-3398-406d-842e-5c9f7a700e91`, { period: period?.getBaseStructure().name }),
471
+ human: Context.i18n.$t(`%AA`, { period: period?.getBaseStructure().name }),
448
472
  field: 'periodId',
449
473
  });
450
474
  }
@@ -454,13 +478,13 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
454
478
  throw new SimpleError({
455
479
  code: 'invalid_field',
456
480
  message: 'Invalid organization',
457
- human: $t(`601c15e5-cfb0-4c34-af03-7dfc55e39d36`),
481
+ human: $t(`%Dz`),
458
482
  field: 'organizationId',
459
483
  });
460
484
  }
461
485
 
462
486
  if (!await Context.auth.hasFullAccess(put.organizationId)) {
463
- throw Context.auth.error($t(`9c632c7f-242e-44a1-b8ad-335b613075d8`));
487
+ throw Context.auth.error($t(`%E0`));
464
488
  }
465
489
 
466
490
  const putForOrganization = await Context.auth.getOrganization(put.organizationId);
@@ -472,7 +496,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
472
496
  code: 'invalid_field',
473
497
  field: 'membershipTypeId',
474
498
  message: 'Invalid membership type',
475
- human: $t(`fa79b34e-deef-4379-9c80-8795b0f5eaa3`),
499
+ human: $t(`%E1`),
476
500
  });
477
501
  }
478
502
 
@@ -494,7 +518,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
494
518
  code: 'invalid_field',
495
519
  field: 'membershipTypeId',
496
520
  message: 'Invalid membership type',
497
- human: $t(`a17551ff-5097-4f09-a8bb-19fe377f2b98`),
521
+ human: $t(`%E2`),
498
522
  });
499
523
  }
500
524
 
@@ -541,7 +565,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
541
565
  code: 'invalid_field',
542
566
  field: 'startDate',
543
567
  message: 'Overlapping memberships',
544
- human: $t(`84ef7751-ddf9-4591-ba5b-53371c67bdc3`),
568
+ human: $t(`%1NA`),
545
569
  });
546
570
  }
547
571
  if (existing.locked) {
@@ -549,7 +573,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
549
573
  code: 'invalid_field',
550
574
  field: 'startDate',
551
575
  message: 'Overlapping memberships',
552
- human: $t(`723af14b-38b8-4f33-a645-ed5087fc7461`),
576
+ human: $t(`%1NB`),
553
577
  });
554
578
  }
555
579
  if (!existing.generated) {
@@ -557,14 +581,14 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
557
581
  code: 'invalid_field',
558
582
  field: 'startDate',
559
583
  message: 'Overlapping memberships',
560
- human: $t(`b0280152-295f-48af-94e0-111c92dbda32`),
584
+ human: $t(`%1NC`),
561
585
  });
562
586
  }
563
587
  throw new SimpleError({
564
588
  code: 'invalid_field',
565
589
  field: 'startDate',
566
590
  message: 'Overlapping memberships',
567
- human: $t(`1c0d9219-ef24-46ad-9b9c-f09b8d093fc8`),
591
+ human: $t(`%1ND`),
568
592
  });
569
593
  }
570
594
  else if (existing) {
@@ -596,12 +620,12 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
596
620
  code: 'invalid_field',
597
621
  field: 'id',
598
622
  message: 'Invalid id',
599
- human: $t(`ee79372d-c14d-41ab-afb1-336acbe52687`),
623
+ human: $t(`%E3`),
600
624
  });
601
625
  }
602
626
 
603
627
  if (!await Context.auth.hasFullAccess(membership.organizationId)) {
604
- throw Context.auth.error($t(`fa5797d7-dafb-469a-a75c-b3b8a6a08737`));
628
+ throw Context.auth.error($t(`%E4`));
605
629
  }
606
630
 
607
631
  if (membership.periodId !== platform.periodId) {
@@ -611,7 +635,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
611
635
  throw new SimpleError({
612
636
  code: 'invalid_field',
613
637
  message: 'Invalid period',
614
- human: $t(`82af2364-c711-4e44-a871-9346c2cab66a`),
638
+ human: $t(`%BZ`),
615
639
  field: 'periodId',
616
640
  });
617
641
  }
@@ -620,7 +644,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
620
644
  throw new SimpleError({
621
645
  code: 'invalid_field',
622
646
  message: 'Invalid period',
623
- human: $t(`92a41b40-9841-4326-abaf-a8a7d97e5d55`),
647
+ human: $t(`%Ba`),
624
648
  field: 'periodId',
625
649
  });
626
650
  }
@@ -633,11 +657,11 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
633
657
  }
634
658
  else {
635
659
  if (p.locked === true) {
636
- throw Context.auth.error($t('bbc639c8-abdb-42d8-b5ed-f58084886ad9'));
660
+ throw Context.auth.error($t('%BX'));
637
661
  }
638
662
 
639
663
  if (p.locked === false) {
640
- throw Context.auth.error($t('c6494677-86f0-4d2e-b9ac-bedfc9e87187'));
664
+ throw Context.auth.error($t('%BY'));
641
665
  }
642
666
  }
643
667
 
@@ -654,12 +678,12 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
654
678
  code: 'invalid_field',
655
679
  field: 'id',
656
680
  message: 'Invalid id',
657
- human: $t(`ee79372d-c14d-41ab-afb1-336acbe52687`),
681
+ human: $t(`%E3`),
658
682
  });
659
683
  }
660
684
 
661
685
  if (!await Context.auth.hasFullAccess(membership.organizationId)) {
662
- throw Context.auth.error($t(`c3cca571-d543-4ca7-9da1-1e5570f5063a`));
686
+ throw Context.auth.error($t(`%E5`));
663
687
  }
664
688
 
665
689
  if (membership.periodId !== platform.periodId) {
@@ -669,7 +693,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
669
693
  throw new SimpleError({
670
694
  code: 'invalid_field',
671
695
  message: 'Invalid period',
672
- human: Context.i18n.$t(`1f1d657d-bc73-4cae-9025-b3ec67a705e7`),
696
+ human: Context.i18n.$t(`%AB`),
673
697
  field: 'periodId',
674
698
  });
675
699
  }
@@ -678,7 +702,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
678
702
  throw new SimpleError({
679
703
  code: 'invalid_field',
680
704
  message: 'Invalid period',
681
- human: Context.i18n.$t(`2e615670-813a-414f-b06c-f76136891bf8`, { period: period?.getBaseStructure().name }),
705
+ human: Context.i18n.$t(`%AC`, { period: period?.getBaseStructure().name }),
682
706
  field: 'periodId',
683
707
  });
684
708
  }
@@ -689,14 +713,14 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
689
713
  throw new SimpleError({
690
714
  code: 'invalid_field',
691
715
  message: 'Invalid invoice',
692
- human: $t(`be7d7286-9c3f-41f9-9378-b028754c8533`),
716
+ human: $t(`%E6`),
693
717
  });
694
718
  }
695
719
 
696
720
  throw new SimpleError({
697
721
  code: 'invalid_field',
698
722
  message: 'Invalid invoice',
699
- human: $t(`1a7b41da-9bd3-4019-9ed4-39e742f99f41`),
723
+ human: $t(`%E7`),
700
724
  });
701
725
  }
702
726
 
@@ -732,8 +756,10 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
732
756
  ] }).catch(console.error);
733
757
  }
734
758
 
759
+ const r = await AuthenticatedStructures.membersBlob(members);
760
+
735
761
  return new Response(
736
- await AuthenticatedStructures.membersBlob(members),
762
+ r,
737
763
  );
738
764
  }
739
765
 
@@ -746,7 +772,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
746
772
  for (const id of ids) {
747
773
  const member = await Member.getByIdWithUsersAndRegistrations(id);
748
774
  if (!member || !await Context.auth.canDeleteMember(member)) {
749
- throw Context.auth.error($t(`39f5696c-3755-429f-b0da-a0ca920ed11e`));
775
+ throw Context.auth.error($t(`%E8`));
750
776
  }
751
777
 
752
778
  await MemberUserSyncer.onDeleteMember(member);
@@ -929,77 +955,102 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
929
955
  }
930
956
  }
931
957
 
932
- static async checkSecurityCode(member: MemberWithUsersRegistrationsAndGroups, securityCode: string | null | undefined, type: 'put' | 'patch') {
933
- if ((type === 'put' && await member.isSafeToMergeDuplicateWithoutSecurityCode()) || await Context.auth.canAccessMember(member, PermissionLevel.Write)) {
934
- console.log('checkSecurityCode: without security code: allowed for ' + member.id);
958
+ private static async checkSecurityCode(member: MemberWithUsersRegistrationsAndGroups, securityCode: string) {
959
+ try {
960
+ securityCodeLimiter.track(member.details.name, 1);
935
961
  }
936
- else if (securityCode) {
937
- try {
938
- securityCodeLimiter.track(member.details.name, 1);
939
- }
940
- catch (e) {
941
- Email.sendWebmaster({
942
- subject: $t(`04cb945a-28aa-4f3e-95b3-16455cdd8892`),
943
- text: $t(`5f7b1766-eb58-4471-bff7-60f3fc66fe41`) + ' ' + member.details.name + ' ' + $t(`7254f2f6-0d15-4e81-85cf-cff6438c9e98`) + ' ' + member.id + ')' + '\n\n' + e.message + '\n\nStamhoofd',
944
- });
962
+ catch (e) {
963
+ Email.sendWebmaster({
964
+ subject: $t(`%E9`),
965
+ text: $t(`%EA`) + ' ' + member.details.name + ' ' + $t(`%1G`) + ' ' + member.id + ')' + '\n\n' + e.message + '\n\nStamhoofd',
966
+ });
945
967
 
968
+ throw new SimpleError({
969
+ code: 'too_many_tries',
970
+ message: 'Too many securityCodes limited',
971
+ human: $t(`%EB`),
972
+ field: 'details.securityCode',
973
+ });
974
+ }
975
+
976
+ // Entered the security code, so we can link the user to the member
977
+ if (STAMHOOFD.environment !== 'development') {
978
+ if (!member.details.securityCode || securityCode !== member.details.securityCode) {
946
979
  throw new SimpleError({
947
- code: 'too_many_tries',
948
- message: 'Too many securityCodes limited',
949
- human: $t(`ddb1b9de-cc00-4960-ba36-fa70429cbac1`),
980
+ code: 'invalid_field',
950
981
  field: 'details.securityCode',
982
+ message: 'Invalid security code',
983
+ human: Context.i18n.$t('%2i'),
984
+ statusCode: 400,
951
985
  });
952
986
  }
987
+ }
953
988
 
954
- // Entered the security code, so we can link the user to the member
955
- if (STAMHOOFD.environment !== 'development') {
956
- if (!member.details.securityCode || securityCode !== member.details.securityCode) {
957
- throw new SimpleError({
958
- code: 'invalid_field',
959
- field: 'details.securityCode',
960
- message: 'Invalid security code',
961
- human: Context.i18n.$t('49753d6a-7ca4-4145-8024-0be05a9ab063'),
962
- statusCode: 400,
963
- });
964
- }
965
- }
989
+ console.log('checkSecurityCode: security code is correct - for ' + member.id);
966
990
 
967
- console.log('checkSecurityCode: security code is correct - for ' + member.id);
991
+ // Grant temporary access to this member without needing to enter the security code again
992
+ await Context.auth.temporarilyGrantMemberAccess(member, PermissionLevel.Full);
968
993
 
969
- // Grant temporary access to this member without needing to enter the security code again
970
- await Context.auth.temporarilyGrantMemberAccess(member, PermissionLevel.Full);
994
+ const log = new AuditLog();
995
+
996
+ // a member has multiple organizations, so this is difficult to determine - for now it is only visible in the admin panel
997
+ log.organizationId = member.organizationId;
971
998
 
972
- const log = new AuditLog();
999
+ log.type = AuditLogType.MemberSecurityCodeUsed;
1000
+ log.source = AuditLogSource.Anonymous;
973
1001
 
974
- // a member has multiple organizations, so this is difficult to determine - for now it is only visible in the admin panel
975
- log.organizationId = member.organizationId;
1002
+ if (Context.user) {
1003
+ log.userId = Context.user.id;
1004
+ log.source = AuditLogSource.User;
1005
+ }
976
1006
 
977
- log.type = AuditLogType.MemberSecurityCodeUsed;
978
- log.source = AuditLogSource.Anonymous;
1007
+ log.objectId = member.id;
1008
+ log.replacements = new Map([
1009
+ ['m', AuditLogReplacement.create({
1010
+ value: member.details.name,
1011
+ type: AuditLogReplacementType.Member,
1012
+ id: member.id,
1013
+ })],
1014
+ ]);
1015
+ await log.save();
1016
+ }
979
1017
 
980
- if (Context.user) {
981
- log.userId = Context.user.id;
982
- log.source = AuditLogSource.User;
1018
+ static async checkCanAccessMember(member: MemberWithUsersRegistrationsAndGroups, securityCode: string | null | undefined, type: 'put' | 'patch') {
1019
+ // do not check security code for user mode organization (throw error if not allowed)
1020
+ if (STAMHOOFD.userMode === 'organization') {
1021
+ if ((type === 'put' && await member.isSafeToMergeDuplicateWithoutSecurityCode()) || await Context.auth.canAccessMember(member, PermissionLevel.Write)) {
1022
+ console.log('checkSecurityCode: allowed for ' + member.id);
1023
+ return;
1024
+ }
1025
+
1026
+ if (type === 'patch') {
1027
+ throw Context.auth.memberNotFoundOrNoAccess();
983
1028
  }
984
1029
 
985
- log.objectId = member.id;
986
- log.replacements = new Map([
987
- ['m', AuditLogReplacement.create({
988
- value: member.details.name,
989
- type: AuditLogReplacementType.Member,
990
- id: member.id,
991
- })],
992
- ]);
993
- await log.save();
1030
+ throw new SimpleError({
1031
+ code: 'known_member_missing_rights',
1032
+ message: 'Creating known member without sufficient access rights',
1033
+ // different message for userMode organization because security codes are not available in that mode
1034
+ human: $t(`{member} is al gekend in ons systeem, maar jouw e-mailadres niet. Neem contact op met de vereniging.`, { member: member.details.firstName }),
1035
+ statusCode: 400,
1036
+ });
1037
+ }
1038
+
1039
+ if ((type === 'put' && await member.isSafeToMergeDuplicateWithoutSecurityCode()) || await Context.auth.canAccessMember(member, PermissionLevel.Write)) {
1040
+ console.log('checkSecurityCode: without security code: allowed for ' + member.id);
1041
+ }
1042
+ else if (securityCode) {
1043
+ await this.checkSecurityCode(member, securityCode);
994
1044
  }
995
1045
  else {
996
1046
  if (type === 'patch') {
997
1047
  throw Context.auth.memberNotFoundOrNoAccess();
998
1048
  }
1049
+
999
1050
  throw new SimpleError({
1000
1051
  code: 'known_member_missing_rights',
1001
1052
  message: 'Creating known member without sufficient access rights',
1002
- human: $t(`510807a1-d4c7-45fa-9e3b-ddc8764d3f6e`, { member: member.details.firstName }),
1053
+ human: $t(`%1BA`, { member: member.details.firstName }),
1003
1054
  statusCode: 400,
1004
1055
  });
1005
1056
  }
@@ -1027,7 +1078,11 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
1027
1078
  // Check for duplicates and prevent creating a duplicate member by a user
1028
1079
  const duplicate = await this.findExistingMember(member);
1029
1080
  if (duplicate) {
1030
- await this.checkSecurityCode(duplicate, securityCode, type);
1081
+ console.error('duplicate detection');
1082
+ console.error(member.details.parents);
1083
+ console.error(duplicate.details.parents);
1084
+
1085
+ await this.checkCanAccessMember(duplicate, securityCode, type);
1031
1086
 
1032
1087
  // Merge data
1033
1088
  // NOTE: We use mergeTwoMembers instead of mergeMultipleMembers, because we should never safe 'member' , because that one does not exist in the database
@@ -1069,11 +1124,11 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
1069
1124
  message: 'Maximum members reached',
1070
1125
  human: responsibility.maximumMembers === 1
1071
1126
  ? (model.groupId
1072
- ? $t('e3e4ba16-7923-42bc-ae23-cd729ce06869', { responsibility: responsibility.name })
1073
- : $t('77e408e8-59e5-42c2-b58d-956f7c391e5c', { responsibility: responsibility.name }))
1127
+ ? $t('%C5', { responsibility: responsibility.name })
1128
+ : $t('%C6', { responsibility: responsibility.name }))
1074
1129
  : (model.groupId
1075
- ? $t('10c13841-9f58-4651-a9b3-a34c8ce1a505', { count: responsibility.maximumMembers.toFixed(), responsibility: responsibility.name })
1076
- : $t('01ef9768-89b5-48ea-955e-b896306a9a87', { count: responsibility.maximumMembers.toFixed(), responsibility: responsibility.name })),
1130
+ ? $t('%C7', { count: responsibility.maximumMembers.toFixed(), responsibility: responsibility.name })
1131
+ : $t('%C8', { count: responsibility.maximumMembers.toFixed(), responsibility: responsibility.name })),
1077
1132
  });
1078
1133
  }
1079
1134
  }
@@ -1,5 +1,6 @@
1
1
  import { SimpleError } from '@simonbackx/simple-errors';
2
- import { FilterWrapperMarker, PermissionLevel, StamhoofdFilter, unwrapFilter, WrapperFilter } from '@stamhoofd/structures';
2
+ import type { StamhoofdFilter, WrapperFilter } from '@stamhoofd/structures';
3
+ import { FilterWrapperMarker, PermissionLevel, unwrapFilter } from '@stamhoofd/structures';
3
4
  import { Context } from '../../../../helpers/Context.js';
4
5
 
5
6
  export async function validateGroupFilter({ filter, permissionLevel, key }: { filter: StamhoofdFilter; permissionLevel: PermissionLevel; key: string | null }) {
@@ -32,7 +33,7 @@ export async function validateGroupFilter({ filter, permissionLevel, key }: { fi
32
33
  code: 'invalid_field',
33
34
  field: 'filter',
34
35
  message: 'You must filter on a group of the organization you are trying to access',
35
- human: $t(`5efbaed8-004e-40b9-a822-bdb31e35fbb7`),
36
+ human: $t(`%15e`),
36
37
  });
37
38
  }
38
39
 
@@ -63,7 +64,7 @@ export async function validateGroupFilter({ filter, permissionLevel, key }: { fi
63
64
  if (permissionLevel !== PermissionLevel.Read || !group.settings.implicitlyAllowViewRegistrations) {
64
65
  throw Context.auth.error({
65
66
  message: 'You do not have access to this group',
66
- human: $t(`45eedf49-0f0a-442c-a0bd-7881c2682698`, { groupName: group.settings.name }),
67
+ human: $t(`%15f`, { groupName: group.settings.name }),
67
68
  });
68
69
  }
69
70
  else {