@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
package/src/crons.ts CHANGED
@@ -1,5 +1,7 @@
1
+ /* eslint-disable @typescript-eslint/no-redundant-type-constituents */
2
+ /* eslint-disable @typescript-eslint/no-unsafe-argument */
1
3
  import { Database } from '@simonbackx/simple-database';
2
- import { logger, StyledText } from "@simonbackx/simple-logging";
4
+ import { logger, StyledText } from '@simonbackx/simple-logging';
3
5
  import { Email, EmailAddress } from '@stamhoofd/email';
4
6
  import { Group, Organization, Payment, Registration, STPackage, Webshop } from '@stamhoofd/models';
5
7
  import { PaymentMethod, PaymentProvider, PaymentStatus } from '@stamhoofd/structures';
@@ -13,151 +15,151 @@ import { checkSettlements } from './helpers/CheckSettlements';
13
15
  import { ForwardHandler } from './helpers/ForwardHandler';
14
16
 
15
17
  // Importing postmark returns undefined (this is a bug, so we need to use require)
16
- // eslint-disable-next-line @typescript-eslint/no-var-requires
17
- const postmark = require("postmark")
18
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
19
+ const postmark = require('postmark');
18
20
 
19
- let lastDNSCheck: Date | null = null
20
- let lastDNSId = ""
21
+ let lastDNSCheck: Date | null = null;
22
+ let lastDNSId = '';
21
23
  async function checkDNS() {
22
- if (STAMHOOFD.environment === "development") {
24
+ if (STAMHOOFD.environment === 'development') {
23
25
  return;
24
26
  }
25
27
 
26
28
  // Wait 6 hours between every complete check
27
29
  if (lastDNSCheck && lastDNSCheck > new Date(new Date().getTime() - 6 * 60 * 60 * 1000)) {
28
- console.log("[DNS] Skip DNS check")
29
- return
30
+ console.log('[DNS] Skip DNS check');
31
+ return;
30
32
  }
31
-
33
+
32
34
  const organizations = await Organization.where({ id: { sign: '>', value: lastDNSId } }, {
33
35
  limit: 50,
34
- sort: ["id"]
35
- })
36
+ sort: ['id'],
37
+ });
36
38
 
37
39
  if (organizations.length == 0) {
38
40
  // Wait an half hour before starting again
39
- lastDNSId = ""
40
- lastDNSCheck = new Date()
41
- return
41
+ lastDNSId = '';
42
+ lastDNSCheck = new Date();
43
+ return;
42
44
  }
43
45
 
44
- console.log("[DNS] Checking DNS...")
46
+ console.log('[DNS] Checking DNS...');
45
47
 
46
48
  for (const organization of organizations) {
47
- if (STAMHOOFD.environment === "production") {
48
- console.log("[DNS] "+organization.name)
49
+ if (STAMHOOFD.environment === 'production') {
50
+ console.log('[DNS] ' + organization.name);
49
51
  }
50
52
  try {
51
- await organization.updateDNSRecords()
52
- } catch (e) {
53
+ await organization.updateDNSRecords();
54
+ }
55
+ catch (e) {
53
56
  console.error(e);
54
57
  }
55
58
  }
56
59
 
57
- lastDNSId = organizations[organizations.length - 1].id
58
-
60
+ lastDNSId = organizations[organizations.length - 1].id;
59
61
  }
60
62
 
61
- let lastExpirationCheck: Date | null = null
63
+ let lastExpirationCheck: Date | null = null;
62
64
  async function checkExpirationEmails() {
63
- if (STAMHOOFD.environment === "development") {
65
+ if (STAMHOOFD.environment === 'development') {
64
66
  return;
65
67
  }
66
68
 
67
69
  // Wait 1 hour between every complete check
68
70
  if (lastExpirationCheck && lastExpirationCheck > new Date(new Date().getTime() - 1 * 60 * 60 * 1000)) {
69
- console.log("[EXPIRATION EMAILS] Skip checkExpirationEmails")
70
- return
71
+ console.log('[EXPIRATION EMAILS] Skip checkExpirationEmails');
72
+ return;
71
73
  }
72
-
74
+
73
75
  // Get all packages that expire between now and 31 days
74
- const packages = await STPackage.where({
76
+ const packages = await STPackage.where({
75
77
  validUntil: [
76
78
  { sign: '!=', value: null },
77
79
  { sign: '>', value: new Date() },
78
- { sign: '<', value: new Date(Date.now() + 1000 * 60 * 60 * 24 * 31) }
80
+ { sign: '<', value: new Date(Date.now() + 1000 * 60 * 60 * 24 * 31) },
79
81
  ],
80
82
  validAt: [
81
83
  { sign: '!=', value: null },
82
84
  ],
83
- emailCount: 0
84
- })
85
+ emailCount: 0,
86
+ });
85
87
 
86
- console.log("[EXPIRATION EMAILS] Sending expiration emails...")
88
+ console.log('[EXPIRATION EMAILS] Sending expiration emails...');
87
89
 
88
90
  for (const pack of packages) {
89
- await pack.sendExpiryEmail()
90
- }
91
- lastExpirationCheck = new Date()
91
+ await pack.sendExpiryEmail();
92
+ }
93
+ lastExpirationCheck = new Date();
92
94
  }
93
95
 
