@stamhoofd/backend 2.39.0 → 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,13 +1,13 @@
1
- import { DecodedRequest, Endpoint, Request, Response } from "@simonbackx/simple-endpoints";
1
+ import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
2
2
  import { Email } from '@stamhoofd/models';
3
- import { EmailPreview } from "@stamhoofd/structures";
3
+ import { EmailPreview } from '@stamhoofd/structures';
4
4
 
5
5
  import { SimpleError } from '@simonbackx/simple-errors';
6
6
  import { Context } from '../../../helpers/Context';
7
7
 
8
- type Params = {id: string};
8
+ type Params = { id: string };
9
9
  type Query = undefined;
10
- type Body = undefined
10
+ type Body = undefined;
11
11
  type ResponseBody = EmailPreview;
12
12
 
13
13
  /**
@@ -16,11 +16,11 @@ type ResponseBody = EmailPreview;
16
16
 
17
17
  export class GetEmailEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
18
18
  protected doesMatch(request: Request): [true, Params] | [false] {
19
- if (request.method != "GET") {
19
+ if (request.method !== 'GET') {
20
20
  return [false];
21
21
  }
22
22
 
23
- const params = Endpoint.parseParameters(request.url, "/email/@id", {id: String});
23
+ const params = Endpoint.parseParameters(request.url, '/email/@id', { id: String });
24
24
 
25
25
  if (params) {
26
26
  return [true, params as Params];
@@ -30,20 +30,20 @@ export class GetEmailEndpoint extends Endpoint<Params, Query, Body, ResponseBody
30
30
 
31
31
  async handle(request: DecodedRequest<Params, Query, Body>) {
32
32
  const organization = await Context.setOptionalOrganizationScope();
33
- const {user} = await Context.authenticate()
33
+ const { user } = await Context.authenticate();
34
34
 
35
35
  if (!Context.auth.canSendEmails()) {
36
- throw Context.auth.error()
37
- }
36
+ throw Context.auth.error();
37
+ }
38
38
 
39
39
  const model = await Email.getByID(request.params.id);
40
40
  if (!model || model.userId !== user.id || (model.organizationId !== (organization?.id ?? null))) {
41
41
  throw new SimpleError({
42
- code: "not_found",
43
- human: "Email not found",
42
+ code: 'not_found',
43
+ human: 'Email not found',
44
44
  message: 'Deze e-mail bestaat niet of is verwijderd',
45
- statusCode: 404
46
- })
45
+ statusCode: 404,
46
+ });
47
47
  }
48
48
 
49
49
  return new Response(await model.getPreviewStructure());
@@ -1,5 +1,5 @@
1
1
  import { AutoEncoder, BooleanDecoder, Decoder, field, StringDecoder } from '@simonbackx/simple-encoding';
2
- import { DecodedRequest, Endpoint, Request, Response } from "@simonbackx/simple-endpoints";
2
+ import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
3
3
  import { SimpleError } from '@simonbackx/simple-errors';
4
4
  import { EmailAddress } from '@stamhoofd/email';
5
5
 
@@ -8,16 +8,16 @@ type Query = undefined;
8
8
 
9
9
  class Body extends AutoEncoder {
10
10
  @field({ decoder: StringDecoder })
11
- id: string
11
+ id: string;
12
12
 
13
13
  @field({ decoder: StringDecoder })
14
- token: string
14
+ token: string;
15
15
 
16
16
  @field({ decoder: BooleanDecoder, optional: true })
17
- unsubscribedMarketing?: boolean
17
+ unsubscribedMarketing?: boolean;
18
18
 
19
19
  @field({ decoder: BooleanDecoder, optional: true })
20
- unsubscribedAll?: boolean
20
+ unsubscribedAll?: boolean;
21
21
  }
22
22
 
23
23
  type ResponseBody = undefined;
@@ -26,11 +26,11 @@ export class ManageEmailAddressEndpoint extends Endpoint<Params, Query, Body, Re
26
26
  bodyDecoder = Body as Decoder<Body>;
27
27
 
28
28
  protected doesMatch(request: Request): [true, Params] | [false] {
29
- if (request.method != "POST") {
29
+ if (request.method !== 'POST') {
30
30
  return [false];
31
31
  }
32
32
 
33
- const params = Endpoint.parseParameters(request.url, "/email/manage", {});
33
+ const params = Endpoint.parseParameters(request.url, '/email/manage', {});
34
34
 
35
35
  if (params) {
36
36
  return [true, params as Params];
@@ -39,19 +39,19 @@ export class ManageEmailAddressEndpoint extends Endpoint<Params, Query, Body, Re
39
39
  }
40
40
 
41
41
  async handle(request: DecodedRequest<Params, Query, Body>) {
42
- const email = await EmailAddress.getByID(request.body.id)
42
+ const email = await EmailAddress.getByID(request.body.id);
43
43
  if (!email || email.token !== request.body.token || request.body.token.length < 10 || request.body.id.length < 10) {
44
44
  throw new SimpleError({
45
- code: "invalid_fields",
46
- message: "Invalid token or id",
47
- human: "Deze link is vervallen. Probeer het opnieuw in een recentere e-mail"
48
- })
45
+ code: 'invalid_fields',
46
+ message: 'Invalid token or id',
47
+ human: 'Deze link is vervallen. Probeer het opnieuw in een recentere e-mail',
48
+ });
49
49
  }
50
50
 
51
- email.unsubscribedAll = request.body.unsubscribedAll ?? email.unsubscribedAll
52
- email.unsubscribedMarketing = request.body.unsubscribedMarketing ?? email.unsubscribedMarketing
51
+ email.unsubscribedAll = request.body.unsubscribedAll ?? email.unsubscribedAll;
52
+ email.unsubscribedMarketing = request.body.unsubscribedMarketing ?? email.unsubscribedMarketing;
53
53
 
54
- await email.save()
54
+ await email.save();
55
55
  return new Response(undefined);
56
56
  }
57
- }
57
+ }
@@ -1,14 +1,14 @@
1
- import { DecodedRequest, Endpoint, Request, Response } from "@simonbackx/simple-endpoints";
1
+ import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
2
2
  import { Email } from '@stamhoofd/models';
3
- import { EmailPreview, EmailStatus, Email as EmailStruct } from "@stamhoofd/structures";
3
+ import { EmailPreview, EmailStatus, Email as EmailStruct } from '@stamhoofd/structures';
4
4
 
5
5
  import { SimpleError } from '@simonbackx/simple-errors';
6
6
  import { Context } from '../../../helpers/Context';
7
- import { AutoEncoderPatchType, Decoder, patchObject } from "@simonbackx/simple-encoding";
7
+ import { AutoEncoderPatchType, Decoder, patchObject } from '@simonbackx/simple-encoding';
8
8
 
9
- type Params = {id: string};
9
+ type Params = { id: string };
10
10
  type Query = undefined;
11
- type Body = AutoEncoderPatchType<EmailStruct>
11
+ type Body = AutoEncoderPatchType<EmailStruct>;
12
12
  type ResponseBody = EmailPreview;
13
13
 
14
14
  /**
@@ -16,14 +16,14 @@ type ResponseBody = EmailPreview;
16
16
  */
