@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
@@ -8,38 +8,37 @@ export class MembershipHelper {
8
8
 
9
9
  let c = 0;
10
10
  let id: string = '';
11
- const tag = "updateAllMemberships";
11
+ const tag = 'updateAllMemberships';
12
12
  const batch = 100;
13
13
 
14
14
  QueueHandler.cancel(tag);
15
15
 
16
16
  await QueueHandler.schedule(tag, async () => {
17
17
  console.log('Starting updateAllMemberships');
18
- await logger.setContext({tags: ['silent-seed', 'seed']}, async () => {
19
- while(true) {
18
+ await logger.setContext({ tags: ['silent-seed', 'seed'] }, async () => {
19
+ while (true) {
20
20
  const rawMembers = await Member.where({
21
21
  id: {
22
22
  value: id,
23
- sign: '>'
24
- }
25
- }, {limit: batch, sort: ['id']});
23
+ sign: '>',
24
+ },
25
+ }, { limit: batch, sort: ['id'] });
26
26
 
27
27
  if (rawMembers.length === 0) {
28
28
  break;
29
29
  }
30
30
 
31
31
  const promises: Promise<any>[] = [];
32
-
33
32
 
34
33
  for (const member of rawMembers) {
35
34
  promises.push((async () => {
36
35
  await Member.updateMembershipsForId(member.id, true);
37
36
  c++;
38
-
39
- if (c%10000 === 0) {
37
+
38
+ if (c % 10000 === 0) {
40
39
  process.stdout.write(c + ' members updated\n');
41
40
  }
42
- })())
41
+ })());
43
42
  }
44
43
 
45
44
  await Promise.all(promises);
@@ -49,7 +48,7 @@ export class MembershipHelper {
49
48
  break;
50
49
  }
51
50
  }
52
- })
53
- })
51
+ });
52
+ });
54
53
  }
55
54
  }
@@ -1,11 +1,11 @@
1
- import { DecodedRequest, Response } from "@simonbackx/simple-endpoints";
2
- import { isSimpleError, isSimpleErrors, SimpleError } from "@simonbackx/simple-errors";
3
- import { Organization, Token, User } from "@stamhoofd/models";
4
- import { LoginProviderType, OpenIDClientConfiguration, Token as TokenStruct } from "@stamhoofd/structures";
5
- import crypto from "crypto";
1
+ import { DecodedRequest, Response } from '@simonbackx/simple-endpoints';
2
+ import { isSimpleError, isSimpleErrors, SimpleError } from '@simonbackx/simple-errors';
3
+ import { Organization, Token, User } from '@stamhoofd/models';
4
+ import { LoginProviderType, OpenIDClientConfiguration, Token as TokenStruct } from '@stamhoofd/structures';
5
+ import crypto from 'crypto';
6
6
  import { generators, Issuer } from 'openid-client';
7
7
 
8
- import { CookieHelper } from "./CookieHelper";
8
+ import { CookieHelper } from './CookieHelper';
9
9
 