94
- let lastWebshopDNSCheck: Date | null = null
95
- let lastWebshopDNSId = ""
96
+ let lastWebshopDNSCheck: Date | null = null;
97
+ let lastWebshopDNSId = '';
96
98
  async function checkWebshopDNS() {
97
- if (STAMHOOFD.environment === "development") {
99
+ if (STAMHOOFD.environment === 'development') {
98
100
  return;
99
101
  }
100
102
 
101
103
  // Wait 6 hours between every complete check
102
104
  if (lastWebshopDNSCheck && lastWebshopDNSCheck > new Date(new Date().getTime() - 6 * 60 * 60 * 1000)) {
103
- console.log("[DNS] Skip webshop DNS check")
104
- return
105
+ console.log('[DNS] Skip webshop DNS check');
106
+ return;
105
107
  }
106
-
107
- const webshops = await Webshop.where({
108
+
109
+ const webshops = await Webshop.where({
108
110
  id: { sign: '>', value: lastWebshopDNSId },
109
- domain: { sign: '!=', value: null }
111
+ domain: { sign: '!=', value: null },
110
112
  }, {
111
113
  limit: 10,
112
- sort: ["id"]
113
- })
114
+ sort: ['id'],
115
+ });
114
116
 
115
117
  if (webshops.length == 0) {
116
118
  // Wait an half hour before starting again
117
- lastWebshopDNSId = ""
118
- lastWebshopDNSCheck = new Date()
119
- return
119
+ lastWebshopDNSId = '';
120
+ lastWebshopDNSCheck = new Date();
121
+ return;
120
122
  }
121
123
 
122
- console.log("[DNS] Checking webshop DNS...")
124
+ console.log('[DNS] Checking webshop DNS...');
123
125
 
124
126
  for (const webshop of webshops) {
125
- console.log("[DNS] Webshop "+webshop.meta.name+" ("+webshop.id+")"+" ("+webshop.domain+")")
126
- await webshop.updateDNSRecords()
127
+ console.log('[DNS] Webshop ' + webshop.meta.name + ' (' + webshop.id + ')' + ' (' + webshop.domain + ')');
128
+ await webshop.updateDNSRecords();
127
129
  }
128
130
 
129
- lastWebshopDNSId = webshops[webshops.length - 1].id
131
+ lastWebshopDNSId = webshops[webshops.length - 1].id;
130
132
  }
131
133
 
132
134
  async function checkReplies() {
133
- if (STAMHOOFD.environment !== "production" || !STAMHOOFD.AWS_ACCESS_KEY_ID) {
134
- return
135
+ if (STAMHOOFD.environment !== 'production' || !STAMHOOFD.AWS_ACCESS_KEY_ID) {
136
+ return;
135
137
  }
136
-
137
- console.log("Checking replies from AWS SQS")
138
+
139
+ console.log('Checking replies from AWS SQS');
138
140
  const sqs = new AWS.SQS();
139
- const messages = await sqs.receiveMessage({ QueueUrl: "https://sqs.eu-west-1.amazonaws.com/118244293157/stamhoofd-email-forwarding", MaxNumberOfMessages: 10 }).promise()
141
+ const messages = await sqs.receiveMessage({ QueueUrl: 'https://sqs.eu-west-1.amazonaws.com/118244293157/stamhoofd-email-forwarding', MaxNumberOfMessages: 10 }).promise();
140
142
  if (messages.Messages) {
141
143
  for (const message of messages.Messages) {
142
- console.log("Received message from forwarding queue");
144
+ console.log('Received message from forwarding queue');
143
145
 
144
146
  if (message.ReceiptHandle) {
145
- if (STAMHOOFD.environment === "production") {
147
+ if (STAMHOOFD.environment === 'production') {
146
148
  await sqs.deleteMessage({
147
- QueueUrl: "https://sqs.eu-west-1.amazonaws.com/118244293157/stamhoofd-email-forwarding",
148
- ReceiptHandle: message.ReceiptHandle
149
- }).promise()
150
- console.log("Deleted from queue");
149
+ QueueUrl: 'https://sqs.eu-west-1.amazonaws.com/118244293157/stamhoofd-email-forwarding',
150
+ ReceiptHandle: message.ReceiptHandle,
151
+ }).promise();
152
+ console.log('Deleted from queue');
151
153
  }
152
154
  }
153
155
 
154
156
  try {
155
157
  if (message.Body) {
156
158
  // decode the JSON value
157
- const bounce = JSON.parse(message.Body)
159
+ const bounce = JSON.parse(message.Body);
158
160
 
159
161
  if (bounce.Message) {
160
- const message = JSON.parse(bounce.Message)
162
+ const message = JSON.parse(bounce.Message);
161
163
 
162
164
  // Read message content
163
165
  if (message.mail && message.content && message.receipt) {
@@ -169,247 +171,258 @@ async function checkReplies() {
169
171
  spfVerdict: { status: 'PASS' | string };
170
172
  dkimVerdict: { status: 'PASS' | string };
171
173
  dmarcVerdict: { status: 'PASS' | string };
172
- }
174
+ };
173
175
 
174
- const options = await ForwardHandler.handle(content, receipt)
176
+ const options = await ForwardHandler.handle(content, receipt);
175
177
  if (options) {
176
- if (STAMHOOFD.environment === "production") {
177
- Email.send(options)
178
+ if (STAMHOOFD.environment === 'production') {
179
+ Email.send(options);
178
180
  }
179
181
  }
180
182
  }
181
183
  }
182
184
  }
183
- } catch (e) {
184
- console.error(e)
185
+ }
186
+ catch (e) {
187
+ console.error(e);
185
188
  }
186
189
  }
187
190
  }
188
191
  }
189
192
 
190
- let lastPostmarkCheck: Date | null = null
191
- let lastPostmarkId: string | null = null
193
+ let lastPostmarkCheck: Date | null = null;
194
+ let lastPostmarkId: string | null = null;
192
195
  async function checkPostmarkBounces() {
193
- if (STAMHOOFD.environment !== "production") {
196
+ if (STAMHOOFD.environment !== 'production') {
194
197
  return;
195
198
  }
196
-
197
- const token = STAMHOOFD.POSTMARK_SERVER_TOKEN
199
+
200
+ const token = STAMHOOFD.POSTMARK_SERVER_TOKEN;
198
201
  if (!token) {
199
- console.log("[POSTMARK BOUNCES] No postmark token, skipping postmark bounces")
200
- return
202
+ console.log('[POSTMARK BOUNCES] No postmark token, skipping postmark bounces');
203
+ return;
201
204
  }
202
- const fromDate = (lastPostmarkCheck ?? new Date(new Date().getTime() - 24 * 60 * 60 * 1000 * 2))
203
- const ET = DateTime.fromJSDate(fromDate).setZone('EST').toISO({ includeOffset: false})
204
- console.log("[POSTMARK BOUNCES] Checking bounces from Postmark since", fromDate, ET)
205
+ const fromDate = (lastPostmarkCheck ?? new Date(new Date().getTime() - 24 * 60 * 60 * 1000 * 2));
206
+ const ET = DateTime.fromJSDate(fromDate).setZone('EST').toISO({ includeOffset: false });
207
+ console.log('[POSTMARK BOUNCES] Checking bounces from Postmark since', fromDate, ET);
205
208
  const client = new postmark.ServerClient(token);
206
209
 
207
210
  const bounces = await client.getBounces({
208
211
  fromdate: ET,
209
- todate: DateTime.now().setZone('EST').toISO({ includeOffset: false}),
212
+ todate: DateTime.now().setZone('EST').toISO({ includeOffset: false }),
210
213
  count: 500,
211
- offset: 0
212
- })
214
+ offset: 0,
215
+ });
213
216
 
214
217
  if (bounces.TotalCount == 0) {
215
- console.log("[POSTMARK BOUNCES] No Postmark bounces at this time")
216
- return
218
+ console.log('[POSTMARK BOUNCES] No Postmark bounces at this time');
219
+ return;
217
220
  }
218
221
 
219
- let lastId: string | null = null
222
+ let lastId: string | null = null;
220
223
 
221
224
  for (const bounce of bounces.Bounces) {
222
225
  // Try to get the organization, if possible, else default to global blocking: "null", which is not visible for an organization, but it is applied
223
- const source = bounce.From
224
- const organization = source ? await Organization.getByEmail(source) : undefined
226
+ const source = bounce.From;
227
+ const organization = source ? await Organization.getByEmail(source) : undefined;
225
228
 
226
- if (bounce.Type === "HardBounce" || bounce.Type === "BadEmailAddress" || bounce.Type === "Blocked") {
229
+ if (bounce.Type === 'HardBounce' || bounce.Type === 'BadEmailAddress' || bounce.Type === 'Blocked') {
227
230
  // Block for everyone, but not visible
228
- console.log("[POSTMARK BOUNCES] Postmark "+bounce.Type+" for: ", bounce.Email, "from", source, "organization", organization?.name)
229
- const emailAddress = await EmailAddress.getOrCreate(bounce.Email, organization?.id ?? null)
230
- emailAddress.hardBounce = true
231
- await emailAddress.save()
232
- } else if (bounce.Type === "SpamComplaint" || bounce.Type === "SpamNotification" || bounce.Type === "VirusNotification") {
233
- console.log("[POSTMARK BOUNCES] Postmark "+bounce.Type+" for: ", bounce.Email, "from", source, "organization", organization?.name)
234
- const emailAddress = await EmailAddress.getOrCreate(bounce.Email, organization?.id ?? null)
235
- emailAddress.markedAsSpam = true
236
- await emailAddress.save()
237
- } else {
238
- console.log("[POSTMARK BOUNCES] Unhandled Postmark "+bounce.Type+": ", bounce.Email, "from", source, "organization", organization?.name)
239
- console.error("[POSTMARK BOUNCES] Unhandled Postmark "+bounce.Type+": ", bounce.Email, "from", source, "organization", organization?.name)
231
+ console.log('[POSTMARK BOUNCES] Postmark ' + bounce.Type + ' for: ', bounce.Email, 'from', source, 'organization', organization?.name);
232
+ const emailAddress = await EmailAddress.getOrCreate(bounce.Email, organization?.id ?? null);
233
+ emailAddress.hardBounce = true;
234
+ await emailAddress.save();
235
+ }
236
+ else if (bounce.Type === 'SpamComplaint' || bounce.Type === 'SpamNotification' || bounce.Type === 'VirusNotification') {
237
+ console.log('[POSTMARK BOUNCES] Postmark ' + bounce.Type + ' for: ', bounce.Email, 'from', source, 'organization', organization?.name);
238
+ const emailAddress = await EmailAddress.getOrCreate(bounce.Email, organization?.id ?? null);
239
+ emailAddress.markedAsSpam = true;
240
+ await emailAddress.save();
241
+ }
242
+ else {
243
+ console.log('[POSTMARK BOUNCES] Unhandled Postmark ' + bounce.Type + ': ', bounce.Email, 'from', source, 'organization', organization?.name);
244
+ console.error('[POSTMARK BOUNCES] Unhandled Postmark ' + bounce.Type + ': ', bounce.Email, 'from', source, 'organization', organization?.name);
240
245
  }
241
246
 
242
- const bouncedAt = new Date(bounce.BouncedAt)
243
- lastPostmarkCheck = lastPostmarkCheck ? new Date(Math.max(bouncedAt.getTime(), lastPostmarkCheck.getTime())) : bouncedAt
247
+ const bouncedAt = new Date(bounce.BouncedAt);
248
+ lastPostmarkCheck = lastPostmarkCheck ? new Date(Math.max(bouncedAt.getTime(), lastPostmarkCheck.getTime())) : bouncedAt;
244
249
 
245
- lastId = bounce.ID
250
+ lastId = bounce.ID;
246
251
  }
247
252
 
248
253
  if (lastId && lastPostmarkId) {
249
254
  if (lastId === lastPostmarkId) {
250
- console.log("[POSTMARK BOUNCES] Postmark has no new bounces")
255
+ console.log('[POSTMARK BOUNCES] Postmark has no new bounces');
251
256
  // Increase timestamp by one second to avoid refetching it every time
252
257
  if (lastPostmarkCheck) {
253
- lastPostmarkCheck = new Date(lastPostmarkCheck.getTime() + 1000)
258
+ lastPostmarkCheck = new Date(lastPostmarkCheck.getTime() + 1000);
254
259
  }
255
260
  }
256
261
  }
257
- lastPostmarkId = lastId
262
+ lastPostmarkId = lastId;
258
263
  }
259
264
 
260
265
  async function checkBounces() {
261
- if (STAMHOOFD.environment !== "production" || !STAMHOOFD.AWS_ACCESS_KEY_ID) {
262
- return
266
+ if (STAMHOOFD.environment !== 'production' || !STAMHOOFD.AWS_ACCESS_KEY_ID) {
267
+ return;
263
268
  }
264
-
265
- console.log("[AWS BOUNCES] Checking bounces from AWS SQS")
269
+
270
+ console.log('[AWS BOUNCES] Checking bounces from AWS SQS');
266
271
  const sqs = new AWS.SQS();
267
- const messages = await sqs.receiveMessage({ QueueUrl: "https://sqs.eu-west-1.amazonaws.com/118244293157/stamhoofd-bounces-queue", MaxNumberOfMessages: 10 }).promise()
272
+ const messages = await sqs.receiveMessage({ QueueUrl: 'https://sqs.eu-west-1.amazonaws.com/118244293157/stamhoofd-bounces-queue', MaxNumberOfMessages: 10 }).promise();
268
273
  if (messages.Messages) {
269
274
  for (const message of messages.Messages) {
270
- console.log("[AWS BOUNCES] Received bounce message");
271
- console.log("[AWS BOUNCES]", message);
275
+ console.log('[AWS BOUNCES] Received bounce message');
276
+ console.log('[AWS BOUNCES]', message);
272
277
 
273
278
  if (message.ReceiptHandle) {
274
- if (STAMHOOFD.environment === "production") {
279
+ if (STAMHOOFD.environment === 'production') {
275
280
  await sqs.deleteMessage({
276
- QueueUrl: "https://sqs.eu-west-1.amazonaws.com/118244293157/stamhoofd-bounces-queue",
277
- ReceiptHandle: message.ReceiptHandle
278
- }).promise()
279
- console.log("[AWS BOUNCES] Deleted from queue");
281
+ QueueUrl: 'https://sqs.eu-west-1.amazonaws.com/118244293157/stamhoofd-bounces-queue',
282
+ ReceiptHandle: message.ReceiptHandle,
283
+ }).promise();
284
+ console.log('[AWS BOUNCES] Deleted from queue');
280
285
  }
281
286
  }
282
287
 
283
288
  try {
284
289
  if (message.Body) {
285
290
  // decode the JSON value
286
- const bounce = JSON.parse(message.Body)
291
+ const bounce = JSON.parse(message.Body);
287
292
 
288
293
  if (bounce.Message) {
289
- const message = JSON.parse(bounce.Message)
294
+ const message = JSON.parse(bounce.Message);
290
295
 
291
296
  if (message.bounce) {
292
- const b = message.bounce
297
+ const b = message.bounce;
293
298
  // Block all receivers that generate a permanent bounce
294
- const type = b.bounceType
299
+ const type = b.bounceType;
295
300
 
296
- const source = message.mail.source
301
+ const source = message.mail.source;
297
302
 
298
303
  // try to find organization that is responsible for this e-mail address
299
304
 
300
305
  for (const recipient of b.bouncedRecipients) {
301
- const email = recipient.emailAddress
306
+ const email = recipient.emailAddress;
302
307
 
303
308
  if (
304
- type === "Permanent"
309
+ type === 'Permanent'
305
310
  || (
306
311
  recipient.diagnosticCode && (
307
- (recipient.diagnosticCode as string).toLowerCase().includes("invalid domain")
312
+ (recipient.diagnosticCode as string).toLowerCase().includes('invalid domain')
308
313
  || (recipient.diagnosticCode as string).toLowerCase().includes('unable to lookup dns')
309
314
  )
310
315
  )
311
316
  ) {
312
- const organization: Organization | undefined = source ? await Organization.getByEmail(source) : undefined
317
+ const organization: Organization | undefined = source ? await Organization.getByEmail(source) : undefined;
313
318
  if (organization) {
314
- const emailAddress = await EmailAddress.getOrCreate(email, organization.id)
315
- emailAddress.hardBounce = true
316
- await emailAddress.save()
317
- } else {
318
- console.error("[AWS BOUNCES] Unknown organization for email address "+source)
319
+ const emailAddress = await EmailAddress.getOrCreate(email, organization.id);
320
+ emailAddress.hardBounce = true;
321
+ await emailAddress.save();
322
+ }
323
+ else {
324
+ console.error('[AWS BOUNCES] Unknown organization for email address ' + source);
319
325
  }
320
326
  }
321
-
322
327
  }
323
- console.log("[AWS BOUNCES] For domain "+source)
324
- } else {
325
- console.log("[AWS BOUNCES] 'bounce' field missing in bounce message")
328
+ console.log('[AWS BOUNCES] For domain ' + source);
326
329
  }
327
- } else {
328
- console.log("[AWS BOUNCES] 'Message' field missing in bounce message")
330
+ else {
331
+ console.log("[AWS BOUNCES] 'bounce' field missing in bounce message");
332
+ }
333
+ }
334
+ else {
335
+ console.log("[AWS BOUNCES] 'Message' field missing in bounce message");
329
336
  }
330
- } else {
331
- console.log("[AWS BOUNCES] Message Body missing in bounce")
332
337
  }
333
- } catch (e) {
334
- console.log("[AWS BOUNCES] Bounce message processing failed:")
335
- console.error("[AWS BOUNCES] Bounce message processing failed:")
336
- console.error("[AWS BOUNCES]", e)
338
+ else {
339
+ console.log('[AWS BOUNCES] Message Body missing in bounce');
340
+ }
341
+ }
342
+ catch (e) {
343
+ console.log('[AWS BOUNCES] Bounce message processing failed:');
344
+ console.error('[AWS BOUNCES] Bounce message processing failed:');
345
+ console.error('[AWS BOUNCES]', e);
337
346
  }
338
347
  }
339
348
  }
340
349
  }
341
350
 
342
351
  async function checkComplaints() {
343
- if (STAMHOOFD.environment !== "production" || !STAMHOOFD.AWS_ACCESS_KEY_ID) {
344
- return
352
+ if (STAMHOOFD.environment !== 'production' || !STAMHOOFD.AWS_ACCESS_KEY_ID) {
353
+ return;
345
354
  }
346
355
 
347
- console.log("[AWS COMPLAINTS] Checking complaints from AWS SQS")
356
+ console.log('[AWS COMPLAINTS] Checking complaints from AWS SQS');
348
357
  const sqs = new AWS.SQS();
349
- const messages = await sqs.receiveMessage({ QueueUrl: "https://sqs.eu-west-1.amazonaws.com/118244293157/stamhoofd-complaints-queue", MaxNumberOfMessages: 10 }).promise()
358
+ const messages = await sqs.receiveMessage({ QueueUrl: 'https://sqs.eu-west-1.amazonaws.com/118244293157/stamhoofd-complaints-queue', MaxNumberOfMessages: 10 }).promise();
350
359
  if (messages.Messages) {
351
360
  for (const message of messages.Messages) {
352
- console.log("[AWS COMPLAINTS] Received complaint message");
353
- console.log("[AWS COMPLAINTS]", message)
361
+ console.log('[AWS COMPLAINTS] Received complaint message');
362
+ console.log('[AWS COMPLAINTS]', message);
354
363
 
355
364
  if (message.ReceiptHandle) {
356
- if (STAMHOOFD.environment === "production") {
365
+ if (STAMHOOFD.environment === 'production') {
357
366
  await sqs.deleteMessage({
358
- QueueUrl: "https://sqs.eu-west-1.amazonaws.com/118244293157/stamhoofd-complaints-queue",
359
- ReceiptHandle: message.ReceiptHandle
360
- }).promise()
361
- console.log("[AWS COMPLAINTS] Deleted from queue");
367
+ QueueUrl: 'https://sqs.eu-west-1.amazonaws.com/118244293157/stamhoofd-complaints-queue',
368
+ ReceiptHandle: message.ReceiptHandle,
369
+ }).promise();
370
+ console.log('[AWS COMPLAINTS] Deleted from queue');
362
371
  }
363
372
  }
364
373
 
365
374
  try {
366
375
  if (message.Body) {
367
376
  // decode the JSON value
368
- const complaint = JSON.parse(message.Body)
369
- console.log("[AWS COMPLAINTS]", complaint)
377
+ const complaint = JSON.parse(message.Body);
378
+ console.log('[AWS COMPLAINTS]', complaint);
370
379
 
371
380
  if (complaint.Message) {
372
- const message = JSON.parse(complaint.Message)
381
+ const message = JSON.parse(complaint.Message);
373
382
 
374
383
  if (message.complaint) {
375
- const b = message.complaint
376
- const source = message.mail.source
377
- const organization: Organization | undefined = source ? await Organization.getByEmail(source) : undefined
384
+ const b = message.complaint;
385
+ const source = message.mail.source;
386
+ const organization: Organization | undefined = source ? await Organization.getByEmail(source) : undefined;
378
387
 
379
- const type: "abuse" | "auth-failure" | "fraud" | "not-spam" | "other" | "virus" = b.complaintFeedbackType
388
+ const type: 'abuse' | 'auth-failure' | 'fraud' | 'not-spam' | 'other' | 'virus' = b.complaintFeedbackType;
380
389
 
381
390
  if (organization) {
382
391
  for (const recipient of b.complainedRecipients) {
383
- const email = recipient.emailAddress
384
- const emailAddress = await EmailAddress.getOrCreate(email, organization.id)
385
- emailAddress.markedAsSpam = type !== "not-spam"
386
- await emailAddress.save()
392
+ const email = recipient.emailAddress;
393
+ const emailAddress = await EmailAddress.getOrCreate(email, organization.id);
394
+ emailAddress.markedAsSpam = type !== 'not-spam';
395
+ await emailAddress.save();
387
396
  }
388
- } else {
389
- console.error("[AWS COMPLAINTS] Unknown organization for email address "+source)
397
+ }
398
+ else {
399
+ console.error('[AWS COMPLAINTS] Unknown organization for email address ' + source);
390
400
  }
391
401
 
392
- if (type == "virus" || type == "fraud") {
393
- console.error("[AWS COMPLAINTS] Received virus / fraud complaint!")
394
- console.error("[AWS COMPLAINTS]", complaint)
395
- if (STAMHOOFD.environment === "production") {
402
+ if (type == 'virus' || type == 'fraud') {
403
+ console.error('[AWS COMPLAINTS] Received virus / fraud complaint!');
404
+ console.error('[AWS COMPLAINTS]', complaint);
405
+ if (STAMHOOFD.environment === 'production') {
396
406
  Email.sendWebmaster({
397
- subject: "Received a "+type+" email notification",
398
- text: "We received a "+type+" notification for an e-mail from the organization: "+organization?.name+". Please check and adjust if needed.\n"
399
- })
407
+ subject: 'Received a ' + type + ' email notification',
408
+ text: 'We received a ' + type + ' notification for an e-mail from the organization: ' + organization?.name + '. Please check and adjust if needed.\n',
409
+ });
400
410
  }
401
411
  }
402
- } else {
403
- console.log("[AWS COMPLAINTS] Missing complaint field")
404
412
  }
405
- } else {
406
- console.log("[AWS COMPLAINTS] Missing message field in complaint")
413
+ else {
414
+ console.log('[AWS COMPLAINTS] Missing complaint field');
415
+ }
416
+ }
417
+ else {
418
+ console.log('[AWS COMPLAINTS] Missing message field in complaint');
407
419
  }
408
420
  }
409
- } catch (e) {
410
- console.log("[AWS COMPLAINTS] Complain message processing failed:")
411
- console.error("[AWS COMPLAINTS] Complain message processing failed:")
412
- console.error("[AWS COMPLAINTS]", e)
421
+ }
422
+ catch (e) {
423
+ console.log('[AWS COMPLAINTS] Complain message processing failed:');
424
+ console.error('[AWS COMPLAINTS] Complain message processing failed:');
425
+ console.error('[AWS COMPLAINTS]', e);
413
426
  }
414
427
  }
415
428
  }
@@ -417,26 +430,26 @@ async function checkComplaints() {
417
430
 
418
431
  // Keep checking pending paymetns for 3 days
419
432
  async function checkPayments() {
420
- if (STAMHOOFD.environment === "development") {
433
+ if (STAMHOOFD.environment === 'development') {
421
434
  return;
422
435
  }
423
436
 
424
- const timeout = 60*1000*31;
425
-
437
+ const timeout = 60 * 1000 * 31;
438
+
426
439
  // TODO: only select the ID + organizationId
427
440
  const payments = await Payment.where({
428
441
  status: {
429
- sign: "IN",
430
- value: [PaymentStatus.Created, PaymentStatus.Pending]
442
+ sign: 'IN',
443
+ value: [PaymentStatus.Created, PaymentStatus.Pending],
431
444
  },
432
445
  method: {
433
- sign: "IN",
434
- value: [PaymentMethod.Bancontact, PaymentMethod.iDEAL, PaymentMethod.Payconiq, PaymentMethod.CreditCard]
446
+ sign: 'IN',
447
+ value: [PaymentMethod.Bancontact, PaymentMethod.iDEAL, PaymentMethod.Payconiq, PaymentMethod.CreditCard],
435
448
  },
436
449
  // Check all payments that are 11 minutes old and are still pending
437
450
  createdAt: {
438
- sign: "<",
439
- value: new Date(new Date().getTime() - timeout)
451
+ sign: '<',
452
+ value: new Date(new Date().getTime() - timeout),
440
453
  },
441
454
  }, {
442
455
  limit: 100,
@@ -445,32 +458,34 @@ async function checkPayments() {
445
458
  // If at some point, they are still pending after 1 day, their status should change to failed
446
459
  sort: [{
447
460
  column: 'createdAt',
448
- direction: 'ASC'
449
- }]
450
- })
461
+ direction: 'ASC',
462
+ }],
463
+ });
451
464
 
452
- console.log("[DELAYED PAYMENTS] Checking pending payments: "+payments.length)
465
+ console.log('[DELAYED PAYMENTS] Checking pending payments: ' + payments.length);
453
466
 
454
467
  for (const payment of payments) {
455
468
  try {
456
469
  if (payment.organizationId) {
457
- const organization = await Organization.getByID(payment.organizationId)
470
+ const organization = await Organization.getByID(payment.organizationId);
458
471
  if (organization) {
459
- await ExchangePaymentEndpoint.pollStatus(payment.id, organization)
472
+ await ExchangePaymentEndpoint.pollStatus(payment.id, organization);
460
473
  continue;
461
474
  }
462
- } else {
475
+ }
476
+ else {
463
477
  // deprecated
464
478
  }
465
479
 
466
480
  // Check expired
467
481
  if (ExchangePaymentEndpoint.isManualExpired(payment.status, payment)) {
468
- console.error('[DELAYED PAYMENTS] Could not resolve handler for expired payment, marking as failed', payment.id)
469
- payment.status = PaymentStatus.Failed
470
- await payment.save()
482
+ console.error('[DELAYED PAYMENTS] Could not resolve handler for expired payment, marking as failed', payment.id);
483
+ payment.status = PaymentStatus.Failed;
484
+ await payment.save();
471
485
  }
472
- } catch (e) {
473
- console.error(e)
486
+ }
487
+ catch (e) {
488
+ console.error(e);
474
489
  }
475
490
  }
476
491
  }
@@ -479,118 +494,120 @@ let didCheckBuckaroo = false;
479
494
  let lastBuckarooId = '';
480
495
 
481
496
  // Time to start checking (needs to be consistent to avoid weird jumps)
482
- const startBuckarooDate = new Date(new Date().getTime() - 60*1000*60*24*7*4);
497
+ const startBuckarooDate = new Date(new Date().getTime() - 60 * 1000 * 60 * 24 * 7 * 4);
483
498
 
484
499
  // Keep checking pending paymetns for 3 days
485
500
  async function checkFailedBuckarooPayments() {
486
- if (STAMHOOFD.environment !== "production") {
487
- return
501
+ if (STAMHOOFD.environment !== 'production') {
502
+ return;
488
503
  }
489
504
 
490
505
  if (didCheckBuckaroo) {
491
- return
506
+ return;
492
507
  }
493
508
 
494
- console.log('Checking failed Buckaroo payments')
495
-
509
+ console.log('Checking failed Buckaroo payments');
510
+
496
511
  // TODO: only select the ID + organizationId
497
512
  const payments = await Payment.where({
498
513
  status: {
499
- sign: "IN",
500
- value: [PaymentStatus.Failed]
514
+ sign: 'IN',
515
+ value: [PaymentStatus.Failed],
501
516
  },
502
517
  provider: PaymentProvider.Buckaroo,
503
518
 
504
519
  // Only check payments of last 4 weeks
505
520
  createdAt: {
506
- sign: ">",
507
- value: startBuckarooDate
521
+ sign: '>',
522
+ value: startBuckarooDate,
508
523
  },
509
524
  id: {
510
- sign: ">",
511
- value: lastBuckarooId
512
- }
525
+ sign: '>',
526
+ value: lastBuckarooId,
527
+ },
513
528
  }, {
514
529
  limit: 100,
515
530
 
516
531
  // Sort by ID
517
532
  sort: [{
518
533
  column: 'id',
519
- direction: 'ASC'
520
- }]
521
- })
534
+ direction: 'ASC',
535
+ }],
536
+ });
522
537
 