17
17
 
18
18
  export class PatchEmailEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
19
- bodyDecoder = EmailStruct.patchType() as Decoder<AutoEncoderPatchType<EmailStruct>>
19
+ bodyDecoder = EmailStruct.patchType() as Decoder<AutoEncoderPatchType<EmailStruct>>;
20
20
 
21
21
  protected doesMatch(request: Request): [true, Params] | [false] {
22
- if (request.method != "PATCH") {
22
+ if (request.method !== 'PATCH') {
23
23
  return [false];
24
24
  }
25
25
 
26
- const params = Endpoint.parseParameters(request.url, "/email/@id", {id: String});
26
+ const params = Endpoint.parseParameters(request.url, '/email/@id', { id: String });
27
27
 
28
28
  if (params) {
29
29
  return [true, params as Params];
@@ -33,29 +33,29 @@ export class PatchEmailEndpoint extends Endpoint<Params, Query, Body, ResponseBo
33
33
 
34
34
  async handle(request: DecodedRequest<Params, Query, Body>) {
35
35
  const organization = await Context.setOptionalOrganizationScope();
36
- const {user} = await Context.authenticate()
36
+ const { user } = await Context.authenticate();
37
37
 
38
38
  if (!Context.auth.canSendEmails()) {
39
- throw Context.auth.error()
40
- }
39
+ throw Context.auth.error();
40
+ }
41
41
 
42
42
  const model = await Email.getByID(request.params.id);
43
43
  if (!model || model.userId !== user.id || (model.organizationId !== (organization?.id ?? null))) {
44
44
  throw new SimpleError({
45
- code: "not_found",
46
- human: "Email not found",
45
+ code: 'not_found',
46
+ human: 'Email not found',
47
47
  message: 'Deze e-mail bestaat niet of is verwijderd',
48
- statusCode: 404
49
- })
48
+ statusCode: 404,
49
+ });
50
50
  }
51
51
 
52
52
  if (model.status !== EmailStatus.Draft) {
53
53
  throw new SimpleError({
54
- code: "not_draft",
55
- human: "Email is not a draft",
54
+ code: 'not_draft',
55
+ human: 'Email is not a draft',
56
56
  message: 'Deze e-mail is al verzonden en kan niet meer aangepast worden',
57
- statusCode: 400
58
- })
57
+ statusCode: 400,
58
+ });
59
59
  }