10
10
  async function randomBytes(size: number): Promise<Buffer> {
11
11
  return new Promise((resolve, reject) => {
@@ -20,28 +20,28 @@ async function randomBytes(size: number): Promise<Buffer> {
20
20
  }
21
21
 
22
22
  type SessionContext = {
23
- expires: Date,
24
- code_verifier: string,
25
- state: string,
26
- nonce: string
27
- redirectUri: string,
28
- spaState: string,
29
- providerType: LoginProviderType
23
+ expires: Date;
24
+ code_verifier: string;
25
+ state: string;
26
+ nonce: string;
27
+ redirectUri: string;
28
+ spaState: string;
29
+ providerType: LoginProviderType;
30
30
  };
31
31
 
32
32
  export class OpenIDConnectHelper {
33
- organization: Organization
34
- configuration: OpenIDClientConfiguration
33
+ organization: Organization;
34
+ configuration: OpenIDClientConfiguration;
35
35
 
36
- static sessionStorage = new Map<string, SessionContext>()
36
+ static sessionStorage = new Map<string, SessionContext>();
37
37
 
38
38
  constructor(organization, configuration: OpenIDClientConfiguration) {
39
- this.organization = organization
40
- this.configuration = configuration
39
+ this.organization = organization;
40
+ this.configuration = configuration;
41
41
  }
42
42
 
43
43
  get redirectUri() {
44
- return 'https://' + this.organization.id + '.' + STAMHOOFD.domains.api + '/openid/callback'
44
+ return 'https://' + this.organization.id + '.' + STAMHOOFD.domains.api + '/openid/callback';
45
45
  }
46
46
 
47
47
  async getClient() {
@@ -59,41 +59,41 @@ export class OpenIDConnectHelper {
59
59
  }
60
60
 
61
61
  static async storeSession(response: Response<any>, data: SessionContext) {
62
- const sessionId = (await randomBytes(192)).toString("base64");
62
+ const sessionId = (await randomBytes(192)).toString('base64');
63
63
 
64
64
  // Delete expired sessions
65
65
  for (const [key, value] of this.sessionStorage) {
66
66
  if (value.expires < new Date()) {
67
- this.sessionStorage.delete(key)
67
+ this.sessionStorage.delete(key);
68
68
  }
69
69
  }
70
70
 
71
71
  this.sessionStorage.set(sessionId, data);
72
72
 
73
73
  // Store
74
- CookieHelper.setCookie(response, "oid_session_id", sessionId, {
74
+ CookieHelper.setCookie(response, 'oid_session_id', sessionId, {
75
75
  httpOnly: true,
76
76
  secure: true,
77
- expires: data.expires
78
- })
77
+ expires: data.expires,
78
+ });
79
79
  }
80
80
 
81
81
  static getSession(request: DecodedRequest<any, any, any>): SessionContext | null {
82
- const sessionId = CookieHelper.getCookie(request, "oid_session_id")
82
+ const sessionId = CookieHelper.getCookie(request, 'oid_session_id');
83
83
  if (!sessionId) {
84
- return null
84
+ return null;
85
85
  }
86
86
 
87
- const session = this.sessionStorage.get(sessionId)
87
+ const session = this.sessionStorage.get(sessionId);
88
88
  if (!session) {
89
- return null
89
+ return null;
90
90
  }
91
91
 
92
92
  if (session.expires < new Date()) {
93
- return null
93
+ return null;
94
94
  }
95
95
 
96
- return session
96
+ return session;
97
97
  }
98
98
 
99
99
  async startAuthCodeFlow(redirectUri: string, providerType: LoginProviderType, spaState: string, prompt: string | null = null): Promise<Response<undefined>> {
@@ -110,13 +110,13 @@ export class OpenIDConnectHelper {
110
110
  nonce,
111
111
  redirectUri,
112
112
  spaState,
113
- providerType
113
+ providerType,
114
114
  };
115
115
 
116
116
  try {
117
117
  const response = new Response(undefined);
118
118
 
119
- const client = await this.getClient()
119
+ const client = await this.getClient();
120
120
  await OpenIDConnectHelper.storeSession(response, session);
121
121
 
122
122
  const redirect = client.authorizationUrl({
@@ -127,53 +127,54 @@ export class OpenIDConnectHelper {
127
127
  response_type: 'code',
128
128
  state,
129
129
  nonce,
130
- prompt: prompt ?? undefined
130
+ prompt: prompt ?? undefined,
131
131
  });
132
132
 
133
133
  response.headers['location'] = redirect;
134
134
  response.status = 302;
135
135
 
136
136
  return response;
137
- } catch (e) {
138
- const message = (isSimpleError(e) || isSimpleErrors(e) ? e.getHuman() : 'Er ging iets mis.')
139
- console.error('Error in openID callback', e)
140
- return OpenIDConnectHelper.getErrorRedirectResponse(session, message)
137
+ }
138
+ catch (e) {
139
+ const message = (isSimpleError(e) || isSimpleErrors(e) ? e.getHuman() : 'Er ging iets mis.');
140
+ console.error('Error in openID callback', e);
141
+ return OpenIDConnectHelper.getErrorRedirectResponse(session, message);
141
142
  }
142
143
  }
143
144
 
144
145
  async callback(request: DecodedRequest<any, any, any>): Promise<Response<undefined>> {
145
- const session = OpenIDConnectHelper.getSession(request)
146
+ const session = OpenIDConnectHelper.getSession(request);
146
147
 
147
148
  if (!session) {
148
- throw new Error("Missing session")
149
+ throw new Error('Missing session');
149
150
  }
150
151
 
151
152
  try {
152
153
  const response = new Response(undefined);
153
- const client = await this.getClient()
154
+ const client = await this.getClient();
154
155
 
155
156
  // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
156
- const tokenSet = await client.callback(this.redirectUri, request.body, {
157
+ const tokenSet = await client.callback(this.redirectUri, request.body, {
157
158
  code_verifier: session.code_verifier,
158
159
  state: session.state,
159
- nonce: session.nonce
160
+ nonce: session.nonce,
160
161
  });
161
162
 
162
163
  console.log('received and validated tokens %j', tokenSet);
163
-
164
+
164
165
  const claims = tokenSet.claims();
165
166
  console.log('validated ID Token claims %j', claims);
166
167
 
167
168
  if (!claims.name) {
168
169
  throw new SimpleError({
169
170
  code: 'invalid_user',
170
- message: "Missing name",
171
- statusCode: 400
172
- })
171
+ message: 'Missing name',
172
+ statusCode: 400,
173
+ });
173
174
  }
174
175
 
175
- let firstName = claims.name.split(" ")[0]
176
- let lastName = claims.name.split(" ").slice(1).join(" ")
176
+ let firstName = claims.name.split(' ')[0];
177
+ let lastName = claims.name.split(' ').slice(1).join(' ');
177
178
 
178
179
  // Get from API
179
180
  if (tokenSet.access_token) {
@@ -182,33 +183,33 @@ export class OpenIDConnectHelper {
182
183
 
183
184
  if (userinfo.given_name) {
184
185
  console.log('userinfo given_name', userinfo.given_name);
185
- firstName = userinfo.given_name
186
+ firstName = userinfo.given_name;
186
187
  }
187
188
 
188
189
  if (userinfo.family_name) {
189
190
  console.log('userinfo family_name', userinfo.family_name);
190
- lastName = userinfo.family_name
191
+ lastName = userinfo.family_name;
191
192
  }
192
193
  }
193
194
 
194
195
  if (!claims.email) {
195
196
  throw new SimpleError({
196
197
  code: 'invalid_user',
197
- message: "Missing email address",
198
- statusCode: 400
199
- })
198
+ message: 'Missing email address',
199
+ statusCode: 400,
200
+ });
200
201
  }
201
202
 
202
203
  if (!claims.sub) {
203
204
  throw new SimpleError({
204
205
  code: 'invalid_user',
205
- message: "Missing sub",
206
- statusCode: 400
207
- })
206
+ message: 'Missing sub',
207
+ statusCode: 400,
208
+ });
208
209
  }
209
210
 
210
211
  // Get user from database
211
- let user = await User.getOrganizationLevelUser(this.organization.id, claims.email)
212
+ let user = await User.getOrganizationLevelUser(this.organization.id, claims.email);
212
213
  if (!user) {
213
214
  // Create a new user
214
215
  user = await User.registerSSO(this.organization, {
@@ -218,53 +219,55 @@ export class OpenIDConnectHelper {
218
219
  lastName,
219
220
  type: session.providerType,
220
221
  sub: claims.sub,
221
- })
222
+ });
222
223
 
223
224
  if (!user) {
224
225
  throw new SimpleError({
225
226
  code: 'invalid_user',
226
- message: "Failed to create user",
227
- statusCode: 500
228
- })
227
+ message: 'Failed to create user',
228
+ statusCode: 500,
229
+ });
229
230
  }
230
- } else {
231
+ }
232
+ else {
231
233
  // Update name
232
234
  if (!user.firstName || !user.hasPasswordBasedAccount()) {
233
- user.firstName = firstName
235
+ user.firstName = firstName;
234
236
  }
235
237
  if (!user.lastName || !user.hasPasswordBasedAccount()) {
236
- user.lastName = lastName
238
+ user.lastName = lastName;
237
239
  }
238
- user.linkLoginProvider(session.providerType, claims.sub)
239
- await user.save()
240
+ user.linkLoginProvider(session.providerType, claims.sub);
241
+ await user.save();
240
242
  }
241
243
 
242
244
  const token = await Token.createExpiredToken(user);
243
-
245
+
244
246
  if (!token) {
245
247
  throw new SimpleError({
246
- code: "error",
247
- message: "Could not generate token",
248
- human: "Er ging iets mis bij het aanmelden",
249
- statusCode: 500
248
+ code: 'error',
249
+ message: 'Could not generate token',
250
+ human: 'Er ging iets mis bij het aanmelden',
251
+ statusCode: 500,
250
252
  });
251
253
  }
252
254
 
253
255
  const st = new TokenStruct(token);
254
256
 
255
257
  // Redirect back to webshop
256
- const redirectUri = new URL(session.redirectUri)
257
- redirectUri.searchParams.set("oid_rt", st.refreshToken)
258
- redirectUri.searchParams.set("s", session.spaState)
258
+ const redirectUri = new URL(session.redirectUri);
259
+ redirectUri.searchParams.set('oid_rt', st.refreshToken);
260
+ redirectUri.searchParams.set('s', session.spaState);
259
261
 
260
262
  response.headers['location'] = redirectUri.toString();
261
263
  response.status = 302;
262
264
 
263
265
  return response;
264
- } catch (e) {
265
- const message = (isSimpleError(e) || isSimpleErrors(e) ? e.getHuman() : 'Er ging iets mis.')
266
- console.error('Error in openID callback', e)
267
- return OpenIDConnectHelper.getErrorRedirectResponse(session, message)
266
+ }
267
+ catch (e) {
268
+ const message = (isSimpleError(e) || isSimpleErrors(e) ? e.getHuman() : 'Er ging iets mis.');
269
+ console.error('Error in openID callback', e);
270
+ return OpenIDConnectHelper.getErrorRedirectResponse(session, message);
268
271
  }
269
272
  }