523
- console.log("[BUCKAROO PAYMENTS] Checking failed payments: "+payments.length)
538
+ console.log('[BUCKAROO PAYMENTS] Checking failed payments: ' + payments.length);
524
539
 
525
540
  for (const payment of payments) {
526
541
  try {
527
542
  if (payment.organizationId) {
528
- const organization = await Organization.getByID(payment.organizationId)
543
+ const organization = await Organization.getByID(payment.organizationId);
529
544
  if (organization) {
530
- await ExchangePaymentEndpoint.pollStatus(payment.id, organization)
545
+ await ExchangePaymentEndpoint.pollStatus(payment.id, organization);
531
546
  continue;
532
547
  }
533
548
  }
534
- } catch (e) {
535
- console.error(e)
549
+ }
550
+ catch (e) {
551
+ console.error(e);
536
552
  }
537
553
  }
538
554
 
539
555
  if (payments.length === 0) {
540
- didCheckBuckaroo = true
541
- lastBuckarooId = ''
542
- } else {
543
- lastBuckarooId = payments[payments.length - 1].id
556
+ didCheckBuckaroo = true;
557
+ lastBuckarooId = '';
558
+ }
559
+ else {
560
+ lastBuckarooId = payments[payments.length - 1].id;
544
561
  }
545
562
  }