60
60
 
61
61
  let rebuild = false;
@@ -92,22 +92,22 @@ export class PatchEmailEndpoint extends Endpoint<Params, Query, Body, ResponseBo
92
92
  // Attachments
93
93
  if (request.body.attachments !== undefined) {
94
94
  model.attachments = patchObject(model.attachments, request.body.attachments);
95
- model.validateAttachments()
95
+ model.validateAttachments();
96
96
  }
97
97
 
98
98
  await model.save();
99
99
 
100
100
  if (rebuild) {
101
- await model.buildExampleRecipient()
102
- model.updateCount()
101
+ await model.buildExampleRecipient();
102
+ model.updateCount();
103
103
 
104
104
  // Force null - because we have stale data
105
- model.recipientCount = null
105
+ model.recipientCount = null;
106
106
  }
107
107
 
108
108
  if (request.body.status === EmailStatus.Sending || request.body.status === EmailStatus.Sent) {
109
- model.throwIfNotReadyToSend()
110
- model.send().catch(console.error)
109
+ model.throwIfNotReadyToSend();
110
+ model.send().catch(console.error);
111
111
  }
112
112
 
113
113
  return new Response(await model.getPreviewStructure());
@@ -1,9 +1,8 @@
1
- /* eslint-disable @typescript-eslint/no-unsafe-argument */
2
1
  import { Decoder } from '@simonbackx/simple-encoding';
3
2
  import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
4
3
  import { SimpleError } from '@simonbackx/simple-errors';
5
4
  import { Event } from '@stamhoofd/models';
6
- import { SQL, SQLFilterDefinitions, SQLSortDefinitions, compileToSQLFilter, compileToSQLSorter } from "@stamhoofd/sql";
5
+ import { SQL, SQLFilterDefinitions, SQLSortDefinitions, compileToSQLFilter, compileToSQLSorter } from '@stamhoofd/sql';
7
6
  import { CountFilteredRequest, Event as EventStruct, LimitedFilteredRequest, PaginatedResponse, StamhoofdFilter, assertSort, getSortFilter } from '@stamhoofd/structures';