270
273
 
@@ -272,13 +275,13 @@ export class OpenIDConnectHelper {
272
275
  const response = new Response(undefined);
273
276
 
274
277
  // Redirect back to webshop
275
- const redirectUri = new URL(session.redirectUri)
276
- redirectUri.searchParams.set("s", session.spaState)
277
- redirectUri.searchParams.set("error", errorMessage)
278
+ const redirectUri = new URL(session.redirectUri);
279
+ redirectUri.searchParams.set('s', session.spaState);
280
+ redirectUri.searchParams.set('error', errorMessage);
278
281
 
279
282
  response.headers['location'] = redirectUri.toString();
280
283
  response.status = 302;
281
284
 
282
285
  return response;
283
286
  }
284
- }
287
+ }
@@ -1,52 +1,50 @@
1
-
2
- import { Group, Member, MemberResponsibilityRecord, Organization, OrganizationRegistrationPeriod, Platform, RegistrationPeriod } from "@stamhoofd/models";
3
- import { AuthenticatedStructures } from "./AuthenticatedStructures";
4
- import { PatchOrganizationRegistrationPeriodsEndpoint } from "../endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint";
5
- import { QueueHandler } from "@stamhoofd/queues";
6
- import { SetupStepUpdater } from "./SetupStepsUpdater";
7
- import { PermissionLevel, Group as GroupStruct } from "@stamhoofd/structures";
8
- import { MemberUserSyncer } from "./MemberUserSyncer";
9
- import { SimpleError } from "@simonbackx/simple-errors";
1
+ import { SimpleError } from '@simonbackx/simple-errors';
2
+ import { Group, Member, MemberResponsibilityRecord, Organization, OrganizationRegistrationPeriod, Platform, RegistrationPeriod, SetupStepUpdater } from '@stamhoofd/models';
3
+ import { QueueHandler } from '@stamhoofd/queues';
4
+ import { Group as GroupStruct, PermissionLevel } from '@stamhoofd/structures';
5
+ import { PatchOrganizationRegistrationPeriodsEndpoint } from '../endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint';
6
+ import { AuthenticatedStructures } from './AuthenticatedStructures';
7
+ import { MemberUserSyncer } from './MemberUserSyncer';
10
8
 