546
563
 
547
564
  // Unreserve reserved registrations
548
565
  async function checkReservedUntil() {
549
- if (STAMHOOFD.environment !== "development") {
550
- console.log("Check reserved until...")
566
+ if (STAMHOOFD.environment !== 'development') {
567
+ console.log('Check reserved until...');
551
568
  }
552
569
 
553
570
  const registrations = await Registration.where({
554
571
  reservedUntil: {
555
- sign: "<",
556
- value: new Date()
572
+ sign: '<',
573
+ value: new Date(),
557
574
  },
558
575
  }, {
559
- limit: 200
560
- })
576
+ limit: 200,
577
+ });
561
578
 
562
579
  if (registrations.length === 0) {
563
- return
580
+ return;
564
581
  }
565
582
 
566
583
  // Clear reservedUntil
567
- const q = `UPDATE ${Registration.table} SET reservedUntil = NULL where id IN (?) AND reservedUntil < ?`
568
- await Database.update(q, [registrations.map(r => r.id), new Date()])
584
+ const q = `UPDATE ${Registration.table} SET reservedUntil = NULL where id IN (?) AND reservedUntil < ?`;
585
+ await Database.update(q, [registrations.map(r => r.id), new Date()]);
569
586
 
570
587
  // Get groups
571
- const groupIds = registrations.map(r => r.groupId)
588
+ const groupIds = registrations.map(r => r.groupId);
572
589
  const groups = await Group.where({
573
590
  id: {
574
- sign: "IN",
575
- value: groupIds
576
- }
577
- })
591
+ sign: 'IN',
592
+ value: groupIds,
593
+ },
594
+ });
578
595
 