8
7
 
9
8
  import { AuthenticatedStructures } from '../../../helpers/AuthenticatedStructures';
@@ -14,20 +13,20 @@ import { eventSorters } from '../../../sql-sorters/events';
14
13
  type Params = Record<string, never>;
15
14
  type Query = LimitedFilteredRequest;
16
15
  type Body = undefined;
17
- type ResponseBody = PaginatedResponse<EventStruct[], LimitedFilteredRequest>
16
+ type ResponseBody = PaginatedResponse<EventStruct[], LimitedFilteredRequest>;
18
17
 
19
- const filterCompilers: SQLFilterDefinitions = eventFilterCompilers
20
- const sorters: SQLSortDefinitions<Event> = eventSorters
18
+ const filterCompilers: SQLFilterDefinitions = eventFilterCompilers;
19
+ const sorters: SQLSortDefinitions<Event> = eventSorters;
21
20
 
22
21
  export class GetEventsEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
23
- queryDecoder = LimitedFilteredRequest as Decoder<LimitedFilteredRequest>
22
+ queryDecoder = LimitedFilteredRequest as Decoder<LimitedFilteredRequest>;
24
23
 
25
24
  protected doesMatch(request: Request): [true, Params] | [false] {
26
- if (request.method != "GET") {
25
+ if (request.method !== 'GET') {
27
26
  return [false];
28
27
  }
29
28
 
30
- const params = Endpoint.parseParameters(request.url, "/events", {});
29
+ const params = Endpoint.parseParameters(request.url, '/events', {});
31
30
 
32
31
  if (params) {
33
32
  return [true, params as Params];
@@ -35,74 +34,74 @@ export class GetEventsEndpoint extends Endpoint<Params, Query, Body, ResponseBod
35
34
  return [false];
36
35
  }
37
36
 
38
- static buildQuery(q: CountFilteredRequest|LimitedFilteredRequest) {
39
- const organization = Context.organization
40
- let scopeFilter: StamhoofdFilter|undefined = undefined;
37
+ static buildQuery(q: CountFilteredRequest | LimitedFilteredRequest) {
38
+ const organization = Context.organization;
39
+ let scopeFilter: StamhoofdFilter | undefined = undefined;
41
40
 
42
41
  if (organization) {
43
42
  scopeFilter = {
44
43
  $or: [
45
44
  {
46
- organizationId: organization.id
45
+ organizationId: organization.id,
47
46
  },
48
47
  {
49
- organizationId: null
50
- }
48
+ organizationId: null,
49
+ },
51
50
  ],
52
51
  };
53
52
  }
54
53
 
55
54
  const query = SQL
56
55
  .select(
57
- SQL.wildcard(Event.table)
56
+ SQL.wildcard(Event.table),
58
57
  )
59
58
  .from(
60
- SQL.table(Event.table)
59
+ SQL.table(Event.table),
61
60
  );
62
-
61
+
63
62
  if (scopeFilter) {
64
- query.where(compileToSQLFilter(scopeFilter, filterCompilers))
63
+ query.where(compileToSQLFilter(scopeFilter, filterCompilers));
65
64
  }
66
65
 
67
66
  if (q.filter) {
68
- query.where(compileToSQLFilter(q.filter, filterCompilers))
67
+ query.where(compileToSQLFilter(q.filter, filterCompilers));
69
68
  }
70
69
 
71
70
  if (q.search) {
72
- let searchFilter: StamhoofdFilter|null = null
71
+ let searchFilter: StamhoofdFilter | null = null;
73
72
 
74
73
  // todo: detect special search patterns and adjust search filter if needed
75
74
  searchFilter = {
76
75
  name: {
77
- $contains: q.search
78
- }
79
- }
76
+ $contains: q.search,
77
+ },
78
+ };
80
79
 
81
80
  if (searchFilter) {
82
- query.where(compileToSQLFilter(searchFilter, filterCompilers))
81
+ query.where(compileToSQLFilter(searchFilter, filterCompilers));
83
82
  }
84
83
  }
85
84
 
86
85
  if (q instanceof LimitedFilteredRequest) {
87
86
  if (q.pageFilter) {
88
- query.where(compileToSQLFilter(q.pageFilter, filterCompilers))
87
+ query.where(compileToSQLFilter(q.pageFilter, filterCompilers));
89
88
  }
90
89
 
91
- q.sort = assertSort(q.sort, [{key: 'id'}])
92
- query.orderBy(compileToSQLSorter(q.sort, sorters))
93
- query.limit(q.limit)
90
+ q.sort = assertSort(q.sort, [{ key: 'id' }]);
91
+ query.orderBy(compileToSQLSorter(q.sort, sorters));
92
+ query.limit(q.limit);
94
93
  }
95
-
96
- return query
94
+
95
+ return query;
97
96
  }