11
9
  export class PeriodHelper {
12
10
  static async moveOrganizationToPeriod(organization: Organization, period: RegistrationPeriod) {
13
- console.log('moveOrganizationToPeriod', organization.id, period.id)
14
-
15
- await this.createOrganizationPeriodForPeriod(organization, period)
16
- organization.periodId = period.id
17
- await organization.save()
11
+ console.log('moveOrganizationToPeriod', organization.id, period.id);
12
+
13
+ await this.createOrganizationPeriodForPeriod(organization, period);
14
+ organization.periodId = period.id;
15
+ await organization.save();
18
16
  }
19
17
 
20
18
  static async stopAllResponsibilities() {
21
- console.log('Stopping all responsibilities')
22
- const platform = await Platform.getSharedPrivateStruct()
23
- const keepPlatformResponsibilityIds = platform.config.responsibilities.filter(r => !r.organizationBased).map(r => r.id)
24
- const keepResponsibilityIds = platform.config.responsibilities.filter(r => !r.organizationBased || r.permissions?.level === PermissionLevel.Full).map(r => r.id)
19
+ console.log('Stopping all responsibilities');
20
+ const platform = await Platform.getSharedPrivateStruct();
21
+ const keepPlatformResponsibilityIds = platform.config.responsibilities.filter(r => !r.organizationBased).map(r => r.id);
22
+ const keepResponsibilityIds = platform.config.responsibilities.filter(r => !r.organizationBased || r.permissions?.level === PermissionLevel.Full).map(r => r.id);
25
23
  const batchSize = 100;
26
24
 
27
- let lastId = "";
25
+ let lastId = '';
28
26
  let c = 0;
29
27
 
30
28
  while (true) {
31
29
  const records = await MemberResponsibilityRecord.where(
32
30
  {
33
- id: { sign: ">", value: lastId },
34
- endDate: null
31
+ id: { sign: '>', value: lastId },
32
+ endDate: null,
33
+ },
34
+ {
35
+ limit: batchSize,
36
+ sort: ['id'],
35
37
  },
36
- {
37
- limit: batchSize,
38
- sort: ["id"]
39
- }
40
38
  );
41
39
 
42
40
  for (const record of records) {
43
41
  lastId = record.id;
44
42
 
45
- const invalid = keepPlatformResponsibilityIds.includes(record.responsibilityId) && record.organizationId
43
+ const invalid = keepPlatformResponsibilityIds.includes(record.responsibilityId) && record.organizationId;
46
44
 
47
45
  if (!keepResponsibilityIds.includes(record.responsibilityId) || invalid) {
48
- record.endDate = new Date()
49
- await record.save()
46
+ record.endDate = new Date();
47
+ await record.save();
50
48
  c++;
51
49
  }
52
50
  }
@@ -54,25 +52,24 @@ export class PeriodHelper {
54
52
  if (records.length < batchSize) {
55
53
  break;
56
54
  }
57
-
58
55
  }
59
56
 
60
- console.log('Done: stopped all responsibilities: ' + c)
57
+ console.log('Done: stopped all responsibilities: ' + c);
61
58
  }
62
59
 
63
60
  static async syncAllMemberUsers() {
64
- console.log('Syncing all members')
61
+ console.log('Syncing all members');
65
62
 
66
63
  let c = 0;
67
64
  let lastId: string = '';
68
65
 
69
- while(true) {
66
+ while (true) {
70
67
  const rawMembers = await Member.where({
71
68
  id: {
72
69
  value: lastId,
73
- sign: '>'
74
- }
75
- }, {limit: 500, sort: ['id']});
70
+ sign: '>',
71
+ },
72
+ }, { limit: 500, sort: ['id'] });
76
73
 
77
74
  if (rawMembers.length === 0) {
78
75
  break;
@@ -87,7 +84,7 @@ export class PeriodHelper {
87
84
  await MemberUserSyncer.onChangeMember(memberWithRegistrations);
88
85
  c++;
89
86
 
90
- if (c%10000 === 0) {
87
+ if (c % 10000 === 0) {
91
88
  console.log('Synced ' + c + ' members');
92
89
  }
93
90
  })());
@@ -97,50 +94,50 @@ export class PeriodHelper {
97
94
  lastId = rawMembers[rawMembers.length - 1].id;
98
95
  }
99
96
 
100
- console.log('Done: synced all members: ' + c)
101
- }
97
+ console.log('Done: synced all members: ' + c);
98
+ }
102
99
 