579
- for(const registration of registrations) {
580
- registration.scheduleStockUpdate()
596
+ for (const registration of registrations) {
597
+ registration.scheduleStockUpdate();
581
598
  }
582
599
 
583
600
  // Update occupancy
584
601
  for (const group of groups) {
585
- await group.updateOccupancy()
586
- await group.save()
602
+ await group.updateOccupancy();
603
+ await group.save();
587
604
  }
588
605
  }
589
606
 
590
- let lastDripCheck: Date | null = null
591
- let lastDripId = ""
607
+ let lastDripCheck: Date | null = null;
608
+ let lastDripId = '';
592
609
  async function checkDrips() {
593
- if (STAMHOOFD.environment === "development") {
610
+ if (STAMHOOFD.environment === 'development') {
594
611
  return;
595
612
  }
596
613
 
@@ -599,146 +616,148 @@ async function checkDrips() {
599
616
  }
600
617
 
601
618
  if (lastDripCheck && lastDripCheck > new Date(new Date().getTime() - 6 * 60 * 60 * 1000)) {
602
- console.log("Skip Drip check")
603
- return
619
+ console.log('Skip Drip check');
620
+ return;
604
621
  }
605
622
 
606
623
  // Only send emails between 8:00 - 18:00 CET
607
- const CETTime = Formatter.timeIso(new Date())
608
- if ((CETTime < "08:00" || CETTime > "18:00") && STAMHOOFD.environment === "production") {
609
- console.log("Skip Drip check: outside hours")
624
+ const CETTime = Formatter.timeIso(new Date());
625
+ if ((CETTime < '08:00' || CETTime > '18:00') && STAMHOOFD.environment === 'production') {
626
+ console.log('Skip Drip check: outside hours');
610
627
  return;
611
628
  }
612
-
629
+
613
630
  const organizations = await Organization.where({ id: { sign: '>', value: lastDripId } }, {
614
- limit: STAMHOOFD.environment === "production" ? 30 : 100,
615
- sort: ["id"]
616
- })
631
+ limit: STAMHOOFD.environment === 'production' ? 30 : 100,
632
+ sort: ['id'],
633
+ });
617
634
 
618
635
  if (organizations.length == 0) {
619
636
  // Wait before starting again
620
- lastDripId = ""
621
- lastDripCheck = new Date()
622
- return
637
+ lastDripId = '';
638
+ lastDripCheck = new Date();
639
+ return;
623
640
  }
624
641
 
625
- console.log("Checking drips...")
642
+ console.log('Checking drips...');
626
643
 
627
644
  for (const organization of organizations) {
628
- console.log(organization.name)
645
+ console.log(organization.name);
629
646
  try {
630
- await organization.checkDrips()
631
- } catch (e) {
647
+ await organization.checkDrips();
648
+ }
649
+ catch (e) {
632
650
  console.error(e);
633
651
  }
634
652
  }
635
653
 
636
- lastDripId = organizations[organizations.length - 1].id
637
-
654
+ lastDripId = organizations[organizations.length - 1].id;
638
655
  }