98
97
 
99
98
  static async buildData(requestQuery: LimitedFilteredRequest) {
100
- const query = GetEventsEndpoint.buildQuery(requestQuery)
101
- const data = await query.fetch()
102
-
99
+ const query = GetEventsEndpoint.buildQuery(requestQuery);
100
+ const data = await query.fetch();
101
+
103
102
  const events = Event.fromRows(data, Event.table);
104
103
 
105
- let next: LimitedFilteredRequest|undefined;
104
+ let next: LimitedFilteredRequest | undefined;
106
105
 
107
106
  if (events.length >= requestQuery.limit) {
108
107
  const lastObject = events[events.length - 1];
@@ -113,8 +112,8 @@ export class GetEventsEndpoint extends Endpoint<Params, Query, Body, ResponseBod
113
112
  pageFilter: nextFilter,
114
113
  sort: requestQuery.sort,
115
114
  limit: requestQuery.limit,
116
- search: requestQuery.search
117
- })
115
+ search: requestQuery.search,
116
+ });
118
117
 
119
118
  if (JSON.stringify(nextFilter) === JSON.stringify(requestQuery.pageFilter)) {
120
119
  console.error('Found infinite loading loop for', requestQuery);
@@ -124,13 +123,13 @@ export class GetEventsEndpoint extends Endpoint<Params, Query, Body, ResponseBod
124
123
 
125
124
  return new PaginatedResponse<EventStruct[], LimitedFilteredRequest>({
126
125
  results: await AuthenticatedStructures.events(events),
127
- next
126
+ next,
128
127
  });
129
128
  }
130
129
 
131
130
  async handle(request: DecodedRequest<Params, Query, Body>) {
132
131
  await Context.setOptionalOrganizationScope();
133
- await Context.authenticate()
132
+ await Context.authenticate();
134
133
 
135
134
  const maxLimit = Context.auth.hasSomePlatformAccess() ? 1000 : 100;
136
135
 
@@ -138,20 +137,20 @@ export class GetEventsEndpoint extends Endpoint<Params, Query, Body, ResponseBod
138
137
  throw new SimpleError({
139
138
  code: 'invalid_field',
140
139
  field: 'limit',
141
- message: 'Limit can not be more than ' + maxLimit
142
- })
140
+ message: 'Limit can not be more than ' + maxLimit,
141
+ });
143
142
  }
144
143
 
145
144
  if (request.query.limit < 1) {
146
145
  throw new SimpleError({
147
146
  code: 'invalid_field',
148
147
  field: 'limit',
149
- message: 'Limit can not be less than 1'
150
- })
148
+ message: 'Limit can not be less than 1',
149
+ });
151
150
  }
152
-
151
+
153
152
  return new Response(
154
- await GetEventsEndpoint.buildData(request.query)
153
+ await GetEventsEndpoint.buildData(request.query),
155
154
  );
156
155
  }
157
156
  }