103
100
  static async createOrganizationPeriodForPeriod(organization: Organization, period: RegistrationPeriod) {
104
- const oPeriods = await OrganizationRegistrationPeriod.where({ periodId: period.id, organizationId: organization.id }, {limit: 1})
105
-
101
+ const oPeriods = await OrganizationRegistrationPeriod.where({ periodId: period.id, organizationId: organization.id }, { limit: 1 });
102
+
106
103
  if (oPeriods.length) {
107
104
  // Already created
108
- return oPeriods[0]
105
+ return oPeriods[0];
109
106
  }
110
107
 
111
- const currentPeriod = await organization.getPeriod()
108
+ const currentPeriod = await organization.getPeriod();
112
109
  if (currentPeriod.periodId === period.id) {
113
- return currentPeriod
110
+ return currentPeriod;
114
111
  }
115
112
 
116
- const struct = await AuthenticatedStructures.organizationRegistrationPeriod(currentPeriod)
113
+ const struct = await AuthenticatedStructures.organizationRegistrationPeriod(currentPeriod);
117
114
 
118
- const duplicate = struct.duplicate(period.getStructure())
119
- return await PatchOrganizationRegistrationPeriodsEndpoint.createOrganizationPeriod(organization, duplicate)
115
+ const duplicate = struct.duplicate(period.getStructure());
116
+ return await PatchOrganizationRegistrationPeriodsEndpoint.createOrganizationPeriod(organization, duplicate);
120
117
  }