639
656
 
640
657
  type CronJobDefinition = {
641
- name: string,
642
- method: () => Promise<void>,
643
- running: boolean
644
- }
658
+ name: string;
659
+ method: () => Promise<void>;
660
+ running: boolean;
661
+ };
645
662
 
646
- const registeredCronJobs: CronJobDefinition[] = []
663
+ const registeredCronJobs: CronJobDefinition[] = [];
647
664
 
648
665
  registeredCronJobs.push({
649
666
  name: 'checkSettlements',
650
667
  method: checkSettlements,
651
- running: false
668
+ running: false,
652
669
  });
653
670
 
654
671
  registeredCronJobs.push({
655
672
  name: 'checkFailedBuckarooPayments',
656
673
  method: checkFailedBuckarooPayments,
657
- running: false
674
+ running: false,
658
675
  });
659
676
 
660
677
  registeredCronJobs.push({
661
678
  name: 'checkExpirationEmails',
662
679
  method: checkExpirationEmails,
663
- running: false
680
+ running: false,
664
681
  });
665
682
 
666
683
  registeredCronJobs.push({
667
684
  name: 'checkPostmarkBounces',
668
685
  method: checkPostmarkBounces,
669
- running: false
686
+ running: false,
670
687
  });
671
688
 
672
689
  registeredCronJobs.push({
673
690
  name: 'checkReservedUntil',
674
691
  method: checkReservedUntil,
675
- running: false
692
+ running: false,
676
693
  });
677
694
 
678
695
  registeredCronJobs.push({
679
696
  name: 'checkComplaints',
680
697
  method: checkComplaints,
681
- running: false
698
+ running: false,
682
699
  });
683
700
 
684
701
  registeredCronJobs.push({
685
702
  name: 'checkReplies',
686
703
  method: checkReplies,
687
- running: false
704
+ running: false,
688
705
  });
689
706
 
690
707
  registeredCronJobs.push({
691
708
  name: 'checkBounces',
692
709
  method: checkBounces,
693
- running: false
710
+ running: false,
694
711
  });
695
712
 
696
713
  registeredCronJobs.push({
697
714
  name: 'checkDNS',
698
715
  method: checkDNS,
699
- running: false
716
+ running: false,
700
717
  });
701
718
 
702
719
  registeredCronJobs.push({
703
720
  name: 'checkWebshopDNS',
704
721
  method: checkWebshopDNS,
705
- running: false
722
+ running: false,
706
723
  });
707
724
 
708
725
  registeredCronJobs.push({
709
726
  name: 'checkPayments',
710
727
  method: checkPayments,
711
- running: false
728
+ running: false,
712
729
  });
713
730
 
714
731
  registeredCronJobs.push({
715
732
  name: 'checkDrips',
716
733
  method: checkDrips,
717
- running: false
734
+ running: false,
718
735
  });