121
118
 
122
119
  static async moveAllOrganizationsToPeriod(period: RegistrationPeriod) {
123
- const tag = "moveAllOrganizationsToPeriod";
120
+ const tag = 'moveAllOrganizationsToPeriod';
124
121
  if (QueueHandler.isRunning(tag)) {
125
122
  throw new SimpleError({
126
123
  code: 'move_period_pending',
127
- message: 'Er is al een jaarovergang bezig. Wacht tot deze klaar is.'
128
- })
124
+ message: 'Er is al een jaarovergang bezig. Wacht tot deze klaar is.',
125
+ });
129
126
  }
130
127
 
131
128
  const batchSize = 10;
132
129
  await QueueHandler.schedule(tag, async () => {
133
- let lastId = "";
130
+ let lastId = '';
134
131
 
135
132
  while (true) {
136
133
  const organizations = await Organization.where(
137
134
  {
138
- id: { sign: ">", value: lastId },
135
+ id: { sign: '>', value: lastId },
136
+ },
137
+ {
138
+ limit: batchSize,
139
+ sort: ['id'],
139
140
  },
140
- {
141
- limit: batchSize,
142
- sort: ["id"]
143
- }
144
141
  );
145
142
 
146
143
  for (const organization of organizations) {
@@ -151,20 +148,19 @@ export class PeriodHelper {
151
148
  if (organizations.length < batchSize) {
152
149
  break;
153
150
  }
154
-
155
151
  }
156
152
 
157
- await this.stopAllResponsibilities()
158
- await this.syncAllMemberUsers()
153
+ await this.stopAllResponsibilities();
154
+ await this.syncAllMemberUsers();
159
155
  });
160
156
 
161
157
  // When done: update setup steps
162
- await SetupStepUpdater.updateSetupStepsForAllOrganizationsInCurrentPeriod()
158
+ await SetupStepUpdater.updateSetupStepsForAllOrganizationsInCurrentPeriod();
163
159
  }
164
160
 
165
161
  static async updateGroupsInPeriod(period: RegistrationPeriod) {
166
- const tag = "updateGroupsInPeriod-"+period.id;
167
-
162
+ const tag = 'updateGroupsInPeriod-' + period.id;
163
+
168
164
  if (QueueHandler.isRunning(tag)) {
169
165
  return;
170
166
  }
@@ -173,29 +169,28 @@ export class PeriodHelper {
173
169
 
174
170
  const batchSize = 100;
175
171
  await QueueHandler.schedule(tag, async () => {
176
- let lastId = "";
172
+ let lastId = '';
177
173
 
178
174
  while (true) {
179
175
  const groups = await Group.where(
180
176
  {
181
- id: { sign: ">", value: lastId },
182
- periodId: period.id
177
+ id: { sign: '>', value: lastId },
178
+ periodId: period.id,
179
+ },
180
+ {
181
+ limit: batchSize,
182
+ sort: ['id'],
183
183
  },
184
- {
185
- limit: batchSize,
186
- sort: ["id"]
187
- }
188
184
  );
189
185
 
190
186
  for (const group of groups) {
191
- await PatchOrganizationRegistrationPeriodsEndpoint.patchGroup(GroupStruct.patch({id: group.id}), period);
187
+ await PatchOrganizationRegistrationPeriodsEndpoint.patchGroup(GroupStruct.patch({ id: group.id }), period);
192
188
  lastId = group.id;
193
189
  }
194
190
 
195
191
  if (groups.length < batchSize) {
196
192
  break;
197
193
  }
198
-
199
194
  }
200
195
  });
201
196
  }