719
736
 
720
737
  registeredCronJobs.push({
721
738
  name: 'clearExcelCache',
722
739
  method: clearExcelCache,
723
- running: false
724
- })
740
+ running: false,
741
+ });
725
742
 
726
743
  async function run(name: string, handler: () => Promise<void>) {
727
744
  try {
728
745
  await logger.setContext({
729
746
  prefixes: [
730
- new StyledText(`[${name}] `).addClass('crons', 'tag')
747
+ new StyledText(`[${name}] `).addClass('crons', 'tag'),
731
748
  ],
732
- tags: ['crons']
749
+ tags: ['crons'],
733
750
  }, async () => {
734
751
  try {
735
- await handler()
736
- } catch (e) {
737
- console.error(new StyledText(e).addClass('error'))
752
+ await handler();
738
753
  }
739
- })
740
- } catch (e) {
741
- console.error(new StyledText(e).addClass('error'))
754
+ catch (e) {
755
+ console.error(new StyledText(e).addClass('error'));
756
+ }
757
+ });
758
+ }
759
+ catch (e) {
760
+ console.error(new StyledText(e).addClass('error'));
742
761
  }
743
762
  }
744
763
 
@@ -750,23 +769,23 @@ export function stopCronScheduling() {
750
769
  let schedulingJobs = false;
751
770
  export function areCronsRunning(): boolean {
752
771
  if (schedulingJobs && !stopCrons) {
753
- return true
772
+ return true;
754
773
  }
755
774
 
756
775
  for (const job of registeredCronJobs) {
757
776
  if (job.running) {
758
- return true
777
+ return true;
759
778
  }
760
779
  }
761
- return false
780
+ return false;
762
781
  }
763
782
 
764
783
  export const crons = async () => {
765
784
  if (STAMHOOFD.CRONS_DISABLED) {
766
- console.log("Crons are disabled. Make sure to enable them in the environment variables.")
785
+ console.log('Crons are disabled. Make sure to enable them in the environment variables.');
767
786
  return;
768
787
  }
769
-
788
+
770
789
  schedulingJobs = true;
771
790
  for (const job of registeredCronJobs) {
772
791
  if (stopCrons) {
@@ -775,15 +794,15 @@ export const crons = async () => {
775
794
  if (job.running) {
776
795
  continue;
777
796
  }
778
- job.running = true
797
+ job.running = true;
779
798
  run(job.name, job.method).finally(() => {
780
- job.running = false
781
- }).catch(e => {
782
- console.error(e)
799
+ job.running = false;
800
+ }).catch((e) => {
801
+ console.error(e);
783
802
  });
784
803
 
785
804
  // Prevent starting too many jobs at once
786
- if (STAMHOOFD.environment !== "development") {
805
+ if (STAMHOOFD.environment !== 'development') {
787
806
  await sleep(10 * 1000);
788
807
  }
789
808
  }